diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 516c94cb46..a8f997c826 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -676,6 +676,14 @@ uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t nrarfcn) return frequency; } +/** + * @brief Get the slot index within the period + */ +int get_slot_idx_in_period(const int slot, const frame_structure_t *fs) +{ + return slot % fs->numb_slots_period; +} + int get_first_ul_slot(int nrofDownlinkSlots, int nrofDownlinkSymbols, int nrofUplinkSymbols) { return (nrofDownlinkSlots + (nrofDownlinkSymbols != 0 && nrofUplinkSymbols == 0)); diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fece81ed62..03838b52fd 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -279,6 +279,8 @@ int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_ unsigned short get_m_srs(int c_srs, int b_srs); unsigned short get_N_b_srs(int c_srs, int b_srs); +int get_slot_idx_in_period(const int slot, const frame_structure_t *fs); + #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 4927f407d0..e4001ebe5f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -283,6 +283,206 @@ nfapi_nr_pm_list_t init_DL_MIMO_codebook(gNB_MAC_INST *gNB, nr_pdsch_AntennaPort return mat; } +/** + * @brief Configures the TDD period, including bitmap, in the frame structure + * + * This function sets the TDD period configuration for DL, UL, and mixed slots in + * the specified frame structure instance, according to the given pattern, and + * updates the bitmap. + * + * @param pattern NR_TDD_UL_DL_Pattern_t configuration containing TDD slots and symbols configuration + * @param fs frame_structure_t pointer + * @param curr_total_slot current position in the slot bitmap to start from + * + * @return Number of slots in the configured TDD period + */ +static uint8_t set_tdd_bmap_period(NR_TDD_UL_DL_Pattern_t *pattern, tdd_period_config_t *pc, int8_t curr_total_slot) +{ + int8_t n_dl_slot = pattern->nrofDownlinkSlots; + int8_t n_ul_slot = pattern->nrofUplinkSlots; + int8_t n_dl_symbols = pattern->nrofDownlinkSymbols; + int8_t n_ul_symbols = pattern->nrofUplinkSymbols; + + // Total slots in the period: if DL/UL symbols are present, is mixed slot + const bool has_mixed_slot = (n_ul_symbols + n_dl_symbols) > 0; + int8_t total_slot = has_mixed_slot ? n_dl_slot + n_ul_slot + 1 : n_dl_slot + n_ul_slot; + + /** Update TDD period configuration: + * mixed slots with DL symbols are counted as DL slots + * mixed slots with UL symbols are counted as UL slots */ + pc->num_dl_slots += (n_dl_slot + (n_dl_symbols > 0)); + pc->num_ul_slots += (n_ul_slot + (n_ul_symbols > 0)); + + // Populate the slot bitmap for each slot in the TDD period + for (int i = 0; i < total_slot; i++) { + tdd_bitmap_t *bitmap = &pc->tdd_slot_bitmap[i + curr_total_slot]; + if (i < n_dl_slot) + bitmap->slot_type = TDD_NR_DOWNLINK_SLOT; + else if ((i == n_dl_slot) && has_mixed_slot) { + bitmap->slot_type = TDD_NR_MIXED_SLOT; + bitmap->num_dl_symbols = n_dl_symbols; + bitmap->num_ul_symbols = n_ul_symbols; + } else if (n_ul_slot) + bitmap->slot_type = TDD_NR_UPLINK_SLOT; + } + + LOG_I(NR_MAC, + "Set TDD configuration period to: %d DL slots, %d UL slots, %d slots per period (NR_TDD_UL_DL_Pattern is %d DL slots, %d " + "UL slots, %d DL symbols, %d UL symbols)\n", + pc->num_dl_slots, + pc->num_ul_slots, + total_slot, + n_dl_slot, + n_ul_slot, + n_dl_symbols, + n_ul_symbols); + + return total_slot; +} + +/** + * @brief Configures TDD patterns (1 or 2) in the frame structure + * + * This function sets up the TDD configuration in the frame structure by applying + * DL and UL patterns as defined in NR_TDD_UL_DL_ConfigCommon. + * It handles both TDD pattern1 and pattern2. + * + * @param tdd NR_TDD_UL_DL_ConfigCommon_t pointer containing pattern1 and pattern2 + * @param fs Pointer to the frame structure to update with the configured TDD patterns. + * + * @return void + */ +static void config_tdd_patterns(NR_TDD_UL_DL_ConfigCommon_t *tdd, frame_structure_t *fs) +{ + int num_of_patterns = 1; + uint8_t nb_slots_p2 = 0; + // Reset num dl/ul slots + tdd_period_config_t *pc = &fs->period_cfg; + pc->num_dl_slots = 0; + pc->num_ul_slots = 0; + // Pattern1 + uint8_t nb_slots_p1 = set_tdd_bmap_period(&tdd->pattern1, pc, 0); + // Pattern2 + if (tdd->pattern2) { + num_of_patterns++; + nb_slots_p2 = set_tdd_bmap_period(tdd->pattern2, pc, nb_slots_p1); + } + LOG_I(NR_MAC, + "Configured %d TDD patterns (total slots: pattern1 = %d, pattern2 = %d)\n", + num_of_patterns, + nb_slots_p1, + nb_slots_p2); +} + +/** + * @brief Get number of DL slots per period (full DL slots + mixed slots with DL symbols) + */ +int get_dl_slots_per_period(const frame_structure_t *fs) +{ + return fs->is_tdd ? fs->period_cfg.num_dl_slots : fs->numb_slots_frame; +} + +/** + * @brief Get number of UL slots per period (full UL slots + mixed slots with UL symbols) + */ +int get_ul_slots_per_period(const frame_structure_t *fs) +{ + return fs->is_tdd ? fs->period_cfg.num_ul_slots : fs->numb_slots_frame; +} + +/** + * @brief Get number of full UL slots per period + * @param fs Pointer to the frame structure + * @return Number of full UL slots + */ +int get_full_ul_slots_per_period(const frame_structure_t *fs) +{ + DevAssert(fs); + + if (!fs->is_tdd) + return fs->numb_slots_frame; + + int count = 0; + + for (int i = 0; i < fs->numb_slots_period; i++) + if (fs->period_cfg.tdd_slot_bitmap[i].slot_type == TDD_NR_UPLINK_SLOT) + count++; + + LOG_D(NR_MAC, "Full UL slots in TDD period: %d\n", count); + return count; +} + +/** + * @brief Get number of full DL slots per period + * @param fs Pointer to the frame structure + * @return Number of full DL slots + */ +int get_full_dl_slots_per_period(const frame_structure_t *fs) +{ + DevAssert(fs); + + if (!fs->is_tdd) + return fs->numb_slots_frame; + + int count = 0; + + for (int i = 0; i < fs->numb_slots_period; i++) + if (fs->period_cfg.tdd_slot_bitmap[i].slot_type == TDD_NR_DOWNLINK_SLOT) + count++; + + LOG_D(NR_MAC, "Full DL slots in TDD period: %d\n", count); + return count; +} + +/** + * @brief Get number of UL slots per frame + */ +int get_ul_slots_per_frame(const frame_structure_t *fs) +{ + return fs->is_tdd ? fs->numb_period_frame * get_ul_slots_per_period(fs) : fs->numb_slots_frame; +} + +/** + * @brief Configures the frame structure and the NFAPI config request + * depending on the duplex mode. If TDD, does the TDD patterns + * and TDD periods configuration. + * + * @param mu numerology + * @param scc pointer to scc + * @param cfg pointer to NFAPI config request + * @param fs pointer to the frame structure to update + * + * @return Number of periods in frame + */ +static int config_frame_structure(int mu, + NR_ServingCellConfigCommon_t *scc, + nfapi_nr_config_request_scf_t *cfg, + frame_structure_t *fs) +{ + fs->numb_slots_frame = nr_slots_per_frame[mu]; + if (cfg->cell_config.frame_duplex_type.value == TDD) { + cfg->tdd_table.tdd_period.tl.tag = NFAPI_NR_CONFIG_TDD_PERIOD_TAG; + cfg->num_tlv++; + cfg->tdd_table.tdd_period.value = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); + fs->numb_period_frame = get_nb_periods_per_frame(cfg->tdd_table.tdd_period.value); + fs->numb_slots_period = fs->numb_slots_frame / fs->numb_period_frame; + fs->is_tdd = true; + config_tdd_patterns(scc->tdd_UL_DL_ConfigurationCommon, fs); + set_tdd_config_nr(cfg, + mu, + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots, + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols, + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots, + scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols); + } else { // FDD + fs->is_tdd = false; + fs->numb_period_frame = 1; + fs->numb_slots_period = nr_slots_per_frame[mu]; + } + AssertFatal(fs->numb_period_frame > 0, "Frame configuration cannot be configured!\n"); + return fs->numb_period_frame; +} + static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR_ServingCellConfigCommon_t *scc) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 46deef46e8..7ecb7925e9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -39,6 +39,12 @@ void set_cset_offset(uint16_t); void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers); int get_NTN_Koffset(const NR_ServingCellConfigCommon_t *scc); +int get_ul_slots_per_period(const frame_structure_t *fs); +int get_ul_slots_per_frame(const frame_structure_t *fs); +int get_dl_slots_per_period(const frame_structure_t *fs); +int get_full_ul_slots_per_period(const frame_structure_t *fs); +int get_full_dl_slots_per_period(const frame_structure_t *fs); + void mac_top_init_gNB(ngran_node_t node_type, NR_ServingCellConfigCommon_t *scc, NR_ServingCellConfig_t *scd, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 012e8f8624..fcd74eef81 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -919,6 +919,59 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc } } +const float tdd_ms_period_pattern[] = {0.5, 0.625, 1.0, 1.25, 2.0, 2.5, 5.0, 10.0}; +const float tdd_ms_period_ext[] = {3.0, 4.0}; + +/** + * @brief Retrieves the periodicity in milliseconds for the given TDD pattern + * depending on the presence of the extension + * @param pattern Pointer to the NR_TDD_UL_DL_Pattern_t pattern structure + * @return Periodicity value in milliseconds. + */ +static float get_tdd_periodicity(NR_TDD_UL_DL_Pattern_t *pattern) { + if (!pattern->ext1) { + LOG_D(NR_MAC, "Setting TDD configuration period to dl_UL_TransmissionPeriodicity %ld\n", pattern->dl_UL_TransmissionPeriodicity); + return tdd_ms_period_pattern[pattern->dl_UL_TransmissionPeriodicity]; + } else { + DevAssert(pattern->ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL); + LOG_D(NR_MAC, + "Setting TDD configuration period to dl_UL_TransmissionPeriodicity_v1530 %ld\n", + *pattern->ext1->dl_UL_TransmissionPeriodicity_v1530); + return tdd_ms_period_ext[*pattern->ext1->dl_UL_TransmissionPeriodicity_v1530]; + } +} + +/** + * @brief Determines the TDD period index based on pattern periodicities + * @note Not applicabile to pattern extension + * @param tdd Pointer to the NR_TDD_UL_DL_ConfigCommon_t containing patterns + * @return Index of the TDD period in tdd_ms_period_pattern + */ +int get_tdd_period_idx(NR_TDD_UL_DL_ConfigCommon_t *tdd) +{ + int tdd_period_idx = 0; + float pattern1_ms = get_tdd_periodicity(&tdd->pattern1); + float pattern2_ms = tdd->pattern2 ? get_tdd_periodicity(tdd->pattern2) : 0.0; + bool found_match = false; + // Find matching TDD period in the predefined list of periodicities + for (int i = 0; i < NFAPI_MAX_NUM_PERIODS; i++) { + if ((pattern1_ms + pattern2_ms) == tdd_ms_period_pattern[i]) { + tdd_period_idx = i; + LOG_I(NR_MAC, + "TDD period index = %d, based on the sum of dl_UL_TransmissionPeriodicity " + "from Pattern1 (%f ms) and Pattern2 (%f ms): Total = %f ms\n", + tdd_period_idx, + pattern1_ms, + pattern2_ms, + pattern1_ms + pattern2_ms); + found_match = true; + break; + } + } + // Assert if no match was found + AssertFatal(found_match, "The sum of pattern1_ms and pattern2_ms does not match any value in tdd_ms_period_pattern"); + return tdd_period_idx; +} static struct NR_PUSCH_TimeDomainResourceAllocation *set_TimeDomainResourceAllocation(const int k2, uint8_t index, int ul_symb) { diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index b9f030e897..3076b09f62 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -112,5 +112,6 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC int uid); NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); +int get_tdd_period_idx(NR_TDD_UL_DL_ConfigCommon_t *tdd); #endif