diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 49afffcdc6..250dcc2f95 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -51,10 +51,12 @@ * *********************************************************************/ -int set_tdd_config_nr( nfapi_nr_config_request_scf_t *cfg, - int mu, - int nrofDownlinkSlots, int nrofDownlinkSymbols, - int nrofUplinkSlots, int nrofUplinkSymbols) +int set_tdd_config_nr(nfapi_nr_config_request_scf_t *cfg, + int mu, + int nrofDownlinkSlots, + int nrofDownlinkSymbols, + int nrofUplinkSlots, + int nrofUplinkSymbols) { int slot_number = 0; diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index b3f9711ed4..b9b62ec39f 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -72,6 +72,9 @@ #define CONFIG_STRING_MACRLC_MIN_GRANT_PRB "min_grant_prb" #define CONFIG_STRING_MACRLC_MIN_GRANT_MCS "min_grant_mcs" #define CONFIG_STRING_MACRLC_IDENTITY_PM "identity_precoding_matrix" +#define CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING "set_analog_beamforming" +#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration" +#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period" #define HLP_MACRLC_UL_PRBBLACK "SNR threshold to decide whether a PRB will be blacklisted or not" #define HLP_MACRLC_DL_BLER_UP "Upper threshold of BLER to decrease DL MCS" @@ -85,6 +88,9 @@ #define HLP_MACRLC_MIN_GRANT_PRB "Minimal Periodic ULSCH Grant PRBs" #define HLP_MACRLC_MIN_GRANT_MCS "Minimal Periodic ULSCH Grant MCS" #define HLP_MACRLC_IDENTITY_PM "Flag to use only identity matrix in DL precoding" +#define HLP_MACRLC_AB "Flag to enable analog beamforming" +#define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams" +#define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -127,6 +133,9 @@ {CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS_F1U, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_SHM_PREFIX, NULL, 0, .strptr=NULL, .defstrval="nvipc", TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_POLL_CORE, NULL, 0, .i8ptr=NULL, .defintval=-1, TYPE_INT8, 0}, \ + {CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, PARAMFLAG_BOOL, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ } // clang-format off @@ -165,6 +174,9 @@ #define MACRLC_LOCAL_N_ADDRESS_F1U_IDX 32 #define MACRLC_TRANSPORT_S_SHM_PREFIX 33 #define MACRLC_TRANSPORT_S_POLL_CORE 34 +#define MACRLC_ANALOG_BEAMFORMING_IDX 35 +#define MACRLC_ANALOG_BEAM_DURATION_IDX 36 +#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 37 #define MACRLCPARAMS_CHECK { \ { .s5 = { NULL } }, \ @@ -202,6 +214,9 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s2 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d4eb1f0895..0dfe99e3cb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1405,6 +1405,15 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) RC.nrmac[j]->identity_pm = *(MacRLC_ParamList.paramarray[j][MACRLC_IDENTITY_PM_IDX].u8ptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; memcpy(RC.nrmac[j]->ulprbbl, prbbl, 275 * sizeof(prbbl[0])); + bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; + if (ab) { + NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; + int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr; + beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *)); + beam_info->beam_duration = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAM_DURATION_IDX].u8ptr; + beam_info->beams_per_period = beams_per_period; + beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration + } } // for (j=0;jtdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols); AssertFatal(periods_per_frame > 0, "TDD configuration cannot be configured\n"); - if (frequency_range == FR2) { - LOG_I(NR_MAC, "Configuring TDD beam association to default\n"); - nrmac->tdd_beam_association = malloc16(periods_per_frame * sizeof(int16_t)); - for (int i = 0; i < periods_per_frame; ++i) - nrmac->tdd_beam_association[i] = -1; /* default: beams not configured */ - } else { - nrmac->tdd_beam_association = NULL; /* default: no beams */ - } } // precoding matrix configuration (to be improved) cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); } +static void initialize_beam_information(NR_beam_info_t *beam_info, int mu, int slots_per_frame) +{ + if(!beam_info->beam_allocation) + return; + + int size = mu == 0 ? slots_per_frame << 1 : slots_per_frame; + // slots in beam duration gives the number of consecutive slots tied the the same beam + AssertFatal(size % beam_info->beam_duration == 0, + "Beam duration %d should be divider of number of slots per frame %d\n", + beam_info->beam_duration, + slots_per_frame); + beam_info->beam_allocation_size = size / beam_info->beam_duration; + for (int i = 0; i < beam_info->beams_per_period; i++) { + beam_info->beam_allocation[i] = malloc16(beam_info->beam_allocation_size * sizeof(int)); + for (int j = 0; j < beam_info->beam_allocation_size; j++) + beam_info->beam_allocation[i][j] = -1; + } +} + void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config) { DevAssert(nrmac != NULL); @@ -624,6 +635,8 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c nrmac->UL_tti_req_ahead[0] = calloc(size, sizeof(nfapi_nr_ul_tti_request_t)); AssertFatal(nrmac->UL_tti_req_ahead[0], "could not allocate memory for nrmac->UL_tti_req_ahead[0]\n"); + initialize_beam_information(&nrmac->beam_info, *scc->ssbSubcarrierSpacing, n); + LOG_I(NR_MAC, "Configuring common parameters from NR ServingCellConfig\n"); config_common(nrmac, config->pdsch_AntennaPorts, config->pusch_AntennaPorts, scc); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index dbd64f524e..9d1ad65315 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -146,6 +146,24 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB, TX_req[CC_idP].Number_of_PDUs = 0; } +void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slot, int mu) +{ + // for now we use the same logic of UL_tti_req_ahead + // reset after 1 frame with the exception of 15kHz + if(!beam_info->beam_allocation) + return; + // initialization done only once + const int slots_per_frame = nr_slots_per_frame[mu]; + AssertFatal(beam_info->beam_allocation_size >= 0, "Beam information not initialized\n"); + int idx_to_clear = (frame * slots_per_frame + slot) / beam_info->beam_duration; + idx_to_clear = (idx_to_clear + beam_info->beam_allocation_size - 1) % beam_info->beam_allocation_size; + if (slot % beam_info->beam_duration == 0) { + // resetting previous period allocation + for (int i = 0; i < beam_info->beams_per_period; i++) + beam_info->beam_allocation[i][idx_to_clear] = -1; + } +} + bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) { return (bitmap >> (slot % 64)) & 0x01; } @@ -195,19 +213,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_ gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = gNB->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SCHED_LOCK(&gNB->sched_lock); - if (slot==0 && (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]>=257)) { - //FR2 - const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - AssertFatal(tdd,"Dynamic TDD not handled yet\n"); - const int nb_periods_per_frame = get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - // re-initialization of tdd_beam_association at beginning of frame - for (int i=0; itdd_beam_association[i] = -1; - } + clear_beam_information(&gNB->beam_info, frame, slot, *scc->ssbSubcarrierSpacing); gNB->frame = frame; start_meas(&gNB->eNB_scheduler); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d1a0bae0dc..b89c566794 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -86,7 +86,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; uint8_t total_RApreambles = MAX_NUM_NR_PRACH_PREAMBLES; - if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL) + if(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL) total_RApreambles = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles; float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; @@ -135,7 +135,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, } // prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; - prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) + + prach_occasion_id = (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; //one RO is shared by one or more SSB @@ -145,7 +145,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, else if ( num_ssb_per_RO > 1) { index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ; for(int j = 0;j < num_ssb_per_RO;j++) { - if(preamble_index < (((j+1) * total_RApreambles) / num_ssb_per_RO)) + if(preamble_index < (((j + 1) * total_RApreambles) / num_ssb_per_RO)) index = index + j; } } @@ -308,24 +308,24 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP uint16_t format1 = (format >> 8) & 0xff; // second column of format from table if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe - if (slotP%2 == 1) + if (slotP % 2 == 1) slot_index = 1; else slot_index = 0; - }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe + } else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe slot_index = 0; } UL_tti_req->SFN = frameP; UL_tti_req->Slot = slotP; UL_tti_req->rach_present = 1; - for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion - for (int td_index=0; td_indexmax_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index; - if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){ + if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)) { AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus); @@ -551,20 +551,6 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont ra->contention_resolution_timer); } -static bool beam_is_active(const NR_TDD_UL_DL_Pattern_t *tdd, int mu, const int16_t *tdd_beam_association, int slot, int16_t ra_beam) -{ - if (tdd_beam_association == NULL) // no beams configured - return true; - DevAssert(tdd != NULL); - - const int n_slots_frame = nr_slots_per_frame[mu]; - uint8_t tdd_period_slot = n_slots_frame/get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); - int num_tdd_period = slot / tdd_period_slot; - int16_t current_beam = tdd_beam_association[num_tdd_period]; - return current_beam == -1 /* no beams */ - || current_beam == ra_beam; -} - static void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t frame, @@ -585,14 +571,19 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) { - // beam association for FR2 - if (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0] >= 257) { - // FR2 - const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - if (!beam_is_active(tdd, mu, nr_mac->tdd_beam_association, sched_slot, ra->beam_id)) - return; + const int n_slots_frame = nr_slots_per_frame[mu]; + NR_beam_alloc_t beam_ul = beam_allocation_procedure(&nr_mac->beam_info, + sched_frame, + sched_slot, + ra->beam_id, + n_slots_frame); + if (beam_ul.idx < 0) + return; + NR_beam_alloc_t beam_dci = beam_allocation_procedure(&nr_mac->beam_info, frame, slot, ra->beam_id, n_slots_frame); + if (beam_dci.idx < 0) { + reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, ra->beam_id, n_slots_frame, beam_ul.new_beam); + return; } - int fh = 0; int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int StartSymbolIndex, NrOfSymbols; @@ -752,7 +743,10 @@ static int get_feasible_msg3_tda(frame_type_t frame_type, uint64_t ulsch_slot_bitmap[3], const NR_PUSCH_TimeDomainResourceAllocationList_t *tda_list, int slots_per_frame, + int frame, int slot, + NR_RA_t *ra, + NR_beam_info_t *beam_info, const NR_TDD_UL_DL_Pattern_t *tdd) { DevAssert(tda_list != NULL); @@ -770,7 +764,9 @@ static int get_feasible_msg3_tda(frame_type_t frame_type, for (int i = 0; i < tda_list->list.count; i++) { // check if it is UL long k2 = *tda_list->list.array[i]->k2 + NTN_gNB_Koffset; - int temp_slot = (slot + k2 + mu_delta) % slots_per_frame; // msg3 slot according to 8.3 in 38.213 + int abs_slot = slot + k2 + mu_delta; + int temp_frame = (frame + (abs_slot / slots_per_frame)) & 1023; + int temp_slot = abs_slot % slots_per_frame; // msg3 slot according to 8.3 in 38.213 if (!is_xlsch_in_slot(ulsch_slot_bitmap[temp_slot / 64], temp_slot)) continue; @@ -791,9 +787,17 @@ static int get_feasible_msg3_tda(frame_type_t frame_type, if ((slot_mask & msg3_mask) != msg3_mask) continue; + // check if it is possible to allocate MSG3 in a beam in this slot + NR_beam_alloc_t beam = beam_allocation_procedure(beam_info, temp_frame, temp_slot, ra->beam_id, slots_per_frame); + if (beam.idx < 0) + continue; + // is in mixed slot with more or equal than 3 symbols, or UL slot - int tda = i; - return tda; + ra->Msg3_frame = temp_frame; + ra->Msg3_slot = temp_slot; + ra->Msg3_tda_id = i; + ra->Msg3_beam = beam; + return true; } return -1; // invalid @@ -804,8 +808,7 @@ static void nr_get_Msg3alloc(module_id_t module_id, NR_ServingCellConfigCommon_t *scc, sub_frame_t current_slot, frame_t current_frame, - NR_RA_t *ra, - int16_t *tdd_beam_association) + NR_RA_t *ra) { // msg3 is scheduled in mixed slot in the following TDD period DevAssert(ra->Msg3_tda_id >= 0 && ra->Msg3_tda_id < 16); @@ -818,24 +821,17 @@ static void nr_get_Msg3alloc(module_id_t module_id, const NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList_Common; int mu = ul_bwp->scs; - const int n_slots_frame = nr_slots_per_frame[mu]; int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ra->msg3_startsymb, &ra->msg3_nbSymb); - long k2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc); - int abs_slot = current_slot + k2 + DELTA[mu]; - ra->Msg3_slot = abs_slot % n_slots_frame; - ra->Msg3_frame = (current_frame + (abs_slot / n_slots_frame)) % MAX_FRAME_NUMBER; - LOG_I(NR_MAC, - "UE %04x: Msg3 scheduled at %d.%d (%d.%d k2 %ld TDA %u)\n", + "UE %04x: Msg3 scheduled at %d.%d (%d.%d TDA %u)\n", ra->rnti, ra->Msg3_frame, ra->Msg3_slot, current_frame, current_slot, - k2, ra->Msg3_tda_id); const int buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, mu, mac->vrb_map_UL_size); uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[buffer_index * MAX_BWP_SIZE]; @@ -1219,26 +1215,32 @@ static void nr_generate_Msg2(module_id_t module_idP, LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: Msg2 not monitored by UE\n", ra->RA_rnti, ra->rnti); return; } + const NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - if (!beam_is_active(tdd, ul_bwp->scs, nr_mac->tdd_beam_association, slotP, ra->beam_id)) { - LOG_I(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: beam %d inactive\n", ra->RA_rnti, ra->rnti, ra->beam_id); - return; - } - ra->Msg3_tda_id = get_feasible_msg3_tda(cc->frame_type, scc, DELTA[ul_bwp->scs], nr_mac->ulsch_slot_bitmap, ul_bwp->tdaList_Common, nr_slots_per_frame[ul_bwp->scs], + frameP, slotP, + ra, + &nr_mac->beam_info, tdd); if (ra->Msg3_tda_id < 0 || ra->Msg3_tda_id > 15) { LOG_D(NR_MAC, "UE RNTI %04x %d.%d: infeasible Msg3 TDA\n", ra->rnti, frameP, slotP); return; } + const int n_slots_frame = nr_slots_per_frame[dl_bwp->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + if (beam.idx < 0) { + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + return; + } + int mcsIndex = -1; // initialization value int rbStart = 0; int rbSize = 8; @@ -1284,6 +1286,8 @@ static void nr_generate_Msg2(module_id_t module_idP, if (rbStart > (BWPSize - rbSize)) { LOG_W(NR_MAC, "%s(): cannot find free vrb_map for RA RNTI %04x!\n", __func__, ra->RA_rnti); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1291,6 +1295,8 @@ static void nr_generate_Msg2(module_id_t module_idP, nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { LOG_W(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1299,6 +1305,8 @@ static void nr_generate_Msg2(module_id_t module_idP, if (CCEIndex < 0) { LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1462,7 +1470,7 @@ static void nr_generate_Msg2(module_id_t module_idP, nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[TX_req->Number_of_PDUs]; // Program UL processing for Msg3 - nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra, nr_mac->tdd_beam_association); + nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *)&tx_req->TLVs[0].value.direct[0]); // Start RA contention resolution timer in Msg3 transmission slot (current slot + K2) @@ -1762,6 +1770,11 @@ static void nr_generate_Msg4(module_id_t module_idP, mac_sdu_length = srb_status.bytes_in_buffer; } + const int n_slots_frame = nr_slots_per_frame[dl_bwp->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + if (beam.idx < 0) + return; + long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; @@ -1785,7 +1798,8 @@ static void nr_generate_Msg4(module_id_t module_idP, true); if (CCEIndex < 0) { - LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI 0x%04x!\n", __func__, ra->rnti); + LOG_E(NR_MAC, "Cannot find free CCE for RA RNTI 0x%04x!\n", ra->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1793,6 +1807,7 @@ static void nr_generate_Msg4(module_id_t module_idP, nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { LOG_I(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1857,7 +1872,8 @@ static void nr_generate_Msg4(module_id_t module_idP, } if (rbStart > (BWPSize - rbSize)) { - LOG_E(NR_MAC, "%s(): cannot find free vrb_map for RNTI %04x!\n", __func__, ra->rnti); + LOG_E(NR_MAC, "Cannot find free vrb_map for RNTI %04x!\n", ra->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } @@ -1877,9 +1893,10 @@ static void nr_generate_Msg4(module_id_t module_idP, LOG_D(NR_MAC, "Msg4 r_pucch %d (CCEIndex %d, delta_PRI %d)\n", r_pucch, CCEIndex, delta_PRI); - alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, r_pucch, 1); + alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, ra->beam_id, r_pucch, 1); if (alloc < 0) { - LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n",frameP,slotP); + LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n", frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); return; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 95ebf5eb5a..2353745c36 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -115,10 +115,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, gNB_MAC_INST *gNB = RC.nrmac[module_idP]; /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ nfapi_nr_dl_tti_request_body_t *dl_req; - uint8_t num_tdd_period,num_ssb; - int CC_id; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { NR_COMMON_channels_t *cc= &gNB->common_channels[CC_id]; const NR_MIB_t *mib = cc->mib->message.choice.mib; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; @@ -169,15 +167,18 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, const BIT_STRING_t *longBitmap = &scc->ssb_PositionsInBurst->choice.longBitmap; uint16_t ssb_start_symbol; + const int n_slots_frame = nr_slots_per_frame[scs]; switch (scc->ssb_PositionsInBurst->present) { case 1: // short bitmap (<3GHz) max 4 SSBs - for (int i_ssb=0; i_ssb<4; i_ssb++) { - if ((shortBitmap->buf[0]>>(7-i_ssb))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 4; i_ssb++) { + if ((shortBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); @@ -202,11 +203,13 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, break; case 2: // medium bitmap (<6GHz) max 8 SSBs - for (int i_ssb=0; i_ssb<8; i_ssb++) { - if ((mediumBitmap->buf[0]>>(7-i_ssb))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 8; i_ssb++) { + if ((mediumBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); @@ -231,23 +234,16 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, break; case 3: // long bitmap FR2 max 64 SSBs - num_ssb = 0; - for (int i_ssb=0; i_ssb<64; i_ssb++) { - if ((longBitmap->buf[i_ssb/8]>>(7-(i_ssb%8)))&0x01) { - ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); + for (int i_ssb = 0; i_ssb < 64; i_ssb++) { + if ((longBitmap->buf[i_ssb / 8] >> (7 - (i_ssb % 8))) & 0x01) { + ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol/14) == rel_slot){ + if ((ssb_start_symbol / 14) == rel_slot){ + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, i_ssb, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, mib_pdu); fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset >> (scs - 2), ssb_start_symbol, CC_id); - const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - // FR2 is only TDD, to be fixed for flexible TDD - const int nr_slots_period = tdd ? n_slots_frame/get_nb_periods_per_frame(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity) : n_slots_frame; - num_tdd_period = rel_slot/nr_slots_period; - gNB->tdd_beam_association[num_tdd_period]=i_ssb; - num_ssb++; - AssertFatal(num_ssb<2,"beamforming currently not supported for more than one SSB per slot\n"); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -571,15 +567,18 @@ void schedule_nr_sib1(module_id_t module_idP, scc->ssb_PositionsInBurst->present); } - for (int i=0; itype0_PDCCH_CSS_config[i]; - if((frameP%2 == type0_PDCCH_CSS_config->sfn_c) && + if((frameP % 2 == type0_PDCCH_CSS_config->sfn_c) && (slotP == type0_PDCCH_CSS_config->n_0) && (type0_PDCCH_CSS_config->num_rbs > 0) && (type0_PDCCH_CSS_config->active == true)) { + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB_mac->beam_info, frameP, slotP, i, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SIB1 corresponding to SSB %d in any available beam\n", i); LOG_D(NR_MAC,"(%d.%d) SIB1 transmission: ssb_index %d\n", frameP, slotP, type0_PDCCH_CSS_config->ssb_index); default_table_type_t table_type = get_default_table_type(type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index dc412cdf78..b608c4c5f0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -565,8 +565,9 @@ static bool allocate_dl_retransmission(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, current_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, r_pucch, 0); - if (alloc<0) { + // TODO properly set the beam index (currently only done for RA) + alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, 0, r_pucch, 0); + if (alloc < 0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, @@ -758,8 +759,9 @@ static void pf_dl(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, r_pucch, 0); - if (alloc<0) { + // TODO properly set the beam index (currently only done for RA) + alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, 0, r_pucch, 0); + if (alloc < 0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI\n", rnti, frame, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index c02691e82c..56c9ff6221 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -149,11 +149,10 @@ void nr_preprocessor_phytest(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(RC.nrmac[module_id], UE, frame, slot, r_pucch, 0); + alloc = nr_acknack_scheduling(RC.nrmac[module_id], UE, frame, slot, 0, r_pucch, 0); if (alloc < 0) { LOG_D(MAC, - "%s(): could not find PUCCH for UE %04x@%d.%d\n", - __func__, + "Could not find PUCCH for UE %04x@%d.%d\n", rnti, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5769efe4f2..3f1519e1da 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3110,6 +3110,43 @@ void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t } } +static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +{ + return ((frame * slots_per_frame + slot) / beam_info->beam_duration) % beam_info->beam_allocation_size; +} + +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +{ + // if no beam allocation for analog beamforming we always return beam index 0 (no multiple beams) + if (!beam_info->beam_allocation) + return (NR_beam_alloc_t) {.new_beam = false, .idx = 0}; + + const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + for (int i = 0; i < beam_info->beams_per_period; i++) { + NR_beam_alloc_t beam_struct = {.new_beam = false, .idx = i}; + int *beam = &beam_info->beam_allocation[i][index]; + if (*beam == -1) { + beam_struct.new_beam = true; + *beam = beam_index; + } + if (*beam == beam_index) + return beam_struct; + } + + return (NR_beam_alloc_t) {.new_beam = false, .idx = -1}; +} + +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam) +{ + if(!new_beam) // need to reset only if the beam was allocated specifically for this instance + return; + const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + for (int i = 0; i < beam_info->beams_per_period; i++) { + if (beam_info->beam_allocation[i][index] == beam_index) + beam_info->beam_allocation[i][index] = -1; + } +} + void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data) { gNB_MAC_INST *mac = RC.nrmac[0]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 3de5c1ea7a..d61b6f0a49 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1239,6 +1239,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot, + int beam_index, int r_pucch, int is_common) { @@ -1335,10 +1336,19 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, bwp_start, bwp_size); if(!ret) { - LOG_D(NR_MAC, "DL %4d.%2d, UL_ACK %4d.%2d PRB resources for this occasion are already occupied, move to the following occasion\n", + LOG_D(NR_MAC, + "DL %4d.%2d, UL_ACK %4d.%2d PRB resources for this occasion are already occupied, move to the following occasion\n", frame, slot, pucch_frame, pucch_slot); continue; } + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, pucch_frame, pucch_slot, beam_index, n_slots_frame); + if (beam.idx < 0) { + LOG_D(NR_MAC, + "DL %4d.%2d, UL_ACK %4d.%2d beam resources for this occasion are already occupied, move to the following occasion\n", + frame, slot, pucch_frame, pucch_slot); + // TODO add reset beam status + continue; + } // allocating a new PUCCH structure for this occasion curr_pucch->active = true; curr_pucch->frame = pucch_frame; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 82fc2ceee1..f262887e8f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -175,6 +175,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frameP, sub_frame_t slotP, + int beam_index, int r_pucch, int do_common); @@ -420,9 +421,11 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, frame_t frame); int ul_buffer_index(int frame, int slot, int scs, int size); - void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam); + void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP); size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 7792b70f6d..3815660ff6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -120,8 +120,15 @@ typedef enum { nrRA_Msg4 = 4, nrRA_WAIT_Msg4_ACK = 5, } RA_gNB_state_t; + static const char *const nrra_text[] = {"IDLE", "Msg2", "WAIT_Msg3", "Msg3_retransmission", "Msg3_dcch_dtch", "Msg4", "WAIT_Msg4_ACK"}; + +typedef struct { + int idx; + bool new_beam; +} NR_beam_alloc_t; + typedef struct nr_pdsch_AntennaPorts_t { int N1; int N2; @@ -203,6 +210,8 @@ typedef struct { frame_t Msg3_frame; /// Msg3 time domain allocation index int Msg3_tda_id; + /// Msg3 beam matrix index + NR_beam_alloc_t Msg3_beam; /// harq_pid used for Msg4 transmission uint8_t harq_pid; /// UE RNTI allocated during RAR @@ -742,6 +751,14 @@ typedef struct { uid_allocator_t uid_allocator; } NR_UEs_t; +typedef struct { + /// list of allocated beams per period + int **beam_allocation; + int beam_duration; // in slots + int beams_per_period; + int beam_allocation_size; +} NR_beam_info_t; + #define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++))) typedef void (*nr_pp_impl_dl)(module_id_t mod_id, @@ -841,8 +858,8 @@ typedef struct gNB_MAC_INST_s { time_stats_t rx_ulsch_sdu; // include rlc_data_ind /// processing time of eNB PCH scheduler time_stats_t schedule_pch; - /// list of allocated beams per period - int16_t *tdd_beam_association; + + NR_beam_info_t beam_info; /// bitmap of DLSCH slots, can hold up to 160 slots uint64_t dlsch_slot_bitmap[3];