diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index daed83543a..665719e7b6 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -1698,9 +1698,10 @@ For two RUs using a 8x8 configuration, i.e. a single antenna system, the referen For two RUs each using a 4x4 configuration, i.e. a distributed antenna system (DAS), we use the analog beamforming implementation. More details can be found in -[this document](./analog_beamforming.md). It is important to note that -the configuration file should be set as a 4x4 scenario and each RU would be given a -different beam. The reference DU configuration file is [`gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf). +[this document](./analog_beamforming.md). It is important to note the following parameters in the configuration file: +- In RU section `nb_tx` and `nb_rx` indicates the total number of physical antenna ports across all distributed RUs. +- `pusch_AntennaPorts`, `pdsch_AntennaPorts_XP * pdsch_AntennaPorts_N1 * pdsch_AntennaPorts_N2` indicate the number of logical antenna ports for one analog beam. +The reference DU configuration file is [`gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf). DAS is enabled by setting to 1 the parameter `enable_das` in `L1` section. diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index a211eb5d81..fe67d93ca8 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -10,11 +10,11 @@ This document explains the implementation of analog beamforming in OAI codebase. Beamforming is a technique applied to antenna arrays to create a directional radiation pattern. This often consists in providing a different phase shift to each element of the array such that signals with a different angle of arrival/departure experience a change in radiation pattern because of constructive or destructive interference. -There are three main beamforming techinques: analog, digital and hybrid. The names refer to the phase shift application before or after the digital to analog conversion (or analog to digital in reception). When we speak about analog beamforming we generally refer to a techinique where the phase shifts that produce the beam stearing are applied by the radio unit (RU) choosing from a finite set of steering directions. The advantage of analog beamforming is a simplified analog circuitry and therefore reduced costs. +There are three main beamforming techniques: analog, digital and hybrid. The names refer to the phase shift application before or after the digital to analog conversion (or analog to digital in reception). When we speak about analog beamforming we generally refer to a technique where the phase shifts that produce the beam steering are applied by the radio unit (RU) choosing from a finite set of steering directions. The advantage of analog beamforming is a simplified analog circuitry and therefore reduced costs. 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. -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. +Analog beamforming implementation also allows to enable distributed antenna systems (DAS), where each beam corresponds to one antenna (or a set of antennas) of the system. In this scenario, the scheduler constraint is alleviated because normally the number of concurrent beams allowed equals the total number of beams. ## Configuration file fields for analog beamforming @@ -55,19 +55,17 @@ This definition of beam-ID is present only in the most recent versions of SCF PH In addition to that, a `config_request` structure defined as 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` Therefore, in case of analog beamforming, L2 provides in each channel FAPI message information about the beam index via the beam-ID parameter with MSB set to 1. ## 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. - +The total number of logical antenna ports available at L1 is same as `pusch_AntennaPorts * beams_per_period` in UL and `pdsch_AntennaPorts_N1 * pdsch_AntennaPorts_N2 * pdsch_AntennaPorts_XP * beams_per_period` in DL. +To handle multiple concurrent beams, L2 uses spatial stream indices specified by FAPI to signal L1 on which logical ports to use for a DL or UL signal. The config file parameter `spatial_stream_index` can be used to specify an array of logical port indices to be used. If this parameter is not provided then the indices defaults to `[0 ... pusch_AntennaPorts - 1]`. This parameter is particularly useful when a specific subset of eAxCID has to be used. 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. -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. +The first dimension of the Tx and Rx buffers contains the number of Tx/Rx antennas which is at least the number of logical antenna ports. diff --git a/executables/main_nr_ru.c b/executables/main_nr_ru.c index 286f7bd42e..009c48ec76 100644 --- a/executables/main_nr_ru.c +++ b/executables/main_nr_ru.c @@ -129,6 +129,10 @@ int beam_index_allocation(bool das, { return 0; } +uint16_t get_first_ant_idx(bool das, uint16_t num_ports_beams, uint16_t beam_id, uint16_t fapi_start_port) +{ + return 0; +}; void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]) { return; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 1b27b2e4e6..f88a334713 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -172,17 +172,15 @@ static void rx_func(processingData_L1_t *info) if (gNB->phase_comp) { //apply the rx signal rotation here int soffset = (slot_rx % RU_RX_SLOT_DEPTH) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; - for (int bb = 0; bb < gNB->common_vars.num_beams_period; bb++) { - for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) { - const uint max_symb = (gNB->frame_parms.Ncp == NR_EXTENDED) ? 12 : 14; - for (int sym = 0; sym < max_symb; sym++) - apply_nr_rotation_symbol_RX(&gNB->frame_parms, - gNB->common_vars.rxdataF[bb][aa] + soffset + sym * gNB->frame_parms.ofdm_symbol_size, - gNB->frame_parms.symbol_rotation[1], - gNB->frame_parms.N_RB_UL, - slot_rx, - sym); - } + for (int aa = 0; aa < gNB->frame_parms.nb_antennas_tx; aa++) { + const uint max_symb = (gNB->frame_parms.Ncp == NR_EXTENDED) ? 12 : 14; + for (int sym = 0; sym < max_symb; sym++) + apply_nr_rotation_symbol_RX(&gNB->frame_parms, + gNB->common_vars.rxdataF[aa] + soffset + sym * gNB->frame_parms.ofdm_symbol_size, + gNB->frame_parms.symbol_rotation[1], + gNB->frame_parms.N_RB_UL, + slot_rx, + sym); } } phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx, &UL_INFO); @@ -360,10 +358,7 @@ void init_eNB_afterRU(void) AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF 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); - 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]; - } + gNB->common_vars.rxdataF[aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i]; } } /* TODO: review this code, there is something wrong. diff --git a/executables/nr-ru.c b/executables/nr-ru.c index ec1555bf4f..fd8a0ef45f 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -347,7 +347,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame); start_meas(&ru->rx_fhaul); - int nb = ru->nb_rx * ru->num_beams_period; + int nb = ru->nb_rx; void *rxp[nb]; for (int i = 0; i < nb; i++) rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)]; @@ -462,12 +462,12 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot) if (ru->common.beam_id) { int prev_slot = (slot - 1 + fp->slots_per_frame) % fp->slots_per_frame; - const int *beam_ids = ru->common.beam_id[0]; - int prev_beam = beam_ids[prev_slot * fp->symbols_per_slot]; - int beam = beam_ids[slot * fp->symbols_per_slot]; + uint16_t **beam_ids = ru->common.beam_id; + uint16_t prev_beam = beam_ids[prev_slot * fp->symbols_per_slot][0]; + int beam = beam_ids[slot * fp->symbols_per_slot][0]; if (prev_beam != beam) { flags_gpio = beam | TX_GPIO_CHANGE; // enable change of gpio - LOG_I(HW, "slot %d, beam %d\n", slot, ru->common.beam_id[0][slot * fp->symbols_per_slot]); + LOG_I(HW, "slot %d, beam %d\n", slot, beam_ids[slot * fp->symbols_per_slot][0]); } } break; @@ -476,7 +476,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot) // the beam index is written in bits 8-10 of the flags // bit 11 enables the gpio programming int beam = 0; - if ((slot % 10 == 0) && ru->common.beam_id && (ru->common.beam_id[0][slot * fp->symbols_per_slot] < 64)) { + if ((slot % 10 == 0) && ru->common.beam_id && (ru->common.beam_id[slot * fp->symbols_per_slot][0] < 64)) { // beam = ru->common.beam_id[0][slot*fp->symbols_per_slot] | 64; beam = 1024; // hardcoded now for beam32 boresight // beam = 127; //for the sake of trying beam63 @@ -559,7 +559,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) const int flags = flags_burst | (flags_gpio << 4); proc->first_tx = 0; - int nt = ru->nb_tx * ru->num_beams_period; + int nt = ru->nb_tx; void *txp[nt]; for (int i = 0; i < nt; i++) txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t); @@ -612,13 +612,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->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; + cfg->tx_num_channels = ru->nb_tx; + cfg->rx_num_channels = ru->nb_rx; + cfg->num_distributed_ru = 1; 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 (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { + for (int i = 0; i < ru->nb_tx; i++) { if (ru->if_frequency == 0) { cfg->tx_freq[i] = fp->dl_CarrierFreq; } else if (ru->if_freq_offset) { @@ -633,7 +633,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) i, cfg->tx_gain[i],cfg->tx_freq[i]); } - for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { + for (int i = 0; i < ru->nb_rx; i++) { if (ru->if_frequency == 0) { cfg->rx_freq[i] = fp->ul_CarrierFreq; } else if (ru->if_freq_offset) { @@ -706,7 +706,7 @@ int setup_RU_buffers(RU_t *ru) if (ru->openair0_cfg.mmapped_dma == 1) { // replace RX signal buffers with mmaped HW versions - for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { + for (int i = 0; i < ru->nb_rx; i++) { int card = i / 4; int 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); @@ -718,7 +718,7 @@ int setup_RU_buffers(RU_t *ru) } } - for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { + for (int i = 0; i < ru->nb_tx; i++) { int card = i / 4; int 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); @@ -980,7 +980,7 @@ void *ru_thread(void *param) prach_item_t p; while (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { // need to extract RACH data for later processing by rx_nr_prach() - rx_nr_prach_ru(&p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); + rx_nr_prach_ru(&p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset, gNB->enable_analog_das); bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p)); // assume prach_l1rx_queue never full: prach_ru_queue filled at // constant pace, but prach_l1rx_queue emptied as fast as possible, diff --git a/nfapi/open-nFAPI/common/public_inc/nfapi.h b/nfapi/open-nFAPI/common/public_inc/nfapi.h index 04b88755a5..bf698d1def 100644 --- a/nfapi/open-nFAPI/common/public_inc/nfapi.h +++ b/nfapi/open-nFAPI/common/public_inc/nfapi.h @@ -52,7 +52,7 @@ uint32_t pullarray32(uint8_t **values_to_pull, uint32_t pullarrays32(uint8_t **in, int32_t out[], uint32_t max_len, uint32_t len, uint8_t *end); uint32_t pusharray8(uint8_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); -uint32_t pusharray16(uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); +uint32_t pusharray16(const uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); uint32_t pusharrays16(int16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); uint32_t pusharray32(const uint32_t *values_to_push, uint32_t max_num_values_to_push, diff --git a/nfapi/open-nFAPI/common/src/nfapi.c b/nfapi/open-nFAPI/common/src/nfapi.c index f997552c1e..49fce92bfc 100644 --- a/nfapi/open-nFAPI/common/src/nfapi.c +++ b/nfapi/open-nFAPI/common/src/nfapi.c @@ -381,7 +381,7 @@ uint32_t pullarrays16(uint8_t **in, int16_t out[], uint32_t max_len, uint32_t le return 0; } } -uint32_t pusharray16(uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +uint32_t pusharray16(const uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) { if (len == 0) return 1; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c index 58f60f6ccc..22bdd13101 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c @@ -268,6 +268,17 @@ static uint8_t pack_dl_tti_csi_rs_pdu_rel15_value(void *tlv, uint8_t **ppWritePa if(!pack_nr_tx_beamforming_pdu(&value->precodingAndBeamforming,ppWritePackedMsg, end)) { return 0; } +#ifndef ENABLE_AERIAL + if (!push8(value->param_v4.numSpatialStreamIndices, ppWritePackedMsg, end)) + return 0; + + if (!pusharray8(value->param_v4.spatialStreamIndices, + MAX_NUM_SPATIAL_STREAMS, + value->param_v4.numSpatialStreamIndices, + ppWritePackedMsg, + end)) + return 0; +#endif return 1; } @@ -307,6 +318,31 @@ static uint8_t pack_dl_tti_pdcch_pdu_rel15_value(void *tlv, uint8_t **ppWritePac return 0; } } + +#ifndef ENABLE_AERIAL + // Spatial steam indices for MU-MIMO + const nfapi_v4_pdcch_pdu_parameters_t *p = &value->param_v4; + if (!push16(p->numSpatialStreams, ppWritePackedMsg, end)) + return 0; + + for (uint_fast16_t i = 0; i < p->numSpatialStreams; i++) + if (!(push16(p->dci_spatialStreamIndices[i].dci_index, ppWritePackedMsg, end) + && push16(p->dci_spatialStreamIndices[i].spatial_stream_index, ppWritePackedMsg, end))) + return 0; +#endif + return 1; +} + +static inline uint8_t pack_spatial_stream_indices(const nfapi_nr_spatial_stream_index_t *ss, + uint8_t **ppWritePackedMsg, + uint8_t *end) +{ + if (!push8(ss->numSpatialStreamIndices, ppWritePackedMsg, end)) + return 0; + + if (!pusharray16(ss->spatialStreamIndices, MAX_NUM_SPATIAL_STREAMS, ss->numSpatialStreamIndices, ppWritePackedMsg, end)) + return 0; + return 1; } @@ -369,6 +405,14 @@ static uint8_t pack_dl_tti_pdsch_pdu_rel15_value(void *tlv, uint8_t **ppWritePac if (!push8(value->maintenance_parms_v3.ldpcBaseGraph, ppWritePackedMsg, end) || !push32(value->maintenance_parms_v3.tbSizeLbrmBytes, ppWritePackedMsg, end)) return 0; + + // PDSCH parameter in FAPI v4 for MU-MIMO spatial stream indexing + if (!push8(value->param_v4.numberCodewords, ppWritePackedMsg, end)) + return 0; + + for (uint_fast8_t c = 0; c < value->param_v4.numberCodewords; c++) + if (!pack_spatial_stream_indices(value->param_v4.spatialStreamsCw + c, ppWritePackedMsg, end)) + return 0; #endif return 1; } @@ -390,6 +434,11 @@ static uint8_t pack_dl_tti_ssb_pdu_rel15_value(void *tlv, uint8_t **ppWritePacke if(!pack_nr_tx_beamforming_pdu(&value->precoding_and_beamforming,ppWritePackedMsg, end)) { return 0; } +#ifndef ENABLE_AERIAL + if (!(push8(value->param_v4.spatialStreamIndexPresent, ppWritePackedMsg, end) + && push16(value->param_v4.spatialStreamIndex, ppWritePackedMsg, end))) + return 0; +#endif return 1; } @@ -517,6 +566,30 @@ static uint8_t unpack_dl_tti_pdcch_pdu_rel15_value(void *tlv, uint8_t **ppReadPa return 0; } } + +#ifndef ENABLE_AERIAL + // Spatial steam indices for MU-MIMO + nfapi_v4_pdcch_pdu_parameters_t *p = &value->param_v4; + if (!pull16(ppReadPackedMsg, &p->numSpatialStreams, end)) + return 0; + + for (uint_fast16_t i = 0; i < p->numSpatialStreams; i++) { + if (!(pull16(ppReadPackedMsg, &p->dci_spatialStreamIndices[i].dci_index, end) + && pull16(ppReadPackedMsg, &p->dci_spatialStreamIndices[i].spatial_stream_index, end))) + return 0; + } +#endif + return 1; +} + +static inline uint8_t unpack_spatial_stream_indices(nfapi_nr_spatial_stream_index_t *ss, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + if (!pull8(ppReadPackedMsg, &ss->numSpatialStreamIndices, end)) + return 0; + + if (!pullarray16(ppReadPackedMsg, ss->spatialStreamIndices, MAX_NUM_SPATIAL_STREAMS, ss->numSpatialStreamIndices, end)) + return 0; + return 1; } @@ -579,6 +652,14 @@ static uint8_t unpack_dl_tti_pdsch_pdu_rel15_value(void *tlv, uint8_t **ppReadPa if (!pull8(ppReadPackedMsg, &value->maintenance_parms_v3.ldpcBaseGraph, end) || !pull32(ppReadPackedMsg, &value->maintenance_parms_v3.tbSizeLbrmBytes, end)) return 0; + + // PDSCH parameter in FAPI v4 for MU-MIMO spatial stream indexing + if (!pull8(ppReadPackedMsg, &value->param_v4.numberCodewords, end)) + return 0; + + for (uint_fast8_t c = 0; c < value->param_v4.numberCodewords; c++) + if (!unpack_spatial_stream_indices(value->param_v4.spatialStreamsCw + c, ppReadPackedMsg, end)) + return 0; #endif return 1; } @@ -602,6 +683,17 @@ static uint8_t unpack_dl_tti_csi_rs_pdu_rel15_value(void *tlv, uint8_t **ppReadP if(!unpack_nr_tx_beamforming_pdu(&value->precodingAndBeamforming, ppReadPackedMsg, end)) { return 0; } +#ifndef ENABLE_AERIAL + if (!pull8(ppReadPackedMsg, &value->param_v4.numSpatialStreamIndices, end)) + return 0; + + if (!pullarray8(ppReadPackedMsg, + value->param_v4.spatialStreamIndices, + MAX_NUM_SPATIAL_STREAMS, + value->param_v4.numSpatialStreamIndices, + end)) + return 0; +#endif return 1; } @@ -626,6 +718,11 @@ static uint8_t unpack_dl_tti_ssb_pdu_rel15_value(void *tlv, uint8_t **ppReadPack if(!unpack_nr_tx_beamforming_pdu(&value->precoding_and_beamforming, ppReadPackedMsg, end)) { return 0; } +#ifndef ENABLE_AERIAL + if (!(pull8(ppReadPackedMsg, &value->param_v4.spatialStreamIndexPresent, end) + && pull16(ppReadPackedMsg, &value->param_v4.spatialStreamIndex, end))) + return 0; +#endif return 1; } @@ -725,7 +822,14 @@ static uint8_t pack_ul_tti_request_prach_pdu(const nfapi_nr_prach_pdu_t *prach_p return 0; } - return pack_nr_rx_beamforming_pdu(&prach_pdu->beamforming, ppWritePackedMsg, end); + if (!pack_nr_rx_beamforming_pdu(&prach_pdu->beamforming, ppWritePackedMsg, end)) + return 0; + + const nfapi_nr_spatial_stream_index_t *p = &prach_pdu->param_v4; + if (!pack_spatial_stream_indices(p, ppWritePackedMsg, end)) + return 0; + + return 1; } static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, uint8_t **ppWritePackedMsg, uint8_t *end) @@ -817,7 +921,8 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui } #ifndef ENABLE_AERIAL if (!(push8(pusch_pdu->maintenance_parms_v3.ldpcBaseGraph, ppWritePackedMsg, end) - && push32(pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes, ppWritePackedMsg, end))) + && push32(pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes, ppWritePackedMsg, end) + && pack_spatial_stream_indices(&pusch_pdu->param_v4, ppWritePackedMsg, end))) return 0; #endif return 1; @@ -845,7 +950,15 @@ static uint8_t pack_ul_tti_request_pucch_pdu(const nfapi_nr_pucch_pdu_t *pucch_p return 0; } - return pack_nr_rx_beamforming_pdu(&pucch_pdu->beamforming, ppWritePackedMsg, end); + if (!pack_nr_rx_beamforming_pdu(&pucch_pdu->beamforming, ppWritePackedMsg, end)) + return 0; + +#ifndef ENABLE_AERIAL + if (!pack_spatial_stream_indices(&pucch_pdu->param_v4, ppWritePackedMsg, end)) + return 0; +#endif + + return 1; } static uint8_t pack_ul_tti_request_srs_parameters_v4(nfapi_v4_srs_parameters_t *srsParameters, @@ -1050,7 +1163,14 @@ static uint8_t unpack_ul_tti_request_prach_pdu(nfapi_nr_prach_pdu_t *prach_pdu, return 0; } - return unpack_nr_rx_beamforming_pdu(&prach_pdu->beamforming, ppReadPackedMsg, end); + if (!unpack_nr_rx_beamforming_pdu(&prach_pdu->beamforming, ppReadPackedMsg, end)) + return 0; +#ifndef ENABLE_AERIAL + if (!unpack_spatial_stream_indices(&prach_pdu->param_v4, ppReadPackedMsg, end)) + return 0; +#endif + + return 1; } static uint8_t unpack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, uint8_t **ppReadPackedMsg, uint8_t *end) @@ -1139,7 +1259,8 @@ static uint8_t unpack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, } #ifndef ENABLE_AERIAL if (!(pull8(ppReadPackedMsg, &pusch_pdu->maintenance_parms_v3.ldpcBaseGraph, end) - && pull32(ppReadPackedMsg, &pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes, end))) + && pull32(ppReadPackedMsg, &pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes, end) + && unpack_spatial_stream_indices(&pusch_pdu->param_v4, ppReadPackedMsg, end))) return 0; #endif return 1; @@ -1166,7 +1287,14 @@ static uint8_t unpack_ul_tti_request_pucch_pdu(nfapi_nr_pucch_pdu_t *pucch_pdu, && pull16(ppReadPackedMsg, &pucch_pdu->bit_len_csi_part2, end))) { return 0; } - return unpack_nr_rx_beamforming_pdu(&pucch_pdu->beamforming, ppReadPackedMsg, end); + if (!unpack_nr_rx_beamforming_pdu(&pucch_pdu->beamforming, ppReadPackedMsg, end)) + return 0; + +#ifndef ENABLE_AERIAL + if (!unpack_spatial_stream_indices(&pucch_pdu->param_v4, ppReadPackedMsg, end)) + return 0; +#endif + return 1; } static uint8_t unpack_ul_tti_request_srs_parameters_v4(nfapi_v4_srs_parameters_t *srsParameters, diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c index ce1c6d8322..543824fa92 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c @@ -983,126 +983,76 @@ static void copy_dl_tti_beamforming(const nfapi_nr_tx_precoding_and_beamforming_ } } +// Macro to get size from start to a member (exclusive) +#define SIZE_UPTO(type, member) offsetof(type, member) + +// Macro to get size from start to a member (inclusive) +#define SIZE_INCLUDING(type, member) (offsetof(type, member) + sizeof(((type *)0)->member)) + +// Macro to copy partial struct +#define PARTIAL_COPY(dst, src, type, last_member) memcpy((dst), (src), SIZE_INCLUDING(type, last_member)) + +// Macro to copy partial struct +#define PARTIAL_COPY_RANGE(dst, src, type, first_member, last_member) \ + memcpy(((uint8_t *)(dst)) + SIZE_UPTO(type, first_member), \ + ((uint8_t *)(src)) + SIZE_UPTO(type, first_member), \ + SIZE_INCLUDING(type, last_member) - SIZE_UPTO(type, first_member)) + +// Macro to copy array +#define COPY_STRUCT_ARRAY(dst, src, data_member, count_member) \ + do { \ + size_t _len = (src)->count_member * sizeof((src)->data_member[0]); \ + if (_len > sizeof((dst)->data_member)) \ + _len = sizeof((dst)->data_member); \ + (dst)->count_member = (src)->count_member; \ + memcpy((dst)->data_member, (src)->data_member, _len); \ + } while (0) + static void copy_dl_tti_request_pdcch_pdu(const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *src, nfapi_nr_dl_tti_pdcch_pdu_rel15_t *dst) { - dst->BWPSize = src->BWPSize; - dst->BWPStart = src->BWPStart; - dst->SubcarrierSpacing = src->SubcarrierSpacing; - dst->CyclicPrefix = src->CyclicPrefix; - dst->StartSymbolIndex = src->StartSymbolIndex; - dst->DurationSymbols = src->DurationSymbols; - for (int fdr_idx = 0; fdr_idx < 6; ++fdr_idx) { - dst->FreqDomainResource[fdr_idx] = src->FreqDomainResource[fdr_idx]; - } - dst->CceRegMappingType = src->CceRegMappingType; - dst->RegBundleSize = src->RegBundleSize; - dst->InterleaverSize = src->InterleaverSize; - dst->CoreSetType = src->CoreSetType; - dst->ShiftIndex = src->ShiftIndex; - dst->precoderGranularity = src->precoderGranularity; - dst->numDlDci = src->numDlDci; + PARTIAL_COPY(dst, src, nfapi_nr_dl_tti_pdcch_pdu_rel15_t, numDlDci); + size_t partial_size = offsetof(nfapi_nr_dl_tti_pdcch_pdu_rel15_t, dci_pdu); + memcpy(dst, src, partial_size); for (int dl_dci = 0; dl_dci < dst->numDlDci; ++dl_dci) { nfapi_nr_dl_dci_pdu_t *dst_dci_pdu = &dst->dci_pdu[dl_dci]; const nfapi_nr_dl_dci_pdu_t *src_dci_pdu = &src->dci_pdu[dl_dci]; - dst_dci_pdu->RNTI = src_dci_pdu->RNTI; - dst_dci_pdu->ScramblingId = src_dci_pdu->ScramblingId; - dst_dci_pdu->ScramblingRNTI = src_dci_pdu->ScramblingRNTI; - dst_dci_pdu->CceIndex = src_dci_pdu->CceIndex; - dst_dci_pdu->AggregationLevel = src_dci_pdu->AggregationLevel; + PARTIAL_COPY(dst_dci_pdu, src_dci_pdu, nfapi_nr_dl_dci_pdu_t, AggregationLevel); copy_dl_tti_beamforming(&src_dci_pdu->precodingAndBeamforming, &dst_dci_pdu->precodingAndBeamforming); - dst_dci_pdu->beta_PDCCH_1_0 = src_dci_pdu->beta_PDCCH_1_0; - dst_dci_pdu->powerControlOffsetSS = src_dci_pdu->powerControlOffsetSS; - dst_dci_pdu->PayloadSizeBits = src_dci_pdu->PayloadSizeBits; - for (int i = 0; i < 8; ++i) { - dst_dci_pdu->Payload[i] = src_dci_pdu->Payload[i]; - } + PARTIAL_COPY_RANGE(dst_dci_pdu, src_dci_pdu, nfapi_nr_dl_dci_pdu_t, beta_PDCCH_1_0, Payload); + } + dst->param_v4.numSpatialStreams = src->param_v4.numSpatialStreams; + for (uint_fast16_t i = 0; i < dst->param_v4.numSpatialStreams; i++) { + dst->param_v4.dci_spatialStreamIndices[i] = src->param_v4.dci_spatialStreamIndices[i]; } } static void copy_dl_tti_request_pdsch_pdu(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *src, nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dst) { - dst->pduBitmap = src->pduBitmap; - dst->rnti = src->rnti; - dst->pduIndex = src->pduIndex; - dst->BWPSize = src->BWPSize; - dst->BWPStart = src->BWPStart; - dst->SubcarrierSpacing = src->SubcarrierSpacing; - dst->CyclicPrefix = src->CyclicPrefix; - dst->NrOfCodewords = src->NrOfCodewords; - for (int cw = 0; cw < dst->NrOfCodewords; ++cw) { - dst->targetCodeRate[cw] = src->targetCodeRate[cw]; - dst->qamModOrder[cw] = src->qamModOrder[cw]; - dst->mcsIndex[cw] = src->mcsIndex[cw]; - dst->mcsTable[cw] = src->mcsTable[cw]; - dst->rvIndex[cw] = src->rvIndex[cw]; - dst->TBSize[cw] = src->TBSize[cw]; - } - dst->dataScramblingId = src->dataScramblingId; - dst->nrOfLayers = src->nrOfLayers; - dst->transmissionScheme = src->transmissionScheme; - dst->refPoint = src->refPoint; - dst->dlDmrsSymbPos = src->dlDmrsSymbPos; - dst->dmrsConfigType = src->dmrsConfigType; - dst->dlDmrsScramblingId = src->dlDmrsScramblingId; - dst->SCID = src->SCID; - dst->numDmrsCdmGrpsNoData = src->numDmrsCdmGrpsNoData; - dst->dmrsPorts = src->dmrsPorts; - dst->resourceAlloc = src->resourceAlloc; - for (int i = 0; i < 36; ++i) { - dst->rbBitmap[i] = src->rbBitmap[i]; - } - dst->rbStart = src->rbStart; - dst->rbSize = src->rbSize; - dst->VRBtoPRBMapping = src->VRBtoPRBMapping; - dst->StartSymbolIndex = src->StartSymbolIndex; - dst->NrOfSymbols = src->NrOfSymbols; - dst->PTRSPortIndex = src->PTRSPortIndex; - dst->PTRSTimeDensity = src->PTRSTimeDensity; - dst->PTRSFreqDensity = src->PTRSFreqDensity; - dst->PTRSReOffset = src->PTRSReOffset; - dst->nEpreRatioOfPDSCHToPTRS = src->nEpreRatioOfPDSCHToPTRS; + PARTIAL_COPY(dst, src, nfapi_nr_dl_tti_pdsch_pdu_rel15_t, nEpreRatioOfPDSCHToPTRS); copy_dl_tti_beamforming(&src->precodingAndBeamforming, &dst->precodingAndBeamforming); - dst->powerControlOffset = src->powerControlOffset; - dst->powerControlOffsetSS = src->powerControlOffsetSS; - dst->isLastCbPresent = src->isLastCbPresent; - dst->isInlineTbCrc = src->isInlineTbCrc; - dst->dlTbCrc = src->dlTbCrc; - dst->maintenance_parms_v3.ldpcBaseGraph = src->maintenance_parms_v3.ldpcBaseGraph; - dst->maintenance_parms_v3.tbSizeLbrmBytes = src->maintenance_parms_v3.tbSizeLbrmBytes; + PARTIAL_COPY_RANGE(dst, src, nfapi_nr_dl_tti_pdsch_pdu_rel15_t, powerControlOffset, maintenance_parms_v3); + dst->param_v4.numberCodewords = src->param_v4.numberCodewords; + for (uint_fast8_t i = 0; i < dst->param_v4.numberCodewords; i++) { + const nfapi_nr_spatial_stream_index_t *s = src->param_v4.spatialStreamsCw + i; + nfapi_nr_spatial_stream_index_t *d = dst->param_v4.spatialStreamsCw + i; + COPY_STRUCT_ARRAY(d, s, spatialStreamIndices, numSpatialStreamIndices); + } } static void copy_dl_tti_request_csi_rs_pdu(const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *src, nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *dst) { - dst->bwp_size = src->bwp_size; - dst->bwp_start = src->bwp_start; - dst->subcarrier_spacing = src->subcarrier_spacing; - dst->cyclic_prefix = src->cyclic_prefix; - dst->start_rb = src->start_rb; - dst->nr_of_rbs = src->nr_of_rbs; - dst->csi_type = src->csi_type; - dst->row = src->row; - dst->freq_domain = src->freq_domain; - dst->symb_l0 = src->symb_l0; - dst->symb_l1 = src->symb_l1; - dst->cdm_type = src->cdm_type; - dst->freq_density = src->freq_density; - dst->scramb_id = src->scramb_id; - dst->power_control_offset = src->power_control_offset; - dst->power_control_offset_ss = src->power_control_offset_ss; + PARTIAL_COPY(dst, src, nfapi_nr_dl_tti_csi_rs_pdu_rel15_t, power_control_offset_ss); copy_dl_tti_beamforming(&src->precodingAndBeamforming, &dst->precodingAndBeamforming); + const struct nfapi_nr_csi_spatial_stream_index *s = &src->param_v4; + struct nfapi_nr_csi_spatial_stream_index *d = &dst->param_v4; + COPY_STRUCT_ARRAY(d, s, spatialStreamIndices, numSpatialStreamIndices); } static void copy_dl_tti_request_ssb_pdu(const nfapi_nr_dl_tti_ssb_pdu_rel15_t *src, nfapi_nr_dl_tti_ssb_pdu_rel15_t *dst) { - dst->PhysCellId = src->PhysCellId; - dst->BetaPss = src->BetaPss; - dst->SsbBlockIndex = src->SsbBlockIndex; - dst->SsbSubcarrierOffset = src->SsbSubcarrierOffset; - dst->ssbOffsetPointA = src->ssbOffsetPointA; - dst->bchPayloadFlag = src->bchPayloadFlag; - dst->bchPayload = src->bchPayload; - dst->ssbRsrp = src->ssbRsrp; + PARTIAL_COPY(dst, src, nfapi_nr_dl_tti_ssb_pdu_rel15_t, ssbRsrp); copy_dl_tti_beamforming(&src->precoding_and_beamforming, &dst->precoding_and_beamforming); + dst->param_v4 = src->param_v4; } static void copy_dl_tti_request_pdu(const nfapi_nr_dl_tti_request_pdu_t *src, nfapi_nr_dl_tti_request_pdu_t *dst) @@ -1175,73 +1125,25 @@ static void copy_ul_tti_beamforming(const nfapi_nr_ul_beamforming_t *src, nfapi_ static void copy_ul_tti_request_prach_pdu(const nfapi_nr_prach_pdu_t *src, nfapi_nr_prach_pdu_t *dst) { - dst->phys_cell_id = src->phys_cell_id; - dst->num_prach_ocas = src->num_prach_ocas; - dst->prach_format = src->prach_format; - dst->num_ra = src->num_ra; - dst->prach_start_symbol = src->prach_start_symbol; - dst->num_cs = src->num_cs; + PARTIAL_COPY(dst, src, nfapi_nr_prach_pdu_t, num_cs); copy_ul_tti_beamforming(&src->beamforming, &dst->beamforming); + const nfapi_nr_spatial_stream_index_t *s = &src->param_v4; + nfapi_nr_spatial_stream_index_t *d = &dst->param_v4; + COPY_STRUCT_ARRAY(d, s, spatialStreamIndices, numSpatialStreamIndices); } static void copy_ul_tti_request_pusch_pdu(const nfapi_nr_pusch_pdu_t *src, nfapi_nr_pusch_pdu_t *dst) { - dst->pdu_bit_map = src->pdu_bit_map; - dst->rnti = src->rnti; - dst->handle = src->handle; - dst->bwp_size = src->bwp_size; - dst->bwp_start = src->bwp_start; - dst->subcarrier_spacing = src->subcarrier_spacing; - dst->cyclic_prefix = src->cyclic_prefix; - dst->target_code_rate = src->target_code_rate; - dst->qam_mod_order = src->qam_mod_order; - dst->mcs_index = src->mcs_index; - dst->mcs_table = src->mcs_table; - dst->transform_precoding = src->transform_precoding; - dst->data_scrambling_id = src->data_scrambling_id; - dst->nrOfLayers = src->nrOfLayers; - dst->ul_dmrs_symb_pos = src->ul_dmrs_symb_pos; - dst->dmrs_config_type = src->dmrs_config_type; - dst->ul_dmrs_scrambling_id = src->ul_dmrs_scrambling_id; - dst->pusch_identity = src->pusch_identity; - dst->scid = src->scid; - dst->num_dmrs_cdm_grps_no_data = src->num_dmrs_cdm_grps_no_data; - dst->dmrs_ports = src->dmrs_ports; - dst->resource_alloc = src->resource_alloc; - for (int i = 0; i < 36; ++i) { - dst->rb_bitmap[i] = src->rb_bitmap[i]; - } - dst->rb_start = src->rb_start; - dst->rb_size = src->rb_size; - dst->vrb_to_prb_mapping = src->vrb_to_prb_mapping; - dst->frequency_hopping = src->frequency_hopping; - dst->tx_direct_current_location = src->tx_direct_current_location; - dst->uplink_frequency_shift_7p5khz = src->uplink_frequency_shift_7p5khz; - dst->start_symbol_index = src->start_symbol_index; - dst->nr_of_symbols = src->nr_of_symbols; - + PARTIAL_COPY(dst, src, nfapi_nr_pusch_pdu_t, nr_of_symbols); if (dst->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_DATA) { const nfapi_nr_pusch_data_t *src_pusch_data = &src->pusch_data; nfapi_nr_pusch_data_t *dst_pusch_data = &dst->pusch_data; - dst_pusch_data->rv_index = src_pusch_data->rv_index; - dst_pusch_data->harq_process_id = src_pusch_data->harq_process_id; - dst_pusch_data->new_data_indicator = src_pusch_data->new_data_indicator; - dst_pusch_data->tb_size = src_pusch_data->tb_size; - dst_pusch_data->num_cb = src_pusch_data->num_cb; - for (int i = 0; i < (src_pusch_data->num_cb + 7) / 8; ++i) { - dst_pusch_data->cb_present_and_position[i] = src_pusch_data->cb_present_and_position[i]; - } + *dst_pusch_data = *src_pusch_data; } if (src->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_UCI) { const nfapi_nr_pusch_uci_t *src_pusch_uci = &src->pusch_uci; nfapi_nr_pusch_uci_t *dst_pusch_uci = &dst->pusch_uci; - dst_pusch_uci->harq_ack_bit_length = src_pusch_uci->harq_ack_bit_length; - dst_pusch_uci->csi_part1_bit_length = src_pusch_uci->csi_part1_bit_length; - dst_pusch_uci->csi_part2_bit_length = src_pusch_uci->csi_part2_bit_length; - dst_pusch_uci->alpha_scaling = src_pusch_uci->alpha_scaling; - dst_pusch_uci->beta_offset_harq_ack = src_pusch_uci->beta_offset_harq_ack; - dst_pusch_uci->beta_offset_csi1 = src_pusch_uci->beta_offset_csi1; - dst_pusch_uci->beta_offset_csi2 = src_pusch_uci->beta_offset_csi2; + *dst_pusch_uci = *src_pusch_uci; } if (src->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { const nfapi_nr_pusch_ptrs_t *src_pusch_ptrs = &src->pusch_ptrs; @@ -1252,10 +1154,7 @@ static void copy_ul_tti_request_pusch_pdu(const nfapi_nr_pusch_pdu_t *src, nfapi for (int i = 0; i < src_pusch_ptrs->num_ptrs_ports; ++i) { const nfapi_nr_ptrs_ports_t *src_ptrs_port = &src_pusch_ptrs->ptrs_ports_list[i]; nfapi_nr_ptrs_ports_t *dst_ptrs_port = &dst_pusch_ptrs->ptrs_ports_list[i]; - - dst_ptrs_port->ptrs_port_index = src_ptrs_port->ptrs_port_index; - dst_ptrs_port->ptrs_dmrs_port = src_ptrs_port->ptrs_dmrs_port; - dst_ptrs_port->ptrs_re_offset = src_ptrs_port->ptrs_re_offset; + *dst_ptrs_port = *src_ptrs_port; } dst_pusch_ptrs->ptrs_time_density = src_pusch_ptrs->ptrs_time_density; @@ -1265,50 +1164,23 @@ static void copy_ul_tti_request_pusch_pdu(const nfapi_nr_pusch_pdu_t *src, nfapi if (src->pdu_bit_map & PUSCH_PDU_BITMAP_DFTS_OFDM) { const nfapi_nr_dfts_ofdm_t *src_dfts_ofdm = &src->dfts_ofdm; nfapi_nr_dfts_ofdm_t *dst_dfts_ofdm = &dst->dfts_ofdm; - - dst_dfts_ofdm->low_papr_group_number = src_dfts_ofdm->low_papr_group_number; - dst_dfts_ofdm->low_papr_sequence_number = src_dfts_ofdm->low_papr_sequence_number; - dst_dfts_ofdm->ul_ptrs_sample_density = src_dfts_ofdm->ul_ptrs_sample_density; - dst_dfts_ofdm->ul_ptrs_time_density_transform_precoding = src_dfts_ofdm->ul_ptrs_time_density_transform_precoding; + *dst_dfts_ofdm = *src_dfts_ofdm; } copy_ul_tti_beamforming(&src->beamforming, &dst->beamforming); dst->maintenance_parms_v3.ldpcBaseGraph = src->maintenance_parms_v3.ldpcBaseGraph; dst->maintenance_parms_v3.tbSizeLbrmBytes = src->maintenance_parms_v3.tbSizeLbrmBytes; + const nfapi_nr_spatial_stream_index_t *s = &src->param_v4; + nfapi_nr_spatial_stream_index_t *d = &dst->param_v4; + COPY_STRUCT_ARRAY(d, s, spatialStreamIndices, numSpatialStreamIndices); } static void copy_ul_tti_request_pucch_pdu(const nfapi_nr_pucch_pdu_t *src, nfapi_nr_pucch_pdu_t *dst) { - dst->rnti = src->rnti; - dst->handle = src->handle; - dst->bwp_size = src->bwp_size; - dst->bwp_start = src->bwp_start; - dst->subcarrier_spacing = src->subcarrier_spacing; - dst->cyclic_prefix = src->cyclic_prefix; - dst->format_type = src->format_type; - dst->multi_slot_tx_indicator = src->multi_slot_tx_indicator; - dst->pi_2bpsk = src->pi_2bpsk; - dst->prb_start = src->prb_start; - dst->prb_size = src->prb_size; - dst->start_symbol_index = src->start_symbol_index; - dst->nr_of_symbols = src->nr_of_symbols; - dst->freq_hop_flag = src->freq_hop_flag; - dst->second_hop_prb = src->second_hop_prb; - dst->group_hop_flag = src->group_hop_flag; - dst->sequence_hop_flag = src->sequence_hop_flag; - dst->hopping_id = src->hopping_id; - dst->initial_cyclic_shift = src->initial_cyclic_shift; - dst->data_scrambling_id = src->data_scrambling_id; - dst->time_domain_occ_idx = src->time_domain_occ_idx; - dst->pre_dft_occ_idx = src->pre_dft_occ_idx; - dst->pre_dft_occ_len = src->pre_dft_occ_len; - dst->add_dmrs_flag = src->add_dmrs_flag; - dst->dmrs_scrambling_id = src->dmrs_scrambling_id; - dst->dmrs_cyclic_shift = src->dmrs_cyclic_shift; - dst->sr_flag = src->sr_flag; - dst->bit_len_harq = src->bit_len_harq; - dst->bit_len_csi_part1 = src->bit_len_csi_part1; - dst->bit_len_csi_part2 = src->bit_len_csi_part2; + PARTIAL_COPY(dst, src, nfapi_nr_pucch_pdu_t, bit_len_csi_part2); copy_ul_tti_beamforming(&src->beamforming, &dst->beamforming); + const nfapi_nr_spatial_stream_index_t *s = &src->param_v4; + nfapi_nr_spatial_stream_index_t *d = &dst->param_v4; + COPY_STRUCT_ARRAY(d, s, spatialStreamIndices, numSpatialStreamIndices); } static void copy_ul_tti_request_srs_parameters(const nfapi_v4_srs_parameters_t *src, @@ -1316,24 +1188,20 @@ static void copy_ul_tti_request_srs_parameters(const nfapi_v4_srs_parameters_t * nfapi_v4_srs_parameters_t *dst) { dst->srs_bandwidth_size = src->srs_bandwidth_size; - for (int symbol_idx = 0; symbol_idx < num_symbols; ++symbol_idx) { - nfapi_v4_srs_parameters_symbols_t *dst_symbol = &dst->symbol_list[symbol_idx]; - const nfapi_v4_srs_parameters_symbols_t *src_symbol = &src->symbol_list[symbol_idx]; - dst_symbol->srs_bandwidth_start = src_symbol->srs_bandwidth_start; - dst_symbol->sequence_group = src_symbol->sequence_group; - dst_symbol->sequence_number = src_symbol->sequence_number; - } - #ifdef ENABLE_AERIAL // For Aerial, we always process the 4 reported symbols, not only the ones indicated by num_symbols - for (int symbol_idx = num_symbols; symbol_idx < 4; ++symbol_idx) { + const uint8_t symbols_to_fill = 4; + (void)num_symbols; // To supress unused warning +#else + const uint8_t symbols_to_fill = num_symbols; +#endif // ENABLE_AERIAL + for (uint_fast8_t symbol_idx = 0; symbol_idx < symbols_to_fill; ++symbol_idx) { nfapi_v4_srs_parameters_symbols_t *dst_symbol = &dst->symbol_list[symbol_idx]; const nfapi_v4_srs_parameters_symbols_t *src_symbol = &src->symbol_list[symbol_idx]; dst_symbol->srs_bandwidth_start = src_symbol->srs_bandwidth_start; dst_symbol->sequence_group = src_symbol->sequence_group; dst_symbol->sequence_number = src_symbol->sequence_number; } -#endif // ENABLE_AERIAL dst->usage = src->usage; const uint8_t nUsage = __builtin_popcount(dst->usage); for (int idx = 0; idx < nUsage; ++idx) { @@ -1346,37 +1214,12 @@ static void copy_ul_tti_request_srs_parameters(const nfapi_v4_srs_parameters_t * dst->ue_antennas_in_this_srs_resource_set = src->ue_antennas_in_this_srs_resource_set; dst->sampled_ue_antennas = src->sampled_ue_antennas; dst->report_scope = src->report_scope; - dst->num_ul_spatial_streams_ports = src->num_ul_spatial_streams_ports; - for (int idx = 0; idx < dst->num_ul_spatial_streams_ports; ++idx) { - dst->Ul_spatial_stream_ports[idx] = src->Ul_spatial_stream_ports[idx]; - } + COPY_STRUCT_ARRAY(dst, src, Ul_spatial_stream_ports, num_ul_spatial_streams_ports); } static void copy_ul_tti_request_srs_pdu(const nfapi_nr_srs_pdu_t *src, nfapi_nr_srs_pdu_t *dst) { - dst->rnti = src->rnti; - dst->handle = src->handle; - dst->bwp_size = src->bwp_size; - dst->bwp_start = src->bwp_start; - dst->subcarrier_spacing = src->subcarrier_spacing; - dst->cyclic_prefix = src->cyclic_prefix; - dst->num_ant_ports = src->num_ant_ports; - dst->num_symbols = src->num_symbols; - dst->num_repetitions = src->num_repetitions; - dst->time_start_position = src->time_start_position; - dst->config_index = src->config_index; - dst->sequence_id = src->sequence_id; - dst->bandwidth_index = src->bandwidth_index; - dst->comb_size = src->comb_size; - dst->comb_offset = src->comb_offset; - dst->cyclic_shift = src->cyclic_shift; - dst->frequency_position = src->frequency_position; - dst->frequency_shift = src->frequency_shift; - dst->frequency_hopping = src->frequency_hopping; - dst->group_or_sequence_hopping = src->group_or_sequence_hopping; - dst->resource_type = src->resource_type; - dst->t_srs = src->t_srs; - dst->t_offset = src->t_offset; + PARTIAL_COPY(dst, src, nfapi_nr_srs_pdu_t, t_offset); copy_ul_tti_beamforming(&src->beamforming, &dst->beamforming); copy_ul_tti_request_srs_parameters(&src->srs_parameters_v4, 1 << src->num_symbols, &dst->srs_parameters_v4); } 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 c779cd1a0f..cbb38399b2 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 @@ -853,6 +853,21 @@ typedef struct { } nfapi_nr_dl_dci_pdu_t; +// The maximum number of spatial streams to be mapped depends on TLV 0x16E and +// the number of streams could be same as number of layers or number of antenna +// ports or number of baseband ports. Hence we set this to be the maximum number +// of baseband ports +#define MAX_NUM_SPATIAL_STREAMS 16 + +typedef struct { + uint16_t dci_index; + uint16_t spatial_stream_index; +} nfapi_v4_dci_spatial_stream_index_t; + +typedef struct { + uint16_t numSpatialStreams; + nfapi_v4_dci_spatial_stream_index_t dci_spatialStreamIndices[MAX_NUM_SPATIAL_STREAMS]; +} nfapi_v4_pdcch_pdu_parameters_t; typedef struct { ///Bandwidth part size [TS38.213 sec12]. Number of contiguous PRBs allocated to the BWP,Value: 1->275 @@ -885,13 +900,32 @@ typedef struct { uint16_t numDlDci; ///DL DCI PDU nfapi_nr_dl_dci_pdu_t dci_pdu[MAX_DCI_CORESET]; -} nfapi_nr_dl_tti_pdcch_pdu_rel15_t; + /// Spatial stream indexing for MU-MIMO + nfapi_v4_pdcch_pdu_parameters_t param_v4; +} nfapi_nr_dl_tti_pdcch_pdu_rel15_t; typedef struct { uint8_t ldpcBaseGraph; uint32_t tbSizeLbrmBytes; }nfapi_v3_pdsch_maintenance_parameters_t; +typedef struct { + /// Number of spatial streams used in the index array + uint8_t numSpatialStreamIndices; + /// Spatial stream index array + uint16_t spatialStreamIndices[MAX_NUM_SPATIAL_STREAMS]; +} nfapi_nr_spatial_stream_index_t; + +#define MAX_NUM_CODEWORDS 2 + +typedef struct { + // MU-MIMO support in FAPIv4 + /// Number of codewords with spatial stream indices + uint8_t numberCodewords; + /// Spatial stream indexing for codeworeds + nfapi_nr_spatial_stream_index_t spatialStreamsCw[MAX_NUM_CODEWORDS]; +} nfapi_v4_pdsch_parameters_t; + typedef struct { uint16_t pduBitmap; uint16_t rnti; @@ -984,8 +1018,9 @@ typedef struct { uint32_t dlTbCrc; nfapi_v3_pdsch_maintenance_parameters_t maintenance_parms_v3; -}nfapi_nr_dl_tti_pdsch_pdu_rel15_t; - + /// PDSCH parameters FAPI v4. used only for spatial stream indexing in MU-MIMO + nfapi_v4_pdsch_parameters_t param_v4; +} nfapi_nr_dl_tti_pdsch_pdu_rel15_t; //for pdsch_pdu: /* @@ -1069,9 +1104,15 @@ typedef struct uint8_t power_control_offset; // Ratio of PDSCH EPRE to NZP CSI-RSEPRE [3GPP TS 38.214, sec 5.2.2.3.1], Value: 0->23 representing -8 to 15 dB in 1dB steps; 255: L1 is configured with ProfileSSS uint8_t power_control_offset_ss; // Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE [3GPP TS 38.214, sec 5.2.2.3.1], Values: 0: -3dB; 1: 0dB; 2: 3dB; 3: 6dB; 255: L1 is configured with ProfileSSS nfapi_nr_tx_precoding_and_beamforming_t precodingAndBeamforming; + /// Spatial stream indexing for MU-MIMO + struct nfapi_nr_csi_spatial_stream_index { + /// Number of spatial streams used in the index array + uint8_t numSpatialStreamIndices; + /// Spatial stream index array + uint8_t spatialStreamIndices[MAX_NUM_SPATIAL_STREAMS]; + } param_v4; } nfapi_nr_dl_tti_csi_rs_pdu_rel15_t; - typedef struct { uint32_t bch_payload;//BCH payload. The valid bits are indicated in the PARAM/CONFIG TLVs. If PARAM/CONFIG TLVs indicate MAC generates full bchPayload then the payload length is 31 bits with the 8 LSB bits being. Otherwise timing PBCH bits are generated by the PHY. And for bchPayload the 24 LSB are used. @@ -1112,6 +1153,11 @@ typedef struct { /// A value indicating the channel quality between the gNB and nrUE. Value: 0->255 dBM uint8_t ssbRsrp; nfapi_nr_tx_precoding_and_beamforming_t precoding_and_beamforming; + /// Spatial stream indexing + struct nfapi_v4_ssb_param { + uint8_t spatialStreamIndexPresent; + uint16_t spatialStreamIndex; + } param_v4; } nfapi_nr_dl_tti_ssb_pdu_rel15_t; typedef struct { @@ -1279,7 +1325,7 @@ typedef struct uint8_t prach_start_symbol; uint16_t num_cs; nfapi_nr_ul_beamforming_t beamforming; - + nfapi_nr_spatial_stream_index_t param_v4; } nfapi_nr_prach_pdu_t; //for pusch_pdu: @@ -1392,6 +1438,8 @@ typedef struct //beamforming nfapi_nr_ul_beamforming_t beamforming; nfapi_v3_pdsch_maintenance_parameters_t maintenance_parms_v3; + // Spatial stream indexing for MU-MIMO + nfapi_nr_spatial_stream_index_t param_v4; } nfapi_nr_pusch_pdu_t; //for pucch_pdu: @@ -1437,7 +1485,7 @@ typedef struct uint16_t bit_len_csi_part2; nfapi_nr_ul_beamforming_t beamforming; - + nfapi_nr_spatial_stream_index_t param_v4; } nfapi_nr_pucch_pdu_t; typedef struct { diff --git a/nfapi/tests/p7/nr_fapi_common_util_test.h b/nfapi/tests/p7/nr_fapi_common_util_test.h new file mode 100644 index 0000000000..0d9d906724 --- /dev/null +++ b/nfapi/tests/p7/nr_fapi_common_util_test.h @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ +#ifndef OPENAIRINTERFACE_NR_FAPI_COMMON_UTIL_TEST_H +#define OPENAIRINTERFACE_NR_FAPI_COMMON_UTIL_TEST_H +#include "nfapi/tests/nr_fapi_test.h" + +static uint8_t get_num_spatial_streams(void) +{ + const uint16_t max_logical_ant_ports = MAX_NUM_SPATIAL_STREAMS; + return rand8_range(0, max_logical_ant_ports); +} + +static void fill_spatial_streams(const uint8_t num_s, uint16_t s[MAX_NUM_SPATIAL_STREAMS]) +{ + for (int n = 0; n < num_s; n++) + s[n] = rand16_range(0, num_s - 1); +} + +#endif diff --git a/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c b/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c index 58b8ac08ce..dbc781187e 100644 --- a/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c +++ b/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c @@ -4,6 +4,7 @@ #include "dci_payload_utils.h" #include "nr_fapi_p7.h" #include "nr_fapi_p7_utils.h" +#include "nr_fapi_common_util_test.h" static void fill_dl_tti_request_beamforming(nfapi_nr_tx_precoding_and_beamforming_t *precodingAndBeamforming) { @@ -48,6 +49,11 @@ static void fill_dl_tti_request_pdcch_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdu pdu->dci_pdu[dl_dci].PayloadSizeBits = rand16_range(0, DCI_PAYLOAD_BYTE_LEN * 8); generate_payload(pdu->dci_pdu[dl_dci].PayloadSizeBits, pdu->dci_pdu[dl_dci].Payload); } + pdu->param_v4.numSpatialStreams = get_num_spatial_streams(); + for (int n = 0; n < pdu->param_v4.numSpatialStreams; n++) { + pdu->param_v4.dci_spatialStreamIndices[n].dci_index = rand16(); + pdu->param_v4.dci_spatialStreamIndices[n].spatial_stream_index = rand16_range(0, pdu->param_v4.numSpatialStreams - 1); + } } static void fill_dl_tti_request_pdsch_pdu(nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdu) @@ -109,6 +115,12 @@ static void fill_dl_tti_request_pdsch_pdu(nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdu } pdu->maintenance_parms_v3.ldpcBaseGraph = rand8(); pdu->maintenance_parms_v3.tbSizeLbrmBytes = rand32(); + pdu->param_v4.numberCodewords = rand8_range(0, MAX_NUM_CODEWORDS); + for (int c = 0; c < pdu->param_v4.numberCodewords; c++) { + pdu->param_v4.spatialStreamsCw[c].numSpatialStreamIndices = get_num_spatial_streams(); + fill_spatial_streams(pdu->param_v4.spatialStreamsCw[c].numSpatialStreamIndices, + pdu->param_v4.spatialStreamsCw[c].spatialStreamIndices); + } } static void fill_dl_tti_request_csi_rs_pdu(nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *pdu) @@ -147,6 +159,9 @@ static void fill_dl_tti_request_csi_rs_pdu(nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *p pdu->power_control_offset = rand8_range(0, 23); pdu->power_control_offset_ss = rand8_range(0, 3); fill_dl_tti_request_beamforming(&pdu->precodingAndBeamforming); + pdu->param_v4.numSpatialStreamIndices = get_num_spatial_streams(); + for (int n = 0; n < pdu->param_v4.numSpatialStreamIndices; n++) + pdu->param_v4.spatialStreamIndices[n] = rand8_range(0, pdu->param_v4.numSpatialStreamIndices - 1); } static void fill_dl_tti_request_ssb_pdu(nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu) @@ -159,6 +174,8 @@ static void fill_dl_tti_request_ssb_pdu(nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu) pdu->bchPayloadFlag = rand8_range(0, 2); pdu->bchPayload = rand24(); fill_dl_tti_request_beamforming(&pdu->precoding_and_beamforming); + pdu->param_v4.spatialStreamIndexPresent = rand8(0, 1); + pdu->param_v4.spatialStreamIndex = rand16_range(0, MAX_NUM_SPATIAL_STREAMS); } static void fill_dl_tti_request(nfapi_nr_dl_tti_request_t *msg) diff --git a/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c b/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c index d30a4892ec..bcd6a7a752 100644 --- a/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c +++ b/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c @@ -4,6 +4,7 @@ #include "dci_payload_utils.h" #include "nr_fapi_p7.h" #include "nr_fapi_p7_utils.h" +#include "nr_fapi_common_util_test.h" static void fill_ul_tti_request_beamforming(nfapi_nr_ul_beamforming_t *beamforming_pdu) { @@ -28,6 +29,8 @@ static void fill_ul_tti_request_prach_pdu(nfapi_nr_prach_pdu_t *pdu) pdu->prach_start_symbol = rand8_range(0, 13); pdu->num_cs = rand16_range(0, 419); fill_ul_tti_request_beamforming(&pdu->beamforming); + pdu->param_v4.numSpatialStreamIndices = get_num_spatial_streams(); + fill_spatial_streams(pdu->param_v4.numSpatialStreamIndices, pdu->param_v4.spatialStreamIndices); } static void fill_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pdu) @@ -133,6 +136,8 @@ static void fill_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pdu) fill_ul_tti_request_beamforming(&pdu->beamforming); pdu->maintenance_parms_v3.ldpcBaseGraph = rand8(); pdu->maintenance_parms_v3.tbSizeLbrmBytes = rand32(); + pdu->param_v4.numSpatialStreamIndices = get_num_spatial_streams(); + fill_spatial_streams(pdu->param_v4.numSpatialStreamIndices, pdu->param_v4.spatialStreamIndices); } static void fill_ul_tti_request_pucch_pdu(nfapi_nr_pucch_pdu_t *pdu) @@ -247,6 +252,8 @@ static void fill_ul_tti_request_pucch_pdu(nfapi_nr_pucch_pdu_t *pdu) } fill_ul_tti_request_beamforming(&pdu->beamforming); + pdu->param_v4.numSpatialStreamIndices = get_num_spatial_streams(); + fill_spatial_streams(pdu->param_v4.numSpatialStreamIndices, pdu->param_v4.spatialStreamIndices); } static void fill_ul_tti_request_srs_parameters(nfapi_v4_srs_parameters_t *params, const uint8_t num_symbols){ diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 9ae2e0a1ab..5f14d0df4a 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -146,23 +146,19 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) /* Do NOT allocate per-antenna rxdataF: the gNB gets a pointer to the * RU to copy/recover freq-domain memory from there */ - common_vars->rxdataF = (c16_t ***)malloc16(common_vars->num_beams_period * sizeof(c16_t**)); - for (int i = 0; i < common_vars->num_beams_period; i++) - common_vars->rxdataF[i] = (c16_t **)malloc16(Prx * sizeof(c16_t*)); + common_vars->rxdataF = malloc16_clear(Prx * sizeof(*common_vars->rxdataF)); + /* beam_id array is common for tx and rx so the max number of both is taken */ + const unsigned int num_antenna_ports = max(Ptx, Prx); 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(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); - memset(common_vars->beam_id[i], -1, fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); - } - } - common_vars->txdataF = (c16_t ***)malloc16(common_vars->num_beams_period * sizeof(c16_t**)); - for (int i = 0; i < common_vars->num_beams_period; i++) { - common_vars->txdataF[i] = (c16_t**)malloc16_clear(Ptx * sizeof(c16_t*)); - for (int j = 0; j < Ptx; j++) - common_vars->txdataF[i][j] = (c16_t*)malloc16_clear(fp->samples_per_slot_wCP * sizeof(c16_t)); + common_vars->beam_id = (uint16_t **)malloc16(fp->slots_per_frame * fp->symbols_per_slot * sizeof(*common_vars->beam_id)); + for (int i = 0; i < fp->slots_per_frame * fp->symbols_per_slot; i++) + common_vars->beam_id[i] = (uint16_t *)malloc16_clear(num_antenna_ports * sizeof(**common_vars->beam_id)); } + + common_vars->txdataF = (c16_t **)malloc16_clear(Ptx * sizeof(*common_vars->txdataF)); + for (int j = 0; j < Ptx; j++) + common_vars->txdataF[j] = (c16_t *)malloc16_clear(fp->samples_per_slot_wCP * sizeof(**common_vars->txdataF)); common_vars->debugBuff = (int32_t*)malloc16_clear(fp->samples_per_frame*sizeof(int32_t)*100); common_vars->debugBuff_sample_offset = 0; @@ -197,7 +193,6 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) void phy_free_nr_gNB(PHY_VARS_gNB *gNB) { - const int Ptx = gNB->gNB_config.carrier_config.num_tx_ant.value; const int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value; const int max_ul_mimo_layers = NR_MAX_NB_LAYERS; const int n_buf = Prx * max_ul_mimo_layers; @@ -214,22 +209,21 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) destroy_DLSCH_struct(gNB); NR_gNB_COMMON * common_vars = &gNB->common_vars; - for (int j = 0; j < common_vars->num_beams_period; j++) { - if (common_vars->beam_id) + if (common_vars->beam_id) { + for (int j = 0; j < gNB->frame_parms.slots_per_frame * gNB->frame_parms.symbols_per_slot; j++) { free_and_zero(common_vars->beam_id[j]); - for (int i = 0; i < Ptx; i++) { - free_and_zero(common_vars->txdataF[j][i]); } - free_and_zero(common_vars->txdataF[j]); } + free_and_zero(common_vars->beam_id); + + for (int i = 0; i < gNB->frame_parms.nb_antennas_tx; i++) { + free_and_zero(common_vars->txdataF[i]); + } + free_and_zero(common_vars->txdataF); /* Do NOT free per-antenna txdataF/rxdataF: the gNB gets a pointer to the * RU's txdataF/rxdataF, and the RU will free that */ - for (int j = 0; j < common_vars->num_beams_period; j++) - free_and_zero(common_vars->rxdataF[j]); - free_and_zero(common_vars->txdataF); free_and_zero(common_vars->rxdataF); - free_and_zero(common_vars->beam_id); free_and_zero(common_vars->debugBuff); @@ -250,7 +244,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free(gNB->pusch_vars); free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface); - } void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 71ad18ab62..f1bf8a2330 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -15,32 +15,21 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n", ru_if_types[ru->if_south], ru->nb_tx, ru->nb_rx); - ru->num_beams_period = 1; - if (ru->num_gNB > 0) { - nfapi_nr_config_request_scf_t *cfg = &ru->config; - ru->nb_log_antennas = 0; - for (int n = 0; n < ru->num_gNB; n++) { - if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas) - ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value; - } - 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; - } - else ru->nb_log_antennas = ru->nb_tx; - // copy configuration from gNB[0] in to RU, assume that all gNB instances sharing RU use the same configuration // (at least the parts that are needed by the RU, numerology and PRACH) - AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas); - 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(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); - memset(ru->common.beam_id[i], -1, fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + int nb_tx_streams = ru->nb_tx; + int nb_rx_streams = ru->nb_rx; + LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d\n", nb_tx_streams, nb_rx_streams); + const unsigned int num_symbols = fp->symbols_per_slot * fp->slots_per_frame; + ru->common.beam_id = malloc16_clear(num_symbols * sizeof(*ru->common.beam_id)); + for (int i = 0; i < num_symbols; i++) { + ru->common.beam_id[i] = malloc16_clear(nb_tx_streams * sizeof(**ru->common.beam_id)); } + if ((nb_tx_streams > fp->nb_antennas_tx) || (nb_rx_streams > fp->nb_antennas_rx)) + LOG_W(NR_PHY, "There could be unused baseband ports because of fewer logical ports.\n"); + 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(nb_tx_streams * sizeof(int32_t*)); @@ -107,8 +96,8 @@ 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; + int nb_tx_streams = ru->nb_tx; + int nb_rx_streams = ru->nb_rx; 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 @@ -143,7 +132,8 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.rxdataF[i]); free_and_zero(ru->common.rxdataF); - for(int i = 0; i < ru->num_beams_period; ++i) + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + for (int i = 0; i < fp->symbols_per_slot * fp->slots_per_frame; ++i) free_and_zero(ru->common.beam_id[i]); free_and_zero(ru->common.beam_id); } diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 1f8be0fa38..bd37dfa2e8 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -133,7 +133,10 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy unsigned int tmp_n0_subband[frame_parms->nb_antennas_rx][frame_parms->N_RB_UL]; memset(tmp_n0_subband, 0, sizeof(tmp_n0_subband)); - // TODO modify the measurements to take into account concurrent beams + /* Noise measurements is done on all spatial streams here. Later these + measurements are used in estimating SNR of individual signal with their + corresponding streams. + */ for (int s = first_symb; s < first_symb + num_symb; s++) { int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; for (int rb = 0; rb < frame_parms->N_RB_UL; rb++) { @@ -142,11 +145,11 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy int offset = offset0 + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; nb_symb[rb]++; for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - c16_t *ul_ch = &common_vars->rxdataF[0][aarx][offset]; + c16_t *ul_ch = &common_vars->rxdataF[aarx][offset]; int32_t signal_energy; if (((frame_parms->N_RB_UL & 1) == 1) && (rb == (frame_parms->N_RB_UL >> 1))) { signal_energy = signal_energy_nodc(ul_ch, 6); - ul_ch = &common_vars->rxdataF[0][aarx][offset0]; + ul_ch = &common_vars->rxdataF[aarx][offset0]; signal_energy += signal_energy_nodc(ul_ch, 6); } else { signal_energy = signal_energy_nodc(ul_ch, 12); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 445deaac74..1a69d4fbd1 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -33,7 +33,7 @@ typedef struct puschAntennaProc_s { unsigned char symbol; unsigned short bwp_start_subcarrier; int aarx; - int beam_nb; + uint16_t ant_port_start; int numAntennas; const nfapi_nr_pusch_pdu_t *pusch_pdu; int *max_ch; @@ -44,7 +44,7 @@ typedef struct puschAntennaProc_s { int chest_freq; NR_gNB_PUSCH *pusch_vars; NR_DL_FRAME_PARMS *frame_parms; - c16_t ***rxdataF; + c16_t **rxdataF; task_ans_t *ans; scopeData_t *scope; c16_t *pusch_ch_est_dmrs_pos_slot_mem; @@ -100,12 +100,13 @@ static void nr_pusch_antenna_processing(void *arg) const int symbol_offset = symbolSize * symbol; const int k0 = bwp_start_subcarrier; const int nb_rb_pusch = pusch_pdu->rb_size; - const int beam_nb = rdata->beam_nb; + const int aa_start = rdata->ant_port_start; + const uint8_t num_sp_streams = rdata->pusch_pdu->param_v4.numSpatialStreamIndices; for (int antenna = aarx; antenna < aarx + numAntennas; antenna++) { c16_t ul_ls_est[symbolSize] __attribute__((aligned(32))); memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize); - c16_t *rxdataF = (c16_t *)&rdata->rxdataF[beam_nb][antenna][symbol_offset + slot_offset]; - c16_t *ul_ch = &ul_ch_estimates[nl * frame_parms->nb_antennas_rx + antenna][symbol_offset]; + c16_t *rxdataF = (c16_t *)&rdata->rxdataF[aa_start + antenna][symbol_offset + slot_offset]; + c16_t *ul_ch = &ul_ch_estimates[nl * num_sp_streams + antenna][symbol_offset]; memset(ul_ch, 0, sizeof(*ul_ch) * symbolSize); LOG_D(PHY, @@ -220,7 +221,7 @@ static void nr_pusch_antenna_processing(void *arg) // Revert delay pilot_cnt = 0; - ul_ch = &ul_ch_estimates[nl * frame_parms->nb_antennas_rx + antenna][symbol_offset]; + ul_ch = &ul_ch_estimates[nl * num_sp_streams + antenna][symbol_offset]; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *ul_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; for (int n = 0; n < 3 * nb_rb_pusch; n++) { @@ -432,7 +433,7 @@ static void nr_pusch_antenna_processing(void *arg) } #ifdef DEBUG_PUSCH - ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset]; + ul_ch = &ul_ch_estimates[nl * num_sp_streams + aarx][symbol_offset]; for (int idxP = 0; idxP < ceil((float)nb_rb_pusch * 12 / 8); idxP++) { for (int idxI = 0; idxI < 8; idxI++) { printf("%d\t%d\t", ul_ch[idxP * 8 + idxI].r, ul_ch[idxP * 8 + idxI].i); @@ -454,7 +455,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, uint8_t lp, unsigned char symbol, NR_gNB_PUSCH *pusch_vars, - int beam_nb, + uint16_t ant_port_start, unsigned short bwp_start_subcarrier, const nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, @@ -538,7 +539,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, delay_t *delay = &pusch_vars->delay; memset(delay, 0, sizeof(*delay)); - int nb_antennas_rx = fp->nb_antennas_rx; + int nb_antennas_rx = pusch_pdu->param_v4.numSpatialStreamIndices; delay_t delay_arr[nb_antennas_rx]; uint64_t noise_amp2_arr[nb_antennas_rx]; int max_ch_arr[nb_antennas_rx]; @@ -555,7 +556,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, initNotifiedFIFO(&respPuschAarx); start_meas(&gNB->pusch_channel_estimation_antenna_processing_stats); int numAntennas = gNB->dmrs_num_antennas_per_thread; - int num_jobs = CEILIDIV(fp->nb_antennas_rx, numAntennas); + int num_jobs = CEILIDIV(nb_antennas_rx, numAntennas); puschAntennaProc_t rdatas[num_jobs]; memset(rdatas, 0, sizeof(rdatas)); task_ans_t ans; @@ -578,7 +579,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, rdata->nest_count = &nest_count_arr[rdata->aarx]; rdata->noise_amp2 = &noise_amp2_arr[rdata->aarx]; rdata->delay = &delay_arr[rdata->aarx]; - rdata->beam_nb = beam_nb; + rdata->ant_port_start = ant_port_start; rdata->frame_parms = fp; rdata->pusch_vars = pusch_vars; rdata->chest_freq = gNB->chest_freq; @@ -599,14 +600,14 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, join_task_ans(&ans); stop_meas(&gNB->pusch_channel_estimation_antenna_processing_stats); - for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) { + for (int aarx = 0; aarx < nb_antennas_rx; aarx++) { *max_ch = max(*max_ch, max_ch_arr[aarx]); noise_amp2 += noise_amp2_arr[aarx]; nest_count += nest_count_arr[aarx]; } // get the maximum delay *delay = delay_arr[0]; - for (int aarx = 1; aarx < fp->nb_antennas_rx; aarx++) { + for (int aarx = 1; aarx < nb_antennas_rx; aarx++) { if (delay_arr[aarx].est_delay >= delay->est_delay) { *delay = delay_arr[aarx]; } @@ -651,6 +652,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_vars, uint8_t nr_tti_rx, unsigned char symbol, + int nb_rx_ant, uint32_t nb_re_pusch) { int32_t *ptrs_re_symbol = NULL; @@ -665,7 +667,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, uint8_t ptrsReOffset = rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; /* loop over antennas */ - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { + for (int aarx = 0; aarx < nb_rx_ant; aarx++) { c16_t *phase_per_symbol = (c16_t *)pusch_vars->ptrs_phase_per_slot[aarx]; ptrs_re_symbol = &pusch_vars->ptrs_re_per_slot; *ptrs_re_symbol = 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 91f6d40647..59fa993d74 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -31,7 +31,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, uint8_t lp, unsigned char symbol, NR_gNB_PUSCH *pusch_vars, - int beam_nb, + uint16_t ant_port_start, unsigned short bwp_start_subcarrier, const nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, @@ -57,6 +57,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_vars, uint8_t nr_tti_rx, unsigned char symbol, + int nb_rx_ant, uint32_t nb_re_pusch); int nr_srs_ls_channel_estimation(int ant, diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c index 83a21995eb..c1a81c924f 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -242,7 +242,8 @@ void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, uint8_t start_symbol, uint16_t dmrs_bitmap, uint16_t num_rbs, - uint8_t nb_layers) + uint8_t nb_layers, + uint8_t num_streams) { simde__m128i *ul_ch128_0; simde__m128i *ul_ch128_1; @@ -252,8 +253,8 @@ void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, int first_dmrs_symb = get_next_dmrs_symbol_in_slot(dmrs_bitmap, start_symbol, total_symbols); AssertFatal(first_dmrs_symb > -1, "No DMRS symbol present in this slot\n"); for (int nl = 0; nl < nb_layers; nl++) { - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - int ch_offset = nl * frame_parms->nb_antennas_rx + aarx; + for (int aarx = 0; aarx < num_streams; aarx++) { + int ch_offset = nl * num_streams + aarx; for (int symb = first_dmrs_symb + 1; symb < total_symbols; symb++) { ul_ch128_0 = (simde__m128i *)&ch_estimates[ch_offset][first_dmrs_symb * frame_parms->ofdm_symbol_size]; if ((dmrs_bitmap >> symb) & 0x01) { diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.h b/openair1/PHY/NR_REFSIG/dmrs_nr.h index 1c250663fc..52dbe0ed32 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.h +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.h @@ -38,7 +38,8 @@ void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, uint8_t start_symbol, uint16_t dmrs_bitmap, uint16_t num_rbs, - uint8_t nb_layers); + uint8_t nb_layers, + uint8_t num_streams); int8_t get_num_dmrs_re_per_rb(const uint8_t dmrs_type, const uint8_t num_cdm_grp_no_data); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 7743a648b5..952d0fceb1 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -27,6 +27,19 @@ static void nr_pdcch_scrambling(uint32_t *in, uint32_t size, uint32_t Nid, uint3 out[i] = in[i] ^ seq[i]; } +static inline uint16_t get_dci_ant_port_index(const nfapi_v4_pdcch_pdu_parameters_t *p, int dci_index) +{ + uint16_t dci_ant_idx = 0; + for (uint_fast16_t i = 0; i < p->numSpatialStreams; i++) { + if (dci_index == p->dci_spatialStreamIndices[i].dci_index) { + // Return at first find because DCIs use only one antenna port at the moment + dci_ant_idx = p->dci_spatialStreamIndices[i].spatial_stream_index; + break; + } + } + return dci_ant_idx; +} + void nr_generate_dci(PHY_VARS_gNB *gNB, const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, NR_DL_FRAME_PARMS *frame_parms, @@ -59,13 +72,21 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, uint32_t cset_nsymb = pdcch_pdu_rel15->DurationSymbols; 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(gNB->enable_analog_das, - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->common_vars, - slot, - frame_parms->symbols_per_slot, - bitmap); + uint16_t symb_bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); + uint16_t beam_id = dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; + uint16_t dci_spatial_stream_index = get_first_ant_idx(gNB->enable_analog_das, + frame_parms->nb_antennas_tx / gNB->common_vars.num_beams_period, + beam_id, + get_dci_ant_port_index(&pdcch_pdu_rel15->param_v4, d)); + + beam_index_allocation(beam_id, + dci_spatial_stream_index, + 1, // Only one antenna port for DCI + frame_parms->symbols_per_slot, + slot, + symb_bitmap, + frame_parms->nb_antennas_tx, + gNB->common_vars.beam_id); LOG_D(NR_PHY_DCI, "pdcch: Coreset rb_offset %d, nb_rb %d BWP Start %d\n", rb_offset, n_rb, pdcch_pdu_rel15->BWPStart); LOG_D(NR_PHY_DCI, @@ -154,7 +175,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, /// Resource mapping uint16_t amp = gNB->TX_AMP; - c16_t *txdataF = gNB->common_vars.txdataF[beam_nb][0]; + c16_t *txdataF = gNB->common_vars.txdataF[dci_spatial_stream_index]; int num_regs = dci_pdu->AggregationLevel * NR_NB_REG_PER_CCE / pdcch_pdu_rel15->DurationSymbols; /*Mapping the encoded DCI along with the DMRS */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 33198ae329..9a18e9cdc1 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -499,7 +499,7 @@ typedef struct pdschSymbolProc_s { unsigned int layerSz2; unsigned int dlPtrsSymPos; unsigned int n_ptrs; - unsigned int beam_nb; + uint16_t *ant_to_map; unsigned int re_beginning_of_symbol[14]; c16_t *tx_layers[4]; time_stats_t dlsch_resource_mapping_stats; @@ -524,7 +524,7 @@ static void nr_pdsch_symbol_processing(void *arg) c16_t mod_dmrs[(n_dmrs + 63) & ~63] __attribute__((aligned(64))); const int symbol_sz = frame_parms->ofdm_symbol_size; - c16_t **txdataF = gNB->common_vars.txdataF[rdata->beam_nb]; + c16_t **txdataF = gNB->common_vars.txdataF; for (int l_symbol = rdata->startSymbol; l_symbol < rdata->startSymbol + rdata->numSymbols; l_symbol++) { start_meas(&rdata->dlsch_resource_mapping_stats); @@ -579,7 +579,9 @@ static void nr_pdsch_symbol_processing(void *arg) start_meas(&rdata->dlsch_precoding_stats); const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz; - for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) { + const uint16_t num_log_ports = + rel15->param_v4.numberCodewords ? rel15->param_v4.spatialStreamsCw[0].numSpatialStreamIndices : 0; + for (int ant = 0; ant < num_log_ports; ant++) { int pos = 0; int block_start, block_end; while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) { @@ -588,7 +590,7 @@ static void nr_pdsch_symbol_processing(void *arg) txdataF_precoding, gNB, rel15, - ant, + rdata->ant_to_map[ant], block_start, block_end - block_start + 1, txdataF_offset_per_symbol); @@ -705,13 +707,24 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // The Codebook Type I const 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(gNB->enable_analog_das, - pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->common_vars, - slot, - frame_parms->symbols_per_slot, - bitmap); + const uint16_t symb_bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); + uint16_t ant_to_map[frame_parms->nb_antennas_tx]; + const uint16_t num_log_ports = rel15->param_v4.numberCodewords ? rel15->param_v4.spatialStreamsCw[0].numSpatialStreamIndices : 0; + for (int ant = 0; ant < num_log_ports; ant++) { + const uint16_t beam_id = pb->prgs_list[0].dig_bf_interface_list[ant].beam_idx; + ant_to_map[ant] = get_first_ant_idx(gNB->enable_analog_das, + frame_parms->nb_antennas_tx / gNB->common_vars.num_beams_period, + beam_id, + rel15->param_v4.spatialStreamsCw[0].spatialStreamIndices[ant]); + beam_index_allocation(beam_id, + ant_to_map[ant], + 1, + frame_parms->symbols_per_slot, + slot, + symb_bitmap, + frame_parms->nb_antennas_tx, + gNB->common_vars.beam_id); + } stop_meas(&gNB->dlsch_layer_mapping_stats); // spawn symbol threads @@ -751,7 +764,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC rdata->layerSz2 = layerSz2; rdata->dlPtrsSymPos = dlPtrsSymPos; rdata->n_ptrs = n_ptrs; - rdata->beam_nb = beam_nb; + rdata->ant_to_map = ant_to_map; for (int s = l_symbol; s < l_symbol + rdata->numSymbols; s++) { rdata->re_beginning_of_symbol[s] = re_beginning_of_symbol; re_beginning_of_symbol += freq_alloc->num_rbs * NR_NB_SC_PER_RB; diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 24b08290de..d3bc04f3f8 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -66,6 +66,7 @@ void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_p const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; const nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; const nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; + const int num_rx_per_beam = gNB->frame_parms.nb_antennas_rx / gNB->common_vars.num_beams_period; prach_item_t prach = { .frame = SFN, .slot = Slot, @@ -78,27 +79,34 @@ void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_p .prach_sequence_length = cfg->prach_sequence_length.value, .restricted_set = cfg->restricted_set_config.value, .numerology_index = fp->numerology_index, - .nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value, + .nb_rx = num_rx_per_beam, .Xu = gNB->X_u, .rx_prach = &gNB->rx_prach, // TODO can be made permanently allocated? .prach_buf = calloc_or_fail(1, sizeof(c16_t) * prach.nb_rx * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L), }; - if (gNB->common_vars.beam_id) { - int n_symb = get_nr_prach_duration(prach_pdu->prach_format); - AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, - "impossible beams size %d\n", - prach_pdu->beamforming.dig_bf_interface); - 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.beams[i] = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - Slot, - gNB->frame_parms.symbols_per_slot, - bitmap); + const int num_beams = prach_pdu->beamforming.dig_bf_interface; + int n_symb = get_nr_prach_duration(prach_pdu->prach_format); + AssertFatal(num_beams < NFAPI_MAX_NUM_BG_IF, "impossible beams size %d\n", num_beams); + for (int i = 0; i < num_beams; 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); + if (gNB->common_vars.beam_id) { + // TODO: Remove assumption of contiguous ports after DAS is properly handled in beamforming + uint16_t ant_start = get_first_ant_idx(gNB->enable_analog_das, + num_rx_per_beam, + fapi_beam_idx, + prach_pdu->param_v4.spatialStreamIndices[i * num_rx_per_beam]); + beam_index_allocation(fapi_beam_idx, + ant_start, + num_rx_per_beam, + NR_SYMBOLS_PER_SLOT, + Slot, + bitmap, + gNB->frame_parms.nb_antennas_rx, + gNB->common_vars.beam_id); + prach.ant_start = ant_start; } } bool found = spsc_q_put(&gNB->prach_ru_queue, &prach, sizeof(prach)); @@ -107,12 +115,12 @@ void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_p } static void rx_nr_prach_ru_internal(prach_item_t *p, - int beam_id, int prachStartSymbol, int prachOccasion, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, - int N_TA_offset) + int N_TA_offset, + bool das) { int sample_offset_slot; const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples; @@ -338,10 +346,23 @@ static void rx_nr_prach_ru_internal(prach_item_t *p, k*=K; k+=kbar; + const uint8_t num_beams = p->pdu.beamforming.dig_bf_interface; + // When more than one beams, then each occasion is on one beam + int ant_offset = 0; + if (num_beams > 1) { + AssertFatal(prachOccasion < num_beams, "Num of PRACH Occasions must be same as number of beams in beamforming mode\n"); + ant_offset = prachOccasion * p->nb_rx; + } + // TODO: Remove assumption of contiguous ports after DAS is properly handled in beamforming + uint16_t ant_start = + get_first_ant_idx(das, + p->nb_rx, + p->pdu.beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + p->pdu.param_v4.numSpatialStreamIndices > 0 ? p->pdu.param_v4.spatialStreamIndices[ant_offset] : 0); for (int aa = 0; aa < p->nb_rx; aa++) { // Fixme: slot or slot makes no sense ??? int slot2 = p->prach_sequence_length ? p->slot : p->slot; - int idx = aa + beam_id * p->nb_rx; + int idx = ant_start + aa; c16_t *prach = (c16_t *)&rxdata[idx][get_samples_slot_timestamp(fp, slot2) + sample_offset_slot - N_TA_offset]; // do DFT @@ -365,17 +386,16 @@ static void rx_nr_prach_ru_internal(prach_item_t *p, } } -void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, int N_TA_offset) +void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, int N_TA_offset, bool das) { int N_dur = get_nr_prach_duration(p->pdu.prach_format); LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", p->frame, p->slot, p->pdu.num_prach_ocas); for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) { int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur; - int beam_id = p->beams[prach_oc]; // 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_internal(p, beam_id, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset); + rx_nr_prach_ru_internal(p, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset, das); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 863903c242..89b0eb044e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -97,8 +97,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, const nfapi_nr_pusch_pdu_t *rel15_ul, uint32_t *ret_unav_res, uint32_t frame, - uint8_t slot, - int beam_nb); + uint8_t slot); /*! \brief This function implements the idft transform precoding in PUSCH @@ -177,7 +176,7 @@ typedef struct rx_prach_out { } rx_prach_out_t; rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion); -void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset); +void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset, bool das); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 51d885cc1e..f92643aca0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -105,12 +105,17 @@ 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); - pusch.beam_nb = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); + const nfapi_nr_spatial_stream_index_t *p = &ulsch_pdu->param_v4; + // We assume the ports are ordered continuously. Hence only the start port idx is enough. + uint16_t ant_port_start = p->numSpatialStreamIndices > 0 ? p->spatialStreamIndices[0] : 0; + beam_index_allocation(fapi_beam_idx, + ant_port_start, + p->numSpatialStreamIndices, + NR_SYMBOLS_PER_SLOT, + slot, + bitmap, + gNB->frame_parms.nb_antennas_rx, + gNB->common_vars.beam_id); } bool done = spsc_q_put(&gNB->pusch_queue, &pusch, sizeof(pusch)); if (!done) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 9e0a4248b9..8199a6fea0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -143,7 +143,8 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, if (stats) { stats->frame = frame; stats->ulsch_stats.round_trials[harq_process->round]++; - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { + const uint8_t num_streams = pusch_pdu->param_v4.numSpatialStreamIndices; + for (int aarx = 0; aarx < num_streams; aarx++) { stats->ulsch_stats.power[aarx] = dB_fixed_x10(pusch->ulsch_power[aarx]); stats->ulsch_stats.noise_power[aarx] = dB_fixed_x10(pusch->ulsch_noise_power[aarx]); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 0827771e88..31d4ac6efd 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -17,7 +17,7 @@ #include "T.h" #include "T_messages_creator.h" #include - +#include "openair1/SCHED_NR/sched_nr.h" #if T_TRACER static void copy_c16_data_to_slot_memory(c16_t *src, c16_t *dst_slot, int nb_re_pusch, int symbol) @@ -872,7 +872,7 @@ static void inner_rx(PHY_VARS_gNB *gNB, time_stats_t *ulsch_llr) { int nb_layer = rel15_ul->nrOfLayers; - int nb_rx_ant = frame_parms->nb_antennas_rx; + int nb_rx_ant = rel15_ul->param_v4.numSpatialStreamIndices; int dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; int buffer_length = ceil_mod(rel15_ul->rb_size * NR_NB_SC_PER_RB, 16); c16_t rxFext[nb_rx_ant][buffer_length] __attribute__((aligned(64))); @@ -962,6 +962,7 @@ static void inner_rx(PHY_VARS_gNB *gNB, pusch_vars, slot, symbol, + nb_rx_ant, buffer_length); pusch_vars->ul_valid_re_per_slot[symbol] -= pusch_vars->ptrs_re_per_slot; } @@ -1025,6 +1026,8 @@ typedef struct puschSymbolProc_s { time_stats_t ulsch_llr; time_stats_t ul_demap; time_stats_t ul_unscram; + // TODO: Remove assumption of contiguous ports after DAS is properly handled in beamforming + uint16_t ant_port_start; task_ans_t *ans; c16_t *pusch_ch_est_dmrs_interpl_slot_mem; c16_t *rxFext_slot_mem; @@ -1054,7 +1057,7 @@ static void nr_pusch_symbol_processing(void *arg) frame_parms, pusch_vars, rel15_ul, - gNB->common_vars.rxdataF[rdata->beam_nb], + gNB->common_vars.rxdataF + rdata->ant_port_start, llrss, soffset, symbol, @@ -1127,10 +1130,14 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, const nfapi_nr_pusch_pdu_t *rel15_ul, uint32_t *ret_unav_res, uint32_t frame, - uint8_t slot, - int beam_nb) + uint8_t slot) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + const nfapi_nr_spatial_stream_index_t *p = &rel15_ul->param_v4; + uint16_t ant_port_start = get_first_ant_idx(gNB->enable_analog_das, + frame_parms->nb_antennas_tx / gNB->common_vars.num_beams_period, + rel15_ul->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + p->numSpatialStreamIndices > 0 ? p->spatialStreamIndices[0] : 0); uint32_t bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start) * NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); @@ -1191,7 +1198,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, dmrs_symb_idx, symbol, pusch_vars, - beam_nb, + ant_port_start, bwp_start_subcarrier, rel15_ul, &max_ch, @@ -1214,30 +1221,33 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, frame_parms->N_RB_UL, false); + const uint8_t num_sp_streams = rel15_ul->param_v4.numSpatialStreamIndices; int start_sc = (rel15_ul->bwp_start + rel15_ul->rb_start) * NR_NB_SC_PER_RB; int middle_sc = frame_parms->ofdm_symbol_size - frame_parms->first_carrier_offset; int end_sc = (start_sc + rel15_ul->rb_size * NR_NB_SC_PER_RB - 1) % frame_parms->ofdm_symbol_size; - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - pusch_vars->ulsch_power[aarx] = 0; - pusch_vars->ulsch_noise_power[aarx] = 0; + for (int aa_pusch = 0; aa_pusch < num_sp_streams; aa_pusch++) { + const int aarx = ant_port_start + aa_pusch; + DevAssert(aarx < sizeofArray(pusch_vars->ulsch_power)); + pusch_vars->ulsch_power[aa_pusch] = 0; + pusch_vars->ulsch_noise_power[aa_pusch] = 0; int64_t symb_energy = 0; for (uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol++) { int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + symbol) * frame_parms->ofdm_symbol_size; int offset = offset0 + (frame_parms->first_carrier_offset + start_sc) % frame_parms->ofdm_symbol_size; - c16_t *ul_ch = &gNB->common_vars.rxdataF[beam_nb][aarx][offset]; + c16_t *ul_ch = &gNB->common_vars.rxdataF[aarx][offset]; if (end_sc < start_sc) { int64_t symb_energy_aux = signal_energy_nodc(ul_ch, middle_sc - start_sc) * (middle_sc - start_sc); - ul_ch = &gNB->common_vars.rxdataF[beam_nb][aarx][offset0]; + ul_ch = &gNB->common_vars.rxdataF[aarx][offset0]; symb_energy_aux += (signal_energy_nodc(ul_ch, end_sc + 1) * (end_sc + 1)); symb_energy += symb_energy_aux / (rel15_ul->rb_size * NR_NB_SC_PER_RB); } else { symb_energy += signal_energy_nodc(ul_ch, rel15_ul->rb_size * NR_NB_SC_PER_RB); } } - pusch_vars->ulsch_power[aarx] += (symb_energy / rel15_ul->nr_of_symbols); + pusch_vars->ulsch_power[aa_pusch] += (symb_energy / rel15_ul->nr_of_symbols); - pusch_vars->ulsch_noise_power[aarx] += + pusch_vars->ulsch_noise_power[aa_pusch] += average_u32(&n0_subband_power[aarx][rel15_ul->bwp_start + rel15_ul->rb_start], rel15_ul->rb_size); LOG_D(PHY, @@ -1246,8 +1256,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, rel15_ul->bwp_start, rel15_ul->rb_start, rel15_ul->rb_size, - pusch_vars->ulsch_power[aarx], - pusch_vars->ulsch_noise_power[aarx]); + pusch_vars->ulsch_power[aa_pusch], + pusch_vars->ulsch_noise_power[aa_pusch]); } // averaging time domain channel estimates @@ -1258,7 +1268,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, rel15_ul->start_symbol_index, rel15_ul->ul_dmrs_symb_pos, rel15_ul->rb_size, - rel15_ul->nrOfLayers); + rel15_ul->nrOfLayers, + num_sp_streams); stop_meas(&gNB->ulsch_channel_estimation_stats); @@ -1325,17 +1336,17 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, else // average of channel estimates stored in first symbol dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, end_symbol); int size_est = nb_re_pusch * frame_parms->symbols_per_slot; - __attribute__((aligned(64))) int ul_ch_estimates_ext[rel15_ul->nrOfLayers * frame_parms->nb_antennas_rx][size_est]; + __attribute__((aligned(32))) int ul_ch_estimates_ext[rel15_ul->nrOfLayers * num_sp_streams][size_est]; memset(ul_ch_estimates_ext, 0, sizeof(ul_ch_estimates_ext)); int buffer_length = rel15_ul->rb_size * NR_NB_SC_PER_RB; - c16_t temp_rxFext[frame_parms->nb_antennas_rx][buffer_length] __attribute__((aligned(64))); - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) + c16_t temp_rxFext[num_sp_streams][buffer_length] __attribute__((aligned(32))); + for (int aarx = 0; aarx < num_sp_streams; aarx++) for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++) { start_meas(&gNB->pusch_extraction_stats); - nr_ulsch_extract_rbs(gNB->common_vars.rxdataF[beam_nb][aarx], - (c16_t *)pusch_vars->ul_ch_estimates[nl * frame_parms->nb_antennas_rx + aarx], + nr_ulsch_extract_rbs(gNB->common_vars.rxdataF[ant_port_start + aarx], + (c16_t *)pusch_vars->ul_ch_estimates[nl * num_sp_streams + aarx], temp_rxFext[aarx], - (c16_t*)&ul_ch_estimates_ext[nl * frame_parms->nb_antennas_rx + aarx][meas_symbol * nb_re_pusch], + (c16_t *)&ul_ch_estimates_ext[nl * num_sp_streams + aarx][meas_symbol * nb_re_pusch], soffset + meas_symbol * frame_parms->ofdm_symbol_size, dmrs_symbol * frame_parms->ofdm_symbol_size, (rel15_ul->ul_dmrs_symb_pos >> meas_symbol) & 0x01, @@ -1349,34 +1360,28 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, //---------------------------------------------------------- //--------------------- Channel Scaling -------------------- //---------------------------------------------------------- - nr_scale_channel(size_est, - ul_ch_estimates_ext, - meas_symbol, - nb_re_pusch, - rel15_ul->nrOfLayers, - frame_parms->nb_antennas_rx, - shift_ch_ext); + nr_scale_channel(size_est, ul_ch_estimates_ext, meas_symbol, nb_re_pusch, rel15_ul->nrOfLayers, num_sp_streams, shift_ch_ext); - int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers]; + int avg[num_sp_streams * rel15_ul->nrOfLayers]; nr_channel_level(meas_symbol, size_est, - (c16_t (*)[size_est])ul_ch_estimates_ext, - frame_parms->nb_antennas_rx, + (c16_t(*)[size_est])ul_ch_estimates_ext, + num_sp_streams, rel15_ul->nrOfLayers, avg, nb_re_pusch); int avgs = 0; for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++) - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) - avgs = cmax(avgs, avg[nl * frame_parms->nb_antennas_rx + aarx]); + for (int aarx = 0; aarx < num_sp_streams; aarx++) + avgs = cmax(avgs, avg[nl * num_sp_streams + aarx]); if (rel15_ul->nrOfLayers == 2 && rel15_ul->qam_mod_order > 6) pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 3; // for MMSE else if (rel15_ul->nrOfLayers == 2) - pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 2 + log2_approx(frame_parms->nb_antennas_rx >> 1); - else - pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(frame_parms->nb_antennas_rx >> 1); + pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 2 + log2_approx(num_sp_streams >> 1); + else + pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(num_sp_streams >> 1); if (pusch_vars->log2_maxh < 0) pusch_vars->log2_maxh = 0; @@ -1419,7 +1424,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, rdata->llr = pusch_vars->llr; rdata->scramblingSequence = scramblingSequence; rdata->nvar = nvar; - rdata->beam_nb = beam_nb; + rdata->ant_port_start = ant_port_start; rdata->rxFext_slot_mem = rxFext_slot_mem; rdata->pusch_ch_est_dmrs_interpl_slot_mem = pusch_ch_est_dmrs_interpl_slot_mem; reset_meas(&rdata->pusch_extr); @@ -1454,16 +1459,24 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, (const c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4); - log_ul_fd_pusch_iq(frame, slot, frame_parms, rel15_ul, - number_dmrs_symbols, dmrs_port, + log_ul_fd_pusch_iq(frame, + slot, + frame_parms, + rel15_ul, + number_dmrs_symbols, + dmrs_port, (const c16_t *)(&(rxFext_slot_mem[0])), - rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4); + rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * num_sp_streams * 4); - log_ul_fd_chan_est_dmrs_interpl(frame, slot, frame_parms, rel15_ul, - number_dmrs_symbols, dmrs_port, - (const c16_t *)pusch_ch_est_dmrs_interpl_slot_mem, - rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols - * frame_parms->nb_antennas_rx * rel15_ul->nrOfLayers * 4); + log_ul_fd_chan_est_dmrs_interpl( + frame, + slot, + frame_parms, + rel15_ul, + number_dmrs_symbols, + dmrs_port, + (const c16_t *)pusch_ch_est_dmrs_interpl_slot_mem, + rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * num_sp_streams * rel15_ul->nrOfLayers * 4); #endif join_task_ans(&ans); diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 6720abdd6c..aa5d97d624 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -46,12 +46,9 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t 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(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); + const nfapi_nr_spatial_stream_index_t *p = &pucch_pdu->param_v4; + const uint16_t ant_port = p->numSpatialStreamIndices > 0 ? p->spatialStreamIndices[0] : 0; + beam_index_allocation(fapi_beam_idx, ant_port, 1, NR_SYMBOLS_PER_SLOT, slot, bitmap, gNB->frame_parms.nb_antennas_rx, gNB->common_vars.beam_id); } bool found = spsc_q_put(&gNB->pucch_queue, &pucch, sizeof(pucch)); if (!found) @@ -206,8 +203,10 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, x_re[1] = table_5_2_2_2_2_Re[u[1]]; x_im[1] = table_5_2_2_2_2_Im[u[1]]; - c64_t xr[frame_parms->nb_antennas_rx][pucch_pdu->nr_of_symbols][12] __attribute__((aligned(32))); - memset(xr, 0, frame_parms->nb_antennas_rx * pucch_pdu->nr_of_symbols * 12 * sizeof(c64_t)); + const uint8_t num_sp_streams = pucch_pdu->param_v4.numSpatialStreamIndices; + + c64_t xr[num_sp_streams][pucch_pdu->nr_of_symbols][12] __attribute__((aligned(32))); + memset(xr, 0, sizeof(xr)); int64_t xrtmag = 0, xrtmag_next = 0; uint8_t maxpos = 0; @@ -223,7 +222,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, if (re_offset[l] >= frame_parms->ofdm_symbol_size) re_offset[l] -= frame_parms->ofdm_symbol_size; - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + for (int aa = 0; aa < num_sp_streams; aa++) { c16_t rp[nb_re_pucch]; memset(rp, 0, sizeof(rp)); c16_t *tmp_rp = &rxdataF[aa][soffset + l2 * frame_parms->ofdm_symbol_size]; @@ -248,7 +247,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, signal_energy_ant0 += energ; } } - signal_energy /= (pucch_pdu->nr_of_symbols * frame_parms->nb_antennas_rx); + signal_energy /= (pucch_pdu->nr_of_symbols * num_sp_streams); signal_energy_ant0 /= pucch_pdu->nr_of_symbols; int pucch_power_dBtimes10 = 10 * dB_fixed(signal_energy); @@ -256,8 +255,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int seq_index = 0; for (int i = 0; i < nr_sequences; i++) { - c64_t corr[frame_parms->nb_antennas_rx][2]; - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + c64_t corr[num_sp_streams][2]; + for (int aa = 0; aa < num_sp_streams; aa++) { for (int l = 0; l < pucch_pdu->nr_of_symbols; l++) { seq_index = (pucch_pdu->initial_cyclic_shift + mcs[i] + gNB->pucch0_lut.lut[cs_ind][slot][l + pucch_pdu->start_symbol_index]) % 12; @@ -291,10 +290,10 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int64_t temp = 0; if (pucch_pdu->freq_hop_flag == 0) { if (pucch_pdu->nr_of_symbols == 1) { // non-coherent correlation - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) + for (int aa = 0; aa < num_sp_streams; aa++) temp += squaredMod(corr[aa][0]); } else { - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + for (int aa = 0; aa < num_sp_streams; aa++) { c64_t corr2; csum(corr2, corr[aa][0], corr[aa][1]); // coherent combining of 2 symbols and then complex modulus for @@ -304,7 +303,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, } } else { // full non-coherent combining of 2 symbols for frequency-hopping case - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) + for (int aa = 0; aa < num_sp_streams; aa++) temp += squaredMod(corr[aa][0]) + squaredMod(corr[aa][1]); } @@ -315,7 +314,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, maxpos = i; uci_stats->current_pucch0_stat0 = 0; int64_t temp2 = 0, temp3 = 0; - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + for (int aa = 0; aa < num_sp_streams; aa++) { temp2 += squaredMod(corr[aa][0]); if (pucch_pdu->nr_of_symbols == 2) temp3 += squaredMod(corr[aa][1]); @@ -483,7 +482,7 @@ void nr_decode_pucch1(PHY_VARS_gNB *gNB, * */ NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - uint8_t n_rx = frame_parms->nb_antennas_rx; + const uint8_t n_rx = pucch_pdu->param_v4.numSpatialStreamIndices; const int soffset = (slot & 3) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the @@ -1152,7 +1151,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, } AssertFatal(pucch_pdu->prb_size * nb_symbols > 1, "number of PRB*SYMB (%d,%d)< 2", pucch_pdu->prb_size, nb_symbols); - int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value; + int Prx = pucch_pdu->param_v4.numSpatialStreamIndices; // AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of2\n",pucch_pdu->prb_size); // use 2 for Nb antennas in case of single antenna to allow the following allocations const int nb_re_pucch = 12 * pucch_pdu->prb_size; diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 554226ea4d..967fe3e629 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -34,12 +34,17 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu const uint8_t l0 = srs_pdu->time_start_position; // L2 already sends the absolute symbol index int bitmap = SL_to_bitmap(l0, 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(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); + const nfapi_v4_srs_parameters_t *p = &srs_pdu->srs_parameters_v4; + // We assume the ports are sequential so taking the first port index here + const uint16_t ant_port_start = p->num_ul_spatial_streams_ports > 0 ? p->Ul_spatial_stream_ports[0] : 0; + beam_index_allocation(fapi_beam_idx, + ant_port_start, + p->num_ul_spatial_streams_ports, + NR_SYMBOLS_PER_SLOT, + slot, + bitmap, + gNB->frame_parms.nb_antennas_rx, + gNB->common_vars.beam_id); } bool found = spsc_q_put(&gNB->srs_queue, &srs, sizeof(srs)); if (!found) @@ -65,9 +70,10 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, const uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; const uint8_t K_TC = 2 << srs_pdu->comb_size; const uint16_t M_sc_b_SRS = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index) * NR_NB_SC_PER_RB / K_TC; + const uint8_t num_sp_streams = srs_pdu->srs_parameters_v4.num_ul_spatial_streams_ports; bool no_srs_signal = true; - for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { + for (int ant = 0; ant < num_sp_streams; ant++) { memset(srs_received_signal[ant], 0, frame_parms->ofdm_symbol_size * sizeof(c16_t)); memset(srs_received_noise[ant], 0, frame_parms->ofdm_symbol_size * sizeof(c16_t)); c16_t *rx_signal = &rxdataF[ant][symbol_offset]; diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 7a2e885279..7081b0820b 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -101,7 +101,7 @@ typedef struct { /// \brief Anaglogue beam ID for each OFDM symbol (used when beamforming not done in RU) /// - first index: concurrent beam /// - second index: beam_id [0.. symbols_per_frame[ - int **beam_id; + uint16_t **beam_id; } RU_COMMON; @@ -435,10 +435,6 @@ 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 int max_pdschReferenceSignalPower; /// maximum RX gain diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index dc4c72a82f..6b3236a76e 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -32,7 +32,6 @@ typedef struct { int frame; int slot; int num_slots; // prach duration in slots - int beams[NFAPI_MAX_NUM_BG_IF]; nfapi_nr_prach_pdu_t pdu; int rootSequenceIndex; int numrootSequenceIndex; @@ -42,6 +41,7 @@ typedef struct { int restricted_set; int numerology_index; int nb_rx; + int ant_start; c16_t (*Xu)[839]; time_stats_t *rx_prach; c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L]; @@ -159,8 +159,6 @@ typedef struct { typedef struct { uint32_t frame; uint32_t slot; - // identifier for concurrent beams - int beam_nb; uint32_t unav_res; /// Pointers to 16 HARQ processes for the ULSCH NR_UL_gNB_HARQ_t *harq_process; @@ -177,8 +175,6 @@ typedef struct { } NR_gNB_ULSCH_t; typedef struct { - // identifier for concurrent beams - int beam_nb; /// Frame where current PUSCH pdu was sent uint32_t frame; /// Slot where current PUSCH pdu was sent @@ -188,8 +184,6 @@ typedef struct { } NR_gNB_PUSCH_job_t; typedef struct { - // identifier for concurrent beams - int beam_nb; /// Frame where current PUCCH pdu was sent uint32_t frame; /// Slot where current PUCCH pdu was sent @@ -199,8 +193,6 @@ typedef struct { } NR_gNB_PUCCH_job_t; typedef struct { - // identifier for concurrent beams - int beam_nb; /// Frame where current SRS pdu was received uint32_t frame; /// Slot where current SRS pdu was received @@ -211,19 +203,19 @@ typedef struct { typedef struct { /// \brief Pointers (dynamic) to the received data in the frequency domain. - /// - first index: rx antenna [0..nb_antennas_rx[ - /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[ - c16_t ***rxdataF; + /// - first index: tx antenna [0..16) where 16 is the total supported antenna ports. + /// - second index: [0..4*ofdm_symbol_size*symbols_per_slot) + c16_t **rxdataF; /// \brief holds the transmit data in the frequency domain. /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. //? - /// - first index: beam (for concurrent beams) - /// - second index: tx antenna [0..14[ where 14 is the total supported antenna ports. - /// - third index: sample [0..samples_per_frame_woCP] - c16_t ***txdataF; + /// - first index: tx antenna [0..16) where 16 is the total supported antenna ports. + /// - second index: sample [0..ofdm_symbol_size*symbols_per_frame) + c16_t **txdataF; /// \brief Anaglogue beam ID for each OFDM symbol (used when beamforming not done in RU) - /// - first index: beam index (for concurrent beams) - /// - second index: beam_id [0.. symbols_per_frame[ - int **beam_id; + /// - first index: symbol index [0 .. symbols_per_frame) + /// - second index: beam ID for each antenna port [0 .. num_ports) + /// Array of beam id assigned to antenna ports in a frame + uint16_t **beam_id; int num_beams_period; bool analog_bf; int32_t *debugBuff; @@ -411,10 +403,6 @@ typedef struct PHY_VARS_gNB_s { /// counter to average prach energh over first 100 prach opportunities int prach_energy_counter; - int ap_N1; - int ap_N2; - int ap_XP; - int pucch0_thres; int pusch_thres; int prach_thres; diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 68dc731f64..2c5065c67a 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -151,27 +151,22 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; start_meas(&ru->precoding_stats); + // Copy beam ID assigned to all ports in this slot 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)); + for (int i = 0; i < fp->symbols_per_slot; i++) { + memcpy(ru->common.beam_id[slot_tx * fp->symbols_per_slot + i], + gNB->common_vars.beam_id[slot_tx * fp->symbols_per_slot + i], + (ru->nb_tx) * sizeof(**ru->common.beam_id)); } } if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) return; - int Ptx = cfg->carrier_config.num_tx_ant.value; // 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 < Ptx; ++i) { - int tx_idx = i + b * ru->nb_tx; - memcpy((void *)ru->common.txdataF_BF[tx_idx], - (void *)gNB->common_vars.txdataF[b][i], - fp->samples_per_slot_wCP * sizeof(int32_t)); - } + for (int i = 0; i < fp->nb_antennas_tx; ++i) { + memcpy(ru->common.txdataF_BF[i], gNB->common_vars.txdataF[i], fp->samples_per_slot_wCP * sizeof(int32_t)); } } else { AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); @@ -187,30 +182,20 @@ 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; - int tx_idx = aa + bb * ru->nb_tx; - - if (tx_idx == 0) + if (aa == 0) start_meas(&ru->precoding_stats); - 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) { // FFT shift const NR_DL_FRAME_PARMS *fp = &ru->gNB_list[0]->frame_parms; - fft_shift(ru->gNB_list[0]->common_vars.txdataF[bb][aa], + fft_shift(ru->gNB_list[0]->common_vars.txdataF[aa], fp->ofdm_symbol_size, fp->N_RB_DL, - (c16_t *)ru->common.txdataF_BF[tx_idx], + (c16_t *)ru->common.txdataF_BF[aa], fp->ofdm_symbol_size, startSymbol, numSymbols); @@ -218,11 +203,11 @@ void nr_feptx(void *arg) AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } - if (tx_idx == 0) + if (aa == 0) stop_meas(&ru->precoding_stats); ////////////FEPTX//////////// - nr_feptx0(ru, slot, startSymbol, numSymbols, tx_idx); + nr_feptx0(ru, slot, startSymbol, numSymbols, aa); // Task completed in // completed_task_ans(feptx->ans); @@ -236,42 +221,47 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) return; start_meas(&ru->ofdm_total_stats); - int nt = ru->nb_tx * ru->num_beams_period; + const NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + int nt = fp->nb_antennas_tx; 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); + // Copy beam IDs + if (ru->gNB_list[0]->common_vars.analog_bf) { + for (uint_fast16_t i = 0; i < fp->symbols_per_slot; i++) + memcpy(ru->common.beam_id[slot * fp->symbols_per_slot + i], + ru->gNB_list[0]->common_vars.beam_id[slot * fp->symbols_per_slot + i], + (ru->nb_tx) * sizeof(**ru->common.beam_id)); + } + int nbfeptx = 0; - for (int beam = 0; beam < ru->num_beams_period; beam++) { - for (int aid = 0; aid < ru->nb_tx; aid++) { + for (int aid = 0; aid < nt; 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) { 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 = 0; - feptx_cmd->numSymbols = - (ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_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++; - 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); @@ -304,13 +294,13 @@ void nr_fep_tp(RU_t *ru, int slot) int nbfeprx = 0; start_meas(&ru->ofdm_demod_stats); - int nt = ru->nb_rx * ru->num_beams_period; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + int nt = fp->nb_antennas_rx; int tasks_per_slot = (ru->half_slot_parallelization > 0) ? 2 : 1; size_t const sz = nt * tasks_per_slot; feprx_cmd_t arr[sz]; task_ans_t ans; init_task_ans(&ans, sz); - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int rxdataF_offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; int symbols_per_task = fp->symbols_per_slot / tasks_per_slot; @@ -321,22 +311,20 @@ void nr_fep_tp(RU_t *ru, int slot) if (task_idx == tasks_per_slot - 1) end_symbol = fp->symbols_per_slot - 1; - 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->fp = fp; - feprx_cmd->slot = ru->proc.tti_rx; - feprx_cmd->startSymbol = start_symbol; - feprx_cmd->endSymbol = end_symbol; - feprx_cmd->rxdata = (const c16_t *)ru->common.rxdata[aid + beam * ru->nb_rx]; - feprx_cmd->rxdataF = (c16_t *)&ru->common.rxdataF[aid + beam * ru->nb_rx][rxdataF_offset]; - feprx_cmd->sample_offet = ru->N_TA_offset; + for (int aid = 0; aid < nt; aid++) { + feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; + feprx_cmd->ans = &ans; + feprx_cmd->fp = fp; + feprx_cmd->slot = ru->proc.tti_rx; + feprx_cmd->startSymbol = start_symbol; + feprx_cmd->endSymbol = end_symbol; + feprx_cmd->rxdata = (const c16_t *)ru->common.rxdata[aid]; + feprx_cmd->rxdataF = (c16_t *)&ru->common.rxdataF[aid][rxdataF_offset]; + feprx_cmd->sample_offet = ru->N_TA_offset; - task_t t = {.func = nr_fep, .args = feprx_cmd}; - pushTpool(ru->threadPool, t); - nbfeprx++; - } + task_t t = {.func = nr_fep, .args = feprx_cmd}; + pushTpool(ru->threadPool, t); + nbfeprx++; } } join_task_ans(&ans); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 61194caaeb..39c54900a7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -39,43 +39,35 @@ static void nr_fill_indication(const PHY_VARS_gNB *gNB, nfapi_nr_crc_t *crc, nfapi_nr_rx_data_pdu_t *pdu); -int beam_index_allocation(bool das, - int fapi_beam_index, - NR_gNB_COMMON *common_vars, - int slot, - int symbols_per_slot, - int bitmap_symbols) +void beam_index_allocation(uint16_t fapi_beam_index, + int ant, + int num_ports, + int symbols_per_slot, + int slot, + uint16_t bitmap_symbols, + int num_ant_max, + uint16_t **ant_beam_id_list) { - if (!common_vars->beam_id) - return 0; + if (!ant_beam_id_list) + return; AssertFatal(IS_BIT_SET(fapi_beam_index, 15), "Can't handle preconfigured DBM yet\n"); - int ru_beam_idx = fapi_beam_index & 0x7fff; - 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++) { - int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i]; - if (current_beam == -1 || current_beam == ru_beam_idx) - idx = j; - else { - idx = -1; - break; - } - } - if (idx != -1) - break; - } - AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", ru_beam_idx); + uint16_t ru_beam_idx = fapi_beam_index & 0x7fff; for (int j = 0; j < symbols_per_slot; j++) { if (((bitmap_symbols >> j) & 0x01)) - common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx; + for (uint_fast8_t p = 0; p < num_ports; p++) { + DevAssert(ant + p < num_ant_max); + ant_beam_id_list[slot * symbols_per_slot + j][ant + p] = ru_beam_idx; + } } - LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot); - return idx; +} + +// Temporary workaround to get antenna ports for DAS. After L1 digital +// beamforming is implemented, DAS case can be handled with a special DBT in +// config file and this function can be removed. +uint16_t get_first_ant_idx(bool das, uint16_t num_ports_beams, uint16_t beam_id, uint16_t fapi_start_port) +{ + return ((das) ? (beam_id & 0x7fff) * num_ports_beams : fapi_start_port); } void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu) @@ -122,25 +114,25 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n } LOG_D(PHY,"SS TX: frame %d, slot %d, start_symbol %d\n", frame, slot, ssb_start_symbol); const nfapi_nr_tx_precoding_and_beamforming_t *pb = &pdu->precoding_and_beamforming; - c16_t ***txdataF = gNB->common_vars.txdataF; + c16_t **txdataF = gNB->common_vars.txdataF; // 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(gNB->enable_analog_das, - pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->common_vars, - slot, - fp->symbols_per_slot, - bitmap); + uint16_t sym_bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols + uint16_t beam_id = pb->prgs_list[0].dig_bf_interface_list[0].beam_idx; + uint16_t ant_port = get_first_ant_idx(gNB->enable_analog_das, + fp->nb_antennas_tx / gNB->common_vars.num_beams_period, + beam_id, + (pdu->param_v4.spatialStreamIndexPresent ? pdu->param_v4.spatialStreamIndex : 0)); + beam_index_allocation(beam_id, ant_port, 1, fp->symbols_per_slot, slot, sym_bitmap, fp->nb_antennas_tx, gNB->common_vars.beam_id); - nr_generate_pss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg, fp); - nr_generate_sss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg->cell_config.phy_cell_id.value, fp); + nr_generate_pss(txdataF[ant_port], gNB->TX_AMP, ssb_start_symbol, cfg, fp); + nr_generate_sss(txdataF[ant_port], gNB->TX_AMP, ssb_start_symbol, cfg->cell_config.phy_cell_id.value, fp); uint16_t slots_per_hf = (fp->slots_per_frame) >> 1; int n_hf = slot < slots_per_hf ? 0 : 1; int hf = fp->Lmax == 4 ? n_hf : 0; nr_generate_pbch_dmrs(nr_gold_pbch(fp->Lmax, gNB->gNB_config.cell_config.phy_cell_id.value, hf, ssb_index & 7), - txdataF[beam_nb][0], + txdataF[ant_port], gNB->TX_AMP, ssb_start_symbol, cfg, @@ -156,25 +148,19 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n } #endif - nr_generate_pbch(gNB, - ssb_pdu, - txdataF[beam_nb][0], - ssb_start_symbol, - n_hf, - frame, - cfg, - fp); + nr_generate_pbch(gNB, ssb_pdu, txdataF[ant_port], ssb_start_symbol, n_hf, frame, cfg, fp); } // clearing beam information to be provided to RU for all slots (DL and UL) void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot) { LOG_D(PHY, "Clearing beam_id structure for slot %d\n", slot); - int slot_sz = gNB->frame_parms.symbols_per_slot; - for (int i = 0; i < gNB->common_vars.num_beams_period; i++) { - if (gNB->common_vars.beam_id) - memset(&gNB->common_vars.beam_id[i][slot * slot_sz], -1, slot_sz * sizeof(**gNB->common_vars.beam_id)); - } + const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + int slot_sz = fp->symbols_per_slot; + if (gNB->common_vars.beam_id) + for (int i = 0; i < slot_sz; i++) { + memset(gNB->common_vars.beam_id[slot * slot_sz + i], 0, fp->nb_antennas_tx * sizeof(**gNB->common_vars.beam_id)); + } } static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, int slot, const nfapi_nr_dl_tti_csi_rs_pdu *csi_rs_pdu) @@ -186,16 +172,32 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, int slot, const nfapi_nr_d csi_mapping_parms_t mapping_parms = get_csi_mapping_parms(csi_params->row, csi_params->freq_domain, csi_params->symb_l0, csi_params->symb_l1); const nfapi_nr_tx_precoding_and_beamforming_t *pb = &csi_params->precodingAndBeamforming; - int csi_bitmap = 0; + uint16_t csi_bitmap = 0; 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(gNB->enable_analog_das, - pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - csi_bitmap); + // Get first antenna port index for CSI assigned by L2 + AssertFatal( + csi_params->param_v4.numSpatialStreamIndices <= 1, + "In current implementation, CSI spatial stream indexing is used to specify the first antenna port. So it cannot be > 1: %d\n", + csi_params->param_v4.numSpatialStreamIndices); + const uint16_t beam_id = pb->prgs_list[0].dig_bf_interface_list[0].beam_idx; + const uint16_t ant_port_offset = + get_first_ant_idx(gNB->enable_analog_das, + gNB->frame_parms.nb_antennas_tx / gNB->common_vars.num_beams_period, + beam_id, + csi_params->param_v4.numSpatialStreamIndices > 0 ? csi_params->param_v4.spatialStreamIndices[0] : 0); + const int group_sz = get_cdm_group_size(csi_params->cdm_type); + const uint16_t start_port = mapping_parms.j[0] * group_sz; // Start port of this CSI config + const uint16_t num_ports = mapping_parms.size * group_sz; + beam_index_allocation(beam_id, + ant_port_offset + start_port, + num_ports, + gNB->frame_parms.symbols_per_slot, + slot, + csi_bitmap, + gNB->frame_parms.nb_antennas_tx, + gNB->common_vars.beam_id); nr_generate_csi_rs(&gNB->frame_parms, &mapping_parms, @@ -210,7 +212,7 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, int slot, const nfapi_nr_d csi_params->scramb_id, csi_params->power_control_offset_ss, csi_params->cdm_type, - gNB->common_vars.txdataF[beam_nb]); + gNB->common_vars.txdataF + ant_port_offset); } void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, @@ -227,10 +229,8 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, return; // clear the transmit data array and beam index for the current slot - for (int i = 0; i < gNB->common_vars.num_beams_period; i++) { - for (int aa = 0; aa < cfg->carrier_config.num_tx_ant.value; aa++) { - memset(gNB->common_vars.txdataF[i][aa], 0, fp->samples_per_slot_wCP * sizeof(***gNB->common_vars.txdataF)); - } + for (int aa = 0; aa < fp->nb_antennas_tx; aa++) { + memset(gNB->common_vars.txdataF[aa], 0, fp->samples_per_slot_wCP * sizeof(**gNB->common_vars.txdataF)); } // Check for PRS slot - section 7.4.1.7.4 in 3GPP rel16 38.211 @@ -243,7 +243,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, { int slot_prs = (slot - i * prs_config->PRSResourceTimeGap + fp->slots_per_frame) % fp->slots_per_frame; LOG_D(PHY,"gNB_TX: frame %d, slot %d, slot_prs %d, PRS Resource ID %d\n",frame, slot, slot_prs, rsc_id); - nr_generate_prs(slot_prs, gNB->common_vars.txdataF[0][0], AMP, prs_config, fp); + nr_generate_prs(slot_prs, gNB->common_vars.txdataF[0], AMP, prs_config, fp); } } } @@ -292,25 +292,23 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, //apply the OFDM symbol rotation here start_meas(&gNB->phase_comp_stats); - for (int i = 0; i < gNB->common_vars.num_beams_period; ++i) { - for (int aa = 0; aa < cfg->carrier_config.num_tx_ant.value; aa++) { - if (gNB->phase_comp) { - apply_nr_rotation_TX(fp, - gNB->common_vars.txdataF[i][aa], - true, - fp->symbol_rotation[0], - slot, - fp->N_RB_DL, - 0, - fp->Ncp == NR_EXTENDED ? 12 : 14); - } - T(T_GNB_PHY_DL_OUTPUT_SIGNAL, - T_INT(0), - T_INT(frame), - T_INT(slot), - T_INT(aa), - T_BUFFER(gNB->common_vars.txdataF[i][aa], fp->samples_per_slot_wCP * sizeof(int32_t))); + for (int aa = 0; aa < fp->nb_antennas_tx; aa++) { + if (gNB->phase_comp) { + apply_nr_rotation_TX(fp, + gNB->common_vars.txdataF[aa], + true, + fp->symbol_rotation[0], + slot, + fp->N_RB_DL, + 0, + fp->Ncp == NR_EXTENDED ? 12 : 14); } + T(T_GNB_PHY_DL_OUTPUT_SIGNAL, + T_INT(0), + T_INT(frame), + T_INT(slot), + T_INT(aa), + T_BUFFER(gNB->common_vars.txdataF[aa], fp->samples_per_slot_wCP * sizeof(int32_t))); } stop_meas(&gNB->phase_comp_stats); } @@ -561,7 +559,7 @@ static int fill_srs_channel_matrix(nfapi_nr_srs_normalized_channel_iq_matrix_t * const NR_DL_FRAME_PARMS *frame_parms, const c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) { - const uint16_t num_gnb_antenna_elements = frame_parms->nb_antennas_rx; + const uint16_t num_gnb_antenna_elements = srs_pdu->srs_parameters_v4.num_ul_spatial_streams_ports; const uint16_t num_ue_srs_ports = srs_pdu->srs_parameters_v4.num_total_ue_antennas; const uint8_t normalized_iq_representation = srs_pdu->srs_parameters_v4.iq_representation; const uint16_t prg_size = srs_pdu->srs_parameters_v4.prg_size; @@ -675,7 +673,12 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, } stop_meas(&gNB->generate_srs_stats); - c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; + const nfapi_v4_srs_parameters_t *p = &srs_pdu->srs_parameters_v4; + const uint16_t ant_port_start = get_first_ant_idx(gNB->enable_analog_das, + frame_parms->nb_antennas_tx / gNB->common_vars.num_beams_period, + srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + p->num_ul_spatial_streams_ports > 0 ? p->Ul_spatial_stream_ports[0] : 0); + c16_t **rxdataF = gNB->common_vars.rxdataF + ant_port_start; start_meas(&gNB->get_srs_signal_stats); *srs_est = nr_get_srs_signal(gNB, rxdataF, slot_rx, srs_pdu, &nr_srs_info, srs_received_signal, srs_received_noise); stop_meas(&gNB->get_srs_signal_stats); @@ -818,9 +821,9 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, static void handle_srs(fsn_t now, PHY_VARS_gNB *gNB, const NR_gNB_SRS_job_t *srs, nfapi_nr_srs_indication_pdu_t *srs_indication) { const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; - const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size; const nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + const uint8_t nb_antennas_rx = srs_pdu->srs_parameters_v4.num_ul_spatial_streams_ports; + const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size; uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; uint8_t N_ap = 1 << srs_pdu->num_ant_ports; @@ -987,10 +990,11 @@ static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_v #endif start_meas(&gNB->rx_pusch_stats); - nr_rx_pusch_tp(gNB, pusch_vars, pdu, &ulsch->unav_res, ulsch->frame, ulsch->slot, ulsch->beam_nb); + nr_rx_pusch_tp(gNB, pusch_vars, pdu, &ulsch->unav_res, ulsch->frame, ulsch->slot); pusch_vars->ulsch_power_tot = 0; pusch_vars->ulsch_noise_power_tot = 0; - for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) { + const uint8_t num_sp_streams = pdu->param_v4.numSpatialStreamIndices; + for (int aarx = 0; aarx < num_sp_streams; aarx++) { pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx]; } @@ -1126,7 +1130,6 @@ static int handle_pusch_job_trigger(PHY_VARS_gNB *gNB, const NR_gNB_PUSCH_job_t ulsch->slot = job->slot; ulsch->rnti = pdu->rnti; ulsch->harq_pid = pid; - ulsch->beam_nb = job->beam_nb; ulsch->harq_process->ulsch_pdu = job->pusch_pdu; if (pdu->pusch_data.new_data_indicator) { ulsch->harq_process->harq_to_be_cleared = true; @@ -1188,7 +1191,12 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N UL_INFO->uci_ind.num_ucis = n_pucch; nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list; for (int i = 0; i < n_pucch; ++i) { - c16_t **rxdataF = gNB->common_vars.rxdataF[pucch->beam_nb]; + const nfapi_nr_spatial_stream_index_t *p = &pucch[i].pucch_pdu.param_v4; + const uint16_t ant_port = get_first_ant_idx(gNB->enable_analog_das, + frame_parms->nb_antennas_tx / gNB->common_vars.num_beams_period, + pucch[i].pucch_pdu.beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + p->numSpatialStreamIndices > 0 ? p->spatialStreamIndices[0] : 0); + c16_t **rxdataF = gNB->common_vars.rxdataF + ant_port; handle_pucch(gNB, rxdataF, &pucch[i], uci++); } @@ -1247,7 +1255,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), - T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], frame_parms->symbols_per_slot * ofdm_symbol_size * 4)); + T_BUFFER(&gNB->common_vars.rxdataF[0][0], frame_parms->symbols_per_slot * ofdm_symbol_size * 4)); } return pusch_DTX; diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index ba1d00457b..e2d8ecd221 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -30,10 +30,13 @@ 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(bool das, - int fapi_beam_index, - NR_gNB_COMMON *common_vars, - int slot, - int symbols_per_slot, - int bitmap_symbols); +void beam_index_allocation(uint16_t fapi_beam_index, + int ant, + int num_ports, + int symbols_per_slot, + int slot, + uint16_t bitmap_symbols, + int num_ant_max, + uint16_t **ant_beam_id_list); +uint16_t get_first_ant_idx(bool das, uint16_t num_ports_beams, uint16_t beam_id, uint16_t fapi_start_port); #endif diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 6588c6e196..5287b276eb 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -527,7 +527,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, dlschCfg->start_symbol, dlschCfg->dlDmrsSymbPos, freq_alloc->num_rbs, - dlsch->cw_info.Nl); + dlsch->cw_info.Nl, + ue->frame_parms.nb_antennas_rx); } uint16_t first_symbol_with_data = dlschCfg->start_symbol; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 37ea7ef66c..7ed293fef1 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -250,6 +250,11 @@ void nr_dlsim_preprocessor(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch) 0 /* tb_scaling */, sched_pdsch.nrOfLayers) >> 3; + const nr_pdsch_AntennaPorts_t *p = &nr_mac->radio_config.pdsch_AntennaPorts; + sched_pdsch.ant_port_idx.numSpatialStreamIndices = p->XP * p->N1 * p->N2; + for (int i = 0; i < sched_pdsch.ant_port_idx.numSpatialStreamIndices;i++) + sched_pdsch.ant_port_idx.spatialStreamIndices[i] = nr_mac->radio_config.spatial_stream_index[i]; + /* the simulator assumes the HARQ PID is equal to the slot number */ sched_pdsch.dl_harq_pid = pp_pdsch->slot; @@ -785,7 +790,8 @@ int main(int argc, char **argv) .timer_config.t311 = 3000, .timer_config.n311 = 1, .timer_config.t319 = 400, - .num_agg_level_candidates = {0, 0, 1, 1, 0}}; + .num_agg_level_candidates = {0, 0, 1, 1, 0}, + .spatial_stream_index = {0, 1, 2, 3}}; const nr_rlc_configuration_t rlc_config = { .srb = { .t_poll_retransmit = 45, @@ -814,14 +820,11 @@ int main(int argc, char **argv) RC.nb_nr_macrlc_inst = 1; mac_top_init_gNB(ngran_gNB, scc, &conf, &rlc_config); gNB_mac = RC.nrmac[0]; + gNB_mac->beam_info = (NR_beam_info_t){.beams_per_period = 1}; nr_mac_config_scc(RC.nrmac[0], scc, &conf); gNB_mac->dl_bler.harq_round_max = num_rounds; - gNB->ap_N1 = pdsch_AntennaPorts.N1; - gNB->ap_N2 = pdsch_AntennaPorts.N2; - gNB->ap_XP = pdsch_AntennaPorts.XP; - validate_input_pmi(&gNB_mac->config[0], pdsch_AntennaPorts, g_nrOfLayers, g_pmi); NR_UE_NR_Capability_t *UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); @@ -1134,14 +1137,16 @@ int main(int argc, char **argv) stop_meas(&gNB->phy_proc_tx); if (n_trials==1) { - LOG_M("txsigF0.m","txsF0=", - &gNB->common_vars.txdataF[0][0][2 * frame_parms->ofdm_symbol_size], + LOG_M("txsigF0.m", + "txsF0=", + &gNB->common_vars.txdataF[0][2 * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); if (gNB->frame_parms.nb_antennas_tx>1) - LOG_M("txsigF1.m","txsF1=", - &gNB->common_vars.txdataF[0][1][2 * frame_parms->ofdm_symbol_size], + LOG_M("txsigF1.m", + "txsF1=", + &gNB->common_vars.txdataF[1][2 * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); @@ -1154,7 +1159,7 @@ int main(int argc, char **argv) c16_t fft_in_buff[frame_parms->ofdm_symbol_size * frame_parms->symbols_per_slot] __attribute__((aligned(64))); memset(fft_in_buff, 0, sizeof(fft_in_buff)); if (cyclic_prefix_type == 1) { - fft_shift(gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[aa], frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, fft_in_buff, @@ -1172,7 +1177,7 @@ int main(int argc, char **argv) for (int i = 0; i < 14; i++) { was_symbol_used[i] = true; } - fft_shift(gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[aa], frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, fft_in_buff, diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 1c4cf9b71c..755e8f010d 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -504,7 +504,7 @@ int main(int argc, char **argv) int slot = start_symbol/14; for (aa=0; aaframe_parms.nb_antennas_tx; aa++) - memset(gNB->common_vars.txdataF[0][aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t)); + memset(gNB->common_vars.txdataF[aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t)); nr_common_signal_procedures (gNB,frame,slot, &ssb_pdu[i]); @@ -514,7 +514,7 @@ int main(int argc, char **argv) memset(fft_in_buff, 0, sizeof(fft_in_buff)); if (cyclic_prefix_type == 1) { apply_nr_rotation_TX(frame_parms, - gNB->common_vars.txdataF[0][aa], + gNB->common_vars.txdataF[aa], true, frame_parms->symbol_rotation[0], slot, @@ -522,7 +522,7 @@ int main(int argc, char **argv) 0, 12); - fft_shift(gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[aa], frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, fft_in_buff, @@ -538,7 +538,7 @@ int main(int argc, char **argv) CYCLIC_PREFIX); } else { apply_nr_rotation_TX(frame_parms, - gNB->common_vars.txdataF[0][aa], + gNB->common_vars.txdataF[aa], true, frame_parms->symbol_rotation[0], slot, @@ -546,7 +546,7 @@ int main(int argc, char **argv) 0, 14); - fft_shift(gNB->common_vars.txdataF[0][aa], + fft_shift(gNB->common_vars.txdataF[aa], frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, fft_in_buff, @@ -571,9 +571,9 @@ int main(int argc, char **argv) } } } - LOG_M("txsigF0.m", "txsF0", gNB->common_vars.txdataF[0][0], frame_parms->samples_per_slot_wCP, 1, 1); + LOG_M("txsigF0.m", "txsF0", gNB->common_vars.txdataF[0], frame_parms->samples_per_slot_wCP, 1, 1); if (gNB->frame_parms.nb_antennas_tx > 1) - LOG_M("txsigF1.m", "txsF1", gNB->common_vars.txdataF[0][1], frame_parms->samples_per_slot_wCP, 1, 1); + LOG_M("txsigF1.m", "txsF1", gNB->common_vars.txdataF[1], frame_parms->samples_per_slot_wCP, 1, 1); } else { printf("Reading %d samples from file to antenna buffer %d\n",frame_length_complex_samples,0); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index b47b35b470..217ac82f67 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -766,7 +766,7 @@ int main(int argc, char **argv){ .Xu = gNB->X_u, .rx_prach = &gNB->rx_prach, .prach_buf = (void *)(in + 1)}; - rx_nr_prach_ru(in, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); + rx_nr_prach_ru(in, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset, false); if (n_frames == 1) LOG_I(PHY, "ncs %d,num_seq %d\n", diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 40c6e454aa..2a383275a2 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -418,7 +418,7 @@ int main(int argc, char **argv) /* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU, * so we need to allocate that memory as well. */ for (i = 0; i < n_rx; i++) - gNB->common_vars.rxdataF[0][i] = malloc16_clear(gNB->frame_parms.samples_per_frame_wCP * sizeof(c16_t)); + gNB->common_vars.rxdataF[i] = malloc16_clear(gNB->frame_parms.samples_per_frame_wCP * sizeof(c16_t)); double fs, txbw, rxbw; get_samplerate_and_bw(mu, N_RB_DL, frame_parms->threequarter_fs, &fs, &txbw, &rxbw); @@ -529,12 +529,12 @@ int main(int argc, char **argv) pucch_GroupHopping_t PUCCH_GroupHopping = pucch_tx_pdu.group_hop_flag + (pucch_tx_pdu.sequence_hop_flag << 1); double tx_level_fp = 100.0; - c16_t **rxdataF = gNB->common_vars.rxdataF[0]; + c16_t **rxdataF = gNB->common_vars.rxdataF; for (SNR = snr0; SNR <= snr1 && !stop; SNR += 1) { ack_nack_errors = 0; sr_errors = 0; n_errors = 0; - c16_t **txdataF = gNB->common_vars.txdataF[0]; + c16_t **txdataF = gNB->common_vars.txdataF; for (trial = 0; trial < n_trials && !stop; trial++) { for (int aatx = 0; aatx < 1; aatx++) bzero(txdataF[aatx], frame_parms->ofdm_symbol_size * sizeof(int)); @@ -666,9 +666,9 @@ int main(int argc, char **argv) 10 * log10((double)txlev * UE->frame_parms.ofdm_symbol_size / 12), gNB->measurements.n0_subband_power_tot_dB[startingPRB], gNB->measurements.n0_subband_power_avg_dB); + nfapi_nr_pucch_pdu_t pucch_pdu = {.param_v4.numSpatialStreamIndices = n_rx}; if (format == 0) { nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; - nfapi_nr_pucch_pdu_t pucch_pdu; gNB->phy_stats[0].rnti = 0x1234; pucch_pdu.rnti = 0x1234; pucch_pdu.subcarrier_spacing = 1; @@ -712,7 +712,6 @@ int main(int argc, char **argv) } } else if (format == 1) { nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; - nfapi_nr_pucch_pdu_t pucch_pdu; gNB->phy_stats[0].rnti = 0x1234; pucch_pdu.rnti = 0x1234; pucch_pdu.subcarrier_spacing = 1; @@ -751,7 +750,6 @@ int main(int argc, char **argv) } else if (format == 2) { nfapi_nr_uci_pucch_pdu_format_2_3_4_t uci_pdu = {0}; - nfapi_nr_pucch_pdu_t pucch_pdu = {0}; pucch_pdu.rnti = 0x1234; pucch_pdu.subcarrier_spacing = 1; pucch_pdu.group_hop_flag = PUCCH_GroupHopping & 1; @@ -817,10 +815,8 @@ int main(int argc, char **argv) free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list); free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list); - for (int j = 0; j < gNB->common_vars.num_beams_period; j++) { - for (i = 0; i < n_rx; i++) - free(gNB->common_vars.rxdataF[j][i]); - } + for (i = 0; i < n_rx; i++) + free(gNB->common_vars.rxdataF[i]); phy_free_nr_gNB(gNB); free(RC.gNB[0]); free(RC.gNB); diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 8e2a3ed503..1be7a9af40 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -337,7 +337,7 @@ int main(int argc, char *argv[]) /* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU, * so we need to allocate that memory as well. First index in rxdataF[0] index refers to beams*/ for (i = 0; i < n_rx; i++) - gNB->common_vars.rxdataF[0][i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); + gNB->common_vars.rxdataF[i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); /* no RU: need to have rxdata */ c16_t **rxdata; @@ -432,6 +432,7 @@ int main(int argc, char *argv[]) .srs_parameters_v4.iq_representation = 1, .srs_parameters_v4.prg_size = 1, .srs_parameters_v4.num_total_ue_antennas = 1 << srs_pdu.num_ant_ports, + .srs_parameters_v4.num_ul_spatial_streams_ports = n_rx, .beamforming.num_prgs = m_SRS[srs_pdu.config_index], .beamforming.prg_size = 1}; @@ -543,14 +544,7 @@ int main(int argc, char *argv[]) n_rx); //----------- OFDM Demodulation and RX rotation-------------------------- - nr_ofdm_demod_and_rx_rotation(rxdata, - gNB->common_vars.rxdataF[0], - fp, - n_rx, - slot, - slot_offsetF, - link_type_ul, - was_symbol_used); + nr_ofdm_demod_and_rx_rotation(rxdata, gNB->common_vars.rxdataF, fp, n_rx, slot, slot_offsetF, link_type_ul, was_symbol_used); //----------- UE RX SRS procedures --------------------- @@ -646,7 +640,7 @@ int main(int argc, char *argv[]) free(r_re[i]); free(r_im[i]); free(rxdata[i]); - free(gNB->common_vars.rxdataF[0][i]); + free(gNB->common_vars.rxdataF[i]); } free(r_re); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 1c8b05faf5..337a8ba101 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -807,7 +807,8 @@ int main(int argc, char *argv[]) .timer_config.n310 = 10, .timer_config.t311 = 3000, .timer_config.n311 = 1, - .timer_config.t319 = 400}; + .timer_config.t319 = 400, + .spatial_stream_index = {0, 1, 2, 3, 4, 5, 6, 7}}; const nr_rlc_configuration_t rlc_config = { .srb = { .t_poll_retransmit = 45, @@ -835,6 +836,7 @@ int main(int argc, char *argv[]) RC.nb_nr_macrlc_inst = 1; mac_top_init_gNB(ngran_gNB, scc, &conf, &rlc_config); + RC.nrmac[0]->beam_info = (NR_beam_info_t){.beams_per_period = 1}; nr_mac_config_scc(RC.nrmac[0], scc, &conf); NR_UE_NR_Capability_t* UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); @@ -863,7 +865,7 @@ int main(int argc, char *argv[]) /* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU, * so we need to allocate that memory as well. */ for (i = 0; i < n_rx; i++) - gNB->common_vars.rxdataF[0][i] = malloc16_clear(gNB->frame_parms.samples_per_frame_wCP*sizeof(int32_t)); + gNB->common_vars.rxdataF[i] = malloc16_clear(gNB->frame_parms.samples_per_frame_wCP * sizeof(int32_t)); N_RB_DL = gNB->frame_parms.N_RB_DL; /* no RU: need to have rxdata */ @@ -1302,6 +1304,8 @@ int main(int argc, char *argv[]) pusch_pdu->pusch_ptrs.ptrs_ports_list = (nfapi_nr_ptrs_ports_t *)malloc(2 * sizeof(nfapi_nr_ptrs_ports_t)); pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0; pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS, code_rate); + pusch_pdu->param_v4.numSpatialStreamIndices = conf.pusch_AntennaPorts; + memcpy(pusch_pdu->param_v4.spatialStreamIndices, conf.spatial_stream_index, sizeof(conf.spatial_stream_index)); // if transform precoding is enabled if (transform_precoding == transformPrecoder_enabled) { @@ -1336,6 +1340,7 @@ int main(int argc, char *argv[]) srs_pdu->srs_parameters_v4.iq_representation = 1; srs_pdu->srs_parameters_v4.prg_size = 1; srs_pdu->srs_parameters_v4.num_total_ue_antennas = 1 << srs_pdu->num_ant_ports; + srs_pdu->srs_parameters_v4.num_ul_spatial_streams_ports = n_rx; srs_pdu->beamforming.num_prgs = m_SRS[srs_pdu->config_index]; srs_pdu->beamforming.prg_size = 1; } @@ -1591,7 +1596,7 @@ int main(int argc, char *argv[]) was_symbol_used[i] = true; } nr_ofdm_demod_and_rx_rotation(rxdata, - gNB->common_vars.rxdataF[0], + gNB->common_vars.rxdataF, &gNB->frame_parms, gNB->frame_parms.nb_antennas_rx, slot, @@ -1603,25 +1608,15 @@ int main(int argc, char *argv[]) if (n_trials == 1 && round == 0) { LOG_M("rxsig0.m", "rx0", &rxdata[0][slot_offset], slot_length, 1, 1 | log_format); - LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0][0], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); + LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); if (precod_nbr_layers > 1) { LOG_M("rxsig1.m", "rx1", &rxdata[1][slot_offset], slot_length, 1, 1); - LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[0][1], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); + LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[1], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); if (precod_nbr_layers == 4) { LOG_M("rxsig2.m", "rx2", &rxdata[2][slot_offset], slot_length, 1, 1); LOG_M("rxsig3.m", "rx3", &rxdata[3][slot_offset], slot_length, 1, 1); - LOG_M("rxsigF2.m", - "rxsF2", - gNB->common_vars.rxdataF[0][2], - 14 * gNB->frame_parms.ofdm_symbol_size, - 1, - 1 | log_format); - LOG_M("rxsigF3.m", - "rxsF3", - gNB->common_vars.rxdataF[0][3], - 14 * gNB->frame_parms.ofdm_symbol_size, - 1, - 1 | log_format); + LOG_M("rxsigF2.m", "rxsF2", gNB->common_vars.rxdataF[2], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); + LOG_M("rxsigF3.m", "rxsF3", gNB->common_vars.rxdataF[3], 14 * gNB->frame_parms.ofdm_symbol_size, 1, 1 | log_format); } } } diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 32e510d80b..db956f2666 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -54,6 +54,7 @@ #define MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" #define MACRLC_STATS_MAX_UE "stats_max_ue" +#define MACRLC_SPATIAL_STREAM_IDX "spatial_stream_index" #define HLP_MACRLC_UL_PRBBLACK "SNR threshold to decide whether a PRB will be blacklisted or not" #define HLP_MACRLC_DL_BLER_UP "Upper threshold of BLER to decrease DL MCS" @@ -75,6 +76,7 @@ #define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)" +#define HLP_MACRLC_SPATIAL_STREAM_INDEX "Array of RU antenna ports / eAxCIDs to be used by L1. This may only be applicable for MU-MIMO. Value range [0, 15]" /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -123,6 +125,8 @@ {MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {MACRLC_STATS_MAX_UE, HLP_MACRLC_STATS_MAX_UE, 0, .iptr=NULL, .defintval=8, TYPE_INT, 0}, \ + {MACRLC_SPATIAL_STREAM_IDX, HLP_MACRLC_SPATIAL_STREAM_INDEX, \ + 0, .uptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ } // clang-format off @@ -169,6 +173,7 @@ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ { .s5 = { NULL } }, \ + { .s2 = { NULL } }, /* Spatial stream index */ \ } /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 8d052bdba7..ecc61d99cc 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -816,12 +816,6 @@ void RCconfig_NR_L1(void) LOG_D(NR_PHY, "Copying %d blacklisted PRB to L1 context\n", RC.gNB[j]->num_ulprbbl); memcpy(RC.gNB[j]->ulprbbl, prbbl, MAX_BWP_SIZE * sizeof(prbbl[0])); } - - // Antenna ports - set_antenna_ports(&GNBParamList, &gNB->ap_N1, &gNB->ap_N2, &gNB->ap_XP); - AssertFatal(gNB->ap_N1 * gNB->ap_N2 * gNB->ap_XP <= NR_MAX_CSI_PORTS, - "Number of antenna ports set in config file exceeds the supported value of %d\n", - NR_MAX_CSI_PORTS); } // L1 params @@ -1503,6 +1497,20 @@ static double complex **read_dbt_from_config(const char *prefix, return table; } +static void config_spatial_stream_index(const paramdef_t *param, const size_t np, nr_mac_config_t *radio_config, int num_ru_ports) +{ + const int n = gpd(param, np, MACRLC_SPATIAL_STREAM_IDX)->numelt; + if (n == 0) { + // No indices provided in config file. Set default indices starting from 0. + for (int i = 0; i < num_ru_ports; i++) + radio_config->spatial_stream_index[i] = i; + } else { + AssertFatal(n == num_ru_ports, "Number of spatial stream indices must match number of RU ports\n"); + for (int i = 0; i < n; i++) + radio_config->spatial_stream_index[i] = gpd(param, np, MACRLC_SPATIAL_STREAM_IDX)->uptr[i]; + } +} + void RCconfig_nr_macrlc(configmodule_interface_t *cfg) { int j = 0; @@ -1531,14 +1539,24 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) // RU GET_PARAMS_LIST(RUParamList, RUParams, RUPARAMS_DESC, CONFIG_STRING_RU_LIST, NULL); int num_tx = 0; + int beams_per_period; + if (MacRLC_ParamList.numelt > 0) + beams_per_period = *gpd(MacRLC_ParamList.paramarray[0], sizeofArray(MacRLC_Params), MACRLC_BEAMS_PERIOD)->u8ptr; + else + beams_per_period = 1; if (RUParamList.numelt > 0) { for (int i = 0; i < RUParamList.numelt; i++) num_tx += *(RUParamList.paramarray[i][RU_NB_TX_IDX].uptr); - AssertFatal(num_tx >= config.pdsch_AntennaPorts.XP * config.pdsch_AntennaPorts.N1 * config.pdsch_AntennaPorts.N2, - "Number of logical antenna ports (set in config file with pdsch_AntennaPorts) cannot be larger than physical antennas (nb_tx)\n"); + AssertFatal(num_tx >= p->XP * p->N1 * p->N2 * beams_per_period, + "Number of logical antenna ports (set in config file with pdsch_AntennaPorts and beams_per_period) cannot be " + "larger than physical " + "antennas (nb_tx)\n"); + AssertFatal(p->XP * p->N1 * p->N2 <= NR_MAX_CSI_PORTS, + "Number of antenna ports set in config file exceeds the supported value of %d\n", + NR_MAX_CSI_PORTS); } else { // TODO temporary solution for 3rd party RU or nFAPI, in which case we don't have RU section present in the config file - num_tx = config.pdsch_AntennaPorts.XP * config.pdsch_AntennaPorts.N1 * config.pdsch_AntennaPorts.N2; + num_tx = p->XP * p->N1 * p->N2 * beams_per_period; LOG_E(GNB_APP, "RU information not present in config file. Assuming physical antenna ports equal to logical antenna ports %d\n", num_tx); } config.minRXTXTIME = *GNBParamList.paramarray[0][GNB_MINRXTXTIME_IDX].iptr; @@ -1741,15 +1759,14 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) } // config_get_processedint() takes only paramdef_t *, so cast const away paramdef_t *p_ab = (paramdef_t *)gpd(params, np, MACRLC_ANALOG_BEAMFORMING); - RC.nrmac[j]->beam_info.beam_mode = config_get_processedint(cfg, p_ab); + NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; + beam_info->beam_mode = config_get_processedint(cfg, p_ab); + beam_info->beams_per_period = beams_per_period; if (RC.nrmac[j]->beam_info.beam_mode != NO_BEAM_MODE) { if (RC.nrmac[j]->beam_info.beam_mode == PRECONFIGURED_BEAM_IDX) 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 = *gpd(params, np, MACRLC_BEAMS_PERIOD)->u8ptr; beam_info->beam_allocation = malloc16(beams_per_period * sizeof(beam_info->beam_allocation)); beam_info->beam_duration = *gpd(params, np, MACRLC_BEAM_DURATION)->u8ptr; - beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration } bool das_enabled = false; @@ -1799,6 +1816,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.bt.beam_weights = read_dbt_from_config(prefix, &config.bt.num_beams, &config.bt.num_weights_per_beam, &config.bt.beam_ids); } + + // Read spatial stream indices + config_spatial_stream_index(params, np, &RC.nrmac[j]->radio_config, num_tx); + // triggers also PHY initialization in case we have L1 via FAPI nr_mac_config_scc(RC.nrmac[j], scc, &config); } // for (j=0;jpdsch_AntennaPorts; int num_pdsch_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP; - cfg->carrier_config.num_tx_ant.value = num_pdsch_antenna_ports; + cfg->carrier_config.num_tx_ant.value = num_pdsch_antenna_ports * nrmac->beam_info.beams_per_period; AssertFatal(num_pdsch_antenna_ports > 0 && num_pdsch_antenna_ports < 33, "pdsch_AntennaPorts in 1...32\n"); cfg->carrier_config.num_tx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_TX_ANT_TAG; @@ -727,7 +727,7 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR } int pusch_AntennaPorts = config->pusch_AntennaPorts; - cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts; + cfg->carrier_config.num_rx_ant.value = pusch_AntennaPorts * nrmac->beam_info.beams_per_period; AssertFatal(pusch_AntennaPorts > 0 && pusch_AntennaPorts < 13, "pusch_AntennaPorts in 1...12\n"); cfg->carrier_config.num_rx_ant.tl.tag = NFAPI_NR_CONFIG_NUM_RX_ANT_TAG; LOG_I(NR_MAC, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index a1220c9df7..7956860187 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -490,9 +490,18 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) prach_pdu->num_prach_ocas = num_td_occ; prach_pdu->beamforming.num_prgs = 1; prach_pdu->beamforming.prg_size = n_ra_rb; - prach_pdu->beamforming.dig_bf_interface = num_td_occ; + // Spatial stream indices + const uint16_t num_log_ports = gNB->radio_config.pusch_AntennaPorts; + const uint8_t num_beams = beam.idx + 1; + prach_pdu->param_v4.numSpatialStreamIndices = num_beams * num_log_ports; + const int start_stream_idx = beam.idx * num_log_ports; + for (int s = 0; s < num_log_ports; s++) + prach_pdu->param_v4.spatialStreamIndices[start_stream_idx + s] = + gNB->radio_config.spatial_stream_index[start_stream_idx + s]; + // Beam id const uint16_t fapi_beam = convert_to_fapi_beam(beam_index, gNB->beam_info.beam_mode); - prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = fapi_beam; + prach_pdu->beamforming.dig_bf_interface = num_beams; + prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[beam.idx].beam_idx = fapi_beam; 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", @@ -836,6 +845,12 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, .dmrs_info = dmrs_info, }; + // Map antenna ports for this UE + sched_pusch.ant_port_idx.numSpatialStreamIndices = nr_mac->radio_config.pusch_AntennaPorts; + const int start_stream_idx = beam_ul.idx * nr_mac->radio_config.pusch_AntennaPorts; + for (int i = 0; i < sched_pusch.ant_port_idx.numSpatialStreamIndices; i++) + sched_pusch.ant_port_idx.spatialStreamIndices[i] = nr_mac->radio_config.spatial_stream_index[start_stream_idx + i]; + const int bwpStart = sched_pusch.bwp_info.bwpStart; const int bwpSize = sched_pusch.bwp_info.bwpSize; int rbStart = 0; @@ -914,8 +929,15 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, // Fill PDCCH DL DCI PDU const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode); - nfapi_nr_dl_dci_pdu_t *dci_pdu = - prepare_dci_pdu(pdcch_pdu_rel15, scc, ss, coreset, aggregation_level, CCEIndex, fapi_beam, UE->rnti); + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + ss, + coreset, + sched_pusch.ant_port_idx.spatialStreamIndices, + aggregation_level, + CCEIndex, + fapi_beam, + UE->rnti); pdcch_pdu_rel15->numDlDci++; dci_pdu_rel15_t uldci_payload = {0}; @@ -1198,7 +1220,8 @@ static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, fra return true; } -static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, NR_UE_info_t *UE, uint8_t *RAR_pdu) +static void +nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, NR_UE_info_t *UE, uint8_t *RAR_pdu, int beam_number) { gNB_MAC_INST *mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; @@ -1256,19 +1279,21 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ 1) >> 3; } - NR_sched_pusch_t sched_pusch = { - .bwp_info.bwpSize = sc_info->initial_ul_BWPSize, - .bwp_info.bwpStart = ra->msg3_bwp_start, - .rbSize = ra->msg3_nb_rb, - .rbStart = ra->msg3_first_rb, - .tb_size = TBS, - .R = R, - .Qm = Qm, - .mcs = mcsindex, - .nrOfLayers = 1, - .tda_info = tda_info, - .dmrs_info = dmrs_info - }; + NR_sched_pusch_t sched_pusch = {.bwp_info.bwpSize = sc_info->initial_ul_BWPSize, + .bwp_info.bwpStart = ra->msg3_bwp_start, + .rbSize = ra->msg3_nb_rb, + .rbStart = ra->msg3_first_rb, + .tb_size = TBS, + .R = R, + .Qm = Qm, + .mcs = mcsindex, + .nrOfLayers = 1, + .tda_info = tda_info, + .dmrs_info = dmrs_info, + .ant_port_idx = {.numSpatialStreamIndices = mac->radio_config.pusch_AntennaPorts}}; + const int start_stream_idx = beam_number * mac->radio_config.pusch_AntennaPorts; + for (int i = 0; i < sched_pusch.ant_port_idx.numSpatialStreamIndices; i++) + sched_pusch.ant_port_idx.spatialStreamIndices[i] = mac->radio_config.spatial_stream_index[start_stream_idx + i]; LOG_D(NR_MAC, "UE %04x: %d.%d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d)\n", @@ -1429,8 +1454,15 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, pduindex); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = - prepare_dci_pdu(pdcch_pdu_rel15, scc, sched_ctrl->search_space, coreset, aggregation_level, CCEIndex, fapi_beam, rnti); + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + sched_ctrl->search_space, + coreset, + sched_pdsch->ant_port_idx.spatialStreamIndices, + aggregation_level, + CCEIndex, + fapi_beam, + rnti); pdcch_pdu_rel15->numDlDci++; int tpc = 1; // 0dB change, don't know how to determine this. @@ -1668,20 +1700,25 @@ static void nr_generate_Msg2(module_id_t module_idP, >> 3; // layers } + const nr_pdsch_AntennaPorts_t *p = &nr_mac->radio_config.pdsch_AntennaPorts; + const uint16_t num_log_ports_beam = p->N1 * p->N2 * p->XP; NR_sched_pdsch_t sched_pdsch = { - .R = R, - .Qm = Qm, - .mcs = mcsIndex, - .time_domain_allocation = time_domain_assignment, - .nrOfLayers = 1, - .dmrs_parms = dmrs_parms, - .tda_info = tda_info, - .pm_index = 0, - .tb_size = TBS, - .bwp_info = bwp_info, - .rbStart = rbStart, - .rbSize = rbSize - }; + .R = R, + .Qm = Qm, + .mcs = mcsIndex, + .time_domain_allocation = time_domain_assignment, + .nrOfLayers = 1, + .dmrs_parms = dmrs_parms, + .tda_info = tda_info, + .pm_index = 0, + .tb_size = TBS, + .bwp_info = bwp_info, + .rbStart = rbStart, + .rbSize = rbSize, + // no of layers 1 and pmi 0 gives only one log antenna port + .ant_port_idx = {.numSpatialStreamIndices = 1, + .spatialStreamIndices[0] = nr_mac->radio_config.spatial_stream_index[beam.idx * num_log_ports_beam]}}; + prepare_dl_pdus(nr_mac, UE, &sched_pdsch, @@ -1705,7 +1742,7 @@ static void nr_generate_Msg2(module_id_t module_idP, // but required Msg3. Also, "if RAR includes a MAC subPDU with RAPID: [...] // indicate the reception of an acknowledgement for SI request to upper // layers." which is not the case here. - nr_add_msg3(module_idP, CC_id, frameP, slotP, UE, (uint8_t *)&tx_req->TLVs[0].value.direct[0]); + nr_add_msg3(module_idP, CC_id, frameP, slotP, UE, (uint8_t *)&tx_req->TLVs[0].value.direct[0], beam.idx); if (!ra->cfra) { LOG_D(NR_MAC, @@ -1960,20 +1997,24 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } rnti_t rnti = ra->ra_type == RA_4_STEP ? UE->rnti : ra->MsgB_rnti; + const nr_pdsch_AntennaPorts_t *p = &nr_mac->radio_config.pdsch_AntennaPorts; + const int num_log_ports = p->N1 * p->N2 * p->XP; NR_sched_pdsch_t sched_pdsch = { - .R = nr_get_code_rate_dl(mcsIndex, mcsTableIdx), - .Qm = nr_get_Qm_dl(mcsIndex, mcsTableIdx), - .mcs = mcsIndex, - .time_domain_allocation = time_domain_assignment, - .nrOfLayers = 1, - .dmrs_parms = dmrs_info, - .tda_info = msg4_tda, - .pm_index = 0, - .tb_size = tb_size, - .bwp_info = bwp_info, - .rbStart = rbStart, - .rbSize = rbSize - }; + .R = nr_get_code_rate_dl(mcsIndex, mcsTableIdx), + .Qm = nr_get_Qm_dl(mcsIndex, mcsTableIdx), + .mcs = mcsIndex, + .time_domain_allocation = time_domain_assignment, + .nrOfLayers = 1, + .dmrs_parms = dmrs_info, + .tda_info = msg4_tda, + .pm_index = 0, + .tb_size = tb_size, + .bwp_info = bwp_info, + .rbStart = rbStart, + .rbSize = rbSize, + .ant_port_idx = {.numSpatialStreamIndices = 1, + .spatialStreamIndices[0] = nr_mac->radio_config.spatial_stream_index[beam.idx * num_log_ports]}}; + const int pduindex = nr_mac->pdu_index[CC_id]++; prepare_dl_pdus(nr_mac, UE, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 977c3d12a9..e62a81af01 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -27,7 +27,8 @@ static void schedule_ssb(frame_t frame, int beam_index, uint8_t scoffset, uint16_t offset_pointa, - uint32_t payload) + uint32_t payload, + uint16_t stream_idx) { nfapi_nr_dl_tti_request_pdu_t *dl_config_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); @@ -58,6 +59,8 @@ static void schedule_ssb(frame_t frame, dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.dig_bf_interfaces = 1; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prgs_list[0].pm_idx = 0; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; + dl_config_pdu->ssb_pdu.ssb_pdu_rel15.param_v4.spatialStreamIndexPresent = 1; + dl_config_pdu->ssb_pdu.ssb_pdu_rel15.param_v4.spatialStreamIndex = stream_idx; dl_req->nPDUs++; LOG_D(NR_MAC,"Scheduling ssb %d at frame %d and slot %d\n", i_ssb, frame, slot); @@ -197,7 +200,16 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const uint16_t alloc_beam_idx = get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx); const uint16_t fapi_beam = convert_to_fapi_beam(alloc_beam_idx, gNB->beam_info.beam_mode); - schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, fapi_beam, ssbSubcarrierOffset, offset_pointa, mib_pdu); + schedule_ssb(frameP, + slotP, + scc, + dl_req, + i_ssb, + fapi_beam, + ssbSubcarrierOffset, + offset_pointa, + mib_pdu, + gNB->radio_config.spatial_stream_index[beam.idx]); fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx); if (IS_SA_MODE(get_softmodem_params())) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], @@ -294,6 +306,7 @@ static NR_sched_pdsch_t allocate_sib1(gNB_MAC_INST *gNB_mac, NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, NULL, tda_info, 1); + const uint16_t *sidx = gNB_mac->radio_config.spatial_stream_index; NR_sched_pdsch_t pdsch = { .bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL), .time_domain_allocation = time_domain_allocation, @@ -302,6 +315,8 @@ static NR_sched_pdsch_t allocate_sib1(gNB_MAC_INST *gNB_mac, .nrOfLayers = 1, .pm_index = 0, .mcs = 0, // starting from mcs 0 + // no of layers 1 and pmi 0 gives only one log antenna port + .ant_port_idx = {.numSpatialStreamIndices = 1, .spatialStreamIndices[0] = sidx[beam]}, }; uint16_t *vrb_map = cc->vrb_map[beam]; @@ -360,8 +375,15 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, pdsch_pdu_rel15->dlDmrsSymbPos); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = - prepare_dci_pdu(pdcch_pdu_rel15, scc, search_space, coreset, aggregation_level, cce_index, fapi_beam, SI_RNTI); + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + search_space, + coreset, + pdsch->ant_port_idx.spatialStreamIndices, + aggregation_level, + cce_index, + fapi_beam, + SI_RNTI); pdcch_pdu_rel15->numDlDci++; /* DCI payload */ @@ -678,14 +700,16 @@ static void other_sib_sched_control(module_id_t module_idP, // Mark the corresponding RBs as used fill_pdcch_vrb_map(gNB_mac, 0, gNB_mac->sched_pdcch_otherSI, cce_index, aggregation_level, beam.idx); - NR_sched_pdsch_t sched_pdsch_otherSI = {0}; - sched_pdsch_otherSI.time_domain_allocation = time_domain_allocation; - sched_pdsch_otherSI.bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL); - sched_pdsch_otherSI.dmrs_parms = dmrs_parms; - sched_pdsch_otherSI.tda_info = tda_info; - sched_pdsch_otherSI.nrOfLayers = 1; - sched_pdsch_otherSI.pm_index = 0; - sched_pdsch_otherSI.mcs = 0; // starting from mcs 0 + const uint16_t *sidx = gNB_mac->radio_config.spatial_stream_index; + NR_sched_pdsch_t sched_pdsch_otherSI = { + .time_domain_allocation = time_domain_allocation, + .bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL), + .dmrs_parms = dmrs_parms, + .tda_info = tda_info, + .nrOfLayers = 1, + .pm_index = 0, + .mcs = 0, // starting from mcs 0 + .ant_port_idx = {.numSpatialStreamIndices = 1, .spatialStreamIndices[0] = sidx[beam.idx]}}; uint16_t *vrb_map = cc->vrb_map[beam.idx]; uint8_t *sib_bcch_pdu = cc->other_sib_bcch_pdu[payload_idx]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 542341676e..06a5a0fd84 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -820,6 +820,7 @@ static void nr_dl_schedule(gNB_MAC_INST *mac, sched_pdsch.Qm = harq_pdsch.Qm; sched_pdsch.tb_size = harq_pdsch.tb_size; sched_pdsch.dl_harq_pid = cand->retx_harq_pid; + sched_pdsch.ant_port_idx = harq_pdsch.ant_port_idx; bool tda_changed = sched_pdsch.tda_info.startSymbolIndex != harq_pdsch.tda_info.startSymbolIndex || sched_pdsch.tda_info.nrOfSymbols != harq_pdsch.tda_info.nrOfSymbols; if (tda_changed) @@ -857,6 +858,14 @@ static void nr_dl_schedule(gNB_MAC_INST *mac, int srb1 = 1; if (UE->reconfigCellGroup && sched_ctrl->rlc_status[srb1].bytes_in_buffer > 10) sched_pdsch.action = ack_reconfig; + + // Map antenna ports for this UE + const nr_pdsch_AntennaPorts_t *p = &mac->radio_config.pdsch_AntennaPorts; + const uint16_t num_log_ports = p->XP * p->N1 * p->N2; + sched_pdsch.ant_port_idx.numSpatialStreamIndices = num_log_ports; + const int start_stream_idx = cand->alloc_beam_idx * num_log_ports; + for (int i = 0; i < sched_pdsch.ant_port_idx.numSpatialStreamIndices;i++) + sched_pdsch.ant_port_idx.spatialStreamIndices[i] = mac->radio_config.spatial_stream_index[start_stream_idx + i]; } post_process_dlsch(mac, pp_pdsch, UE, &sched_pdsch, cand); @@ -955,12 +964,16 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu int dl_bw_tbslbrm = UE ? UE->sc_info.dl_bw_tbslbrm : sched_pdsch->bwp_info.bwpSize; pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(pdsch_pdu->mcsTable[0], dl_bw_tbslbrm, nl_tbslbrm); pdsch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pdsch->tb_size << 3, sched_pdsch->R); + // MU-MIMO port mapping info + pdsch_pdu->param_v4.numberCodewords = pdsch_pdu->NrOfCodewords; + memcpy(&pdsch_pdu->param_v4.spatialStreamsCw[0], &sched_pdsch->ant_port_idx, sizeof(*pdsch_pdu->param_v4.spatialStreamsCw)); // Precoding and beamforming pdsch_pdu->precodingAndBeamforming.num_prgs = 1; pdsch_pdu->precodingAndBeamforming.prg_size = pdsch_pdu->rbSize; - pdsch_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; - pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = sched_pdsch->pm_index; - pdsch_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; + pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = sched_pdsch->pm_index; + pdsch_pdu->precodingAndBeamforming.dig_bf_interfaces = pdsch_pdu->param_v4.spatialStreamsCw[0].numSpatialStreamIndices; + for (int i = 0; i < pdsch_pdu->param_v4.spatialStreamsCw[0].numSpatialStreamIndices; i++) + pdsch_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx = beam_index; return pdsch_pdu; } @@ -1327,6 +1340,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, scc, sched_ctrl->search_space, sched_ctrl->coreset, + sched_pdsch->ant_port_idx.spatialStreamIndices, sched_ctrl->aggregation_level, sched_ctrl->cce_index, fapi_beam, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index efb2b42805..674a469746 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -167,6 +167,14 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) .time_domain_allocation = tda, .tda_info = tda_info, }; + // Map antenna ports for this UE + const nr_pdsch_AntennaPorts_t *p = &mac->radio_config.pdsch_AntennaPorts; + const uint16_t num_log_ports = p->XP * p->N1 * p->N2; + sched_pdsch.ant_port_idx.numSpatialStreamIndices = num_log_ports; + const int start_stream_idx = beam.idx * num_log_ports; + for (int i = 0; i < sched_pdsch.ant_port_idx.numSpatialStreamIndices;i++) + sched_pdsch.ant_port_idx.spatialStreamIndices[i] = mac->radio_config.spatial_stream_index[start_stream_idx + i]; + sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */ sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm, sched_pdsch.R, @@ -303,7 +311,12 @@ void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_p .tda_info = tda_info, .dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, target_ul_Nl), .bwp_info = get_pusch_bwp_start_size(UE), + .ant_port_idx.numSpatialStreamIndices = nr_mac->radio_config.pusch_AntennaPorts, }; + const uint16_t start_stream_idx = beam * nr_mac->radio_config.pusch_AntennaPorts; + for (int i = 0; i < sched.ant_port_idx.numSpatialStreamIndices; i++) + sched.ant_port_idx.spatialStreamIndices[i] = nr_mac->radio_config.spatial_stream_index[start_stream_idx + i]; + sched_ctrl->ul_bler_stats.mcs = sched.mcs; /* for logging output */ /* Calculate TBS from MCS */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 75f10e6253..3e839f7e57 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -875,6 +875,7 @@ nfapi_nr_dl_dci_pdu_t *prepare_dci_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_ const NR_ServingCellConfigCommon_t *scc, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, + const uint16_t *spatial_stream_idx, int aggregation_level, int cce_index, int beam_index, @@ -901,8 +902,18 @@ nfapi_nr_dl_dci_pdu_t *prepare_dci_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_ dci_pdu->powerControlOffsetSS = 1; dci_pdu->precodingAndBeamforming.num_prgs = 1; dci_pdu->precodingAndBeamforming.prg_size = N_rb; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; + + // Spatial stream indexing for MU-MIMO + const int num_ant_ports_per_dci = 1; // Only one stream per DCI for now + pdcch_pdu->param_v4.numSpatialStreams = (pdcch_pdu->numDlDci + 1 /*count this dci too*/) * num_ant_ports_per_dci; + for (uint_fast16_t i = 0; i < num_ant_ports_per_dci; i++) { + pdcch_pdu->param_v4.dci_spatialStreamIndices[pdcch_pdu->numDlDci * num_ant_ports_per_dci + i].dci_index = pdcch_pdu->numDlDci; + // Map the spatial stream index from the corresponding PDSCH signal + pdcch_pdu->param_v4.dci_spatialStreamIndices[pdcch_pdu->numDlDci * num_ant_ports_per_dci + i].spatial_stream_index = + spatial_stream_idx[i]; + } + dci_pdu->precodingAndBeamforming.dig_bf_interfaces = num_ant_ports_per_dci; dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; return dci_pdu; } @@ -1371,7 +1382,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, uint16_t O_ack, uint8_t O_sr, int r_pucch, - nr_beam_mode_t beam_mode) + nr_beam_mode_t beam_mode, + uint16_t ant_port_idx) { NR_PUCCH_Resource_t *pucchres; NR_PUCCH_FormatConfig_t *pucchfmt; @@ -1585,6 +1597,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, pucch_pdu->beamforming.dig_bf_interface = 1; const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, beam_mode); pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; + pucch_pdu->param_v4.numSpatialStreamIndices = 1; + pucch_pdu->param_v4.spatialStreamIndices[0] = ant_port_idx; } void set_r_pucch_parms(int rsetindex, @@ -3338,7 +3352,16 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt csirs_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 1; csirs_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, gNB_mac->beam_info.beam_mode); + // TODO: set correctly dig_bf_interface_list when ports of same CDM group is used and PMI if used. csirs_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; + const nr_pdsch_AntennaPorts_t *p = &gNB_mac->radio_config.pdsch_AntennaPorts; + const uint16_t num_max_csi_ports = p->N1 * p->N2 * p->XP; + /* The L1 does not take number of spatial streams parameter into + consideration because the CSI-RS generation function uses information + in mapping params to determine number of ports and maps to contiguous + logical ports. Hence we set only the first port for CSI-RS here. */ + csirs_pdu_rel15->param_v4.numSpatialStreamIndices = 1; + csirs_pdu_rel15->param_v4.spatialStreamIndices[0] = beam_csi.idx * num_max_csi_ports; csirs_pdu_rel15->bwp_size = dl_bwp->BWPSize; csirs_pdu_rel15->bwp_start = dl_bwp->BWPStart; csirs_pdu_rel15->subcarrier_spacing = dl_bwp->scs; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 07c0a0662f..eebe79279c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -457,9 +457,19 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac, srs_pdu->beamforming.prg_size = srs_pdu->srs_parameters_v4.srs_bandwidth_size; } const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nrmac->beam_info.beam_mode); - srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n"); + + // Indexing SRS antenna ports when beamformed + const unsigned int srs_num_rx_ant_ports = nrmac->radio_config.pusch_AntennaPorts; + srs_pdu->srs_parameters_v4.num_ul_spatial_streams_ports = srs_num_rx_ant_ports; + srs_pdu->beamforming.dig_bf_interface = srs_num_rx_ant_ports; + for (int i = 0; i < srs_num_rx_ant_ports;i++){ + srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx = fapi_beam; + srs_pdu->srs_parameters_v4.Ul_spatial_stream_ports[i] = + nrmac->radio_config.spatial_stream_index[beam.idx * srs_num_rx_ant_ports + i]; + } + uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE]; uint16_t num = 1 << srs_pdu->num_symbols; // 0,1,2 means 1,2,4 symbols, see 222.10.04 table 3-105 const uint8_t l0 = srs_pdu->time_start_position; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 38a1c6579f..72b63f3dff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -71,6 +71,7 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, frame_t frame, slot_t slot, pucch->frame, pucch->ul_slot); + const uint16_t ant_ports_to_use = pucch->beam_idx * nrmac->radio_config.pusch_AntennaPorts; nr_configure_pucch(pucch_pdu, scc, UE, @@ -79,7 +80,8 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, frame_t frame, slot_t slot, pucch->dai_c, pucch->sr_flag, pucch->r_pucch, - nrmac->beam_info.beam_mode); + nrmac->beam_info.beam_mode, + ant_ports_to_use); } //Differential RSRP values Table 10.1.6.1-2 from 38.133 @@ -259,6 +261,7 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot) // going through the list of PUCCH resources to find the one indexed by resource_id NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, n_slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate CSI measurements on PUCCH in any available beam\n"); + curr_pucch->beam_idx = beam.idx; const int index = ul_buffer_index(sched_frame, sched_slot, n_slots_frame, nrmac->vrb_map_UL_size); uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; @@ -1263,6 +1266,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, pucch_slot); continue; } + curr_pucch->beam_idx = beam.idx; const int index = ul_buffer_index(pucch_frame, pucch_slot, n_slots_frame, mac->vrb_map_UL_size); uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; bool ret = test_pucch0_vrb_occupation(curr_pucch, vrb_map_UL, bwp_start); @@ -1371,6 +1375,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot) LOG_E(NR_MAC,"Cannot schedule SR. PRBs not available\n"); continue; } + curr_pucch->beam_idx = beam.idx; curr_pucch->frame = SFN; curr_pucch->ul_slot = slot; curr_pucch->sr_flag = true; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7139b8627b..3bf555c645 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1797,6 +1797,13 @@ static int apply_ul_new_transmission(gNB_MAC_INST *nrmac, sched.dmrs_info = get_ul_dmrs_params(scc, current_BWP, tda_info, sched.nrOfLayers); sched.bwp_info = bi; + // Map antenna ports for this UE + sched.ant_port_idx.numSpatialStreamIndices = nrmac->radio_config.pusch_AntennaPorts; + const int start_stream_idx = cand->alloc_beam_idx * nrmac->radio_config.pusch_AntennaPorts; + for (int i = 0; i < nrmac->radio_config.pusch_AntennaPorts; i++) + sched.ant_port_idx.spatialStreamIndices[i] = nrmac->radio_config.spatial_stream_index[start_stream_idx + i]; + sched.dci_ant_idx = cand->alloc_dci_beam_idx; + update_ul_ue_R_Qm(sched.mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched.R, &sched.Qm); sched.tb_size = nr_compute_tbs(sched.Qm, sched.R, @@ -2057,9 +2064,11 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti // Beamforming pusch_pdu->beamforming.num_prgs = 1; pusch_pdu->beamforming.prg_size = pusch_pdu->bwp_size; - pusch_pdu->beamforming.dig_bf_interface = 1; - pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = - convert_to_fapi_beam(UE->UE_beam_index, beam_mode); + pusch_pdu->beamforming.dig_bf_interface = sched_pusch->ant_port_idx.numSpatialStreamIndices; + memcpy(&pusch_pdu->param_v4, &sched_pusch->ant_port_idx, sizeof(pusch_pdu->param_v4)); + const uint16_t fapi_beam_id = convert_to_fapi_beam(UE->UE_beam_index, beam_mode); + for (int i = 0; i < sched_pusch->ant_port_idx.numSpatialStreamIndices;i++) + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx = fapi_beam_id; /* TRANSFORM PRECODING --------------------------------------------------------*/ if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled @@ -2258,6 +2267,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE scc, ss, coreset, + &sched_pusch->dci_ant_idx, sched_ctrl->aggregation_level, sched_ctrl->cce_index, convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode), diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 07edd81314..0072cff5a1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -157,6 +157,7 @@ nfapi_nr_dl_dci_pdu_t *prepare_dci_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_ const NR_ServingCellConfigCommon_t *scc, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, + const uint16_t *spatial_stream_idx, int aggregation_level, int cce_index, int beam_index, @@ -202,7 +203,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, uint16_t O_ack, uint8_t O_sr, int r_pucch, - nr_beam_mode_t mode); + nr_beam_mode_t mode, + uint16_t ant_port_idx); void find_search_space(int ss_type, NR_BWP_Downlink_t *bwp, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 4a21160e00..e03801d17f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -207,6 +207,8 @@ typedef struct nr_mac_config_s { nr_ptrs_config_t *ptrs; nr_config_report_type_t report_type; nr_beam_table_t bt; + /// Spatial stream indexing for mapping onto RU ports. Needed for MU-MIMO + uint16_t spatial_stream_index[MAX_NUM_SPATIAL_STREAMS]; } nr_mac_config_t; typedef struct NR_preamble_ue { @@ -410,6 +412,7 @@ typedef struct NR_sched_pucch { int second_hop_prb; int nr_of_symb; int start_symb; + int beam_idx; } NR_sched_pucch_t; typedef struct NR_pusch_dmrs { @@ -455,6 +458,10 @@ typedef struct NR_sched_pusch { /// TPC command for this PUSCH int tpc_pusch; + // Antenna ports to use + nfapi_nr_spatial_stream_index_t ant_port_idx; + // Antenna port for PUSCH DCI + uint16_t dci_ant_idx; } NR_sched_pusch_t; typedef struct NR_pdsch_dmrs { @@ -499,6 +506,8 @@ typedef struct NR_sched_pdsch { int time_domain_allocation; NR_tda_info_t tda_info; feedback_action_t action; + // Baseband ports to use + nfapi_nr_spatial_stream_index_t ant_port_idx; } NR_sched_pdsch_t; typedef struct NR_UE_harq { diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 6aaaa0d8fb..32dcf630ca 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -369,6 +369,8 @@ int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int ); // `p.slot` = slot in which PRACH is scheduled if (is_prach_slot) { ru->prach_buf = p.prach_buf; + ru->nb_prach_rx = p.nb_rx; + ru->start_prach_rx = p.ant_start; } else { LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, p.slot); } @@ -408,13 +410,13 @@ int xran_fh_rx_prach_read_slot(PHY_VARS_gNB *gNB, ru_info_t *ru, int *frame, int int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. - for (int aa = 0; aa < ru->nb_rx; aa++) { + for (int aa = ru->start_prach_rx; aa < ru->start_prach_rx + ru->nb_prach_rx; aa++) { for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { int16_t *dst, *src; int idx = 0; oran_buf_list_t *bufs = get_xran_buffers(aa / nb_rx_per_ru); // hardcoded to use only first prach occasion - dst = (int16_t *)ru->prach_buf[aa][0]; + dst = (int16_t *)ru->prach_buf[aa - ru->start_prach_rx][0]; #if defined K_RELEASE struct xran_prb_map * pPrbMap = (struct xran_prb_map *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; struct xran_rx_packet_ctl *p_rx_packet_ctl = &pPrbMap->sFrontHaulRxPacketCtrl[sym_idx]; @@ -799,22 +801,10 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) #endif LOG_D(HW, "pPrbMap[%d] : PRBstart %d nPRBs %d\n", idxElm, startRB, numRB); // For Liteon FR2 with RunSlotPrbMapBySymbolEnable xran_prb_map will have xran_prb_elm prbMap[14], each idxElm matches to sym_idx. - if (fh_cfg->RunSlotPrbMapBySymbolEnable) { - if (sym_idx >= pRbElm->nStartSymb && sym_idx < pRbElm->nStartSymb + pRbElm->numSymb) { - if (!p_sec_desc->pCtrl) - continue; - // ant_id / no of antenna per beam gives the beam_nb - pRbElm->nBeamIndex = ru->beam_id[ant_id / (ru->nb_rx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx]; - // In phy-f-1.0/fhi_lib/lib/api/xran_pkt_cp.h, beamId:15 is of 15bit. -1 set extension bit ef:1 to 1 mistakenly. - if (pRbElm->nBeamIndex == -1) - pRbElm->nBeamIndex = 0; - } - } else { - // ant_id / no of antenna per beam gives the beam_nb - int16_t beam_id = ru->beam_id[ant_id / (ru->nb_tx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx]; - if (beam_id != -1) - pRbElm->nBeamIndex = beam_id; - } + if (fh_cfg->RunSlotPrbMapBySymbolEnable && (sym_idx < pRbElm->nStartSymb || sym_idx >= pRbElm->nStartSymb + pRbElm->numSymb) && !p_sec_desc->pCtrl) + continue; + + pRbElm->nBeamIndex = ru->beam_id[slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx][ant_id]; } } } @@ -829,31 +819,22 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) continue; } - // For Liteon FR2 with RunSlotPrbMapBySymbolEnable. Set nPrbElm if beam_id = -1 for all downlink symbols + /* TODO: Remove this hack to set nPrbElm for mixed slot. This can be set statically during init based on TDD pattern. */ if (fh_cfg->RunSlotPrbMapBySymbolEnable) { - bool beam_used = false; uint8_t *pPrbMapData = bufs->srccp[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; struct xran_prb_map *pRbMap = pPrbMap; int32_t dl_sym_end = 0; for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { - if (is_tdd_dl_symbol(frame_conf, slot, sym_idx)) { - if (ru->beam_id[ant_id / (ru->nb_tx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT+ sym_idx] != -1) - beam_used |= true; - } - else { - dl_sym_end = sym_idx; - break; + if (!is_tdd_dl_symbol(frame_conf, slot, sym_idx)) { + dl_sym_end = sym_idx; + break; } } if (is_tdd_guard_slot(frame_conf, slot)) pRbMap->nPrbElm = dl_sym_end; else pRbMap->nPrbElm = XRAN_NUM_OF_SYMBOL_PER_SLOT; - if (!beam_used) { - pRbMap->nPrbElm = 0; - continue; - } } // This loop would better be more inner to avoid confusion and maybe also errors. @@ -911,17 +892,8 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) p_sec_desc->iq_buffer_len = 0; continue; } - // ant_id / no of antenna per beam gives the beam_nb - p_prbMapElm->nBeamIndex = ru->beam_id[ant_id / (ru->nb_tx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT+ sym_idx]; - // In phy-f-1.0/fhi_lib/lib/api/xran_pkt_cp.h, beamId:15 is of 15bit. -1 set extension bit ef:1 to 1 mistakenly. - if (p_prbMapElm->nBeamIndex == -1) - p_prbMapElm->nBeamIndex = 0; - } else { - // ant_id / no of antenna per beam gives the beam_nb - int16_t beam_id = ru->beam_id[ant_id / (ru->nb_tx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx]; - if ( beam_id != -1) - p_prbMapElm->nBeamIndex = beam_id; } + p_prbMapElm->nBeamIndex = ru->beam_id[slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx][ant_id]; dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod); diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 5d3a624555..2d49c7726a 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -269,11 +269,10 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) int ret = 0; // return code for PUSCH/PRACH processing ru_info_t ru_info = { - .nb_rx = ru->nb_rx * ru->num_beams_period, - .nb_tx = ru->nb_tx * ru->num_beams_period, + .nb_rx = ru->nb_rx, + .nb_tx = ru->nb_tx, .rxdataF = ru->common.rxdataF, .beam_id = ru->common.beam_id, - .num_beams_period = ru->num_beams_period, .prach_buf = NULL, }; @@ -341,11 +340,10 @@ 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 = { - .nb_rx = ru->nb_rx * ru->num_beams_period, - .nb_tx = ru->nb_tx * ru->num_beams_period, + .nb_rx = ru->nb_rx, + .nb_tx = ru->nb_tx, .txdataF_BF = ru->common.txdataF_BF, .beam_id = ru->common.beam_id, - .num_beams_period = ru->num_beams_period, }; // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index 24ee524656..c1338b5554 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -29,15 +29,14 @@ typedef struct ru_info_s { int32_t **txdataF_BF; /// \brief Anaglogue beam ID for each OFDM symbol (used when beamforming not done in RU) - /// - first index: concurrent beam - /// - second index: beam_id [0.. symbols_per_frame] - int32_t **beam_id; - - /// number of concurrent analog beams in period - int num_beams_period; + /// - first index: symbol index [0.. symbols_per_frame) + /// - second index: beam_id [0..num_ports) + uint16_t **beam_id; // Needed for Prach c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L]; + int nb_prach_rx; + int start_prach_rx; } ru_info_t; void print_fhi_counters(ru_info_t *ru, const int frame, const int slot); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf index 044426471d..2b50b2a8ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-das-benetel650_650.conf @@ -206,8 +206,8 @@ L1s = ( RUs = ( { local_rf = "no"; - nb_tx = 4; - nb_rx = 4; + nb_tx = 8; + nb_rx = 8; att_tx = 0; att_rx = 0; bands = [77];