diff --git a/.clang-tidy b/.clang-tidy index c5a75d316..874dd51ad 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,6 +7,7 @@ # - init of static memory may cause an exception (cert-err58) # - forbidden implicit conversion from pointer/int to bool # - recommended auto +# - remove llvm-specific checks (header guard style, usage of llvm namespace, restriction of libc includes, etc.) # Naming conventions set to snake_case Checks: '*,-fuchsia-*, -cppcoreguidelines-pro-type-vararg,-hicpp-vararg, @@ -14,12 +15,15 @@ Checks: '*,-fuchsia-*, -cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay, -cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-type-cstyle-cast, -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-static-cast-downcast, -modernize-use-using,-modernize-use-trailing-return-type, -modernize-use-auto,-hicpp-use-auto, - -llvmlibc-callee-namespace, + -llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-llvmlibc-restrict-system-libc-headers, + -llvm-header-guard, -google-runtime-references,-google-readability-casting,-google-build-using-namespace, google-default-arguments,-cppcoreguidelines-pro-bounds-pointer-arithmetic, -cert-err58-cpp, + -readability-function-cognitive-complexity,-readability-isolate-declaration, -misc-non-private-member-variables-in-classes,-altera-struct-pack-align,-readability-uppercase-literal-suffix, -cppcoreguidelines-non-private-member-variables-in-classes, readability-identifier-naming' diff --git a/lib/include/srslte/adt/bounded_vector.h b/lib/include/srslte/adt/bounded_vector.h index b0bfb9479..e4d0da045 100644 --- a/lib/include/srslte/adt/bounded_vector.h +++ b/lib/include/srslte/adt/bounded_vector.h @@ -116,8 +116,8 @@ public: } T& front() { return (*this)[0]; } const T& front() const { return (*this)[0]; } - T* data() { return &front(); } - const T* data() const { return &front(); } + T* data() { return reinterpret_cast(buffer); } + const T* data() const { return reinterpret_cast(buffer); } // Iterators iterator begin() { return data(); } diff --git a/lib/include/srslte/common/task_scheduler.h b/lib/include/srslte/common/task_scheduler.h index b2fb04d51..b1537b5b3 100644 --- a/lib/include/srslte/common/task_scheduler.h +++ b/lib/include/srslte/common/task_scheduler.h @@ -51,7 +51,11 @@ public: srslte::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.get_queue_handler(qsize); } //! Delays a task processing by duration_ms - void defer_callback(uint32_t duration_ms, std::function func) { timers.defer_callback(duration_ms, func); } + template + void defer_callback(uint32_t duration_ms, F&& func) + { + timers.defer_callback(duration_ms, std::forward(func)); + } //! Enqueues internal task to be run in next tic void defer_task(srslte::move_task_t func) { internal_tasks.push_back(std::move(func)); } @@ -123,9 +127,10 @@ public: { sched->notify_background_task_result(std::move(task)); } - void defer_callback(uint32_t duration_ms, std::function func) + template + void defer_callback(uint32_t duration_ms, F&& func) { - sched->defer_callback(duration_ms, std::move(func)); + sched->defer_callback(duration_ms, std::forward(func)); } void defer_task(srslte::move_task_t func) { sched->defer_task(std::move(func)); } @@ -145,9 +150,10 @@ public: sched->notify_background_task_result(std::move(task)); } srslte::task_queue_handle make_task_queue() { return sched->make_task_queue(); } - void defer_callback(uint32_t duration_ms, std::function func) + template + void defer_callback(uint32_t duration_ms, F&& func) { - sched->defer_callback(duration_ms, std::move(func)); + sched->defer_callback(duration_ms, std::forward(func)); } private: diff --git a/lib/include/srslte/interfaces/rrc_nr_interface_types.h b/lib/include/srslte/interfaces/rrc_nr_interface_types.h index 7081f1ac9..34b75bd63 100644 --- a/lib/include/srslte/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_nr_interface_types.h @@ -33,6 +33,7 @@ namespace srslte { **************************/ struct phy_cfg_nr_t { + srslte_tdd_config_nr_t tdd = {}; srslte_sch_hl_cfg_nr_t pdsch = {}; srslte_sch_hl_cfg_nr_t pusch = {}; srslte_pucch_nr_hl_cfg_t pucch = {}; @@ -43,9 +44,6 @@ struct phy_cfg_nr_t { phy_cfg_nr_t() { - // Default PDSCH configuration - pdsch.sch_cfg.mcs_table = srslte_mcs_table_256qam; - // Default PRACH configuration prach.is_nr = true; prach.config_idx = 16; @@ -55,6 +53,21 @@ struct phy_cfg_nr_t { prach.num_ra_preambles = 64; prach.hs_flag = false; + // tdd-UL-DL-ConfigurationCommon + // referenceSubcarrierSpacing: kHz15 (0) + // pattern1 + // dl-UL-TransmissionPeriodicity: ms10 (7) + // nrofDownlinkSlots: 7 + // nrofDownlinkSymbols: 6 + // nrofUplinkSlots: 2 + // nrofUplinkSymbols: 4 + tdd.pattern1.period_ms = 10; + tdd.pattern1.nof_dl_slots = 7; + tdd.pattern1.nof_dl_symbols = 6; + tdd.pattern1.nof_ul_slots = 2; + tdd.pattern1.nof_ul_symbols = 4; + tdd.pattern2.period_ms = 0; + // physicalCellGroupConfig // pdsch-HARQ-ACK-Codebook: dynamic (1) harq_ack.pdsch_harq_ack_codebook = srslte_pdsch_harq_ack_codebook_dynamic; @@ -93,8 +106,8 @@ struct phy_cfg_nr_t { srslte_search_space_t search_space1 = {}; search_space1.id = 1; search_space1.coreset_id = 1; - search_space1.nof_candidates[0] = 0; - search_space1.nof_candidates[1] = 0; + search_space1.nof_candidates[0] = 1; + search_space1.nof_candidates[1] = 1; search_space1.nof_candidates[2] = 1; search_space1.nof_candidates[3] = 0; search_space1.nof_candidates[4] = 0; @@ -108,6 +121,56 @@ struct phy_cfg_nr_t { pdcch.ra_search_space.type = srslte_search_space_type_common_1; pdcch.ra_search_space_present = true; + // spCellConfigDedicated + // initialDownlinkBWP + // pdcch-Config: setup (1) + // setup + // controlResourceSetToAddModList: 1 item + // Item 0 + // ControlResourceSet + // controlResourceSetId: 2 + // frequencyDomainResources: ff0000000000 [bit length 45, 3 LSB pad bits, 1111 1111 0000 + // 0000 0000 0000 0000 0000 0000 0000 0000 0... decimal value 35046933135360] + // duration: 1 + // cce-REG-MappingType: nonInterleaved (1) + // nonInterleaved: NULL + // precoderGranularity: sameAsREG-bundle (0) + pdcch.coreset[2].id = 2; + pdcch.coreset[2].precoder_granularity = srslte_coreset_precoder_granularity_reg_bundle; + pdcch.coreset[2].duration = 1; + pdcch.coreset[2].mapping_type = srslte_coreset_mapping_type_non_interleaved; + for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + pdcch.coreset[2].freq_resources[i] = (i < 8); + } + pdcch.coreset_present[2] = true; + + // searchSpacesToAddModList: 1 item + // Item 0 + // SearchSpace + // searchSpaceId: 2 + // controlResourceSetId: 2 + // monitoringSlotPeriodicityAndOffset: sl1 (0) + // sl1: NULL + // monitoringSymbolsWithinSlot: 8000 [bit length 14, 2 LSB pad bits, 1000 0000 0000 + // 00.. decimal value 8192] nrofCandidates + // aggregationLevel1: n0 (0) + // aggregationLevel2: n2 (2) + // aggregationLevel4: n1 (1) + // aggregationLevel8: n0 (0) + // aggregationLevel16: n0 (0) + // searchSpaceType: ue-Specific (1) + // ue-Specific + // dci-Formats: formats0-0-And-1-0 (0) + pdcch.search_space[2].id = 2; + pdcch.search_space[2].coreset_id = 2; + pdcch.search_space[2].nof_candidates[0] = 0; + pdcch.search_space[2].nof_candidates[1] = 2; + pdcch.search_space[2].nof_candidates[2] = 1; + pdcch.search_space[2].nof_candidates[3] = 0; + pdcch.search_space[2].nof_candidates[4] = 0; + pdcch.search_space[2].type = srslte_search_space_type_ue; + pdcch.search_space_present[2] = true; + // pdsch-ConfigCommon: setup (1) // setup // pdsch-TimeDomainAllocationList: 2 items @@ -187,11 +250,22 @@ struct phy_cfg_nr_t { // betaOffsetACK-Index1: 9 // betaOffsetACK-Index2: 9 // betaOffsetACK-Index3: 9 + pusch.beta_offsets.ack_index1 = 9; + pusch.beta_offsets.ack_index2 = 9; + pusch.beta_offsets.ack_index3 = 9; + // betaOffsetCSI-Part1-Index1: 6 // betaOffsetCSI-Part1-Index2: 6 + pusch.beta_offsets.csi1_index1 = 6; + pusch.beta_offsets.csi1_index2 = 6; + // betaOffsetCSI-Part2-Index1: 6 // betaOffsetCSI-Part2-Index2: 6 + pusch.beta_offsets.csi2_index1 = 6; + pusch.beta_offsets.csi2_index2 = 6; + // scaling: f1 (3) + pusch.scaling = 1; // pucch-Config: setup (1) // setup diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 9e41e98a8..c8ec0d466 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -223,27 +223,22 @@ public: } dl_sched_bc_t; - typedef struct { - uint32_t cfi; - uint32_t nof_data_elems; - uint32_t nof_rar_elems; - uint32_t nof_bc_elems; - dl_sched_data_t data[MAX_DATA_LIST]; - dl_sched_rar_t rar[MAX_RAR_LIST]; - dl_sched_bc_t bc[MAX_BC_LIST]; - } dl_sched_res_t; + struct dl_sched_res_t { + uint32_t cfi; + srslte::bounded_vector data; + srslte::bounded_vector rar; + srslte::bounded_vector bc; + }; typedef struct { uint16_t rnti; enum phich_elem { ACK, NACK } phich; } ul_sched_phich_t; - typedef struct { - uint32_t nof_dci_elems; - uint32_t nof_phich_elems; - ul_sched_data_t pusch[MAX_DATA_LIST]; - ul_sched_phich_t phich[MAX_PHICH_LIST]; - } ul_sched_res_t; + struct ul_sched_res_t { + srslte::bounded_vector pusch; + srslte::bounded_vector phich; + }; /******************* Scheduler Control ****************************/ diff --git a/lib/include/srslte/interfaces/ue_phy_interfaces.h b/lib/include/srslte/interfaces/ue_phy_interfaces.h index a62bea7e1..bf7a6505a 100644 --- a/lib/include/srslte/interfaces/ue_phy_interfaces.h +++ b/lib/include/srslte/interfaces/ue_phy_interfaces.h @@ -113,8 +113,8 @@ class phy_interface_mac_common { public: /* Time advance commands */ - virtual void set_timeadv_rar(uint32_t ta_cmd) = 0; - virtual void set_timeadv(uint32_t ta_cmd) = 0; + virtual void set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) = 0; + virtual void set_timeadv(uint32_t tti, uint32_t ta_cmd) = 0; /* Activate / Disactivate SCell*/ virtual void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) = 0; diff --git a/lib/include/srslte/phy/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h index 51bff5c2c..f1867bc0c 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_ul.h +++ b/lib/include/srslte/phy/ch_estimation/chest_ul.h @@ -56,7 +56,7 @@ typedef struct SRSLTE_API { float epre_dBfs; float snr; float snr_db; - float cfo; + float cfo_hz; float ta_us; } srslte_chest_ul_res_t; diff --git a/lib/include/srslte/phy/common/phy_common_nr.h b/lib/include/srslte/phy/common/phy_common_nr.h index 35f28912c..ae43f994c 100644 --- a/lib/include/srslte/phy/common/phy_common_nr.h +++ b/lib/include/srslte/phy/common/phy_common_nr.h @@ -95,10 +95,17 @@ extern "C" { #define SRSLTE_PDCCH_MAX_RE ((SRSLTE_NRE - 3U) * (1U << (SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR - 1U)) * 6U) /** - * @brief defines the maximum number of candidates for a given Aggregation level + * @brief defines the maximum number of candidates for a given search-space and aggregation level according to TS 38.331 + * SearchSpace sequence */ #define SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR 8 +/** + * @brief defines the maximum number of monitored PDCCH candidates per slot and per serving cell according to TS 38.213 + * Table 10.1-2 + */ +#define SRSLTE_MAX_NOF_CANDIDATES_SLOT_NR 44 + /** * @brief defines the maximum number of resource elements per PRB * @remark Defined in TS 38.214 V15.10.0 5.1.3.2 Transport block size determination, point 1, second bullet @@ -310,6 +317,25 @@ typedef struct SRSLTE_API { uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR]; } srslte_search_space_t; +/** + * @brief TDD pattern configuration + */ +typedef struct SRSLTE_API { + uint32_t period_ms; ///< Period in milliseconds, set to 0 if not present + uint32_t nof_dl_slots; ///< Number of consecutive full DL slots at the beginning of each DL-UL pattern + uint32_t nof_dl_symbols; ///< Number of consecutive DL symbols in the beginning of the slot following the last DL slot + uint32_t nof_ul_slots; ///< Number of consecutive full UL slots at the end of each DL-UL pattern + uint32_t nof_ul_symbols; ///< Number of consecutive UL symbols in the end of the slot preceding the first full UL slot +} srslte_tdd_pattern_t; + +/** + * @brief TDD configuration as described in TS 38.331 v15.10.0 TDD-UL-DL-ConfigCommon + */ +typedef struct SRSLTE_API { + srslte_tdd_pattern_t pattern1; + srslte_tdd_pattern_t pattern2; +} srslte_tdd_config_nr_t; + /** * @brief Get the RNTI type name for NR * @param rnti_type RNTI type name @@ -381,6 +407,24 @@ SRSLTE_API uint32_t srslte_min_symbol_sz_rb(uint32_t nof_prb); */ SRSLTE_API float srslte_symbol_distance_s(uint32_t l0, uint32_t l1, uint32_t numerology); +/** + * @brief Decides whether a given slot is configured as Downlink + * @param cfg Provides TDD configuration + * @param numerology Provides BWP numerology + * @param slot_idx Slot index in the frame for the given numerology + * @return true if the provided slot index is configured for Downlink + */ +SRSLTE_API bool srslte_tdd_nr_is_dl(const srslte_tdd_config_nr_t* cfg, uint32_t numerology, uint32_t slot_idx); + +/** + * @brief Decides whether a given slot is configured as Uplink + * @param cfg Provides TDD configuration + * @param numerology Provides BWP numerology + * @param slot_idx Slot index in the frame for the given numerology + * @return true if the provided slot index is configured for Uplink + */ +SRSLTE_API bool srslte_tdd_nr_is_ul(const srslte_tdd_config_nr_t* cfg, uint32_t numerology, uint32_t slot_idx); + #ifdef __cplusplus } #endif diff --git a/lib/include/srslte/phy/phch/phch_cfg_nr.h b/lib/include/srslte/phy/phch/phch_cfg_nr.h index da3e9c3cb..b52081521 100644 --- a/lib/include/srslte/phy/phch/phch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/phch_cfg_nr.h @@ -153,6 +153,20 @@ typedef struct SRSLTE_API { srslte_sch_tb_t tb[SRSLTE_MAX_TB]; } srslte_sch_grant_nr_t; +/** + * @brief Beta offset configuration provided from upper layers + * @remark Configure according to TS 38.331 BetaOffsets + */ +typedef struct { + uint32_t ack_index1; ///< Use for up to 2 HARQ-ACK bits. Set to 11 if absent. + uint32_t ack_index2; ///< Use for up to 11 HARQ-ACK bits. Set to 11 if absent. + uint32_t ack_index3; ///< Use for more than 11 HARQ-ACK bits. Set to 11 if absent. + uint32_t csi1_index1; ///< Use for up to 11 CSI bits. Set to 13 if absent. + uint32_t csi1_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. + uint32_t csi2_index1; ///< Use for up to 11 CSI bits. Set to 13 if absent. + uint32_t csi2_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. +} srslte_beta_offsets_t; + /** * @brief flatten SCH configuration parameters provided by higher layers * @remark Described in TS 38.331 V15.10.0 Section PDSCH-Config @@ -197,6 +211,10 @@ typedef struct SRSLTE_API { bool rbg_size_cfg_1; ///< RBG size configuration (1 or 2) srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters + + /// PUSCH only + srslte_beta_offsets_t beta_offsets; /// Semi-static only. + float scaling; /// Indicates a scaling factor to limit the number of resource elements assigned to UCI on PUSCH. } srslte_sch_hl_cfg_nr_t; /** @@ -216,6 +234,7 @@ typedef struct SRSLTE_API { bool enable_transform_precoder; float beta_harq_ack_offset; float beta_csi_part1_offset; + float beta_csi_part2_offset; float scaling; bool freq_hopping_enabled; } srslte_sch_cfg_nr_t; diff --git a/lib/include/srslte/phy/phch/pusch_nr.h b/lib/include/srslte/phy/phch/pusch_nr.h index 58e2764fb..fb0184822 100644 --- a/lib/include/srslte/phy/phch/pusch_nr.h +++ b/lib/include/srslte/phy/phch/pusch_nr.h @@ -124,6 +124,7 @@ SRSLTE_API uint32_t srslte_pusch_nr_rx_info(const srslte_pusch_nr_t* q, SRSLTE_API uint32_t srslte_pusch_nr_tx_info(const srslte_pusch_nr_t* q, const srslte_sch_cfg_nr_t* cfg, const srslte_sch_grant_nr_t* grant, + const srslte_uci_value_nr_t* uci_value, char* str, uint32_t str_len); diff --git a/lib/include/srslte/phy/phch/ra_nr.h b/lib/include/srslte/phy/phch/ra_nr.h index b06d1d3c0..e69fbf74e 100644 --- a/lib/include/srslte/phy/phch/ra_nr.h +++ b/lib/include/srslte/phy/phch/ra_nr.h @@ -130,4 +130,18 @@ SRSLTE_API int srslte_ra_ul_dci_to_grant_nr(const srslte_carrier_nr_t* carrie srslte_sch_cfg_nr_t* pusch_cfg, srslte_sch_grant_nr_t* pusch_grant); +/** + * @brief Set up the Uplink Control Information configuration for a PUSCH transmission + * + * @remark Implement procedure described in TS 38.213 9.3 UCI reporting in physical uplink shared channel + * + * @param pusch_hl_cfg PUSCH configuration provided by higher layers + * @param uci_cfg Uplink Control Information configuration for this PUSCH transmission + * @param pusch_cfg PUSCH configuration after applying the procedure + * @return SRSLTE_SUCCESS if the procedure is successful, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_ra_ul_set_grant_uci_nr(const srslte_sch_hl_cfg_nr_t* pusch_hl_cfg, + const srslte_uci_cfg_nr_t* uci_cfg, + srslte_sch_cfg_nr_t* pusch_cfg); + #endif // SRSLTE_RA_NR_H diff --git a/lib/include/srslte/phy/ue/ue_dl_nr.h b/lib/include/srslte/phy/ue/ue_dl_nr.h index 6fc90e479..e0b696931 100644 --- a/lib/include/srslte/phy/ue/ue_dl_nr.h +++ b/lib/include/srslte/phy/ue/ue_dl_nr.h @@ -111,6 +111,14 @@ typedef struct SRSLTE_API { uint32_t nof_dl_data_to_ul_ack; } srslte_ue_dl_nr_harq_ack_cfg_t; +typedef struct SRSLTE_API { + uint32_t coreset_id; + uint32_t ss_id; + srslte_dci_location_t location; + srslte_dmrs_pdcch_measure_t measure; + srslte_pdcch_nr_res_t result; +} srslte_ue_dl_nr_pdcch_info_t; + typedef struct SRSLTE_API { uint32_t max_prb; uint32_t nof_rx_antennas; @@ -131,6 +139,14 @@ typedef struct SRSLTE_API { srslte_pdcch_nr_t pdcch; srslte_dmrs_pdcch_ce_t* pdcch_ce; + /// Store Blind-search information from all possible candidate locations for debug purposes + srslte_ue_dl_nr_pdcch_info_t pdcch_info[SRSLTE_MAX_NOF_CANDIDATES_SLOT_NR]; + uint32_t pdcch_info_count; + + /// Temporally stores Found DCI messages from all SS + srslte_dci_msg_nr_t dci_msg[SRSLTE_MAX_DCI_MSG_NR]; + uint32_t dci_msg_count; + srslte_dci_msg_nr_t pending_ul_dci_msg[SRSLTE_MAX_DCI_MSG_NR]; uint32_t pending_ul_dci_count; } srslte_ue_dl_nr_t; diff --git a/lib/include/srslte/phy/ue/ue_ul_nr.h b/lib/include/srslte/phy/ue/ue_ul_nr.h index daedd4d4b..d65993751 100644 --- a/lib/include/srslte/phy/ue/ue_ul_nr.h +++ b/lib/include/srslte/phy/ue/ue_ul_nr.h @@ -76,8 +76,11 @@ SRSLTE_API int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* SRSLTE_API void srslte_ue_ul_nr_free(srslte_ue_ul_nr_t* q); -SRSLTE_API int -srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, const srslte_sch_cfg_nr_t* cfg, char* str, uint32_t str_len); +SRSLTE_API int srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, + const srslte_sch_cfg_nr_t* cfg, + const srslte_uci_value_nr_t* uci_value, + char* str, + uint32_t str_len); SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource, const srslte_uci_data_nr_t* uci_data, diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index c58140760..88f9de6bb 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -109,6 +109,7 @@ private: std::array, SRSLTE_MAX_CHANNELS> rx_buffer; std::array interpolators = {}; std::array decimators = {}; + bool decimator_busy = false; ///< Indicates the decimator is changing the rate rf_timestamp_t end_of_burst_time = {}; bool is_start_of_burst = false; diff --git a/lib/include/srslte/srslog/detail/log_entry_metadata.h b/lib/include/srslte/srslog/detail/log_entry_metadata.h index f23f30a2f..9413f78cb 100644 --- a/lib/include/srslte/srslog/detail/log_entry_metadata.h +++ b/lib/include/srslte/srslog/detail/log_entry_metadata.h @@ -27,6 +27,9 @@ namespace srslog { +/// This type is used to store small strings without doing any memory allocation. +using small_str_buffer = fmt::basic_memory_buffer; + namespace detail { /// This structure gives the user a way to log generic information as a context. @@ -40,13 +43,14 @@ struct log_context { /// Metadata fields carried for each log entry. struct log_entry_metadata { - std::chrono::high_resolution_clock::time_point tp; - log_context context; - const char* fmtstring; + std::chrono::high_resolution_clock::time_point tp; + log_context context; + const char* fmtstring; fmt::dynamic_format_arg_store store; - std::string log_name; - char log_tag; - std::vector hex_dump; + std::string log_name; + char log_tag; + small_str_buffer small_str; + std::vector hex_dump; }; } // namespace detail diff --git a/lib/include/srslte/srslog/detail/support/work_queue.h b/lib/include/srslte/srslog/detail/support/work_queue.h index 2eb3ae4f7..b913c62ec 100644 --- a/lib/include/srslte/srslog/detail/support/work_queue.h +++ b/lib/include/srslte/srslog/detail/support/work_queue.h @@ -120,7 +120,7 @@ public: // Did we wake up on timeout? if (timedout && queue.empty()) { cond_var.unlock(); - return {false, T{}}; + return {false, T()}; } // Here we have been woken up normally. diff --git a/lib/include/srslte/srslog/log_channel.h b/lib/include/srslte/srslog/log_channel.h index acfb7911b..331fe96a0 100644 --- a/lib/include/srslte/srslog/log_channel.h +++ b/lib/include/srslte/srslog/log_channel.h @@ -122,7 +122,34 @@ public: fmtstr, std::move(store), log_name, - log_tag}}; + log_tag, + small_str_buffer()}}; + backend.push(std::move(entry)); + } + + /// Builds the provided log entry and passes it to the backend. When the + /// channel is disabled the log entry will be discarded. + void operator()(small_str_buffer &&str) + { + if (!enabled()) { + return; + } + + // Send the log entry to the backend. + log_formatter& formatter = log_sink.get_formatter(); + detail::log_entry entry = { + &log_sink, + [&formatter](detail::log_entry_metadata&& metadata, + fmt::memory_buffer& buffer) { + formatter.format(std::move(metadata), buffer); + }, + {std::chrono::high_resolution_clock::now(), + {ctx_value, should_print_context}, + nullptr, + {}, + log_name, + log_tag, + std::move(str)}}; backend.push(std::move(entry)); } @@ -161,6 +188,7 @@ public: std::move(store), log_name, log_tag, + small_str_buffer(), std::vector(buffer, buffer + len)}}; backend.push(std::move(entry)); } @@ -187,7 +215,8 @@ public: nullptr, {}, log_name, - log_tag}}; + log_tag, + small_str_buffer()}}; backend.push(std::move(entry)); } @@ -218,7 +247,8 @@ public: fmtstr, std::move(store), log_name, - log_tag}}; + log_tag, + small_str_buffer()}}; backend.push(std::move(entry)); } diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index adfaeddbb..c295a9e3b 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -483,14 +483,7 @@ public: bool ret = true; pdu->N_bytes = static_cast(n_recv); - if (flags & MSG_NOTIFICATION) { - // Received notification - union sctp_notification* notification = (union sctp_notification*)pdu->msg; - if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) { - // Socket Shutdown - ret = false; - } - } + // SCTP notifications handled in callback. func(std::move(pdu), from, sri, flags); return ret; } diff --git a/lib/src/common/pcap.c b/lib/src/common/pcap.c index bb536a24e..0cc5ce380 100644 --- a/lib/src/common/pcap.c +++ b/lib/src/common/pcap.c @@ -100,6 +100,10 @@ inline int LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(MAC_Context_Info_t* context, uint buffer[offset++] = MAC_LTE_CRC_STATUS_TAG; buffer[offset++] = context->crcStatusOK; + /* CARRIER ID */ + buffer[offset++] = MAC_LTE_CARRIER_ID_TAG; + buffer[offset++] = context->cc_idx; + /* NB-IoT mode tag */ buffer[offset++] = MAC_LTE_NB_MODE_TAG; buffer[offset++] = context->nbiotMode; diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index 0496de116..5255aae01 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -297,6 +297,15 @@ static void chest_ul_estimate(srslte_chest_ul_t* q, uint32_t n_prb[SRSLTE_NOF_SLOTS_PER_SF], srslte_chest_ul_res_t* res) { + // Calculate CFO + if (nslots == 2) { + float phase = cargf(srslte_vec_dot_prod_conj_ccc( + &q->pilot_estimates[0 * nrefs_sym], &q->pilot_estimates[1 * nrefs_sym], nrefs_sym)); + res->cfo_hz = phase / (2.0f * (float)M_PI * 0.0005f); + } else { + res->cfo_hz = NAN; + } + // Calculate time alignment error float ta_err = 0.0f; if (meas_ta_en) { diff --git a/lib/src/phy/ch_estimation/csi_rs.c b/lib/src/phy/ch_estimation/csi_rs.c index 8aff62419..1b6dbd619 100644 --- a/lib/src/phy/ch_estimation/csi_rs.c +++ b/lib/src/phy/ch_estimation/csi_rs.c @@ -121,7 +121,7 @@ uint32_t csi_rs_cinit(const srslte_carrier_nr_t* carrier, const srslte_csi_rs_nzp_resource_t* resource, uint32_t l) { - uint32_t n = slot_cfg->idx % SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology); + uint32_t n = SRSLTE_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx); uint32_t n_id = resource->scrambling_id; return ((SRSLTE_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id; diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index 0ba5b4c48..1dce054f9 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -265,7 +265,7 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q, } // Measure CFO - res->cfo = NAN; // Not implemented + res->cfo_hz = NAN; // Not implemented // Do averaging here // ... Not implemented @@ -298,7 +298,7 @@ static uint32_t dmrs_pucch_format2_cinit(const srslte_carrier_nr_t* car const srslte_slot_cfg_t* slot, uint32_t l) { - uint64_t n = slot->idx; + uint64_t n = SRSLTE_SLOT_NR_MOD(carrier->numerology, slot->idx); uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id; return SRSLTE_SEQUENCE_MOD((((SRSLTE_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 17UL) + 2UL * n_id); diff --git a/lib/src/phy/ch_estimation/dmrs_sch.c b/lib/src/phy/ch_estimation/dmrs_sch.c index b3df3b020..6f381c651 100644 --- a/lib/src/phy/ch_estimation/dmrs_sch.c +++ b/lib/src/phy/ch_estimation/dmrs_sch.c @@ -460,8 +460,6 @@ static uint32_t srslte_dmrs_sch_seed(const srslte_carrier_nr_t* carrier, { const srslte_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs; - slot_idx = slot_idx % SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology); - // Calculate scrambling IDs uint32_t n_id = carrier->id; uint32_t n_scid = (grant->n_scid) ? 1 : 0; @@ -584,8 +582,8 @@ int srslte_dmrs_sch_put_sf(srslte_dmrs_sch_t* q, // Iterate symbols for (uint32_t i = 0; i < nof_symbols; i++) { - uint32_t l = symbols[i]; // Symbol index inside the slot - uint32_t slot_idx = slot_cfg->idx; // Slot index in the frame + uint32_t l = symbols[i]; // Symbol index inside the slot + uint32_t slot_idx = SRSLTE_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx); // Slot index in the frame uint32_t cinit = srslte_dmrs_sch_seed(&q->carrier, pdsch_cfg, grant, slot_idx, l); srslte_dmrs_sch_put_symbol(q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l]); @@ -708,7 +706,8 @@ int srslte_dmrs_sch_estimate(srslte_dmrs_sch_t* q, for (uint32_t i = 0; i < nof_symbols; i++) { uint32_t l = symbols[i]; // Symbol index inside the slot - uint32_t cinit = srslte_dmrs_sch_seed(&q->carrier, pdsch_cfg, grant, slot_cfg->idx, l); + uint32_t cinit = srslte_dmrs_sch_seed( + &q->carrier, pdsch_cfg, grant, SRSLTE_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), l); nof_pilots_x_symbol = srslte_dmrs_sch_get_symbol( q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]); diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 295bd61f0..952f04799 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -155,3 +155,49 @@ float srslte_symbol_distance_s(uint32_t l0, uint32_t l1, uint32_t numerology) // Return symbol distance in microseconds return (N << numerology) * SRSLTE_LTE_TS; } + +bool srslte_tdd_nr_is_dl(const srslte_tdd_config_nr_t* cfg, uint32_t numerology, uint32_t slot_idx) +{ + if (cfg == NULL) { + return false; + } + + // Calculate slot index within the TDD overall period + uint32_t slot_x_ms = 1U << numerology; // Number of slots per millisecond + uint32_t period_sum = (cfg->pattern1.period_ms + cfg->pattern2.period_ms) * slot_x_ms; // Total perdiod sum + uint32_t slot_idx_period = slot_idx % period_sum; // Slot index within the period + + // Select pattern + const srslte_tdd_pattern_t* pattern = &cfg->pattern1; + if ((slot_idx_period >= cfg->pattern1.period_ms * slot_x_ms)) { + pattern = &cfg->pattern2; + slot_idx_period -= cfg->pattern1.period_ms * slot_x_ms; // Remove pattern 1 offset + } + + return (slot_idx_period < pattern->nof_dl_slots || + (slot_idx_period == pattern->nof_dl_slots && pattern->nof_dl_symbols != 0)); +} + +bool srslte_tdd_nr_is_ul(const srslte_tdd_config_nr_t* cfg, uint32_t numerology, uint32_t slot_idx) +{ + if (cfg == NULL) { + return false; + } + + // Calculate slot index within the TDD overall period + uint32_t slot_x_ms = 1U << numerology; // Number of slots per millisecond + uint32_t period_sum = (cfg->pattern1.period_ms + cfg->pattern2.period_ms) * slot_x_ms; // Total perdiod sum + uint32_t slot_idx_period = slot_idx % period_sum; // Slot index within the period + + // Select pattern + const srslte_tdd_pattern_t* pattern = &cfg->pattern1; + if ((slot_idx_period >= cfg->pattern1.period_ms * slot_x_ms)) { + pattern = &cfg->pattern2; + slot_idx_period -= cfg->pattern1.period_ms * slot_x_ms; // Remove pattern 1 offset + } + + // Calculate slot in which UL starts + uint32_t start_ul = (pattern->period_ms * slot_x_ms - pattern->nof_ul_slots) - 1; + + return (slot_idx_period > start_ul || (slot_idx_period == start_ul && pattern->nof_ul_symbols != 0)); +} diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c index 730e97ad0..e27a58262 100644 --- a/lib/src/phy/phch/dci_nr.c +++ b/lib/src/phy/phch/dci_nr.c @@ -799,7 +799,7 @@ static int dci_nr_format_1_0_to_str(const srslte_dci_dl_nr_t* dci, char* str, ui // Downlink assignment index – 2 bits if (dci->rnti_type == srslte_rnti_type_c || dci->rnti_type == srslte_rnti_type_tc) { - len = srslte_print_check(str, str_len, len, "sii=%d ", dci->sii); + len = srslte_print_check(str, str_len, len, "dai=%d ", dci->dai); } // TPC command for scheduled PUCCH – 2 bits diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index 7893639cd..dc9500df2 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -37,16 +37,17 @@ /** * @brief Recursive Y_p_n function */ -static uint32_t srslte_pdcch_calculate_Y_p_n(uint32_t coreset_id, uint16_t rnti, int n) +static uint32_t srslte_pdcch_calculate_Y_p_n(uint32_t coreset_id, uint16_t rnti, uint32_t n) { static const uint32_t A_p[3] = {39827, 39829, 39839}; const uint32_t D = 65537; - if (n < 0) { - return rnti; + uint32_t Y_p_n = (uint32_t)rnti; + for (uint32_t i = 0; i <= n; i++) { + Y_p_n = (A_p[coreset_id % 3] * Y_p_n) % D; } - return (A_p[coreset_id % 3] * srslte_pdcch_calculate_Y_p_n(coreset_id, rnti, n - 1)) % D; + return Y_p_n; } /** diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index 24c353c92..df1e3e3fa 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -685,13 +685,10 @@ static uint32_t srslte_pdsch_nr_grant_info(const srslte_sch_cfg_nr_t* cfg, uint32_t len = 0; len = srslte_print_check(str, str_len, len, "rnti=0x%x", grant->rnti); - char freq_str[SRSLTE_MAX_PRB_NR + 1] = {}; - for (uint32_t i = 0, nof_prb = 0; i < SRSLTE_MAX_PRB_NR && nof_prb < grant->nof_prb; i++) { + uint32_t first_prb = SRSLTE_MAX_PRB_NR; + for (uint32_t i = 0; i < SRSLTE_MAX_PRB_NR && first_prb == SRSLTE_MAX_PRB_NR; i++) { if (grant->prb_idx[i]) { - freq_str[i] = '1'; - nof_prb++; - } else { - freq_str[i] = '0'; + first_prb = i; } } @@ -699,9 +696,10 @@ static uint32_t srslte_pdsch_nr_grant_info(const srslte_sch_cfg_nr_t* cfg, len = srslte_print_check(str, str_len, len, - ",k0=%d,freq=%s,symb=%d:%d,mapping=%s", + ",k0=%d,prb=%d:%d,symb=%d:%d,mapping=%s", grant->k, - freq_str, + first_prb, + grant->nof_prb, grant->S, grant->L, srslte_sch_mapping_type_to_str(grant->mapping)); diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 72cc40859..fa26b28da 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -80,7 +80,7 @@ int srslte_pucch_nr_alpha_idx(const srslte_carrier_nr_t* carrier, } // Compute number of slot - uint32_t n_slot = slot->idx % SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology); + uint32_t n_slot = SRSLTE_SLOT_NR_MOD(carrier->numerology, slot->idx); // Generate pseudo-random sequence uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->id; diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 6f7f27643..02cd751d5 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -524,6 +524,11 @@ uint32_t srslte_pusch_rx_info(srslte_pusch_cfg_t* cfg, len = srslte_print_check(str, str_len, len, ", ta=%.1f us", chest_res->ta_us); } + // Append CFO information if available + if (!isnan(chest_res->cfo_hz)) { + len = srslte_print_check(str, str_len, len, ", cfo=%.1f hz", chest_res->cfo_hz); + } + // Append EVM measurement if available if (cfg->meas_evm_en) { len = srslte_print_check(str, str_len, len, ", evm=%.1f %%", res->evm * 100); diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index 0a8f5bcaa..1c94c5463 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -1246,13 +1246,10 @@ static uint32_t srslte_pusch_nr_grant_info(const srslte_sch_cfg_nr_t* cfg, uint32_t len = 0; len = srslte_print_check(str, str_len, len, "rnti=0x%x", grant->rnti); - char freq_str[SRSLTE_MAX_PRB_NR + 1] = {}; - for (uint32_t i = 0, nof_prb = 0; i < SRSLTE_MAX_PRB_NR && nof_prb < grant->nof_prb; i++) { + uint32_t first_prb = SRSLTE_MAX_PRB_NR; + for (uint32_t i = 0; i < SRSLTE_MAX_PRB_NR && first_prb == SRSLTE_MAX_PRB_NR; i++) { if (grant->prb_idx[i]) { - freq_str[i] = '1'; - nof_prb++; - } else { - freq_str[i] = '0'; + first_prb = i; } } @@ -1260,9 +1257,10 @@ static uint32_t srslte_pusch_nr_grant_info(const srslte_sch_cfg_nr_t* cfg, len = srslte_print_check(str, str_len, len, - ",k2=%d,freq=%s,S=%d,L=%d,mapping=%s", + ",k2=%d,prb=%d:%d,S=%d,L=%d,mapping=%s", grant->k, - freq_str, + first_prb, + grant->nof_prb, grant->S, grant->L, srslte_sch_mapping_type_to_str(grant->mapping)); @@ -1293,6 +1291,10 @@ uint32_t srslte_pusch_nr_rx_info(const srslte_pusch_nr_t* q, { uint32_t len = 0; + if (q == NULL || cfg == NULL || grant == NULL || str == NULL || str_len == 0) { + return 0; + } + len += srslte_pusch_nr_grant_info(cfg, grant, &str[len], str_len - len); if (q->evm_buffer != NULL) { @@ -1311,6 +1313,11 @@ uint32_t srslte_pusch_nr_rx_info(const srslte_pusch_nr_t* q, } if (res != NULL) { + srslte_uci_data_nr_t uci_data = {}; + uci_data.cfg = cfg->uci; + uci_data.value = res[0].uci; + len += srslte_uci_nr_info(&uci_data, &str[len], str_len - len); + len = srslte_print_check(str, str_len, len, ",crc={", 0); for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (grant->tb[i].enabled) { @@ -1335,13 +1342,25 @@ uint32_t srslte_pusch_nr_rx_info(const srslte_pusch_nr_t* q, uint32_t srslte_pusch_nr_tx_info(const srslte_pusch_nr_t* q, const srslte_sch_cfg_nr_t* cfg, const srslte_sch_grant_nr_t* grant, + const srslte_uci_value_nr_t* uci_value, char* str, uint32_t str_len) { uint32_t len = 0; + if (q == NULL || cfg == NULL || grant == NULL || str == NULL || str_len == 0) { + return 0; + } + len += srslte_pusch_nr_grant_info(cfg, grant, &str[len], str_len - len); + if (uci_value != NULL) { + srslte_uci_data_nr_t uci_data = {}; + uci_data.cfg = cfg->uci; + uci_data.value = *uci_value; + len += srslte_uci_nr_info(&uci_data, &str[len], str_len - len); + } + if (q->meas_time_en) { len = srslte_print_check(str, str_len, len, ", t=%d us", q->meas_time_us); } diff --git a/lib/src/phy/phch/ra_dl.c b/lib/src/phy/phch/ra_dl.c index e72aae7d2..911eb984d 100644 --- a/lib/src/phy/phch/ra_dl.c +++ b/lib/src/phy/phch/ra_dl.c @@ -163,7 +163,7 @@ uint32_t ra_re_x_prb(const srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, uint32_t /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 * Decode grant->type?_alloc to grant - * This function only reads grant->type?_alloc and grant->alloc_type fields. + * This function only reads dci->type?_alloc (e.g. rbg_bitmask, mode, riv) and dci->alloc_type fields. * This function only writes grant->prb_idx and grant->nof_prb. */ /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index b13df3846..6e88500a1 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -20,6 +20,7 @@ */ #include "srslte/phy/phch/ra_nr.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/pdsch_nr.h" #include "srslte/phy/phch/ra_dl_nr.h" #include "srslte/phy/phch/ra_ul_nr.h" @@ -35,6 +36,8 @@ typedef struct { #define RA_NR_MCS_SIZE_TABLE2 28 #define RA_NR_MCS_SIZE_TABLE3 29 #define RA_NR_TBS_SIZE_TABLE 93 +#define RA_NR_BETA_OFFSET_HARQACK_SIZE 32 +#define RA_NR_BETA_OFFSET_CSI_SIZE 32 #define RA_NR_READ_TABLE(N) \ static double srslte_ra_nr_R_from_mcs_table##N(uint32_t mcs_idx) \ @@ -117,6 +120,23 @@ static const uint32_t ra_nr_tbs_table[RA_NR_TBS_SIZE_TABLE] = { 1192, 1224, 1256, 1288, 1320, 1352, 1416, 1480, 1544, 1608, 1672, 1736, 1800, 1864, 1928, 2024, 2088, 2152, 2216, 2280, 2408, 2472, 2536, 2600, 2664, 2728, 2792, 2856, 2976, 3104, 3240, 3368, 3496, 3624, 3752, 3824}; +/** + * TS 38.213 V15.10.0 Table 9.3-1: Mapping of beta_offset values for HARQ-ACK information and the index signalled by + * higher layers + */ +static const float ra_nr_beta_offset_ack_table[RA_NR_BETA_OFFSET_HARQACK_SIZE] = { + 1.000f, 2.000f, 2.500f, 3.125f, 4.000f, 5.000f, 6.250f, 8.000f, 10.000f, 12.625f, 15.875f, + 20.000f, 31.000f, 50.000f, 80.000f, 126.000f, NAN, NAN, NAN, NAN, NAN, NAN, + NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN}; + +/** + * TS 38.213 V15.10.0 Table 9.3-2: Mapping of beta_offset values for CSI and the index signalled by higher layers + */ +static const float ra_nr_beta_offset_csi_table[RA_NR_BETA_OFFSET_HARQACK_SIZE] = { + 1.125f, 1.250f, 1.375f, 1.625f, 1.750f, 2.000f, 2.250f, 2.500f, 2.875f, 3.125f, 3.500f, + 4.000f, 5.000f, 6.250f, 8.000f, 10.000f, 12.625f, 15.875f, 20.000f, NAN, NAN, NAN, + NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN}; + typedef enum { ra_nr_table_1 = 0, ra_nr_table_2, ra_nr_table_3 } ra_nr_table_t; static ra_nr_table_t ra_nr_select_table_pusch_noprecoding(srslte_mcs_table_t mcs_table, @@ -645,3 +665,94 @@ int srslte_ra_ul_dci_to_grant_nr(const srslte_carrier_nr_t* carrier, return SRSLTE_SUCCESS; } + +/* + * Implements clauses related to HARQ-ACK beta offset selection from the section `9.3 UCI reporting in physical uplink + * shared channel` + */ +static float ra_ul_beta_offset_ack_semistatic(const srslte_beta_offsets_t* beta_offsets, + const srslte_uci_cfg_nr_t* uci_cfg) +{ + // Select Beta Offset index from the number of HARQ-ACK bits + uint32_t beta_offset_index = beta_offsets->ack_index1; + if (uci_cfg->o_ack > 11) { + beta_offset_index = beta_offsets->ack_index3; + } else if (uci_cfg->o_ack > 2) { + beta_offset_index = beta_offsets->ack_index1; + } + + // Protect table boundary + if (beta_offset_index > RA_NR_BETA_OFFSET_HARQACK_SIZE) { + ERROR("Beta offset index for HARQ-ACK (%d) for O_ack=%d exceeds table size (%d)", + beta_offset_index, + uci_cfg->o_ack, + RA_NR_BETA_OFFSET_HARQACK_SIZE); + return NAN; + } + + // Select beta offset from Table 9.3-1 + return ra_nr_beta_offset_ack_table[beta_offset_index]; +} + +/* + * Implements clauses related to HARQ-ACK beta offset selection from the section `9.3 UCI reporting in physical uplink + * shared channel` + */ +static float ra_ul_beta_offset_csi_semistatic(const srslte_beta_offsets_t* beta_offsets, + const srslte_uci_cfg_nr_t* uci_cfg, + bool part2) +{ + // Calculate number of CSI bits; CSI part 2 is not supported. + uint32_t O_csi = part2 ? 0 : srslte_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); + + // Select Beta Offset index from the number of HARQ-ACK bits + uint32_t beta_offset_index = part2 ? beta_offsets->csi2_index1 : beta_offsets->csi1_index1; + if (O_csi > 11) { + beta_offset_index = part2 ? beta_offsets->csi2_index2 : beta_offsets->csi1_index2; + } + + // Protect table boundary + if (beta_offset_index > RA_NR_BETA_OFFSET_CSI_SIZE) { + ERROR("Beta offset index for CSI (%d) for O_csi=%d exceeds table size (%d)", + beta_offset_index, + O_csi, + RA_NR_BETA_OFFSET_CSI_SIZE); + return NAN; + } + + // Select beta offset from Table 9.3-1 + return ra_nr_beta_offset_csi_table[beta_offset_index]; +} + +int srslte_ra_ul_set_grant_uci_nr(const srslte_sch_hl_cfg_nr_t* pusch_hl_cfg, + const srslte_uci_cfg_nr_t* uci_cfg, + srslte_sch_cfg_nr_t* pusch_cfg) +{ + // Select beta offsets + pusch_cfg->beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); + if (!isnormal(pusch_cfg->beta_harq_ack_offset)) { + return SRSLTE_ERROR; + } + + pusch_cfg->beta_csi_part1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); + if (!isnormal(pusch_cfg->beta_csi_part1_offset)) { + return SRSLTE_ERROR; + } + + pusch_cfg->beta_csi_part2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); + if (!isnormal(pusch_cfg->beta_csi_part2_offset)) { + return SRSLTE_ERROR; + } + + // pusch_cfg->beta_csi_part2_offset = pusch_hl_cfg->beta_offset_csi2; + pusch_cfg->scaling = pusch_hl_cfg->scaling; + if (!isnormal(pusch_cfg->scaling)) { + ERROR("Invalid Scaling (%f)", pusch_cfg->scaling); + return SRSLTE_ERROR; + } + + // Copy UCI configuration + pusch_cfg->uci = *uci_cfg; + + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index b8254795c..401186c53 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -202,6 +202,63 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequenc return A; } +static int uci_nr_pack_ack_sr_csi(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) +{ + int A = 0; + + // Append ACK bits + srslte_vec_u8_copy(&sequence[A], value->ack, cfg->o_ack); + A += cfg->o_ack; + + // Append SR bits + uint8_t* bits = &sequence[A]; + srslte_bit_unpack(value->sr, &bits, cfg->o_sr); + A += cfg->o_sr; + + // Append CSI bits + int n = srslte_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, bits, SRSLTE_UCI_NR_MAX_NOF_BITS - A); + if (n < SRSLTE_SUCCESS) { + ERROR("Packing CSI part 1"); + return SRSLTE_ERROR; + } + A += n; + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_TX("Packed UCI bits: "); + srslte_vec_fprint_byte(stdout, sequence, A); + } + + return A; +} + +static int uci_nr_unpack_ack_sr_csi(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) +{ + int A = 0; + + // Append ACK bits + srslte_vec_u8_copy(value->ack, &sequence[A], cfg->o_ack); + A += cfg->o_ack; + + // Append SR bits + uint8_t* bits = &sequence[A]; + value->sr = srslte_bit_pack(&bits, cfg->o_sr); + A += cfg->o_sr; + + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + UCI_NR_INFO_RX("Unpacked UCI bits: "); + srslte_vec_fprint_byte(stdout, sequence, A); + } + + // Append CSI bits + int n = srslte_csi_part1_unpack(cfg->csi, cfg->nof_csi, bits, SRSLTE_UCI_NR_MAX_NOF_BITS - A, value->csi); + if (n < SRSLTE_SUCCESS) { + ERROR("Packing CSI part 1"); + return SRSLTE_ERROR; + } + + return A; +} + static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) { int o_csi = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi); @@ -236,8 +293,7 @@ static int uci_nr_pack_pucch(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_va } // 6.3.1.1.3 HARQ-ACK/SR and CSI - ERROR("HARQ-ACK/SR and CSI encoding are not implemented"); - return SRSLTE_ERROR; + return uci_nr_pack_ack_sr_csi(cfg, value, sequence); } static int uci_nr_unpack_pucch(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) @@ -256,8 +312,7 @@ static int uci_nr_unpack_pucch(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence } // 6.3.1.1.3 HARQ-ACK/SR and CSI - ERROR("HARQ-ACK/SR and CSI encoding are not implemented"); - return SRSLTE_ERROR; + return uci_nr_unpack_ack_sr_csi(cfg, sequence, value); } static int uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint8_t* o, uint32_t E) @@ -1099,7 +1154,7 @@ static int uci_nr_pusch_Q_prime_csi1(const srslte_uci_nr_pusch_cfg_t* cfg, uint3 return SRSLTE_ERROR; } - uint32_t M_uci_sum = 0; + uint32_t M_uci_sum = 0; for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) { M_uci_sum += cfg->M_uci_sc[l]; } diff --git a/lib/src/phy/rf/rf_uhd_generic.h b/lib/src/phy/rf/rf_uhd_generic.h index aa982738a..12f397b1e 100644 --- a/lib/src/phy/rf/rf_uhd_generic.h +++ b/lib/src/phy/rf/rf_uhd_generic.h @@ -30,20 +30,30 @@ private: uhd::usrp::multi_usrp::sptr usrp = nullptr; const uhd::fs_path TREE_DBOARD_RX_FRONTEND_NAME = "/mboards/0/dboards/A/rx_frontends/A/name"; const std::chrono::milliseconds FE_RX_RESET_SLEEP_TIME_MS = std::chrono::milliseconds(2000UL); - uhd::stream_args_t stream_args; - double lo_freq_tx_hz = 0.0; - double lo_freq_rx_hz = 0.0; + uhd::stream_args_t stream_args = {}; + double lo_freq_tx_hz = 0.0; + double lo_freq_rx_hz = 0.0; uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) override { // Destroy any previous USRP instance usrp = nullptr; + Debug("Making USRP object with args '" << dev_addr.to_string() << "'"); + UHD_SAFE_C_SAVE_ERROR(this, usrp = uhd::usrp::multi_usrp::make(dev_addr);) } - uhd_error set_tx_subdev(const std::string& string) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_subdev_spec(string);) } - uhd_error set_rx_subdev(const std::string& string) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_subdev_spec(string);) } + uhd_error set_tx_subdev(const std::string& string) + { + Info("Setting tx_subdev_spec to '" << string << "'"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_subdev_spec(string);) + } + uhd_error set_rx_subdev(const std::string& string) + { + Info("Setting rx_subdev_spec to '" << string << "'"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_subdev_spec(string);) + } uhd_error test_ad936x_device(uint32_t nof_channels) { @@ -113,8 +123,14 @@ private: } public: - rf_uhd_generic(){}; - virtual ~rf_uhd_generic(){}; + rf_uhd_generic() { Info("RF UHD Generic instance constructed"); } + virtual ~rf_uhd_generic() + { + rx_stream = nullptr; + tx_stream = nullptr; + usrp = nullptr; + Debug("RF UHD closed Ok"); + } uhd_error usrp_make(const uhd::device_addr_t& dev_addr_, uint32_t nof_channels) override { uhd::device_addr_t dev_addr = dev_addr_; @@ -163,7 +179,6 @@ public: // Set transmitter subdev spec if specified if (not tx_subdev.empty()) { - printf("Setting tx_subdev_spec to '%s'\n", tx_subdev.c_str()); err = set_tx_subdev(tx_subdev); if (err != UHD_ERROR_NONE) { return err; @@ -172,7 +187,6 @@ public: // Set receiver subdev spec if specified if (not rx_subdev.empty()) { - printf("Setting rx_subdev_spec to '%s'\n", rx_subdev.c_str()); err = set_rx_subdev(tx_subdev); if (err != UHD_ERROR_NONE) { return err; @@ -256,6 +270,7 @@ public: } uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) override { + Debug("Setting Time at next PPS..."); UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_unknown_pps(timespec);) } uhd_error get_time_now(uhd::time_spec_t& timespec) override @@ -264,10 +279,11 @@ public: } uhd_error set_sync_source(const std::string& source) override { + Debug("Setting PPS source to '" << source << "'"); #if UHD_VERSION < 3140099 - UHD_SAFE_C_SAVE_ERROR(this, usrp->set_clock_source(source); usrp->set_time_source(source);) + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_clock_source(source); usrp->set_time_source(source);) #else - UHD_SAFE_C_SAVE_ERROR(this, usrp->set_sync_source(source, source);) + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_sync_source(source, source);) #endif } uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range) override @@ -276,38 +292,61 @@ public: } uhd_error set_master_clock_rate(double rate) override { + Debug("Setting master clock rate to " << rate / 1e6 << " MHz"); UHD_SAFE_C_SAVE_ERROR(this, usrp->set_master_clock_rate(rate);) } - uhd_error set_rx_rate(double rate) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_rate(rate);) } - uhd_error set_tx_rate(double rate) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_rate(rate);) } + uhd_error set_rx_rate(double rate) override + { + Debug("Setting Rx Rate to " << rate / 1e6 << "MHz"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_rate(rate);) + } + uhd_error set_tx_rate(double rate) override + { + Debug("Setting Tx Rate to " << rate / 1e6 << "MHz"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_rate(rate);) + } uhd_error set_command_time(const uhd::time_spec_t& timespec) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_command_time(timespec);) } uhd_error get_rx_stream(size_t& max_num_samps) override { - UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr; rx_stream = usrp->get_rx_stream(stream_args); - max_num_samps = rx_stream->get_max_num_samps(); - if (max_num_samps == 0UL) { - last_error = "The maximum number of receive samples is zero."; - return UHD_ERROR_VALUE; - }) + Debug("Creating Rx stream"); + UHD_SAFE_C_SAVE_ERROR( + this, rx_stream = nullptr; rx_stream = usrp->get_rx_stream(stream_args); + max_num_samps = rx_stream->get_max_num_samps(); + if (max_num_samps == 0UL) { + last_error = "The maximum number of receive samples is zero."; + return UHD_ERROR_VALUE; + }) } uhd_error get_tx_stream(size_t& max_num_samps) override { - UHD_SAFE_C_SAVE_ERROR(this, tx_stream = nullptr; tx_stream = usrp->get_tx_stream(stream_args); - max_num_samps = tx_stream->get_max_num_samps(); - if (max_num_samps == 0UL) { - last_error = "The maximum number of transmit samples is zero."; - return UHD_ERROR_VALUE; - }) + Debug("Creating Tx stream"); + UHD_SAFE_C_SAVE_ERROR( + this, tx_stream = nullptr; tx_stream = usrp->get_tx_stream(stream_args); + max_num_samps = tx_stream->get_max_num_samps(); + if (max_num_samps == 0UL) { + last_error = "The maximum number of transmit samples is zero."; + return UHD_ERROR_VALUE; + }) + } + uhd_error set_tx_gain(size_t ch, double gain) override + { + Debug("Setting channel " << ch << " Tx gain to " << gain << " dB"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_gain(gain, ch);) + } + uhd_error set_rx_gain(size_t ch, double gain) override + { + Debug("Setting channel " << ch << " Rx gain to " << gain << " dB"); + UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_gain(gain, ch);) } - uhd_error set_tx_gain(size_t ch, double gain) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_gain(gain, ch);) } - uhd_error set_rx_gain(size_t ch, double gain) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_gain(gain, ch);) } uhd_error get_rx_gain(double& gain) override { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_rx_gain();) } uhd_error get_tx_gain(double& gain) override { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_tx_gain();) } uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) override { + Debug("Setting channel " << ch << " Tx frequency to " << target_freq / 1e6 << " MHz"); + // Create Tune request uhd::tune_request_t tune_request(target_freq); @@ -323,6 +362,7 @@ public: } uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) override { + Debug("Setting channel " << ch << " Rx frequency to " << target_freq / 1e6 << " MHz"); // Create Tune request uhd::tune_request_t tune_request(target_freq); diff --git a/lib/src/phy/rf/rf_uhd_imp.cc b/lib/src/phy/rf/rf_uhd_imp.cc index 28c3f4c25..87e1b304c 100644 --- a/lib/src/phy/rf/rf_uhd_imp.cc +++ b/lib/src/phy/rf/rf_uhd_imp.cc @@ -120,17 +120,21 @@ static const std::chrono::milliseconds RF_UHD_IMP_ASYNCH_MSG_SLEEP_MS = std::chr static const uint32_t RF_UHD_IMP_MAX_RX_TRIALS = 100; struct rf_uhd_handler_t { + size_t id; + std::string devname; std::shared_ptr uhd = nullptr; - srslte_rf_info_t info; - size_t rx_nof_samples = 0; - size_t tx_nof_samples = 0; - double tx_rate = 1.92e6; - double rx_rate = 1.92e6; - bool dynamic_master_rate = true; - uint32_t nof_rx_channels = 0; - uint32_t nof_tx_channels = 0; + srslte_rf_info_t info; + size_t rx_nof_samples = 0; + size_t tx_nof_samples = 0; + double tx_rate = 1.92e6; + double rx_rate = 1.92e6; + bool dynamic_master_rate = true; + uint32_t nof_rx_channels = 0; + uint32_t nof_tx_channels = 0; + std::array tx_freq = {}; + std::array rx_freq = {}; srslte_rf_error_handler_t uhd_error_handler = nullptr; void* uhd_error_handler_arg = nullptr; @@ -152,6 +156,10 @@ struct rf_uhd_handler_t { #endif /* HAVE_ASYNC_THREAD */ }; +// Store UHD Handler instances as shared pointer to avoid new/delete +static std::map > rf_uhd_map; +static size_t uhd_handler_counter = 0; + #if UHD_VERSION < 31100 static void (*handler)(const char*); @@ -286,10 +294,8 @@ static void* async_thread(void* h) } #endif -static inline void uhd_free(rf_uhd_handler_t* h) +static inline void uhd_free(rf_uhd_handler_t* handler) { - rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; - // NULL handler, return if (handler == nullptr) { return; @@ -303,7 +309,8 @@ static inline void uhd_free(rf_uhd_handler_t* h) } #endif - delete handler; + // Erase element from MAP + rf_uhd_map.erase(handler->id); } void rf_uhd_suppress_stdout(void* h) @@ -462,6 +469,7 @@ const char* rf_uhd_devname(void* h) bool rf_uhd_rx_wait_lo_locked(void* h) { rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; + Debug("Waiting for Rx LO Locked"); // wait for clock source to lock std::string sensor_name = "lo_locked"; @@ -528,7 +536,15 @@ int rf_uhd_stop_rx_stream(void* h) rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; std::unique_lock lock(handler->rx_mutex); - return rf_uhd_stop_rx_stream_unsafe(handler); + if (rf_uhd_stop_rx_stream_unsafe(handler) < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Make sure the Rx stream is flushed + lock.unlock(); // Flush has its own lock + rf_uhd_flush_buffer(h); + + return SRSLTE_SUCCESS; } void rf_uhd_flush_buffer(void* h) @@ -569,21 +585,8 @@ int rf_uhd_open(char* args, void** h) return rf_uhd_open_multi(args, h, 1); } -int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) +static int uhd_init(rf_uhd_handler_t* handler, char* args, uint32_t nof_channels) { - // Check valid handler pointer - if (h == nullptr) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - if (nof_channels > SRSLTE_MAX_CHANNELS) { - ERROR("Error opening UHD: maximum number of channels exceeded (%d>%d)", nof_channels, SRSLTE_MAX_CHANNELS); - return SRSLTE_ERROR; - } - - rf_uhd_handler_t* handler = new rf_uhd_handler_t; - *h = handler; - // Disable fast-path (U/L/O) messages setenv("UHD_LOG_FASTPATH_DISABLE", "1", 0); @@ -685,6 +688,32 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) } handler->current_master_clock = device_addr.cast("master_clock_rate", 0.0); + // Parse default frequencies + for (uint32_t i = 0; i < nof_channels; i++) { + // Parse Tx frequency + if (i == 0 and device_addr.has_key("tx_freq")) { + handler->tx_freq[i] = device_addr.cast("tx_freq", handler->tx_freq[i]); + device_addr.pop("tx_freq"); + } else { + std::string key = "tx_freq" + std::to_string(i); + if (device_addr.has_key(key)) { + handler->tx_freq[i] = device_addr.cast(key, handler->tx_freq[i]); + device_addr.pop(key); + } + } + + // Parse Rx frequency + if (i == 0 and device_addr.has_key("rx_freq")) { + handler->rx_freq[i] = device_addr.cast("rx_freq", handler->rx_freq[i]); + } else { + std::string key = "rx_freq" + std::to_string(i); + if (device_addr.has_key(key)) { + handler->rx_freq[i] = device_addr.cast("rx_freq" + std::to_string(i), handler->rx_freq[i]); + device_addr.pop(key); + } + } + } + // Set dynamic master clock rate configuration if (device_addr.has_key("type")) { handler->dynamic_master_rate = RH_UHD_IMP_FIX_MASTER_CLOCK_RATE_DEVICE_LIST.count(device_addr["type"]) == 0; @@ -715,7 +744,6 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) // Make USRP if (handler->uhd->usrp_make(device_addr, nof_channels) != UHD_ERROR_NONE) { print_usrp_error(handler); - uhd_free(handler); return SRSLTE_ERROR; } @@ -786,6 +814,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) handler->nof_rx_channels = nof_channels; handler->nof_tx_channels = nof_channels; + // Set default Tx/Rx rates if (handler->uhd->set_rx_rate(handler->rx_rate) != UHD_ERROR_NONE) { print_usrp_error(handler); return SRSLTE_ERROR; @@ -795,6 +824,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) return SRSLTE_ERROR; } + // Reset timestamps if (nof_channels > 1 and clock_src != "gpsdo") { handler->uhd->set_time_unknown_pps(uhd::time_spec_t()); } @@ -809,6 +839,27 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) return SRSLTE_ERROR; } + // Tune LOs if the default frequency is provided + bool require_wait_rx_lock = false; + for (uint32_t i = 0; i < nof_channels; i++) { + if (std::isnormal(handler->rx_freq[i])) { + if (handler->uhd->set_rx_freq(i, handler->rx_freq[i], handler->rx_freq[i]) != UHD_ERROR_NONE) { + print_usrp_error(handler); + return SRSLTE_ERROR; + } + rf_uhd_rx_wait_lo_locked(handler); + require_wait_rx_lock = true; + } + } + for (uint32_t i = 0; i < nof_channels; i++) { + if (std::isnormal(handler->tx_freq[i])) { + if (handler->uhd->set_tx_freq(i, handler->tx_freq[i], handler->tx_freq[i]) != UHD_ERROR_NONE) { + print_usrp_error(handler); + return SRSLTE_ERROR; + } + } + } + // Populate RF device info uhd::gain_range_t tx_gain_range; uhd::gain_range_t rx_gain_range; @@ -841,6 +892,37 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) return SRSLTE_SUCCESS; } +int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) +{ + // Check valid handler pointer + if (h == nullptr) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (nof_channels > SRSLTE_MAX_CHANNELS) { + ERROR("Error opening UHD: maximum number of channels exceeded (%d>%d)", nof_channels, SRSLTE_MAX_CHANNELS); + return SRSLTE_ERROR; + } + + // Create UHD handler + rf_uhd_map[uhd_handler_counter] = std::make_shared(); + rf_uhd_handler_t* handler = rf_uhd_map[uhd_handler_counter].get(); + handler->id = uhd_handler_counter; + uhd_handler_counter++; + *h = handler; + + // Initialise UHD handler + if (uhd_init(handler, args, nof_channels) < SRSLTE_SUCCESS) { + ERROR("uhd_init failed, freeing..."); + // Free/Close UHD handler properly + uhd_free(handler); + *h = nullptr; + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + int rf_uhd_close(void* h) { // Makes sure Tx is ended @@ -861,7 +943,7 @@ int rf_uhd_close(void* h) static inline void rf_uhd_set_master_clock_rate_unsafe(rf_uhd_handler_t* handler, double rate) { // Set master clock rate if it is allowed and change is required - if (handler->dynamic_master_rate && handler->current_master_clock != rate) { + if (handler->dynamic_master_rate and handler->current_master_clock != rate) { if (handler->uhd->set_master_clock_rate(rate) != UHD_ERROR_NONE) { print_usrp_error(handler); } @@ -1087,44 +1169,61 @@ srslte_rf_info_t* rf_uhd_get_info(void* h) return info; } +static bool rf_uhd_set_freq_ch(rf_uhd_handler_t* handler, uint32_t ch, double& freq, bool is_tx) +{ + double& curr_freq = (is_tx) ? handler->tx_freq[ch] : handler->rx_freq[ch]; + + // Skip if frequency is unchanged + if (round(freq) == round(curr_freq)) { + return false; + } + + // Set frequency + if (is_tx) { + if (handler->uhd->set_tx_freq(ch, freq, curr_freq) != UHD_ERROR_NONE) { + print_usrp_error(handler); + } + } else { + if (handler->uhd->set_rx_freq(ch, freq, curr_freq) != UHD_ERROR_NONE) { + print_usrp_error(handler); + } + } + return true; +} double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq) { + bool require_rx_wait_lo_locked = false; + rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; if (ch < handler->nof_rx_channels) { - if (handler->uhd->set_rx_freq(ch, freq, freq) != UHD_ERROR_NONE) { - print_usrp_error(handler); - return SRSLTE_ERROR; - } + require_rx_wait_lo_locked |= rf_uhd_set_freq_ch(handler, ch, freq, false); } else { for (uint32_t i = 0; i < handler->nof_rx_channels; i++) { - if (handler->uhd->set_rx_freq(i, freq, freq) != UHD_ERROR_NONE) { - print_usrp_error(handler); - return SRSLTE_ERROR; - } + require_rx_wait_lo_locked |= rf_uhd_set_freq_ch(handler, i, freq, false); } } - rf_uhd_rx_wait_lo_locked(handler); - return freq; + + // wait for LO Locked + if (require_rx_wait_lo_locked) { + rf_uhd_rx_wait_lo_locked(handler); + } + + return handler->rx_freq[ch % handler->nof_rx_channels]; } double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq) { rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; if (ch < handler->nof_tx_channels) { - if (handler->uhd->set_tx_freq(ch, freq, freq) != UHD_ERROR_NONE) { - print_usrp_error(handler); - return SRSLTE_ERROR; - } + rf_uhd_set_freq_ch(handler, ch, freq, true); } else { for (uint32_t i = 0; i < handler->nof_tx_channels; i++) { - if (handler->uhd->set_tx_freq(i, freq, freq) != UHD_ERROR_NONE) { - print_usrp_error(handler); - return SRSLTE_ERROR; - } + rf_uhd_set_freq_ch(handler, i, freq, true); } } - return freq; + + return handler->tx_freq[ch % handler->nof_tx_channels]; } void rf_uhd_get_time(void* h, time_t* secs, double* frac_secs) diff --git a/lib/src/phy/rf/rf_uhd_safe.h b/lib/src/phy/rf/rf_uhd_safe.h index 0d4be2ef1..30ade9732 100644 --- a/lib/src/phy/rf/rf_uhd_safe.h +++ b/lib/src/phy/rf/rf_uhd_safe.h @@ -120,17 +120,18 @@ protected: public: std::string last_error; - virtual uhd_error usrp_make(const uhd::device_addr_t& dev_addr, uint32_t nof_channels) = 0; - virtual uhd_error get_mboard_name(std::string& mboard_name) = 0; - virtual uhd_error get_mboard_sensor_names(std::vector& sensors) = 0; - virtual uhd_error get_rx_sensor_names(std::vector& sensors) = 0; - virtual uhd_error get_sensor(const std::string& sensor_name, double& sensor_value) = 0; - virtual uhd_error get_sensor(const std::string& sensor_name, bool& sensor_value) = 0; - virtual uhd_error get_rx_sensor(const std::string& sensor_name, bool& sensor_value) = 0; - virtual uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) = 0; - virtual uhd_error get_time_now(uhd::time_spec_t& timespec) = 0; + virtual uhd_error usrp_make(const uhd::device_addr_t& dev_addr, uint32_t nof_channels) = 0; + virtual uhd_error get_mboard_name(std::string& mboard_name) = 0; + virtual uhd_error get_mboard_sensor_names(std::vector& sensors) = 0; + virtual uhd_error get_rx_sensor_names(std::vector& sensors) = 0; + virtual uhd_error get_sensor(const std::string& sensor_name, double& sensor_value) = 0; + virtual uhd_error get_sensor(const std::string& sensor_name, bool& sensor_value) = 0; + virtual uhd_error get_rx_sensor(const std::string& sensor_name, bool& sensor_value) = 0; + virtual uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) = 0; + virtual uhd_error get_time_now(uhd::time_spec_t& timespec) = 0; uhd_error start_rx_stream(double delay) { + Debug("Starting Rx stream"); uhd::time_spec_t time_spec; uhd_error err = get_time_now(time_spec); if (err != UHD_ERROR_NONE) { @@ -146,7 +147,9 @@ public: } uhd_error stop_rx_stream() { + Debug("Stopping Rx stream"); UHD_SAFE_C_SAVE_ERROR(this, uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + stream_cmd.stream_now = true; rx_stream->issue_stream_cmd(stream_cmd);) } virtual uhd_error set_sync_source(const std::string& source) = 0; @@ -156,15 +159,13 @@ public: virtual uhd_error set_tx_rate(double rate) = 0; virtual uhd_error set_command_time(const uhd::time_spec_t& timespec) = 0; virtual uhd_error get_rx_stream(size_t& max_num_samps) = 0; - virtual uhd_error destroy_rx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) } - virtual uhd_error get_tx_stream(size_t& max_num_samps) = 0; - virtual uhd_error destroy_tx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) } - virtual uhd_error set_tx_gain(size_t ch, double gain) = 0; - virtual uhd_error set_rx_gain(size_t ch, double gain) = 0; - virtual uhd_error get_rx_gain(double& gain) = 0; - virtual uhd_error get_tx_gain(double& gain) = 0; - virtual uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0; - virtual uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0; + virtual uhd_error get_tx_stream(size_t& max_num_samps) = 0; + virtual uhd_error set_tx_gain(size_t ch, double gain) = 0; + virtual uhd_error set_rx_gain(size_t ch, double gain) = 0; + virtual uhd_error get_rx_gain(double& gain) = 0; + virtual uhd_error get_tx_gain(double& gain) = 0; + virtual uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0; + virtual uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0; uhd_error receive(void** buffs, const size_t nsamps_per_buff, uhd::rx_metadata_t& metadata, diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index aa0429cfa..945277926 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -219,39 +219,52 @@ static int ue_dl_nr_find_dci_ncce(srslte_ue_dl_nr_t* q, srslte_pdcch_nr_res_t* pdcch_res, uint32_t coreset_id) { - srslte_dmrs_pdcch_measure_t m = {}; + // Select debug information + srslte_ue_dl_nr_pdcch_info_t* pdcch_info = NULL; + if (q->pdcch_info_count < SRSLTE_MAX_NOF_CANDIDATES_SLOT_NR) { + pdcch_info = &q->pdcch_info[q->pdcch_info_count]; + q->pdcch_info_count++; + } else { + ERROR("The UE does not expect more than %d candidates in this serving cell", SRSLTE_MAX_NOF_CANDIDATES_SLOT_NR); + return SRSLTE_ERROR; + } + SRSLTE_MEM_ZERO(pdcch_info, srslte_ue_dl_nr_pdcch_info_t, 1); + pdcch_info->coreset_id = dci_msg->coreset_id; + pdcch_info->ss_id = dci_msg->search_space; + pdcch_info->location = dci_msg->location; + srslte_dmrs_pdcch_measure_t* m = &pdcch_info->measure; // Measures the PDCCH transmission DMRS - if (srslte_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &dci_msg->location, &m) < SRSLTE_SUCCESS) { + if (srslte_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &dci_msg->location, m) < SRSLTE_SUCCESS) { ERROR("Error getting measure location L=%d, ncce=%d", dci_msg->location.L, dci_msg->location.ncce); return SRSLTE_ERROR; } // If measured correlation is invalid, early return - if (!isnormal(m.norm_corr)) { + if (!isnormal(m->norm_corr)) { INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;", dci_msg->location.L, dci_msg->location.ncce); return SRSLTE_SUCCESS; } // Compare EPRE with threshold - if (m.epre_dBfs < q->pdcch_dmrs_epre_thr) { + if (m->epre_dBfs < q->pdcch_dmrs_epre_thr) { INFO("Discarded PDCCH candidate L=%d;ncce=%d; EPRE is too weak (%.1f<%.1f);", dci_msg->location.L, dci_msg->location.ncce, - m.epre_dBfs, + m->epre_dBfs, q->pdcch_dmrs_epre_thr); return SRSLTE_SUCCESS; } // Compare DMRS correlation with threshold - if (m.norm_corr < q->pdcch_dmrs_corr_thr) { + if (m->norm_corr < q->pdcch_dmrs_corr_thr) { INFO("Discarded PDCCH candidate L=%d;ncce=%d; Correlation is too low (%.1f<%.1f); EPRE=%+.2f; RSRP=%+.2f;", dci_msg->location.L, dci_msg->location.ncce, - m.norm_corr, + m->norm_corr, q->pdcch_dmrs_corr_thr, - m.epre_dBfs, - m.rsrp_dBfs); + m->epre_dBfs, + m->rsrp_dBfs); return SRSLTE_SUCCESS; } @@ -267,6 +280,9 @@ static int ue_dl_nr_find_dci_ncce(srslte_ue_dl_nr_t* q, return SRSLTE_ERROR; } + // Save information + pdcch_info->result = *pdcch_res; + return SRSLTE_SUCCESS; } @@ -290,15 +306,8 @@ static int ue_dl_nr_find_dl_dci_ss(srslte_ue_dl_nr_t* q, const srslte_slot_cfg_t* slot_cfg, const srslte_search_space_t* search_space, uint16_t rnti, - srslte_rnti_type_t rnti_type, - srslte_dci_msg_nr_t* dci_msg_list, - uint32_t nof_dci_msg) + srslte_rnti_type_t rnti_type) { - // Check inputs - if (q == NULL || slot_cfg == NULL || dci_msg_list == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - // Select CORESET uint32_t coreset_id = search_space->coreset_id; if (coreset_id >= SRSLTE_UE_DL_NR_MAX_NOF_CORESET || !q->cfg.coreset_present[coreset_id]) { @@ -313,8 +322,6 @@ static int ue_dl_nr_find_dl_dci_ss(srslte_ue_dl_nr_t* q, return SRSLTE_ERROR; } - uint32_t count = 0; - // Hard-coded values srslte_dci_format_nr_t dci_format = srslte_dci_format_nr_1_0; @@ -326,17 +333,19 @@ static int ue_dl_nr_find_dl_dci_ss(srslte_ue_dl_nr_t* q, } // Iterate all possible aggregation levels - for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && count < nof_dci_msg; L++) { + for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && q->dci_msg_count < SRSLTE_MAX_DCI_MSG_NR; + L++) { // Calculate possible PDCCH DCI candidates uint32_t candidates[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; - int nof_candidates = srslte_pdcch_nr_locations_coreset(coreset, search_space, rnti, L, slot_cfg->idx, candidates); + int nof_candidates = srslte_pdcch_nr_locations_coreset( + coreset, search_space, rnti, L, SRSLTE_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), candidates); if (nof_candidates < SRSLTE_SUCCESS) { ERROR("Error calculating DCI candidate location"); return SRSLTE_ERROR; } // Iterate over the candidates - for (int ncce_idx = 0; ncce_idx < nof_candidates && count < nof_dci_msg; ncce_idx++) { + for (int ncce_idx = 0; ncce_idx < nof_candidates && q->dci_msg_count < SRSLTE_MAX_DCI_MSG_NR; ncce_idx++) { // Set DCI context srslte_dci_msg_nr_t dci_msg = {}; dci_msg.location.L = L; @@ -379,19 +388,19 @@ static int ue_dl_nr_find_dl_dci_ss(srslte_ue_dl_nr_t* q, } // Check if the grant exists already in the message list - if (find_dci_msg(dci_msg_list, count, &dci_msg)) { + if (find_dci_msg(q->dci_msg, q->dci_msg_count, &dci_msg)) { // The same DCI is in the list, keep moving continue; } INFO("Found DCI in L=%d,ncce=%d", dci_msg.location.L, dci_msg.location.ncce); // Append DCI message into the list - dci_msg_list[count] = dci_msg; - count++; + q->dci_msg[q->dci_msg_count] = dci_msg; + q->dci_msg_count++; } } - return (int)count; + return SRSLTE_SUCCESS; } int srslte_ue_dl_nr_find_dl_dci(srslte_ue_dl_nr_t* q, @@ -401,9 +410,6 @@ int srslte_ue_dl_nr_find_dl_dci(srslte_ue_dl_nr_t* q, srslte_dci_dl_nr_t* dci_dl_list, uint32_t nof_dci_msg) { - int count = 0; - srslte_dci_msg_nr_t dci_msg_list[SRSLTE_MAX_DCI_MSG_NR] = {}; - // Check inputs if (q == NULL || slot_cfg == NULL || dci_dl_list == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; @@ -412,45 +418,43 @@ int srslte_ue_dl_nr_find_dl_dci(srslte_ue_dl_nr_t* q, // Limit maximum number of DCI messages to find nof_dci_msg = SRSLTE_MIN(nof_dci_msg, SRSLTE_MAX_DCI_MSG_NR); + // Reset grant and blind search information counters + q->dci_msg_count = 0; + q->pdcch_info_count = 0; + // If the UE looks for a RAR and RA search space is provided, search for it if (q->cfg.ra_search_space_present && rnti_type == srslte_rnti_type_ra) { // Find DCIs in the RA search space - int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type, dci_msg_list, nof_dci_msg); + int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type); if (ret < SRSLTE_SUCCESS) { ERROR("Error searching RAR DCI"); return SRSLTE_ERROR; } - - // Count the found DCIs - count += ret; } else { // Iterate all possible common and UE search spaces - for (uint32_t i = 0; i < SRSLTE_UE_DL_NR_MAX_NOF_SEARCH_SPACE && count < nof_dci_msg; i++) { + for (uint32_t i = 0; i < SRSLTE_UE_DL_NR_MAX_NOF_SEARCH_SPACE && q->dci_msg_count < nof_dci_msg; i++) { // Skip search space if not present if (!q->cfg.search_space_present[i]) { continue; } // Find DCIs in the selected search space - int ret = ue_dl_nr_find_dl_dci_ss( - q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type, &dci_msg_list[count], nof_dci_msg - count); + int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type); if (ret < SRSLTE_SUCCESS) { ERROR("Error searching DCI"); return SRSLTE_ERROR; } - - // Count the found DCIs - count += ret; } } // Convert found DCI messages into DL grants - for (uint32_t i = 0; i < count; i++) { - const srslte_coreset_t* coreset = &q->cfg.coreset[dci_msg_list[i].coreset_id]; - srslte_dci_nr_format_1_0_unpack(&q->carrier, coreset, &dci_msg_list[i], &dci_dl_list[i]); + uint32_t dci_msg_count = SRSLTE_MIN(nof_dci_msg, q->dci_msg_count); + for (uint32_t i = 0; i < dci_msg_count; i++) { + const srslte_coreset_t* coreset = &q->cfg.coreset[q->dci_msg[i].coreset_id]; + srslte_dci_nr_format_1_0_unpack(&q->carrier, coreset, &q->dci_msg[i], &dci_dl_list[i]); } - return count; + return (int)dci_msg_count; } int srslte_ue_dl_nr_find_ul_dci(srslte_ue_dl_nr_t* q, diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 8fb4611a4..12cc54456 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -239,12 +239,16 @@ void srslte_ue_ul_nr_free(srslte_ue_ul_nr_t* q) SRSLTE_MEM_ZERO(q, srslte_ue_ul_nr_t, 1); } -int srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, const srslte_sch_cfg_nr_t* cfg, char* str, uint32_t str_len) +int srslte_ue_ul_nr_pusch_info(const srslte_ue_ul_nr_t* q, + const srslte_sch_cfg_nr_t* cfg, + const srslte_uci_value_nr_t* uci_value, + char* str, + uint32_t str_len) { int len = 0; // Append PDSCH info - len += srslte_pusch_nr_tx_info(&q->pusch, cfg, &cfg->grant, &str[len], str_len - len); + len += srslte_pusch_nr_tx_info(&q->pusch, cfg, &cfg->grant, uci_value, &str[len], str_len - len); return len; } diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index b050efc7f..007a66a75 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -289,7 +289,15 @@ bool radio::rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time std::unique_lock lock(rx_mutex); bool ret = true; rf_buffer_t buffer_rx; - uint32_t ratio = SRSLTE_MAX(1, decimators[0].ratio); + + // Extract decimation ratio. As the decimation may take some time to set a new ratio, deactivate the decimation and + // keep receiving samples to avoid stalling the RX stream + uint32_t ratio = 1; // No decimation by default + if (decimator_busy) { + lock.unlock(); + } else if (decimators[0].ratio > 1) { + ratio = decimators[0].ratio; + } // Calculate number of samples, considering the decimation ratio uint32_t nof_samples = buffer.get_nof_samples() * ratio; @@ -683,6 +691,7 @@ void radio::set_rx_srate(const double& srate) } // If fix sampling rate... if (std::isnormal(fix_srate_hz)) { + decimator_busy = true; std::unique_lock lock(rx_mutex); // If the sampling rate was not set, set it @@ -698,6 +707,7 @@ void radio::set_rx_srate(const double& srate) srslte_resampler_fft_init(&decimators[ch], SRSLTE_RESAMPLER_MODE_DECIMATE, ratio); } + decimator_busy = false; } else { for (srslte_rf_t& rf_device : rf_devices) { cur_rx_srate = srslte_rf_set_rx_srate(&rf_device, srate); diff --git a/lib/src/radio/test/benchmark_radio.cc b/lib/src/radio/test/benchmark_radio.cc index b7fe6b1ec..c500d7b5e 100644 --- a/lib/src/radio/test/benchmark_radio.cc +++ b/lib/src/radio/test/benchmark_radio.cc @@ -341,6 +341,7 @@ static void* radio_thread_run(void* arg) radio_args.nof_carriers = 1; radio_args.device_args = radios_args[r].empty() ? "auto" : radios_args[r]; radio_args.rx_gain = agc_enable ? -1 : rf_gain; + radio_args.tx_gain = agc_enable ? -1 : rf_gain; radio_args.device_name = radio_device; if (radio_h[r]->init(radio_args, &phy) != SRSLTE_SUCCESS) { diff --git a/lib/src/srslog/backend_worker.cpp b/lib/src/srslog/backend_worker.cpp index 909f378ea..044b65b0e 100644 --- a/lib/src/srslog/backend_worker.cpp +++ b/lib/src/srslog/backend_worker.cpp @@ -99,6 +99,11 @@ void backend_worker::process_log_entry(detail::log_entry&& entry) assert(entry.format_func && "Invalid format function"); fmt_buffer.clear(); + + // Already formatted strings in the foreground are passed to the formatter as the fmtstring. + if (entry.metadata.small_str.size()) { + entry.metadata.fmtstring = entry.metadata.small_str.data(); + } entry.format_func(std::move(entry.metadata), fmt_buffer); if (auto err_str = entry.s->write({fmt_buffer.data(), fmt_buffer.size()})) { @@ -108,8 +113,7 @@ void backend_worker::process_log_entry(detail::log_entry&& entry) void backend_worker::process_outstanding_entries() { - assert(!running_flag && - "Cannot process outstanding entries while thread is running"); + assert(!running_flag && "Cannot process outstanding entries while thread is running"); while (true) { auto item = queue.timed_pop(1); diff --git a/lib/src/srslog/event_trace.cpp b/lib/src/srslog/event_trace.cpp index 3479a9169..e374a84cb 100644 --- a/lib/src/srslog/event_trace.cpp +++ b/lib/src/srslog/event_trace.cpp @@ -20,7 +20,7 @@ */ #include "srslte/srslog/event_trace.h" -#include "sinks/single_write_file_sink.h" +#include "sinks/buffered_file_sink.h" #include "srslte/srslog/srslog.h" #include @@ -71,16 +71,14 @@ bool srslog::event_trace_init(const std::string& filename, std::size_t capacity) return false; } - auto tracer_sink = std::unique_ptr(new single_write_file_sink( - filename, capacity, get_default_log_formatter())); + auto tracer_sink = std::unique_ptr(new buffered_file_sink(filename, capacity, get_default_log_formatter())); if (!install_custom_sink(sink_name, std::move(tracer_sink))) { return false; } if (sink* s = find_sink(sink_name)) { - log_channel& c = - fetch_log_channel("event_trace_channel", *s, {"TRACE", '\0', false}); - tracer = &c; + log_channel& c = fetch_log_channel("event_trace_channel", *s, {"TRACE", '\0', false}); + tracer = &c; return true; } @@ -91,7 +89,7 @@ bool srslog::event_trace_init(const std::string& filename, std::size_t capacity) static void format_time(char* buffer, size_t len) { std::time_t t = std::time(nullptr); - std::tm lt{}; + std::tm lt{}; ::localtime_r(&t, <); std::strftime(buffer, len, "%FT%T", <); } @@ -106,11 +104,7 @@ void trace_duration_begin(const std::string& category, const std::string& name) char fmt_time[24]; format_time(fmt_time, sizeof(fmt_time)); - (*tracer)("[%s] [TID:%0u] Entering \"%s\": %s", - fmt_time, - (unsigned)::pthread_self(), - category, - name); + (*tracer)("[%s] [TID:%0u] Entering \"%s\": %s", fmt_time, (unsigned)::pthread_self(), category, name); } void trace_duration_end(const std::string& category, const std::string& name) @@ -121,11 +115,7 @@ void trace_duration_end(const std::string& category, const std::string& name) char fmt_time[24]; format_time(fmt_time, sizeof(fmt_time)); - (*tracer)("[%s] [TID:%0u] Leaving \"%s\": %s", - fmt_time, - (unsigned)::pthread_self(), - category, - name); + (*tracer)("[%s] [TID:%0u] Leaving \"%s\": %s", fmt_time, (unsigned)::pthread_self(), category, name); } } // namespace srslog @@ -133,17 +123,16 @@ void trace_duration_end(const std::string& category, const std::string& name) /// Private implementation of the complete event destructor. srslog::detail::scoped_complete_event::~scoped_complete_event() { - if (!tracer) + if (!tracer) { return; + } - auto end = std::chrono::steady_clock::now(); - unsigned long long diff = - std::chrono::duration_cast(end - start) - .count(); + auto end = std::chrono::steady_clock::now(); + unsigned long long diff = std::chrono::duration_cast(end - start).count(); - (*tracer)("[TID:%0u] Complete event \"%s\" (duration %lld us): %s", - (unsigned)::pthread_self(), - category, - diff, - name); + small_str_buffer str; + // Limit to the category and name strings to a predefined length so everything fits in a small string. + fmt::format_to(str, "{:.32} {:.16}, {}", category, name, diff); + str.push_back('\0'); + (*tracer)(std::move(str)); } diff --git a/lib/src/srslog/sinks/buffered_file_sink.h b/lib/src/srslog/sinks/buffered_file_sink.h new file mode 100644 index 000000000..e2908d38c --- /dev/null +++ b/lib/src/srslog/sinks/buffered_file_sink.h @@ -0,0 +1,89 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSLOG_BUFFERED_FILE_SINK_H +#define SRSLOG_BUFFERED_FILE_SINK_H + +#include "file_utils.h" +#include "srslte/srslog/sink.h" + +namespace srslog { + +/// This class is a wrapper of a file handle that buffers the input data into an internal buffer and writes its contents +/// to the file once the buffer is full or in object destruction. +class buffered_file_sink : public sink +{ +public: + buffered_file_sink(std::string filename, std::size_t capacity, std::unique_ptr f) : + sink(std::move(f)), filename(std::move(filename)) + { + buffer.reserve(capacity); + } + + ~buffered_file_sink() override { flush_buffer(); } + + buffered_file_sink(const buffered_file_sink& other) = delete; + buffered_file_sink& operator=(const buffered_file_sink& other) = delete; + + detail::error_string write(detail::memory_buffer input_buffer) override + { + // Create a new file the first time we hit this method. + if (!is_file_created) { + is_file_created = true; + assert(!handler && "No handler should be created yet"); + if (auto err_str = handler.create(filename)) { + return err_str; + } + } + + if (has_room_for(input_buffer.size())) { + buffer.insert(buffer.end(), input_buffer.begin(), input_buffer.end()); + return {}; + } + + return flush_buffer(); + } + + detail::error_string flush() override + { + if (auto err = flush_buffer()) { + return err; + } + return handler.flush(); + } + +private: + /// Returns true if the internal buffer has room for the specified input size, + /// otherwise returns false. + bool has_room_for(std::size_t s) const { return s + buffer.size() < buffer.capacity(); } + + /// Flushes the buffer contents into the file. + detail::error_string flush_buffer() + { + if (buffer.empty()) { + return {}; + } + auto err = handler.write(detail::memory_buffer(buffer.data(), buffer.size())); + buffer.clear(); + return err; + } + +private: + const std::string filename; + file_utils::file handler; + std::vector buffer; + bool is_file_created = false; +}; + +} // namespace srslog + +#endif // SRSLOG_BUFFERED_FILE_SINK_H diff --git a/lib/src/srslog/sinks/single_write_file_sink.h b/lib/src/srslog/sinks/single_write_file_sink.h deleted file mode 100644 index a4e8981db..000000000 --- a/lib/src/srslog/sinks/single_write_file_sink.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright 2013-2021 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef SRSLOG_SINGLE_WRITE_FILE_SINK_H -#define SRSLOG_SINGLE_WRITE_FILE_SINK_H - -#include "file_utils.h" -#include "srslte/srslog/sink.h" - -namespace srslog { - -/// This class is a wrapper of a file handle that stores the input data into an -/// internal buffer and writes its contents to the file once the buffer is full -/// or in object destruction. -class single_write_file_sink : public sink -{ -public: - single_write_file_sink(std::string filename, - std::size_t capacity, - std::unique_ptr f) : - sink(std::move(f)), filename(std::move(filename)) - { - buffer.reserve(capacity); - } - - ~single_write_file_sink() override - { - if (!is_written) { - write_contents(); - } - } - - single_write_file_sink(const single_write_file_sink& other) = delete; - single_write_file_sink& - operator=(const single_write_file_sink& other) = delete; - - detail::error_string write(detail::memory_buffer input_buffer) override - { - // Nothing to do when the contents have been already written. - if (is_written) { - return {}; - } - - if (has_room_for(input_buffer.size())) { - buffer.insert(buffer.end(), input_buffer.begin(), input_buffer.end()); - return {}; - } - - return write_contents(); - } - - detail::error_string flush() override { return handler.flush(); } - -private: - /// Returns true if the internal buffer has room for the specified input size, - /// otherwise returns false. - bool has_room_for(std::size_t s) const - { - return s + buffer.size() < buffer.capacity(); - } - - /// Writes the buffer contents into the file. - detail::error_string write_contents() - { - is_written = true; - if (auto err_str = handler.create(filename)) { - return err_str; - } - return handler.write(detail::memory_buffer(buffer.data(), buffer.size())); - } - -private: - const std::string filename; - file_utils::file handler; - std::vector buffer; - bool is_written = false; -}; - -} // namespace srslog - -#endif // SRSLOG_SINGLE_WRITE_FILE_SINK_H diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index a5716df36..bf26d2f13 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -448,7 +448,7 @@ void pdcp_entity_lte::update_rx_counts_queue(uint32_t rx_count) // If the size of the rx_vector_info is getting very large // Consider the FMC as lost and update the vector. if (rx_counts_info.size() > reordering_window) { - logger.debug("Queue too large. Updating. Old FMC=%d, Old back=%d, old queue_size=%d", + logger.debug("Queue too large. Updating. Old FMC=%d, Old back=%d, old queue_size=%zu", fmc, rx_counts_info.back(), rx_counts_info.size()); @@ -457,16 +457,16 @@ void pdcp_entity_lte::update_rx_counts_queue(uint32_t rx_count) rx_counts_info.pop_back(); fmc++; } - logger.debug("Queue too large. Updating. New FMC=%d, new back=%d, new queue_size=%d", + logger.debug("Queue too large. Updating. New FMC=%d, new back=%d, new queue_size=%zu", fmc, rx_counts_info.back(), rx_counts_info.size()); } if (rx_counts_info.empty()) { - logger.info("Updated RX_COUNT info with SDU COUNT=%d, queue_size=%d, FMC=%d", rx_count, rx_counts_info.size(), fmc); + logger.info("Updated RX_COUNT info with SDU COUNT=%d, queue_size%zu, FMC=%d", rx_count, rx_counts_info.size(), fmc); } else { - logger.info("Updated RX_COUNT info with SDU COUNT=%d, queue_size=%d, FMC=%d, back=%d", + logger.info("Updated RX_COUNT info with SDU COUNT=%d, queue_size=%zu, FMC=%d, back=%d", rx_count, rx_counts_info.size(), fmc, @@ -716,7 +716,7 @@ void pdcp_entity_lte::notify_delivery(const pdcp_sn_vector_t& pdcp_sns) return; } - logger.info("Received delivery notification from RLC. Number of PDU notified=%ld", pdcp_sns.size()); + logger.info("Received delivery notification from RLC. Number of PDU notified=%zu", pdcp_sns.size()); for (uint32_t sn : pdcp_sns) { logger.debug("Delivery notification received for PDU with SN=%d", sn); if (sn == UINT32_MAX) { @@ -746,7 +746,7 @@ void pdcp_entity_lte::notify_failure(const pdcp_sn_vector_t& pdcp_sns) return; } - logger.info("Received failure notification from RLC. Number of PDU notified=%ld", pdcp_sns.size()); + logger.info("Received failure notification from RLC. Number of PDU notified=%zu", pdcp_sns.size()); for (uint32_t sn : pdcp_sns) { logger.info("Failure notification received for PDU with SN=%d", sn); @@ -809,7 +809,7 @@ std::map pdcp_entity_lte::get_buffered_p logger.error("Buffered PDUs being requested for non-AM DRB"); return std::map{}; } - logger.info("Buffered PDUs requested, buffer_size=%d", undelivered_sdus->size()); + logger.info("Buffered PDUs requested, buffer_size=%zu", undelivered_sdus->size()); return undelivered_sdus->get_buffered_sdus(); } diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 55d64e08e..8efdb9e7f 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -448,15 +448,14 @@ int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) return SRSLTE_ERROR; } - // Store SDU info - logger.debug( - "Storing PDCP SDU info in queue. PDCP_SN=%d, Queue Size=%ld", sdu_pdcp_sn, undelivered_sdu_info_queue.nof_sdus()); - if (undelivered_sdu_info_queue.has_pdcp_sn(sdu_pdcp_sn)) { - logger.error("PDCP SDU info already exists. SN=%d", sdu_pdcp_sn); + logger.warning("PDCP_SN=%d already marked as undelivered", sdu_pdcp_sn); return SRSLTE_ERROR; } + // Store SDU info + logger.debug("Marking PDCP_SN=%d as undelivered (queue_len=%ld)", sdu_pdcp_sn, undelivered_sdu_info_queue.nof_sdus()); + undelivered_sdu_info_queue.add_pdcp_sdu(sdu_pdcp_sn); return SRSLTE_SUCCESS; } diff --git a/lib/test/mac/mac_pcap_test.cc b/lib/test/mac/mac_pcap_test.cc index b224b7f4d..a7d80df28 100644 --- a/lib/test/mac/mac_pcap_test.cc +++ b/lib/test/mac/mac_pcap_test.cc @@ -49,6 +49,8 @@ void write_pcap_nr_thread_function(srslte::mac_pcap* pcap_handle, const std::arr int mac_pcap_eutra_test() { + auto& pcap_logger = srslog::fetch_basic_logger("PCAP"); + pcap_logger.info("In mac_pcap_eutra_test"); std::array tv = { 0x21, 0x08, 0x22, 0x80, 0x82, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, @@ -67,16 +69,17 @@ int mac_pcap_eutra_test() TESTASSERT(pcap_handle->open("mac_pcap_test.pcap") != SRSLTE_SUCCESS); // open again will fail std::vector writer_threads; + pcap_logger.info("Start writer_threads"); for (uint32_t i = 0; i < num_threads; i++) { writer_threads.push_back(std::thread(write_pcap_eutra_thread_function, pcap_handle.get(), tv, num_pdus_per_thread)); } - + pcap_logger.info("Wait for writer_threads to finish"); // wait for threads to finish for (std::thread& thread : writer_threads) { thread.join(); } - + pcap_logger.info("Close PCAP handle"); TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS); TESTASSERT(pcap_handle->close() != 0); // closing twice will fail @@ -85,6 +88,8 @@ int mac_pcap_eutra_test() int mac_pcap_nr_test() { + auto& pcap_logger = srslog::fetch_basic_logger("PCAP"); + pcap_logger.info("In mac_pcap_nr_test"); std::array tv = {0x42, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; uint32_t num_threads = 10; @@ -95,16 +100,19 @@ int mac_pcap_nr_test() TESTASSERT(pcap_handle->open("mac_pcap_nr_test.pcap") != SRSLTE_SUCCESS); // open again will fail std::vector writer_threads; + pcap_logger.info("Start writer_threads"); for (uint32_t i = 0; i < num_threads; i++) { writer_threads.push_back(std::thread(write_pcap_nr_thread_function, pcap_handle.get(), tv, num_pdus_per_thread)); } + pcap_logger.info("Wait for writer_threads to finish"); // wait for threads to finish for (std::thread& thread : writer_threads) { thread.join(); } + pcap_logger.info("Close PCAP handle"); TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS); TESTASSERT(pcap_handle->close() != 0); // closing twice will fail @@ -113,6 +121,21 @@ int mac_pcap_nr_test() int main() { + // Start the log backend. + srslog::init(); + + auto& mac_logger = srslog::fetch_basic_logger("MAC", false); + mac_logger.set_level(srslog::basic_levels::debug); + mac_logger.set_hex_dump_max_size(-1); + + auto& pcap_logger = srslog::fetch_basic_logger("PCAP", false); + pcap_logger.set_level(srslog::basic_levels::debug); + pcap_logger.set_hex_dump_max_size(-1); + + pcap_logger.info("Start mac_pcap_eutra_test"); TESTASSERT(mac_pcap_eutra_test() == SRSLTE_SUCCESS); + pcap_logger.info("Start mac_pcap_nr_test"); TESTASSERT(mac_pcap_nr_test() == SRSLTE_SUCCESS); + + srslog::flush(); } diff --git a/lib/test/srslog/json_formatter_test.cpp b/lib/test/srslog/json_formatter_test.cpp index d4d836d3d..c3eee7804 100644 --- a/lib/test/srslog/json_formatter_test.cpp +++ b/lib/test/srslog/json_formatter_test.cpp @@ -36,7 +36,7 @@ static detail::log_entry_metadata build_log_entry_metadata() fmt::dynamic_format_arg_store store; store.push_back(88); - return {tp, {10, true}, "Text %d", std::move(store), "ABC", 'Z'}; + return {tp, {10, true}, "Text %d", std::move(store), "ABC", 'Z', small_str_buffer()}; } static bool when_fully_filled_log_entry_then_everything_is_formatted() diff --git a/lib/test/srslog/log_backend_test.cpp b/lib/test/srslog/log_backend_test.cpp index f9c32ee17..338f44ea6 100644 --- a/lib/test/srslog/log_backend_test.cpp +++ b/lib/test/srslog/log_backend_test.cpp @@ -79,19 +79,6 @@ private: } // namespace -static bool when_backend_is_not_started_then_pushed_log_entries_are_ignored() -{ - sink_spy spy; - log_backend_impl backend; - - detail::log_entry entry = {&spy}; - backend.push(std::move(entry)); - - ASSERT_EQ(spy.write_invocation_count(), 0); - - return true; -} - /// Builds a basic log entry. static detail::log_entry build_log_entry(sink* s) { @@ -104,7 +91,19 @@ static detail::log_entry build_log_entry(sink* s) return { s, [](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) {}, - {tp, {0, false}, "Text %d", std::move(store), "", '\0'}}; + {tp, {0, false}, "Text %d", std::move(store), "", '\0', small_str_buffer()}}; +} + +static bool when_backend_is_not_started_then_pushed_log_entries_are_ignored() +{ + sink_spy spy; + log_backend_impl backend; + + backend.push(build_log_entry(&spy)); + + ASSERT_EQ(spy.write_invocation_count(), 0); + + return true; } static bool when_backend_is_started_then_pushed_log_entries_are_sent_to_sink() diff --git a/lib/test/srslog/log_channel_test.cpp b/lib/test/srslog/log_channel_test.cpp index 412201e58..c26f1e192 100644 --- a/lib/test/srslog/log_channel_test.cpp +++ b/lib/test/srslog/log_channel_test.cpp @@ -287,6 +287,31 @@ when_logging_with_context_and_message_then_filled_in_log_entry_is_pushed_into_th return true; } +static bool +when_logging_with_small_string_then_filled_in_log_entry_is_pushed_into_the_backend() +{ + backend_spy backend; + test_dummies::sink_dummy s; + + log_channel log("id", s, backend); + + small_str_buffer buf; + fmt::format_to(buf, "A {} {} {}", 1, 2, 3); + buf.push_back('\0'); + log(std::move(buf)); + + ASSERT_EQ(backend.push_invocation_count(), 1); + + const detail::log_entry& entry = backend.last_entry(); + ASSERT_EQ(&s, entry.s); + ASSERT_NE(entry.format_func, nullptr); + ASSERT_NE(entry.metadata.tp.time_since_epoch().count(), 0); + ASSERT_EQ(entry.metadata.hex_dump.empty(), true); + ASSERT_EQ(std::string(entry.metadata.small_str.data()), "A 1 2 3"); + + return true; +} + int main() { TEST_FUNCTION(when_log_channel_is_created_then_id_matches_expected_value); @@ -305,6 +330,8 @@ int main() when_logging_with_context_then_filled_in_log_entry_is_pushed_into_the_backend); TEST_FUNCTION( when_logging_with_context_and_message_then_filled_in_log_entry_is_pushed_into_the_backend); + TEST_FUNCTION( + when_logging_with_small_string_then_filled_in_log_entry_is_pushed_into_the_backend); return 0; } diff --git a/lib/test/srslog/text_formatter_test.cpp b/lib/test/srslog/text_formatter_test.cpp index e5bf49fe3..6fdda8ac2 100644 --- a/lib/test/srslog/text_formatter_test.cpp +++ b/lib/test/srslog/text_formatter_test.cpp @@ -36,7 +36,7 @@ static detail::log_entry_metadata build_log_entry_metadata() fmt::dynamic_format_arg_store store; store.push_back(88); - return {tp, {10, true}, "Text %d", std::move(store), "ABC", 'Z'}; + return {tp, {10, true}, "Text %d", std::move(store), "ABC", 'Z', small_str_buffer()}; } static bool when_fully_filled_log_entry_then_everything_is_formatted() diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 3907bb06d..07379ec95 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -116,7 +116,7 @@ void parse_args(stress_test_args_t* args, int argc, char* argv[]) ("singletx", bpo::value(&args->single_tx)->default_value(false), "If set to true, only one node is generating data") ("pcap", bpo::value(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file") ("zeroseed", bpo::value(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero") - ("max_retx", bpo::value(&args->max_retx)->default_value(8), "Maximum number of RLC retransmission attempts") + ("max_retx", bpo::value(&args->max_retx)->default_value(32), "Maximum number of RLC retransmission attempts") ("nof_pdu_tti", bpo::value(&args->nof_pdu_tti)->default_value(1), "Number of PDUs processed in a TTI"); // clang-format on diff --git a/srsenb/hdr/stack/mac/sched.h b/srsenb/hdr/stack/mac/sched.h index 08de8eba3..d741d7440 100644 --- a/srsenb/hdr/stack/mac/sched.h +++ b/srsenb/hdr/stack/mac/sched.h @@ -106,11 +106,11 @@ protected: std::vector > carrier_schedulers; // Storage of past scheduling results - sched_result_list sched_results; + sched_result_ringbuffer sched_results; srslte::tti_point last_tti; std::mutex sched_mutex; - std::atomic configured; + bool configured; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/sched_carrier.h b/srsenb/hdr/stack/mac/sched_carrier.h index 757a4059c..25ac61b56 100644 --- a/srsenb/hdr/stack/mac/sched_carrier.h +++ b/srsenb/hdr/stack/mac/sched_carrier.h @@ -37,7 +37,7 @@ public: explicit carrier_sched(rrc_interface_mac* rrc_, std::map >* ue_db_, uint32_t enb_cc_idx_, - sched_result_list* sched_results_); + sched_result_ringbuffer* sched_results_); ~carrier_sched(); void reset(); void carrier_cfg(const sched_cell_params_t& sched_params_); @@ -66,10 +66,10 @@ private: const uint32_t enb_cc_idx; // Subframe scheduling logic - std::array sf_scheds; + srslte::circular_array sf_scheds; // scheduling results - sched_result_list* prev_sched_results; + sched_result_ringbuffer* prev_sched_results; std::vector sf_dl_mask; ///< Some TTIs may be forbidden for DL sched due to MBMS @@ -100,6 +100,7 @@ private: // args const sched_cell_params_t* cc_cfg = nullptr; rrc_interface_mac* rrc = nullptr; + srslog::basic_logger& logger; std::array pending_sibs; @@ -123,14 +124,16 @@ public: void reset(); private: + alloc_result allocate_pending_rar(sf_sched* tti_sched, const pending_rar_t& rar, uint32_t& nof_grants_alloc); + // args srslog::basic_logger& logger; const sched_cell_params_t* cc_cfg = nullptr; sched_ue_list* ue_db = nullptr; - std::deque pending_rars; - uint32_t rar_aggr_level = 2; - static const uint32_t PRACH_RAR_OFFSET = 3; // TS 36.321 Sec. 5.1.4 + std::deque pending_rars; + uint32_t rar_aggr_level = 2; + static const uint32_t PRACH_RAR_OFFSET = 3; // TS 36.321 Sec. 5.1.4 }; } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/sched_common.h b/srsenb/hdr/stack/mac/sched_common.h index eefab2a26..cbbf1e806 100644 --- a/srsenb/hdr/stack/mac/sched_common.h +++ b/srsenb/hdr/stack/mac/sched_common.h @@ -115,6 +115,10 @@ struct prb_interval : public srslte::interval { /// Type of Allocation stored in PDSCH/PUSCH enum class alloc_type_t { DL_BC, DL_PCCH, DL_RAR, DL_DATA, UL_DATA }; +inline bool is_dl_ctrl_alloc(alloc_type_t a) +{ + return a == alloc_type_t::DL_BC or a == alloc_type_t::DL_PCCH or a == alloc_type_t::DL_RAR; +} } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/sched_grid.h b/srsenb/hdr/stack/mac/sched_grid.h index a5c8c9348..829360dcd 100644 --- a/srsenb/hdr/stack/mac/sched_grid.h +++ b/srsenb/hdr/stack/mac/sched_grid.h @@ -23,99 +23,96 @@ #define SRSLTE_SCHED_GRID_H #include "lib/include/srslte/interfaces/sched_interface.h" +#include "sched_phy_ch/sched_result.h" #include "sched_phy_ch/sf_cch_allocator.h" #include "sched_ue.h" #include "srslte/adt/bounded_bitset.h" +#include "srslte/adt/circular_array.h" #include "srslte/srslog/srslog.h" -#include #include namespace srsenb { /// Error code of alloc attempt -struct alloc_outcome_t { - enum result_enum { - SUCCESS, - DCI_COLLISION, - RB_COLLISION, - ERROR, - NOF_RB_INVALID, - PUCCH_COLLISION, - MEASGAP_COLLISION, - ALREADY_ALLOC, - NO_DATA, - INVALID_PRBMASK, - INVALID_CARRIER - }; - result_enum result = ERROR; - alloc_outcome_t() = default; - alloc_outcome_t(result_enum e) : result(e) {} - operator result_enum() { return result; } - operator bool() { return result == SUCCESS; } - const char* to_string() const; -}; - -//! Result of a Subframe sched computation -struct cc_sched_result { - tti_point tti_rx; - sched_interface::dl_sched_res_t dl_sched_result = {}; - sched_interface::ul_sched_res_t ul_sched_result = {}; - rbgmask_t dl_mask = {}; ///< Accumulation of all DL RBG allocations - prbmask_t ul_mask = {}; ///< Accumulation of all UL PRB allocations - pdcch_mask_t pdcch_mask = {}; ///< Accumulation of all CCE allocations - - bool is_generated(tti_point tti_rx_) const { return tti_rx == tti_rx_; } +enum class alloc_result { + success, + sch_collision, + no_cch_space, + no_sch_space, + no_rnti_opportunity, + invalid_grant_params, + invalid_coderate, + no_grant_space, + other_cause }; +const char* to_string(alloc_result res); struct sf_sched_result { - srslte::tti_point tti_rx; + tti_point tti_rx; std::vector enb_cc_list; - cc_sched_result* new_cc(uint32_t enb_cc_idx); + void new_tti(tti_point tti_rx); + bool is_generated(uint32_t enb_cc_idx) const + { + return enb_cc_list.size() > enb_cc_idx and enb_cc_list[enb_cc_idx].generated; + } const cc_sched_result* get_cc(uint32_t enb_cc_idx) const { - return enb_cc_idx < enb_cc_list.size() ? &enb_cc_list[enb_cc_idx] : nullptr; + assert(enb_cc_idx < enb_cc_list.size()); + return &enb_cc_list[enb_cc_idx]; } cc_sched_result* get_cc(uint32_t enb_cc_idx) { - return enb_cc_idx < enb_cc_list.size() ? &enb_cc_list[enb_cc_idx] : nullptr; + assert(enb_cc_idx < enb_cc_list.size()); + return &enb_cc_list[enb_cc_idx]; } bool is_ul_alloc(uint16_t rnti) const; bool is_dl_alloc(uint16_t rnti) const; }; -struct sched_result_list { +struct sched_result_ringbuffer { public: - sf_sched_result* new_tti(srslte::tti_point tti_rx); - sf_sched_result* get_sf(srslte::tti_point tti_rx); - const sf_sched_result* get_sf(srslte::tti_point tti_rx) const; - const cc_sched_result* get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx) const; - cc_sched_result* get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx); + void set_nof_carriers(uint32_t nof_carriers); + void new_tti(srslte::tti_point tti_rx); + bool has_sf(srslte::tti_point tti_rx) const { return results[tti_rx.to_uint()].tti_rx == tti_rx; } + sf_sched_result* get_sf(srslte::tti_point tti_rx) + { + assert(has_sf(tti_rx)); + return &results[tti_rx.to_uint()]; + } + const sf_sched_result* get_sf(srslte::tti_point tti_rx) const + { + assert(has_sf(tti_rx)); + return &results[tti_rx.to_uint()]; + } + const cc_sched_result* get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx) const + { + return get_sf(tti_rx)->get_cc(enb_cc_idx); + } + cc_sched_result* get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx) { return get_sf(tti_rx)->get_cc(enb_cc_idx); } private: - std::array results; + uint32_t nof_carriers = 1; + srslte::circular_array results; }; /// manages a subframe grid resources, namely CCE and DL/UL RB allocations class sf_grid_t { public: - struct dl_ctrl_alloc_t { - alloc_outcome_t outcome; - rbg_interval rbg_range; - }; - sf_grid_t() : logger(srslog::fetch_basic_logger("MAC")) {} - void init(const sched_cell_params_t& cell_params_); - void new_tti(tti_point tti_rx); - dl_ctrl_alloc_t alloc_dl_ctrl(uint32_t aggr_lvl, alloc_type_t alloc_type); - alloc_outcome_t alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant); - bool reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg); - alloc_outcome_t alloc_ul_data(sched_ue* user, prb_interval alloc, bool needs_pdcch, bool strict = true); - alloc_outcome_t reserve_ul_prbs(const prbmask_t& prbmask, bool strict); - alloc_outcome_t reserve_ul_prbs(prb_interval alloc, bool strict); - bool find_ul_alloc(uint32_t L, prb_interval* alloc) const; + void init(const sched_cell_params_t& cell_params_); + void new_tti(tti_point tti_rx); + alloc_result alloc_dl_ctrl(uint32_t aggr_lvl, rbg_interval rbg_range, alloc_type_t alloc_type); + alloc_result alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant); + bool reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg); + void rem_last_alloc_dl(rbg_interval rbgs); + + alloc_result alloc_ul_data(sched_ue* user, prb_interval alloc, bool needs_pdcch, bool strict = true); + alloc_result reserve_ul_prbs(const prbmask_t& prbmask, bool strict); + alloc_result reserve_ul_prbs(prb_interval alloc, bool strict); + bool find_ul_alloc(uint32_t L, prb_interval* alloc) const; // getters const rbgmask_t& get_dl_mask() const { return dl_mask; } @@ -125,17 +122,16 @@ public: uint32_t get_pucch_width() const { return pucch_nrb; } private: - alloc_outcome_t alloc_dl(uint32_t aggr_lvl, - alloc_type_t alloc_type, - rbgmask_t alloc_mask, - sched_ue* user = nullptr, - bool has_pusch_grant = false); + alloc_result alloc_dl(uint32_t aggr_lvl, + alloc_type_t alloc_type, + rbgmask_t alloc_mask, + sched_ue* user = nullptr, + bool has_pusch_grant = false); // consts const sched_cell_params_t* cc_cfg = nullptr; srslog::basic_logger& logger; - uint32_t nof_rbgs = 0; - uint32_t si_n_rbg = 0, rar_n_rbg = 0; + uint32_t nof_rbgs = 0; uint32_t pucch_nrb = 0; prbmask_t pucch_mask; @@ -144,9 +140,8 @@ private: // internal state tti_point tti_rx; - uint32_t avail_rbg = 0; - rbgmask_t dl_mask = {}; - prbmask_t ul_mask = {}; + rbgmask_t dl_mask = {}; + prbmask_t ul_mask = {}; }; /** Description: Stores the RAR, broadcast, paging, DL data, UL data allocations for the given subframe @@ -159,21 +154,14 @@ public: struct ctrl_alloc_t { size_t dci_idx; rbg_interval rbg_range; - uint16_t rnti; uint32_t req_bytes; - alloc_type_t alloc_type; }; struct rar_alloc_t { sf_sched::ctrl_alloc_t alloc_data; sched_interface::dl_sched_rar_t rar_grant; - rar_alloc_t(const sf_sched::ctrl_alloc_t& c, const sched_interface::dl_sched_rar_t& r) : alloc_data(c), rar_grant(r) - {} }; struct bc_alloc_t : public ctrl_alloc_t { - uint32_t rv = 0; - uint32_t sib_idx = 0; - bc_alloc_t() = default; - explicit bc_alloc_t(const ctrl_alloc_t& c) : ctrl_alloc_t(c) {} + sched_interface::dl_sched_bc_t bc_grant; }; struct dl_alloc_t { size_t dci_idx; @@ -198,13 +186,6 @@ public: uint32_t n_prb = 0; uint32_t mcs = 0; }; - struct pending_rar_t { - uint16_t ra_rnti = 0; - tti_point prach_tti{}; - uint32_t nof_grants = 0; - sched_interface::dl_sched_rar_info_t msg3_grant[sched_interface::MAX_RAR_LIST] = {}; - }; - typedef std::pair ctrl_code_t; // Control/Configuration Methods sf_sched(); @@ -212,29 +193,32 @@ public: void new_tti(srslte::tti_point tti_rx_, sf_sched_result* cc_results); // DL alloc methods - alloc_outcome_t alloc_bc(uint32_t aggr_lvl, uint32_t sib_idx, uint32_t sib_ntx); - alloc_outcome_t alloc_paging(uint32_t aggr_lvl, uint32_t paging_payload); - std::pair alloc_rar(uint32_t aggr_lvl, const pending_rar_t& rar_grant); + alloc_result alloc_sib(uint32_t aggr_lvl, uint32_t sib_idx, uint32_t sib_ntx, rbg_interval rbgs); + alloc_result alloc_paging(uint32_t aggr_lvl, uint32_t paging_payload, rbg_interval rbgs); + alloc_result alloc_rar(uint32_t aggr_lvl, const pending_rar_t& rar_grant, rbg_interval rbgs, uint32_t nof_grants); bool reserve_dl_rbgs(uint32_t rbg_start, uint32_t rbg_end) { return tti_alloc.reserve_dl_rbgs(rbg_start, rbg_end); } - const std::vector& get_allocated_rars() const { return rar_allocs; } // UL alloc methods - alloc_outcome_t alloc_msg3(sched_ue* user, const sched_interface::dl_sched_rar_grant_t& rargrant); - alloc_outcome_t - alloc_ul(sched_ue* user, prb_interval alloc, ul_alloc_t::type_t alloc_type, bool is_msg3 = false, int msg3_mcs = -1); - bool reserve_ul_prbs(const prbmask_t& ulmask, bool strict) { return tti_alloc.reserve_ul_prbs(ulmask, strict); } - bool alloc_phich(sched_ue* user, sched_interface::ul_sched_res_t* ul_sf_result); + alloc_result alloc_msg3(sched_ue* user, const sched_interface::dl_sched_rar_grant_t& rargrant); + alloc_result + alloc_ul(sched_ue* user, prb_interval alloc, ul_alloc_t::type_t alloc_type, bool is_msg3 = false, int msg3_mcs = -1); + alloc_result reserve_ul_prbs(const prbmask_t& ulmask, bool strict) + { + return tti_alloc.reserve_ul_prbs(ulmask, strict); + } + alloc_result alloc_phich(sched_ue* user); // compute DCIs and generate dl_sched_result/ul_sched_result for a given TTI void generate_sched_results(sched_ue_list& ue_db); - alloc_outcome_t alloc_dl_user(sched_ue* user, const rbgmask_t& user_mask, uint32_t pid); - tti_point get_tti_tx_dl() const { return to_tx_dl(tti_rx); } - uint32_t get_nof_ctrl_symbols() const; - const rbgmask_t& get_dl_mask() const { return tti_alloc.get_dl_mask(); } - alloc_outcome_t alloc_ul_user(sched_ue* user, prb_interval alloc); - const prbmask_t& get_ul_mask() const { return tti_alloc.get_ul_mask(); } - tti_point get_tti_tx_ul() const { return to_tx_ul(tti_rx); } + alloc_result alloc_dl_user(sched_ue* user, const rbgmask_t& user_mask, uint32_t pid); + tti_point get_tti_tx_dl() const { return to_tx_dl(tti_rx); } + uint32_t get_nof_ctrl_symbols() const; + const rbgmask_t& get_dl_mask() const { return tti_alloc.get_dl_mask(); } + alloc_result alloc_ul_user(sched_ue* user, prb_interval alloc); + const prbmask_t& get_ul_mask() const { return tti_alloc.get_ul_mask(); } + tti_point get_tti_tx_ul() const { return to_tx_ul(tti_rx); } + srslte::const_span get_allocated_rars() const { return rar_allocs; } // getters tti_point get_tti_rx() const { return tti_rx; } @@ -244,18 +228,12 @@ public: const sched_cell_params_t* get_cc_cfg() const { return cc_cfg; } private: - ctrl_code_t alloc_dl_ctrl(uint32_t aggr_lvl, uint32_t tbs_bytes, uint16_t rnti); - int generate_format1a(prb_interval prb_range, uint32_t tbs, uint32_t rv, uint16_t rnti, srslte_dci_dl_t* dci); - void set_bc_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::dl_sched_res_t* dl_result); - void set_rar_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::dl_sched_res_t* dl_result); - void set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::dl_sched_res_t* dl_result, - sched_ue_list& ue_list); - void set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::ul_sched_res_t* ul_result, - sched_ue_list& ue_list); + void set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, + sched_interface::dl_sched_res_t* dl_result, + sched_ue_list& ue_list); + void set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, + sched_interface::ul_sched_res_t* ul_result, + sched_ue_list& ue_list); // consts const sched_cell_params_t* cc_cfg = nullptr; @@ -263,12 +241,13 @@ private: sf_sched_result* cc_results; ///< Results of other CCs for the same Subframe // internal state - sf_grid_t tti_alloc; - std::vector bc_allocs; - std::vector rar_allocs; - std::vector data_allocs; - std::vector ul_data_allocs; - uint32_t last_msg3_prb = 0, max_msg3_prb = 0; + sf_grid_t tti_alloc; + + srslte::bounded_vector bc_allocs; + srslte::bounded_vector rar_allocs; + srslte::bounded_vector data_allocs; + srslte::bounded_vector ul_data_allocs; + uint32_t last_msg3_prb = 0, max_msg3_prb = 0; // Next TTI state tti_point tti_rx; diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h index da984fdb9..62c7c3edb 100644 --- a/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h @@ -22,7 +22,8 @@ #ifndef SRSLTE_SCHED_DCI_H #define SRSLTE_SCHED_DCI_H -#include +#include "../sched_common.h" +#include "srslte/adt/bounded_vector.h" namespace srsenb { @@ -55,7 +56,7 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, bool use_tbs_index_alt); /** - * Compute lowest MCS, TBS based on CQI, N_prb that satisfies TBS >= req_bytes + * Compute lowest MCS, TBS based on CQI, N_prb that satisfies TBS >= req_bytes (best effort) * \remark See TS 36.213 - Table 7.1.7.1-1/1A * @return resulting TBS (in bytes) and mcs. TBS=-1 if no valid solution was found. */ @@ -68,6 +69,46 @@ tbs_info compute_min_mcs_and_tbs_from_required_bytes(uint32_t nof_prb, bool ulqam64_enabled, bool use_tbs_index_alt); +struct pending_rar_t { + uint16_t ra_rnti = 0; + tti_point prach_tti{}; + srslte::bounded_vector msg3_grant = {}; +}; + +bool generate_sib_dci(sched_interface::dl_sched_bc_t& bc, + tti_point tti_tx_dl, + uint32_t sib_idx, + uint32_t sib_ntx, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params, + uint32_t current_cfi); + +bool generate_paging_dci(sched_interface::dl_sched_bc_t& bc, + tti_point tti_tx_dl, + uint32_t req_bytes, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params, + uint32_t current_cfi); + +bool generate_rar_dci(sched_interface::dl_sched_rar_t& rar, + tti_point tti_tx_dl, + const pending_rar_t& pending_rar, + rbg_interval rbg_range, + uint32_t nof_grants, + uint32_t start_msg3_prb, + const sched_cell_params_t& cell_params, + uint32_t current_cfi); + +void log_broadcast_allocation(const sched_interface::dl_sched_bc_t& bc, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params); + +void log_rar_allocation(const sched_interface::dl_sched_rar_t& rar, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params); + +void log_rar_allocation(const sched_interface::dl_sched_rar_t& rar, rbg_interval rbg_range); + } // namespace srsenb #endif // SRSLTE_SCHED_DCI_H diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sched_result.h b/srsenb/hdr/stack/mac/sched_phy_ch/sched_result.h new file mode 100644 index 000000000..fb41598ef --- /dev/null +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sched_result.h @@ -0,0 +1,41 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSLTE_SCHED_RESULT_H +#define SRSLTE_SCHED_RESULT_H + +#include "../sched_common.h" + +namespace srsenb { + +/// Result of a Subframe sched computation +struct cc_sched_result { + bool generated = false; + tti_point tti_rx{}; + + /// Accumulation of all DL RBG allocations + rbgmask_t dl_mask = {}; + + /// Accumulation of all UL PRB allocations + prbmask_t ul_mask = {}; + + /// Accumulation of all CCE allocations + pdcch_mask_t pdcch_mask = {}; + + /// Individual allocations information + sched_interface::dl_sched_res_t dl_sched_result = {}; + sched_interface::ul_sched_res_t ul_sched_result = {}; +}; + +} // namespace srsenb + +#endif // SRSLTE_SCHED_RESULT_H diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h b/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h index 0cb226ebd..4012c62ac 100644 --- a/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h @@ -20,6 +20,7 @@ */ #include "../sched_common.h" +#include "sched_result.h" #ifndef SRSLTE_PDCCH_SCHED_H #define SRSLTE_PDCCH_SCHED_H @@ -33,15 +34,17 @@ class sf_cch_allocator { public: const static uint32_t MAX_CFI = 3; - struct alloc_t { - int8_t pucch_n_prb; ///< this PUCCH resource identifier - uint16_t rnti = 0; - srslte_dci_location_t dci_pos = {0, 0}; - pdcch_mask_t current_mask; ///< this allocation PDCCH mask - pdcch_mask_t total_mask; ///< Accumulation of all PDCCH masks for the current solution (tree route) - prbmask_t total_pucch_mask; ///< Accumulation of all PUCCH masks for the current solution/tree route + struct tree_node { + int8_t pucch_n_prb = -1; ///< this PUCCH resource identifier + uint16_t rnti = SRSLTE_INVALID_RNTI; + uint32_t record_idx = 0; + uint32_t dci_pos_idx = 0; + srslte_dci_location_t dci_pos = {0, 0}; + /// Accumulation of all PDCCH masks for the current solution (DFS path) + pdcch_mask_t total_mask, current_mask; + prbmask_t total_pucch_mask; }; - using alloc_result_t = srslte::bounded_vector; + using alloc_result_t = srslte::bounded_vector; sf_cch_allocator() : logger(srslog::fetch_basic_logger("MAC")) {} @@ -57,56 +60,28 @@ public: */ bool alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user = nullptr, bool has_pusch_grant = false); + void rem_last_dci(); + // getters uint32_t get_cfi() const { return current_cfix + 1; } void get_allocs(alloc_result_t* vec = nullptr, pdcch_mask_t* tot_mask = nullptr, size_t idx = 0) const; uint32_t nof_cces() const { return cc_cfg->nof_cce_table[current_cfix]; } size_t nof_allocs() const { return dci_record_list.size(); } - size_t nof_alloc_combinations() const { return get_alloc_tree().nof_leaves(); } std::string result_to_string(bool verbose = false) const; private: /// DCI allocation parameters - struct alloc_record_t { - sched_ue* user; + struct alloc_record { + bool pusch_uci; uint32_t aggr_idx; alloc_type_t alloc_type; - bool pusch_uci; - }; - /// Tree-based data structure to store possible DCI allocation decisions - struct alloc_tree_t { - struct node_t { - int parent_idx; - alloc_t node; - node_t(int i, const alloc_t& a) : parent_idx(i), node(a) {} - }; - - // args - size_t nof_cces; - const sched_cell_params_t* cc_cfg = nullptr; - srslte_pucch_cfg_t* pucch_cfg_temp = nullptr; - uint32_t cfi; - // state - std::vector dci_alloc_tree; - size_t prev_start = 0, prev_end = 0; - - explicit alloc_tree_t(uint32_t this_cfi, const sched_cell_params_t& cc_params, srslte_pucch_cfg_t& pucch_cfg); - size_t nof_leaves() const { return prev_end - prev_start; } - void reset(); - void get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const; - bool add_tree_node_leaves(int node_idx, - const alloc_record_t& dci_record, - const cce_cfi_position_table& dci_locs, - tti_point tti_rx); - std::string result_to_string(bool verbose) const; + sched_ue* user; }; - - const alloc_tree_t& get_alloc_tree() const { return alloc_trees[current_cfix]; } const cce_cfi_position_table* get_cce_loc_table(alloc_type_t alloc_type, sched_ue* user, uint32_t cfix) const; // PDCCH allocation algorithm - bool set_cfi(uint32_t cfi); - bool alloc_dci_record(const alloc_record_t& record, uint32_t cfix); + bool alloc_dfs_node(const alloc_record& record, uint32_t start_child_idx); + bool get_next_dfs(); // consts const sched_cell_params_t* cc_cfg = nullptr; @@ -114,10 +89,11 @@ private: srslte_pucch_cfg_t pucch_cfg_common = {}; // tti vars - tti_point tti_rx; - uint32_t current_cfix = 0; - std::vector alloc_trees; ///< List of PDCCH alloc trees, where index is the cfi index - std::vector dci_record_list; ///< Keeps a record of all the PDCCH allocations done so far + tti_point tti_rx; + uint32_t current_cfix = 0; + uint32_t current_max_cfix = 0; + std::vector last_dci_dfs, temp_dci_dfs; + std::vector dci_record_list; ///< Keeps a record of all the PDCCH allocations done so far }; // Helper methods diff --git a/srsenb/hdr/stack/mac/schedulers/sched_base.h b/srsenb/hdr/stack/mac/schedulers/sched_base.h index c7212dc51..4770906bf 100644 --- a/srsenb/hdr/stack/mac/schedulers/sched_base.h +++ b/srsenb/hdr/stack/mac/schedulers/sched_base.h @@ -43,14 +43,16 @@ protected: /**************** Helper methods ****************/ +rbg_interval find_empty_rbg_interval(uint32_t max_nof_rbgs, const rbgmask_t& current_mask); + /** * Finds a bitmask of available RBG resources for a given UE in a greedy fashion * @param ue UE being allocated - * @param enb_cc_idx carrier index + * @param is_contiguous whether to find a contiguous range of RBGs * @param current_mask bitmask of occupied RBGs, where to search for available RBGs * @return bitmask of found RBGs. If a valid mask wasn't found, bitmask::size() == 0 */ -rbgmask_t compute_user_rbgmask_greedy(sched_ue& ue, uint32_t enb_cc_idx, const rbgmask_t& current_mask); +rbgmask_t compute_rbgmask_greedy(uint32_t max_nof_rbgs, bool is_contiguous, const rbgmask_t& current_mask); /** * Finds a range of L contiguous PRBs that are empty @@ -66,10 +68,10 @@ const ul_harq_proc* get_ul_retx_harq(sched_ue& user, sf_sched* tti_sched); const ul_harq_proc* get_ul_newtx_harq(sched_ue& user, sf_sched* tti_sched); /// Helper methods to allocate resources in subframe -alloc_outcome_t try_dl_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h); -alloc_outcome_t - try_dl_newtx_alloc_greedy(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h, rbgmask_t* result_mask = nullptr); -alloc_outcome_t try_ul_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const ul_harq_proc& h); +alloc_result try_dl_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h); +alloc_result + try_dl_newtx_alloc_greedy(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h, rbgmask_t* result_mask = nullptr); +alloc_result try_ul_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const ul_harq_proc& h); } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 99d9cd8f5..11bd36d0d 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -68,7 +68,7 @@ private: srslog::basic_logger* logger; srslte::pdu_queue* shared_pdu_queue; - srslte::circular_array, SRSLTE_FDD_NOF_HARQ * 2> pdu_map; + srslte::circular_array, SRSLTE_FDD_NOF_HARQ * 8> pdu_map; }; class cc_buffer_handler diff --git a/srsenb/hdr/stack/rrc/mac_controller.h b/srsenb/hdr/stack/rrc/mac_controller.h index 5f1fd81a0..d3b656b3b 100644 --- a/srsenb/hdr/stack/rrc/mac_controller.h +++ b/srsenb/hdr/stack/rrc/mac_controller.h @@ -64,6 +64,8 @@ public: const srslte::rrc_ue_capabilities_t& uecaps); void handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep); + void handle_max_retx(); + const ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; } bool is_crnti_set() const { return crnti_set; } diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index 9d3ae3a43..801ae3d1b 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -25,6 +25,7 @@ #include "common_enb.h" #include "srslte/common/buffer_pool.h" +#include "srslte/common/task_scheduler.h" #include "srslte/common/threads.h" #include "srslte/interfaces/enb_gtpu_interfaces.h" #include "srslte/phy/common/phy_common.h" @@ -43,7 +44,7 @@ class stack_interface_gtpu_lte; class gtpu final : public gtpu_interface_rrc, public gtpu_interface_pdcp { public: - explicit gtpu(srslog::basic_logger& logger); + explicit gtpu(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger); int init(std::string gtp_bind_addr_, std::string mme_addr_, @@ -84,6 +85,7 @@ private: std::string mme_addr; srsenb::pdcp_interface_gtpu* pdcp = nullptr; srslog::basic_logger& logger; + srslte::task_sched_handle task_sched; // Class to create class m1u_handler @@ -113,16 +115,17 @@ private: const uint32_t undefined_pdcp_sn = std::numeric_limits::max(); struct tunnel { - bool dl_enabled = true; - bool fwd_teid_in_present = false; - bool prior_teid_in_present = false; - uint16_t rnti = SRSLTE_INVALID_RNTI; - uint32_t lcid = SRSENB_N_RADIO_BEARERS; - uint32_t teid_in = 0; - uint32_t teid_out = 0; - uint32_t spgw_addr = 0; - uint32_t fwd_teid_in = 0; ///< forward Rx SDUs to this TEID - uint32_t prior_teid_in = 0; ///< buffer bearer SDUs until this TEID receives an End Marker + bool dl_enabled = true; + bool fwd_teid_in_present = false; + bool prior_teid_in_present = false; + uint16_t rnti = SRSLTE_INVALID_RNTI; + uint32_t lcid = SRSENB_N_RADIO_BEARERS; + uint32_t teid_in = 0; + uint32_t teid_out = 0; + uint32_t spgw_addr = 0; + uint32_t fwd_teid_in = 0; ///< forward Rx SDUs to this TEID + uint32_t prior_teid_in = 0; ///< buffer bearer SDUs until this TEID receives an End Marker + srslte::unique_timer rx_timer; std::multimap buffer; }; std::unordered_map tunnels; @@ -138,7 +141,9 @@ private: void echo_response(in_addr_t addr, in_port_t port, uint16_t seq); void error_indication(in_addr_t addr, in_port_t port, uint32_t err_teid); - void end_marker(uint32_t teidin); + bool end_marker(uint32_t teidin); + + void handle_end_marker(tunnel& rx_tunnel); int create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in); diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index fe08eaa04..60eb4c376 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -42,7 +42,7 @@ enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : pdcp(&task_sched, pdcp_logger), mac(&task_sched, mac_logger), rlc(rlc_logger), - gtpu(gtpu_logger), + gtpu(&task_sched, gtpu_logger), s1ap(&task_sched, s1ap_logger), rrc(&task_sched), mac_pcap(), diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index edd309f74..02930403a 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -593,7 +593,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) srslte::rwlock_read_guard lock(rwlock); // Copy data grants - for (uint32_t i = 0; i < sched_result.nof_data_elems; i++) { + for (uint32_t i = 0; i < sched_result.data.size(); i++) { uint32_t tb_count = 0; // Get UE @@ -654,7 +654,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) } // Copy RAR grants - for (uint32_t i = 0; i < sched_result.nof_rar_elems; i++) { + for (uint32_t i = 0; i < sched_result.rar.size(); i++) { // Copy dci info dl_sched_res->pdsch[n].dci = sched_result.rar[i].dci; @@ -689,7 +689,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) } // Copy SI and Paging grants - for (uint32_t i = 0; i < sched_result.nof_bc_elems; i++) { + for (uint32_t i = 0; i < sched_result.bc.size(); i++) { // Copy dci info dl_sched_res->pdsch[n].dci = sched_result.bc[i].dci; @@ -909,7 +909,7 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list) // Copy DCI grants phy_ul_sched_res->nof_grants = 0; int n = 0; - for (uint32_t i = 0; i < sched_result.nof_dci_elems; i++) { + for (uint32_t i = 0; i < sched_result.pusch.size(); i++) { if (sched_result.pusch[i].tbs > 0) { // Get UE uint16_t rnti = sched_result.pusch[i].dci.rnti; @@ -952,11 +952,11 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list) } // Copy PHICH actions - for (uint32_t i = 0; i < sched_result.nof_phich_elems; i++) { + for (uint32_t i = 0; i < sched_result.phich.size(); i++) { phy_ul_sched_res->phich[i].ack = sched_result.phich[i].phich == sched_interface::ul_sched_phich_t::ACK; phy_ul_sched_res->phich[i].rnti = sched_result.phich[i].rnti; } - phy_ul_sched_res->nof_phich = sched_result.nof_phich_elems; + phy_ul_sched_res->nof_phich = sched_result.phich.size(); } // clear old buffers from all users for (auto& u : ue_db) { diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index 4e7baba96..5c8638c29 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -77,6 +77,8 @@ int sched::cell_cfg(const std::vector& cell_cfg) } } + sched_results.set_nof_carriers(cell_cfg.size()); + // Create remaining cells, if not created yet uint32_t prev_size = carrier_schedulers.size(); carrier_schedulers.resize(sched_cell_params.size()); @@ -89,7 +91,7 @@ int sched::cell_cfg(const std::vector& cell_cfg) carrier_schedulers[i]->carrier_cfg(sched_cell_params[i]); } - configured.store(true, std::memory_order_release); + configured = true; return 0; } @@ -296,11 +298,10 @@ std::array sched::get_scell_activation_mask(uint16_t // Downlink Scheduler API int sched::dl_sched(uint32_t tti_tx_dl, uint32_t enb_cc_idx, sched_interface::dl_sched_res_t& sched_result) { - if (not configured.load(std::memory_order_acquire)) { + std::lock_guard lock(sched_mutex); + if (not configured) { return 0; } - - std::lock_guard lock(sched_mutex); if (enb_cc_idx >= carrier_schedulers.size()) { return 0; } @@ -317,11 +318,10 @@ int sched::dl_sched(uint32_t tti_tx_dl, uint32_t enb_cc_idx, sched_interface::dl // Uplink Scheduler API int sched::ul_sched(uint32_t tti, uint32_t enb_cc_idx, srsenb::sched_interface::ul_sched_res_t& sched_result) { - if (not configured.load(std::memory_order_acquire)) { + std::lock_guard lock(sched_mutex); + if (not configured) { return 0; } - - std::lock_guard lock(sched_mutex); if (enb_cc_idx >= carrier_schedulers.size()) { return 0; } @@ -355,9 +355,7 @@ void sched::new_tti(tti_point tti_rx) /// Check if TTI result is generated bool sched::is_generated(srslte::tti_point tti_rx, uint32_t enb_cc_idx) const { - const sf_sched_result* sf_result = sched_results.get_sf(tti_rx); - return sf_result != nullptr and sf_result->get_cc(enb_cc_idx) != nullptr and - sf_result->get_cc(enb_cc_idx)->is_generated(tti_rx); + return sched_results.has_sf(tti_rx) and sched_results.get_sf(tti_rx)->is_generated(enb_cc_idx); } // Common way to access ue_db elements in a read locking way diff --git a/srsenb/src/stack/mac/sched_carrier.cc b/srsenb/src/stack/mac/sched_carrier.cc index 9c7434431..4f2194b6c 100644 --- a/srsenb/src/stack/mac/sched_carrier.cc +++ b/srsenb/src/stack/mac/sched_carrier.cc @@ -35,7 +35,9 @@ using srslte::tti_point; * Broadcast (SIB+Paging) scheduling *******************************************************/ -bc_sched::bc_sched(const sched_cell_params_t& cfg_, srsenb::rrc_interface_mac* rrc_) : cc_cfg(&cfg_), rrc(rrc_) {} +bc_sched::bc_sched(const sched_cell_params_t& cfg_, srsenb::rrc_interface_mac* rrc_) : + cc_cfg(&cfg_), rrc(rrc_), logger(srslog::fetch_basic_logger("MAC")) +{} void bc_sched::dl_sched(sf_sched* tti_sched) { @@ -98,34 +100,69 @@ void bc_sched::alloc_sibs(sf_sched* tti_sched) uint32_t current_sf_idx = tti_sched->get_tti_tx_dl().sf_idx(); uint32_t current_sfn = tti_sched->get_tti_tx_dl().sfn(); - for (uint32_t i = 0; i < pending_sibs.size(); i++) { - if (cc_cfg->cfg.sibs[i].len > 0 and pending_sibs[i].is_in_window and pending_sibs[i].n_tx < 4) { - uint32_t nof_tx = (i > 0) ? SRSLTE_MIN(srslte::ceil_div(cc_cfg->cfg.si_window_ms, 10), 4) : 4; - uint32_t n_sf = (tti_sched->get_tti_tx_dl() - pending_sibs[i].window_start); + for (uint32_t sib_idx = 0; sib_idx < pending_sibs.size(); sib_idx++) { + sched_sib_t& pending_sib = pending_sibs[sib_idx]; + // Check if SIB is configured and within window + if (cc_cfg->cfg.sibs[sib_idx].len == 0 or not pending_sib.is_in_window or pending_sib.n_tx >= 4) { + continue; + } - // Check if there is any SIB to tx - bool sib1_flag = (i == 0) and (current_sfn % 2) == 0 and current_sf_idx == 5; - bool other_sibs_flag = - (i > 0) and (n_sf >= (cc_cfg->cfg.si_window_ms / nof_tx) * pending_sibs[i].n_tx) and current_sf_idx == 9; - if (not sib1_flag and not other_sibs_flag) { - continue; - } + // Check if subframe index is the correct one for SIB transmission + uint32_t nof_tx = (sib_idx > 0) ? SRSLTE_MIN(srslte::ceil_div(cc_cfg->cfg.si_window_ms, 10), 4) : 4; + uint32_t n_sf = (tti_sched->get_tti_tx_dl() - pending_sibs[sib_idx].window_start); + bool sib1_flag = (sib_idx == 0) and (current_sfn % 2) == 0 and current_sf_idx == 5; + bool other_sibs_flag = (sib_idx > 0) and + (n_sf >= (cc_cfg->cfg.si_window_ms / nof_tx) * pending_sibs[sib_idx].n_tx) and + current_sf_idx == 9; + if (not sib1_flag and not other_sibs_flag) { + continue; + } - // Schedule SIB - tti_sched->alloc_bc(bc_aggr_level, i, pending_sibs[i].n_tx); - pending_sibs[i].n_tx++; + // Attempt PDSCH grants with increasing number of RBGs + alloc_result ret = alloc_result::invalid_coderate; + for (uint32_t nrbgs = 1; nrbgs < cc_cfg->nof_rbgs and ret == alloc_result::invalid_coderate; ++nrbgs) { + rbg_interval rbg_interv = find_empty_rbg_interval(nrbgs, tti_sched->get_dl_mask()); + if (rbg_interv.length() != nrbgs) { + ret = alloc_result::no_sch_space; + break; + } + ret = tti_sched->alloc_sib(bc_aggr_level, sib_idx, pending_sibs[sib_idx].n_tx, rbg_interv); + if (ret == alloc_result::success) { + // SIB scheduled successfully + pending_sibs[sib_idx].n_tx++; + } + } + if (ret != alloc_result::success) { + logger.warning("SCHED: Could not allocate SIB=%d, len=%d. Cause: %s", + sib_idx + 1, + cc_cfg->cfg.sibs[sib_idx].len, + to_string(ret)); } } } void bc_sched::alloc_paging(sf_sched* tti_sched) { - /* Allocate DCIs and RBGs for paging */ - if (rrc != nullptr) { - uint32_t paging_payload = 0; - if (rrc->is_paging_opportunity(current_tti.to_uint(), &paging_payload) and paging_payload > 0) { - tti_sched->alloc_paging(bc_aggr_level, paging_payload); + uint32_t paging_payload = 0; + + // Check if pending Paging message + if (not rrc->is_paging_opportunity(tti_sched->get_tti_tx_dl().to_uint(), &paging_payload) or paging_payload == 0) { + return; + } + + alloc_result ret = alloc_result::invalid_coderate; + for (uint32_t nrbgs = 1; nrbgs < cc_cfg->nof_rbgs and ret == alloc_result::invalid_coderate; ++nrbgs) { + rbg_interval rbg_interv = find_empty_rbg_interval(nrbgs, tti_sched->get_dl_mask()); + if (rbg_interv.length() != nrbgs) { + ret = alloc_result::no_sch_space; + break; } + + ret = tti_sched->alloc_paging(bc_aggr_level, paging_payload, rbg_interv); + } + + if (ret != alloc_result::success) { + logger.warning("SCHED: Could not allocate Paging with payload length=%d, cause=%s", paging_payload, to_string(ret)); } } @@ -144,6 +181,31 @@ ra_sched::ra_sched(const sched_cell_params_t& cfg_, sched_ue_list& ue_db_) : cc_cfg(&cfg_), logger(srslog::fetch_basic_logger("MAC")), ue_db(&ue_db_) {} +alloc_result ra_sched::allocate_pending_rar(sf_sched* tti_sched, const pending_rar_t& rar, uint32_t& nof_grants_alloc) +{ + alloc_result ret = alloc_result::other_cause; + for (nof_grants_alloc = rar.msg3_grant.size(); nof_grants_alloc > 0; nof_grants_alloc--) { + ret = alloc_result::invalid_coderate; + for (uint32_t nrbg = 1; nrbg < cc_cfg->nof_rbgs and ret == alloc_result::invalid_coderate; ++nrbg) { + rbg_interval rbg_interv = find_empty_rbg_interval(nrbg, tti_sched->get_dl_mask()); + if (rbg_interv.length() == nrbg) { + ret = tti_sched->alloc_rar(rar_aggr_level, rar, rbg_interv, nof_grants_alloc); + } else { + ret = alloc_result::no_sch_space; + } + } + + // If allocation was not successful because there were not enough RBGs, try allocating fewer Msg3 grants + if (ret != alloc_result::invalid_coderate and ret != alloc_result::no_sch_space) { + break; + } + } + if (ret != alloc_result::success) { + logger.info("SCHED: RAR allocation for L=%d was postponed. Cause=%s", rar_aggr_level, to_string(ret)); + } + return ret; +} + // Schedules RAR // On every call to this function, we schedule the oldest RAR which is still within the window. If outside the window we // discard it. @@ -152,10 +214,12 @@ void ra_sched::dl_sched(sf_sched* tti_sched) tti_point tti_tx_dl = tti_sched->get_tti_tx_dl(); rar_aggr_level = 2; - while (not pending_rars.empty()) { - sf_sched::pending_rar_t& rar = pending_rars.front(); + for (auto it = pending_rars.begin(); it != pending_rars.end();) { + auto& rar = *it; - // Discard all RARs out of the window. The first one inside the window is scheduled, if we can't we exit + // In case of RAR outside RAR window: + // - if window has passed, discard RAR + // - if window hasn't started, stop loop, as RARs are ordered by TTI srslte::tti_interval rar_window{rar.prach_tti + PRACH_RAR_OFFSET, rar.prach_tti + PRACH_RAR_OFFSET + cc_cfg->cfg.prach_rar_window}; if (not rar_window.contains(tti_tx_dl)) { @@ -167,34 +231,37 @@ void ra_sched::dl_sched(sf_sched* tti_sched) rar_window, tti_tx_dl); srslte::console("%s\n", srslte::to_c_str(str_buffer)); - logger.error("%s", srslte::to_c_str(str_buffer)); - // Remove from pending queue and get next one if window has passed already - pending_rars.pop_front(); + logger.warning("%s", srslte::to_c_str(str_buffer)); + it = pending_rars.erase(it); continue; } - // If window not yet started do not look for more pending RARs return; } // Try to schedule DCI + RBGs for RAR Grant - std::pair ret = tti_sched->alloc_rar(rar_aggr_level, rar); - if (ret.first == alloc_outcome_t::RB_COLLISION) { - // there are not enough RBs for RAR or Msg3 allocation. We can skip this TTI - return; - } - if (ret.first != alloc_outcome_t::SUCCESS) { - // try to scheduler next RAR with different RA-RNTI - continue; - } + uint32_t nof_rar_allocs = 0; + alloc_result ret = allocate_pending_rar(tti_sched, rar, nof_rar_allocs); + + if (ret == alloc_result::success) { + // If RAR allocation was successful: + // - in case all Msg3 grants were allocated, remove pending RAR, and continue with following RAR + // - otherwise, erase only Msg3 grants that were allocated, and stop iteration - uint32_t nof_rar_allocs = ret.second; - if (nof_rar_allocs == rar.nof_grants) { - // all RAR grants were allocated. Remove pending RAR - pending_rars.pop_front(); + if (nof_rar_allocs == rar.msg3_grant.size()) { + it = pending_rars.erase(it); + } else { + std::copy(rar.msg3_grant.begin() + nof_rar_allocs, rar.msg3_grant.end(), rar.msg3_grant.begin()); + rar.msg3_grant.resize(rar.msg3_grant.size() - nof_rar_allocs); + break; + } } else { - // keep the RAR grants that were not scheduled, so we can schedule in next TTI - std::copy(&rar.msg3_grant[nof_rar_allocs], &rar.msg3_grant[rar.nof_grants], &rar.msg3_grant[0]); - rar.nof_grants -= nof_rar_allocs; + // If RAR allocation was not successful: + // - in case of unavailable PDCCH space, try next pending RAR allocation + // - otherwise, stop iteration + if (ret != alloc_result::no_cch_space) { + break; + } + ++it; } } } @@ -213,24 +280,22 @@ int ra_sched::dl_rach_info(dl_sched_rar_info_t rar_info) uint16_t ra_rnti = 1 + (uint16_t)(rar_info.prach_tti % 10u); // find pending rar with same RA-RNTI - for (sf_sched::pending_rar_t& r : pending_rars) { + for (pending_rar_t& r : pending_rars) { if (r.prach_tti.to_uint() == rar_info.prach_tti and ra_rnti == r.ra_rnti) { - if (r.nof_grants >= sched_interface::MAX_RAR_LIST) { + if (r.msg3_grant.size() >= sched_interface::MAX_RAR_LIST) { logger.warning("PRACH ignored, as the the maximum number of RAR grants per tti has been reached"); return SRSLTE_ERROR; } - r.msg3_grant[r.nof_grants] = rar_info; - r.nof_grants++; + r.msg3_grant.push_back(rar_info); return SRSLTE_SUCCESS; } } // create new RAR - sf_sched::pending_rar_t p; - p.ra_rnti = ra_rnti; - p.prach_tti = tti_point{rar_info.prach_tti}; - p.nof_grants = 1; - p.msg3_grant[0] = rar_info; + pending_rar_t p; + p.ra_rnti = ra_rnti; + p.prach_tti = tti_point{rar_info.prach_tti}; + p.msg3_grant.push_back(rar_info); pending_rars.push_back(p); return SRSLTE_SUCCESS; @@ -239,13 +304,14 @@ int ra_sched::dl_rach_info(dl_sched_rar_info_t rar_info) //! Schedule Msg3 grants in UL based on allocated RARs void ra_sched::ul_sched(sf_sched* sf_dl_sched, sf_sched* sf_msg3_sched) { - const std::vector& alloc_rars = sf_dl_sched->get_allocated_rars(); + srslte::const_span alloc_rars = sf_dl_sched->get_allocated_rars(); for (const auto& rar : alloc_rars) { for (const auto& msg3grant : rar.rar_grant.msg3_grant) { uint16_t crnti = msg3grant.data.temp_crnti; auto user_it = ue_db->find(crnti); - if (user_it != ue_db->end() and sf_msg3_sched->alloc_msg3(user_it->second.get(), msg3grant)) { + if (user_it != ue_db->end() and + sf_msg3_sched->alloc_msg3(user_it->second.get(), msg3grant) == alloc_result::success) { logger.debug("SCHED: Queueing Msg3 for rnti=0x%x at tti=%d", crnti, sf_msg3_sched->get_tti_tx_ul().to_uint()); } else { logger.error( @@ -264,10 +330,10 @@ void ra_sched::reset() * Carrier scheduling *******************************************************/ -sched::carrier_sched::carrier_sched(rrc_interface_mac* rrc_, - sched_ue_list* ue_db_, - uint32_t enb_cc_idx_, - sched_result_list* sched_results_) : +sched::carrier_sched::carrier_sched(rrc_interface_mac* rrc_, + sched_ue_list* ue_db_, + uint32_t enb_cc_idx_, + sched_result_ringbuffer* sched_results_) : rrc(rrc_), ue_db(ue_db_), logger(srslog::fetch_basic_logger("MAC")), @@ -277,7 +343,7 @@ sched::carrier_sched::carrier_sched(rrc_interface_mac* rrc_, sf_dl_mask.resize(1, 0); } -sched::carrier_sched::~carrier_sched() {} +sched::carrier_sched::~carrier_sched() = default; void sched::carrier_sched::reset() { @@ -318,7 +384,7 @@ const cc_sched_result& sched::carrier_sched::generate_tti_result(tti_point tti_r { sf_sched* tti_sched = get_sf_sched(tti_rx); sf_sched_result* sf_result = prev_sched_results->get_sf(tti_rx); - cc_sched_result* cc_result = sf_result->new_cc(enb_cc_idx); + cc_sched_result* cc_result = sf_result->get_cc(enb_cc_idx); bool dl_active = sf_dl_mask[tti_sched->get_tti_tx_dl().to_uint() % sf_dl_mask.size()] == 0; @@ -329,10 +395,9 @@ const cc_sched_result& sched::carrier_sched::generate_tti_result(tti_point tti_r /* Schedule PHICH */ for (auto& ue_pair : *ue_db) { - if (cc_result->ul_sched_result.nof_phich_elems >= MAX_PHICH_LIST) { + if (tti_sched->alloc_phich(ue_pair.second.get()) == alloc_result::no_grant_space) { break; } - tti_sched->alloc_phich(ue_pair.second.get(), &cc_result->ul_sched_result); } /* Schedule DL control data */ @@ -402,13 +467,13 @@ int sched::carrier_sched::alloc_ul_users(sf_sched* tti_sched) sf_sched* sched::carrier_sched::get_sf_sched(tti_point tti_rx) { - sf_sched* ret = &sf_scheds[tti_rx.to_uint() % sf_scheds.size()]; + sf_sched* ret = &sf_scheds[tti_rx.to_uint()]; if (ret->get_tti_rx() != tti_rx) { - sf_sched_result* sf_res = prev_sched_results->get_sf(tti_rx); - if (sf_res == nullptr) { + if (not prev_sched_results->has_sf(tti_rx)) { // Reset if tti_rx has not been yet set in the sched results - sf_res = prev_sched_results->new_tti(tti_rx); + prev_sched_results->new_tti(tti_rx); } + sf_sched_result* sf_res = prev_sched_results->get_sf(tti_rx); // start new TTI for the given CC. ret->new_tti(tti_rx, sf_res); } diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 35da3034e..12efa4acf 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -23,54 +23,49 @@ #include "srsenb/hdr/stack/mac/sched_helpers.h" #include "srslte/common/string_helpers.h" -using srslte::tti_point; - namespace srsenb { -const char* alloc_outcome_t::to_string() const +const char* to_string(alloc_result result) { switch (result) { - case SUCCESS: + case alloc_result::success: return "success"; - case DCI_COLLISION: - return "dci_collision"; - case RB_COLLISION: - return "rb_collision"; - case ERROR: + case alloc_result::sch_collision: + return "Collision with existing SCH allocations"; + case alloc_result::other_cause: return "error"; - case NOF_RB_INVALID: - return "invalid nof prbs"; - case PUCCH_COLLISION: - return "pucch_collision"; - case MEASGAP_COLLISION: - return "measgap_collision"; - case ALREADY_ALLOC: - return "already allocated"; - case NO_DATA: - return "no pending data to allocate"; - case INVALID_PRBMASK: - return "invalid rbg mask"; - case INVALID_CARRIER: - return "invalid eNB carrier"; + case alloc_result::no_cch_space: + return "No space available in PUCCH or PDCCH"; + case alloc_result::no_sch_space: + return "Requested number of PRBs not available"; + case alloc_result::no_rnti_opportunity: + return "rnti cannot be allocated (e.g. already allocated, no data, meas gap collision, carrier inactive, etc.)"; + case alloc_result::invalid_grant_params: + return "invalid grant arguments (e.g. invalid prb mask)"; + case alloc_result::invalid_coderate: + return "Effective coderate exceeds threshold"; + case alloc_result::no_grant_space: + return "Max number of allocations reached"; default: break; } return "unknown error"; } -cc_sched_result* sf_sched_result::new_cc(uint32_t enb_cc_idx) +void sf_sched_result::new_tti(tti_point tti_rx_) { - if (enb_cc_idx >= enb_cc_list.size()) { - enb_cc_list.resize(enb_cc_idx + 1); + assert(tti_rx != tti_rx_); + tti_rx = tti_rx_; + for (auto& cc : enb_cc_list) { + cc = {}; } - return &enb_cc_list[enb_cc_idx]; } bool sf_sched_result::is_ul_alloc(uint16_t rnti) const { for (const auto& cc : enb_cc_list) { - for (uint32_t j = 0; j < cc.ul_sched_result.nof_dci_elems; ++j) { - if (cc.ul_sched_result.pusch[j].dci.rnti == rnti) { + for (const auto& pusch : cc.ul_sched_result.pusch) { + if (pusch.dci.rnti == rnti) { return true; } } @@ -80,8 +75,8 @@ bool sf_sched_result::is_ul_alloc(uint16_t rnti) const bool sf_sched_result::is_dl_alloc(uint16_t rnti) const { for (const auto& cc : enb_cc_list) { - for (uint32_t j = 0; j < cc.dl_sched_result.nof_data_elems; ++j) { - if (cc.dl_sched_result.data[j].dci.rnti == rnti) { + for (const auto& data : cc.dl_sched_result.data) { + if (data.dci.rnti == rnti) { return true; } } @@ -89,36 +84,18 @@ bool sf_sched_result::is_dl_alloc(uint16_t rnti) const return false; } -sf_sched_result* sched_result_list::new_tti(srslte::tti_point tti_rx) -{ - sf_sched_result* res = &results[tti_rx.to_uint() % results.size()]; - res->tti_rx = tti_rx; - res->enb_cc_list.clear(); - return res; -} - -sf_sched_result* sched_result_list::get_sf(srslte::tti_point tti_rx) -{ - sf_sched_result* res = &results[tti_rx.to_uint() % results.size()]; - return (res->tti_rx != tti_rx) ? nullptr : res; -} - -const sf_sched_result* sched_result_list::get_sf(srslte::tti_point tti_rx) const -{ - const sf_sched_result* res = &results[tti_rx.to_uint() % results.size()]; - return (res->tti_rx != tti_rx) ? nullptr : res; -} - -const cc_sched_result* sched_result_list::get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx) const +void sched_result_ringbuffer::set_nof_carriers(uint32_t nof_carriers_) { - const sf_sched_result* res = get_sf(tti_rx); - return res != nullptr ? res->get_cc(enb_cc_idx) : nullptr; + nof_carriers = nof_carriers_; + for (auto& sf_res : results) { + sf_res.enb_cc_list.resize(nof_carriers_); + } } -cc_sched_result* sched_result_list::get_cc(srslte::tti_point tti_rx, uint32_t enb_cc_idx) +void sched_result_ringbuffer::new_tti(srslte::tti_point tti_rx) { - sf_sched_result* res = get_sf(tti_rx); - return res != nullptr ? res->get_cc(enb_cc_idx) : nullptr; + sf_sched_result* res = &results[tti_rx.to_uint()]; + res->new_tti(tti_rx); } /******************************************************* @@ -127,10 +104,8 @@ cc_sched_result* sched_result_list::get_cc(srslte::tti_point tti_rx, uint32_t en void sf_grid_t::init(const sched_cell_params_t& cell_params_) { - cc_cfg = &cell_params_; - nof_rbgs = cc_cfg->nof_rbgs; - si_n_rbg = srslte::ceil_div(4, cc_cfg->P); - rar_n_rbg = srslte::ceil_div(3, cc_cfg->P); + cc_cfg = &cell_params_; + nof_rbgs = cc_cfg->nof_rbgs; dl_mask.resize(nof_rbgs); ul_mask.resize(cc_cfg->nof_prb()); @@ -155,7 +130,6 @@ void sf_grid_t::new_tti(tti_point tti_rx_) dl_mask.reset(); ul_mask.reset(); - avail_rbg = nof_rbgs; // Reserve PRBs for PUCCH ul_mask |= pucch_mask; @@ -177,79 +151,80 @@ void sf_grid_t::new_tti(tti_point tti_rx_) } //! Allocates CCEs and RBs for the given mask and allocation type (e.g. data, BC, RAR, paging) -alloc_outcome_t sf_grid_t::alloc_dl(uint32_t aggr_idx, - alloc_type_t alloc_type, - rbgmask_t alloc_mask, - sched_ue* user, - bool has_pusch_grant) +alloc_result sf_grid_t::alloc_dl(uint32_t aggr_idx, + alloc_type_t alloc_type, + rbgmask_t alloc_mask, + sched_ue* user, + bool has_pusch_grant) { // Check RBG collision if ((dl_mask & alloc_mask).any()) { - return alloc_outcome_t::RB_COLLISION; + logger.debug("SCHED: Provided RBG mask collides with allocation previously made.\n"); + return alloc_result::sch_collision; } // Allocate DCI in PDCCH if (not pdcch_alloc.alloc_dci(alloc_type, aggr_idx, user, has_pusch_grant)) { - if (user != nullptr) { - if (logger.debug.enabled()) { - logger.debug("No space in PDCCH for rnti=0x%x DL tx. Current PDCCH allocation: %s", + if (logger.debug.enabled()) { + if (user != nullptr) { + logger.debug("SCHED: No space in PDCCH for rnti=0x%x DL tx. Current PDCCH allocation:\n%s", user->get_rnti(), pdcch_alloc.result_to_string(true).c_str()); + } else { + logger.debug("SCHED: No space in PDCCH for DL tx. Current PDCCH allocation:\n%s", + pdcch_alloc.result_to_string(true).c_str()); } } - return alloc_outcome_t::DCI_COLLISION; + return alloc_result::no_cch_space; } // Allocate RBGs dl_mask |= alloc_mask; - avail_rbg -= alloc_mask.count(); - return alloc_outcome_t::SUCCESS; + return alloc_result::success; } -//! Allocates CCEs and RBs for control allocs. It allocates RBs in a contiguous manner. -sf_grid_t::dl_ctrl_alloc_t sf_grid_t::alloc_dl_ctrl(uint32_t aggr_idx, alloc_type_t alloc_type) +/// Allocates CCEs and RBs for control allocs. It allocates RBs in a contiguous manner. +alloc_result sf_grid_t::alloc_dl_ctrl(uint32_t aggr_idx, rbg_interval rbg_range, alloc_type_t alloc_type) { - rbg_interval range{nof_rbgs - avail_rbg, - nof_rbgs - avail_rbg + ((alloc_type == alloc_type_t::DL_RAR) ? rar_n_rbg : si_n_rbg)}; - if (alloc_type != alloc_type_t::DL_RAR and alloc_type != alloc_type_t::DL_BC and alloc_type != alloc_type_t::DL_PCCH) { logger.error("SCHED: DL control allocations must be RAR/BC/PDCCH"); - return {alloc_outcome_t::ERROR, range}; + return alloc_result::other_cause; } - // Setup range starting from left - if (range.stop() > nof_rbgs) { - return {alloc_outcome_t::RB_COLLISION, range}; + // Setup rbg_range starting from left + if (rbg_range.stop() > nof_rbgs) { + return alloc_result::sch_collision; } // allocate DCI and RBGs rbgmask_t new_mask(dl_mask.size()); - new_mask.fill(range.start(), range.stop()); - return {alloc_dl(aggr_idx, alloc_type, new_mask), range}; + new_mask.fill(rbg_range.start(), rbg_range.stop()); + return alloc_dl(aggr_idx, alloc_type, new_mask); } //! Allocates CCEs and RBs for a user DL data alloc. -alloc_outcome_t sf_grid_t::alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant) +alloc_result sf_grid_t::alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant) { srslte_dci_format_t dci_format = user->get_dci_format(); uint32_t nof_bits = srslte_dci_format_sizeof(&cc_cfg->cfg.cell, nullptr, nullptr, dci_format); uint32_t aggr_idx = user->get_aggr_level(cc_cfg->enb_cc_idx, nof_bits); - alloc_outcome_t ret = alloc_dl(aggr_idx, alloc_type_t::DL_DATA, user_mask, user, has_pusch_grant); + alloc_result ret = alloc_dl(aggr_idx, alloc_type_t::DL_DATA, user_mask, user, has_pusch_grant); return ret; } -alloc_outcome_t sf_grid_t::alloc_ul_data(sched_ue* user, prb_interval alloc, bool needs_pdcch, bool strict) +alloc_result sf_grid_t::alloc_ul_data(sched_ue* user, prb_interval alloc, bool needs_pdcch, bool strict) { if (alloc.stop() > ul_mask.size()) { - return alloc_outcome_t::ERROR; + return alloc_result::no_sch_space; } prbmask_t newmask(ul_mask.size()); newmask.fill(alloc.start(), alloc.stop()); if (strict and (ul_mask & newmask).any()) { - return alloc_outcome_t::RB_COLLISION; + logger.debug("SCHED: Failed UL allocation. Cause: %s", to_string(alloc_result::sch_collision)); + return alloc_result::sch_collision; } // Generate PDCCH except for RAR and non-adaptive retx @@ -258,17 +233,17 @@ alloc_outcome_t sf_grid_t::alloc_ul_data(sched_ue* user, prb_interval alloc, boo uint32_t aggr_idx = user->get_aggr_level(cc_cfg->enb_cc_idx, nof_bits); if (not pdcch_alloc.alloc_dci(alloc_type_t::UL_DATA, aggr_idx, user)) { if (logger.debug.enabled()) { - logger.debug("No space in PDCCH for rnti=0x%x UL tx. Current PDCCH allocation: %s", + logger.debug("No space in PDCCH for rnti=0x%x UL tx. Current PDCCH allocation:\n%s", user->get_rnti(), pdcch_alloc.result_to_string(true).c_str()); } - return alloc_outcome_t::DCI_COLLISION; + return alloc_result::no_cch_space; } } ul_mask |= newmask; - return alloc_outcome_t::SUCCESS; + return alloc_result::success; } bool sf_grid_t::reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg) @@ -277,10 +252,23 @@ bool sf_grid_t::reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg) return true; } -alloc_outcome_t sf_grid_t::reserve_ul_prbs(prb_interval alloc, bool strict) +void sf_grid_t::rem_last_alloc_dl(rbg_interval rbgs) +{ + if (pdcch_alloc.nof_allocs() == 0) { + logger.error("Remove DL alloc called for empty Subframe RB grid"); + return; + } + + pdcch_alloc.rem_last_dci(); + rbgmask_t rbgmask(dl_mask.size()); + rbgmask.fill(rbgs.start(), rbgs.stop()); + dl_mask &= ~rbgmask; +} + +alloc_result sf_grid_t::reserve_ul_prbs(prb_interval alloc, bool strict) { if (alloc.stop() > ul_mask.size()) { - return alloc_outcome_t::ERROR; + return alloc_result::invalid_grant_params; } prbmask_t newmask(ul_mask.size()); @@ -288,14 +276,17 @@ alloc_outcome_t sf_grid_t::reserve_ul_prbs(prb_interval alloc, bool strict) return reserve_ul_prbs(newmask, strict); } -alloc_outcome_t sf_grid_t::reserve_ul_prbs(const prbmask_t& prbmask, bool strict) +alloc_result sf_grid_t::reserve_ul_prbs(const prbmask_t& prbmask, bool strict) { - alloc_outcome_t ret = alloc_outcome_t::SUCCESS; + alloc_result ret = alloc_result::success; if (strict and (ul_mask & prbmask).any()) { - fmt::memory_buffer tmp_buffer; - fmt::format_to(tmp_buffer, "There was a collision in the UL. Current mask={:x}, new mask={:x}", ul_mask, prbmask); - logger.error("%s", srslte::to_c_str(tmp_buffer)); - ret = alloc_outcome_t::ERROR; + if (logger.info.enabled()) { + fmt::memory_buffer tmp_buffer; + fmt::format_to( + tmp_buffer, "There was a collision in the UL. Current mask=0x{:x}, new mask=0x{:x}", ul_mask, prbmask); + logger.info("%s", srslte::to_c_str(tmp_buffer)); + ret = alloc_result::sch_collision; + } } ul_mask |= prbmask; return ret; @@ -346,7 +337,7 @@ void sf_sched::init(const sched_cell_params_t& cell_params_) { cc_cfg = &cell_params_; tti_alloc.init(*cc_cfg); - max_msg3_prb = std::max(6u, cc_cfg->cfg.cell.nof_prb - tti_alloc.get_pucch_width()); + max_msg3_prb = std::max(6U, cc_cfg->cfg.cell.nof_prb - tti_alloc.get_pucch_width()); } void sf_sched::new_tti(tti_point tti_rx_, sf_sched_result* cc_results_) @@ -371,148 +362,113 @@ void sf_sched::new_tti(tti_point tti_rx_, sf_sched_result* cc_results_) bool sf_sched::is_dl_alloc(uint16_t rnti) const { - for (const auto& a : data_allocs) { - if (a.rnti == rnti) { - return true; - } - } - return false; + return std::any_of(data_allocs.begin(), data_allocs.end(), [rnti](const dl_alloc_t& u) { return u.rnti == rnti; }); } bool sf_sched::is_ul_alloc(uint16_t rnti) const { - for (const auto& a : ul_data_allocs) { - if (a.rnti == rnti) { - return true; - } - } - return false; + return std::any_of( + ul_data_allocs.begin(), ul_data_allocs.end(), [rnti](const ul_alloc_t& u) { return u.rnti == rnti; }); } -sf_sched::ctrl_code_t sf_sched::alloc_dl_ctrl(uint32_t aggr_lvl, uint32_t tbs_bytes, uint16_t rnti) +alloc_result sf_sched::alloc_sib(uint32_t aggr_lvl, uint32_t sib_idx, uint32_t sib_ntx, rbg_interval rbgs) { - ctrl_alloc_t ctrl_alloc{}; - - // based on rnti, check which type of alloc - alloc_type_t alloc_type = alloc_type_t::DL_RAR; - if (rnti == SRSLTE_SIRNTI) { - alloc_type = alloc_type_t::DL_BC; - } else if (rnti == SRSLTE_PRNTI) { - alloc_type = alloc_type_t::DL_PCCH; + if (bc_allocs.full()) { + logger.warning("SCHED: Maximum number of Broadcast allocations reached"); + return alloc_result::no_grant_space; } + bc_alloc_t bc_alloc; - /* Allocate space in the DL RBG and PDCCH grids */ - sf_grid_t::dl_ctrl_alloc_t ret = tti_alloc.alloc_dl_ctrl(aggr_lvl, alloc_type); - if (not ret.outcome) { - return {ret.outcome, ctrl_alloc}; + // Allocate SIB RBGs and PDCCH + alloc_result ret = tti_alloc.alloc_dl_ctrl(aggr_lvl, rbgs, alloc_type_t::DL_BC); + if (ret != alloc_result::success) { + return ret; } - // Allocation Successful - ctrl_alloc.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; - ctrl_alloc.rbg_range = ret.rbg_range; - ctrl_alloc.rnti = rnti; - ctrl_alloc.req_bytes = tbs_bytes; - ctrl_alloc.alloc_type = alloc_type; - - return {ret.outcome, ctrl_alloc}; -} - -alloc_outcome_t sf_sched::alloc_bc(uint32_t aggr_lvl, uint32_t sib_idx, uint32_t sib_ntx) -{ - uint32_t sib_len = cc_cfg->cfg.sibs[sib_idx].len; - uint32_t rv = get_rvidx(sib_ntx); - ctrl_code_t ret = alloc_dl_ctrl(aggr_lvl, sib_len, SRSLTE_SIRNTI); - if (not ret.first) { - logger.warning("SCHED: Could not allocate SIB=%d, L=%d, len=%d, cause=%s", - sib_idx + 1, - aggr_lvl, - sib_len, - ret.first.to_string()); - return ret.first; + // Generate DCI for SIB + if (not generate_sib_dci(bc_alloc.bc_grant, get_tti_tx_dl(), sib_idx, sib_ntx, rbgs, *cc_cfg, tti_alloc.get_cfi())) { + // Cancel on-going allocation + tti_alloc.rem_last_alloc_dl(rbgs); + return alloc_result::invalid_coderate; } - // BC allocation successful - bc_alloc_t bc_alloc(ret.second); - bc_alloc.rv = rv; - bc_alloc.sib_idx = sib_idx; + // Allocation Successful + bc_alloc.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; + bc_alloc.rbg_range = rbgs; + bc_alloc.req_bytes = cc_cfg->cfg.sibs[sib_idx].len; bc_allocs.push_back(bc_alloc); - return ret.first; + return alloc_result::success; } -alloc_outcome_t sf_sched::alloc_paging(uint32_t aggr_lvl, uint32_t paging_payload) +alloc_result sf_sched::alloc_paging(uint32_t aggr_lvl, uint32_t paging_payload, rbg_interval rbgs) { - if (bc_allocs.size() >= sched_interface::MAX_BC_LIST) { + if (bc_allocs.full()) { logger.warning("SCHED: Maximum number of Broadcast allocations reached"); - return alloc_outcome_t::ERROR; + return alloc_result::no_grant_space; } - ctrl_code_t ret = alloc_dl_ctrl(aggr_lvl, paging_payload, SRSLTE_PRNTI); - if (not ret.first) { - logger.warning( - "SCHED: Could not allocate Paging with payload length=%d, cause=%s", paging_payload, ret.first.to_string()); - return ret.first; + bc_alloc_t bc_alloc; + + // Allocate Paging RBGs and PDCCH + alloc_result ret = tti_alloc.alloc_dl_ctrl(aggr_lvl, rbgs, alloc_type_t::DL_PCCH); + if (ret != alloc_result::success) { + return ret; + } + + // Generate DCI for Paging message + if (not generate_paging_dci(bc_alloc.bc_grant, get_tti_tx_dl(), paging_payload, rbgs, *cc_cfg, tti_alloc.get_cfi())) { + // Cancel on-going allocation + tti_alloc.rem_last_alloc_dl(rbgs); + return alloc_result::invalid_coderate; } - // Paging allocation successful - bc_alloc_t bc_alloc(ret.second); + // Allocation Successful + bc_alloc.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; + bc_alloc.rbg_range = rbgs; + bc_alloc.req_bytes = paging_payload; bc_allocs.push_back(bc_alloc); - return ret.first; + return alloc_result::success; } -std::pair sf_sched::alloc_rar(uint32_t aggr_lvl, const pending_rar_t& rar) +alloc_result sf_sched::alloc_rar(uint32_t aggr_lvl, const pending_rar_t& rar, rbg_interval rbgs, uint32_t nof_grants) { - const uint32_t msg3_grant_size = 3; - std::pair ret = {alloc_outcome_t::ERROR, 0}; - if (rar_allocs.size() >= sched_interface::MAX_RAR_LIST) { - logger.warning("SCHED: Maximum number of RAR allocations per TTI reached."); - return ret; + static const uint32_t msg3_nof_prbs = 3; + if (rar_allocs.full()) { + logger.info("SCHED: Maximum number of RAR allocations per TTI reached."); + return alloc_result::no_grant_space; } - for (uint32_t nof_grants = rar.nof_grants; nof_grants > 0; nof_grants--) { - uint32_t buf_rar = 7 * nof_grants + 1; // 1+6 bytes per RAR subheader+body and 1 byte for Backoff - uint32_t total_msg3_size = msg3_grant_size * nof_grants; + uint32_t buf_rar = 7 * nof_grants + 1; // 1+6 bytes per RAR subheader+body and 1 byte for Backoff + uint32_t total_ul_nof_prbs = msg3_nof_prbs * nof_grants; - // check if there is enough space for Msg3, try again with a lower number of grants - if (last_msg3_prb + total_msg3_size > max_msg3_prb) { - ret.first = alloc_outcome_t::RB_COLLISION; - continue; - } + // check if there is enough space for Msg3 + if (last_msg3_prb + total_ul_nof_prbs > max_msg3_prb) { + return alloc_result::sch_collision; + } - // allocate RBs and PDCCH - sf_sched::ctrl_code_t ret2 = alloc_dl_ctrl(aggr_lvl, buf_rar, rar.ra_rnti); - ret.first = ret2.first.result; - ret.second = nof_grants; + // allocate RBGs and PDCCH + alloc_result ret = tti_alloc.alloc_dl_ctrl(aggr_lvl, rbgs, alloc_type_t::DL_RAR); + if (ret != alloc_result::success) { + return ret; + } - // if there was no space for the RAR, try again - if (ret.first == alloc_outcome_t::RB_COLLISION) { - continue; - } - // if any other error, return - if (ret.first != alloc_outcome_t::SUCCESS) { - logger.warning("SCHED: Could not allocate RAR for L=%d, cause=%s", aggr_lvl, ret.first.to_string()); - return ret; - } + // Generate DCI for RAR + rar_alloc_t rar_alloc; + if (not generate_rar_dci( + rar_alloc.rar_grant, get_tti_tx_dl(), rar, rbgs, nof_grants, last_msg3_prb, *cc_cfg, tti_alloc.get_cfi())) { + // Cancel on-going allocation + tti_alloc.rem_last_alloc_dl(rbgs); + return alloc_result::invalid_coderate; + } - // RAR allocation successful - sched_interface::dl_sched_rar_t rar_grant = {}; - rar_grant.msg3_grant.resize(nof_grants); - for (uint32_t i = 0; i < nof_grants; ++i) { - rar_grant.msg3_grant[i].data = rar.msg3_grant[i]; - rar_grant.msg3_grant[i].grant.tpc_pusch = 3; - rar_grant.msg3_grant[i].grant.trunc_mcs = 0; - uint32_t rba = srslte_ra_type2_to_riv(msg3_grant_size, last_msg3_prb, cc_cfg->cfg.cell.nof_prb); - rar_grant.msg3_grant[i].grant.rba = rba; - - last_msg3_prb += msg3_grant_size; - } - rar_allocs.emplace_back(ret2.second, rar_grant); + // RAR allocation successful + rar_alloc.alloc_data.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; + rar_alloc.alloc_data.rbg_range = rbgs; + rar_alloc.alloc_data.req_bytes = buf_rar; + rar_allocs.push_back(rar_alloc); + last_msg3_prb += total_ul_nof_prbs * nof_grants; - break; - } - if (ret.first != alloc_outcome_t::SUCCESS) { - logger.info("SCHED: RAR allocation postponed due to lack of RBs"); - } return ret; } @@ -528,24 +484,24 @@ bool is_periodic_cqi_expected(const sched_interface::ue_cfg_t& ue_cfg, tti_point return false; } -alloc_outcome_t sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_mask, uint32_t pid) +alloc_result sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_mask, uint32_t pid) { - if (data_allocs.size() >= sched_interface::MAX_DATA_LIST) { + if (data_allocs.full()) { logger.warning("SCHED: Maximum number of DL allocations reached"); - return alloc_outcome_t::ERROR; + return alloc_result::no_grant_space; } if (is_dl_alloc(user->get_rnti())) { logger.warning("SCHED: Attempt to assign multiple harq pids to the same user rnti=0x%x", user->get_rnti()); - return alloc_outcome_t::ALREADY_ALLOC; + return alloc_result::no_rnti_opportunity; } auto* cc = user->find_ue_carrier(cc_cfg->enb_cc_idx); if (cc == nullptr or cc->cc_state() != cc_st::active) { - return alloc_outcome_t::INVALID_CARRIER; + return alloc_result::no_rnti_opportunity; } if (not user->pdsch_enabled(srslte::tti_point{get_tti_rx()}, cc_cfg->enb_cc_idx)) { - return alloc_outcome_t::MEASGAP_COLLISION; + return alloc_result::no_rnti_opportunity; } // Check if allocation would cause segmentation @@ -554,15 +510,15 @@ alloc_outcome_t sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_ma // It is newTx rbg_interval r = user->get_required_dl_rbgs(cc_cfg->enb_cc_idx); if (r.start() > user_mask.count()) { - logger.warning("SCHED: The number of RBGs allocated to rnti=0x%x will force segmentation", user->get_rnti()); - return alloc_outcome_t::NOF_RB_INVALID; + logger.debug("SCHED: The number of RBGs allocated to rnti=0x%x will force segmentation", user->get_rnti()); + return alloc_result::invalid_grant_params; } } srslte_dci_format_t dci_format = user->get_dci_format(); if (dci_format == SRSLTE_DCI_FORMAT1A and not is_contiguous(user_mask)) { logger.warning("SCHED: Can't use distributed RBGs for DCI format 1A"); - return alloc_outcome_t::INVALID_PRBMASK; + return alloc_result::invalid_grant_params; } bool has_pusch_grant = is_ul_alloc(user->get_rnti()) or cc_results->is_ul_alloc(user->get_rnti()); @@ -578,28 +534,28 @@ alloc_outcome_t sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_ma prb_interval alloc = {}; uint32_t L = user->get_required_prb_ul(cc_cfg->enb_cc_idx, srslte::ceil_div(SRSLTE_UCI_CQI_CODED_PUCCH_B + 2, 8)); tti_alloc.find_ul_alloc(L, &alloc); - has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc); + has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc) == alloc_result::success; if (ue_cc_idx != 0 and not has_pusch_grant) { // For SCells, if we can't allocate small PUSCH grant, abort DL allocation - return alloc_outcome_t::PUCCH_COLLISION; + return alloc_result::no_cch_space; } } // Try to allocate RBGs, PDCCH, and PUCCH - alloc_outcome_t ret = tti_alloc.alloc_dl_data(user, user_mask, has_pusch_grant); + alloc_result ret = tti_alloc.alloc_dl_data(user, user_mask, has_pusch_grant); - if (ret == alloc_outcome_t::DCI_COLLISION and not has_pusch_grant and not data_allocs.empty() and + if (ret == alloc_result::no_cch_space and not has_pusch_grant and not data_allocs.empty() and user->get_ul_harq(get_tti_tx_ul(), get_enb_cc_idx())->is_empty()) { // PUCCH may be too full. Attempt small UL grant allocation for UCI-PUSCH uint32_t L = user->get_required_prb_ul(cc_cfg->enb_cc_idx, srslte::ceil_div(SRSLTE_UCI_CQI_CODED_PUCCH_B + 2, 8)); prb_interval alloc = {}; tti_alloc.find_ul_alloc(L, &alloc); - has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc); + has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc) == alloc_result::success; if (has_pusch_grant) { ret = tti_alloc.alloc_dl_data(user, user_mask, has_pusch_grant); } } - if (ret != alloc_outcome_t::SUCCESS) { + if (ret != alloc_result::success) { return ret; } @@ -611,49 +567,49 @@ alloc_outcome_t sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_ma alloc.pid = pid; data_allocs.push_back(alloc); - return alloc_outcome_t::SUCCESS; + return alloc_result::success; } -alloc_outcome_t +alloc_result sf_sched::alloc_ul(sched_ue* user, prb_interval alloc, ul_alloc_t::type_t alloc_type, bool is_msg3, int msg3_mcs) { - if (ul_data_allocs.size() >= sched_interface::MAX_DATA_LIST) { - logger.warning("SCHED: Maximum number of UL allocations reached"); - return alloc_outcome_t::ERROR; + if (ul_data_allocs.full()) { + logger.debug("SCHED: Maximum number of UL allocations=%zd reached", ul_data_allocs.size()); + return alloc_result::no_grant_space; } - // Check whether user was already allocated if (is_ul_alloc(user->get_rnti())) { - logger.warning("SCHED: Attempt to assign multiple ul_harq_proc to the same user rnti=0x%x", user->get_rnti()); - return alloc_outcome_t::ALREADY_ALLOC; + logger.warning("SCHED: Attempt to assign multiple UL grants to the same user rnti=0x%x", user->get_rnti()); + return alloc_result::no_rnti_opportunity; } // Check if there is no collision with measGap bool needs_pdcch = alloc_type == ul_alloc_t::ADAPT_RETX or (alloc_type == ul_alloc_t::NEWTX and not is_msg3); - if (not user->pusch_enabled(srslte::tti_point{get_tti_rx()}, cc_cfg->enb_cc_idx, needs_pdcch)) { - return alloc_outcome_t::MEASGAP_COLLISION; + if (not user->pusch_enabled(get_tti_rx(), cc_cfg->enb_cc_idx, needs_pdcch)) { + logger.debug("SCHED: PDCCH would collide with rnti=0x%x Measurement Gap", user->get_rnti()); + return alloc_result::no_rnti_opportunity; } // Allocate RBGs and DCI space - bool allow_pucch_collision = cc_cfg->nof_prb() == 6 and is_msg3; - alloc_outcome_t ret = tti_alloc.alloc_ul_data(user, alloc, needs_pdcch, not allow_pucch_collision); - if (ret != alloc_outcome_t::SUCCESS) { + bool allow_pucch_collision = cc_cfg->nof_prb() == 6 and is_msg3; + alloc_result ret = tti_alloc.alloc_ul_data(user, alloc, needs_pdcch, not allow_pucch_collision); + if (ret != alloc_result::success) { return ret; } - ul_alloc_t ul_alloc = {}; - ul_alloc.type = alloc_type; - ul_alloc.is_msg3 = is_msg3; - ul_alloc.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; - ul_alloc.rnti = user->get_rnti(); - ul_alloc.alloc = alloc; - ul_alloc.msg3_mcs = msg3_mcs; - ul_data_allocs.push_back(ul_alloc); + ul_data_allocs.emplace_back(); + ul_alloc_t& ul_alloc = ul_data_allocs.back(); + ul_alloc.type = alloc_type; + ul_alloc.is_msg3 = is_msg3; + ul_alloc.dci_idx = tti_alloc.get_pdcch_grid().nof_allocs() - 1; + ul_alloc.rnti = user->get_rnti(); + ul_alloc.alloc = alloc; + ul_alloc.msg3_mcs = msg3_mcs; - return alloc_outcome_t::SUCCESS; + return alloc_result::success; } -alloc_outcome_t sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc) +alloc_result sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc) { // check whether adaptive/non-adaptive retx/newtx ul_alloc_t::type_t alloc_type; @@ -661,7 +617,7 @@ alloc_outcome_t sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc) bool has_retx = h->has_pending_retx(); if (not has_retx) { alloc_type = ul_alloc_t::NEWTX; - } else if (h->retx_requires_pdcch(tti_point{get_tti_tx_ul()}, alloc)) { + } else if (h->retx_requires_pdcch(get_tti_tx_ul(), alloc)) { alloc_type = ul_alloc_t::ADAPT_RETX; } else { alloc_type = ul_alloc_t::NOADAPT_RETX; @@ -670,150 +626,32 @@ alloc_outcome_t sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc) return alloc_ul(user, alloc, alloc_type, h->is_msg3()); } -bool sf_sched::alloc_phich(sched_ue* user, sched_interface::ul_sched_res_t* ul_sf_result) +alloc_result sf_sched::alloc_phich(sched_ue* user) { - if (ul_sf_result->nof_phich_elems >= sched_interface::MAX_PHICH_LIST) { + using phich_t = sched_interface::ul_sched_phich_t; + + auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; + if (ul_sf_result->phich.full()) { logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); - return false; + return alloc_result::no_grant_space; } - using phich_t = sched_interface::ul_sched_phich_t; - auto& phich_list = ul_sf_result->phich[ul_sf_result->nof_phich_elems]; auto p = user->get_active_cell_index(cc_cfg->enb_cc_idx); if (not p.first) { // user does not support this carrier - return false; + return alloc_result::no_rnti_opportunity; } ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); /* Indicate PHICH acknowledgment if needed */ if (h->has_pending_phich()) { - phich_list.phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; - phich_list.rnti = user->get_rnti(); - ul_sf_result->nof_phich_elems++; - return true; - } - return false; -} - -void sf_sched::set_bc_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::dl_sched_res_t* dl_result) -{ - for (const auto& bc_alloc : bc_allocs) { - sched_interface::dl_sched_bc_t* bc = &dl_result->bc[dl_result->nof_bc_elems]; - - // assign NCCE/L - bc->dci.location = dci_result[bc_alloc.dci_idx]->dci_pos; - - /* Generate DCI format1A */ - prb_interval prb_range = prb_interval::rbgs_to_prbs(bc_alloc.rbg_range, cc_cfg->nof_prb()); - int tbs = generate_format1a(prb_range, bc_alloc.req_bytes, bc_alloc.rv, bc_alloc.rnti, &bc->dci); - - // Setup BC/Paging processes - if (bc_alloc.alloc_type == alloc_type_t::DL_BC) { - if (tbs <= (int)bc_alloc.req_bytes) { - logger.warning("SCHED: Error SIB%d, rbgs=(%d,%d), dci=(%d,%d), len=%d", - bc_alloc.sib_idx + 1, - bc_alloc.rbg_range.start(), - bc_alloc.rbg_range.stop(), - bc->dci.location.L, - bc->dci.location.ncce, - bc_alloc.req_bytes); - continue; - } - - // Setup BC process - bc->index = bc_alloc.sib_idx; - bc->type = sched_interface::dl_sched_bc_t::BCCH; - bc->tbs = (uint32_t)bc_alloc.req_bytes; - - logger.debug("SCHED: SIB%d, rbgs=(%d,%d), dci=(%d,%d), rv=%d, len=%d, period=%d, mcs=%d", - bc_alloc.sib_idx + 1, - bc_alloc.rbg_range.start(), - bc_alloc.rbg_range.stop(), - bc->dci.location.L, - bc->dci.location.ncce, - bc_alloc.rv, - bc_alloc.req_bytes, - cc_cfg->cfg.sibs[bc_alloc.sib_idx].period_rf, - bc->dci.tb[0].mcs_idx); - } else { - // Paging - if (tbs <= 0) { - fmt::memory_buffer str_buffer; - fmt::format_to(str_buffer, "{}", bc_alloc.rbg_range); - logger.warning("SCHED: Error Paging, rbgs=%s, dci=(%d,%d)", - srslte::to_c_str(str_buffer), - bc->dci.location.L, - bc->dci.location.ncce); - continue; - } - - // Setup Paging process - bc->type = sched_interface::dl_sched_bc_t::PCCH; - bc->tbs = (uint32_t)tbs; - - fmt::memory_buffer str_buffer; - fmt::format_to(str_buffer, "{}", bc_alloc.rbg_range); - logger.info("SCHED: PCH, rbgs=%s, dci=(%d,%d), tbs=%d, mcs=%d", - srslte::to_c_str(str_buffer), - bc->dci.location.L, - bc->dci.location.ncce, - tbs, - bc->dci.tb[0].mcs_idx); - } - - dl_result->nof_bc_elems++; - } -} - -void sf_sched::set_rar_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, - sched_interface::dl_sched_res_t* dl_result) -{ - for (const auto& rar_alloc : rar_allocs) { - sched_interface::dl_sched_rar_t* rar = &dl_result->rar[dl_result->nof_rar_elems]; - - // Assign NCCE/L - rar->dci.location = dci_result[rar_alloc.alloc_data.dci_idx]->dci_pos; - - /* Generate DCI format1A */ - prb_interval prb_range = prb_interval::rbgs_to_prbs(rar_alloc.alloc_data.rbg_range, cc_cfg->nof_prb()); - int tbs = generate_format1a(prb_range, rar_alloc.alloc_data.req_bytes, 0, rar_alloc.alloc_data.rnti, &rar->dci); - if (tbs <= 0) { - fmt::memory_buffer str_buffer; - fmt::format_to(str_buffer, "{}", rar_alloc.alloc_data.rbg_range); - logger.warning("SCHED: Error RAR, ra_rnti_idx=%d, rbgs=%s, dci=(%d,%d)", - rar_alloc.alloc_data.rnti, - srslte::to_c_str(str_buffer), - rar->dci.location.L, - rar->dci.location.ncce); - continue; - } - - // Setup RAR process - rar->tbs = rar_alloc.alloc_data.req_bytes; - rar->msg3_grant = rar_alloc.rar_grant.msg3_grant; - - // Print RAR allocation result - for (uint32_t i = 0; i < rar->msg3_grant.size(); ++i) { - const auto& msg3_grant = rar->msg3_grant[i]; - uint16_t expected_rnti = msg3_grant.data.temp_crnti; - fmt::memory_buffer str_buffer; - fmt::format_to(str_buffer, "{}", rar_alloc.alloc_data.rbg_range); - logger.info("SCHED: RAR, temp_crnti=0x%x, ra-rnti=%d, rbgs=%s, dci=(%d,%d), rar_grant_rba=%d, " - "rar_grant_mcs=%d", - expected_rnti, - rar_alloc.alloc_data.rnti, - srslte::to_c_str(str_buffer), - rar->dci.location.L, - rar->dci.location.ncce, - msg3_grant.grant.rba, - msg3_grant.grant.trunc_mcs); - } - - dl_result->nof_rar_elems++; + ul_sf_result->phich.emplace_back(); + ul_sf_result->phich.back().rnti = user->get_rnti(); + ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; + return alloc_result::success; } + return alloc_result::no_rnti_opportunity; } void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, @@ -821,7 +659,8 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& sched_ue_list& ue_list) { for (const auto& data_alloc : data_allocs) { - sched_interface::dl_sched_data_t* data = &dl_result->data[dl_result->nof_data_elems]; + dl_result->data.emplace_back(); + sched_interface::dl_sched_data_t* data = &dl_result->data.back(); // Assign NCCE/L data->dci.location = dci_result[data_alloc.dci_idx]->dci_pos; @@ -856,7 +695,7 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& // Print Resulting DL Allocation fmt::memory_buffer str_buffer; fmt::format_to(str_buffer, - "SCHED: DL {} rnti=0x{:x}, cc={}, pid={}, mask={:x}, dci=({}, {}), n_rtx={}, tbs={}, buffer={}/{}", + "SCHED: DL {} rnti=0x{:x}, cc={}, pid={}, mask=0x{:x}, dci=({}, {}), n_rtx={}, tbs={}, buffer={}/{}", is_newtx ? "tx" : "retx", user->get_rnti(), cc_cfg->enb_cc_idx, @@ -869,8 +708,6 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& data_before, user->get_requested_dl_bytes(cc_cfg->enb_cc_idx).stop()); logger.info("%s", srslte::to_c_str(str_buffer)); - - dl_result->nof_data_elems++; } } @@ -912,7 +749,7 @@ uci_pusch_t is_uci_included(const sf_sched* sf_sched, needs_ack_uci = sf_sched->is_dl_alloc(user->get_rnti()); } else { auto& dl_result = other_cc_results.enb_cc_list[enbccidx].dl_sched_result; - for (uint32_t j = 0; j < dl_result.nof_data_elems; ++j) { + for (uint32_t j = 0; j < dl_result.data.size(); ++j) { if (dl_result.data[j].dci.rnti == user->get_rnti()) { needs_ack_uci = true; break; @@ -941,7 +778,7 @@ uci_pusch_t is_uci_included(const sf_sched* sf_sched, } for (uint32_t enbccidx = 0; enbccidx < other_cc_results.enb_cc_list.size(); ++enbccidx) { - for (uint32_t j = 0; j < other_cc_results.enb_cc_list[enbccidx].ul_sched_result.nof_dci_elems; ++j) { + for (uint32_t j = 0; j < other_cc_results.enb_cc_list[enbccidx].ul_sched_result.pusch.size(); ++j) { // Checks all the UL grants already allocated for the given rnti if (other_cc_results.enb_cc_list[enbccidx].ul_sched_result.pusch[j].dci.rnti == user->get_rnti()) { auto p = user->get_active_cell_index(enbccidx); @@ -966,8 +803,6 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r { /* Set UL data DCI locs and format */ for (const auto& ul_alloc : ul_data_allocs) { - sched_interface::ul_sched_data_t* pusch = &ul_result->pusch[ul_result->nof_dci_elems]; - auto ue_it = ue_list.find(ul_alloc.rnti); if (ue_it == ue_list.end()) { continue; @@ -983,8 +818,10 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r uci_pusch_t uci_type = is_uci_included(this, *cc_results, user, cc_cfg->enb_cc_idx); /* Generate DCI Format1A */ - uint32_t total_data_before = user->get_pending_ul_data_total(get_tti_tx_ul(), cc_cfg->enb_cc_idx); - int tbs = user->generate_format0(pusch, + ul_result->pusch.emplace_back(); + sched_interface::ul_sched_data_t& pusch = ul_result->pusch.back(); + uint32_t total_data_before = user->get_pending_ul_data_total(get_tti_tx_ul(), cc_cfg->enb_cc_idx); + int tbs = user->generate_format0(&pusch, get_tti_tx_ul(), cc_cfg->enb_cc_idx, ul_alloc.alloc, @@ -996,7 +833,7 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); uint32_t new_pending_bytes = user->get_pending_ul_new_data(get_tti_tx_ul(), cc_cfg->enb_cc_idx); // Allow TBS=0 in case of UCI-only PUSCH - if (tbs < 0 || (tbs == 0 && pusch->dci.tb.mcs_idx != 29)) { + if (tbs < 0 || (tbs == 0 && pusch.dci.tb.mcs_idx != 29)) { fmt::memory_buffer str_buffer; fmt::format_to(str_buffer, "SCHED: Error {} {} rnti=0x{:x}, pid={}, dci=({},{}), prb={}, bsr={}", @@ -1004,11 +841,12 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r ul_alloc.is_retx() ? "retx" : "tx", user->get_rnti(), h->get_id(), - pusch->dci.location.L, - pusch->dci.location.ncce, + pusch.dci.location.L, + pusch.dci.location.ncce, ul_alloc.alloc, new_pending_bytes); logger.warning("%s", srslte::to_c_str(str_buffer)); + ul_result->pusch.pop_back(); continue; } @@ -1019,12 +857,12 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r fmt::format_to(str_buffer, "SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, tbs={}, bsr={} ({}-{})", ul_alloc.is_msg3 ? "Msg3" : "UL", - ul_alloc.is_retx() ? "retx" : "newtx", + ul_alloc.is_retx() ? "retx" : "tx", user->get_rnti(), cc_cfg->enb_cc_idx, h->get_id(), - pusch->dci.location.L, - pusch->dci.location.ncce, + pusch.dci.location.L, + pusch.dci.location.ncce, ul_alloc.alloc, h->nof_retx(0), tbs, @@ -1034,22 +872,20 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r logger.info("%s", srslte::to_c_str(str_buffer)); } - pusch->current_tx_nb = h->nof_retx(0); - - ul_result->nof_dci_elems++; + pusch.current_tx_nb = h->nof_retx(0); } } -alloc_outcome_t sf_sched::alloc_msg3(sched_ue* user, const sched_interface::dl_sched_rar_grant_t& rargrant) +alloc_result sf_sched::alloc_msg3(sched_ue* user, const sched_interface::dl_sched_rar_grant_t& rargrant) { // Derive PRBs from allocated RAR grants prb_interval msg3_alloc = prb_interval::riv_to_prbs(rargrant.grant.rba, cc_cfg->nof_prb()); - alloc_outcome_t ret = alloc_ul(user, msg3_alloc, sf_sched::ul_alloc_t::NEWTX, true, rargrant.grant.trunc_mcs); - if (not ret) { + alloc_result ret = alloc_ul(user, msg3_alloc, sf_sched::ul_alloc_t::NEWTX, true, rargrant.grant.trunc_mcs); + if (ret != alloc_result::success) { fmt::memory_buffer str_buffer; fmt::format_to(str_buffer, "{}", msg3_alloc); - logger.warning("SCHED: Could not allocate msg3 within %s", srslte::to_c_str(str_buffer)); + logger.warning("SCHED: Could not allocate msg3 within %s.", srslte::to_c_str(str_buffer)); } return ret; } @@ -1061,7 +897,7 @@ void sf_sched::generate_sched_results(sched_ue_list& ue_db) /* Resume UL HARQs with pending retxs that did not get allocated */ using phich_t = sched_interface::ul_sched_phich_t; auto& phich_list = cc_result->ul_sched_result.phich; - for (uint32_t i = 0; i < cc_result->ul_sched_result.nof_phich_elems; ++i) { + for (uint32_t i = 0; i < cc_result->ul_sched_result.phich.size(); ++i) { auto& phich = phich_list[i]; if (phich.phich == phich_t::NACK) { auto& ue = *ue_db[phich.rnti]; @@ -1083,18 +919,26 @@ void sf_sched::generate_sched_results(sched_ue_list& ue_db) cc_result->dl_sched_result.cfi = tti_alloc.get_pdcch_grid().get_cfi(); /* Generate DCI formats and fill sched_result structs */ - set_bc_sched_result(dci_result, &cc_result->dl_sched_result); + for (const auto& bc_alloc : bc_allocs) { + cc_result->dl_sched_result.bc.emplace_back(bc_alloc.bc_grant); + cc_result->dl_sched_result.bc.back().dci.location = dci_result[bc_alloc.dci_idx]->dci_pos; + log_broadcast_allocation(cc_result->dl_sched_result.bc.back(), bc_alloc.rbg_range, *cc_cfg); + } - set_rar_sched_result(dci_result, &cc_result->dl_sched_result); + for (const auto& rar_alloc : rar_allocs) { + cc_result->dl_sched_result.rar.emplace_back(rar_alloc.rar_grant); + cc_result->dl_sched_result.rar.back().dci.location = dci_result[rar_alloc.alloc_data.dci_idx]->dci_pos; + log_rar_allocation(cc_result->dl_sched_result.rar.back(), rar_alloc.alloc_data.rbg_range); + } set_dl_data_sched_result(dci_result, &cc_result->dl_sched_result, ue_db); set_ul_sched_result(dci_result, &cc_result->ul_sched_result, ue_db); /* Store remaining sf_sched results for this TTI */ - cc_result->dl_mask = tti_alloc.get_dl_mask(); - cc_result->ul_mask = tti_alloc.get_ul_mask(); - cc_result->tti_rx = get_tti_rx(); + cc_result->dl_mask = tti_alloc.get_dl_mask(); + cc_result->ul_mask = tti_alloc.get_ul_mask(); + cc_result->generated = true; } uint32_t sf_sched::get_nof_ctrl_symbols() const @@ -1102,53 +946,4 @@ uint32_t sf_sched::get_nof_ctrl_symbols() const return tti_alloc.get_cfi() + ((cc_cfg->cfg.cell.nof_prb <= 10) ? 1 : 0); } -int sf_sched::generate_format1a(prb_interval prb_range, - uint32_t tbs_bytes, - uint32_t rv, - uint16_t rnti, - srslte_dci_dl_t* dci) -{ - /* Calculate I_tbs for this TBS */ - int tbs = tbs_bytes * 8; - int i; - int mcs = -1; - for (i = 0; i < 27; i++) { - if (srslte_ra_tbs_from_idx(i, 2) >= tbs) { - dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_2; - mcs = i; - tbs = srslte_ra_tbs_from_idx(i, 2); - break; - } - if (srslte_ra_tbs_from_idx(i, 3) >= tbs) { - dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_3; - mcs = i; - tbs = srslte_ra_tbs_from_idx(i, 3); - break; - } - } - if (i == 28) { - logger.error("Can't allocate Format 1A for TBS=%d", tbs); - return -1; - } - - logger.debug("ra_tbs=%d/%d, tbs_bytes=%d, tbs=%d, mcs=%d", - srslte_ra_tbs_from_idx(mcs, 2), - srslte_ra_tbs_from_idx(mcs, 3), - tbs_bytes, - tbs, - mcs); - - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; - dci->type2_alloc.mode = srslte_ra_type2_t::SRSLTE_RA_TYPE2_LOC; - dci->type2_alloc.riv = srslte_ra_type2_to_riv(prb_range.length(), prb_range.start(), cc_cfg->cfg.cell.nof_prb); - dci->pid = 0; - dci->tb[0].mcs_idx = mcs; - dci->tb[0].rv = rv; - dci->format = SRSLTE_DCI_FORMAT1A; - dci->rnti = rnti; - dci->ue_cc_idx = std::numeric_limits::max(); - - return tbs; -} - } // namespace srsenb diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index 6aae1de83..29f09c044 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -37,7 +37,7 @@ using dl_sched_res_t = sched_interface::dl_sched_res_t; using dl_sched_data_t = sched_interface::dl_sched_data_t; using custom_mem_buffer = fmt::basic_memory_buffer; -srslog::basic_logger& get_mac_logger() +static srslog::basic_logger& get_mac_logger() { static srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC"); return mac_logger; @@ -125,8 +125,7 @@ void log_dl_cc_results(srslog::basic_logger& logger, uint32_t enb_cc_idx, const } custom_mem_buffer strbuf; - for (uint32_t i = 0; i < result.nof_data_elems; ++i) { - const dl_sched_data_t& data = result.data[i]; + for (const auto& data : result.data) { if (logger.debug.enabled()) { fill_dl_cc_result_debug(strbuf, data); } else { @@ -151,7 +150,7 @@ void log_phich_cc_results(srslog::basic_logger& logger, return; } custom_mem_buffer strbuf; - for (uint32_t i = 0; i < result.nof_phich_elems; ++i) { + for (uint32_t i = 0; i < result.phich.size(); ++i) { const phich_t& phich = result.phich[i]; const char* prefix = strbuf.size() > 0 ? " | " : ""; const char* val = phich.phich == phich_t::ACK ? "ACK" : "NACK"; @@ -392,8 +391,6 @@ sched_cell_params_t::get_dl_nof_res(srslte::tti_point tti_tx_dl, const srslte_dc } } - // sanity check - assert(nof_re == srslte_ra_dl_grant_nof_re(&cfg.cell, &dl_sf, &grant)); return nof_re; } diff --git a/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc index 7c7250a93..1f1795a71 100644 --- a/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc +++ b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc @@ -21,11 +21,20 @@ #include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" #include "srsenb/hdr/stack/mac/sched_common.h" +#include "srsenb/hdr/stack/mac/sched_helpers.h" +#include "srslte/common/string_helpers.h" + #include #include namespace srsenb { +static srslog::basic_logger& get_mac_logger() +{ + static srslog::basic_logger& logger = srslog::fetch_basic_logger("MAC"); + return logger; +} + /// Compute max TBS based on max coderate int coderate_to_tbs(float max_coderate, uint32_t nof_re) { @@ -83,7 +92,7 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, float max_coderate = srslte_cqi_to_coderate(std::min(cqi + 1U, 15U), use_tbs_index_alt); uint32_t max_Qm = (is_ul) ? (ulqam64_enabled ? 6 : 4) : (use_tbs_index_alt ? 8 : 6); - max_coderate = std::min(max_coderate, 0.93F * max_Qm); + max_coderate = std::min(max_coderate, 0.932F * max_Qm); int mcs = 0; float prev_max_coderate = 0; @@ -113,7 +122,7 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, // update max coderate based on mcs srslte_mod_t mod = (is_ul) ? srslte_ra_ul_mod_from_mcs(mcs) : srslte_ra_dl_mod_from_mcs(mcs, use_tbs_index_alt); uint32_t Qm = srslte_mod_bits_x_symbol(mod); - max_coderate = std::min(0.93F * Qm, max_coderate); + max_coderate = std::min(0.932F * Qm, max_coderate); if (coderate <= max_coderate) { // solution was found @@ -171,4 +180,206 @@ tbs_info compute_min_mcs_and_tbs_from_required_bytes(uint32_t nof_prb, return tb_max; } +int generate_ra_bc_dci_format1a_common(srslte_dci_dl_t& dci, + uint16_t rnti, + tti_point tti_tx_dl, + uint32_t req_bytes, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params, + uint32_t current_cfi) +{ + static const uint32_t Qm = 2, bc_rar_cqi = 4; + static const float max_ctrl_coderate = std::min(srslte_cqi_to_coderate(bc_rar_cqi + 1, false), 0.932F * Qm); + + // Calculate I_tbs for this TBS + int tbs = static_cast(req_bytes) * 8; + int mcs = -1; + for (uint32_t i = 0; i < 27; i++) { + if (srslte_ra_tbs_from_idx(i, 2) >= tbs) { + dci.type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_2; + mcs = i; + tbs = srslte_ra_tbs_from_idx(i, 2); + break; + } + if (srslte_ra_tbs_from_idx(i, 3) >= tbs) { + dci.type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_3; + mcs = i; + tbs = srslte_ra_tbs_from_idx(i, 3); + break; + } + } + if (mcs < 0) { + // logger.error("Can't allocate Format 1A for TBS=%d", tbs); + return -1; + } + + // Generate remaining DCI Format1A content + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci.type2_alloc.mode = srslte_ra_type2_t::SRSLTE_RA_TYPE2_LOC; + prb_interval prb_range = prb_interval::rbgs_to_prbs(rbg_range, cell_params.nof_prb()); + dci.type2_alloc.riv = srslte_ra_type2_to_riv(prb_range.length(), prb_range.start(), cell_params.nof_prb()); + dci.pid = 0; + dci.tb[0].mcs_idx = mcs; + dci.tb[0].rv = 0; // used for SIBs + dci.format = SRSLTE_DCI_FORMAT1A; + dci.rnti = rnti; + dci.ue_cc_idx = std::numeric_limits::max(); + + // Compute effective code rate and verify it doesn't exceed max code rate + uint32_t nof_re = cell_params.get_dl_nof_res(tti_tx_dl, dci, current_cfi); + if (srslte_coderate(tbs, nof_re) >= max_ctrl_coderate) { + return -1; + } + + get_mac_logger().debug("ra_tbs=%d/%d, tbs_bytes=%d, tbs=%d, mcs=%d", + srslte_ra_tbs_from_idx(mcs, 2), + srslte_ra_tbs_from_idx(mcs, 3), + req_bytes, + tbs, + mcs); + + return tbs; +} + +bool generate_sib_dci(sched_interface::dl_sched_bc_t& bc, + tti_point tti_tx_dl, + uint32_t sib_idx, + uint32_t sib_ntx, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params, + uint32_t current_cfi) +{ + bc = {}; + int tbs_bits = generate_ra_bc_dci_format1a_common( + bc.dci, SRSLTE_SIRNTI, tti_tx_dl, cell_params.cfg.sibs[sib_idx].len, rbg_range, cell_params, current_cfi); + if (tbs_bits < 0) { + return false; + } + + // generate SIB-specific fields + bc.index = sib_idx; + bc.type = sched_interface::dl_sched_bc_t::BCCH; + // bc.tbs = sib_len; + bc.tbs = tbs_bits / 8; + bc.dci.tb[0].rv = get_rvidx(sib_ntx); + + return true; +} + +bool generate_paging_dci(sched_interface::dl_sched_bc_t& bc, + tti_point tti_tx_dl, + uint32_t req_bytes, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params, + uint32_t current_cfi) +{ + bc = {}; + int tbs_bits = generate_ra_bc_dci_format1a_common( + bc.dci, SRSLTE_PRNTI, tti_tx_dl, req_bytes, rbg_range, cell_params, current_cfi); + if (tbs_bits < 0) { + return false; + } + + // generate Paging-specific fields + bc.type = sched_interface::dl_sched_bc_t::PCCH; + bc.tbs = tbs_bits / 8; + + return true; +} + +bool generate_rar_dci(sched_interface::dl_sched_rar_t& rar, + tti_point tti_tx_dl, + const pending_rar_t& pending_rar, + rbg_interval rbg_range, + uint32_t nof_grants, + uint32_t start_msg3_prb, + const sched_cell_params_t& cell_params, + uint32_t current_cfi) +{ + const uint32_t msg3_Lcrb = 3; + uint32_t req_bytes = 7 * nof_grants + 1; // 1+6 bytes per RAR subheader+body and 1 byte for Backoff + + rar = {}; + int tbs_bits = generate_ra_bc_dci_format1a_common( + rar.dci, pending_rar.ra_rnti, tti_tx_dl, req_bytes, rbg_range, cell_params, current_cfi); + if (tbs_bits < 0) { + return false; + } + + rar.msg3_grant.resize(nof_grants); + for (uint32_t i = 0; i < nof_grants; ++i) { + rar.msg3_grant[i].data = pending_rar.msg3_grant[i]; + rar.msg3_grant[i].grant.tpc_pusch = 3; + rar.msg3_grant[i].grant.trunc_mcs = 0; + rar.msg3_grant[i].grant.rba = srslte_ra_type2_to_riv(msg3_Lcrb, start_msg3_prb, cell_params.nof_prb()); + + start_msg3_prb += msg3_Lcrb; + } + // rar.tbs = tbs_bits / 8; + rar.tbs = req_bytes; + + return true; +} + +void log_broadcast_allocation(const sched_interface::dl_sched_bc_t& bc, + rbg_interval rbg_range, + const sched_cell_params_t& cell_params) +{ + if (not get_mac_logger().info.enabled()) { + return; + } + + fmt::memory_buffer str_buffer; + fmt::format_to(str_buffer, "{}", rbg_range); + + if (bc.type == sched_interface::dl_sched_bc_t::bc_type::BCCH) { + get_mac_logger().debug("SCHED: SIB%d, cc=%d, rbgs=(%d,%d), dci=(%d,%d), rv=%d, len=%d, period=%d, mcs=%d", + bc.index + 1, + cell_params.enb_cc_idx, + rbg_range.start(), + rbg_range.stop(), + bc.dci.location.L, + bc.dci.location.ncce, + bc.dci.tb[0].rv, + cell_params.cfg.sibs[bc.index].len, + cell_params.cfg.sibs[bc.index].period_rf, + bc.dci.tb[0].mcs_idx); + } else { + get_mac_logger().info("SCHED: PCH, cc=%d, rbgs=%s, dci=(%d,%d), tbs=%d, mcs=%d", + cell_params.enb_cc_idx, + srslte::to_c_str(str_buffer), + bc.dci.location.L, + bc.dci.location.ncce, + bc.tbs, + bc.dci.tb[0].mcs_idx); + } +} + +void log_rar_allocation(const sched_interface::dl_sched_rar_t& rar, rbg_interval rbg_range) +{ + if (not get_mac_logger().info.enabled()) { + return; + } + + fmt::memory_buffer str_buffer; + fmt::format_to(str_buffer, "{}", rbg_range); + + fmt::memory_buffer str_buffer2; + for (size_t i = 0; i < rar.msg3_grant.size(); ++i) { + fmt::format_to(str_buffer2, + "{}{{c-rnti=0x{:x}, rba={}, mcs={}}}", + i > 0 ? ", " : "", + rar.msg3_grant[i].data.temp_crnti, + rar.msg3_grant[i].grant.rba, + rar.msg3_grant[i].grant.trunc_mcs); + } + + get_mac_logger().info("SCHED: RAR, ra-rnti=%d, rbgs=%s, dci=(%d,%d), msg3 grants=[%s]", + rar.dci.rnti, + srslte::to_c_str(str_buffer), + rar.dci.location.L, + rar.dci.location.ncce, + srslte::to_c_str(str_buffer2)); +} + } // namespace srsenb diff --git a/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc b/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc index 0b9da52a6..bf84715b6 100644 --- a/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc +++ b/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc @@ -25,28 +25,28 @@ namespace srsenb { +bool is_pucch_sr_collision(const srslte_pucch_cfg_t& ue_pucch_cfg, tti_point tti_tx_dl_ack, uint32_t n1_pucch) +{ + if (ue_pucch_cfg.sr_configured && srslte_ue_ul_sr_send_tti(&ue_pucch_cfg, tti_tx_dl_ack.to_uint())) { + return n1_pucch == ue_pucch_cfg.n_pucch_sr; + } + return false; +} + void sf_cch_allocator::init(const sched_cell_params_t& cell_params_) { cc_cfg = &cell_params_; pucch_cfg_common = cc_cfg->pucch_cfg_common; - - // init alloc trees - alloc_trees.reserve(cc_cfg->sched_cfg->max_nof_ctrl_symbols); - for (uint32_t i = 0; i < cc_cfg->sched_cfg->max_nof_ctrl_symbols; ++i) { - alloc_trees.emplace_back(i + 1, *cc_cfg, pucch_cfg_common); - } } void sf_cch_allocator::new_tti(tti_point tti_rx_) { tti_rx = tti_rx_; - // Reset back all CFIs - for (auto& t : alloc_trees) { - t.reset(); - } dci_record_list.clear(); - current_cfix = cc_cfg->sched_cfg->min_nof_ctrl_symbols - 1; + last_dci_dfs.clear(); + current_cfix = cc_cfg->sched_cfg->min_nof_ctrl_symbols - 1; + current_max_cfix = cc_cfg->sched_cfg->max_nof_ctrl_symbols - 1; } const cce_cfi_position_table* @@ -54,13 +54,11 @@ sf_cch_allocator::get_cce_loc_table(alloc_type_t alloc_type, sched_ue* user, uin { switch (alloc_type) { case alloc_type_t::DL_BC: - return &cc_cfg->common_locations[cfix]; case alloc_type_t::DL_PCCH: return &cc_cfg->common_locations[cfix]; case alloc_type_t::DL_RAR: return &cc_cfg->rar_locations[to_tx_dl(tti_rx).sf_idx()][cfix]; case alloc_type_t::DL_DATA: - return user->get_locations(cc_cfg->enb_cc_idx, cfix + 1, to_tx_dl(tti_rx).sf_idx()); case alloc_type_t::UL_DATA: return user->get_locations(cc_cfg->enb_cc_idx, cfix + 1, to_tx_dl(tti_rx).sf_idx()); default: @@ -71,253 +69,189 @@ sf_cch_allocator::get_cce_loc_table(alloc_type_t alloc_type, sched_ue* user, uin bool sf_cch_allocator::alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user, bool has_pusch_grant) { - // TODO: Make the alloc tree update lazy - alloc_record_t record{.user = user, .aggr_idx = aggr_idx, .alloc_type = alloc_type, .pusch_uci = has_pusch_grant}; - - // Try to allocate user in PDCCH for given CFI. If it fails, increment CFI. - uint32_t first_cfi = get_cfi(); - bool success; - do { - success = alloc_dci_record(record, get_cfi() - 1); - } while (not success and get_cfi() < cc_cfg->sched_cfg->max_nof_ctrl_symbols and set_cfi(get_cfi() + 1)); - - if (not success) { - // DCI allocation failed. go back to original CFI - if (get_cfi() != first_cfi and not set_cfi(first_cfi)) { - logger.error("SCHED: Failed to return back to original PDCCH state"); + temp_dci_dfs.clear(); + uint32_t start_cfix = current_cfix; + + alloc_record record; + record.user = user; + record.aggr_idx = aggr_idx; + record.alloc_type = alloc_type; + record.pusch_uci = has_pusch_grant; + + if (is_dl_ctrl_alloc(alloc_type) and nof_allocs() == 0 and cc_cfg->nof_prb() == 6 and + current_max_cfix > current_cfix) { + // Given that CFI is not currently dynamic for ctrl allocs, in case of SIB/RAR alloc and a low number of PRBs, + // start with an CFI that maximizes nof potential CCE locs + uint32_t nof_locs = 0, lowest_cfix = current_cfix; + for (uint32_t cfix_tmp = current_max_cfix; cfix_tmp > lowest_cfix; --cfix_tmp) { + const cce_cfi_position_table* dci_locs = get_cce_loc_table(record.alloc_type, record.user, cfix_tmp); + if ((*dci_locs)[record.aggr_idx].size() > nof_locs) { + nof_locs = (*dci_locs)[record.aggr_idx].size(); + current_cfix = cfix_tmp; + } else { + break; + } } - return false; - } - - // DCI record allocation successful - dci_record_list.push_back(record); - return true; -} - -bool sf_cch_allocator::alloc_dci_record(const alloc_record_t& record, uint32_t cfix) -{ - bool ret = false; - auto& tree = alloc_trees[cfix]; - - // Get DCI Location Table - const cce_cfi_position_table* dci_locs = get_cce_loc_table(record.alloc_type, record.user, cfix); - if (dci_locs == nullptr or (*dci_locs)[record.aggr_idx].empty()) { - return ret; } - if (tree.prev_end > 0) { - for (size_t j = tree.prev_start; j < tree.prev_end; ++j) { - ret |= tree.add_tree_node_leaves((int)j, record, *dci_locs, tti_rx); + // Try to allocate grant. If it fails, attempt the same grant, but using a different permutation of past grant DCI + // positions + do { + bool success = alloc_dfs_node(record, 0); + if (success) { + // DCI record allocation successful + dci_record_list.push_back(record); + + if (is_dl_ctrl_alloc(alloc_type)) { + // Dynamic CFI not yet supported for DL control allocations, as coderate can be exceeded + current_max_cfix = current_cfix; + } + return true; } - } else { - ret = tree.add_tree_node_leaves(-1, record, *dci_locs, tti_rx); - } - - if (ret) { - tree.prev_start = tree.prev_end; - tree.prev_end = tree.dci_alloc_tree.size(); - } + if (temp_dci_dfs.empty()) { + temp_dci_dfs = last_dci_dfs; + } + } while (get_next_dfs()); - return ret; + // Revert steps to initial state, before dci record allocation was attempted + last_dci_dfs.swap(temp_dci_dfs); + current_cfix = start_cfix; + return false; } -bool sf_cch_allocator::set_cfi(uint32_t cfi) +bool sf_cch_allocator::get_next_dfs() { - if (cfi < cc_cfg->sched_cfg->min_nof_ctrl_symbols or cfi > cc_cfg->sched_cfg->max_nof_ctrl_symbols) { - logger.error("Invalid CFI value. Defaulting to current CFI."); - return false; - } - - uint32_t new_cfix = cfi - 1; - if (new_cfix == current_cfix) { - return true; - } - - // setup new PDCCH alloc tree - auto& new_tree = alloc_trees[new_cfix]; - new_tree.reset(); - - if (not dci_record_list.empty()) { - // there are already PDCCH allocations - - // Rebuild Allocation Tree - bool ret = true; - for (const auto& old_record : dci_record_list) { - ret &= alloc_dci_record(old_record, new_cfix); + do { + uint32_t start_child_idx = 0; + if (last_dci_dfs.empty()) { + // If we reach root, increase CFI + current_cfix++; + if (current_cfix > current_max_cfix) { + return false; + } + } else { + // Attempt to re-add last tree node, but with a higher node child index + start_child_idx = last_dci_dfs.back().dci_pos_idx + 1; + last_dci_dfs.pop_back(); } - - if (not ret) { - // Fail to rebuild allocation tree. Go back to previous CFI - return false; + while (last_dci_dfs.size() < dci_record_list.size() and + alloc_dfs_node(dci_record_list[last_dci_dfs.size()], start_child_idx)) { + start_child_idx = 0; } - } + } while (last_dci_dfs.size() < dci_record_list.size()); - current_cfix = new_cfix; + // Finished computation of next DFS node return true; } -void sf_cch_allocator::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const -{ - alloc_trees[current_cfix].get_allocs(vec, tot_mask, idx); -} - -std::string sf_cch_allocator::result_to_string(bool verbose) const -{ - return alloc_trees[current_cfix].result_to_string(verbose); -} - -sf_cch_allocator::alloc_tree_t::alloc_tree_t(uint32_t this_cfi, - const sched_cell_params_t& cc_params, - srslte_pucch_cfg_t& pucch_cfg_common) : - cfi(this_cfi), cc_cfg(&cc_params), pucch_cfg_temp(&pucch_cfg_common), nof_cces(cc_params.nof_cce_table[this_cfi - 1]) +bool sf_cch_allocator::alloc_dfs_node(const alloc_record& record, uint32_t start_dci_idx) { - dci_alloc_tree.reserve(8); -} - -void sf_cch_allocator::alloc_tree_t::reset() -{ - prev_start = 0; - prev_end = 0; - dci_alloc_tree.clear(); -} - -bool is_pucch_sr_collision(const srslte_pucch_cfg_t& ue_pucch_cfg, tti_point tti_tx_dl_ack, uint32_t n1_pucch) -{ - if (ue_pucch_cfg.sr_configured && srslte_ue_ul_sr_send_tti(&ue_pucch_cfg, tti_tx_dl_ack.to_uint())) { - return n1_pucch == ue_pucch_cfg.n_pucch_sr; + // Get DCI Location Table + const cce_cfi_position_table* dci_locs = get_cce_loc_table(record.alloc_type, record.user, current_cfix); + if (dci_locs == nullptr or (*dci_locs)[record.aggr_idx].empty()) { + return false; + } + const cce_position_list& dci_pos_list = (*dci_locs)[record.aggr_idx]; + if (start_dci_idx >= dci_pos_list.size()) { + return false; } - return false; -} - -/// Algorithm to compute a valid PDCCH allocation -bool sf_cch_allocator::alloc_tree_t::add_tree_node_leaves(int parent_node_idx, - const alloc_record_t& dci_record, - const cce_cfi_position_table& dci_locs, - tti_point tti_rx_) -{ - bool ret = false; - - alloc_t alloc; - alloc.rnti = (dci_record.user != nullptr) ? dci_record.user->get_rnti() : SRSLTE_INVALID_RNTI; - alloc.dci_pos.L = dci_record.aggr_idx; + tree_node node; + node.dci_pos_idx = start_dci_idx; + node.dci_pos.L = record.aggr_idx; + node.rnti = record.user != nullptr ? record.user->get_rnti() : SRSLTE_INVALID_RNTI; + node.current_mask.resize(nof_cces()); // get cumulative pdcch & pucch masks - pdcch_mask_t parent_total_mask; - prbmask_t parent_pucch_mask; - if (parent_node_idx >= 0) { - parent_total_mask = dci_alloc_tree[parent_node_idx].node.total_mask; - parent_pucch_mask = dci_alloc_tree[parent_node_idx].node.total_pucch_mask; + if (not last_dci_dfs.empty()) { + node.total_mask = last_dci_dfs.back().total_mask; + node.total_pucch_mask = last_dci_dfs.back().total_pucch_mask; } else { - parent_total_mask.resize(nof_cces); - parent_pucch_mask.resize(cc_cfg->nof_prb()); + node.total_mask.resize(nof_cces()); + node.total_pucch_mask.resize(cc_cfg->nof_prb()); } - for (uint32_t i = 0; i < dci_locs[dci_record.aggr_idx].size(); ++i) { - int8_t pucch_prbidx = -1; - uint32_t ncce_pos = dci_locs[dci_record.aggr_idx][i]; + for (; node.dci_pos_idx < dci_pos_list.size(); ++node.dci_pos_idx) { + node.dci_pos.ncce = dci_pos_list[node.dci_pos_idx]; - if (dci_record.alloc_type == alloc_type_t::DL_DATA and not dci_record.pusch_uci) { + if (record.alloc_type == alloc_type_t::DL_DATA and not record.pusch_uci) { // The UE needs to allocate space in PUCCH for HARQ-ACK - pucch_cfg_temp->n_pucch = ncce_pos + pucch_cfg_temp->N_pucch_1; + pucch_cfg_common.n_pucch = node.dci_pos.ncce + pucch_cfg_common.N_pucch_1; - if (is_pucch_sr_collision( - dci_record.user->get_ue_cfg().pucch_cfg, to_tx_dl_ack(tti_rx_), pucch_cfg_temp->n_pucch)) { + if (is_pucch_sr_collision(record.user->get_ue_cfg().pucch_cfg, to_tx_dl_ack(tti_rx), pucch_cfg_common.n_pucch)) { // avoid collision of HARQ-ACK with own SR n(1)_pucch continue; } - pucch_prbidx = srslte_pucch_n_prb(&cc_cfg->cfg.cell, pucch_cfg_temp, 0); - if (not cc_cfg->sched_cfg->pucch_mux_enabled and parent_pucch_mask.test(pucch_prbidx)) { + node.pucch_n_prb = srslte_pucch_n_prb(&cc_cfg->cfg.cell, &pucch_cfg_common, 0); + if (not cc_cfg->sched_cfg->pucch_mux_enabled and node.total_pucch_mask.test(node.pucch_n_prb)) { // PUCCH allocation would collide with other PUCCH/PUSCH grants. Try another CCE position continue; } } - pdcch_mask_t alloc_mask(nof_cces); - alloc_mask.fill(ncce_pos, ncce_pos + (1u << dci_record.aggr_idx)); - if ((parent_total_mask & alloc_mask).any()) { + node.current_mask.reset(); + node.current_mask.fill(node.dci_pos.ncce, node.dci_pos.ncce + (1U << record.aggr_idx)); + if ((node.total_mask & node.current_mask).any()) { // there is a PDCCH collision. Try another CCE position continue; } // Allocation successful - alloc.current_mask = alloc_mask; - alloc.total_mask = parent_total_mask | alloc_mask; - alloc.dci_pos.ncce = ncce_pos; - alloc.pucch_n_prb = pucch_prbidx; - alloc.total_pucch_mask = parent_pucch_mask; - if (pucch_prbidx >= 0) { - alloc.total_pucch_mask.set(pucch_prbidx); - } - - // Prune if repetition of total_masks - uint32_t j = prev_end; - for (; j < dci_alloc_tree.size(); ++j) { - if (dci_alloc_tree[j].node.total_mask == alloc.total_mask) { - // leave nested for-loop - break; - } - } - if (j < dci_alloc_tree.size()) { - continue; + node.total_mask |= node.current_mask; + if (node.pucch_n_prb >= 0) { + node.total_pucch_mask.set(node.pucch_n_prb); } - - // Register allocation - dci_alloc_tree.emplace_back(parent_node_idx, alloc); - ret = true; + last_dci_dfs.push_back(node); + return true; } - return ret; + return false; } -void sf_cch_allocator::alloc_tree_t::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const +void sf_cch_allocator::rem_last_dci() { - // if alloc tree is empty - if (prev_start == prev_end) { - if (vec != nullptr) { - vec->clear(); - } - if (tot_mask != nullptr) { - tot_mask->resize(nof_cces); - tot_mask->reset(); - } - return; - } + assert(not dci_record_list.empty()); + + // Remove DCI record + last_dci_dfs.pop_back(); + dci_record_list.pop_back(); +} - // set vector of allocations +void sf_cch_allocator::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const +{ if (vec != nullptr) { vec->clear(); - size_t i = prev_start + idx; - while (dci_alloc_tree[i].parent_idx >= 0) { - vec->push_back(&dci_alloc_tree[i].node); - i = (size_t)dci_alloc_tree[i].parent_idx; + + vec->resize(last_dci_dfs.size()); + for (uint32_t i = 0; i < last_dci_dfs.size(); ++i) { + (*vec)[i] = &last_dci_dfs[i]; } - vec->push_back(&dci_alloc_tree[i].node); - std::reverse(vec->begin(), vec->end()); } - // set final cce mask if (tot_mask != nullptr) { - *tot_mask = dci_alloc_tree[prev_start + idx].node.total_mask; + if (last_dci_dfs.empty()) { + tot_mask->resize(nof_cces()); + tot_mask->reset(); + } else { + *tot_mask = last_dci_dfs.back().total_mask; + } } } -std::string sf_cch_allocator::alloc_tree_t::result_to_string(bool verbose) const +std::string sf_cch_allocator::result_to_string(bool verbose) const { - // get all the possible combinations of DCI pos allocations fmt::basic_memory_buffer strbuf; - fmt::format_to(strbuf, - "SCHED: PDCCH allocations cfi={}, nof_cce={}, {} possible combinations:\n", - cfi, - nof_cces, - prev_end - prev_start); - uint32_t count = 0; - for (size_t i = prev_start; i < prev_end; ++i) { + if (dci_record_list.empty()) { + fmt::format_to(strbuf, "SCHED: PDCCH allocations cfi={}, nof_cce={}, No allocations.\n", get_cfi(), nof_cces()); + } else { + fmt::format_to(strbuf, + "SCHED: PDCCH allocations cfi={}, nof_cce={}, nof_allocs={}, total PDCCH mask=0x{:x}", + get_cfi(), + nof_cces(), + nof_allocs(), + last_dci_dfs.back().total_mask); alloc_result_t vec; - pdcch_mask_t tot_mask; - get_allocs(&vec, &tot_mask, i - prev_start); - - fmt::format_to(strbuf, "[{}]: total mask=0x{:x}", count, tot_mask); + get_allocs(&vec); if (verbose) { fmt::format_to(strbuf, ", allocations:\n"); for (const auto& dci_alloc : vec) { @@ -328,9 +262,8 @@ std::string sf_cch_allocator::alloc_tree_t::result_to_string(bool verbose) const dci_alloc->total_mask); } } else { - fmt::format_to(strbuf, "\n"); + fmt::format_to(strbuf, ".\n"); } - count++; } return fmt::to_string(strbuf); } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index b18e8a208..c43dfffe8 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -794,12 +794,6 @@ srslte::interval sched_ue::get_requested_dl_bytes(uint32_t enb_cc_idx) assert(cells.at(enb_cc_idx).configured()); /* Set Maximum boundary */ - // Ensure there is space for ConRes and RRC Setup - // SRB0 is a special case due to being RLC TM (no segmentation possible) - if (not lch_handler.is_bearer_dl(0)) { - logger.error("SRB0 must always be activated for DL"); - return {}; - } if (cells[enb_cc_idx].cc_state() != cc_st::active) { return {}; } diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 3899c7104..3de2ea2e3 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -243,7 +243,7 @@ tbs_info cqi_to_tbs_dl(const sched_ue_cell& cell, ret = compute_min_mcs_and_tbs_from_required_bytes( nof_prb, nof_re, cell.dl_cqi, cell.max_mcs_dl, req_bytes, false, false, use_tbs_index_alt); - // If coderate > SRSLTE_MIN(max_coderate, 0.930 * Qm) we should set TBS=0. We don't because it's not correctly + // If coderate > SRSLTE_MIN(max_coderate, 0.932 * Qm) we should set TBS=0. We don't because it's not correctly // handled by the scheduler, but we might be scheduling undecodable codewords at very low SNR if (ret.tbs_bytes < 0) { ret.mcs = 0; @@ -269,7 +269,7 @@ tbs_info cqi_to_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof ret = compute_min_mcs_and_tbs_from_required_bytes( nof_prb, nof_re, cell.ul_cqi, cell.max_mcs_ul, req_bytes, true, ulqam64_enabled, false); - // If coderate > SRSLTE_MIN(max_coderate, 0.930 * Qm) we should set TBS=0. We don't because it's not correctly + // If coderate > SRSLTE_MIN(max_coderate, 0.932 * Qm) we should set TBS=0. We don't because it's not correctly // handled by the scheduler, but we might be scheduling undecodable codewords at very low SNR if (ret.tbs_bytes < 0) { ret.mcs = 0; diff --git a/srsenb/src/stack/mac/schedulers/sched_base.cc b/srsenb/src/stack/mac/schedulers/sched_base.cc index ca5b9b9c6..9a1a658a9 100644 --- a/srsenb/src/stack/mac/schedulers/sched_base.cc +++ b/srsenb/src/stack/mac/schedulers/sched_base.cc @@ -69,7 +69,12 @@ rbgmask_t find_available_rb_mask(const rbgmask_t& in_mask, uint32_t max_size) return localmask; } -rbgmask_t compute_user_rbgmask_greedy(uint32_t max_nof_rbgs, bool is_contiguous, const rbgmask_t& current_mask) +rbg_interval find_empty_rbg_interval(uint32_t max_nof_rbgs, const rbgmask_t& current_mask) +{ + return find_contiguous_interval(current_mask, max_nof_rbgs); +} + +rbgmask_t compute_rbgmask_greedy(uint32_t max_nof_rbgs, bool is_contiguous, const rbgmask_t& current_mask) { // Allocate enough RBs that accommodate pending data rbgmask_t newtx_mask(current_mask.size()); @@ -116,27 +121,26 @@ const dl_harq_proc* get_dl_newtx_harq(sched_ue& user, sf_sched* tti_sched) return user.get_empty_dl_harq(tti_sched->get_tti_tx_dl(), tti_sched->get_enb_cc_idx()); } -alloc_outcome_t try_dl_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h) +alloc_result try_dl_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h) { // Try to reuse the same mask - rbgmask_t retx_mask = h.get_rbgmask(); - alloc_outcome_t code = tti_sched.alloc_dl_user(&ue, retx_mask, h.get_id()); - if (code == alloc_outcome_t::SUCCESS or code == alloc_outcome_t::DCI_COLLISION) { + rbgmask_t retx_mask = h.get_rbgmask(); + alloc_result code = tti_sched.alloc_dl_user(&ue, retx_mask, h.get_id()); + if (code != alloc_result::sch_collision) { return code; } // If previous mask does not fit, find another with exact same number of rbgs size_t nof_rbg = retx_mask.count(); bool is_contiguous_alloc = ue.get_dci_format() == SRSLTE_DCI_FORMAT1A; - retx_mask = compute_user_rbgmask_greedy(nof_rbg, is_contiguous_alloc, tti_sched.get_dl_mask()); + retx_mask = compute_rbgmask_greedy(nof_rbg, is_contiguous_alloc, tti_sched.get_dl_mask()); if (retx_mask.count() == nof_rbg) { return tti_sched.alloc_dl_user(&ue, retx_mask, h.get_id()); } - return alloc_outcome_t::RB_COLLISION; + return alloc_result::sch_collision; } -alloc_outcome_t -try_dl_newtx_alloc_greedy(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h, rbgmask_t* result_mask) +alloc_result try_dl_newtx_alloc_greedy(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& h, rbgmask_t* result_mask) { if (result_mask != nullptr) { *result_mask = {}; @@ -145,25 +149,25 @@ try_dl_newtx_alloc_greedy(sf_sched& tti_sched, sched_ue& ue, const dl_harq_proc& // If all RBGs are occupied, the next steps can be shortcut const rbgmask_t& current_mask = tti_sched.get_dl_mask(); if (current_mask.all()) { - return alloc_outcome_t::RB_COLLISION; + return alloc_result::no_sch_space; } // If there is no data to transmit, no need to allocate rbg_interval req_rbgs = ue.get_required_dl_rbgs(tti_sched.get_enb_cc_idx()); if (req_rbgs.stop() == 0) { - return alloc_outcome_t::NO_DATA; + return alloc_result::no_rnti_opportunity; } // Find RBG mask that accommodates pending data bool is_contiguous_alloc = ue.get_dci_format() == SRSLTE_DCI_FORMAT1A; - rbgmask_t newtxmask = compute_user_rbgmask_greedy(req_rbgs.stop(), is_contiguous_alloc, current_mask); + rbgmask_t newtxmask = compute_rbgmask_greedy(req_rbgs.stop(), is_contiguous_alloc, current_mask); if (newtxmask.none() or newtxmask.count() < req_rbgs.start()) { - return alloc_outcome_t::RB_COLLISION; + return alloc_result::no_sch_space; } // empty RBGs were found. Attempt allocation - alloc_outcome_t ret = tti_sched.alloc_dl_user(&ue, newtxmask, h.get_id()); - if (ret == alloc_outcome_t::SUCCESS and result_mask != nullptr) { + alloc_result ret = tti_sched.alloc_dl_user(&ue, newtxmask, h.get_id()); + if (ret == alloc_result::success and result_mask != nullptr) { *result_mask = newtxmask; } return ret; @@ -232,7 +236,7 @@ const ul_harq_proc* get_ul_newtx_harq(sched_ue& user, sf_sched* tti_sched) return h->is_empty() ? h : nullptr; } -alloc_outcome_t try_ul_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const ul_harq_proc& h) +alloc_result try_ul_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const ul_harq_proc& h) { prb_interval alloc = h.get_alloc(); if (tti_sched.get_cc_cfg()->nof_prb() == 6 and h.is_msg3()) { @@ -242,20 +246,20 @@ alloc_outcome_t try_ul_retx_alloc(sf_sched& tti_sched, sched_ue& ue, const ul_ha // If can schedule the same mask as in earlier tx, do it if (not tti_sched.get_ul_mask().any(alloc.start(), alloc.stop())) { - alloc_outcome_t ret = tti_sched.alloc_ul_user(&ue, alloc); - if (ret == alloc_outcome_t::SUCCESS or ret == alloc_outcome_t::DCI_COLLISION) { + alloc_result ret = tti_sched.alloc_ul_user(&ue, alloc); + if (ret != alloc_result::sch_collision) { return ret; } } // Avoid measGaps accounting for PDCCH if (not ue.pusch_enabled(tti_sched.get_tti_rx(), tti_sched.get_enb_cc_idx(), true)) { - return alloc_outcome_t::MEASGAP_COLLISION; + return alloc_result::no_rnti_opportunity; } uint32_t nof_prbs = alloc.length(); alloc = find_contiguous_ul_prbs(nof_prbs, tti_sched.get_ul_mask()); if (alloc.length() != nof_prbs) { - return alloc_outcome_t::RB_COLLISION; + return alloc_result::no_sch_space; } return tti_sched.alloc_ul_user(&ue, alloc); } diff --git a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc index d1ee2f7ad..afdaea3c7 100644 --- a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc +++ b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc @@ -80,25 +80,22 @@ void sched_time_pf::sched_dl_users(sched_ue_list& ue_db, sf_sched* tti_sched) uint32_t sched_time_pf::try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, sf_sched* tti_sched) { - alloc_outcome_t code = alloc_outcome_t::ERROR; + alloc_result code = alloc_result::other_cause; if (ue_ctxt.dl_retx_h != nullptr) { code = try_dl_retx_alloc(*tti_sched, ue, *ue_ctxt.dl_retx_h); - if (code == alloc_outcome_t::SUCCESS) { + if (code == alloc_result::success) { return ue_ctxt.dl_retx_h->get_tbs(0) + ue_ctxt.dl_retx_h->get_tbs(1); } } // There is space in PDCCH and an available DL HARQ - if (code != alloc_outcome_t::DCI_COLLISION and ue_ctxt.dl_newtx_h != nullptr) { + if (code != alloc_result::no_cch_space and ue_ctxt.dl_newtx_h != nullptr) { rbgmask_t alloc_mask; code = try_dl_newtx_alloc_greedy(*tti_sched, ue, *ue_ctxt.dl_newtx_h, &alloc_mask); - if (code == alloc_outcome_t::SUCCESS) { + if (code == alloc_result::success) { return ue.get_expected_dl_bitrate(cc_cfg->enb_cc_idx, alloc_mask.count()) * tti_duration_ms / 8; } } - if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL tx for rnti=0x%x", ue.get_rnti()); - } return 0; } @@ -131,11 +128,11 @@ uint32_t sched_time_pf::try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, sf_sched* t return ue_ctxt.ul_h->get_pending_data(); } - alloc_outcome_t code; - uint32_t estim_tbs_bytes = 0; + alloc_result code; + uint32_t estim_tbs_bytes = 0; if (ue_ctxt.ul_h->has_pending_retx()) { code = try_ul_retx_alloc(*tti_sched, ue, *ue_ctxt.ul_h); - estim_tbs_bytes = code == alloc_outcome_t::SUCCESS ? ue_ctxt.ul_h->get_pending_data() : 0; + estim_tbs_bytes = code == alloc_result::success ? ue_ctxt.ul_h->get_pending_data() : 0; } else { // Note: h->is_empty check is required, in case CA allocated a small UL grant for UCI uint32_t pending_data = ue.get_pending_ul_new_data(tti_sched->get_tti_tx_ul(), cc_cfg->enb_cc_idx); @@ -149,13 +146,10 @@ uint32_t sched_time_pf::try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, sf_sched* t return 0; } code = tti_sched->alloc_ul_user(&ue, alloc); - estim_tbs_bytes = code == alloc_outcome_t::SUCCESS + estim_tbs_bytes = code == alloc_result::success ? ue.get_expected_ul_bitrate(cc_cfg->enb_cc_idx, alloc.length()) * tti_duration_ms / 8 : 0; } - if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x", ue.get_rnti()); - } return estim_tbs_bytes; } diff --git a/srsenb/src/stack/mac/schedulers/sched_time_rr.cc b/srsenb/src/stack/mac/schedulers/sched_time_rr.cc index 022db540d..7f029d8d3 100644 --- a/srsenb/src/stack/mac/schedulers/sched_time_rr.cc +++ b/srsenb/src/stack/mac/schedulers/sched_time_rr.cc @@ -20,7 +20,6 @@ */ #include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h" -#include namespace srsenb { @@ -59,10 +58,7 @@ void sched_time_rr::sched_dl_retxs(sched_ue_list& ue_db, sf_sched* tti_sched, si if (h == nullptr) { continue; } - alloc_outcome_t code = try_dl_retx_alloc(*tti_sched, user, *h); - if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL retx for rnti=0x%x", user.get_rnti()); - } + try_dl_retx_alloc(*tti_sched, user, *h); } } @@ -83,7 +79,7 @@ void sched_time_rr::sched_dl_newtxs(sched_ue_list& ue_db, sf_sched* tti_sched, s if (h == nullptr) { continue; } - if (try_dl_newtx_alloc_greedy(*tti_sched, user, *h) == alloc_outcome_t::DCI_COLLISION) { + if (try_dl_newtx_alloc_greedy(*tti_sched, user, *h) == alloc_result::no_cch_space) { logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL tx for rnti=0x%x", user.get_rnti()); } } @@ -118,9 +114,9 @@ void sched_time_rr::sched_ul_retxs(sched_ue_list& ue_db, sf_sched* tti_sched, si if (h == nullptr) { continue; } - alloc_outcome_t code = try_ul_retx_alloc(*tti_sched, user, *h); - if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x", user.get_rnti()); + alloc_result code = try_ul_retx_alloc(*tti_sched, user, *h); + if (code == alloc_result::no_cch_space) { + logger.debug("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x", user.get_rnti()); } } } @@ -149,9 +145,10 @@ void sched_time_rr::sched_ul_newtxs(sched_ue_list& ue_db, sf_sched* tti_sched, s if (alloc.empty()) { continue; } - alloc_outcome_t ret = tti_sched->alloc_ul_user(&user, alloc); - if (ret == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for UL tx of rnti=0x%x", user.get_rnti()); + alloc_result ret = tti_sched->alloc_ul_user(&user, alloc); + if (ret == alloc_result::no_cch_space) { + logger.info( + "SCHED: rnti=0x%x, cc=%d, Couldn't find space in PDCCH for UL tx", user.get_rnti(), cc_cfg->enb_cc_idx); } } } diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 3017490fc..5ffff2daf 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -432,9 +432,9 @@ void ue::deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx) { std::unique_lock lock(rx_buffers_mutex); if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().try_deallocate_pdu(tti_point(tti))) { - logger.warning("UE buffers: Null RX PDU pointer in deallocate_pdu for rnti=0x%x pid=%d cc_idx=%d", + logger.warning("UE buffers: Null RX PDU pointer in deallocate_pdu for rnti=0x%x tti=%d cc_idx=%d", rnti, - tti % nof_rx_harq_proc, + tti, ue_cc_idx); } } @@ -444,7 +444,7 @@ void ue::push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len) std::unique_lock lock(rx_buffers_mutex); if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().push_pdu(tti_point(tti), len)) { logger.warning( - "UE buffers: Failed to push RX PDU for rnti=0x%x pid=%d cc_idx=%d", rnti, tti % nof_rx_harq_proc, ue_cc_idx); + "UE buffers: Failed to push RX PDU for rnti=0x%x tti=%d cc_idx=%d", rnti, tti, ue_cc_idx); } } diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index 9bd865887..64d2fe0ce 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -308,6 +308,11 @@ void mac_controller::handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_p } } +void mac_controller::handle_max_retx() +{ + set_drb_activation(false); +} + void mac_controller::set_scell_activation(const std::bitset& scell_mask) { for (uint32_t i = 1; i < current_sched_ue_cfg.supported_cc_list.size(); ++i) { diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 5663823ef..90f2bff4f 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -145,6 +145,8 @@ void rrc::ue::max_retx_reached() // Give UE time to start re-establishment set_activity_timeout(UE_REESTABLISH_TIMEOUT); + + mac_ctrl.handle_max_retx(); } } diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index 5cdc90386..affc25dbc 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -18,6 +18,7 @@ * and at http://www.gnu.org/licenses/. * */ + #include "srslte/upper/gtpu.h" #include "srsenb/hdr/stack/upper/gtpu.h" #include "srslte/common/network_utils.h" @@ -35,7 +36,9 @@ using namespace srslte; namespace srsenb { -gtpu::gtpu(srslog::basic_logger& logger) : m1u(this), logger(logger) {} +gtpu::gtpu(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger) : + m1u(this), task_sched(task_sched_), logger(logger) +{} int gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, @@ -183,6 +186,26 @@ uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t after_tun.dl_enabled = false; after_tun.prior_teid_in_present = true; after_tun.prior_teid_in = teid_in; + // Schedule autoremoval of this indirect tunnel + uint32_t after_teidin = after_tun.teid_in; + uint32_t before_teidin = new_tun.teid_in; + new_tun.rx_timer = task_sched.get_unique_timer(); + new_tun.rx_timer.set(500, [this, before_teidin, after_teidin](uint32_t tid) { + auto it = tunnels.find(after_teidin); + if (it != tunnels.end()) { + tunnel& after_tun = it->second; + if (after_tun.prior_teid_in_present) { + after_tun.prior_teid_in_present = false; + set_tunnel_status(after_tun.teid_in, true); + } + // else: indirect tunnel already removed + } else { + logger.info("Callback to automatic indirect tunnel deletion called for non-existent TEID=%d", after_teidin); + } + // This will self-destruct the callback object + rem_tunnel(before_teidin); + }); + new_tun.rx_timer.run(); } // Connect tunnels if forwarding is activated @@ -275,16 +298,11 @@ void gtpu::rem_tunnel(uint32_t teidin) logger.warning("Removing GTPU tunnel TEID In=0x%x", teidin); return; } - if (it->second.fwd_teid_in_present) { - // Forward End Marker to forwarding tunnel, before deleting tunnel - end_marker(it->second.fwd_teid_in); - it->second.fwd_teid_in_present = false; - } auto ue_it = ue_teidin_db.find(it->second.rnti); std::vector& lcid_tunnels = ue_it->second[it->second.lcid]; lcid_tunnels.erase(std::remove(lcid_tunnels.begin(), lcid_tunnels.end(), teidin), lcid_tunnels.end()); + logger.debug("TEID In=%d for rnti=0x%x erased", teidin, it->second.rnti); tunnels.erase(it); - logger.debug("TEID In=%d erased", teidin); } void gtpu::rem_user(uint16_t rnti) @@ -300,6 +318,39 @@ void gtpu::rem_user(uint16_t rnti) } } +void gtpu::handle_end_marker(tunnel& rx_tunnel) +{ + uint16_t rnti = rx_tunnel.rnti; + logger.info("Received GTPU End Marker for rnti=0x%x.", rnti); + + // TS 36.300, Sec 10.1.2.2.1 - Path Switch upon handover + if (rx_tunnel.fwd_teid_in_present) { + // END MARKER should be forwarded to TeNB if forwarding is activated + end_marker(rx_tunnel.fwd_teid_in); + rx_tunnel.fwd_teid_in_present = false; + + rem_tunnel(rx_tunnel.teid_in); + } else { + // TeNB switches paths, and flush PDUs that have been buffered + auto rnti_it = ue_teidin_db.find(rnti); + if (rnti_it == ue_teidin_db.end()) { + logger.error("No rnti=0x%x entry for associated TEID=%d", rnti, rx_tunnel.teid_in); + return; + } + std::vector& bearer_tunnels = rnti_it->second[rx_tunnel.lcid]; + for (uint32_t new_teidin : bearer_tunnels) { + tunnel& new_tun = tunnels.at(new_teidin); + if (new_teidin != rx_tunnel.teid_in and new_tun.prior_teid_in_present and + new_tun.prior_teid_in == rx_tunnel.teid_in) { + rem_tunnel(new_tun.prior_teid_in); + new_tun.prior_teid_in_present = false; + set_tunnel_status(new_tun.teid_in, true); + break; + } + } + } +} + void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const sockaddr_in& addr) { logger.debug("Received %d bytes from S1-U interface", pdu->N_bytes); @@ -310,11 +361,20 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc return; } - if (header.teid != 0 && tunnels.count(header.teid) == 0) { - // Received G-PDU for non-existing and non-zero TEID. - // Sending GTP-U error indication - error_indication(addr.sin_addr.s_addr, addr.sin_port, header.teid); - return; + tunnel* rx_tunnel = nullptr; + if (header.teid != 0) { + auto it = tunnels.find(header.teid); + if (it == tunnels.end()) { + // Received G-PDU for non-existing and non-zero TEID. + // Sending GTP-U error indication + error_indication(addr.sin_addr.s_addr, addr.sin_port, header.teid); + } + rx_tunnel = &it->second; + + if (rx_tunnel->rx_timer.is_valid()) { + // Restart Rx timer + rx_tunnel->rx_timer.run(); + } } switch (header.message_type) { @@ -353,31 +413,11 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc } } } break; - case GTPU_MSG_END_MARKER: { - tunnel& old_tun = tunnels.find(header.teid)->second; - uint16_t rnti = old_tun.rnti; - logger.info("Received GTPU End Marker for rnti=0x%x.", rnti); - - // TS 36.300, Sec 10.1.2.2.1 - Path Switch upon handover - if (old_tun.fwd_teid_in_present) { - // END MARKER should be forwarded to TeNB if forwarding is activated - end_marker(old_tun.fwd_teid_in); - old_tun.fwd_teid_in_present = false; - } else { - // TeNB switches paths, and flush PDUs that have been buffered - std::vector& bearer_tunnels = ue_teidin_db.find(old_tun.rnti)->second[old_tun.lcid]; - for (uint32_t new_teidin : bearer_tunnels) { - tunnel& new_tun = tunnels.at(new_teidin); - if (new_teidin != old_tun.teid_in and new_tun.prior_teid_in_present and - new_tun.prior_teid_in == old_tun.teid_in) { - new_tun.prior_teid_in_present = false; - set_tunnel_status(new_tun.teid_in, true); - } - } - } + case GTPU_MSG_END_MARKER: + handle_end_marker(*rx_tunnel); break; - } default: + logger.warning("Unhandled GTPU message type=%d", header.message_type); break; } } @@ -480,13 +520,22 @@ void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq) /**************************************************************************** * GTP-U END MARKER ***************************************************************************/ -void gtpu::end_marker(uint32_t teidin) +bool gtpu::end_marker(uint32_t teidin) { logger.info("TX GTPU End Marker."); - tunnel& tunnel = tunnels.find(teidin)->second; + auto it = tunnels.find(teidin); + if (it == tunnels.end()) { + logger.error("TEID=%d not found to send the end marker to", teidin); + return false; + } + tunnel& tunnel = it->second; gtpu_header_t header = {}; unique_byte_buffer_t pdu = make_byte_buffer(); + if (pdu == nullptr) { + logger.warning("Failed to allocate buffer to send End Marker to TEID=%d", teidin); + return false; + } // header header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL; @@ -502,6 +551,7 @@ void gtpu::end_marker(uint32_t teidin) servaddr.sin_port = htons(GTPU_PORT); sendto(fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); + return true; } /**************************************************************************** diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 4b5466db9..b3a0bc20d 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -183,11 +183,7 @@ srslte::proc_outcome_t s1ap::s1_setup_proc_t::start_mme_connection() } if (not s1ap_ptr->connect_mme()) { - procInfo("Failed to initiate SCTP socket. Attempting reconnection in %d seconds", - s1ap_ptr->mme_connect_timer.duration() / 1000); - srslte::console("Failed to initiate SCTP socket. Attempting reconnection in %d seconds\n", - s1ap_ptr->mme_connect_timer.duration() / 1000); - s1ap_ptr->mme_connect_timer.run(); + procInfo("Could not connect to MME"); return srslte::proc_outcome_t::error; } @@ -212,7 +208,7 @@ srslte::proc_outcome_t s1ap::s1_setup_proc_t::react(const srsenb::s1ap::s1_setup procInfo("S1Setup procedure completed successfully"); return srslte::proc_outcome_t::success; } - procError("S1Setup failed. Exiting..."); + procError("S1Setup failed."); srslte::console("S1setup failed\n"); return srslte::proc_outcome_t::error; } @@ -220,8 +216,15 @@ srslte::proc_outcome_t s1ap::s1_setup_proc_t::react(const srsenb::s1ap::s1_setup void s1ap::s1_setup_proc_t::then(const srslte::proc_state_t& result) const { if (result.is_error()) { + procInfo("Failed to initiate S1 connection. Attempting reconnection in %d seconds", + s1ap_ptr->mme_connect_timer.duration() / 1000); + srslte::console("Failed to initiate S1 connection. Attempting reconnection in %d seconds\n", + s1ap_ptr->mme_connect_timer.duration() / 1000); + s1ap_ptr->mme_connect_timer.run(); + s1ap_ptr->stack->remove_mme_socket(s1ap_ptr->s1ap_socket.get_socket()); s1ap_ptr->s1ap_socket.reset(); procInfo("S1AP socket closed."); + // Try again with in 10 seconds } } @@ -438,11 +441,13 @@ bool s1ap::connect_mme() &s1ap_socket, srslte::net_utils::socket_type::seqpacket, args.s1c_bind_addr.c_str())) { return false; } + logger.info("SCTP socket opened. fd=%d", s1ap_socket.fd()); // Connect to the MME address if (not s1ap_socket.connect_to(args.mme_addr.c_str(), MME_PORT, &mme_addr)) { return false; } + logger.info("SCTP socket connected with MME. fd=%d", s1ap_socket.fd()); // Assign a handler to rx MME packets (going to run in a different thread) stack->add_mme_socket(s1ap_socket.fd()); diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt index 45de0240c..1efc4ca55 100644 --- a/srsenb/test/mac/CMakeLists.txt +++ b/srsenb/test/mac/CMakeLists.txt @@ -70,3 +70,7 @@ add_test(sched_tpc_test sched_tpc_test) add_executable(sched_dci_test sched_dci_test.cc) target_link_libraries(sched_dci_test srslte_common srsenb_mac srslte_mac sched_test_common) add_test(sched_dci_test sched_dci_test) + +add_executable(sched_benchmark_test sched_benchmark.cc) +target_link_libraries(sched_benchmark_test srslte_common srsenb_mac srslte_mac sched_test_common) +add_test(sched_benchmark_test sched_benchmark_test) diff --git a/srsenb/test/mac/sched_benchmark.cc b/srsenb/test/mac/sched_benchmark.cc new file mode 100644 index 000000000..d61b270c4 --- /dev/null +++ b/srsenb/test/mac/sched_benchmark.cc @@ -0,0 +1,414 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "sched_test_common.h" +#include "srsenb/hdr/stack/mac/sched.h" +#include "srslte/adt/accumulators.h" +#include + +namespace srsenb { + +struct run_params { + uint32_t nof_prbs; + uint32_t nof_ues; + uint32_t nof_ttis; + uint32_t cqi; + const char* sched_policy; +}; + +struct run_params_range { + std::vector nof_prbs = {6, 15, 25, 50, 75, 100}; + std::vector nof_ues = {1, 2, 5}; + uint32_t nof_ttis = 10000; + std::vector cqi = {5, 10, 15}; + std::vector sched_policy = {"time_rr", "time_pf"}; + + size_t nof_runs() const { return nof_prbs.size() * nof_ues.size() * cqi.size() * sched_policy.size(); } + run_params get_params(size_t idx) const + { + run_params r = {}; + r.nof_ttis = nof_ttis; + r.nof_prbs = nof_prbs[idx % nof_prbs.size()]; + idx /= nof_prbs.size(); + r.nof_ues = nof_ues[idx % nof_ues.size()]; + idx /= nof_ues.size(); + r.cqi = cqi[idx % cqi.size()]; + idx /= cqi.size(); + r.sched_policy = sched_policy.at(idx); + return r; + } +}; + +class sched_tester : public sched_sim_base +{ + static std::vector get_cell_cfg(srslte::span cell_params) + { + std::vector cell_cfg_list; + for (const auto& c : cell_params) { + cell_cfg_list.push_back(c.cfg); + } + return cell_cfg_list; + } + +public: + explicit sched_tester(sched* sched_obj_, + const sched_interface::sched_args_t& sched_args, + const std::vector& cell_cfg_list) : + sched_sim_base(sched_obj_, sched_args, cell_cfg_list), + sched_ptr(sched_obj_), + dl_result(cell_cfg_list.size()), + ul_result(cell_cfg_list.size()) + {} + + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC"); + sched* sched_ptr; + uint32_t dl_bytes_per_tti = 100000; + uint32_t ul_bytes_per_tti = 100000; + run_params current_run_params = {}; + + std::vector dl_result; + std::vector ul_result; + + struct throughput_stats { + srslte::rolling_average mean_dl_tbs, mean_ul_tbs, avg_dl_mcs, avg_ul_mcs; + srslte::rolling_average avg_latency; + }; + throughput_stats total_stats; + + int advance_tti() + { + tti_point tti_rx = get_tti_rx().is_valid() ? get_tti_rx() + 1 : tti_point(0); + mac_logger.set_context(tti_rx.to_uint()); + new_tti(tti_rx); + + for (uint32_t cc = 0; cc < get_cell_params().size(); ++cc) { + std::chrono::time_point tp = std::chrono::steady_clock::now(); + TESTASSERT(sched_ptr->dl_sched(to_tx_dl(tti_rx).to_uint(), cc, dl_result[cc]) == SRSLTE_SUCCESS); + TESTASSERT(sched_ptr->ul_sched(to_tx_ul(tti_rx).to_uint(), cc, ul_result[cc]) == SRSLTE_SUCCESS); + std::chrono::time_point tp2 = std::chrono::steady_clock::now(); + std::chrono::nanoseconds tdur = std::chrono::duration_cast(tp2 - tp); + total_stats.avg_latency.push(tdur.count()); + } + + sf_output_res_t sf_out{get_cell_params(), tti_rx, ul_result, dl_result}; + update(sf_out); + process_stats(sf_out); + + return SRSLTE_SUCCESS; + } + + void set_external_tti_events(const sim_ue_ctxt_t& ue_ctxt, ue_tti_events& pending_events) override + { + // do nothing + if (ue_ctxt.conres_rx) { + sched_ptr->ul_bsr(ue_ctxt.rnti, 1, dl_bytes_per_tti); + sched_ptr->dl_rlc_buffer_state(ue_ctxt.rnti, 3, ul_bytes_per_tti, 0); + + if (get_tti_rx().to_uint() % 5 == 0) { + for (auto& cc : pending_events.cc_list) { + cc.dl_cqi = current_run_params.cqi; + cc.ul_snr = 40; + } + } + } + } + + void process_stats(sf_output_res_t& sf_out) + { + for (uint32_t cc = 0; cc < get_cell_params().size(); ++cc) { + uint32_t dl_tbs = 0, ul_tbs = 0, dl_mcs = 0, ul_mcs = 0; + for (const auto& data : sf_out.dl_cc_result[cc].data) { + dl_tbs += data.tbs[0]; + dl_tbs += data.tbs[1]; + dl_mcs = std::max(dl_mcs, data.dci.tb[0].mcs_idx); + } + total_stats.mean_dl_tbs.push(dl_tbs); + if (not sf_out.dl_cc_result[cc].data.empty()) { + total_stats.avg_dl_mcs.push(dl_mcs); + } + for (const auto& pusch : sf_out.ul_cc_result[cc].pusch) { + ul_tbs += pusch.tbs; + ul_mcs = std::max(ul_mcs, pusch.dci.tb.mcs_idx); + } + total_stats.mean_ul_tbs.push(ul_tbs); + if (not sf_out.ul_cc_result[cc].pusch.empty()) { + total_stats.avg_ul_mcs.push(ul_mcs); + } + } + } +}; + +struct run_data { + run_params params; + float avg_dl_throughput; + float avg_ul_throughput; + float avg_dl_mcs; + float avg_ul_mcs; + std::chrono::microseconds avg_latency; +}; + +int run_benchmark_scenario(run_params params, std::vector& run_results) +{ + std::vector cell_list(1, generate_default_cell_cfg(params.nof_prbs)); + sched_interface::ue_cfg_t ue_cfg_default = generate_default_ue_cfg(); + sched_interface::sched_args_t sched_args = {}; + sched_args.sched_policy = params.sched_policy; + + sched sched_obj; + rrc_dummy rrc{}; + sched_obj.init(&rrc, sched_args); + sched_tester tester(&sched_obj, sched_args, cell_list); + + tester.total_stats = {}; + tester.current_run_params = params; + + for (uint32_t ue_idx = 0; ue_idx < params.nof_ues; ++ue_idx) { + uint16_t rnti = 0x46 + ue_idx; + // Add user (first need to advance to a PRACH TTI) + while (not srslte_prach_tti_opportunity_config_fdd( + tester.get_cell_params()[ue_cfg_default.supported_cc_list[0].enb_cc_idx].cfg.prach_config, + tester.get_tti_rx().to_uint(), + -1)) { + TESTASSERT(tester.advance_tti() == SRSLTE_SUCCESS); + } + TESTASSERT(tester.add_user(rnti, ue_cfg_default, 16) == SRSLTE_SUCCESS); + TESTASSERT(tester.advance_tti() == SRSLTE_SUCCESS); + } + + // Ignore stats of the first TTIs until all UEs DRB1 are created + auto ue_db_ctxt = tester.get_enb_ctxt().ue_db; + while (not std::all_of(ue_db_ctxt.begin(), ue_db_ctxt.end(), [](std::pair p) { + return p.second->conres_rx; + })) { + tester.advance_tti(); + ue_db_ctxt = tester.get_enb_ctxt().ue_db; + } + tester.total_stats = {}; + + // Run benchmark + for (uint32_t count = 0; count < params.nof_ttis; ++count) { + tester.advance_tti(); + } + + run_data run_result = {}; + run_result.params = params; + run_result.avg_dl_throughput = tester.total_stats.mean_dl_tbs.value() * 8.0F / 1e-3F; + run_result.avg_ul_throughput = tester.total_stats.mean_ul_tbs.value() * 8.0F / 1e-3F; + run_result.avg_dl_mcs = tester.total_stats.avg_dl_mcs.value(); + run_result.avg_ul_mcs = tester.total_stats.avg_ul_mcs.value(); + run_result.avg_latency = std::chrono::microseconds(static_cast(tester.total_stats.avg_latency.value() / 1000)); + run_results.push_back(run_result); + + return SRSLTE_SUCCESS; +} + +run_data expected_run_result(run_params params) +{ + assert(params.cqi == 15 && "only cqi=15 supported for now"); + run_data ret{}; + int tbs_idx = srslte_ra_tbs_idx_from_mcs(28, false, false); + int tbs = srslte_ra_tbs_from_idx(tbs_idx, params.nof_prbs); + ret.avg_dl_throughput = static_cast(tbs) * 1e3F; // bps + + tbs_idx = srslte_ra_tbs_idx_from_mcs(24, false, true); + uint32_t nof_pusch_prbs = params.nof_prbs - (params.nof_prbs == 6 ? 2 : 4); + tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_pusch_prbs); + ret.avg_ul_throughput = static_cast(tbs) * 1e3F; // bps + + ret.avg_dl_mcs = 27; + ret.avg_ul_mcs = 22; + switch (params.nof_prbs) { + case 6: + ret.avg_dl_mcs = 25; + ret.avg_dl_throughput *= 0.68; + ret.avg_ul_throughput *= 0.75; + break; + case 15: + ret.avg_dl_throughput *= 0.95; + ret.avg_ul_throughput *= 0.7; + break; + default: + ret.avg_dl_throughput *= 0.97; + ret.avg_ul_throughput *= 0.85; + break; + } + return ret; +} + +void print_benchmark_results(const std::vector& run_results) +{ + srslog::flush(); + fmt::print("run | Nprb | cqi | sched pol | Nue | DL/UL [Mbps] | DL/UL mcs | DL/UL OH [%] | latency " + "[usec]\n"); + fmt::print("---------------------------------------------------------------------------------------" + "------\n"); + for (uint32_t i = 0; i < run_results.size(); ++i) { + const run_data& r = run_results[i]; + + int tbs_idx = srslte_ra_tbs_idx_from_mcs(28, false, false); + int tbs = srslte_ra_tbs_from_idx(tbs_idx, r.params.nof_prbs); + float dl_rate_overhead = 1.0F - r.avg_dl_throughput / (static_cast(tbs) * 1e3F); + tbs_idx = srslte_ra_tbs_idx_from_mcs(24, false, true); + uint32_t nof_pusch_prbs = r.params.nof_prbs - (r.params.nof_prbs == 6 ? 2 : 4); + tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_pusch_prbs); + float ul_rate_overhead = 1.0F - r.avg_ul_throughput / (static_cast(tbs) * 1e3F); + + fmt::print("{:>3d}{:>6d}{:>6d}{:>12}{:>6d}{:>9.2}/{:>4.2}{:>9.1f}/{:>4.1f}{:9.1f}/{:>4.1f}{:12d}\n", + i, + r.params.nof_prbs, + r.params.cqi, + r.params.sched_policy, + r.params.nof_ues, + r.avg_dl_throughput / 1e6, + r.avg_ul_throughput / 1e6, + r.avg_dl_mcs, + r.avg_ul_mcs, + dl_rate_overhead * 100, + ul_rate_overhead * 100, + r.avg_latency.count()); + } +} + +int run_rate_test() +{ + fmt::print("\n====== Scheduler Rate Test ======\n\n"); + run_params_range run_param_list{}; + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC"); + + run_param_list.nof_ues = {1}; + run_param_list.cqi = {15}; + + std::vector run_results; + size_t nof_runs = run_param_list.nof_runs(); + + for (size_t r = 0; r < nof_runs; ++r) { + run_params runparams = run_param_list.get_params(r); + + mac_logger.info("\n=== New run {} ===\n", r); + TESTASSERT(run_benchmark_scenario(runparams, run_results) == SRSLTE_SUCCESS); + } + + print_benchmark_results(run_results); + + bool success = true; + for (auto& run : run_results) { + run_data expected = expected_run_result(run.params); + if (run.avg_dl_mcs < expected.avg_dl_mcs) { + fmt::print( + "Nprb={:>2d}: DL mcs below expected ({} < {})\n", run.params.nof_prbs, run.avg_dl_mcs, expected.avg_dl_mcs); + success = false; + } + if (run.avg_dl_throughput < expected.avg_dl_throughput) { + fmt::print("Nprb={:>2d}: DL rate below expected ({:.2} < {:.2}) Mbps\n", + run.params.nof_prbs, + run.avg_dl_throughput / 1e6, + expected.avg_dl_throughput / 1e6); + success = false; + } + if (run.avg_ul_mcs < expected.avg_ul_mcs) { + fmt::print( + "Nprb={:>2d}: UL mcs below expected ({} < {})\n", run.params.nof_prbs, run.avg_ul_mcs, expected.avg_ul_mcs); + success = false; + } + if (run.avg_ul_throughput < expected.avg_ul_throughput) { + fmt::print("Nprb={:>2d}: UL rate below expected ({:.2} < {:.2}) Mbps\n", + run.params.nof_prbs, + run.avg_ul_throughput / 1e6, + expected.avg_ul_throughput / 1e6); + success = false; + } + } + return success ? SRSLTE_SUCCESS : SRSLTE_ERROR; +} + +int run_all() +{ + run_params_range run_param_list{}; + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC"); + + fmt::print("Running all param combinations\n"); + std::vector run_results; + size_t nof_runs = run_param_list.nof_runs(); + for (size_t r = 0; r < nof_runs; ++r) { + run_params runparams = run_param_list.get_params(r); + + mac_logger.info("\n### New run {} ###\n", r); + TESTASSERT(run_benchmark_scenario(runparams, run_results) == SRSLTE_SUCCESS); + } + + print_benchmark_results(run_results); + + return SRSLTE_SUCCESS; +} + +int run_benchmark() +{ + run_params_range run_param_list{}; + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("MAC"); + + run_param_list.nof_ttis = 1000000; + run_param_list.nof_prbs = {100}; + run_param_list.cqi = {15}; + run_param_list.nof_ues = {5}; + run_param_list.sched_policy = {"time_pf"}; + + std::vector run_results; + size_t nof_runs = run_param_list.nof_runs(); + fmt::print("Running Benchmark\n"); + for (size_t r = 0; r < nof_runs; ++r) { + run_params runparams = run_param_list.get_params(r); + + mac_logger.info("\n### New run {} ###\n", r); + TESTASSERT(run_benchmark_scenario(runparams, run_results) == SRSLTE_SUCCESS); + } + + print_benchmark_results(run_results); + + return SRSLTE_SUCCESS; +} + +} // namespace srsenb + +int main(int argc, char* argv[]) +{ + // Setup the log spy to intercept error and warning log entries. + if (!srslog::install_custom_sink( + srslte::log_sink_spy::name(), + std::unique_ptr(new srslte::log_sink_spy(srslog::get_default_log_formatter())))) { + return SRSLTE_ERROR; + } + + auto* spy = static_cast(srslog::find_sink(srslte::log_sink_spy::name())); + if (spy == nullptr) { + return SRSLTE_ERROR; + } + + auto& mac_log = srslog::fetch_basic_logger("MAC"); + mac_log.set_level(srslog::basic_levels::warning); + auto& test_log = srslog::fetch_basic_logger("TEST", *spy, false); + test_log.set_level(srslog::basic_levels::warning); + + // Start the log backend. + srslog::init(); + + bool run_benchmark = false; + + if (argc == 1 or strcmp(argv[1], "test") == 0) { + TESTASSERT(srsenb::run_rate_test() == SRSLTE_SUCCESS); + } else if (strcmp(argv[1], "benchmark") == 0) { + TESTASSERT(srsenb::run_benchmark() == SRSLTE_SUCCESS); + } else { + TESTASSERT(srsenb::run_all() == SRSLTE_SUCCESS); + } + + return 0; +} \ No newline at end of file diff --git a/srsenb/test/mac/sched_ca_test.cc b/srsenb/test/mac/sched_ca_test.cc index 237026295..08c50df5f 100644 --- a/srsenb/test/mac/sched_ca_test.cc +++ b/srsenb/test/mac/sched_ca_test.cc @@ -26,7 +26,7 @@ using namespace srsenb; -uint32_t const seed = std::chrono::system_clock::now().time_since_epoch().count(); +uint32_t seed = std::chrono::system_clock::now().time_since_epoch().count(); /******************* * Logging * @@ -166,7 +166,7 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para } }; generate_data(20, 1.0, P_ul_sr, randf()); - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); // Event: Reconf Complete. Activate SCells. Check if CE correctly transmitted generator.step_tti(); @@ -178,7 +178,7 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para user->ue_sim_cfg->ue_cfg.supported_cc_list[i].active = true; user->ue_sim_cfg->ue_cfg.supported_cc_list[i].enb_cc_idx = cc_idxs[i]; } - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); auto activ_list = tester.get_enb_ue_cc_map(rnti1); for (uint32_t i = 0; i < cc_idxs.size(); ++i) { TESTASSERT(activ_list[i] >= 0); @@ -186,7 +186,7 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para // TEST: When a DL newtx takes place, it should also encode the CE for (uint32_t i = 0; i < 100; ++i) { - if (tester.tti_info.dl_sched_result[params.pcell_idx].nof_data_elems > 0) { + if (not tester.tti_info.dl_sched_result[params.pcell_idx].data.empty()) { // DL data was allocated if (tester.tti_info.dl_sched_result[params.pcell_idx].data[0].nof_pdu_elems[0] > 0) { // it is a new DL tx @@ -196,7 +196,7 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para } } generator.step_tti(); - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); } // Event: Wait for UE to receive and ack CE. Send cqi==0, which should not activate the SCell @@ -207,12 +207,12 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para generator.step_tti(); } } - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); // The UE should now have received the CE // Event: Generate a bit more data, it should *not* go through SCells until we send a CQI generate_data(5, P_dl, P_ul_sr, randf()); - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); TESTASSERT(tester.sched_stats->users[rnti1].tot_dl_sched_data[params.pcell_idx] > 0); TESTASSERT(tester.sched_stats->users[rnti1].tot_ul_sched_data[params.pcell_idx] > 0); for (uint32_t i = 1; i < cc_idxs.size(); ++i) { @@ -226,7 +226,7 @@ int test_scell_activation(uint32_t sim_number, test_scell_activation_params para tester.dl_cqi_info(tester.tti_rx.to_uint(), rnti1, cc_idxs[i], cqi); } generate_data(10, 1.0, 1.0, 1.0); - tester.test_next_ttis(generator.tti_events); + TESTASSERT(tester.test_next_ttis(generator.tti_events) == SRSLTE_SUCCESS); uint64_t tot_dl_sched_data = 0; uint64_t tot_ul_sched_data = 0; for (const auto& c : cc_idxs) { diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index 46614a0a6..e828eb554 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -64,7 +64,7 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co try_ul_fill({cell_params.cfg.cell.nof_prb - pucch_nrb, (uint32_t)cell_params.cfg.cell.nof_prb}, "PUCCH", strict); /* TEST: check collisions in the UL PUSCH */ - for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_result.pusch.size(); ++i) { uint32_t L, RBstart; srslte_ra_type2_from_riv(ul_result.pusch[i].dci.type2_alloc.riv, &L, &RBstart, nof_prb, nof_prb); strict = ul_result.pusch[i].needs_pdcch or nof_prb != 6; // Msg3 may collide with PUCCH at PRB==6 @@ -122,12 +122,12 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co }; // Decode BC allocations, check collisions, and fill cumulative mask - for (uint32_t i = 0; i < dl_result.nof_bc_elems; ++i) { + for (uint32_t i = 0; i < dl_result.bc.size(); ++i) { TESTASSERT(try_dl_mask_fill(dl_result.bc[i].dci, "BC") == SRSLTE_SUCCESS); } // Decode RAR allocations, check collisions, and fill cumulative mask - for (uint32_t i = 0; i < dl_result.nof_rar_elems; ++i) { + for (uint32_t i = 0; i < dl_result.rar.size(); ++i) { TESTASSERT(try_dl_mask_fill(dl_result.rar[i].dci, "RAR") == SRSLTE_SUCCESS); } @@ -140,7 +140,7 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co } // Decode Data allocations, check collisions and fill cumulative mask - for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_result.data.size(); ++i) { TESTASSERT(try_dl_mask_fill(dl_result.data[i].dci, "data") == SRSLTE_SUCCESS); } @@ -179,8 +179,8 @@ int test_sib_scheduling(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) bool sib1_expected = ((sfn % 2) == 0) and sf_idx == 5; using bc_elem = const sched_interface::dl_sched_bc_t; - bc_elem* bc_begin = &dl_result.bc[0]; - bc_elem* bc_end = &dl_result.bc[dl_result.nof_bc_elems]; + bc_elem* bc_begin = dl_result.bc.begin(); + bc_elem* bc_end = dl_result.bc.end(); /* Test if SIB1 was correctly scheduled */ auto it = std::find_if(bc_begin, bc_end, [](bc_elem& elem) { return elem.index == 0; }); @@ -197,6 +197,9 @@ int test_sib_scheduling(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) "Allocated BC process with TBS=%d < sib_len=%d", bc->tbs, cell_params.cfg.sibs[bc->index].len); + CONDERROR(bc->dci.rnti != 0xffff, "Invalid rnti=0x%x for SIB%d", bc->dci.rnti, bc->index); + CONDERROR(bc->dci.format != SRSLTE_DCI_FORMAT1A, "Invalid DCI format for SIB%d", bc->index); + uint32_t x = (bc->index - 1) * cell_params.cfg.si_window_ms; uint32_t sf = x % 10; uint32_t sfn_start = sfn; @@ -235,7 +238,7 @@ int test_pdcch_collisions(const sf_output_res_t& sf_out, }; /* TEST: verify there are no dci collisions for UL, DL data, BC, RAR */ - for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_result.pusch.size(); ++i) { const auto& pusch = ul_result.pusch[i]; if (not pusch.needs_pdcch) { // In case of non-adaptive retx or Msg3 @@ -243,13 +246,13 @@ int test_pdcch_collisions(const sf_output_res_t& sf_out, } try_cce_fill(pusch.dci.location, "UL"); } - for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_result.data.size(); ++i) { try_cce_fill(dl_result.data[i].dci.location, "DL data"); } - for (uint32_t i = 0; i < dl_result.nof_bc_elems; ++i) { + for (uint32_t i = 0; i < dl_result.bc.size(); ++i) { try_cce_fill(dl_result.bc[i].dci.location, "DL BC"); } - for (uint32_t i = 0; i < dl_result.nof_rar_elems; ++i) { + for (uint32_t i = 0; i < dl_result.rar.size(); ++i) { try_cce_fill(dl_result.rar[i].dci.location, "DL RAR"); } @@ -268,7 +271,7 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) const auto& ul_result = sf_out.ul_cc_result[enb_cc_idx]; std::set alloc_rntis; - for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_result.pusch.size(); ++i) { const auto& pusch = ul_result.pusch[i]; uint16_t rnti = pusch.dci.rnti; CONDERROR(pusch.tbs == 0, "Allocated PUSCH with invalid TBS=%d", pusch.tbs); @@ -287,7 +290,7 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) } alloc_rntis.clear(); - for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_result.data.size(); ++i) { auto& data = dl_result.data[i]; uint16_t rnti = data.dci.rnti; CONDERROR(data.tbs[0] == 0 and data.tbs[1] == 0, "Allocated DL data has empty TBS"); @@ -311,8 +314,24 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) } } } - for (uint32_t i = 0; i < dl_result.nof_bc_elems; ++i) { - auto& bc = dl_result.bc[i]; + + // TEST: max coderate is not exceeded for RA and Broadcast + srslte_dl_sf_cfg_t dl_sf = {}; + dl_sf.cfi = sf_out.dl_cc_result[enb_cc_idx].cfi; + dl_sf.tti = to_tx_dl(sf_out.tti_rx).to_uint(); + auto test_ra_bc_coderate = [&dl_sf, &cell_params](uint32_t tbs, const srslte_dci_dl_t& dci) { + srslte_pdsch_grant_t grant = {}; + srslte_ra_dl_grant_to_grant_prb_allocation(&dci, &grant, cell_params.cfg.cell.nof_prb); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&cell_params.cfg.cell, &dl_sf, &grant); + float coderate = srslte_coderate(tbs * 8, nof_re); + const uint32_t Qm = 2; + CONDERROR( + coderate > 0.932f * Qm, "Max coderate was exceeded from %s DCI", dci.rnti == SRSLTE_SIRNTI ? "SIB" : "RAR"); + return SRSLTE_SUCCESS; + }; + + for (uint32_t i = 0; i < dl_result.bc.size(); ++i) { + const sched_interface::dl_sched_bc_t& bc = dl_result.bc[i]; if (bc.type == sched_interface::dl_sched_bc_t::BCCH) { CONDERROR(bc.tbs < cell_params.cfg.sibs[bc.index].len, "Allocated BC process with TBS=%d < sib_len=%d", @@ -323,10 +342,16 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) } else { TESTERROR("Invalid broadcast process id=%d", (int)bc.type); } + + TESTASSERT(test_ra_bc_coderate(bc.tbs, bc.dci) == SRSLTE_SUCCESS); } - for (uint32_t i = 0; i < dl_result.nof_rar_elems; ++i) { + + for (uint32_t i = 0; i < dl_result.rar.size(); ++i) { const auto& rar = dl_result.rar[i]; CONDERROR(rar.tbs == 0, "Allocated RAR process with invalid TBS=%d", rar.tbs); + + // TEST: max coderate is not exceeded + TESTASSERT(test_ra_bc_coderate(rar.tbs, rar.dci) == SRSLTE_SUCCESS); } return SRSLTE_SUCCESS; diff --git a/srsenb/test/mac/sched_dci_test.cc b/srsenb/test/mac/sched_dci_test.cc index dca53d2c4..2803c322c 100644 --- a/srsenb/test/mac/sched_dci_test.cc +++ b/srsenb/test/mac/sched_dci_test.cc @@ -63,7 +63,7 @@ bool lower_coderate(tbs_info tb, uint32_t nof_re, const tbs_test_args& args) srslte_mod_t mod = (args.is_ul) ? srslte_ra_ul_mod_from_mcs(tb.mcs) : srslte_ra_dl_mod_from_mcs(tb.mcs, args.use_tbs_index_alt); float Qm = std::min(args.get_max_Qm(), srslte_mod_bits_x_symbol(mod)); - return coderate <= 0.930f * Qm; + return coderate <= 0.932f * Qm; } int test_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_test_args& args, tbs_info* result) @@ -112,7 +112,7 @@ int test_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_tes tbs_info tb2; for (tb2.mcs = ret.mcs + 1; tb2.mcs <= (int)args.max_mcs; ++tb2.mcs) { int tbs_idx2 = srslte_ra_tbs_idx_from_mcs(tb2.mcs, args.use_tbs_index_alt, args.is_ul); - tb2.tbs_bytes = srslte_ra_tbs_from_idx(tbs_idx2, args.prb_grant_size) / 8u; + tb2.tbs_bytes = srslte_ra_tbs_from_idx(tbs_idx2, args.prb_grant_size) / 8U; TESTASSERT(not lower_coderate(tb2, nof_re, args) or (args.prb_grant_size == 1 and tb2.mcs == 6)); } @@ -131,62 +131,55 @@ int test_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_tes return SRSLTE_SUCCESS; } -int test_mcs_lookup_specific() +int assert_mcs_tbs_result(uint32_t cell_nof_prb, + uint32_t cqi, + uint32_t prb_grant_size, + uint32_t tbs, + uint32_t mcs, + bool alt_cqi_table = false) { sched_cell_params_t cell_params = {}; - sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(6); + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(cell_nof_prb); sched_interface::sched_args_t sched_args = {}; cell_params.set_cfg(0, cell_cfg, sched_args); tbs_test_args args; - args.verbose = true; - tbs_info expected_result; + args.verbose = true; + args.cqi = cqi; + args.prb_grant_size = prb_grant_size; + args.use_tbs_index_alt = alt_cqi_table; + if (alt_cqi_table) { + args.max_mcs = std::min(args.max_mcs, 27U); // limited to 27 for 256-QAM + } - /* TEST CASE: DL, no 256-QAM */ - // cqi=5,Nprb=1 -> {mcs=3, tbs_idx=3, tbs=40} + tbs_info expected_result; TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); - CONDERROR(expected_result != tbs_info(40 / 8, 3), - "TBS computation failure. {%d, %d}!={40, 3}", + CONDERROR(expected_result != tbs_info(tbs / 8, mcs), + "TBS computation failure. {%d, %d}!={%d, %d}", expected_result.tbs_bytes * 8, - expected_result.mcs); + expected_result.mcs, + tbs, + mcs); - // cqi=15,Nprb=1 -> {mcs=19, tbs_idx=17, tbs=336} - args.cqi = 15; - TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); - CONDERROR(expected_result != tbs_info(336 / 8, 19), - "TBS computation failure. {%d, %d}!={336, 19}", - expected_result.tbs_bytes * 8, - expected_result.mcs); + return SRSLTE_SUCCESS; +} - // cqi=9,Nprb=1,cell_nprb=100 -> {mcs=28, tbs_idx=17, tbs=712} - cell_params = {}; - cell_cfg = generate_default_cell_cfg(100); - cell_params.set_cfg(0, cell_cfg, sched_args); - args.cqi = 9; - TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); - CONDERROR(expected_result != tbs_info(712 / 8, 28), - "TBS computation failure. {%d, %d}!={712, 28}", - expected_result.tbs_bytes * 8, - expected_result.mcs); +int test_mcs_lookup_specific() +{ + /* TEST CASE: DL, no 256-QAM */ + // cqi=5,Nprb=1 -> {mcs=3, tbs_idx=3, tbs=40} + TESTASSERT(assert_mcs_tbs_result(6, 5, 1, 40, 3) == SRSLTE_SUCCESS); + TESTASSERT(assert_mcs_tbs_result(6, 5, 4, 256, 4) == SRSLTE_SUCCESS); - // cqi=10,Nprb=10,cell_nprb=100 -> {mcs=28, tbs=5736} - args.prb_grant_size = 10; - args.cqi = 10; - TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); - CONDERROR(expected_result != tbs_info(5736 / 8, 25), - "TBS computation failure. {%d, %d}!={5736, 25}", - expected_result.tbs_bytes * 8, - expected_result.mcs); + TESTASSERT(assert_mcs_tbs_result(100, 9, 1, 712, 28) == SRSLTE_SUCCESS); + TESTASSERT(assert_mcs_tbs_result(100, 10, 10, 5736, 25) == SRSLTE_SUCCESS); - // cqi=15,Nprb=1,256-QAM -> {mcs=26,tbs_idx=32,tbs=968} - args.prb_grant_size = 1; - args.use_tbs_index_alt = true; - args.max_mcs = 27; // limited to 27 for 256-QAM - args.cqi = 15; - TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); - CONDERROR(expected_result != tbs_info(968 / 8, 27), - "TBS computation failure. {%d, %d}!={968, 27}", - expected_result.tbs_bytes * 8, - expected_result.mcs); + // cqi=15 + TESTASSERT(assert_mcs_tbs_result(6, 15, 1, 336, 19) == SRSLTE_SUCCESS); // I_tbs=17 + TESTASSERT(assert_mcs_tbs_result(6, 15, 6, 2152, 19) == SRSLTE_SUCCESS); // I_tbs=17 + TESTASSERT(assert_mcs_tbs_result(100, 15, 1, 712, 28) == SRSLTE_SUCCESS); // I_tbs=26 + TESTASSERT(assert_mcs_tbs_result(100, 15, 2, 1480, 28) == SRSLTE_SUCCESS); // I_tbs=26 + TESTASSERT(assert_mcs_tbs_result(100, 15, 10, 7480, 28) == SRSLTE_SUCCESS); // I_tbs=26 + TESTASSERT(assert_mcs_tbs_result(100, 15, 1, 968, 27, true) == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } @@ -217,6 +210,9 @@ int test_mcs_tbs_consistency_all() return SRSLTE_SUCCESS; } +/** + * Note: assumes lowest bound for nof of REs + */ int test_min_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_test_args& args, tbs_info* result) { uint32_t nof_re = cell_params.get_dl_lb_nof_re(args.tti_tx_dl, args.prb_grant_size); @@ -288,6 +284,14 @@ int test_min_mcs_tbs_specific() int main() { + auto& mac_log = srslog::fetch_basic_logger("MAC"); + mac_log.set_level(srslog::basic_levels::info); + auto& test_log = srslog::fetch_basic_logger("TEST"); + test_log.set_level(srslog::basic_levels::info); + + // Start the log backend. + srslog::init(); + TESTASSERT(srsenb::test_mcs_lookup_specific() == SRSLTE_SUCCESS); TESTASSERT(srsenb::test_mcs_tbs_consistency_all() == SRSLTE_SUCCESS); TESTASSERT(srsenb::test_min_mcs_tbs_specific() == SRSLTE_SUCCESS); diff --git a/srsenb/test/mac/sched_grid_test.cc b/srsenb/test/mac/sched_grid_test.cc index a8ed38584..56e5f57fb 100644 --- a/srsenb/test/mac/sched_grid_test.cc +++ b/srsenb/test/mac/sched_grid_test.cc @@ -58,7 +58,6 @@ int test_pdcch_one_ue() sched_ue sched_ue{rnti, cell_params, ue_cfg}; pdcch.init(cell_params[PCell_IDX]); - TESTASSERT(pdcch.nof_alloc_combinations() == 0); TESTASSERT(pdcch.nof_allocs() == 0); uint32_t tti_counter = 0; @@ -101,7 +100,7 @@ int test_pdcch_one_ue() TESTASSERT(pdcch_result[0]->rnti == sched_ue.get_rnti()); TESTASSERT(pdcch_result[0]->total_mask.size() == cell_params[ENB_CC_IDX].nof_cce_table[pdcch.get_cfi() - 1]); TESTASSERT(pdcch_result[0]->current_mask == pdcch_result[0]->total_mask); - TESTASSERT(pdcch_result[0]->current_mask.count() == 1u << aggr_idx); + TESTASSERT(pdcch_result[0]->current_mask.count() == 1U << aggr_idx); TESTASSERT(std::count(dci_locs.begin(), dci_locs.end(), pdcch_result[0]->dci_pos.ncce) > 0); // allocate UL user @@ -129,7 +128,7 @@ int test_pdcch_one_ue() TESTASSERT(pdcch_result[1]->rnti == sched_ue.get_rnti()); TESTASSERT(pdcch_result[1]->total_mask.size() == cell_params[ENB_CC_IDX].nof_cce_table[pdcch.get_cfi() - 1]); TESTASSERT((pdcch_result[1]->current_mask & pdcch_result[0]->current_mask).none()); - TESTASSERT(pdcch_result[1]->current_mask.count() == 1u << aggr_idx); + TESTASSERT(pdcch_result[1]->current_mask.count() == 1U << aggr_idx); TESTASSERT(pdcch_result[1]->total_mask == (pdcch_result[0]->current_mask | pdcch_result[1]->current_mask)); TESTASSERT(std::count(dci_locs2.begin(), dci_locs2.end(), pdcch_result[0]->dci_pos.ncce) > 0); @@ -140,6 +139,118 @@ int test_pdcch_one_ue() return SRSLTE_SUCCESS; } +int test_pdcch_ue_and_sibs() +{ + // Params + uint32_t nof_prb = 100; + + std::vector cell_params(1); + sched_interface::ue_cfg_t ue_cfg = generate_default_ue_cfg(); + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(nof_prb); + sched_interface::sched_args_t sched_args{}; + TESTASSERT(cell_params[0].set_cfg(0, cell_cfg, sched_args)); + + sf_cch_allocator pdcch; + sched_ue sched_ue{0x46, cell_params, ue_cfg}; + + pdcch.init(cell_params[PCell_IDX]); + TESTASSERT(pdcch.nof_allocs() == 0); + + tti_point tti_rx{std::uniform_int_distribution(0, 9)(get_rand_gen())}; + + pdcch.new_tti(tti_rx); + TESTASSERT(pdcch.nof_cces() == cell_params[0].nof_cce_table[0]); + TESTASSERT(pdcch.get_cfi() == 1); // Start at CFI=1 + TESTASSERT(pdcch.nof_allocs() == 0); + + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_BC, 2)); + TESTASSERT(pdcch.nof_allocs() == 1); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_RAR, 2)); + TESTASSERT(pdcch.nof_allocs() == 2); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, 2, &sched_ue, false)); + TESTASSERT(pdcch.nof_allocs() == 3); + + // TEST: Ability to revert last allocation + pdcch.rem_last_dci(); + TESTASSERT(pdcch.nof_allocs() == 2); + + // TEST: DCI positions + uint32_t cfi = pdcch.get_cfi(); + sf_cch_allocator::alloc_result_t dci_result; + pdcch_mask_t result_pdcch_mask; + pdcch.get_allocs(&dci_result, &result_pdcch_mask); + TESTASSERT(dci_result.size() == 2); + const cce_position_list& bc_dci_locs = cell_params[0].common_locations[cfi - 1][2]; + TESTASSERT(bc_dci_locs[0] == dci_result[0]->dci_pos.ncce); + const cce_position_list& rar_dci_locs = cell_params[0].rar_locations[to_tx_dl(tti_rx).sf_idx()][cfi - 1][2]; + TESTASSERT(std::any_of(rar_dci_locs.begin(), rar_dci_locs.end(), [&dci_result](uint32_t val) { + return dci_result[1]->dci_pos.ncce == val; + })); + + return SRSLTE_SUCCESS; +} + +int test_6prbs() +{ + std::vector cell_params(1); + sched_interface::ue_cfg_t ue_cfg = generate_default_ue_cfg(); + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(6); + sched_interface::sched_args_t sched_args{}; + TESTASSERT(cell_params[0].set_cfg(0, cell_cfg, sched_args)); + + sf_cch_allocator pdcch; + sched_ue sched_ue{0x46, cell_params, ue_cfg}, sched_ue2{0x47, cell_params, ue_cfg}; + sf_cch_allocator::alloc_result_t dci_result; + pdcch_mask_t result_pdcch_mask; + + pdcch.init(cell_params[PCell_IDX]); + TESTASSERT(pdcch.nof_allocs() == 0); + + uint32_t opt_cfi = 3; + uint32_t bc_aggr_idx = 2, ue_aggr_idx = 1; + + // TEST: The first rnti will pick a DCI position of its 3 possible ones that avoids clash with SIB. The second rnti + // wont find space + tti_point tti_rx{0}; + pdcch.new_tti(tti_rx); + const cce_position_list& bc_dci_locs = cell_params[0].common_locations[opt_cfi - 1][bc_aggr_idx]; + const cce_position_list& rnti_dci_locs = + (*sched_ue.get_locations(0, opt_cfi, to_tx_dl(tti_rx).sf_idx()))[ue_aggr_idx]; + const cce_position_list& rnti2_dci_locs = + (*sched_ue2.get_locations(0, opt_cfi, to_tx_dl(tti_rx).sf_idx()))[ue_aggr_idx]; + + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_BC, bc_aggr_idx)); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, ue_aggr_idx, &sched_ue, false)); + TESTASSERT(not pdcch.alloc_dci(alloc_type_t::DL_DATA, ue_aggr_idx, &sched_ue2, false)); + TESTASSERT(pdcch.nof_allocs() == 2); + + pdcch.get_allocs(&dci_result, &result_pdcch_mask); + TESTASSERT(dci_result.size() == 2); + TESTASSERT(dci_result[0]->dci_pos.ncce == bc_dci_locs[0]); + TESTASSERT(dci_result[1]->dci_pos.ncce == rnti_dci_locs[2]); + + // TEST: Two RNTIs can be allocated if one doesnt use the PUCCH + opt_cfi = 2; + tti_rx = tti_point{1}; + pdcch.new_tti(tti_rx); + const cce_position_list& rnti_dci_locs3 = + (*sched_ue.get_locations(0, opt_cfi, to_tx_dl(tti_rx).sf_idx()))[ue_aggr_idx]; + const cce_position_list& rnti_dci_locs4 = + (*sched_ue2.get_locations(0, opt_cfi, to_tx_dl(tti_rx).sf_idx()))[ue_aggr_idx]; + + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, ue_aggr_idx, &sched_ue, false)); + TESTASSERT(not pdcch.alloc_dci(alloc_type_t::DL_DATA, ue_aggr_idx, &sched_ue2, false)); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, ue_aggr_idx, &sched_ue2, true)); + TESTASSERT(pdcch.nof_allocs() == 2 and pdcch.get_cfi() == opt_cfi); + + pdcch.get_allocs(&dci_result, &result_pdcch_mask); + TESTASSERT(dci_result.size() == 2); + TESTASSERT(dci_result[0]->dci_pos.ncce == rnti_dci_locs3[0]); + TESTASSERT(dci_result[1]->dci_pos.ncce == rnti_dci_locs4[0]); + + return SRSLTE_SUCCESS; +} + int main() { srsenb::set_randseed(seed); @@ -152,6 +263,8 @@ int main() srslog::init(); TESTASSERT(test_pdcch_one_ue() == SRSLTE_SUCCESS); + TESTASSERT(test_pdcch_ue_and_sibs() == SRSLTE_SUCCESS); + TESTASSERT(test_6prbs() == SRSLTE_SUCCESS); srslog::flush(); diff --git a/srsenb/test/mac/sched_lc_ch_test.cc b/srsenb/test/mac/sched_lc_ch_test.cc index 6cd8fd7ec..e7a2807cd 100644 --- a/srsenb/test/mac/sched_lc_ch_test.cc +++ b/srsenb/test/mac/sched_lc_ch_test.cc @@ -54,7 +54,7 @@ int test_pdu_alloc_successful(srsenb::lch_ue_manager& lch_handler, int test_retx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_t rlc_payload_size) { int start_rlc_bytes = lch_handler.get_dl_retx(lcid); - int nof_pdus = ceil(start_rlc_bytes / (float)rlc_payload_size); + int nof_pdus = ceil(static_cast(start_rlc_bytes) / static_cast(rlc_payload_size)); int rem_rlc_bytes = start_rlc_bytes; sched_interface::dl_sched_pdu_t pdu; @@ -70,7 +70,7 @@ int test_retx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_ int test_newtx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_t rlc_payload_size) { int start_rlc_bytes = lch_handler.get_dl_tx(lcid); - int nof_pdus = ceil(start_rlc_bytes / (float)rlc_payload_size); + int nof_pdus = ceil(static_cast(start_rlc_bytes) / (float)rlc_payload_size); int rem_rlc_bytes = start_rlc_bytes; sched_interface::dl_sched_pdu_t pdu; diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index b417d231f..a7c9596ba 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -87,7 +87,7 @@ int ue_sim::update(const sf_output_res_t& sf_out) void ue_sim::update_dl_harqs(const sf_output_res_t& sf_out) { for (uint32_t cc = 0; cc < sf_out.cc_params.size(); ++cc) { - for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) { + for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].data.size(); ++i) { const auto& data = sf_out.dl_cc_result[cc].data[i]; if (data.dci.rnti != ctxt.rnti) { continue; @@ -116,7 +116,7 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); for (uint32_t cc = 0; cc < sf_out.cc_params.size(); ++cc) { // Update UL harqs with PHICH info - for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].nof_phich_elems; ++i) { + for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].phich.size(); ++i) { const auto& phich = sf_out.ul_cc_result[cc].phich[i]; if (phich.rnti != ctxt.rnti) { continue; @@ -137,7 +137,7 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) } // Update UL harqs with PUSCH grants - for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].nof_dci_elems; ++i) { + for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) { const auto& data = sf_out.ul_cc_result[cc].pusch[i]; if (data.dci.rnti != ctxt.rnti) { continue; @@ -180,7 +180,7 @@ void ue_sim::update_conn_state(const sf_output_res_t& sf_out) srslte::tti_interval rar_window{ctxt.prach_tti_rx + 3, ctxt.prach_tti_rx + 3 + rar_win_size}; if (rar_window.contains(tti_tx_dl)) { - for (uint32_t i = 0; i < dl_cc_result.nof_rar_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_result.rar.size(); ++i) { for (uint32_t j = 0; j < dl_cc_result.rar[i].msg3_grant.size(); ++j) { const auto& data = dl_cc_result.rar[i].msg3_grant[j].data; if (data.prach_tti == (uint32_t)ctxt.prach_tti_rx.to_uint() and data.preamble_idx == ctxt.preamble_idx) { @@ -197,7 +197,7 @@ void ue_sim::update_conn_state(const sf_output_res_t& sf_out) srslte::tti_point expected_msg3_tti_rx = ctxt.rar_tti_rx + MSG3_DELAY_MS; if (expected_msg3_tti_rx == sf_out.tti_rx) { // Msg3 should exist - for (uint32_t i = 0; i < ul_cc_result.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_cc_result.pusch.size(); ++i) { if (ul_cc_result.pusch[i].dci.rnti == ctxt.rnti) { ctxt.msg3_tti_rx = sf_out.tti_rx; } @@ -207,7 +207,7 @@ void ue_sim::update_conn_state(const sf_output_res_t& sf_out) if (ctxt.msg3_tti_rx.is_valid() and not ctxt.msg4_tti_rx.is_valid()) { // Msg3 scheduled, but Msg4 not yet scheduled - for (uint32_t i = 0; i < dl_cc_result.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_result.data.size(); ++i) { if (dl_cc_result.data[i].dci.rnti == ctxt.rnti) { for (uint32_t j = 0; j < dl_cc_result.data[i].nof_pdu_elems[0]; ++j) { if (dl_cc_result.data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) { @@ -220,10 +220,21 @@ void ue_sim::update_conn_state(const sf_output_res_t& sf_out) } } +sched_sim_base::sched_sim_base(sched_interface* sched_ptr_, + const sched_interface::sched_args_t& sched_args, + const std::vector& cell_cfg_list) : + logger(srslog::fetch_basic_logger("TEST")), sched_ptr(sched_ptr_), cell_params(cell_cfg_list.size()) +{ + for (uint32_t cc = 0; cc < cell_params.size(); ++cc) { + cell_params[cc].set_cfg(cc, cell_cfg_list[cc], sched_args); + } + sched_ptr->cell_cfg(cell_cfg_list); // call parent cfg +} + int sched_sim_base::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, uint32_t preamble_idx) { CONDERROR(!srslte_prach_tti_opportunity_config_fdd( - (*cell_params)[ue_cfg_.supported_cc_list[0].enb_cc_idx].prach_config, current_tti_rx.to_uint(), -1), + cell_params[ue_cfg_.supported_cc_list[0].enb_cc_idx].cfg.prach_config, current_tti_rx.to_uint(), -1), "New user added in a non-PRACH TTI"); TESTASSERT(ue_db.count(rnti) == 0); @@ -287,7 +298,7 @@ sim_enb_ctxt_t sched_sim_base::get_enb_ctxt() const int sched_sim_base::set_default_tti_events(const sim_ue_ctxt_t& ue_ctxt, ue_tti_events& pending_events) { pending_events.cc_list.clear(); - pending_events.cc_list.resize(cell_params->size()); + pending_events.cc_list.resize(cell_params.size()); pending_events.tti_rx = current_tti_rx; for (uint32_t enb_cc_idx = 0; enb_cc_idx < pending_events.cc_list.size(); ++enb_cc_idx) { @@ -380,8 +391,8 @@ int sched_sim_base::apply_tti_events(sim_ue_ctxt_t& ue_ctxt, const ue_tti_events sched_ptr->dl_cqi_info(events.tti_rx.to_uint(), ue_ctxt.rnti, enb_cc_idx, cc_feedback.dl_cqi); } - if (cc_feedback.ul_cqi >= 0) { - sched_ptr->ul_snr_info(events.tti_rx.to_uint(), ue_ctxt.rnti, enb_cc_idx, cc_feedback.ul_cqi, 0); + if (cc_feedback.ul_snr >= 0) { + sched_ptr->ul_snr_info(events.tti_rx.to_uint(), ue_ctxt.rnti, enb_cc_idx, cc_feedback.ul_snr, 0); } } diff --git a/srsenb/test/mac/sched_sim_ue.h b/srsenb/test/mac/sched_sim_ue.h index 46562d39a..e1ffc832d 100644 --- a/srsenb/test/mac/sched_sim_ue.h +++ b/srsenb/test/mac/sched_sim_ue.h @@ -61,8 +61,8 @@ struct sim_ue_ctxt_t { }; struct sim_enb_ctxt_t { - const std::vector* cell_params; - std::map ue_db; + srslte::span cell_params; + std::map ue_db; }; struct ue_tti_events { struct cc_data { @@ -74,7 +74,7 @@ struct ue_tti_events { int ul_pid = -1; bool ul_ack = false; int dl_cqi = -1; - int ul_cqi = -1; + int ul_snr = -1; }; srslte::tti_point tti_rx; std::vector cc_list; @@ -108,11 +108,9 @@ private: class sched_sim_base { public: - sched_sim_base(sched_interface* sched_ptr_, const std::vector& cell_params_) : - logger(srslog::fetch_basic_logger("MAC")), sched_ptr(sched_ptr_), cell_params(&cell_params_) - { - sched_ptr->cell_cfg(cell_params_); // call parent cfg - } + sched_sim_base(sched_interface* sched_ptr_, + const sched_interface::sched_args_t& sched_args, + const std::vector& cell_params_); virtual ~sched_sim_base() = default; int add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, uint32_t preamble_idx); @@ -142,6 +140,9 @@ public: const ue_sim* ret = find_rnti(rnti); return ret == nullptr ? nullptr : &ret->get_ctxt().ue_cfg; } + sched_interface* get_sched() { return sched_ptr; } + srslte::const_span get_cell_params() { return cell_params; } + tti_point get_tti_rx() const { return current_tti_rx; } std::map::iterator begin() { return ue_db.begin(); } std::map::iterator end() { return ue_db.end(); } @@ -153,9 +154,9 @@ private: int set_default_tti_events(const sim_ue_ctxt_t& ue_ctxt, ue_tti_events& pending_events); int apply_tti_events(sim_ue_ctxt_t& ue_ctxt, const ue_tti_events& events); - srslog::basic_logger& logger; - sched_interface* sched_ptr; - const std::vector* cell_params; + srslog::basic_logger& logger; + sched_interface* sched_ptr; + std::vector cell_params; srslte::tti_point current_tti_rx; std::map ue_db; diff --git a/srsenb/test/mac/sched_test_common.cc b/srsenb/test/mac/sched_test_common.cc index 715401e52..36076434c 100644 --- a/srsenb/test/mac/sched_test_common.cc +++ b/srsenb/test/mac/sched_test_common.cc @@ -83,8 +83,8 @@ void sched_sim_random::set_external_tti_events(const sim_ue_ctxt_t& ue_ctxt, ue_ } // UL CQI - if (cc_feedback.ul_cqi >= 0) { - cc_feedback.ul_cqi = std::uniform_int_distribution{5, 40}(get_rand_gen()); + if (cc_feedback.ul_snr >= 0) { + cc_feedback.ul_snr = std::uniform_int_distribution{5, 40}(get_rand_gen()); } } } @@ -98,12 +98,12 @@ void sched_result_stats::process_results(tti_point const std::vector& ul_result) { for (uint32_t ccidx = 0; ccidx < dl_result.size(); ++ccidx) { - for (uint32_t i = 0; i < dl_result[ccidx].nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_result[ccidx].data.size(); ++i) { user_stats* user = get_user(dl_result[ccidx].data[i].dci.rnti); user->tot_dl_sched_data[ccidx] += dl_result[ccidx].data[i].tbs[0]; user->tot_dl_sched_data[ccidx] += dl_result[ccidx].data[i].tbs[1]; } - for (uint32_t i = 0; i < ul_result[ccidx].nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_result[ccidx].pusch.size(); ++i) { user_stats* user = get_user(ul_result[ccidx].pusch[i].dci.rnti); user->tot_ul_sched_data[ccidx] += ul_result[ccidx].pusch[i].tbs; } @@ -125,6 +125,10 @@ sched_result_stats::user_stats* sched_result_stats::get_user(uint16_t rnti) * Common Sched Tester **********************/ +common_sched_tester::common_sched_tester() : logger(srslog::fetch_basic_logger("TEST")) {} + +common_sched_tester::~common_sched_tester() {} + const sched::ue_cfg_t* common_sched_tester::get_current_ue_cfg(uint16_t rnti) const { return sched_sim->get_user_cfg(rnti); @@ -134,9 +138,9 @@ int common_sched_tester::sim_cfg(sim_sched_args args) { sim_args0 = std::move(args); - sched::init(nullptr, sim_args0.sched_args); + sched::init(&rrc_ptr, sim_args0.sched_args); - sched_sim.reset(new sched_sim_random{this, sim_args0.cell_cfg}); + sched_sim.reset(new sched_sim_random{this, sim_args0.sched_args, sim_args0.cell_cfg}); sched_stats.reset(new sched_result_stats{sim_args0.cell_cfg}); return SRSLTE_SUCCESS; diff --git a/srsenb/test/mac/sched_test_common.h b/srsenb/test/mac/sched_test_common.h index 85a083f6d..09d2cfc22 100644 --- a/srsenb/test/mac/sched_test_common.h +++ b/srsenb/test/mac/sched_test_common.h @@ -25,6 +25,7 @@ #include "sched_sim_ue.h" #include "sched_test_utils.h" #include "srsenb/hdr/stack/mac/sched.h" +#include "srslte/interfaces/enb_rrc_interfaces.h" #include "srslte/srslog/srslog.h" #include @@ -38,6 +39,15 @@ void set_randseed(uint64_t seed); float randf(); std::default_random_engine& get_rand_gen(); +struct rrc_dummy : public rrc_interface_mac { +public: + int add_user(uint16_t rnti, const sched_interface::ue_cfg_t& init_ue_cfg) { return SRSLTE_SUCCESS; } + void upd_user(uint16_t new_rnti, uint16_t old_rnti) {} + void set_activity_user(uint16_t rnti) {} + bool is_paging_opportunity(uint32_t tti, uint32_t* payload_len) { return false; } + uint8_t* read_pdu_bcch_dlsch(const uint8_t enb_cc_idx, const uint32_t sib_index) { return nullptr; } +}; + /************************** * Testers *************************/ @@ -88,8 +98,8 @@ public: std::vector ul_sched_result; }; - common_sched_tester() : logger(srslog::fetch_basic_logger("TEST")) {} - ~common_sched_tester() override = default; + common_sched_tester(); + ~common_sched_tester() override; const ue_cfg_t* get_current_ue_cfg(uint16_t rnti) const; @@ -123,6 +133,8 @@ public: protected: virtual void new_test_tti(); virtual void before_sched() {} + + rrc_dummy rrc_ptr; }; } // namespace srsenb diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 62a8cf5ec..94c7533a0 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -148,7 +148,6 @@ int sched_tester::process_results() { const srsenb::cc_sched_result* cc_result = sched_results.get_cc(tti_rx, CARRIER_IDX); srsenb::sf_output_res_t sf_out{sched_cell_params, tti_rx, tti_info.ul_sched_result, tti_info.dl_sched_result}; - TESTASSERT(tti_rx == cc_result->tti_rx); // Common tests TESTASSERT(test_pdcch_collisions(sf_out, CARRIER_IDX, &cc_result->pdcch_mask) == SRSLTE_SUCCESS); @@ -168,7 +167,7 @@ int sched_tester::process_results() int sched_tester::test_harqs() { /* check consistency of DL harq procedures and allocations */ - for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].nof_data_elems; ++i) { + for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].data.size(); ++i) { const auto& data = tti_info.dl_sched_result[CARRIER_IDX].data[i]; uint32_t h_id = data.dci.pid; uint16_t rnti = data.dci.rnti; @@ -181,7 +180,7 @@ int sched_tester::test_harqs() } /* Check PHICH allocations */ - for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_phich_elems; ++i) { + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].phich.size(); ++i) { const auto& phich = tti_info.ul_sched_result[CARRIER_IDX].phich[i]; const auto& hprev = tti_data.ue_data[phich.rnti].ul_harq; const auto* h = ue_db[phich.rnti]->get_ul_harq(srsenb::to_tx_ul(tti_rx), CARRIER_IDX); @@ -192,7 +191,7 @@ int sched_tester::test_harqs() if (not hprev.is_empty()) { // In case it was resumed CONDERROR(h == nullptr or h->is_empty(), "Cannot resume empty UL harq"); - for (uint32_t j = 0; j < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++j) { + for (uint32_t j = 0; j < tti_info.ul_sched_result[CARRIER_IDX].pusch.size(); ++j) { auto& pusch = tti_info.ul_sched_result[CARRIER_IDX].pusch[j]; CONDERROR(pusch.dci.rnti == phich.rnti, "Cannot send PHICH::ACK for same harq that got UL grant."); } @@ -208,7 +207,7 @@ int sched_tester::test_harqs() int sched_tester::update_ue_stats() { // update ue stats with number of allocated UL PRBs - for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++i) { + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].pusch.size(); ++i) { const auto& pusch = tti_info.ul_sched_result[CARRIER_IDX].pusch[i]; uint32_t L, RBstart; srslte_ra_type2_from_riv(pusch.dci.type2_alloc.riv, @@ -224,7 +223,7 @@ int sched_tester::update_ue_stats() // update ue stats with number of DL RB allocations srslte::bounded_bitset<100, true> alloc_mask(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].nof_data_elems; ++i) { + for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].data.size(); ++i) { auto& data = tti_info.dl_sched_result[CARRIER_IDX].data[i]; TESTASSERT(srsenb::extract_dl_prbmask(sched_cell_params[CARRIER_IDX].cfg.cell, tti_info.dl_sched_result[CARRIER_IDX].data[i].dci, diff --git a/srsenb/test/mac/sched_test_utils.h b/srsenb/test/mac/sched_test_utils.h index fc4de650c..8541948fd 100644 --- a/srsenb/test/mac/sched_test_utils.h +++ b/srsenb/test/mac/sched_test_utils.h @@ -58,9 +58,9 @@ inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t no cell_cfg.maxharq_msg3tx = 3; cell_cfg.initial_dl_cqi = 6; cell_cfg.target_ul_sinr = -1; - cell_cfg.nrb_cqi = 2; + cell_cfg.nrb_cqi = 1; cell_cfg.n1pucch_an = 12; - cell_cfg.delta_pucch_shift = 2; + cell_cfg.delta_pucch_shift = 1; cell_cfg.ncs_an = 0; return cell_cfg; diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index cd8fdbc52..83779f35d 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -52,18 +52,16 @@ int sim_ue_ctxt_t::enb_to_ue_cc_idx(uint32_t enb_cc_idx) const const pusch_t* find_pusch_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res) { - const pusch_t* ptr = std::find_if(&ul_cc_res.pusch[0], - &ul_cc_res.pusch[ul_cc_res.nof_dci_elems], - [rnti](const pusch_t& pusch) { return pusch.dci.rnti == rnti; }); - return ptr == &ul_cc_res.pusch[ul_cc_res.nof_dci_elems] ? nullptr : ptr; + const pusch_t* ptr = std::find_if( + ul_cc_res.pusch.begin(), ul_cc_res.pusch.end(), [rnti](const pusch_t& pusch) { return pusch.dci.rnti == rnti; }); + return ptr == ul_cc_res.pusch.end() ? nullptr : ptr; } const pdsch_t* find_pdsch_grant(uint16_t rnti, const sched_interface::dl_sched_res_t& dl_cc_res) { - const pdsch_t* ptr = std::find_if(&dl_cc_res.data[0], - &dl_cc_res.data[dl_cc_res.nof_data_elems], - [rnti](const pdsch_t& pdsch) { return pdsch.dci.rnti == rnti; }); - return ptr == &dl_cc_res.data[dl_cc_res.nof_data_elems] ? nullptr : ptr; + const pdsch_t* ptr = std::find_if( + dl_cc_res.data.begin(), dl_cc_res.data.end(), [rnti](const pdsch_t& pdsch) { return pdsch.dci.rnti == rnti; }); + return ptr == dl_cc_res.data.end() ? nullptr : ptr; } int test_pdsch_grant(const sim_enb_ctxt_t& enb_ctxt, @@ -74,7 +72,7 @@ int test_pdsch_grant(const sim_enb_ctxt_t& enb_ctxt, tti_point tti_rx = sf_out.tti_rx; const sim_ue_ctxt_t& ue_ctxt = *enb_ctxt.ue_db.at(pdsch.dci.rnti); const sched_interface::ue_cfg_t::cc_cfg_t* cc_cfg = ue_ctxt.get_cc_cfg(enb_cc_idx); - const sched_interface::cell_cfg_t& cell_params = (*enb_ctxt.cell_params)[enb_cc_idx]; + const sched_cell_params_t& cell_params = enb_ctxt.cell_params[enb_cc_idx]; bool has_pusch_grant = find_pusch_grant(pdsch.dci.rnti, sf_out.ul_cc_result[enb_cc_idx]) != nullptr; // TEST: Check if CC is configured and active @@ -87,7 +85,7 @@ int test_pdsch_grant(const sim_enb_ctxt_t& enb_ctxt, uint32_t nof_retx = get_nof_retx(pdsch.dci.tb[0].rv); // 0..3 if (h.nof_txs == 0 or h.ndi != pdsch.dci.tb[0].ndi) { // It is newtx - CONDERROR(nof_retx != 0, "Invalid rv index for new tx"); + CONDERROR(nof_retx != 0, "Invalid rv index for new DL tx"); CONDERROR(h.active, "DL newtx for already active DL harq pid=%d", h.pid); } else { // it is retx @@ -109,19 +107,19 @@ int test_pdsch_grant(const sim_enb_ctxt_t& enb_ctxt, srslte_dl_sf_cfg_t dl_sf = {}; dl_sf.cfi = sf_out.dl_cc_result[enb_cc_idx].cfi; dl_sf.tti = to_tx_dl(tti_rx).to_uint(); - srslte_ra_dl_grant_to_grant_prb_allocation(&pdsch.dci, &grant, cell_params.cell.nof_prb); - uint32_t nof_re = srslte_ra_dl_grant_nof_re(&cell_params.cell, &dl_sf, &grant); + srslte_ra_dl_grant_to_grant_prb_allocation(&pdsch.dci, &grant, cell_params.nof_prb()); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&cell_params.cfg.cell, &dl_sf, &grant); float coderate = srslte_coderate(pdsch.tbs[0] * 8, nof_re); srslte_mod_t mod = srslte_ra_dl_mod_from_mcs(pdsch.dci.tb[0].mcs_idx, ue_ctxt.ue_cfg.use_tbs_index_alt); uint32_t max_Qm = ue_ctxt.ue_cfg.use_tbs_index_alt ? 8 : 6; uint32_t Qm = std::min(max_Qm, srslte_mod_bits_x_symbol(mod)); - CONDERROR(coderate > 0.930f * Qm, "Max coderate was exceeded"); + CONDERROR(coderate > 0.932f * Qm, "Max coderate was exceeded"); } // TEST: PUCCH-ACK will not collide with SR CONDERROR(not has_pusch_grant and is_pucch_sr_collision(ue_ctxt.ue_cfg.pucch_cfg, to_tx_dl_ack(sf_out.tti_rx), - pdsch.dci.location.ncce + cell_params.n1pucch_an), + pdsch.dci.location.ncce + cell_params.cfg.n1pucch_an), "Collision detected between UE PUCCH-ACK and SR"); return SRSLTE_SUCCESS; @@ -129,8 +127,8 @@ int test_pdsch_grant(const sim_enb_ctxt_t& enb_ctxt, int test_dl_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { - for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { - for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) { + for (uint32_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { + for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].data.size(); ++i) { const sched_interface::dl_sched_data_t& data = sf_out.dl_cc_result[cc].data[i]; CONDERROR( enb_ctxt.ue_db.count(data.dci.rnti) == 0, "Allocated DL grant for non-existent rnti=0x%x", data.dci.rnti); @@ -144,11 +142,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& { uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); - for (size_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { - const auto* phich_begin = &sf_out.ul_cc_result[cc].phich[0]; - const auto* phich_end = &sf_out.ul_cc_result[cc].phich[sf_out.ul_cc_result[cc].nof_phich_elems]; - const auto* pusch_begin = &sf_out.ul_cc_result[cc].pusch[0]; - const auto* pusch_end = &sf_out.ul_cc_result[cc].pusch[sf_out.ul_cc_result[cc].nof_dci_elems]; + for (size_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { + const auto* phich_begin = sf_out.ul_cc_result[cc].phich.begin(); + const auto* phich_end = sf_out.ul_cc_result[cc].phich.end(); + const auto* pusch_begin = sf_out.ul_cc_result[cc].pusch.begin(); + const auto* pusch_end = sf_out.ul_cc_result[cc].pusch.end(); // TEST: rnti must exist for all PHICH CONDERROR(std::any_of(phich_begin, @@ -205,7 +203,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& if (h.nof_txs == 0 or h.ndi != pusch_ptr->dci.tb.ndi) { // newtx - CONDERROR(nof_retx != 0, "Invalid rv index for new tx"); + CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx"); CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted"); CONDERROR(not h_inactive, "New tx for already active UL HARQ"); CONDERROR(not pusch_ptr->needs_pdcch and ue.msg3_tti_rx.is_valid() and sf_out.tti_rx > ue.msg3_tti_rx, @@ -237,7 +235,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { - for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { + for (uint32_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { const auto& dl_cc_res = sf_out.dl_cc_result[cc]; const auto& ul_cc_res = sf_out.ul_cc_result[cc]; for (const auto& ue_pair : enb_ctxt.ue_db) { @@ -251,7 +249,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) } // TEST: RAR allocation - uint32_t rar_win_size = (*enb_ctxt.cell_params)[cc].prach_rar_window; + uint32_t rar_win_size = enb_ctxt.cell_params[cc].cfg.prach_rar_window; srslte::tti_interval rar_window{ue.prach_tti_rx + 3, ue.prach_tti_rx + 3 + rar_win_size}; srslte::tti_point tti_tx_dl = to_tx_dl(sf_out.tti_rx); @@ -259,14 +257,14 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) CONDERROR(not ue.rar_tti_rx.is_valid() and tti_tx_dl > rar_window.stop(), "rnti=0x%x RAR not scheduled within the RAR Window", rnti); - for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_rar_elems; ++i) { + for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].rar.size(); ++i) { CONDERROR(sf_out.dl_cc_result[cc].rar[i].dci.rnti == rnti, "No RAR allocations allowed outside of user RAR window"); } } else { // Inside RAR window uint32_t nof_rars = ue.rar_tti_rx.is_valid() ? 1 : 0; - for (uint32_t i = 0; i < dl_cc_res.nof_rar_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_res.rar.size(); ++i) { for (const auto& grant : dl_cc_res.rar[i].msg3_grant) { const auto& data = grant.data; if (data.prach_tti == (uint32_t)ue.prach_tti_rx.to_uint() and data.preamble_idx == ue.preamble_idx) { @@ -287,7 +285,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) if (expected_msg3_tti_rx == sf_out.tti_rx) { // Msg3 should exist uint32_t msg3_count = 0; - for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_cc_res.pusch.size(); ++i) { if (ul_cc_res.pusch[i].dci.rnti == rnti) { msg3_count++; CONDERROR(ul_cc_res.pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH"); @@ -304,7 +302,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) if (ue.msg3_tti_rx.is_valid() and not ue.msg4_tti_rx.is_valid()) { // Msg3 scheduled, but Msg4 not yet scheduled uint32_t msg4_count = 0; - for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_res.data.size(); ++i) { if (dl_cc_res.data[i].dci.rnti == rnti) { CONDERROR(to_tx_dl(sf_out.tti_rx) < to_tx_ul(ue.msg3_tti_rx), "Msg4 cannot be scheduled without Msg3 being tx"); @@ -325,7 +323,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) if (not ue.msg4_tti_rx.is_valid()) { // TEST: No UL allocs except for Msg3 before Msg4 - for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < ul_cc_res.pusch.size(); ++i) { if (ul_cc_res.pusch[i].dci.rnti == rnti) { CONDERROR(not ue.rar_tti_rx.is_valid(), "No UL allocs before RAR allowed"); srslte::tti_point expected_msg3_tti = ue.rar_tti_rx + MSG3_DELAY_MS; @@ -340,7 +338,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) // TEST: No DL allocs before Msg3 if (not ue.msg3_tti_rx.is_valid()) { - for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_res.data.size(); ++i) { CONDERROR(dl_cc_res.data[i].dci.rnti == rnti, "No DL data allocs allowed before Msg3 is scheduled"); } } @@ -348,7 +346,7 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) } // TEST: Ensure there are no spurious RARs that do not belong to any user - for (uint32_t i = 0; i < dl_cc_res.nof_rar_elems; ++i) { + for (uint32_t i = 0; i < dl_cc_res.rar.size(); ++i) { for (uint32_t j = 0; j < dl_cc_res.rar[i].msg3_grant.size(); ++j) { uint32_t prach_tti = dl_cc_res.rar[i].msg3_grant[j].data.prach_tti; uint32_t preamble_idx = dl_cc_res.rar[i].msg3_grant[j].data.preamble_idx; @@ -374,7 +372,7 @@ bool is_in_measgap(srslte::tti_point tti, uint32_t period, uint32_t offset) int test_meas_gaps(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { - for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { + for (uint32_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { const auto& dl_cc_res = sf_out.dl_cc_result[cc]; const auto& ul_cc_res = sf_out.ul_cc_result[cc]; for (const auto& ue_pair : enb_ctxt.ue_db) { diff --git a/srsenb/test/upper/gtpu_test.cc b/srsenb/test/upper/gtpu_test.cc index cd46616b1..70b55b3f0 100644 --- a/srsenb/test/upper/gtpu_test.cc +++ b/srsenb/test/upper/gtpu_test.cc @@ -157,9 +157,10 @@ int test_gtpu_direct_tunneling() logger1.set_hex_dump_max_size(2048); srslog::basic_logger& logger2 = srslog::fetch_basic_logger("GTPU2"); logger2.set_hex_dump_max_size(2048); - srsenb::gtpu senb_gtpu(logger1), tenb_gtpu(logger2); - stack_tester senb_stack, tenb_stack; - pdcp_tester senb_pdcp, tenb_pdcp; + srslte::task_scheduler task_sched; + srsenb::gtpu senb_gtpu(&task_sched, logger1), tenb_gtpu(&task_sched, logger2); + stack_tester senb_stack, tenb_stack; + pdcp_tester senb_pdcp, tenb_pdcp; senb_gtpu.init(senb_addr_str, sgw_addr_str, "", "", &senb_pdcp, &senb_stack, false); tenb_gtpu.init(tenb_addr_str, sgw_addr_str, "", "", &tenb_pdcp, &tenb_stack, false); diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h index 8f6f441ee..5731d7309 100644 --- a/srsue/hdr/metrics_stdout.h +++ b/srsue/hdr/metrics_stdout.h @@ -47,6 +47,8 @@ public: void stop(){}; private: + static const bool FORCE_NEIGHBOUR_CELL = false; // Set to true for printing always neighbour cells + std::string float_to_string(float f, int digits); std::string float_to_eng_string(float f, int digits); void print_table(const bool display_neighbours); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 2416b93e9..6b69debfc 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -149,8 +149,8 @@ public: int sr_last_tx_tti() final; // Time advance commands - void set_timeadv_rar(uint32_t ta_cmd) final; - void set_timeadv(uint32_t ta_cmd) final; + void set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) final; + void set_timeadv(uint32_t tti, uint32_t ta_cmd) final; /* Activate / Disactivate SCell*/ void deactivate_scells() final; diff --git a/srsue/hdr/phy/phy_metrics.h b/srsue/hdr/phy/phy_metrics.h index c09d3ab76..4651e0f57 100644 --- a/srsue/hdr/phy/phy_metrics.h +++ b/srsue/hdr/phy/phy_metrics.h @@ -33,6 +33,8 @@ struct info_metrics_t { struct sync_metrics_t { float ta_us; + float distance_km; + float speed_kmph; float cfo; float sfo; }; diff --git a/srsue/hdr/phy/ta_control.h b/srsue/hdr/phy/ta_control.h index 1fd81ecdc..3fd064fcf 100644 --- a/srsue/hdr/phy/ta_control.h +++ b/srsue/hdr/phy/ta_control.h @@ -31,11 +31,34 @@ namespace srsue { class ta_control { private: + static const size_t MAX_NOF_SPEED_VALUES = 50; ///< Maximum number of data to store for speed calculation + static const size_t MIN_NOF_SPEED_VALUES = 1; ///< Minimum number of data for calculating the speed + static const size_t MAX_AGE_SPEED_VALUES = 10000; ///< Maximum age of speed data in milliseconds. Discards older data. + srslog::basic_logger& logger; mutable std::mutex mutex; uint32_t next_base_nta = 0; float next_base_sec = 0.0f; + // Vector containing data for calculating speed. The first value is the time increment from TTI and the second value + // is the distance increment from the TA command + struct speed_data_t { + uint32_t tti; + float delta_t; + float delta_d; + }; + std::array speed_data = {}; + int32_t last_tti = -1; // Last TTI writen, -1 if none + uint32_t write_idx = 0; + uint32_t read_idx = 0; + + void reset_speed_data() + { + write_idx = 0; + read_idx = 0; + last_tti = -1; + } + public: ta_control(srslog::basic_logger& logger) : logger(logger) {} @@ -54,6 +77,9 @@ public: // Update base in nta next_base_nta = static_cast(roundf(next_base_sec / SRSLTE_LTE_TS)); + // Reset speed data + reset_speed_data(); + logger.info("PHY: Set TA base: n_ta: %d, ta_usec: %.1f", next_base_nta, next_base_sec * 1e6f); } @@ -83,7 +109,7 @@ public: * * @param ta_cmd Time Alignment command */ - void add_ta_cmd_rar(uint32_t ta_cmd) + void add_ta_cmd_rar(uint32_t tti, uint32_t ta_cmd) { std::lock_guard lock(mutex); @@ -93,6 +119,10 @@ public: // Update base in seconds next_base_sec = static_cast(next_base_nta) * SRSLTE_LTE_TS; + // Reset speed data + reset_speed_data(); + last_tti = tti; + logger.info("PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f", ta_cmd, next_base_nta, next_base_sec * 1e6f); } @@ -101,9 +131,10 @@ public: * * @param ta_cmd Time Alignment command */ - void add_ta_cmd_new(uint32_t ta_cmd) + void add_ta_cmd_new(uint32_t tti, uint32_t ta_cmd) { std::lock_guard lock(mutex); + float prev_base_sec = next_base_sec; // Update base nta next_base_nta = srslte_N_ta_new(next_base_nta, ta_cmd); @@ -112,6 +143,26 @@ public: next_base_sec = static_cast(next_base_nta) * SRSLTE_LTE_TS; logger.info("PHY: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f", ta_cmd, next_base_nta, next_base_sec * 1e6f); + + // Calculate speed data + if (last_tti > 0) { + float delta_t = TTI_SUB(tti, last_tti) * 1e-3f; // Calculate the elapsed time since last time command + float delta_d = (next_base_sec - prev_base_sec) * 3e8f / 2.0f; // Calculate distance difference in metres + + // Write new data + speed_data[write_idx].tti = tti; + speed_data[write_idx].delta_t = delta_t; + speed_data[write_idx].delta_d = delta_d; + + // Advance write index + write_idx = (write_idx + 1) % MAX_NOF_SPEED_VALUES; + + // Advance read index if overlaps with write + if (write_idx == read_idx) { + read_idx = (read_idx + 1) % MAX_NOF_SPEED_VALUES; + } + } + last_tti = tti; // Update last TTI } /** @@ -150,7 +201,48 @@ public: std::lock_guard lock(mutex); // Returns the current base, one direction distance - return next_base_sec * (3.6f * 3e8f / 2.0f); + return next_base_sec * (3e8f / 2e3f); + } + + /** + * Calculates approximated speed in km/h from the TA commands + * + * @return Distance based on the current time base if enough data has been gathered + */ + float get_speed_kmph(uint32_t tti) + { + std::lock_guard lock(mutex); + + // Advance read pointer for old TTI + while (read_idx != write_idx and TTI_SUB(tti, speed_data[read_idx].tti) > MAX_AGE_SPEED_VALUES) { + read_idx = (read_idx + 1) % MAX_NOF_SPEED_VALUES; + + // If there us no data, make last_tti invalid to prevent invalid TTI difference + if (read_idx == write_idx) { + last_tti = -1; + } + } + + // Early return if there is not enough data to calculate speed + uint32_t nof_values = ((write_idx + MAX_NOF_SPEED_VALUES) - read_idx) % MAX_NOF_SPEED_VALUES; + if (nof_values < MIN_NOF_SPEED_VALUES) { + return 0.0f; + } + + // Compute speed from gathered data + float sum_t = 0.0f; + float sum_d = 0.0f; + for (uint32_t i = read_idx; i != write_idx; i = (i + 1) % MAX_NOF_SPEED_VALUES) { + sum_t += speed_data[i].delta_t; + sum_d += speed_data[i].delta_d; + } + if (!std::isnormal(sum_t)) { + return 0.0f; // Avoid zero division + } + float speed_mps = sum_d / sum_t; // Speed in m/s + + // Returns the speed in km/h + return speed_mps * 3.6f; } }; diff --git a/srsue/hdr/stack/mac/demux.h b/srsue/hdr/stack/mac/demux.h index 74d49825d..d75bb8d2b 100644 --- a/srsue/hdr/stack/mac/demux.h +++ b/srsue/hdr/stack/mac/demux.h @@ -87,7 +87,7 @@ private: void process_sch_pdu(srslte::sch_pdu* pdu); void process_mch_pdu(srslte::mch_pdu* pdu); bool process_ce(srslte::sch_subh* subheader, uint32_t tti); - void parse_ta_cmd(srslte::sch_subh* subh); + void parse_ta_cmd(srslte::sch_subh* subh, uint32_t tti); bool is_uecrid_successful = false; diff --git a/srsue/hdr/stack/mac/proc_ra.h b/srsue/hdr/stack/mac/proc_ra.h index bb03e1aa7..13731470a 100644 --- a/srsue/hdr/stack/mac/proc_ra.h +++ b/srsue/hdr/stack/mac/proc_ra.h @@ -79,7 +79,7 @@ private: void state_backoff_wait(uint32_t tti); void state_contention_resolution(); - void process_timeadv_cmd(uint32_t ta_cmd); + void process_timeadv_cmd(uint32_t tti, uint32_t ta_cmd); void initialization(); void resource_selection(); void preamble_transmission(); diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc index 4504d5927..1cada6420 100644 --- a/srsue/src/metrics_csv.cc +++ b/srsue/src/metrics_csv.cc @@ -83,7 +83,7 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period if (file.is_open() && ue != NULL) { if (n_reports == 0 && !file_exists) { file << "time;cc;earfcn;pci;rsrp;pl;cfo;pci_neigh;rsrp_neigh;cfo_neigh;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;" - "ul_ta;ul_mcs;ul_buff;ul_brate;ul_" + "ul_ta;distance_km;speed_kmph;ul_mcs;ul_buff;ul_brate;ul_" "bler;" "rf_o;rf_" "u;rf_l;is_attached;" @@ -139,6 +139,8 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period } file << float_to_string(metrics.phy.sync[r].ta_us, 2); + file << float_to_string(metrics.phy.sync[r].distance_km, 2); + file << float_to_string(metrics.phy.sync[r].speed_kmph, 2); file << float_to_string(metrics.phy.ul[r].mcs, 2); file << float_to_string((float)metrics.stack.mac[r].ul_buffer, 2); @@ -163,11 +165,11 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period file << (metrics.stack.rrc.state == RRC_STATE_CONNECTED ? "1.0" : "0.0") << ";"; // Write system metrics. - const srslte::sys_metrics_t &m = metrics.sys; + const srslte::sys_metrics_t& m = metrics.sys; file << float_to_string(m.process_realmem, 2); file << std::to_string(m.process_realmem_kB) << ";"; file << float_to_string(m.process_virtualmem, 2); - file << std::to_string(m.process_virtualmem_kB) << ";" ; + file << std::to_string(m.process_virtualmem_kB) << ";"; file << float_to_string(m.system_mem, 2); file << float_to_string(m.process_cpu_usage, 2); file << std::to_string(m.thread_count); diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index cd57d43c7..d2dec8d25 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -105,11 +105,11 @@ void metrics_stdout::set_metrics(const ue_metrics_t& metrics, const uint32_t per return; } - bool display_neighbours = false; + bool display_neighbours = FORCE_NEIGHBOUR_CELL; if (metrics.phy.nof_active_cc > 1) { - display_neighbours = metrics.stack.rrc.neighbour_cells.size() > metrics.phy.nof_active_cc - 1; + display_neighbours |= metrics.stack.rrc.neighbour_cells.size() > metrics.phy.nof_active_cc - 1; } else { - display_neighbours = metrics.stack.rrc.neighbour_cells.size() > 0; + display_neighbours |= metrics.stack.rrc.neighbour_cells.size() > 0; } // print table header every 10 reports diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index f04a0bebc..5a6626036 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -154,6 +154,21 @@ void cc_worker::decode_pdcch_dl() // Enqueue UL grants phy->set_dl_pending_grant(dl_slot_cfg.idx, dci_rx[i]); } + + if (logger.debug.enabled()) { + for (uint32_t i = 0; i < ue_dl.pdcch_info_count; i++) { + const srslte_ue_dl_nr_pdcch_info_t* info = &ue_dl.pdcch_info[i]; + logger.debug("PDCCH: crst_id=%d, ss_id=%d, ncce=%d, al=%d, EPRE=%+.2f, RSRP=%+.2f, corr=%.3f; crc=%s", + info->coreset_id, + info->ss_id, + info->location.ncce, + info->location.L, + info->measure.epre_dBfs, + info->measure.rsrp_dBfs, + info->measure.norm_corr, + info->result.crc ? "OK" : "KO"); + } + } } void cc_worker::decode_pdcch_ul() @@ -190,6 +205,11 @@ void cc_worker::decode_pdcch_ul() bool cc_worker::work_dl() { + // Check if it is a DL slot, if not skip + if (!srslte_tdd_nr_is_dl(&phy->cfg.tdd, 0, dl_slot_cfg.idx)) { + return true; + } + // Run FFT srslte_ue_dl_nr_estimate_fft(&ue_dl, &dl_slot_cfg); @@ -258,6 +278,13 @@ bool cc_worker::work_dl() bool cc_worker::work_ul() { + // Check if it is a UL slot, if not skip + if (!srslte_tdd_nr_is_ul(&phy->cfg.tdd, 0, ul_slot_cfg.idx)) { + // No NR signal shall be transmitted + srslte_vec_cf_zero(tx_buffer[0], ue_ul.ifft.sf_sz); + return true; + } + srslte_uci_data_nr_t uci_data = {}; uint32_t pid = 0; @@ -292,14 +319,18 @@ bool cc_worker::work_ul() mac_ul_grant.rnti = pusch_cfg.grant.rnti; mac_ul_grant.tti = ul_slot_cfg.idx; mac_ul_grant.tbs = pusch_cfg.grant.tb[0].tbs; - phy->stack->new_grant_ul(0, mac_ul_grant, &ul_action); - // Assignning MAC provided values to PUSCH config structs + // Set UCI configuration following procedures + srslte_ra_ul_set_grant_uci_nr(&phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); + + // Assigning MAC provided values to PUSCH config structs pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer; + // Setup data for encoding srslte_pusch_data_nr_t data = {}; data.payload = ul_action.tb.payload->msg; + data.uci = uci_data.value; // Encode PUSCH transmission if (srslte_ue_ul_nr_encode_pusch(&ue_ul, &ul_slot_cfg, &pusch_cfg, &data) < SRSLTE_SUCCESS) { @@ -310,7 +341,7 @@ bool cc_worker::work_ul() // PUSCH Logging if (logger.info.enabled()) { std::array str; - srslte_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, str.data(), str.size()); + srslte_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, &data.uci, str.data(), str.size()); logger.info(ul_action.tb.payload->msg, pusch_cfg.grant.tb[0].tbs / 8, "PUSCH (NR): cc=%d, %s, tti_tx=%d", diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index f066f3c48..dae242152 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -213,14 +213,14 @@ void phy::get_metrics(phy_metrics_t* m) m->nof_active_cc = args.nof_lte_carriers; } -void phy::set_timeadv_rar(uint32_t ta_cmd) +void phy::set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) { - common.ta.add_ta_cmd_rar(ta_cmd); + common.ta.add_ta_cmd_rar(tti, ta_cmd); } -void phy::set_timeadv(uint32_t ta_cmd) +void phy::set_timeadv(uint32_t tti, uint32_t ta_cmd) { - common.ta.add_ta_cmd_new(ta_cmd); + common.ta.add_ta_cmd_new(tti, ta_cmd); } void phy::deactivate_scells() diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 709ff6f42..da015009d 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -874,6 +874,8 @@ void phy_common::set_sync_metrics(const uint32_t& cc_idx, const sync_metrics_t& sync_metrics[cc_idx].cfo = sync_metrics[cc_idx].cfo + (m.cfo - sync_metrics[cc_idx].cfo) / sync_metrics_count[cc_idx]; sync_metrics[cc_idx].sfo = sync_metrics[cc_idx].sfo + (m.sfo - sync_metrics[cc_idx].sfo) / sync_metrics_count[cc_idx]; sync_metrics[cc_idx].ta_us = m.ta_us; + sync_metrics[cc_idx].distance_km = m.distance_km; + sync_metrics[cc_idx].speed_kmph = m.speed_kmph; } void phy_common::get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS]) diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index ed1613024..d51bb0656 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -134,6 +134,10 @@ void sync::stop() q->stop(); } running = false; + + // Reset (stop Rx stream) as soon as possible to avoid base-band Rx buffer overflow + radio_h->reset(); + wait_thread_finish(); } @@ -472,9 +476,11 @@ void sync::run_camping_in_sync_state(lte::sf_worker* lte_worker, Debug("SYNC: Worker %d synchronized", lte_worker->get_id()); - metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); - metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); - metrics.ta_us = worker_com->ta.get_usec(); + metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); + metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); + metrics.ta_us = worker_com->ta.get_usec(); + metrics.distance_km = worker_com->ta.get_km(); + metrics.speed_kmph = worker_com->ta.get_speed_kmph(tti); for (uint32_t i = 0; i < worker_com->args->nof_lte_carriers; i++) { worker_com->set_sync_metrics(i, metrics); } diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index 28beed284..9864f162d 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -105,7 +105,7 @@ void demux::push_pdu_temp_crnti(uint8_t* buff, uint32_t nof_bytes) } break; case srslte::dl_sch_lcid::TA_CMD: - parse_ta_cmd(pending_mac_msg.get()); + parse_ta_cmd(pending_mac_msg.get(), 0); break; default: break; @@ -284,7 +284,7 @@ bool demux::process_ce(srslte::sch_subh* subh, uint32_t tti) // Do nothing break; case srslte::dl_sch_lcid::TA_CMD: - parse_ta_cmd(subh); + parse_ta_cmd(subh, tti); break; case srslte::dl_sch_lcid::SCELL_ACTIVATION: { uint32_t cmd = (uint32_t)subh->get_activation_deactivation_cmd(); @@ -302,9 +302,9 @@ bool demux::process_ce(srslte::sch_subh* subh, uint32_t tti) return true; } -void demux::parse_ta_cmd(srslte::sch_subh* subh) +void demux::parse_ta_cmd(srslte::sch_subh* subh, uint32_t tti) { - phy_h->set_timeadv(subh->get_ta_cmd()); + phy_h->set_timeadv(tti, subh->get_ta_cmd()); Info("Received TA=%d (%d/%d) ", subh->get_ta_cmd(), time_alignment_timer->time_elapsed(), diff --git a/srsue/src/stack/mac/proc_ra.cc b/srsue/src/stack/mac/proc_ra.cc index f6763038c..0c1a3a1a1 100644 --- a/srsue/src/stack/mac/proc_ra.cc +++ b/srsue/src/stack/mac/proc_ra.cc @@ -311,11 +311,11 @@ void ra_proc::preamble_transmission() } // Process Timing Advance Command as defined in Section 5.2 -void ra_proc::process_timeadv_cmd(uint32_t ta) +void ra_proc::process_timeadv_cmd(uint32_t tti, uint32_t ta) { if (preambleIndex == 0) { // Preamble not selected by UE MAC - phy_h->set_timeadv_rar(ta); + phy_h->set_timeadv_rar(tti, ta); // Only if timer is running reset the timer if (time_alignment_timer->is_running()) { time_alignment_timer->run(); @@ -324,7 +324,7 @@ void ra_proc::process_timeadv_cmd(uint32_t ta) } else { // Preamble selected by UE MAC if (!time_alignment_timer->is_running()) { - phy_h->set_timeadv_rar(ta); + phy_h->set_timeadv_rar(tti, ta); time_alignment_timer->run(); logger.debug("Applying RAR TA CMD %d", ta); } else { @@ -386,7 +386,7 @@ void ra_proc::tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti) while (rar_pdu_msg.next()) { if (rar_pdu_msg.get()->has_rapid() && rar_pdu_msg.get()->get_rapid() == sel_preamble) { rar_received = true; - process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd()); + process_timeadv_cmd(tti, rar_pdu_msg.get()->get_ta_cmd()); // TODO: Indicate received target power // phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep); diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc index 36d857e27..9e152fe5f 100644 --- a/srsue/test/mac_test.cc +++ b/srsue/test/mac_test.cc @@ -153,8 +153,8 @@ public: void set_mch_period_stop(uint32_t stop) override{}; // phy_interface_mac_common - void set_timeadv_rar(uint32_t ta_cmd) override { rar_time_adv = ta_cmd; } - void set_timeadv(uint32_t ta_cmd) override{}; + void set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) override { rar_time_adv = ta_cmd; } + void set_timeadv(uint32_t tti, uint32_t ta_cmd) override{}; void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) override { scell_cmd = cmd; }; void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) override { diff --git a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h index 3a46d0a1c..a2e72c4e1 100644 --- a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h +++ b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h @@ -92,8 +92,8 @@ public: int sr_last_tx_tti() override; // phy_interface_mac_common - void set_timeadv_rar(uint32_t ta_cmd) override; - void set_timeadv(uint32_t ta_cmd) override; + void set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) override; + void set_timeadv(uint32_t tti, uint32_t ta_cmd) override; void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) override; uint32_t get_current_tti() override; float get_phr() override; diff --git a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc index 71f203e72..1a7a7309a 100644 --- a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc +++ b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc @@ -225,12 +225,12 @@ int lte_ttcn3_phy::sr_last_tx_tti() // The RAT-agnostic interface for MAC /* Time advance commands */ -void lte_ttcn3_phy::set_timeadv_rar(uint32_t ta_cmd) +void lte_ttcn3_phy::set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) { logger.debug("%s not implemented.", __FUNCTION__); } -void lte_ttcn3_phy::set_timeadv(uint32_t ta_cmd) +void lte_ttcn3_phy::set_timeadv(uint32_t tti, uint32_t ta_cmd) { logger.debug("%s not implemented.", __FUNCTION__); }