From bd05075ac6e42ede8cdad279d9bdb99ca3ef1aa1 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 29 Jan 2025 14:20:53 +0100 Subject: [PATCH 01/17] code cosmetic improvement --- executables/nr-gnb.c | 19 +++---- executables/nr-ru.c | 55 ++++++++----------- openair1/PHY/INIT/nr_init_ru.c | 33 +++++------ openair1/PHY/NR_TRANSPORT/nr_prach.c | 5 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 7 +-- openair1/SCHED_NR/nr_ru_procedures.c | 18 +++--- openair1/SCHED_NR/sched_nr.h | 2 +- 7 files changed, 60 insertions(+), 79 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 9f20e6f409..24b835d419 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -360,13 +360,11 @@ void term_gNB_Tpool(int inst) { } /// eNB kept in function name for nffapi calls, TO FIX -void init_eNB_afterRU(void) { - int inst,ru_id,i,aa; - PHY_VARS_gNB *gNB; - - for (inst=0; instnum_RU, gNB->Mod_id); - for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) { + int aa = 0; + for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) { AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); - for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { - LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa); + for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { + LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i]; // TODO hardcoded beam to 0, still need to understand how to handle this properly gNB->common_vars.rxdataF[0][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i]; } } - /* TODO: review this code, there is something wrong. * In monolithic mode, we come here with nb_antennas_rx == 0 * (not tested in other modes). @@ -393,7 +391,6 @@ void init_eNB_afterRU(void) { //init_precoding_weights(RC.gNB[inst]); init_gNB_Tpool(inst); } - } /** diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 6187c9bc2e..0ae303b4e8 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -240,20 +240,20 @@ int connect_rau(RU_t *ru) { void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0); - void *buffs[ru->nb_tx]; - for (int aid=0;aidnb_tx;aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset]; + void *buffs[ru->nb_tx]; + for (int aid = 0; aid < ru->nb_tx; aid++) + buffs[aid] = (void*)&ru->common.txdata[aid][offset]; struct timespec txmeas; clock_gettime(CLOCK_MONOTONIC, &txmeas); LOG_D(NR_PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1], 10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec); ru->ifdevice.trx_write_func2(&ru->ifdevice, - timestamp, + timestamp, buffs, - 0, - ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms), - 0, - ru->nb_tx); - + 0, + ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms), + 0, + ru->nb_tx); } // southbound IF4p5 fronthaul @@ -591,33 +591,27 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; openair0_config_t *cfg = &ru->openair0_cfg; - void *rxp[ru->nb_rx]; - unsigned int rxs; - int i; uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); - uint32_t samples_per_slot_prev ; - openair0_timestamp ts,old_ts; - AssertFatal(*slotslots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); + AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame); start_meas(&ru->rx_fhaul); - for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; + void *rxp[ru->nb_rx]; + for (int i = 0; i < ru->nb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)]; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); - old_ts = proc->timestamp_rx; - LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1); + openair0_timestamp old_ts = proc->timestamp_rx; + LOG_D(PHY,"Reading %d samples for slot %d (%p)\n", samples_per_slot, *slot, rxp[0]); + openair0_timestamp ts; + unsigned int rxs; if(emulate_rf) { wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); rxs = samples_per_slot; ts = old_ts + rxs; } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - samples_per_slot, - ru->nb_rx); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); @@ -629,7 +623,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs); if (proc->first_rx != 1) { - samples_per_slot_prev = fp->get_samples_per_slot((*slot-1)%fp->slots_per_frame,fp); + uint32_t samples_per_slot_prev = fp->get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp); if (proc->timestamp_rx - old_ts != samples_per_slot_prev) { LOG_D(PHY, @@ -752,8 +746,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *cfg = &ru->config; - void *txp[ru->nb_tx]; - int i; T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), @@ -820,7 +812,8 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot); - for (i = 0; i < ru->nb_tx; i++) + void *txp[ru->nb_tx]; + for (int i = 0; i < ru->nb_tx; i++) txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff); @@ -830,12 +823,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) timestamp + ru->ts_offset - sf_extension, txp, siglen + sf_extension, - ru->nb_tx, flags); + ru->nb_tx, + flags); LOG_D(PHY, - "[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " + "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " "returned %d, E %f\n", ru->idx, - i, (long long unsigned int)(timestamp + ru->ts_offset - sf_extension), frame, slot, diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 674c70cdc3..93964f3ee9 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -29,7 +29,7 @@ void init_prach_ru_list(RU_t *ru); -int nr_phy_init_RU(RU_t *ru) +void nr_phy_init_RU(RU_t *ru) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; @@ -53,30 +53,30 @@ int nr_phy_init_RU(RU_t *ru) if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals - ru->common.txdata = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*)); - ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + ru->common.txdata = (int32_t**)malloc16(ru->nb_tx * sizeof(int32_t*)); + ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); for (int i = 0; i < ru->nb_tx; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t)); + ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t)); LOG_D(PHY, "[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n", i, ru->common.txdata[i], (ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t), ru->sf_extension); - ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; + ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; LOG_D(PHY, "[INIT] common.txdata[%d] = %p \n", i, ru->common.txdata[i]); } for (int i = 0; i < ru->nb_rx; i++) { - ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_frame*sizeof(int32_t) ); + ru->common.rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame * sizeof(int32_t)); } } // IF5 or local RF else { - ru->common.txdata = (int32_t**)NULL; - ru->common.rxdata = (int32_t**)NULL; + ru->common.txdata = (int32_t**)NULL; + ru->common.rxdata = (int32_t**)NULL; } if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing LOG_D(PHY, "nb_tx %d\n", ru->nb_tx); @@ -85,7 +85,6 @@ int nr_phy_init_RU(RU_t *ru) ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_subframe*2*sizeof(int32_t) ); LOG_D(PHY, "rxdata_7_5kHz[%d] %p for RU %d\n", i, ru->common.rxdata_7_5kHz[i], ru->idx); } - // allocate precoding input buffers (TX) ru->common.txdataF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); @@ -97,11 +96,11 @@ int nr_phy_init_RU(RU_t *ru) ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, ru->nb_tx * sizeof(int32_t *)); for (int i = 0; i < ru->nb_tx; i++) { - ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP*sizeof(int32_t) ); + ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t)); LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx); } // allocate FFT output buffers (RX) - ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); for (int i = 0; i < ru->nb_rx; i++) { // allocate 4 slots of I/Q signal data (frequency) int size = RU_RX_SLOT_DEPTH * fp->symbols_per_slot * fp->ofdm_symbol_size; @@ -117,21 +116,17 @@ int nr_phy_init_RU(RU_t *ru) for (int i = 0; i < ru->nb_rx; i++) { // largest size for PRACH FFT is 4x98304 (16*24576) - ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear( 4*98304*2*sizeof(int16_t) ); - LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,ru->prach_rxsigF[j][i]); + ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t)); + LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); } } - - AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX,"gNB instances %d > %d\n", - ru->num_gNB,NUMBER_OF_gNB_MAX); + + AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX, "gNB instances %d > %d\n", ru->num_gNB,NUMBER_OF_gNB_MAX); LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB); - } // !=IF5 init_prach_ru_list(ru); - - return(0); } void nr_phy_free_RU(RU_t *ru) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 858257893f..9094064fde 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -159,7 +159,6 @@ void rx_nr_prach_ru(RU_t *ru, { AssertFatal(ru != NULL,"ru is null\n"); - int16_t **rxsigF = NULL; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int slot2 = slot; int16_t *prach[ru->nb_rx]; @@ -191,12 +190,12 @@ void rx_nr_prach_ru(RU_t *ru, prachStartSymbol, prachOccasion); - rxsigF = ru->prach_rxsigF[prachOccasion]; + int16_t **rxsigF = ru->prach_rxsigF[prachOccasion]; AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); - for (int aa=0; aanb_rx; aa++){ + for (int aa = 0; aa < ru->nb_rx; aa++) { if (prach_sequence_length == 0) slot2 = prachStartSlot; prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 437a3c20db..c6d0ed1ef3 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -264,7 +264,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, - int prachOccasion, + int prachOccasion, int frame, int subframe, uint16_t *max_preamble, @@ -280,10 +280,7 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu); +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index a0b3a69ba8..0dc8c360b0 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -47,7 +47,7 @@ // RU OFDM Modulator gNodeB // OFDM modulation core routine, generates a first_symbol to first_symbol+num_symbols on a particular slot and TX antenna port -void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) +void nr_feptx0(RU_t *ru, int tti_tx, int first_symbol, int num_symbols, int aa) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; @@ -345,24 +345,24 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) void nr_fep(void* arg) { feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg; - RU_t *ru = feprx_cmd->ru; - int aid = feprx_cmd->aid; - int tti_rx = feprx_cmd->slot; - int startSymbol = feprx_cmd->startSymbol; - int endSymbol = feprx_cmd->endSymbol; + RU_t *ru = feprx_cmd->ru; + int aid = feprx_cmd->aid; + int slot = feprx_cmd->slot; + int startSymbol = feprx_cmd->startSymbol; + int endSymbol = feprx_cmd->endSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, tti_rx, startSymbol, endSymbol); + LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, slot, startSymbol, endSymbol); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1); - int offset = (tti_rx % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; + int offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (int l = startSymbol; l <= endSymbol; l++) nr_slot_fep_ul(fp, ru->common.rxdata[aid], &ru->common.rxdataF[aid][offset], l, - tti_rx, + slot, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0); diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index bf5a1eda3f..9f65819960 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -44,7 +44,7 @@ void nr_feptx_prec_control(RU_t *ru,int frame,int tti_tx); void nr_fep_tp(RU_t *ru, int slot); void nr_feptx_tp(RU_t *ru, int frame_tx, int slot); void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); -int nr_phy_init_RU(RU_t *ru); +void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols); From 8a544b9fbb64e65f549ea5958d68d5cbddca67f3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 6 Dec 2024 17:16:15 +0100 Subject: [PATCH 02/17] simpler RU beam management by storing RU beam index at L1 instead of FAPI beam index --- openair1/PHY/NR_TRANSPORT/nr_dci.c | 1 + openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 1 + openair1/PHY/NR_TRANSPORT/nr_prach.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/srs_rx.c | 7 ++++++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 16 ++++++++++++---- openair1/SCHED_NR/sched_nr.h | 7 ++++++- 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 6cca7fcfcc..899432c37a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -82,6 +82,7 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + &gNB->gNB_config.dbt_config, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 6e68a459c9..ee93f78e45 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -681,6 +681,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &gNB->gNB_config.dbt_config, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 9094064fde..a5e6c86e86 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -85,7 +85,12 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p // TODO no idea how to compute final prach symbol here so for now we go til the end of the slot int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); - prach->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + prach->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 982b236b70..84656ba1d0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -76,7 +76,12 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t if (gNB->common_vars.beam_id) { int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); - ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } ulsch->frame = frame; ulsch->slot = slot; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index a66812b39e..c7dacd7104 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -73,7 +73,12 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, if (gNB->common_vars.beam_id) { int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); - pucch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + pucch->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t)); LOG_D(PHY, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 8ece090cc5..642095345d 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -59,7 +59,12 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu if (gNB->common_vars.beam_id) { int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + srs->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t)); break; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 095c41d0da..19fdd4dca8 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,18 +45,24 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG -int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols) +int beam_index_allocation(int fapi_beam_index, + nfapi_nr_dbt_pdu_t *dbt_config, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols) { if (!common_vars->beam_id) return 0; int idx = -1; + int ru_beam_idx = dbt_config->dig_beam_list[fapi_beam_index].txru_list[0].dig_beam_weight_Re; for (int j = 0; j < common_vars->num_beams_period; j++) { for (int i = 0; i < symbols_per_slot; i++) { if (((bitmap_symbols >> i) & 0x01) == 0) continue; int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i]; - if (current_beam == -1 || current_beam == fapi_beam_index) + if (current_beam == -1 || current_beam == ru_beam_idx) idx = j; else { idx = -1; @@ -66,10 +72,10 @@ int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int s if (idx != -1) break; } - AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", fapi_beam_index); + AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", ru_beam_idx); for (int j = 0; j < symbols_per_slot; j++) { if (((bitmap_symbols >> j) & 0x01)) - common_vars->beam_id[idx][slot * symbols_per_slot + j] = fapi_beam_index; + common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx; } LOG_D(PHY, "Allocating beam %d in slot %d\n", idx, slot); return idx; @@ -132,6 +138,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &cfg->dbt_config, &gNB->common_vars, slot, fp->symbols_per_slot, @@ -273,6 +280,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &cfg->dbt_config, &gNB->common_vars, slot, fp->symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 9f65819960..72d2d96b4c 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -47,5 +47,10 @@ void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); -int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols); +int beam_index_allocation(int fapi_beam_index, + nfapi_nr_dbt_pdu_t *dbt_config, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols); #endif From 675e1129b42dd863503a8e25656b5411ac5e45c4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 9 Dec 2024 10:25:07 +0100 Subject: [PATCH 03/17] using the analog beamforming oai extension fapi fields instead of digital beamforming structure for analog beamforming --- doc/analog_beamforming.md | 2 ++ .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 ++ openair1/PHY/INIT/nr_init.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_dci.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 2 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- openair1/PHY/NR_TRANSPORT/srs_rx.c | 2 +- openair1/PHY/defs_gNB.h | 1 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++--- openair1/SCHED_NR/sched_nr.h | 2 +- openair2/GNB_APP/gnb_config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 34 ++++++++----------- 14 files changed, 31 insertions(+), 35 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 6d9e5bf71c..7943111f72 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -10,6 +10,8 @@ There are three main beamforming techinques: analog, digital and hybrid. The nam The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming. +To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. + # Configuration file fields for analog beamforming A set of parameters in configuration files controls the implementation of analog beamforming and instructs the scheduler on how to behave in such scenarios. Since most notably this technique in 5G is employed in FR2, the configuration file example currently available is a RFsim one for band 261. [Config file example](../ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index a34796eeb3..6ddb376bd3 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -496,6 +496,8 @@ typedef struct { typedef struct { nfapi_uint8_tlv_t num_beams_period_vendor_ext; nfapi_uint8_tlv_t analog_bf_vendor_ext; + nfapi_uint8_tlv_t total_num_beams_vendor_ext; + nfapi_uint8_tlv_t *analog_beam_list; } nfapi_nr_analog_beamforming_ve_t; // ERROR enums diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index d94d2ba493..ca453b6e65 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -172,8 +172,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) for (int i = 0; i < common_vars->num_beams_period; i++) common_vars->rxdataF[i] = (c16_t **)malloc16(Prx * sizeof(c16_t*)); - common_vars->num_beams = cfg->dbt_config.num_dig_beams; - if (common_vars->num_beams > 0) { + if (cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) { common_vars->beam_id = (int **)malloc16(common_vars->num_beams_period * sizeof(int*)); for (int i = 0; i < common_vars->num_beams_period; i++) common_vars->beam_id[i] = (int*)malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 899432c37a..38a671d50c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -82,7 +82,7 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index ee93f78e45..7e3d68f282 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -681,7 +681,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index a5e6c86e86..b01b35f502 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -86,7 +86,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); prach->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 84656ba1d0..f63bec4d5b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -77,7 +77,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index c7dacd7104..a16b68f708 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -74,7 +74,7 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); pucch->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 642095345d..16b92be946 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -60,7 +60,7 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; srs->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 59d92444d5..d305197554 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -287,7 +287,6 @@ typedef struct { /// - first index: beam index (for concurrent beams) /// - second index: beam_id [0.. symbols_per_frame[ int **beam_id; - int num_beams; int num_beams_period; bool analog_bf; int32_t *debugBuff; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 19fdd4dca8..ca90965ebc 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -46,7 +46,7 @@ //#define SRS_IND_DEBUG int beam_index_allocation(int fapi_beam_index, - nfapi_nr_dbt_pdu_t *dbt_config, + nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, @@ -56,7 +56,7 @@ int beam_index_allocation(int fapi_beam_index, return 0; int idx = -1; - int ru_beam_idx = dbt_config->dig_beam_list[fapi_beam_index].txru_list[0].dig_beam_weight_Re; + int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; for (int j = 0; j < common_vars->num_beams_period; j++) { for (int i = 0; i < symbols_per_slot; i++) { if (((bitmap_symbols >> i) & 0x01) == 0) @@ -138,7 +138,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->dbt_config, + &cfg->analog_beamforming_ve, &gNB->common_vars, slot, fp->symbols_per_slot, @@ -280,7 +280,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->dbt_config, + &cfg->analog_beamforming_ve, &gNB->common_vars, slot, fp->symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 72d2d96b4c..7450518f19 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -48,7 +48,7 @@ void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(int fapi_beam_index, - nfapi_nr_dbt_pdu_t *dbt_config, + nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..4b34c3858d 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1572,7 +1572,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) // each beam is described by a set of weights (one for each antenna) // on the other hand in case of analog beamforming an index to the RU beam identifier is provided config.nb_bfw[0] = num_tx; // number of tx antennas - config.nb_bfw[1] = n / num_tx; // number of beams + config.nb_bfw[1] = n; // number of beams weights/indices config.bw_list = malloc16_clear(n * sizeof(*config.bw_list)); for (int b = 0; b < n; b++) { config.bw_list[b] = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].iptr[b]; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 43d48eeeeb..59262c50d9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -715,36 +715,30 @@ static void config_common(gNB_MAC_INST *nrmac, if (cfg->cell_config.frame_duplex_type.value == TDD) set_tdd_config_nr(cfg, fs); - int nb_tx = config->nb_bfw[0]; // number of tx antennas - int nb_beams = config->nb_bfw[1]; // number of beams // precoding matrix configuration (to be improved) cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); - // beamforming matrix configuration - cfg->dbt_config.num_dig_beams = nb_beams; - if (nb_beams > 0) { - cfg->dbt_config.num_txrus = nb_tx; - cfg->dbt_config.dig_beam_list = malloc16(nb_beams * sizeof(*cfg->dbt_config.dig_beam_list)); - AssertFatal(cfg->dbt_config.dig_beam_list, "out of memory\n"); - for (int i = 0; i < nb_beams; i++) { - nfapi_nr_dig_beam_t *beam = &cfg->dbt_config.dig_beam_list[i]; - beam->beam_idx = i; - beam->txru_list = malloc16(nb_tx * sizeof(*beam->txru_list)); - for (int j = 0; j < nb_tx; j++) { - nfapi_nr_txru_t *txru = &beam->txru_list[j]; - txru->dig_beam_weight_Re = config->bw_list[j + i * nb_tx] & 0xffff; - txru->dig_beam_weight_Im = (config->bw_list[j + i * nb_tx] >> 16) & 0xffff; - LOG_D(NR_MAC, "Beam %d Tx %d Weight (%d, %d)\n", i, j, txru->dig_beam_weight_Re, txru->dig_beam_weight_Im); - } - } - } + int nb_beams = config->nb_bfw[1]; // number of beams if (nrmac->beam_info.beam_allocation) { + LOG_I(NR_MAC, "Configuring analog beamforming in config_request message\n"); cfg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag = NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value = nrmac->beam_info.beams_per_period; cfg->num_tlv++; cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled cfg->num_tlv++; + //cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = ???; + cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams; + cfg->num_tlv++; + cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list)); + for (int i = 0; i < nb_beams; i++) + cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i]; + } else { + cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled + if (NFAPI_MODE == NFAPI_MONOLITHIC) { + cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; + cfg->num_tlv++; + } } } From f5072833b651e618bed6aa347f94ec6735315714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Soares=20Silva?= Date: Mon, 9 Dec 2024 11:36:31 +0000 Subject: [PATCH 04/17] Add pack/unpack functionality for 2 new vendor extension TLVs. Add the ability to pack/unpack 2 new TLVs for analog beamforming total_num_beams_vendor_ext and analog_beam_list Add the unpack related changes for the first 2 vendor extension TLVs introduced related to beamforming. For the moment the packing is guarded by an Assert to ensure it is not used. Add the necessary utility function changes to support these VE TLVs Add the necessary changes to the corresponding unitary test for pack/unpack, commented for the moment, since the packing is disabled with an Assert. --- nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c | 47 +++++++++++++++++++ nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c | 30 ++++++++++++ .../nfapi/public_inc/nfapi_nr_interface.h | 2 + nfapi/tests/p5/nr_fapi_config_request_test.c | 27 +++++++++++ openair2/LAYER2/NR_MAC_gNB/config.c | 6 ++- 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index 796f424abe..281043b6d3 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -1124,6 +1124,33 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e // only increase if it was set numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; + AssertFatal(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == 0, + "Total num beams Vendor extension shouldn't be set!"); + // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, + // so, it's safe to add the call to pack_nr_tlv even if it is not always set + retval &= pack_nr_tlv(NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + // only increase if it was set + numTLVs += + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; + + for (int beam = 0; beam < pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value; beam++) { + AssertFatal(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam].tl.tag == 0, + "Analog beams list Vendor extension shouldn't be set!"); + // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, + // so, it's safe to add the call to pack_nr_tlv even if it is not always set + retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam]), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + // only increase if it was set + numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; + } + pNfapiMsg->num_tlv = numTLVs; retval &= push8(pNfapiMsg->num_tlv, &pNumTLVFields, end); return retval; @@ -1138,6 +1165,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * int config_beam_idx = 0; int tdd_periodicity_idx = 0; int symbol_per_slot_idx = 0; + int beam_ve_idx = 0; nfapi_nr_config_request_scf_t *pNfapiMsg = (nfapi_nr_config_request_scf_t *)msg; // unpack TLVs @@ -1188,6 +1216,10 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, NULL, &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), &unpack_ipv4_address_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), &unpack_ipv6_address_value}, @@ -1221,6 +1253,21 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * } int result = 0; switch (generic_tl.tag) { + case NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG: + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = generic_tl.tag; + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.length = generic_tl.length; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext, ppReadPackedMsg, end); + pNfapiMsg->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + beam_ve_idx = 0; + break; + case NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG: + unpack_fns[idx].tlv = &pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx]; + pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.tag = generic_tl.tag; + pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.length = generic_tl.length; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end); + beam_ve_idx ++; + break; case NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG: pNfapiMsg->prach_config.num_prach_fd_occasions.tl.tag = generic_tl.tag; pNfapiMsg->prach_config.num_prach_fd_occasions.tl.length = generic_tl.length; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c index 4267992d07..1b5e3f0ad8 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -276,6 +276,17 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const EQ_TLV(unpacked_req->nfapi_config.timing_info_mode, req->nfapi_config.timing_info_mode); EQ_TLV(unpacked_req->nfapi_config.timing_info_period, req->nfapi_config.timing_info_period); + + EQ_TLV(unpacked_req->analog_beamforming_ve.num_beams_period_vendor_ext, req->analog_beamforming_ve.num_beams_period_vendor_ext); + + EQ_TLV(unpacked_req->analog_beamforming_ve.analog_bf_vendor_ext, req->analog_beamforming_ve.analog_bf_vendor_ext); + + EQ_TLV(unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext, req->analog_beamforming_ve.total_num_beams_vendor_ext); + + for (int i = 0; i < unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + EQ_TLV(unpacked_req->analog_beamforming_ve.analog_beam_list[i], req->analog_beamforming_ve.analog_beam_list[i]); + } + return true; } @@ -422,6 +433,10 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) if (msg->pmi_list.pmi_pdu) { free(msg->pmi_list.pmi_pdu); } + + if (msg->analog_beamforming_ve.analog_beam_list) { + free(msg->analog_beamforming_ve.analog_beam_list); + } } void free_config_response(nfapi_nr_config_response_scf_t *msg) @@ -832,6 +847,21 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf COPY_TLV(dst->nfapi_config.ul_dci_timing_offset, src->nfapi_config.ul_dci_timing_offset); COPY_TLV(dst->nfapi_config.tx_data_timing_offset, src->nfapi_config.tx_data_timing_offset); + + COPY_TLV(dst->analog_beamforming_ve.num_beams_period_vendor_ext, src->analog_beamforming_ve.num_beams_period_vendor_ext); + + COPY_TLV(dst->analog_beamforming_ve.analog_bf_vendor_ext, src->analog_beamforming_ve.analog_bf_vendor_ext); + + COPY_TLV(dst->analog_beamforming_ve.total_num_beams_vendor_ext, src->analog_beamforming_ve.total_num_beams_vendor_ext); + + if (dst->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { + dst->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( + dst->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + for (int i = 0; i < src->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + COPY_TLV(dst->analog_beamforming_ve.analog_beam_list[i], src->analog_beamforming_ve.analog_beam_list[i]); + } + } + } void copy_config_response(const nfapi_nr_config_response_scf_t *src, nfapi_nr_config_response_scf_t *dst) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 39e9eca3e0..b7e6577fa2 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -31,6 +31,8 @@ #define NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120 #define NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG 0xA000 #define NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG 0xA001 +#define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002 +#define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003 typedef struct { uint16_t phy_id; diff --git a/nfapi/tests/p5/nr_fapi_config_request_test.c b/nfapi/tests/p5/nr_fapi_config_request_test.c index 3b6ae99e94..93ff5b5f3a 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -229,6 +229,33 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->nfapi_config.timing_info_period, NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, rand8()); nfapi_resp->num_tlv++; +/* + // TODO: Uncomment this block when ready to enable the pack of the following VE TLVs in nr_fapi_p5.c + // NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG + FILL_TLV(nfapi_resp->analog_beamforming_ve.num_beams_period_vendor_ext, + NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, + rand8()); + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_bf_vendor_ext, NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, rand8()); + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext, + NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, + rand8()); + nfapi_resp->num_tlv++; + + if (nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { + nfapi_resp->analog_beamforming_ve.analog_beam_list = + (nfapi_uint8_tlv_t *)malloc(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + for (int i = 0; i < nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_beam_list[i], NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, rand8()); + nfapi_resp->num_tlv++; + } + }*/ } static void test_pack_unpack(nfapi_nr_config_request_scf_t *req) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 59262c50d9..f87b4024b9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -727,12 +727,14 @@ static void config_common(gNB_MAC_INST *nrmac, cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled cfg->num_tlv++; - //cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = ???; + cfg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams; cfg->num_tlv++; cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list)); - for (int i = 0; i < nb_beams; i++) + for (int i = 0; i < nb_beams; i++) { + cfg->analog_beamforming_ve.analog_beam_list[i].tl.tag = NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i]; + } } else { cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled if (NFAPI_MODE == NFAPI_MONOLITHIC) { From 038247f0743e2a5b86e963470a6fdbc73b09907f Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 Dec 2024 16:13:21 +0100 Subject: [PATCH 05/17] RU analog beam management (not for 7.2) --- executables/nr-gnb.c | 9 +- executables/nr-ru.c | 17 ++- openair1/PHY/INIT/nr_init_ru.c | 40 +++--- openair1/PHY/NR_TRANSPORT/nr_prach.c | 10 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 8 +- openair1/PHY/defs_RU.h | 5 + openair1/SCHED_NR/fapi_nr_l1.c | 4 +- openair1/SCHED_NR/nr_ru_procedures.c | 123 +++++++++--------- openair1/SIMULATION/NR_PHY/prachsim.c | 2 +- 9 files changed, 115 insertions(+), 103 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 24b835d419..acab30751b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -360,7 +360,6 @@ void term_gNB_Tpool(int inst) { } /// eNB kept in function name for nffapi calls, TO FIX - void init_eNB_afterRU(void) { for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) { @@ -371,17 +370,17 @@ void init_eNB_afterRU(void) if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id); LOG_D(NR_PHY, "Mapping RX ports from %d RUs to gNB %d\n", gNB->num_RU, gNB->Mod_id); - int aa = 0; for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) { AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); - for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i]; - // TODO hardcoded beam to 0, still need to understand how to handle this properly - gNB->common_vars.rxdataF[0][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i]; + for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) { + int idx = i + b * gNB->RU_list[ru_id]->nb_rx; + gNB->common_vars.rxdataF[b][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[idx]; + } } } /* TODO: review this code, there is something wrong. diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 0ae303b4e8..a8ef32485f 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -591,12 +591,13 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; openair0_config_t *cfg = &ru->openair0_cfg; - uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); + uint32_t samples_per_slot = fp->get_samples_per_slot(*slot, fp); AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame); start_meas(&ru->rx_fhaul); - void *rxp[ru->nb_rx]; - for (int i = 0; i < ru->nb_rx; i++) + int nb = ru->nb_rx * ru->num_beams_period; + void *rxp[nb]; + for (int i = 0; i < nb; i++) rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)]; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1); @@ -611,7 +612,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) rxs = samples_per_slot; ts = old_ts + rxs; } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); @@ -812,8 +813,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot); - void *txp[ru->nb_tx]; - for (int i = 0; i < ru->nb_tx; i++) + int nt = ru->nb_tx * ru->num_beams_period; + void *txp[nt]; + for (int i = 0; i < nt; i++) txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff); @@ -823,7 +825,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) timestamp + ru->ts_offset - sf_extension, txp, siglen + sf_extension, - ru->nb_tx, + nt, flags); LOG_D(PHY, "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " @@ -1321,6 +1323,7 @@ void *ru_thread(void *param) rx_nr_prach_ru(ru, p->fmt, // could also use format p->numRA, + p->beam, prachStartSymbol, p->slot, prach_oc, diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 93964f3ee9..49d3890a0b 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -47,17 +47,21 @@ void nr_phy_init_RU(RU_t *ru) AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas); - ru->common.beam_id = malloc16_clear(MAX_NUM_BEAM_PERIODS * sizeof(int*)); - for(int i = 0; i < MAX_NUM_BEAM_PERIODS; i++) + nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve; + ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1; + int nb_tx_streams = ru->nb_tx * ru->num_beams_period; + int nb_rx_streams = ru->nb_rx * ru->num_beams_period; + + ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*)); + for(int i = 0; i < ru->num_beams_period; i++) ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals - ru->common.txdata = (int32_t**)malloc16(ru->nb_tx * sizeof(int32_t*)); - ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); + ru->common.txdata = (int32_t**)malloc16(nb_tx_streams * sizeof(int32_t*)); + ru->common.rxdata = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*)); - - for (int i = 0; i < ru->nb_tx; i++) { + for (int i = 0; i < nb_tx_streams; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t)); LOG_D(PHY, @@ -70,7 +74,7 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "[INIT] common.txdata[%d] = %p \n", i, ru->common.txdata[i]); } - for (int i = 0; i < ru->nb_rx; i++) { + for (int i = 0; i < nb_rx_streams; i++) { ru->common.rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame * sizeof(int32_t)); } } // IF5 or local RF @@ -93,15 +97,15 @@ void nr_phy_init_RU(RU_t *ru) ru->common.txdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); // allocate IFFT input buffers (TX) - ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); - LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, ru->nb_tx * sizeof(int32_t *)); - for (int i = 0; i < ru->nb_tx; i++) { + ru->common.txdataF_BF = (int32_t **)malloc16(nb_tx_streams * sizeof(int32_t*)); + LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, nb_tx_streams * sizeof(int32_t *)); + for (int i = 0; i < nb_tx_streams; i++) { ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t)); LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx); } // allocate FFT output buffers (RX) - ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); - for (int i = 0; i < ru->nb_rx; i++) { + ru->common.rxdataF = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*)); + for (int i = 0; i < nb_rx_streams; i++) { // allocate 4 slots of I/Q signal data (frequency) int size = RU_RX_SLOT_DEPTH * fp->symbols_per_slot * fp->ofdm_symbol_size; ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(**ru->common.rxdataF) * size); @@ -132,16 +136,18 @@ void nr_phy_init_RU(RU_t *ru) void nr_phy_free_RU(RU_t *ru) { LOG_D(PHY, "Freeing RU signal buffers (if_south %s) nb_tx %d\n", ru_if_types[ru->if_south], ru->nb_tx); + int nb_tx_streams = ru->nb_tx * ru->num_beams_period; + int nb_rx_streams = ru->nb_rx * ru->num_beams_period; if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals // Hack: undo what is done at allocation - for (int i = 0; i < ru->nb_tx; i++) { + for (int i = 0; i < nb_tx_streams; i++) { int32_t *p = &ru->common.txdata[i][-ru->sf_extension]; free_and_zero(p); } free_and_zero(ru->common.txdata); - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->common.rxdata[i]); free_and_zero(ru->common.rxdata); } // else: IF5 or local RF -> nothing to free() @@ -157,12 +163,12 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.txdataF); // free IFFT input buffers (TX) - for (int i = 0; i < ru->nb_tx; i++) + for (int i = 0; i < nb_tx_streams; i++) free_and_zero(ru->common.txdataF_BF[i]); free_and_zero(ru->common.txdataF_BF); // free FFT output buffers (RX) - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->common.rxdataF[i]); free_and_zero(ru->common.rxdataF); @@ -171,7 +177,7 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->prach_rxsigF[j][i]); free_and_zero(ru->prach_rxsigF[j]); } - for(int i = 0; i < MAX_NUM_BEAM_PERIODS; ++i) + for(int i = 0; i < ru->num_beams_period; ++i) free_and_zero(ru->common.beam_id[i]); free_and_zero(ru->common.beam_id); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index b01b35f502..ed90a3e318 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -70,7 +70,7 @@ int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { return -1; } -void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { int prach_id = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)), "illegal or no prach_id found!!! prach_id %d\n", prach_id); @@ -94,6 +94,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); + return prach_id; } void init_prach_ru_list(RU_t *ru) @@ -126,7 +127,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) return -1; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), @@ -140,6 +141,7 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p ru->prach_list[prach_id].num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1; ru->prach_list[prach_id].fmt = fmt; ru->prach_list[prach_id].numRA = prach_pdu->num_ra; + ru->prach_list[prach_id].beam = beam_id; ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol; ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas; pthread_mutex_unlock(&ru->prach_list_mutex); @@ -156,6 +158,7 @@ void free_nr_ru_prach_entry(RU_t *ru, int prach_id) void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, + int beam, int prachStartSymbol, int prachStartSlot, int prachOccasion, @@ -203,7 +206,8 @@ void rx_nr_prach_ru(RU_t *ru, for (int aa = 0; aa < ru->nb_rx; aa++) { if (prach_sequence_length == 0) slot2 = prachStartSlot; - prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; + int idx = aa + beam * ru->nb_rx; + prach[aa] = (int16_t*)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; } int reps; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index c6d0ed1ef3..ab1c9c2990 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -257,10 +257,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -void nr_fill_prach(PHY_VARS_gNB *gNB, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu); +int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, @@ -274,13 +271,14 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, void rx_nr_prach_ru(RU_t *ru, int prach_fmt, int numRA, + int beam, int prachStartSymbol, int prachStartSlot, int prachOccasion, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdum, int beam_id); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 1417180cb3..95667943a2 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -172,6 +172,7 @@ typedef struct RU_prec_t_s{ typedef struct { int aid; + int beam; struct RU_t_s *ru; int startSymbol; int endSymbol; @@ -181,6 +182,7 @@ typedef struct { typedef struct { int aid; + int beam; struct RU_t_s *ru; int slot; int startSymbol; @@ -196,6 +198,7 @@ typedef struct { int prachStartSymbol; int num_prach_ocas; int num_slots; + int beam; } RU_PRACH_list_t; #define NUMBER_OF_NR_RU_PRACH_MAX 8 @@ -488,6 +491,8 @@ typedef struct RU_t_s { int nb_rx; /// number of TX paths on device int nb_tx; + /// number of concurrent analog beams in period + int num_beams_period; /// number of logical antennas at TX beamformer input int nb_log_antennas; /// maximum PDSCH RS EPRE diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 5570b329fd..6b671abcfe 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -157,9 +157,9 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + int id = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, gNB->prach_vars.list[id].beam_nb); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 0dc8c360b0..cf0a1c6ee1 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -238,6 +238,7 @@ void nr_feptx(void *arg) RU_t *ru = feptx->ru; int slot = feptx->slot; int aa = feptx->aid; + int bb = feptx->beam; int startSymbol = feptx->startSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int numSymbols = feptx->numSymbols; @@ -246,44 +247,32 @@ void nr_feptx(void *arg) int txdataF_BF_offset = startSymbol * fp->ofdm_symbol_size; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 1); + int tx_idx = aa + bb * ru->nb_tx; - if (aa == 0) + if (tx_idx == 0) start_meas(&ru->precoding_stats); - if (ru->config.dbt_config.num_dig_beams != 0) { - for(int i = 0; i < ru->gNB_list[0]->common_vars.num_beams_period; i++) { - memcpy(&ru->common.beam_id[i][slot * fp->symbols_per_slot], - &ru->gNB_list[0]->common_vars.beam_id[i][slot * fp->symbols_per_slot], - (fp->symbols_per_slot) * sizeof(int)); - } + if (ru->gNB_list[0]->common_vars.analog_bf) { + memcpy(&ru->common.beam_id[bb][slot * fp->symbols_per_slot], + &ru->gNB_list[0]->common_vars.beam_id[bb][slot * fp->symbols_per_slot], + (fp->symbols_per_slot) * sizeof(int)); } // If there is no digital beamforming we just need to copy the data to RU if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) - memcpy((void*)&ru->common.txdataF_BF[aa][txdataF_BF_offset], - (void*)&ru->gNB_list[0]->common_vars.txdataF[0][aa][txdataF_offset], // TODO hardcoded beam to 0, still need to understand how to handle this properly + memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset], + (void*)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset], numSamples * sizeof(int32_t)); else { AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); - for(int i = 0; i < fp->symbols_per_slot; ++i) { - nr_beam_precoding((c16_t **)ru->gNB_list[0]->common_vars.txdataF, - (c16_t **)ru->common.txdataF_BF, - fp, - ru->beam_weights[0], - slot, - i, - aa, - ru->nb_log_antennas, - txdataF_offset); - } } - if (aa==0) + if (tx_idx == 0) stop_meas(&ru->precoding_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 0); ////////////FEPTX//////////// - nr_feptx0(ru, slot, startSymbol, numSymbols, aa); + nr_feptx0(ru, slot, startSymbol, numSymbols, tx_idx); // Task completed in // completed_task_ans(feptx->ans); @@ -299,39 +288,42 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 1); start_meas(&ru->ofdm_total_stats); - size_t const sz = ru->nb_tx + (ru->half_slot_parallelization > 0) * ru->nb_tx; + int nt = ru->nb_tx * ru->num_beams_period; + size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt; feptx_cmd_t arr[sz]; task_ans_t ans; init_task_ans(&ans, sz); int nbfeptx = 0; - for (int aid = 0; aid < ru->nb_tx; aid++) { - feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; - feptx_cmd->ans = &ans; - - feptx_cmd->aid = aid; - feptx_cmd->ru = ru; - feptx_cmd->slot = slot; - feptx_cmd->startSymbol = 0; - feptx_cmd->numSymbols = - (ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot; - - task_t t = {.func = nr_feptx, .args = feptx_cmd}; - pushTpool(ru->threadPool, t); - nbfeptx++; - if (ru->half_slot_parallelization > 0) { + for (int beam = 0; beam < ru->num_beams_period; beam++) { + for (int aid = 0; aid < ru->nb_tx; aid++) { feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; feptx_cmd->ans = &ans; - + feptx_cmd->beam = beam; feptx_cmd->aid = aid; feptx_cmd->ru = ru; feptx_cmd->slot = slot; - feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; - feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1; + feptx_cmd->startSymbol = 0; + feptx_cmd->numSymbols = + (ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot; task_t t = {.func = nr_feptx, .args = feptx_cmd}; pushTpool(ru->threadPool, t); nbfeptx++; + if (ru->half_slot_parallelization > 0) { + feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; + feptx_cmd->ans = &ans; + feptx_cmd->beam = beam; + feptx_cmd->aid = aid; + feptx_cmd->ru = ru; + feptx_cmd->slot = slot; + feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; + feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1; + + task_t t = {.func = nr_feptx, .args = feptx_cmd}; + pushTpool(ru->threadPool, t); + nbfeptx++; + } } } join_task_ans(&ans); @@ -347,6 +339,7 @@ void nr_fep(void* arg) feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg; RU_t *ru = feprx_cmd->ru; int aid = feprx_cmd->aid; + int beam = feprx_cmd->beam; int slot = feprx_cmd->slot; int startSymbol = feprx_cmd->startSymbol; int endSymbol = feprx_cmd->endSymbol; @@ -356,11 +349,12 @@ void nr_fep(void* arg) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1); + int idx = aid + beam * ru->nb_rx; int offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (int l = startSymbol; l <= endSymbol; l++) nr_slot_fep_ul(fp, - ru->common.rxdata[aid], - &ru->common.rxdataF[aid][offset], + ru->common.rxdata[idx], + &ru->common.rxdataF[idx][offset], l, slot, ru->N_TA_offset); @@ -377,39 +371,42 @@ void nr_fep_tp(RU_t *ru, int slot) { if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); start_meas(&ru->ofdm_demod_stats); - size_t const sz = ru->nb_rx + (ru->half_slot_parallelization > 0) * ru->nb_rx; + int nt = ru->nb_rx * ru->num_beams_period; + size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt; feprx_cmd_t arr[sz]; task_ans_t ans; init_task_ans(&ans, sz); - for (int aid=0;aidnb_rx;aid++) { - feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; - feprx_cmd->ans = &ans; - - feprx_cmd->aid = aid; - feprx_cmd->ru = ru; - feprx_cmd->slot = ru->proc.tti_rx; - feprx_cmd->startSymbol = 0; - feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1 - : (ru->nr_frame_parms->symbols_per_slot - 1); - - task_t t = {.func = nr_fep, .args = feprx_cmd}; - pushTpool(ru->threadPool, t); - nbfeprx++; - if (ru->half_slot_parallelization > 0) { + for (int beam = 0; beam < ru->num_beams_period; beam++) { + for (int aid = 0; aid < ru->nb_rx; aid++) { feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; feprx_cmd->ans = &ans; - + feprx_cmd->beam = beam; feprx_cmd->aid = aid; feprx_cmd->ru = ru; feprx_cmd->slot = ru->proc.tti_rx; - feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; - feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1; + feprx_cmd->startSymbol = 0; + feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1 + : (ru->nr_frame_parms->symbols_per_slot - 1); task_t t = {.func = nr_fep, .args = feprx_cmd}; pushTpool(ru->threadPool, t); - nbfeprx++; + if (ru->half_slot_parallelization > 0) { + feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; + feprx_cmd->ans = &ans; + feprx_cmd->beam = beam; + feprx_cmd->aid = aid; + feprx_cmd->ru = ru; + feprx_cmd->slot = ru->proc.tti_rx; + feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; + feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1; + + task_t t = {.func = nr_fep, .args = feprx_cmd}; + pushTpool(ru->threadPool, t); + + nbfeprx++; + } } } join_task_ans(&ans); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index aebfe4997f..a13918a606 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -773,7 +773,7 @@ int main(int argc, char **argv){ } } - rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, slot, prachOccasion, frame, slot); + rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot); for (int i = 0; i < ru->nb_rx; ++i) gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i]; From 93b08c5f20445c27e0d80b9a51fb1efc83fe8a9c Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 20 Dec 2024 11:30:55 +0100 Subject: [PATCH 06/17] bugfix in L1 analog beam allocation the allocation in L1 is done symbol-wise but the L2 is scheduling beams slot-based this means we need to check for beam availability in the whole slot --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index ca90965ebc..b626aa59cd 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -58,9 +58,8 @@ int beam_index_allocation(int fapi_beam_index, int idx = -1; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; for (int j = 0; j < common_vars->num_beams_period; j++) { + // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot for (int i = 0; i < symbols_per_slot; i++) { - if (((bitmap_symbols >> i) & 0x01) == 0) - continue; int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i]; if (current_beam == -1 || current_beam == ru_beam_idx) idx = j; @@ -77,7 +76,7 @@ int beam_index_allocation(int fapi_beam_index, if (((bitmap_symbols >> j) & 0x01)) common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx; } - LOG_D(PHY, "Allocating beam %d in slot %d\n", idx, slot); + LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot); return idx; } From bf6ddb70c4d3da4a0ac660dc73f853dc989484a0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 18 Jan 2025 10:37:48 +0100 Subject: [PATCH 07/17] extension of analog beamforming doc to lower layers --- doc/analog_beamforming.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 7943111f72..6bdb99b82d 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -30,3 +30,24 @@ This matrix contains the beams already allocated in a given slot, to flag the sc To this goal, we extended the virtual resource block (VRB) map by one dimension to also contain information per allocated beam. As said, the scheduler can independently schedule users in a number of beams up to `beams_per_period` concurrently. It is important to note that in current implementation, there are several periodical channels, e.g. PRACH or PUCCH for CSI et cetera, that have the precendence in being assigned a beam, that is because the scheduling is automatic, set in RRC configuration, and not up to the scheduler. For these instances, we assume the beam is available (if not there are assertions to stop the process). For data channels, the currently implemented PF scheduler is used. The only modification is that a UE can be served only if there is a free beam available or the one of the beams already in use correspond to that UE beam. + +# FAPI implementation + +In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: +- `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming +- `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period` +- `total_num_beams_vendor_ext` which corresponds to the number of beams configured in `beam_weights` +- `analog_beam_list` which contains the RU beamforming indices configured in `beam_weights` + +Additionally, L2 provides in each channel FAPI message information about the beam index. Small Cell Forum (SCF) FAPI provides in its PHY API specifications for the channels only a field for digital beamforming as part of the `precoding_and_beamforming` stucture. Therefore without a better option, we are currently using that one to store the internal analog beamforming index. This is the index used internally by the code to progressively identify the beam with a value from 0 to `total_num_beams_vendor_ext`. + +# L1 implementation + +To handle multiple concurrent beams, the buffers containing Tx and Rx data in frequency domain (`txdataF` and `rxdataF`) have been extended by one dimension to contain multiple concurrent beams to be transmitted/received. +The function `beam_index_allocation`, called by every L1 channel, is responsible to match the FAPI analog beam index to the RU beam index and to store the latter `beam_id` structure, which allocates the beams per symbol, despite L2 only supporting beam change at slot level. At the same time, the function returns the concurrent beam index, to be used to store data in frequency domain buffers. While doing so, the function also checks if there is room for current beam in the list of concurrent beams, which should always be the case, if L2 properly allocated the channels. + +# RU implementation + +The implementation is still work in progress. + +The first dimension of the Tx and Rx buffers that used to contain the number of Tx/Rx antennas, it is now extended to contain the number of parallel streams which is the number of antennas multiplied by the number of concurrent beams. From be8771189ee73e5ed05d84f7425cd40a5d7119e8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 3 Feb 2025 18:57:15 +0100 Subject: [PATCH 08/17] moving beam weigths to MACRLC config file section and requiring only a single beam index per beam in analog beamforming --- .../gnb.sa.band261.u3.32prb.rfsim.conf | 2 +- doc/analog_beamforming.md | 3 +- openair2/GNB_APP/MACRLC_nr_paramdef.h | 8 +++-- openair2/GNB_APP/gnb_config.c | 29 ++++++++++--------- openair2/GNB_APP/gnb_paramdef.h | 12 +++----- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf index 7cc7a9e3f9..d5b1695d5c 100644 --- a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf @@ -21,7 +21,6 @@ gNBs = sib1_tda = 15; min_rxtxtime = 6; - beam_weights = [0]; // single SSB -> one analog beam servingCellConfigCommon = ( { @@ -179,6 +178,7 @@ MACRLCs = ({ set_analog_beamforming = 1; beam_duration = 1; beams_per_period = 1; + beam_weights = [0]; // single SSB -> one analog beam }); L1s = ( diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 6bdb99b82d..3c695c5464 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -20,8 +20,7 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) - `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) - -In the `gNBs` section of the configuration file, under the phyisical parameters, a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. This field is called `beam_weights`. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. # Implementation in OAI scheduler diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index e682c559fa..c1382d7b70 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -76,6 +76,7 @@ #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 CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights" #define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" @@ -143,6 +144,7 @@ {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}, \ + {CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ {CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ @@ -189,8 +191,9 @@ #define MACRLC_ANALOG_BEAMFORMING_IDX 36 #define MACRLC_ANALOG_BEAM_DURATION_IDX 37 #define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38 -#define MACRLC_PUSCH_RSSI_THRES_IDX 39 -#define MACRLC_PUCCH_RSSI_THRES_IDX 40 +#define MACRLC_BEAMWEIGHTS_IDX 39 +#define MACRLC_PUSCH_RSSI_THRES_IDX 40 +#define MACRLC_PUCCH_RSSI_THRES_IDX 41 #define MACRLCPARAMS_CHECK { \ { .s5 = { NULL } }, \ @@ -232,6 +235,7 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ } diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 4b34c3858d..aab1ca831c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1566,19 +1566,6 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.timer_config.n311, config.timer_config.t319); - if (config_isparamset(GNBParamList.paramarray[0], GNB_BEAMWEIGHTS_IDX)) { - int n = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].numelt; - AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n"); - // each beam is described by a set of weights (one for each antenna) - // on the other hand in case of analog beamforming an index to the RU beam identifier is provided - config.nb_bfw[0] = num_tx; // number of tx antennas - config.nb_bfw[1] = n; // number of beams weights/indices - config.bw_list = malloc16_clear(n * sizeof(*config.bw_list)); - for (int b = 0; b < n; b++) { - config.bw_list[b] = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].iptr[b]; - } - } - // Construct default aggragation level list or read from config int uess_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; uess_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; @@ -1711,6 +1698,22 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration } + if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) { + int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; + int num_beam = n; + if (!ab) { + AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n"); + num_beam = n / num_tx; + } + // each beam is described by a set of weights (one for each antenna) + // in case of analog beamforming an index to the RU beam identifier is provided + // (one for each beam regardless of the number of antennas per beam) + config.nb_bfw[0] = num_tx; // number of tx antennas + config.nb_bfw[1] = num_beam; // number of beams weights/indices + config.bw_list = calloc_or_fail(n, sizeof(*config.bw_list)); + for (int b = 0; b < n; b++) + config.bw_list[b] = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].iptr[b]; + } // triggers also PHY initialization in case we have L1 via FAPI nr_mac_config_scc(RC.nrmac[j], scc, &config); } // for (j=0;j Date: Tue, 4 Feb 2025 19:46:27 +0100 Subject: [PATCH 09/17] fix beam allocation for multiple TD prach occasions in a slot --- executables/nr-ru.c | 3 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 29 ++++---- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 4 +- openair1/PHY/defs_RU.h | 2 +- openair1/PHY/defs_gNB.h | 2 +- openair1/SCHED_NR/nr_prach_procedures.c | 7 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 72 ++++++++++--------- 8 files changed, 64 insertions(+), 57 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a8ef32485f..a2b7fc858d 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1319,11 +1319,12 @@ void *ru_thread(void *param) for (int prach_oc = 0; prach_oc < p->num_prach_ocas; prach_oc++) { int prachStartSymbol = p->prachStartSymbol + prach_oc * N_dur; + int beam_id = ru->prach_list[prach_id].beam ? ru->prach_list[prach_id].beam[prach_oc] : 0; //comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}. rx_nr_prach_ru(ru, p->fmt, // could also use format p->numRA, - p->beam, + beam_id, prachStartSymbol, p->slot, prach_oc, diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 6ddb376bd3..6698ba9f29 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -24,7 +24,7 @@ #define NFAPI_MAX_NUM_GROUPS 8 #define NFAPI_MAX_NUM_CB 8 #define NFAPI_MAX_NUM_PRGS 1 -#define NFAPI_MAX_NUM_BG_IF 1 +#define NFAPI_MAX_NUM_BG_IF 6 #define NFAPI_MAX_NUM_PERIODS 8 // Extension to the generic structures for single tlv values diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index ed90a3e318..55a235737a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -42,7 +42,6 @@ void init_prach_list(PHY_VARS_gNB *gNB) for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++){ gNB->prach_vars.list[i].frame = -1; gNB->prach_vars.list[i].slot = -1; - gNB->prach_vars.list[i].beam_nb = -1; gNB->prach_vars.list[i].num_slots = -1; } } @@ -51,8 +50,8 @@ void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id) { gNB->prach_vars.list[prach_id].frame = -1; gNB->prach_vars.list[prach_id].slot = -1; - gNB->prach_vars.list[prach_id].beam_nb = -1; gNB->prach_vars.list[prach_id].num_slots = -1; + free_and_zero(gNB->prach_vars.list[prach_id].beam_nb); } int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { @@ -79,18 +78,20 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr prach->slot = Slot; const int format = prach_pdu->prach_format; prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; - prach->beam_nb = 0; if (gNB->common_vars.beam_id) { - int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - // TODO no idea how to compute final prach symbol here so for now we go til the end of the slot - int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; - int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); - prach->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, - &gNB->common_vars, - Slot, - NR_NUMBER_OF_SYMBOLS_PER_SLOT, - bitmap); + int n_symb = get_nr_prach_duration(prach_pdu->prach_format); + prach->beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->beam_nb)); + for (int i = 0; i < prach_pdu->beamforming.dig_bf_interface; i++) { + int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; + int start_symb = prach_pdu->prach_start_symbol + i * n_symb; + int bitmap = SL_to_bitmap(start_symb, n_symb); + prach->beam_nb[i] = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); + } } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); @@ -127,7 +128,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) return -1; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int beam_id) +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index ab1c9c2990..db49237a9e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -278,7 +278,7 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdum, int beam_id); +void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); @@ -304,7 +304,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); void free_nr_ru_prach_entry(RU_t *ru, int prach_id); -uint8_t get_nr_prach_duration(uint8_t prach_format); +int get_nr_prach_duration(uint8_t prach_format); void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 95667943a2..a2c39852f5 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -198,7 +198,7 @@ typedef struct { int prachStartSymbol; int num_prach_ocas; int num_slots; - int beam; + int *beam; } RU_PRACH_list_t; #define NUMBER_OF_NR_RU_PRACH_MAX 8 diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index d305197554..975588ec65 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -138,9 +138,9 @@ typedef struct { int frame; int slot; // identifier for concurrent beams - int beam_nb; // prach duration in slots int num_slots; + int *beam_nb; nfapi_nr_prach_pdu_t pdu; } gNB_PRACH_list_t; diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index c9f6a9c8cc..ece4482137 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -42,8 +42,9 @@ #include "assertions.h" #include -uint8_t get_nr_prach_duration(uint8_t prach_format){ +int get_nr_prach_duration(uint8_t prach_format) +{ switch(prach_format){ case 0: // format 0 @@ -117,14 +118,14 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list[prach_id].pdu; const int prach_start_slot = gNB->prach_vars.list[prach_id].slot; uint8_t prachStartSymbol; - uint8_t N_dur = get_nr_prach_duration(prach_pdu->prach_format); + int N_dur = get_nr_prach_duration(prach_pdu->prach_format); for(int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { for (ru_aa=0,aa=0;ru_aanb_rx;ru_aa++,aa++) { gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa]; } - prachStartSymbol = prach_pdu->prach_start_symbol+prach_oc*N_dur; + prachStartSymbol = prach_pdu->prach_start_symbol + prach_oc * N_dur; //comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}. rx_nr_prach(gNB, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index e67a30e67a..e398da1eaf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -356,10 +356,11 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) NR_COMMON_channels_t *cc = gNB->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; + NR_BWP_UplinkCommon_t *initialUplinkBWP = scc->uplinkConfigCommon->initialUplinkBWP; + NR_RACH_ConfigCommon_t *rach_ConfigCommon = initialUplinkBWP->rach_ConfigCommon->choice.setup; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) - msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; + if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16) + msgacc = initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; int slots_frame = gNB->frame_structure.numb_slots_frame; int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size); nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index]; @@ -371,7 +372,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) int slot_index = 0; uint16_t prach_occasion_id = -1; - int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bwp_start = NRRIV2PRBOFFSET(initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; @@ -399,6 +400,16 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) uint32_t N_t_slot = cc->prach_info.N_t_slot; uint32_t start_symb = cc->prach_info.start_symbol; for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion + 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); + + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t); + nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu; + memset(prach_pdu, 0, sizeof(nfapi_nr_prach_pdu_t)); + UL_tti_req->n_pdus += 1; + int num_td_occ = 0; for (int td_index = 0; td_index < N_t_slot; td_index++) { uint32_t config_period = cc->prach_info.x; prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + @@ -407,6 +418,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) if (prach_occasion_id >= cc->total_prach_occasions) // to be confirmed: unused occasion? continue; + num_td_occ++; float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; int beam_index = 0; if(num_ssb_per_RO <= 1) { @@ -417,8 +429,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) // multi-beam allocation structure beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to %d SSB transmitted in any available beam\n", n_ssb + 1); - } - else { + } else { int first_ssb_index = (prach_occasion_id * (int)num_ssb_per_RO) % cc->num_active_ssb; for(int j = first_ssb_index; j < first_ssb_index + num_ssb_per_RO; j++) { // fapi beam index @@ -428,40 +439,15 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", j); } } - if(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); - - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE; - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t); - nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu; - memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t)); - UL_tti_req->n_pdus+=1; - + if(num_td_occ == 1) { // filling the prach fapi structure prach_pdu->phys_cell_id = *scc->physCellId; - prach_pdu->num_prach_ocas = N_t_slot; - gNB->num_scheduled_prach_rx += N_t_slot; prach_pdu->prach_start_symbol = start_symb; prach_pdu->num_ra = fdm_index; prach_pdu->num_cs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, rach_ConfigCommon->restrictedSetConfig); - prach_pdu->beamforming.num_prgs = 0; - prach_pdu->beamforming.prg_size = 0; - prach_pdu->beamforming.dig_bf_interface = 1; - prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; - - LOG_D(NR_MAC, - "Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n", - frameP, - slotP, - prach_occasion_id, - prach_pdu->num_ra, - start_symb, - slot_index, - RA_sfn_index); // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities // We added 9 = A1/B1 10 = A2/B2 11 A3/B3 if (format1!=0xff) { @@ -518,8 +504,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) AssertFatal(1==0,"Invalid PRACH format"); } } - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 - && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { + if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { if (gNB->UE_info.connected_ue_list[0] == NULL) schedule_nr_MsgA_pusch(scc->uplinkConfigCommon, gNB, @@ -531,7 +516,26 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) *scc->physCellId); } } + prach_pdu->num_prach_ocas = num_td_occ; + prach_pdu->beamforming.num_prgs = 0; + prach_pdu->beamforming.prg_size = 0; + prach_pdu->beamforming.dig_bf_interface = num_td_occ; + prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = beam_index; + + LOG_D(NR_MAC, + "Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n", + frameP, + slotP, + prach_occasion_id, + prach_pdu->num_ra, + prach_pdu->prach_start_symbol, + slot_index, + RA_sfn_index); } + if (num_td_occ == 0) // no TD PRACH occasion -> no PRACH PDU + UL_tti_req->n_pdus -= 1; + else + gNB->num_scheduled_prach_rx += num_td_occ; } // block resources in vrb_map_UL From 964c737b7d3ad6b9249a3322c4cd2190f9b610c6 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 10 Jun 2025 11:12:44 +0200 Subject: [PATCH 10/17] simplify get_nr_prach_duration function --- openair1/SCHED_NR/nr_prach_procedures.c | 55 ++----------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index ece4482137..c56a37ca1d 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -37,63 +37,14 @@ #include "nfapi_pnf.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" - - #include "assertions.h" - #include int get_nr_prach_duration(uint8_t prach_format) { - switch(prach_format){ - - case 0: // format 0 - return 0; - - case 1: // format 1 - return 0; - - case 2: // format 2 - return 0; - - case 3: // format 3 - return 0; - - case 4: // format A1 - return 2; - - case 5: // format A2 - return 4; - - case 6: // format A3 - return 6; - - case 7: // format B1 - return 2; - - case 8: // format B4 - return 12; - - case 9: // format C0 - return 2; - - case 10: // format C2 - return 6; - - case 11: // format A1/B1 - return 2; - - case 12: // format A2/B2 - return 4; - - case 13: // format A3/B3 - return 6; - - default : - AssertFatal(1==0,"Invalid Prach format\n"); - break; - - } + const int val[14] = {0, 0, 0, 0, 2, 4, 6, 2, 12, 2, 6, 2, 4, 6}; + AssertFatal(prach_format < sizeofArray(val), "Invalid Prach format %d\n", prach_format); + return val[prach_format]; } void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind) From f555bf2957245b3f53050b166d286606d6e49d3c Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 10 Feb 2025 09:46:49 +0100 Subject: [PATCH 11/17] analog beamforming based distributed antenna system --- doc/analog_beamforming.md | 8 ++++- executables/nr-ru.c | 37 +++++++++++------------ openair1/PHY/NR_TRANSPORT/nr_dci.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 3 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 8 ++--- openair1/PHY/NR_TRANSPORT/srs_rx.c | 3 +- openair1/PHY/defs_gNB.h | 2 ++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 13 +++++--- openair1/SCHED_NR/sched_nr.h | 3 +- openair2/GNB_APP/L1_nr_paramdef.h | 10 ++++-- openair2/GNB_APP/gnb_config.c | 1 + 13 files changed, 59 insertions(+), 38 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 3c695c5464..e953e02fb3 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -10,7 +10,7 @@ There are three main beamforming techinques: analog, digital and hybrid. The nam The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming. -To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. +Analog beamforming implementation also allows to enable distributed antenna systems (DAS), where each beam corrisponds to one antenna (or a set of antennas) of the system. In this scenario, the scheduler constaint is alleviated because normally the number of concurrent beams allowed equals the total number of beams. # Configuration file fields for analog beamforming @@ -22,6 +22,8 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) - `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. + # Implementation in OAI scheduler A new MAC structure `NR_beam_info_t` controls the behavior of the scheduler in presence of analog beamforming. Besides the already mentioned parameters `beam_duration` and `beams_per_period`, the structure also holds a matrix `beam_allocation[i][j]`, whose indices `i` and `j` stands respectively for the number of beams in the period and the slot index (the size of the latter depends on the frame characteristics). @@ -32,6 +34,8 @@ It is important to note that in current implementation, there are several period # FAPI implementation +To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. + In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: - `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming - `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period` @@ -45,6 +49,8 @@ Additionally, L2 provides in each channel FAPI message information about the bea To handle multiple concurrent beams, the buffers containing Tx and Rx data in frequency domain (`txdataF` and `rxdataF`) have been extended by one dimension to contain multiple concurrent beams to be transmitted/received. The function `beam_index_allocation`, called by every L1 channel, is responsible to match the FAPI analog beam index to the RU beam index and to store the latter `beam_id` structure, which allocates the beams per symbol, despite L2 only supporting beam change at slot level. At the same time, the function returns the concurrent beam index, to be used to store data in frequency domain buffers. While doing so, the function also checks if there is room for current beam in the list of concurrent beams, which should always be the case, if L2 properly allocated the channels. +In case of DAS, since each beam corresponds to a specific antenna port, the `beam_index_allocation` function is simplified in the sense that the beam index corresponds to the antenna port index of the frequency domain buffers. + # RU implementation The implementation is still work in progress. diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a2b7fc858d..910de225b7 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -846,7 +846,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) static void fill_rf_config(RU_t *ru, char *rf_config_file) { - int i; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index openair0_config_t *cfg = &ru->openair0_cfg; @@ -872,13 +871,13 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) AssertFatal(ru->nb_rx > 0 && ru->nb_rx <= 8, "openair0 does not support more than 8 antennas\n"); cfg->Mod_id = 0; - cfg->num_rb_dl=N_RB; - cfg->tx_num_channels=ru->nb_tx; - cfg->rx_num_channels=ru->nb_rx; + cfg->num_rb_dl = N_RB; + cfg->tx_num_channels = ru->nb_tx * ru->num_beams_period; + cfg->rx_num_channels = ru->nb_rx * ru->num_beams_period; LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels); LOG_I(PHY,"tune_offset %.0f Hz, sample_rate %.0f Hz\n",cfg->tune_offset,cfg->sample_rate); - for (i=0; inb_tx; i++) { + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; } else if (ru->if_freq_offset) { @@ -893,7 +892,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) i, cfg->tx_gain[i],cfg->tx_freq[i]); } - for (i=0; inb_rx; i++) { + for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; } else if (ru->if_freq_offset) { @@ -939,8 +938,8 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ Each rf chain is is addressed by the card number and the chain on the card. The rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple antennas are mapped to successive RF chains on the same card. */ -int setup_RU_buffers(RU_t *ru) { - int i,j; +int setup_RU_buffers(RU_t *ru) +{ int card,ant; //uint16_t N_TA_offset = 0; NR_DL_FRAME_PARMS *fp; @@ -962,27 +961,27 @@ int setup_RU_buffers(RU_t *ru) { if (ru->openair0_cfg.mmapped_dma == 1) { // replace RX signal buffers with mmaped HW versions - for (i=0; inb_rx; i++) { - card = i/4; - ant = i%4; + for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { + card = i / 4; + ant = i % 4; LOG_D(PHY, "Mapping RU id %u, rx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.rxdata[i]); ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain + ant]; - for (j = 0; j < 16; j++) { - ru->common.rxdata[i][j] = 16-j; + for (int j = 0; j < 16; j++) { + ru->common.rxdata[i][j] = 16 - j; } } - for (i=0; inb_tx; i++) { - card = i/4; - ant = i%4; + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { + card = i / 4; + ant = i % 4; LOG_D(PHY, "Mapping RU id %u, tx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.txdata[i]); ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain + ant]; - for (j = 0; j < 16; j++) { - ru->common.txdata[i][j] = 16-j; + for (int j = 0; j < 16; j++) { + ru->common.txdata[i][j] = 16 - j; } } } else { // not memory-mapped DMA @@ -1049,7 +1048,7 @@ void ru_tx_func(void *param) ru->fh_north_out(ru); } else { if(frame_tx == print_frame) { - for (int i=0; inb_tx; i++) { + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { if(slot_tx == 0) { sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx); LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 38a671d50c..bea9cb63c5 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -81,7 +81,8 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, int dci_idx = 0; // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); - int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 7e3d68f282..58d11413f4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -680,7 +680,8 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 55a235737a..6398c59faa 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -85,7 +85,8 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; int start_symb = prach_pdu->prach_start_symbol + i * n_symb; int bitmap = SL_to_bitmap(start_symb, n_symb); - prach->beam_nb[i] = beam_index_allocation(fapi_beam_idx, + prach->beam_nb[i] = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, Slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index f63bec4d5b..4621e184a6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -76,7 +76,8 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t if (gNB->common_vars.beam_id) { int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); - ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, + ulsch->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index a16b68f708..a9639ce0d7 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -57,10 +57,7 @@ //#define DEBUG_NR_PUCCH_RX 1 -void nr_fill_pucch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pucch_pdu_t *pucch_pdu) +void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu) { bool found = false; for (int i = 0; i < gNB->max_nb_pucch; i++) { @@ -73,7 +70,8 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, if (gNB->common_vars.beam_id) { int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); - pucch->beam_nb = beam_index_allocation(fapi_beam_idx, + pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 16b92be946..c8b6d99c30 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -59,7 +59,8 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu if (gNB->common_vars.beam_id) { int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(fapi_beam_idx, + srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 975588ec65..ad17c243ae 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -492,6 +492,8 @@ typedef struct PHY_VARS_gNB_s { int num_ulprbbl; uint16_t ulprbbl [MAX_BWP_SIZE]; + bool enable_analog_das; + time_stats_t phy_proc_tx; time_stats_t phy_proc_rx; time_stats_t rx_prach; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b626aa59cd..ad75cc733e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,7 +45,8 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG -int beam_index_allocation(int fapi_beam_index, +int beam_index_allocation(bool das, + int fapi_beam_index, nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, @@ -55,8 +56,10 @@ int beam_index_allocation(int fapi_beam_index, if (!common_vars->beam_id) return 0; - int idx = -1; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; + if (das) + return ru_beam_idx; + int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot for (int i = 0; i < symbols_per_slot; i++) { @@ -136,7 +139,8 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n int txdataF_offset = slot * fp->samples_per_slot_wCP; // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &cfg->analog_beamforming_ve, &gNB->common_vars, slot, @@ -278,7 +282,8 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int lprime_num = mapping_parms.lprime + 1; for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &cfg->analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 7450518f19..40c32c2199 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -47,7 +47,8 @@ void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); -int beam_index_allocation(int fapi_beam_index, +int beam_index_allocation(bool das, + int fapi_beam_index, nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, diff --git a/openair2/GNB_APP/L1_nr_paramdef.h b/openair2/GNB_APP/L1_nr_paramdef.h index e313818ad2..b2b4ab93c1 100644 --- a/openair2/GNB_APP/L1_nr_paramdef.h +++ b/openair2/GNB_APP/L1_nr_paramdef.h @@ -61,6 +61,8 @@ #define HLP_L1_PHASE_COMP "Apply NR symbolwise phase rotation" #define CONFIG_STRING_NUM_ANTENNAS_PER_THREAD "dmrs_num_antennas_per_thread" #define HLP_NUM_ARX "Number of antennas per thread for PUSCH channel estimation" +#define CONFIG_STRING_ANALOG_DAS "enable_das" + /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* L1 configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -81,12 +83,13 @@ {CONFIG_STRING_L1_PRACH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=150, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=50, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_SRS_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=30, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \ {CONFIG_STRING_NUM_ANTENNAS_PER_THREAD, HLP_NUM_ARX,0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \ + {CONFIG_STRING_ANALOG_DAS, NULL, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \ } // clang-format on #define L1_CC_IDX 0 @@ -109,6 +112,7 @@ #define L1_TX_AMP_BACKOFF_dB 17 #define L1_PHASE_COMP 18 #define NUM_ANTENNAS_PER_THREAD 19 +#define L1_ANALOG_DAS 20 /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index aab1ca831c..4a68aa1f78 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1061,6 +1061,7 @@ void RCconfig_NR_L1(void) gNB->TX_AMP = min(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)), INT16_MAX); gNB->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr; gNB->dmrs_num_antennas_per_thread = *(L1_ParamList.paramarray[j][NUM_ANTENNAS_PER_THREAD].uptr); + gNB->enable_analog_das = *(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr); LOG_I(NR_PHY, "TX_AMP = %d (-%d dBFS)\n", gNB->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr); AssertFatal(gNB->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", gNB->TX_AMP); // Midhaul configuration From 3743719b88a1bfd7a35c0fb8f86d00f02783de55 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 7 Jan 2025 14:44:19 +0100 Subject: [PATCH 12/17] fix wrong assertion in nr_fill_prach_ru --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 6398c59faa..76d9b1185f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -132,7 +132,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), + AssertFatal((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX), "illegal or no prach_id found!!! prach_id %d\n", prach_id); From e15631b23c835464db5a9b76956aad1699ee1068 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 3 Feb 2025 15:58:10 +0100 Subject: [PATCH 13/17] adapting nr_feptx_prec function to analog beam management --- openair1/SCHED_NR/nr_ru_procedures.c | 66 ++++++++++------------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index cf0a1c6ee1..c455e5ac76 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -175,57 +175,39 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) { } -void nr_feptx_prec(RU_t *ru, int frame_tx, int tti_tx) +void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) { - PHY_VARS_gNB **gNB_list = ru->gNB_list,*gNB; - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + PHY_VARS_gNB **gNB_list = ru->gNB_list; + AssertFatal(ru->num_gNB == 1, "Cannot handle more than 1 gNB\n"); + PHY_VARS_gNB *gNB = gNB_list[0]; nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config; - int slot_tx = tti_tx; - int txdataF_offset = (tti_tx*fp->samples_per_slot_wCP); - + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + int txdataF_offset = slot_tx * fp->samples_per_slot_wCP; start_meas(&ru->precoding_stats); - AssertFatal(ru->nb_log_antennas > 0, "ru->nb_log_antennas is 0!\n"); if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) return; - if (ru->num_gNB == 1) { - gNB = gNB_list[0]; + if (gNB->common_vars.analog_bf) { + for (int i = 0; i < ru->num_beams_period; i++) { + memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot], + (void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot], + (fp->symbols_per_slot) * sizeof(int)); + } + } - if (ru->config.dbt_config.num_dig_beams != 0) { - for(int i = 0; i < gNB->common_vars.num_beams_period; ++i) { - memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot], - (void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot], - (fp->symbols_per_slot) * sizeof(int)); - } - } - - if (ru->config.dbt_config.num_dig_beams == 0 || gNB->common_vars.analog_bf) { - for (int i = 0; i < ru->nb_log_antennas; ++i) { - // TODO hardcoded beam to 0, still need to understand how to handle this properly - memcpy(ru->common.txdataF_BF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); - } - } - else { - for(int i = 0; i < ru->nb_log_antennas; ++i) { - // TODO hardcoded beam to 0, still need to understand how to handle this properly - memcpy(ru->common.txdataF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); - } - for (int l = 0; l < fp->symbols_per_slot; l++) { - for (int aa = 0; aa < ru->nb_tx; aa++) { - AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); - nr_beam_precoding((c16_t **)ru->common.txdataF, - (c16_t **)ru->common.txdataF_BF, - fp, - ru->beam_weights[0], - tti_tx, - l, - aa, - ru->nb_log_antennas, - 0); - } + // If there is no digital beamforming we just need to copy the data to RU + if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) { + for (int b = 0; b < ru->num_beams_period; b++) { + for (int i = 0; i < ru->nb_tx; ++i) { + int tx_idx = i + b * ru->nb_tx; + memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_offset], + (void*)&gNB->common_vars.txdataF[b][i][txdataF_offset], + fp->samples_per_slot_wCP * sizeof(int32_t)); } } + } else { + AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } stop_meas(&ru->precoding_stats); } @@ -264,7 +246,7 @@ void nr_feptx(void *arg) (void*)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset], numSamples * sizeof(int32_t)); else { - AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); + AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } if (tx_idx == 0) From a1a4f24d0f0aaf51d79d2ee07421ef6bc607f310 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 12 Feb 2025 21:05:31 +0100 Subject: [PATCH 14/17] hotfix for F. Mani's update to nr_feptx_prec handling of multiple beams --- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair1/SCHED_NR/nr_ru_procedures.c | 2 +- radio/fhi_72/oran_isolate.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 49d3890a0b..d96a279b9b 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -51,7 +51,7 @@ void nr_phy_init_RU(RU_t *ru) ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1; int nb_tx_streams = ru->nb_tx * ru->num_beams_period; int nb_rx_streams = ru->nb_rx * ru->num_beams_period; - + LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period); ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*)); for(int i = 0; i < ru->num_beams_period; i++) ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index c455e5ac76..0546455e36 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -201,7 +201,7 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) for (int b = 0; b < ru->num_beams_period; b++) { for (int i = 0; i < ru->nb_tx; ++i) { int tx_idx = i + b * ru->nb_tx; - memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_offset], + memcpy((void*)ru->common.txdataF_BF[tx_idx], (void*)&gNB->common_vars.txdataF[b][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); } diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 0a200a39a0..7ceec513c6 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -208,7 +208,7 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { ru_info_t ru_info; - ru_info.nb_rx = ru->nb_rx; + ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; ru_info.rxdataF = ru->common.rxdataF; ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id] @@ -262,7 +262,7 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { start_meas(&ru->tx_fhaul); ru_info_t ru_info; - ru_info.nb_tx = ru->nb_tx; + ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; ru_info.txdataF_BF = ru->common.txdataF_BF; // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); From 1153721b19c032287880d5a5afbe3815860fce3f Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 21 Mar 2025 12:22:29 +0100 Subject: [PATCH 15/17] changes for multi-RU DAS scenario, handling of antenna ports in 7.2 (memory allocations for PRACH and neAxc in fh_config) --- executables/nr-ru.c | 1 + openair1/PHY/INIT/nr_init_ru.c | 6 +++--- radio/COMMON/common_lib.h | 2 ++ radio/fhi_72/oran-config.c | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 910de225b7..411caf9a63 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -874,6 +874,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) cfg->num_rb_dl = N_RB; cfg->tx_num_channels = ru->nb_tx * ru->num_beams_period; cfg->rx_num_channels = ru->nb_rx * ru->num_beams_period; + cfg->num_distributed_ru = ru->num_beams_period; LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels); LOG_I(PHY,"tune_offset %.0f Hz, sample_rate %.0f Hz\n",cfg->tune_offset,cfg->sample_rate); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index d96a279b9b..a0766c348f 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -116,9 +116,9 @@ void nr_phy_init_RU(RU_t *ru) // AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), // "nb_antennas_rx too large"); for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - ru->prach_rxsigF[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); + ru->prach_rxsigF[j] = (int16_t**)malloc(nb_rx_streams * sizeof(int16_t*)); - for (int i = 0; i < ru->nb_rx; i++) { + for (int i = 0; i < nb_rx_streams; i++) { // largest size for PRACH FFT is 4x98304 (16*24576) ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t)); LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); @@ -173,7 +173,7 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.rxdataF); for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->prach_rxsigF[j][i]); free_and_zero(ru->prach_rxsigF[j]); } diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index a33e65c150..86d09b00fb 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -225,6 +225,8 @@ typedef struct openair0_config { int rx_num_channels; //! number of TX channels (=TX antennas) int tx_num_channels; + //! number of distributed radio-units + int num_distributed_ru; //! rx daughter card char* rx_subdev; //! tx daughter card diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 71804c5298..891634dbfc 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -834,7 +834,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c { AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n"); AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus); - DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0); + DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0 && oai0->num_distributed_ru > 0); DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0); DevAssert(oai0->tx_freq[0] > 0); for (int i = 1; i < oai0->tx_num_channels; ++i) @@ -879,7 +879,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->dpdk_port = ru_idx; // DPDK port number used for FH fh_config->sector_id = 0; // Band sector ID for FH; not used in xran fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info - fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) + fh_config->neAxc = RTE_MAX(oai0->num_distributed_ru * oai0->tx_num_channels / num_rus, oai0->num_distributed_ru * oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B fh_config->nDLFftSize = 0; // DL FFT size; not used in xran From ded31877343d2d32acd0fa2b7abd0b46c0a5ddd8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 22 Apr 2025 17:54:51 +0200 Subject: [PATCH 16/17] omitting beam weigths in case of DAS --- doc/analog_beamforming.md | 4 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 ++-- openair2/GNB_APP/gnb_config.c | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index e953e02fb3..4ff208343e 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -20,9 +20,9 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) - `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) -- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted -DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. +DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. In case of DAS enabled, the field `beam_weights` in `MACRLC` section can be omitted. # Implementation in OAI scheduler diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index ad75cc733e..d21674edaf 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -55,10 +55,10 @@ int beam_index_allocation(bool das, { if (!common_vars->beam_id) return 0; + if (das) + return fapi_beam_index; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; - if (das) - return ru_beam_idx; int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 4a68aa1f78..44ea5648bf 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1700,6 +1700,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration } if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) { + if (NFAPI_MODE == NFAPI_MONOLITHIC) { + GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL); + AssertFatal(*(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr) == 0, "No need to set beam weights in case of DAS\n"); + } int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; int num_beam = n; if (!ab) { From 73a2ba3894c662699e285cf2c43df49f54a13b1c Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 Jun 2025 10:22:23 +0200 Subject: [PATCH 17/17] assertion to avoid using analog beamforming in split scenario --- openair2/GNB_APP/gnb_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 44ea5648bf..e9d0099340 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1692,6 +1692,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) } bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; if (ab) { + AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n"); 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 *));