diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index 22038d130..15afb3cab 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -213,17 +213,111 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8 LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg); /********************************************************************* - IE Name: PMCH Info List + IE Name: TMGI - Description: Specifies configuration of all PMCHs of an MBSFN area + Description: Temporary Mobile Group Identity (PLMN + MBMS service ID) Document Reference: 36.331 v10.0.0 Section 6.3.7 *********************************************************************/ // Defines // Enums // Structs +typedef struct{ + uint16 mcc; + uint16 mnc; +}LIBLTE_RRC_PLMN_IDENTITY_STRUCT; +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id_r9; + uint8 plmn_index_r9; + bool plmn_id_explicit; + uint32 serviceid_r9; +}LIBLTE_RRC_TMGI_R9_STRUCT; // Functions -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_TMGI_R9_STRUCT *tmgi); + +/********************************************************************* + IE Name: MBMS Session Info + + Description: Information about an individual MBMS session + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_TMGI_R9_STRUCT tmgi_r9; + uint8 sessionid_r9; + bool sessionid_r9_present; + uint8 logicalchannelid_r9; +}LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info); + +/********************************************************************* + IE Name: PMCH Config + + Description: Contains configuration parameters of the sessions + carried by a PMCH + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines + +// Enums +typedef enum{ + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8 = 0, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF16, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF32, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF128, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF256, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF512, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024, + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS, +}LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM; +static const char liblte_rrc_mch_scheduling_period_r9_text[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS][20] = {"8", "16", "32", "64", "128", "256", "512", "1024"}; +static const uint16 liblte_rrc_mch_scheduling_period_r9_num[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS] = {8, 16, 32, 64, 128, 256, 512, 1024}; + +// Structs +typedef struct{ + uint16 sf_alloc_end_r9; + uint8 datamcs_r9; + LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM mch_schedulingperiod_r9; +}LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg); + +/********************************************************************* + IE Name: PMCH Info + + Description: Specifies configuration of PMCH of an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_SESSION_PER_PMCH 29 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT pmch_config_r9; + LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT mbms_sessioninfolist_r9[LIBLTE_RRC_MAX_SESSION_PER_PMCH]; + uint8 mbms_sessioninfolist_r9_size; +}LIBLTE_RRC_PMCH_INFO_R9_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info); /********************************************************************* IE Name: C-RNTI @@ -2227,10 +2321,6 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8 // Defines // Enums // Structs -typedef struct{ - uint16 mcc; - uint16 mnc; -}LIBLTE_RRC_PLMN_IDENTITY_STRUCT; typedef struct{ LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; uint32 cell_id; @@ -5135,7 +5225,7 @@ typedef struct{ LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants; LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra; LIBLTE_RRC_UL_BW_STRUCT ul_bw; - LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS]; + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg_list[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS]; LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer; uint32 mbsfn_subfr_cnfg_list_size; uint8 additional_spectrum_emission; @@ -5545,7 +5635,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8 // Structs typedef struct{ LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS]; - LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbms_notification_config; + LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_config; uint8 mbsfn_area_info_list_r9_size; }LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT; // Functions @@ -5771,18 +5861,18 @@ typedef enum{ LIBLTE_RRC_SIB_TYPE_11, LIBLTE_RRC_SIB_TYPE_12_v920, LIBLTE_RRC_SIB_TYPE_13_v920, - LIBLTE_RRC_SIB_TYPE_SPARE_5, - LIBLTE_RRC_SIB_TYPE_SPARE_4, - LIBLTE_RRC_SIB_TYPE_SPARE_3, - LIBLTE_RRC_SIB_TYPE_SPARE_2, - LIBLTE_RRC_SIB_TYPE_SPARE_1, + LIBLTE_RRC_SIB_TYPE_14_v1130, + LIBLTE_RRC_SIB_TYPE_15_v1130, + LIBLTE_RRC_SIB_TYPE_16_v1130, + LIBLTE_RRC_SIB_TYPE_17_v1250, + LIBLTE_RRC_SIB_TYPE_18_v1250, LIBLTE_RRC_SIB_TYPE_N_ITEMS, }LIBLTE_RRC_SIB_TYPE_ENUM; -static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6", - "7", "8", "9", "10", - "11", "12", "13", "SPARE", - "SPARE", "SPARE", "SPARE", "SPARE"}; -static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0}; +static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6", + "7", "8", "9", "10", + "11", "12_v920", "13_v920", "14_v1130", + "15_v1130", "16_v1130", "17_v1250", "18_v1250"}; +static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; // Structs typedef struct{ LIBLTE_RRC_PLMN_IDENTITY_STRUCT id; @@ -5846,14 +5936,20 @@ typedef enum{ LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_14, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_15, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_16, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_17, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_18, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS, }LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM; static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5", "6", "7", "8", "9", - "10", "11", "12", "13", - "1"}; -static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1}; + "10", "11", "12", "13", + "14", "15", "16", "17", + "18", "1"}; +static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1}; // Structs typedef union{ LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; @@ -6551,10 +6647,37 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT Document Reference: 36.331 v10.0.0 Section 6.2.2 *********************************************************************/ // Defines +#define LIBLTE_RRC_MAX_PMCH_PER_MBSFN 15 + // Enums +typedef enum{ + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF4 = 0, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF8, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF16, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF32, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF128, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256, + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS, +}LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM; +static const char liblte_rrc_mbsfn_common_sf_alloc_period_r9_text[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS][20] = {"4", "8", "16", "32", + "64", "128", "256"}; +static const uint32 liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS] = {4, 8, 16, 32, + 64, 128, 256}; // Structs +typedef struct{ + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT commonsf_allocpatternlist_r9[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS]; + uint8 commonsf_allocpatternlist_r9_size; + LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM commonsf_allocperiod_r9; + LIBLTE_RRC_PMCH_INFO_R9_STRUCT pmch_infolist_r9[LIBLTE_RRC_MAX_PMCH_PER_MBSFN]; + uint8 pmch_infolist_r9_size; +}LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT; + // Functions -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *msg, + LIBLTE_RRC_PAGING_STRUCT *mbsfn_area_cnfg); /********************************************************************* Message Name: Master Information Block @@ -6783,8 +6906,12 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT // Defines // Enums // Structs +typedef LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT LIBLTE_RRC_MCCH_MSG_STRUCT; // Functions -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg); /********************************************************************* Message Name: PCCH Message diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index 436f35edd..d4cca957a 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -57,7 +57,9 @@ public: void reestablish(); void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); + void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void config_security(uint32_t lcid, uint8_t *k_enc, uint8_t *k_int, @@ -72,9 +74,11 @@ public: // RLC interface void write_pdu(uint32_t lcid, byte_buffer_t *sdu); + void write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu); void write_pdu_bcch_bch(byte_buffer_t *sdu); void write_pdu_bcch_dlsch(byte_buffer_t *sdu); void write_pdu_pcch(byte_buffer_t *sdu); + private: srsue::rlc_interface_pdcp *rlc; @@ -83,10 +87,12 @@ private: log *pdcp_log; pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS]; + pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS]; uint32_t lcid; // default LCID that is maintained active by PDCP instance uint8_t direction; bool valid_lcid(uint32_t lcid); + bool valid_mch_lcid(uint32_t lcid); }; } // namespace srslte diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 05472e0e8..888dfa4f1 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -63,17 +63,21 @@ public: // PDCP interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - + void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu); bool rb_is_um(uint32_t lcid); // MAC interface uint32_t get_buffer_state(uint32_t lcid); uint32_t get_total_buffer_state(uint32_t lcid); + uint32_t get_total_mch_buffer_state(uint32_t lcid); int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + int read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + int get_increment_sequence_num(); void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); + void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); // RRC interface void reestablish(); @@ -81,7 +85,8 @@ public: void empty_queue(); void add_bearer(uint32_t lcid); void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg); - + void add_bearer_mrb(uint32_t lcid); + void add_bearer_mrb_enb(uint32_t lcid); private: void reset_metrics(); @@ -92,13 +97,16 @@ private: srslte::mac_interface_timers *mac_timers; srsue::ue_interface *ue; srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS]; + srslte::rlc_um rlc_array_mrb[SRSLTE_N_MCH_LCIDS]; uint32_t default_lcid; long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS]; long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS]; + long dl_tput_bytes_mrb[SRSLTE_N_MCH_LCIDS]; struct timeval metrics_time[3]; bool valid_lcid(uint32_t lcid); + bool valid_lcid_mrb(uint32_t lcid); }; } // namespace srsue diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index 3a8c2cc16..2d05967f5 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -72,11 +72,13 @@ class rlc_am public: rlc_am(); ~rlc_am(); - void init(log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers); + + void init(log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers, + bool is_mrb_=false); void configure(srslte_rlc_config_t cnfg); void reset(); void reestablish(); diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index 9be390d31..9c304d4f6 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -155,7 +155,8 @@ public: uint32_t lcid_, srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, - srslte::mac_interface_timers *mac_timers_) = 0; + srslte::mac_interface_timers *mac_timers_, + bool is_mrb_=false) = 0; virtual void configure(srslte_rlc_config_t cnfg) = 0; virtual void reset() = 0; virtual void stop() = 0; diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index cd30d5999..eca470709 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -47,12 +47,12 @@ class rlc_entity { public: rlc_entity(); - void init(rlc_mode_t mode, - log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers_); + void init(rlc_mode_t mode, + log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers_); void configure(srslte_rlc_config_t cnfg); void reset(); diff --git a/lib/include/srslte/upper/rlc_tm.h b/lib/include/srslte/upper/rlc_tm.h index d3a8aa1ae..8adda8639 100644 --- a/lib/include/srslte/upper/rlc_tm.h +++ b/lib/include/srslte/upper/rlc_tm.h @@ -41,11 +41,12 @@ class rlc_tm { public: rlc_tm(); - void init(log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers); + void init(log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers, + bool is_mrb_=false); void configure(srslte_rlc_config_t cnfg); void reset(); void stop(); diff --git a/lib/include/srslte/upper/rlc_um.h b/lib/include/srslte/upper/rlc_um.h index d41192d6d..6a9eaef5c 100644 --- a/lib/include/srslte/upper/rlc_um.h +++ b/lib/include/srslte/upper/rlc_um.h @@ -50,17 +50,19 @@ class rlc_um { public: rlc_um(); - ~rlc_um(); - void init(log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers_); + ~rlc_um(); + void init(log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers_, + bool mrb_=false); void configure(srslte_rlc_config_t cnfg); void reset(); void stop(); void empty_queue(); + bool is_mrb(); rlc_mode_t get_mode(); uint32_t get_bearer(); @@ -73,7 +75,7 @@ public: uint32_t get_total_buffer_state(); int read_pdu(uint8_t *payload, uint32_t nof_bytes); void write_pdu(uint8_t *payload, uint32_t nof_bytes); - + int get_increment_sequence_num(); // Timeout callback interface void timer_expired(uint32_t timeout_id); @@ -87,10 +89,12 @@ private: srsue::pdcp_interface_rlc *pdcp; srsue::rrc_interface_rlc *rrc; mac_interface_timers *mac_timers; + bool mrb; // TX SDU buffers rlc_tx_queue tx_sdu_queue; byte_buffer_t *tx_sdu; + byte_buffer_t tx_sdu_temp; // Rx window std::map rx_window; @@ -133,9 +137,13 @@ private: int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes); + int build_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes); + void handle_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes); void reassemble_rx_sdus(); bool inside_reordering_window(uint16_t sn); void debug_state(); + + std::string rb_name(); }; /**************************************************************************** diff --git a/lib/src/asn1/liblte_rrc.cc b/lib/src/asn1/liblte_rrc.cc index 8e489cd9f..eb264a0ec 100644 --- a/lib/src/asn1/liblte_rrc.cc +++ b/lib/src/asn1/liblte_rrc.cc @@ -327,13 +327,218 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8 } /********************************************************************* - IE Name: PMCH Info List + IE Name: TMGI - Description: Specifies configuration of all PMCHs of an MBSFN area + Description: Temporary Mobile Group Identity (PLMN + MBMS service ID) Document Reference: 36.331 v10.0.0 Section 6.3.7 *********************************************************************/ -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(tmgi != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(tmgi->plmn_id_explicit?1:0, ie_ptr, 1); + if(tmgi->plmn_id_explicit){ + liblte_rrc_pack_plmn_identity_ie(&tmgi->plmn_id_r9, ie_ptr); + }else{ + liblte_value_2_bits(tmgi->plmn_index_r9-1, ie_ptr, 3); + } + liblte_value_2_bits(tmgi->serviceid_r9, ie_ptr, 24); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_TMGI_R9_STRUCT *tmgi) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tmgi != NULL) + { + tmgi->plmn_id_explicit = liblte_bits_2_value(ie_ptr, 1); + if(tmgi->plmn_id_explicit){ + liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &tmgi->plmn_id_r9); + }else{ + tmgi->plmn_index_r9 = liblte_bits_2_value(ie_ptr, 3) + 1; + } + tmgi->serviceid_r9 = liblte_bits_2_value(ie_ptr, 24); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MBMS Session Info + + Description: Information about an individual MBMS session + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mbms_session_info != NULL && + ie_ptr != NULL) + { + // ext + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(mbms_session_info->sessionid_r9_present?1:0, ie_ptr, 1); + liblte_rrc_pack_tmgi_r9_ie(&mbms_session_info->tmgi_r9, ie_ptr); + if(mbms_session_info->sessionid_r9_present){ + liblte_value_2_bits(mbms_session_info->sessionid_r9, ie_ptr, 8); + } + liblte_value_2_bits(mbms_session_info->logicalchannelid_r9, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mbms_session_info != NULL) + { + // ext + bool ext = liblte_bits_2_value(ie_ptr, 1); + + mbms_session_info->sessionid_r9_present = liblte_bits_2_value(ie_ptr, 1); + liblte_rrc_unpack_tmgi_r9_ie(ie_ptr, &mbms_session_info->tmgi_r9); + if(mbms_session_info->sessionid_r9_present){ + mbms_session_info->sessionid_r9 = liblte_bits_2_value(ie_ptr, 8); + } + mbms_session_info->logicalchannelid_r9 = liblte_bits_2_value(ie_ptr, 5); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PMCH Config + + Description: Contains configuration parameters of the sessions + carried by a PMCH + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pmch_cnfg != NULL && + ie_ptr != NULL) + { + // ext + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(pmch_cnfg->sf_alloc_end_r9, ie_ptr, 11); + liblte_value_2_bits(pmch_cnfg->datamcs_r9, ie_ptr, 5); + liblte_value_2_bits(pmch_cnfg->mch_schedulingperiod_r9, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pmch_cnfg != NULL) + { + // ext + bool ext = liblte_bits_2_value(ie_ptr, 1); + + pmch_cnfg->sf_alloc_end_r9 = liblte_bits_2_value(ie_ptr, 11); + pmch_cnfg->datamcs_r9 = liblte_bits_2_value(ie_ptr, 5); + pmch_cnfg->mch_schedulingperiod_r9 = (LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM)liblte_bits_2_value(ie_ptr, 3); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + + +/********************************************************************* + IE Name: PMCH Info + + Description: Specifies configuration of PMCH of an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(pmch_info != NULL && + ie_ptr != NULL) + { + // ext + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_rrc_pack_pmch_config_r9_ie(&pmch_info->pmch_config_r9, ie_ptr); + liblte_value_2_bits(pmch_info->mbms_sessioninfolist_r9_size, ie_ptr, 5); + for(i=0; imbms_sessioninfolist_r9_size; i++){ + liblte_rrc_pack_mbms_session_info_r9_ie(&pmch_info->mbms_sessioninfolist_r9[i], ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr, + LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + pmch_info != NULL) + { + // ext + bool ext = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_pmch_config_r9_ie(ie_ptr, &pmch_info->pmch_config_r9); + pmch_info->mbms_sessioninfolist_r9_size = liblte_bits_2_value(ie_ptr, 5); + for(i=0; imbms_sessioninfolist_r9_size; i++){ + liblte_rrc_unpack_mbms_session_info_r9_ie(ie_ptr, &pmch_info->mbms_sessioninfolist_r9[i]); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} /********************************************************************* IE Name: C-RNTI @@ -8896,7 +9101,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_B liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3); for(i=0; imbsfn_subfr_cnfg_list_size; i++) { - liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg[i], ie_ptr); + liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg_list[i], ie_ptr); } } @@ -8994,7 +9199,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8 sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1; for(i=0; imbsfn_subfr_cnfg_list_size; i++) { - liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg[i]); + liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg_list[i]); } }else{ sib2->mbsfn_subfr_cnfg_list_size = 0; @@ -10288,7 +10493,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_ { liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr); } - liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbms_notification_config, ie_ptr); + liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbsfn_notification_config, ie_ptr); err = LIBLTE_SUCCESS; } @@ -10317,7 +10522,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8 { liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]); } - liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbms_notification_config); + liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbsfn_notification_config); liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); @@ -13001,9 +13206,82 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT Description: Contains the MBMS control information applicable for an MBSFN area - Document Reference: 36.331 v10.0.0 Section 6.2.2 + Document Reference: 36.331 v10.0.0 Section 6.2.2 *********************************************************************/ -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(mbsfn_area_cnfg != NULL && + msg != NULL) + { + // Non-critical extension + liblte_value_2_bits(0, &msg_ptr, 1); + + // commonsf_allocpatternlist_r9 + liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size-1, &msg_ptr, 3); + for(i=0; icommonsf_allocpatternlist_r9_size; i++){ + liblte_rrc_pack_mbsfn_subframe_config_ie(&mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i], &msg_ptr); + } + + // commonsf_allocperiod_r9 + liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocperiod_r9, &msg_ptr, 3); + + // pmch_infolist_r9 + liblte_value_2_bits(mbsfn_area_cnfg->pmch_infolist_r9_size, &msg_ptr, 4); + for(i=0; ipmch_infolist_r9_size; i++){ + liblte_rrc_pack_pmch_info_r9_ie(&mbsfn_area_cnfg->pmch_infolist_r9[i], &msg_ptr); + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + bool ext; + + if(msg != NULL && + mbsfn_area_cnfg != NULL) + { + // Non-critical extension + ext = liblte_bits_2_value(&msg_ptr, 1); + liblte_rrc_warning_not_handled(ext, __func__); + + // commonsf_allocpatternlist_r9 + mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size = liblte_bits_2_value(&msg_ptr, 3) + 1; + for(i=0; icommonsf_allocpatternlist_r9_size; i++){ + liblte_rrc_unpack_mbsfn_subframe_config_ie(&msg_ptr, &mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i]); + } + + // commonsf_allocperiod_r9 + mbsfn_area_cnfg->commonsf_allocperiod_r9 = (LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM)liblte_bits_2_value(&msg_ptr, 3); + + // pmch_infolist_r9 + mbsfn_area_cnfg->pmch_infolist_r9_size = liblte_bits_2_value(&msg_ptr, 4); + for(i=0; ipmch_infolist_r9_size; i++){ + liblte_rrc_unpack_pmch_info_r9_ie(&msg_ptr, &mbsfn_area_cnfg->pmch_infolist_r9[i]); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + /********************************************************************* Message Name: Master Information Block @@ -13104,7 +13382,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_S liblte_bits_2_value(&msg_ptr, 2); // Optional indicator - liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__); // Dedicated info type choice dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2); @@ -13373,6 +13651,66 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT return(err); } +/********************************************************************* + Message Name: MCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the MCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(mcch_msg != NULL && + msg != NULL) + { + // MCCH choice + liblte_value_2_bits(0, &msg_ptr, 1); + + err = liblte_rrc_pack_mbsfn_area_configuration_r9_msg(mcch_msg, + &global_msg); + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 1)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 1; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 N_bits_used; + + if(msg != NULL && + mcch_msg != NULL) + { + // MCCH choice + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 1)) + { + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + err = liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(&global_msg, + mcch_msg); + } + } + + return(err); +} + /********************************************************************* Message Name: PCCH Message diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index cb3ec7d84..e577a12ce 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -100,6 +100,12 @@ void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) } } +void pdcp::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) +{ + if(valid_mch_lcid(lcid)){ + pdcp_array_mrb[lcid].write_sdu(sdu); + } +} void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg) { if(lcid >= SRSLTE_N_RADIO_BEARERS) { @@ -114,6 +120,21 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg) } } + +void pdcp::add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cfg) +{ + if(lcid >= SRSLTE_N_RADIO_BEARERS) { + pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); + return; + } + if (!pdcp_array_mrb[lcid].is_active()) { + pdcp_array_mrb[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg); + pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); + } else { + pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); + } +} + void pdcp::config_security(uint32_t lcid, uint8_t *k_enc, uint8_t *k_int, @@ -175,6 +196,15 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu) rrc->write_pdu_pcch(sdu); } +void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu) +{ + if(0 == lcid) { + rrc->write_pdu_mch(lcid, sdu); + } else { + gw->write_pdu_mch(lcid, sdu); + } +} + /******************************************************************************* Helpers *******************************************************************************/ @@ -191,4 +221,17 @@ bool pdcp::valid_lcid(uint32_t lcid) return true; } +bool pdcp::valid_mch_lcid(uint32_t lcid) +{ + if(lcid >= SRSLTE_N_MCH_LCIDS) { + pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); + return false; + } + if(!pdcp_array_mrb[lcid].is_active()) { + pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); + return false; + } + return true; +} + } // namespace srsue diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index e771c34a2..77a71afd4 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -139,6 +139,12 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) rlc_array[lcid].write_sdu(sdu); } } +void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) +{ + if(valid_lcid_mrb(lcid)) { + rlc_array_mrb[lcid].write_sdu(sdu); + } +} bool rlc::rb_is_um(uint32_t lcid) { return rlc_array[lcid].get_mode()==RLC_MODE_UM; @@ -165,6 +171,15 @@ uint32_t rlc::get_total_buffer_state(uint32_t lcid) } } +uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid) +{ + if(valid_lcid_mrb(lcid)) { + return rlc_array_mrb[lcid].get_total_buffer_state(); + } else { + return 0; + } +} + int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { if(valid_lcid(lcid)) { @@ -174,6 +189,15 @@ int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) return 0; } +int rlc::read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) +{ + if(valid_lcid_mrb(lcid)) { + ul_tput_bytes[lcid] += nof_bytes; + return rlc_array_mrb[lcid].read_pdu(payload, nof_bytes); + } + return 0; +} + void rlc::write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { if(valid_lcid(lcid)) { @@ -227,6 +251,14 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) } } +void rlc::write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) +{ + if(valid_lcid_mrb(lcid)) { + dl_tput_bytes_mrb[lcid] += nof_bytes; + rlc_array_mrb[lcid].write_pdu(payload, nof_bytes); + } +} + /******************************************************************************* RRC interface *******************************************************************************/ @@ -287,6 +319,27 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) } +void rlc::add_bearer_mrb(uint32_t lcid) +{ + // 36.321 Table 6.2.1-4 + if(lcid < 0 || lcid >= SRSLTE_N_MCH_LCIDS) { + rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid); + return; + } + bool is_mrb = true; + rlc_array_mrb[lcid].init(rlc_log, lcid, pdcp, rrc, mac_timers, is_mrb); +} + +void rlc::add_bearer_mrb_enb(uint32_t lcid) +{ + if(lcid >= SRSLTE_N_MCH_LCIDS) { + rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid); + return; + } + rlc_array_mrb[lcid].init(rlc_log,lcid,pdcp,rrc,mac_timers,true); + +} + /******************************************************************************* Helpers *******************************************************************************/ @@ -301,5 +354,16 @@ bool rlc::valid_lcid(uint32_t lcid) return true; } +bool rlc::valid_lcid_mrb(uint32_t lcid) +{ + if(lcid < 0 || lcid > 31) { + return false; + } + if(!rlc_array_mrb[lcid].is_mrb()) { + return false; + } + return true; +} + } // namespace srsue diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 461d5141d..a992e1182 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -81,12 +81,12 @@ rlc_am::~rlc_am() pool->deallocate(tx_sdu); } } - -void rlc_am::init(srslte::log *log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - srslte::mac_interface_timers *mac_timers) +void rlc_am::init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srslte::mac_interface_timers *mac_timers, + bool is_mrb) { log = log_; lcid = lcid_; diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 0dd16bf4d..21db7b0ac 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -42,7 +42,8 @@ void rlc_tm::init(srslte::log *log_, uint32_t lcid_, srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers) + mac_interface_timers *mac_timers, + bool is_mrb) { log = log_; lcid = lcid_; diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 5a018d40b..25d3ccfd1 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -26,6 +26,7 @@ #include "srslte/upper/rlc_um.h" +#include #define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod @@ -55,6 +56,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32) vr_ur_in_rx_sdu = 0; mac_timers = NULL; + mrb = false; pdu_lost = false; } @@ -63,24 +65,42 @@ rlc_um::~rlc_um() { stop(); } - -void rlc_um::init(srslte::log *log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - srslte::mac_interface_timers *mac_timers_) +void rlc_um::init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srslte::mac_interface_timers *mac_timers_, + bool mrb_) { log = log_; lcid = lcid_; pdcp = pdcp_; rrc = rrc_; mac_timers = mac_timers_; + mrb = mrb_; reordering_timer_id = mac_timers->timer_get_unique_id(); reordering_timer = mac_timers->timer_get(reordering_timer_id); + + if(mrb) { + cfg.t_reordering = 0; + cfg.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; + cfg.rx_window_size = 0; + cfg.rx_mod = 32; + cfg.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; + cfg.tx_mod = 32; + log->info("MRB%d configured in %s mode: " + "t_reordering=%d ms, rx_sn_field_length=%u bits\n", + lcid, liblte_rrc_rlc_mode_text[LIBLTE_RRC_RLC_MODE_UM_UNI_DL], + cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); + } } void rlc_um::configure(srslte_rlc_config_t cnfg_) -{ +{ + if(mrb) { + return; // Default configured in init() + } + cfg = cnfg_.um; switch(cnfg_.rlc_mode) @@ -88,18 +108,19 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_) case LIBLTE_RRC_RLC_MODE_UM_BI: log->warning("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n", rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: log->warning("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; default: @@ -116,6 +137,11 @@ void rlc_um::empty_queue() { } } +bool rlc_um::is_mrb() +{ + return mrb; +} + void rlc_um::stop() { reset(); @@ -197,7 +223,7 @@ uint32_t rlc_um::get_buffer_state() // Room needed for fixed header? if(n_bytes > 0) - n_bytes += 3; + n_bytes += (mrb)?2:3; return n_bytes; } @@ -209,9 +235,14 @@ uint32_t rlc_um::get_total_buffer_state() int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes) { + int r; log->debug("MAC opportunity - %d bytes\n", nof_bytes); pthread_mutex_lock(&mutex); - int r = build_data_pdu(payload, nof_bytes); + if(mrb){ + r = build_mch_data_pdu(payload, nof_bytes); + } else{ + r = build_data_pdu(payload, nof_bytes); + } pthread_mutex_unlock(&mutex); return r; } @@ -219,7 +250,11 @@ int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) { pthread_mutex_lock(&mutex); - handle_data_pdu(payload, nof_bytes); + if(mrb) { + handle_mch_data_pdu(payload, nof_bytes); + } else { + handle_data_pdu(payload, nof_bytes); + } pthread_mutex_unlock(&mutex); } @@ -235,7 +270,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) // 36.322 v10 Section 5.1.2.2.4 log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", - rrc->get_rb_name(lcid).c_str()); + rb_name().c_str()); log->warning("Lost PDU SN: %d\n", vr_ur); pdu_lost = true; @@ -269,6 +304,130 @@ bool rlc_um::reordering_timeout_running() * Helpers ***************************************************************************/ + +int rlc_um::build_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + + if(!tx_sdu && tx_sdu_queue.size() == 0) + { + log->info("No data available to be sent\n"); + return 0; + } + + byte_buffer_t *pdu = pool_allocate; + if(!pdu || pdu->N_bytes != 0) + { + log->error("Failed to allocate PDU buffer\n"); + return 0; + } + + rlc_umd_pdu_header_t header; + header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; + header.sn = vt_us; + header.N_li = 0; + header.sn_size = RLC_UMD_SN_SIZE_5_BITS; //cfg.tx_sn_field_length; + + + uint32_t to_move = 0; + uint32_t last_li = 0; + uint8_t *pdu_ptr = pdu->msg; + + int head_len = rlc_um_packed_length(&header); + int pdu_space = nof_bytes; + + if(pdu_space <= head_len + 1) + { + pool->deallocate(pdu); + log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", + rb_name().c_str(), nof_bytes, head_len); + return 0; + } + + // Check for SDU segment + if(tx_sdu) + { + uint32_t space = pdu_space-head_len; + to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; + log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", + rb_name().c_str(), to_move, tx_sdu->N_bytes); + memcpy(pdu_ptr, tx_sdu->msg, to_move); + + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + pdu_space -= to_move; + header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU + } + + // Pull SDUs from queue + while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) + { + log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len); + if(last_li > 0) + header.li[header.N_li++] = last_li; + head_len = rlc_um_packed_length(&header); + tx_sdu_queue.read(&tx_sdu); + + uint32_t space = pdu_space-head_len; + to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; + log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", + rb_name().c_str(), to_move, tx_sdu->N_bytes); + memcpy(pdu_ptr, tx_sdu->msg, to_move); + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + pdu_space -= to_move; + } + + if(tx_sdu) + header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU + + // Set SN + header.sn = vt_us; + vt_us = (vt_us + 1)%cfg.tx_mod; + + + // Add header and TX + log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes); + + + if(pdu_space > 0 && tx_sdu == NULL){ + //header.li[header.N_li++] = last_li; + header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; + } + rlc_um_write_data_pdu_header(&header, pdu); + memcpy(payload, pdu->msg, pdu->N_bytes); + uint32_t ret = pdu->N_bytes; + + log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + + pool->deallocate(pdu); + + debug_state(); + return ret; + + +} + int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { if(!tx_sdu && tx_sdu_queue.size() == 0) @@ -300,7 +459,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { pool->deallocate(pdu); log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + rb_name().c_str(), nof_bytes, head_len); return 0; } @@ -310,7 +469,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + rb_name().c_str(), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -339,7 +498,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + rb_name().c_str(), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -360,14 +519,16 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU // Set SN + header.sn = vt_us; vt_us = (vt_us + 1)%cfg.tx_mod; // Add header and TX - log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes); rlc_um_write_data_pdu_header(&header, pdu); memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; + log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); pool->deallocate(pdu); @@ -375,6 +536,63 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) return ret; } +void rlc_um::handle_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(!rx_sdu) { + rx_sdu = pool_allocate; + } + + rlc_umd_pdu_header_t header; + rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); + + log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", + rb_name().c_str(), header.sn); + + //Strip header from PDU + int header_len = rlc_um_packed_length(&header); + payload += header_len; + nof_bytes -= header_len; + if(0 == header.sn) { + vr_uh = 0; + } + + // Handle SDU segments + for(uint32_t i=0; ireset(); + vr_uh = header.sn; + if(!rlc_um_start_aligned(header.fi)) { + payload += len; + nof_bytes -= len; + } + } else { + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, len); + log->debug("Concatenating %d bytes in to current length %d.\n", len, rx_sdu->N_bytes); + rx_sdu->N_bytes += len; + payload += len; + nof_bytes -= len; + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU i=%d", rb_name().c_str(), i); + rx_sdu->set_timestamp(); + pdcp->write_pdu_mch(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + } + + // Handle last segment + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, nof_bytes); + rx_sdu->N_bytes += nof_bytes; + log->debug("Writing last segment in SDU buffer. Buffer size=%d, segment size=%d\n", + rx_sdu->N_bytes, nof_bytes); + if(rlc_um_end_aligned(header.fi)) { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_name().c_str()); + rx_sdu->set_timestamp(); + pdcp->write_pdu_mch(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + vr_uh = (header.sn + 1); +} + void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) { std::map::iterator it; @@ -382,20 +600,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + rb_name().c_str(), header.sn); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh); + rb_name().c_str(), header.sn, vr_ur, vr_uh); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + rb_name().c_str(), header.sn); return; } @@ -486,7 +704,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_name().c_str(), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -562,7 +780,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_name().c_str(), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -601,7 +819,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name().c_str(), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -625,6 +843,9 @@ clean_up_rx_window: bool rlc_um::inside_reordering_window(uint16_t sn) { + if(cfg.rx_window_size == 0) { + return true; + } if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh)) { @@ -637,10 +858,20 @@ bool rlc_um::inside_reordering_window(uint16_t sn) void rlc_um::debug_state() { log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", - rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh); + rb_name().c_str(), vt_us, vr_ur, vr_ux, vr_uh); } +std::string rlc_um::rb_name() { + if(mrb) { + std::stringstream ss; + ss << "MRB" << lcid; + return ss.str(); + } else { + return rrc->get_rb_name(lcid); + } +} + /**************************************************************************** * Header pack/unpack helper functions * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1