Merge remote-tracking branch 'origin/RU_beam_management' into integration_2025_w24 (!3169)

NR RU improvements for analog beamforming
This commit is contained in:
Robert Schmidt
2025-06-11 18:37:15 +02:00
35 changed files with 534 additions and 411 deletions
@@ -21,7 +21,6 @@ gNBs =
sib1_tda = 15;
min_rxtxtime = 6;
beam_weights = [0]; // single SSB -> one analog beam
servingCellConfigCommon = (
{
@@ -179,6 +178,7 @@ MACRLCs = ({
set_analog_beamforming = 1;
beam_duration = 1;
beams_per_period = 1;
beam_weights = [0]; // single SSB -> one analog beam
});
L1s = (
+29 -1
View File
@@ -10,6 +10,8 @@ There are three main beamforming techinques: analog, digital and hybrid. The nam
The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming.
Analog beamforming implementation also allows to enable distributed antenna systems (DAS), where each beam corrisponds to one antenna (or a set of antennas) of the system. In this scenario, the scheduler constaint is alleviated because normally the number of concurrent beams allowed equals the total number of beams.
# Configuration file fields for analog beamforming
A set of parameters in configuration files controls the implementation of analog beamforming and instructs the scheduler on how to behave in such scenarios. Since most notably this technique in 5G is employed in FR2, the configuration file example currently available is a RFsim one for band 261. [Config file example](../ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf)
@@ -18,8 +20,9 @@ In the `MACRLC` section of configuration files, there are three new parameters:
- `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0)
- `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1)
- `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1)
- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted
In the `gNBs` section of the configuration file, under the phyisical parameters, a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. This field is called `beam_weights`. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted.
DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. In case of DAS enabled, the field `beam_weights` in `MACRLC` section can be omitted.
# Implementation in OAI scheduler
@@ -28,3 +31,28 @@ This matrix contains the beams already allocated in a given slot, to flag the sc
To this goal, we extended the virtual resource block (VRB) map by one dimension to also contain information per allocated beam. As said, the scheduler can independently schedule users in a number of beams up to `beams_per_period` concurrently.
It is important to note that in current implementation, there are several periodical channels, e.g. PRACH or PUCCH for CSI et cetera, that have the precendence in being assigned a beam, that is because the scheduling is automatic, set in RRC configuration, and not up to the scheduler. For these instances, we assume the beam is available (if not there are assertions to stop the process). For data channels, the currently implemented PF scheduler is used. The only modification is that a UE can be served only if there is a free beam available or the one of the beams already in use correspond to that UE beam.
# FAPI implementation
To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI.
In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information:
- `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming
- `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period`
- `total_num_beams_vendor_ext` which corresponds to the number of beams configured in `beam_weights`
- `analog_beam_list` which contains the RU beamforming indices configured in `beam_weights`
Additionally, L2 provides in each channel FAPI message information about the beam index. Small Cell Forum (SCF) FAPI provides in its PHY API specifications for the channels only a field for digital beamforming as part of the `precoding_and_beamforming` stucture. Therefore without a better option, we are currently using that one to store the internal analog beamforming index. This is the index used internally by the code to progressively identify the beam with a value from 0 to `total_num_beams_vendor_ext`.
# L1 implementation
To handle multiple concurrent beams, the buffers containing Tx and Rx data in frequency domain (`txdataF` and `rxdataF`) have been extended by one dimension to contain multiple concurrent beams to be transmitted/received.
The function `beam_index_allocation`, called by every L1 channel, is responsible to match the FAPI analog beam index to the RU beam index and to store the latter `beam_id` structure, which allocates the beams per symbol, despite L2 only supporting beam change at slot level. At the same time, the function returns the concurrent beam index, to be used to store data in frequency domain buffers. While doing so, the function also checks if there is room for current beam in the list of concurrent beams, which should always be the case, if L2 properly allocated the channels.
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.
+12 -16
View File
@@ -360,32 +360,29 @@ void term_gNB_Tpool(int inst) {
}
/// eNB kept in function name for nffapi calls, TO FIX
void init_eNB_afterRU(void) {
int inst,ru_id,i,aa;
PHY_VARS_gNB *gNB;
for (inst=0; inst<RC.nb_nr_L1_inst; inst++) {
gNB = RC.gNB[inst];
void init_eNB_afterRU(void)
{
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
PHY_VARS_gNB *gNB = RC.gNB[inst];
phy_init_nr_gNB(gNB);
// map antennas and PRACH signals to gNB RX
if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id);
LOG_D(NR_PHY, "Mapping RX ports from %d RUs to gNB %d\n", gNB->num_RU, gNB->Mod_id);
for (ru_id=0,aa=0; ru_id<gNB->num_RU; ru_id++) {
int aa = 0;
for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) {
AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx);
AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx);
for (i=0; 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 i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) {
LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa);
gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i];
// TODO hardcoded beam to 0, still need to understand how to handle this properly
gNB->common_vars.rxdataF[0][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i];
for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) {
int idx = i + b * gNB->RU_list[ru_id]->nb_rx;
gNB->common_vars.rxdataF[b][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[idx];
}
}
}
/* TODO: review this code, there is something wrong.
* In monolithic mode, we come here with nb_antennas_rx == 0
* (not tested in other modes).
@@ -393,7 +390,6 @@ void init_eNB_afterRU(void) {
//init_precoding_weights(RC.gNB[inst]);
init_gNB_Tpool(inst);
}
}
/**
+48 -51
View File
@@ -240,20 +240,20 @@ int connect_rau(RU_t *ru) {
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
void *buffs[ru->nb_tx];
for (int aid=0;aid<ru->nb_tx;aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset];
void *buffs[ru->nb_tx];
for (int aid = 0; aid < ru->nb_tx; aid++)
buffs[aid] = (void*)&ru->common.txdata[aid][offset];
struct timespec txmeas;
clock_gettime(CLOCK_MONOTONIC, &txmeas);
LOG_D(NR_PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1],
10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec);
ru->ifdevice.trx_write_func2(&ru->ifdevice,
timestamp,
timestamp,
buffs,
0,
ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms),
0,
ru->nb_tx);
0,
ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms),
0,
ru->nb_tx);
}
// southbound IF4p5 fronthaul
@@ -591,33 +591,28 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
openair0_config_t *cfg = &ru->openair0_cfg;
void *rxp[ru->nb_rx];
unsigned int rxs;
int i;
uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp);
uint32_t samples_per_slot_prev ;
openair0_timestamp ts,old_ts;
AssertFatal(*slot<fp->slots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame);
uint32_t samples_per_slot = fp->get_samples_per_slot(*slot, fp);
AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame);
start_meas(&ru->rx_fhaul);
for (i=0; i<ru->nb_rx; i++)
rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)];
int nb = ru->nb_rx * ru->num_beams_period;
void *rxp[nb];
for (int i = 0; i < nb; i++)
rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
old_ts = proc->timestamp_rx;
LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1);
openair0_timestamp old_ts = proc->timestamp_rx;
LOG_D(PHY,"Reading %d samples for slot %d (%p)\n", samples_per_slot, *slot, rxp[0]);
openair0_timestamp ts;
unsigned int rxs;
if(emulate_rf) {
wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
rxs = samples_per_slot;
ts = old_ts + rxs;
} else {
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
&ts,
rxp,
samples_per_slot,
ru->nb_rx);
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
@@ -629,7 +624,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs);
if (proc->first_rx != 1) {
samples_per_slot_prev = fp->get_samples_per_slot((*slot-1)%fp->slots_per_frame,fp);
uint32_t samples_per_slot_prev = fp->get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp);
if (proc->timestamp_rx - old_ts != samples_per_slot_prev) {
LOG_D(PHY,
@@ -752,8 +747,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
void *txp[ru->nb_tx];
int i;
T(T_ENB_PHY_OUTPUT_SIGNAL,
T_INT(0),
T_INT(0),
@@ -820,7 +813,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot);
for (i = 0; i < ru->nb_tx; i++)
int nt = ru->nb_tx * ru->num_beams_period;
void *txp[nt];
for (int i = 0; i < nt; i++)
txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff);
@@ -830,12 +825,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
timestamp + ru->ts_offset - sf_extension,
txp,
siglen + sf_extension,
ru->nb_tx, flags);
nt,
flags);
LOG_D(PHY,
"[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
"[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
"returned %d, E %f\n",
ru->idx,
i,
(long long unsigned int)(timestamp + ru->ts_offset - sf_extension),
frame,
slot,
@@ -851,7 +846,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
static void fill_rf_config(RU_t *ru, char *rf_config_file)
{
int i;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index
openair0_config_t *cfg = &ru->openair0_cfg;
@@ -877,13 +871,14 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
AssertFatal(ru->nb_rx > 0 && ru->nb_rx <= 8, "openair0 does not support more than 8 antennas\n");
cfg->Mod_id = 0;
cfg->num_rb_dl=N_RB;
cfg->tx_num_channels=ru->nb_tx;
cfg->rx_num_channels=ru->nb_rx;
cfg->num_rb_dl = N_RB;
cfg->tx_num_channels = ru->nb_tx * ru->num_beams_period;
cfg->rx_num_channels = ru->nb_rx * ru->num_beams_period;
cfg->num_distributed_ru = ru->num_beams_period;
LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels);
LOG_I(PHY,"tune_offset %.0f Hz, sample_rate %.0f Hz\n",cfg->tune_offset,cfg->sample_rate);
for (i=0; i<ru->nb_tx; i++) {
for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
if (ru->if_frequency == 0) {
cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
} else if (ru->if_freq_offset) {
@@ -898,7 +893,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
i, cfg->tx_gain[i],cfg->tx_freq[i]);
}
for (i=0; i<ru->nb_rx; i++) {
for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) {
if (ru->if_frequency == 0) {
cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
} else if (ru->if_freq_offset) {
@@ -944,8 +939,8 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_
Each rf chain is is addressed by the card number and the chain on the card. The
rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple
antennas are mapped to successive RF chains on the same card. */
int setup_RU_buffers(RU_t *ru) {
int i,j;
int setup_RU_buffers(RU_t *ru)
{
int card,ant;
//uint16_t N_TA_offset = 0;
NR_DL_FRAME_PARMS *fp;
@@ -967,27 +962,27 @@ int setup_RU_buffers(RU_t *ru) {
if (ru->openair0_cfg.mmapped_dma == 1) {
// replace RX signal buffers with mmaped HW versions
for (i=0; i<ru->nb_rx; i++) {
card = i/4;
ant = i%4;
for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) {
card = i / 4;
ant = i % 4;
LOG_D(PHY, "Mapping RU id %u, rx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant);
free(ru->common.rxdata[i]);
ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain + ant];
for (j = 0; j < 16; j++) {
ru->common.rxdata[i][j] = 16-j;
for (int j = 0; j < 16; j++) {
ru->common.rxdata[i][j] = 16 - j;
}
}
for (i=0; i<ru->nb_tx; i++) {
card = i/4;
ant = i%4;
for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
card = i / 4;
ant = i % 4;
LOG_D(PHY, "Mapping RU id %u, tx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant);
free(ru->common.txdata[i]);
ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain + ant];
for (j = 0; j < 16; j++) {
ru->common.txdata[i][j] = 16-j;
for (int j = 0; j < 16; j++) {
ru->common.txdata[i][j] = 16 - j;
}
}
} else { // not memory-mapped DMA
@@ -1054,7 +1049,7 @@ void ru_tx_func(void *param)
ru->fh_north_out(ru);
} else {
if(frame_tx == print_frame) {
for (int i=0; i<ru->nb_tx; i++) {
for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
if(slot_tx == 0) {
sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx);
LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1);
@@ -1324,10 +1319,12 @@ void *ru_thread(void *param)
for (int prach_oc = 0; prach_oc < p->num_prach_ocas; prach_oc++) {
int prachStartSymbol = p->prachStartSymbol + prach_oc * N_dur;
int beam_id = ru->prach_list[prach_id].beam ? ru->prach_list[prach_id].beam[prach_oc] : 0;
//comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach_ru(ru,
p->fmt, // could also use format
p->numRA,
beam_id,
prachStartSymbol,
p->slot,
prach_oc,
+47
View File
@@ -1124,6 +1124,33 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
// only increase if it was set
numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG;
AssertFatal(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == 0,
"Total num beams Vendor extension shouldn't be set!");
// The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set,
// so, it's safe to add the call to pack_nr_tlv even if it is not always set
retval &= pack_nr_tlv(NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG,
&(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext),
ppWritePackedMsg,
end,
&pack_uint8_tlv_value);
// only increase if it was set
numTLVs +=
pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG;
for (int beam = 0; beam < pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value; beam++) {
AssertFatal(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam].tl.tag == 0,
"Analog beams list Vendor extension shouldn't be set!");
// The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set,
// so, it's safe to add the call to pack_nr_tlv even if it is not always set
retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG,
&(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam]),
ppWritePackedMsg,
end,
&pack_uint8_tlv_value);
// only increase if it was set
numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG;
}
pNfapiMsg->num_tlv = numTLVs;
retval &= push8(pNfapiMsg->num_tlv, &pNumTLVFields, end);
return retval;
@@ -1138,6 +1165,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *
int config_beam_idx = 0;
int tdd_periodicity_idx = 0;
int symbol_per_slot_idx = 0;
int beam_ve_idx = 0;
nfapi_nr_config_request_scf_t *pNfapiMsg = (nfapi_nr_config_request_scf_t *)msg;
// unpack TLVs
@@ -1188,6 +1216,10 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *
&unpack_uint8_tlv_value},
{NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), &unpack_uint8_tlv_value},
{NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, NULL, &unpack_uint8_tlv_value},
{NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), &unpack_uint8_tlv_value},
{NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), &unpack_uint8_tlv_value},
{NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value},
{NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value},
{NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value},
{NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), &unpack_ipv4_address_value},
{NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), &unpack_ipv6_address_value},
@@ -1221,6 +1253,21 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *
}
int result = 0;
switch (generic_tl.tag) {
case NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG:
pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = generic_tl.tag;
pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.length = generic_tl.length;
result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext, ppReadPackedMsg, end);
pNfapiMsg->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc(
pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t));
beam_ve_idx = 0;
break;
case NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG:
unpack_fns[idx].tlv = &pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx];
pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.tag = generic_tl.tag;
pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.length = generic_tl.length;
result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end);
beam_ve_idx ++;
break;
case NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG:
pNfapiMsg->prach_config.num_prach_fd_occasions.tl.tag = generic_tl.tag;
pNfapiMsg->prach_config.num_prach_fd_occasions.tl.length = generic_tl.length;
@@ -276,6 +276,17 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const
EQ_TLV(unpacked_req->nfapi_config.timing_info_mode, req->nfapi_config.timing_info_mode);
EQ_TLV(unpacked_req->nfapi_config.timing_info_period, req->nfapi_config.timing_info_period);
EQ_TLV(unpacked_req->analog_beamforming_ve.num_beams_period_vendor_ext, req->analog_beamforming_ve.num_beams_period_vendor_ext);
EQ_TLV(unpacked_req->analog_beamforming_ve.analog_bf_vendor_ext, req->analog_beamforming_ve.analog_bf_vendor_ext);
EQ_TLV(unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext, req->analog_beamforming_ve.total_num_beams_vendor_ext);
for (int i = 0; i < unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) {
EQ_TLV(unpacked_req->analog_beamforming_ve.analog_beam_list[i], req->analog_beamforming_ve.analog_beam_list[i]);
}
return true;
}
@@ -422,6 +433,10 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg)
if (msg->pmi_list.pmi_pdu) {
free(msg->pmi_list.pmi_pdu);
}
if (msg->analog_beamforming_ve.analog_beam_list) {
free(msg->analog_beamforming_ve.analog_beam_list);
}
}
void free_config_response(nfapi_nr_config_response_scf_t *msg)
@@ -832,6 +847,21 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf
COPY_TLV(dst->nfapi_config.ul_dci_timing_offset, src->nfapi_config.ul_dci_timing_offset);
COPY_TLV(dst->nfapi_config.tx_data_timing_offset, src->nfapi_config.tx_data_timing_offset);
COPY_TLV(dst->analog_beamforming_ve.num_beams_period_vendor_ext, src->analog_beamforming_ve.num_beams_period_vendor_ext);
COPY_TLV(dst->analog_beamforming_ve.analog_bf_vendor_ext, src->analog_beamforming_ve.analog_bf_vendor_ext);
COPY_TLV(dst->analog_beamforming_ve.total_num_beams_vendor_ext, src->analog_beamforming_ve.total_num_beams_vendor_ext);
if (dst->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) {
dst->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc(
dst->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t));
for (int i = 0; i < src->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) {
COPY_TLV(dst->analog_beamforming_ve.analog_beam_list[i], src->analog_beamforming_ve.analog_beam_list[i]);
}
}
}
void copy_config_response(const nfapi_nr_config_response_scf_t *src, nfapi_nr_config_response_scf_t *dst)
@@ -31,6 +31,8 @@
#define NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120
#define NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG 0xA000
#define NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG 0xA001
#define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002
#define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003
typedef struct {
uint16_t phy_id;
@@ -24,7 +24,7 @@
#define NFAPI_MAX_NUM_GROUPS 8
#define NFAPI_MAX_NUM_CB 8
#define NFAPI_MAX_NUM_PRGS 1
#define NFAPI_MAX_NUM_BG_IF 1
#define NFAPI_MAX_NUM_BG_IF 6
#define NFAPI_MAX_NUM_PERIODS 8
// Extension to the generic structures for single tlv values
@@ -496,6 +496,8 @@ typedef struct {
typedef struct {
nfapi_uint8_tlv_t num_beams_period_vendor_ext;
nfapi_uint8_tlv_t analog_bf_vendor_ext;
nfapi_uint8_tlv_t total_num_beams_vendor_ext;
nfapi_uint8_tlv_t *analog_beam_list;
} nfapi_nr_analog_beamforming_ve_t;
// ERROR enums
@@ -229,6 +229,33 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap
FILL_TLV(nfapi_resp->nfapi_config.timing_info_period, NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, rand8());
nfapi_resp->num_tlv++;
/*
// TODO: Uncomment this block when ready to enable the pack of the following VE TLVs in nr_fapi_p5.c
// NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG
// NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG
// NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG
// NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG
FILL_TLV(nfapi_resp->analog_beamforming_ve.num_beams_period_vendor_ext,
NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG,
rand8());
nfapi_resp->num_tlv++;
FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_bf_vendor_ext, NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, rand8());
nfapi_resp->num_tlv++;
FILL_TLV(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext,
NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG,
rand8());
nfapi_resp->num_tlv++;
if (nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) {
nfapi_resp->analog_beamforming_ve.analog_beam_list =
(nfapi_uint8_tlv_t *)malloc(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t));
for (int i = 0; i < nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) {
FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_beam_list[i], NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, rand8());
nfapi_resp->num_tlv++;
}
}*/
}
static void test_pack_unpack(nfapi_nr_config_request_scf_t *req)
+1 -2
View File
@@ -172,8 +172,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
for (int i = 0; i < common_vars->num_beams_period; i++)
common_vars->rxdataF[i] = (c16_t **)malloc16(Prx * sizeof(c16_t*));
common_vars->num_beams = cfg->dbt_config.num_dig_beams;
if (common_vars->num_beams > 0) {
if (cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) {
common_vars->beam_id = (int **)malloc16(common_vars->num_beams_period * sizeof(int*));
for (int i = 0; i < common_vars->num_beams_period; i++)
common_vars->beam_id[i] = (int*)malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int));
+37 -36
View File
@@ -29,7 +29,7 @@
void init_prach_ru_list(RU_t *ru);
int nr_phy_init_RU(RU_t *ru)
void nr_phy_init_RU(RU_t *ru)
{
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -47,36 +47,40 @@ int nr_phy_init_RU(RU_t *ru)
AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas);
ru->common.beam_id = malloc16_clear(MAX_NUM_BEAM_PERIODS * sizeof(int*));
for(int i = 0; i < MAX_NUM_BEAM_PERIODS; i++)
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
int nb_tx_streams = ru->nb_tx * ru->num_beams_period;
int nb_rx_streams = ru->nb_rx * ru->num_beams_period;
LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period);
ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*));
for(int i = 0; i < ru->num_beams_period; i++)
ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int));
if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals
// Time-domain signals
ru->common.txdata = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*));
ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) );
ru->common.txdata = (int32_t**)malloc16(nb_tx_streams * sizeof(int32_t*));
ru->common.rxdata = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*));
for (int i = 0; i < ru->nb_tx; i++) {
for (int i = 0; i < nb_tx_streams; i++) {
// Allocate 10 subframes of I/Q TX signal data (time) if not
ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t));
ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t));
LOG_D(PHY,
"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",
i,
ru->common.txdata[i],
(ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t),
ru->sf_extension);
ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension];
ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension];
LOG_D(PHY, "[INIT] common.txdata[%d] = %p \n", i, ru->common.txdata[i]);
}
for (int i = 0; i < ru->nb_rx; i++) {
ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_frame*sizeof(int32_t) );
for (int i = 0; i < nb_rx_streams; i++) {
ru->common.rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame * sizeof(int32_t));
}
} // IF5 or local RF
else {
ru->common.txdata = (int32_t**)NULL;
ru->common.rxdata = (int32_t**)NULL;
ru->common.txdata = (int32_t**)NULL;
ru->common.rxdata = (int32_t**)NULL;
}
if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing
LOG_D(PHY, "nb_tx %d\n", ru->nb_tx);
@@ -85,7 +89,6 @@ int nr_phy_init_RU(RU_t *ru)
ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_subframe*2*sizeof(int32_t) );
LOG_D(PHY, "rxdata_7_5kHz[%d] %p for RU %d\n", i, ru->common.rxdata_7_5kHz[i], ru->idx);
}
// allocate precoding input buffers (TX)
ru->common.txdataF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*));
@@ -94,15 +97,15 @@ int nr_phy_init_RU(RU_t *ru)
ru->common.txdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
// allocate IFFT input buffers (TX)
ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*));
LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, ru->nb_tx * sizeof(int32_t *));
for (int i = 0; i < ru->nb_tx; i++) {
ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP*sizeof(int32_t) );
ru->common.txdataF_BF = (int32_t **)malloc16(nb_tx_streams * sizeof(int32_t*));
LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, nb_tx_streams * sizeof(int32_t *));
for (int i = 0; i < nb_tx_streams; i++) {
ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t));
LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx);
}
// allocate FFT output buffers (RX)
ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) );
for (int i = 0; i < ru->nb_rx; i++) {
ru->common.rxdataF = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*));
for (int i = 0; i < nb_rx_streams; i++) {
// allocate 4 slots of I/Q signal data (frequency)
int size = RU_RX_SLOT_DEPTH * fp->symbols_per_slot * fp->ofdm_symbol_size;
ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(**ru->common.rxdataF) * size);
@@ -113,40 +116,38 @@ int nr_phy_init_RU(RU_t *ru)
// AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]),
// "nb_antennas_rx too large");
for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) {
ru->prach_rxsigF[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*));
ru->prach_rxsigF[j] = (int16_t**)malloc(nb_rx_streams * sizeof(int16_t*));
for (int i = 0; i < ru->nb_rx; i++) {
for (int i = 0; i < nb_rx_streams; i++) {
// largest size for PRACH FFT is 4x98304 (16*24576)
ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear( 4*98304*2*sizeof(int16_t) );
LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,ru->prach_rxsigF[j][i]);
ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t));
LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]);
}
}
AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX,"gNB instances %d > %d\n",
ru->num_gNB,NUMBER_OF_gNB_MAX);
AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX, "gNB instances %d > %d\n", ru->num_gNB,NUMBER_OF_gNB_MAX);
LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB);
} // !=IF5
init_prach_ru_list(ru);
return(0);
}
void nr_phy_free_RU(RU_t *ru)
{
LOG_D(PHY, "Freeing RU signal buffers (if_south %s) nb_tx %d\n", ru_if_types[ru->if_south], ru->nb_tx);
int nb_tx_streams = ru->nb_tx * ru->num_beams_period;
int nb_rx_streams = ru->nb_rx * ru->num_beams_period;
if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals
// Hack: undo what is done at allocation
for (int i = 0; i < ru->nb_tx; i++) {
for (int i = 0; i < nb_tx_streams; i++) {
int32_t *p = &ru->common.txdata[i][-ru->sf_extension];
free_and_zero(p);
}
free_and_zero(ru->common.txdata);
for (int i = 0; i < ru->nb_rx; i++)
for (int i = 0; i < nb_rx_streams; i++)
free_and_zero(ru->common.rxdata[i]);
free_and_zero(ru->common.rxdata);
} // else: IF5 or local RF -> nothing to free()
@@ -162,21 +163,21 @@ void nr_phy_free_RU(RU_t *ru)
free_and_zero(ru->common.txdataF);
// free IFFT input buffers (TX)
for (int i = 0; i < ru->nb_tx; i++)
for (int i = 0; i < nb_tx_streams; i++)
free_and_zero(ru->common.txdataF_BF[i]);
free_and_zero(ru->common.txdataF_BF);
// free FFT output buffers (RX)
for (int i = 0; i < ru->nb_rx; i++)
for (int i = 0; i < nb_rx_streams; i++)
free_and_zero(ru->common.rxdataF[i]);
free_and_zero(ru->common.rxdataF);
for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) {
for (int i = 0; i < ru->nb_rx; i++)
for (int i = 0; i < nb_rx_streams; i++)
free_and_zero(ru->prach_rxsigF[j][i]);
free_and_zero(ru->prach_rxsigF[j]);
}
for(int i = 0; i < MAX_NUM_BEAM_PERIODS; ++i)
for(int i = 0; i < ru->num_beams_period; ++i)
free_and_zero(ru->common.beam_id[i]);
free_and_zero(ru->common.beam_id);
}
+3 -1
View File
@@ -81,7 +81,9 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB,
int dci_idx = 0;
// multi-beam number (for concurrent beams)
int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols);
int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx,
int beam_nb = beam_index_allocation(gNB->enable_analog_das,
dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
frame_parms->symbols_per_slot,
+3 -1
View File
@@ -680,7 +680,9 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming;
// beam number in multi-beam scenario (concurrent beams)
int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols);
int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
int beam_nb = beam_index_allocation(gNB->enable_analog_das,
pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
frame_parms->symbols_per_slot,
+25 -15
View File
@@ -42,7 +42,6 @@ void init_prach_list(PHY_VARS_gNB *gNB)
for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++){
gNB->prach_vars.list[i].frame = -1;
gNB->prach_vars.list[i].slot = -1;
gNB->prach_vars.list[i].beam_nb = -1;
gNB->prach_vars.list[i].num_slots = -1;
}
}
@@ -51,8 +50,8 @@ void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id)
{
gNB->prach_vars.list[prach_id].frame = -1;
gNB->prach_vars.list[prach_id].slot = -1;
gNB->prach_vars.list[prach_id].beam_nb = -1;
gNB->prach_vars.list[prach_id].num_slots = -1;
free_and_zero(gNB->prach_vars.list[prach_id].beam_nb);
}
int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) {
@@ -70,7 +69,7 @@ int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) {
return -1;
}
void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu)
int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu)
{
int prach_id = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE);
AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)), "illegal or no prach_id found!!! prach_id %d\n", prach_id);
@@ -79,16 +78,25 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p
prach->slot = Slot;
const int format = prach_pdu->prach_format;
prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1;
prach->beam_nb = 0;
if (gNB->common_vars.beam_id) {
int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
// TODO no idea how to compute final prach symbol here so for now we go til the end of the slot
int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol;
int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols);
prach->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap);
int n_symb = get_nr_prach_duration(prach_pdu->prach_format);
prach->beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->beam_nb));
for (int i = 0; i < prach_pdu->beamforming.dig_bf_interface; i++) {
int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx;
int start_symb = prach_pdu->prach_start_symbol + i * n_symb;
int bitmap = SL_to_bitmap(start_symb, n_symb);
prach->beam_nb[i] = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
Slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
}
}
LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id);
memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu));
return prach_id;
}
void init_prach_ru_list(RU_t *ru)
@@ -121,10 +129,10 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type)
return -1;
}
void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu)
void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id)
{
int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE);
AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0),
AssertFatal((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX),
"illegal or no prach_id found!!! prach_id %d\n",
prach_id);
@@ -135,6 +143,7 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p
ru->prach_list[prach_id].num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1;
ru->prach_list[prach_id].fmt = fmt;
ru->prach_list[prach_id].numRA = prach_pdu->num_ra;
ru->prach_list[prach_id].beam = beam_id;
ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol;
ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas;
pthread_mutex_unlock(&ru->prach_list_mutex);
@@ -151,6 +160,7 @@ void free_nr_ru_prach_entry(RU_t *ru, int prach_id)
void rx_nr_prach_ru(RU_t *ru,
int prachFormat,
int numRA,
int beam,
int prachStartSymbol,
int prachStartSlot,
int prachOccasion,
@@ -159,7 +169,6 @@ void rx_nr_prach_ru(RU_t *ru,
{
AssertFatal(ru != NULL,"ru is null\n");
int16_t **rxsigF = NULL;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int slot2 = slot;
int16_t *prach[ru->nb_rx];
@@ -191,15 +200,16 @@ void rx_nr_prach_ru(RU_t *ru,
prachStartSymbol,
prachOccasion);
rxsigF = ru->prach_rxsigF[prachOccasion];
int16_t **rxsigF = ru->prach_rxsigF[prachOccasion];
AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5,
"we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n");
for (int aa=0; aa<ru->nb_rx; aa++){
for (int aa = 0; aa < ru->nb_rx; aa++) {
if (prach_sequence_length == 0)
slot2 = prachStartSlot;
prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset];
int idx = aa + beam * ru->nb_rx;
prach[aa] = (int16_t*)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset];
}
int reps;
+5 -10
View File
@@ -257,14 +257,11 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB,
int slot,
nfapi_nr_pusch_pdu_t *ulsch_pdu);
void nr_fill_prach(PHY_VARS_gNB *gNB,
int SFN,
int Slot,
nfapi_nr_prach_pdu_t *prach_pdu);
int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu);
void rx_nr_prach(PHY_VARS_gNB *gNB,
nfapi_nr_prach_pdu_t *prach_pdu,
int prachOccasion,
int prachOccasion,
int frame,
int subframe,
uint16_t *max_preamble,
@@ -274,16 +271,14 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
void rx_nr_prach_ru(RU_t *ru,
int prach_fmt,
int numRA,
int beam,
int prachStartSymbol,
int prachStartSlot,
int prachOccasion,
int frame,
int subframe);
void nr_fill_prach_ru(RU_t *ru,
int SFN,
int Slot,
nfapi_nr_prach_pdu_t *prach_pdu);
void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb);
int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type);
int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type);
@@ -309,7 +304,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB,
void init_prach_list(PHY_VARS_gNB *gNB);
void init_prach_ru_list(RU_t *ru);
void free_nr_ru_prach_entry(RU_t *ru, int prach_id);
uint8_t get_nr_prach_duration(uint8_t prach_format);
int get_nr_prach_duration(uint8_t prach_format);
void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id);
+7 -1
View File
@@ -76,7 +76,13 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t
if (gNB->common_vars.beam_id) {
int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols);
ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap);
ulsch->beam_nb = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
}
ulsch->frame = frame;
ulsch->slot = slot;
+8 -5
View File
@@ -57,10 +57,7 @@
//#define DEBUG_NR_PUCCH_RX 1
void nr_fill_pucch(PHY_VARS_gNB *gNB,
int frame,
int slot,
nfapi_nr_pucch_pdu_t *pucch_pdu)
void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu)
{
bool found = false;
for (int i = 0; i < gNB->max_nb_pucch; i++) {
@@ -73,7 +70,13 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB,
if (gNB->common_vars.beam_id) {
int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols);
pucch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap);
pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
}
memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t));
LOG_D(PHY,
+7 -1
View File
@@ -59,7 +59,13 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu
if (gNB->common_vars.beam_id) {
int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols);
int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
srs->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap);
srs->beam_nb = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
}
memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t));
break;
+5
View File
@@ -172,6 +172,7 @@ typedef struct RU_prec_t_s{
typedef struct {
int aid;
int beam;
struct RU_t_s *ru;
int startSymbol;
int endSymbol;
@@ -181,6 +182,7 @@ typedef struct {
typedef struct {
int aid;
int beam;
struct RU_t_s *ru;
int slot;
int startSymbol;
@@ -196,6 +198,7 @@ typedef struct {
int prachStartSymbol;
int num_prach_ocas;
int num_slots;
int *beam;
} RU_PRACH_list_t;
#define NUMBER_OF_NR_RU_PRACH_MAX 8
@@ -488,6 +491,8 @@ typedef struct RU_t_s {
int nb_rx;
/// number of TX paths on device
int nb_tx;
/// number of concurrent analog beams in period
int num_beams_period;
/// number of logical antennas at TX beamformer input
int nb_log_antennas;
/// maximum PDSCH RS EPRE
+3 -2
View File
@@ -138,9 +138,9 @@ typedef struct {
int frame;
int slot;
// identifier for concurrent beams
int beam_nb;
// prach duration in slots
int num_slots;
int *beam_nb;
nfapi_nr_prach_pdu_t pdu;
} gNB_PRACH_list_t;
@@ -287,7 +287,6 @@ typedef struct {
/// - first index: beam index (for concurrent beams)
/// - second index: beam_id [0.. symbols_per_frame[
int **beam_id;
int num_beams;
int num_beams_period;
bool analog_bf;
int32_t *debugBuff;
@@ -493,6 +492,8 @@ typedef struct PHY_VARS_gNB_s {
int num_ulprbbl;
uint16_t ulprbbl [MAX_BWP_SIZE];
bool enable_analog_das;
time_stats_t phy_proc_tx;
time_stats_t phy_proc_rx;
time_stats_t rx_prach;
+2 -2
View File
@@ -157,9 +157,9 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti
UL_tti_req->SFN,
UL_tti_req->Slot);
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu;
nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
int id = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
if (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)
nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, gNB->prach_vars.list[id].beam_nb);
break;
case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE:
LOG_D(NR_PHY,
+7 -55
View File
@@ -37,62 +37,14 @@
#include "nfapi_pnf.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "assertions.h"
#include <time.h>
uint8_t get_nr_prach_duration(uint8_t prach_format){
switch(prach_format){
case 0: // format 0
return 0;
case 1: // format 1
return 0;
case 2: // format 2
return 0;
case 3: // format 3
return 0;
case 4: // format A1
return 2;
case 5: // format A2
return 4;
case 6: // format A3
return 6;
case 7: // format B1
return 2;
case 8: // format B4
return 12;
case 9: // format C0
return 2;
case 10: // format C2
return 6;
case 11: // format A1/B1
return 2;
case 12: // format A2/B2
return 4;
case 13: // format A3/B3
return 6;
default :
AssertFatal(1==0,"Invalid Prach format\n");
break;
}
int get_nr_prach_duration(uint8_t prach_format)
{
const int val[14] = {0, 0, 0, 0, 2, 4, 6, 2, 12, 2, 6, 2, 4, 6};
AssertFatal(prach_format < sizeofArray(val), "Invalid Prach format %d\n", prach_format);
return val[prach_format];
}
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind)
@@ -117,14 +69,14 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list[prach_id].pdu;
const int prach_start_slot = gNB->prach_vars.list[prach_id].slot;
uint8_t prachStartSymbol;
uint8_t N_dur = get_nr_prach_duration(prach_pdu->prach_format);
int N_dur = get_nr_prach_duration(prach_pdu->prach_format);
for(int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) {
for (ru_aa=0,aa=0;ru_aa<ru->nb_rx;ru_aa++,aa++) {
gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa];
}
prachStartSymbol = prach_pdu->prach_start_symbol+prach_oc*N_dur;
prachStartSymbol = prach_pdu->prach_start_symbol + prach_oc * N_dur;
//comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach(gNB,
+93 -114
View File
@@ -47,7 +47,7 @@
// RU OFDM Modulator gNodeB
// OFDM modulation core routine, generates a first_symbol to first_symbol+num_symbols on a particular slot and TX antenna port
void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa)
void nr_feptx0(RU_t *ru, int tti_tx, int first_symbol, int num_symbols, int aa)
{
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -175,57 +175,39 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
}
void nr_feptx_prec(RU_t *ru, int frame_tx, int tti_tx)
void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx)
{
PHY_VARS_gNB **gNB_list = ru->gNB_list,*gNB;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
PHY_VARS_gNB **gNB_list = ru->gNB_list;
AssertFatal(ru->num_gNB == 1, "Cannot handle more than 1 gNB\n");
PHY_VARS_gNB *gNB = gNB_list[0];
nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
int slot_tx = tti_tx;
int txdataF_offset = (tti_tx*fp->samples_per_slot_wCP);
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int txdataF_offset = slot_tx * fp->samples_per_slot_wCP;
start_meas(&ru->precoding_stats);
AssertFatal(ru->nb_log_antennas > 0, "ru->nb_log_antennas is 0!\n");
if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT)
return;
if (ru->num_gNB == 1) {
gNB = gNB_list[0];
if (gNB->common_vars.analog_bf) {
for (int i = 0; i < ru->num_beams_period; i++) {
memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot],
(void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot],
(fp->symbols_per_slot) * sizeof(int));
}
}
if (ru->config.dbt_config.num_dig_beams != 0) {
for(int i = 0; i < gNB->common_vars.num_beams_period; ++i) {
memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot],
(void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot],
(fp->symbols_per_slot) * sizeof(int));
}
}
if (ru->config.dbt_config.num_dig_beams == 0 || gNB->common_vars.analog_bf) {
for (int i = 0; i < ru->nb_log_antennas; ++i) {
// TODO hardcoded beam to 0, still need to understand how to handle this properly
memcpy(ru->common.txdataF_BF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t));
}
}
else {
for(int i = 0; i < ru->nb_log_antennas; ++i) {
// TODO hardcoded beam to 0, still need to understand how to handle this properly
memcpy(ru->common.txdataF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t));
}
for (int l = 0; l < fp->symbols_per_slot; l++) {
for (int aa = 0; aa < ru->nb_tx; aa++) {
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
nr_beam_precoding((c16_t **)ru->common.txdataF,
(c16_t **)ru->common.txdataF_BF,
fp,
ru->beam_weights[0],
tti_tx,
l,
aa,
ru->nb_log_antennas,
0);
}
// If there is no digital beamforming we just need to copy the data to RU
if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) {
for (int b = 0; b < ru->num_beams_period; b++) {
for (int i = 0; i < ru->nb_tx; ++i) {
int tx_idx = i + b * ru->nb_tx;
memcpy((void*)ru->common.txdataF_BF[tx_idx],
(void*)&gNB->common_vars.txdataF[b][i][txdataF_offset],
fp->samples_per_slot_wCP * sizeof(int32_t));
}
}
} else {
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
}
stop_meas(&ru->precoding_stats);
}
@@ -238,6 +220,7 @@ void nr_feptx(void *arg)
RU_t *ru = feptx->ru;
int slot = feptx->slot;
int aa = feptx->aid;
int bb = feptx->beam;
int startSymbol = feptx->startSymbol;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int numSymbols = feptx->numSymbols;
@@ -246,44 +229,32 @@ void nr_feptx(void *arg)
int txdataF_BF_offset = startSymbol * fp->ofdm_symbol_size;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 1);
int tx_idx = aa + bb * ru->nb_tx;
if (aa == 0)
if (tx_idx == 0)
start_meas(&ru->precoding_stats);
if (ru->config.dbt_config.num_dig_beams != 0) {
for(int i = 0; i < ru->gNB_list[0]->common_vars.num_beams_period; i++) {
memcpy(&ru->common.beam_id[i][slot * fp->symbols_per_slot],
&ru->gNB_list[0]->common_vars.beam_id[i][slot * fp->symbols_per_slot],
(fp->symbols_per_slot) * sizeof(int));
}
if (ru->gNB_list[0]->common_vars.analog_bf) {
memcpy(&ru->common.beam_id[bb][slot * fp->symbols_per_slot],
&ru->gNB_list[0]->common_vars.beam_id[bb][slot * fp->symbols_per_slot],
(fp->symbols_per_slot) * sizeof(int));
}
// If there is no digital beamforming we just need to copy the data to RU
if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf)
memcpy((void*)&ru->common.txdataF_BF[aa][txdataF_BF_offset],
(void*)&ru->gNB_list[0]->common_vars.txdataF[0][aa][txdataF_offset], // TODO hardcoded beam to 0, still need to understand how to handle this properly
memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset],
(void*)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset],
numSamples * sizeof(int32_t));
else {
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
for(int i = 0; i < fp->symbols_per_slot; ++i) {
nr_beam_precoding((c16_t **)ru->gNB_list[0]->common_vars.txdataF,
(c16_t **)ru->common.txdataF_BF,
fp,
ru->beam_weights[0],
slot,
i,
aa,
ru->nb_log_antennas,
txdataF_offset);
}
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
}
if (aa==0)
if (tx_idx == 0)
stop_meas(&ru->precoding_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 0);
////////////FEPTX////////////
nr_feptx0(ru, slot, startSymbol, numSymbols, aa);
nr_feptx0(ru, slot, startSymbol, numSymbols, tx_idx);
// Task completed in //
completed_task_ans(feptx->ans);
@@ -299,39 +270,42 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 1);
start_meas(&ru->ofdm_total_stats);
size_t const sz = ru->nb_tx + (ru->half_slot_parallelization > 0) * ru->nb_tx;
int nt = ru->nb_tx * ru->num_beams_period;
size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt;
feptx_cmd_t arr[sz];
task_ans_t ans;
init_task_ans(&ans, sz);
int nbfeptx = 0;
for (int aid = 0; aid < ru->nb_tx; aid++) {
feptx_cmd_t *feptx_cmd = &arr[nbfeptx];
feptx_cmd->ans = &ans;
feptx_cmd->aid = aid;
feptx_cmd->ru = ru;
feptx_cmd->slot = slot;
feptx_cmd->startSymbol = 0;
feptx_cmd->numSymbols =
(ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot;
task_t t = {.func = nr_feptx, .args = feptx_cmd};
pushTpool(ru->threadPool, t);
nbfeptx++;
if (ru->half_slot_parallelization > 0) {
for (int beam = 0; beam < ru->num_beams_period; beam++) {
for (int aid = 0; aid < ru->nb_tx; aid++) {
feptx_cmd_t *feptx_cmd = &arr[nbfeptx];
feptx_cmd->ans = &ans;
feptx_cmd->beam = beam;
feptx_cmd->aid = aid;
feptx_cmd->ru = ru;
feptx_cmd->slot = slot;
feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1;
feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1;
feptx_cmd->startSymbol = 0;
feptx_cmd->numSymbols =
(ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot;
task_t t = {.func = nr_feptx, .args = feptx_cmd};
pushTpool(ru->threadPool, t);
nbfeptx++;
if (ru->half_slot_parallelization > 0) {
feptx_cmd_t *feptx_cmd = &arr[nbfeptx];
feptx_cmd->ans = &ans;
feptx_cmd->beam = beam;
feptx_cmd->aid = aid;
feptx_cmd->ru = ru;
feptx_cmd->slot = slot;
feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1;
feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1;
task_t t = {.func = nr_feptx, .args = feptx_cmd};
pushTpool(ru->threadPool, t);
nbfeptx++;
}
}
}
join_task_ans(&ans);
@@ -345,24 +319,26 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot)
void nr_fep(void* arg)
{
feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg;
RU_t *ru = feprx_cmd->ru;
int aid = feprx_cmd->aid;
int tti_rx = feprx_cmd->slot;
int startSymbol = feprx_cmd->startSymbol;
int endSymbol = feprx_cmd->endSymbol;
RU_t *ru = feprx_cmd->ru;
int aid = feprx_cmd->aid;
int beam = feprx_cmd->beam;
int slot = feprx_cmd->slot;
int startSymbol = feprx_cmd->startSymbol;
int endSymbol = feprx_cmd->endSymbol;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, tti_rx, startSymbol, endSymbol);
LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, slot, startSymbol, endSymbol);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1);
int offset = (tti_rx % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size;
int idx = aid + beam * ru->nb_rx;
int offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size;
for (int l = startSymbol; l <= endSymbol; l++)
nr_slot_fep_ul(fp,
ru->common.rxdata[aid],
&ru->common.rxdataF[aid][offset],
ru->common.rxdata[idx],
&ru->common.rxdataF[idx][offset],
l,
tti_rx,
slot,
ru->N_TA_offset);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0);
@@ -377,39 +353,42 @@ void nr_fep_tp(RU_t *ru, int slot) {
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 );
start_meas(&ru->ofdm_demod_stats);
size_t const sz = ru->nb_rx + (ru->half_slot_parallelization > 0) * ru->nb_rx;
int nt = ru->nb_rx * ru->num_beams_period;
size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt;
feprx_cmd_t arr[sz];
task_ans_t ans;
init_task_ans(&ans, sz);
for (int aid=0;aid<ru->nb_rx;aid++) {
feprx_cmd_t *feprx_cmd = &arr[nbfeprx];
feprx_cmd->ans = &ans;
feprx_cmd->aid = aid;
feprx_cmd->ru = ru;
feprx_cmd->slot = ru->proc.tti_rx;
feprx_cmd->startSymbol = 0;
feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1
: (ru->nr_frame_parms->symbols_per_slot - 1);
task_t t = {.func = nr_fep, .args = feprx_cmd};
pushTpool(ru->threadPool, t);
nbfeprx++;
if (ru->half_slot_parallelization > 0) {
for (int beam = 0; beam < ru->num_beams_period; beam++) {
for (int aid = 0; aid < ru->nb_rx; aid++) {
feprx_cmd_t *feprx_cmd = &arr[nbfeprx];
feprx_cmd->ans = &ans;
feprx_cmd->beam = beam;
feprx_cmd->aid = aid;
feprx_cmd->ru = ru;
feprx_cmd->slot = ru->proc.tti_rx;
feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1;
feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1;
feprx_cmd->startSymbol = 0;
feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1
: (ru->nr_frame_parms->symbols_per_slot - 1);
task_t t = {.func = nr_fep, .args = feprx_cmd};
pushTpool(ru->threadPool, t);
nbfeprx++;
if (ru->half_slot_parallelization > 0) {
feprx_cmd_t *feprx_cmd = &arr[nbfeprx];
feprx_cmd->ans = &ans;
feprx_cmd->beam = beam;
feprx_cmd->aid = aid;
feprx_cmd->ru = ru;
feprx_cmd->slot = ru->proc.tti_rx;
feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1;
feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1;
task_t t = {.func = nr_fep, .args = feprx_cmd};
pushTpool(ru->threadPool, t);
nbfeprx++;
}
}
}
join_task_ans(&ans);
+21 -9
View File
@@ -45,18 +45,26 @@
//#define DEBUG_RXDATA
//#define SRS_IND_DEBUG
int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols)
int beam_index_allocation(bool das,
int fapi_beam_index,
nfapi_nr_analog_beamforming_ve_t *analog_bf,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols)
{
if (!common_vars->beam_id)
return 0;
if (das)
return fapi_beam_index;
int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value;
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++) {
if (((bitmap_symbols >> i) & 0x01) == 0)
continue;
int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i];
if (current_beam == -1 || current_beam == fapi_beam_index)
if (current_beam == -1 || current_beam == ru_beam_idx)
idx = j;
else {
idx = -1;
@@ -66,12 +74,12 @@ int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int s
if (idx != -1)
break;
}
AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", fapi_beam_index);
AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", ru_beam_idx);
for (int j = 0; j < symbols_per_slot; j++) {
if (((bitmap_symbols >> j) & 0x01))
common_vars->beam_id[idx][slot * symbols_per_slot + j] = fapi_beam_index;
common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx;
}
LOG_D(PHY, "Allocating beam %d in slot %d\n", idx, slot);
LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot);
return idx;
}
@@ -131,7 +139,9 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n
int txdataF_offset = slot * fp->samples_per_slot_wCP;
// beam number in a scenario with multiple concurrent beams
int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols
int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
int beam_nb = beam_index_allocation(gNB->enable_analog_das,
pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
&cfg->analog_beamforming_ve,
&gNB->common_vars,
slot,
fp->symbols_per_slot,
@@ -272,7 +282,9 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx,
int lprime_num = mapping_parms.lprime + 1;
for (int j = 0; j < mapping_parms.size; j++)
csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j];
int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
int beam_nb = beam_index_allocation(gNB->enable_analog_das,
pb->prgs_list[0].dig_bf_interface_list[0].beam_idx,
&cfg->analog_beamforming_ve,
&gNB->common_vars,
slot,
fp->symbols_per_slot,
+8 -2
View File
@@ -44,8 +44,14 @@ void nr_feptx_prec_control(RU_t *ru,int frame,int tti_tx);
void nr_fep_tp(RU_t *ru, int slot);
void nr_feptx_tp(RU_t *ru, int frame_tx, int slot);
void feptx_prec(RU_t *ru,int frame_tx,int tti_tx);
int nr_phy_init_RU(RU_t *ru);
void nr_phy_init_RU(RU_t *ru);
void nr_phy_free_RU(RU_t *ru);
void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot);
int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols);
int beam_index_allocation(bool das,
int fapi_beam_index,
nfapi_nr_analog_beamforming_ve_t *analog_bf,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols);
#endif
+1 -1
View File
@@ -773,7 +773,7 @@ int main(int argc, char **argv){
}
}
rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, slot, prachOccasion, frame, slot);
rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot);
for (int i = 0; i < ru->nb_rx; ++i)
gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i];
+7 -3
View File
@@ -61,6 +61,8 @@
#define HLP_L1_PHASE_COMP "Apply NR symbolwise phase rotation"
#define CONFIG_STRING_NUM_ANTENNAS_PER_THREAD "dmrs_num_antennas_per_thread"
#define HLP_NUM_ARX "Number of antennas per thread for PUSCH channel estimation"
#define CONFIG_STRING_ANALOG_DAS "enable_das"
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
/* L1 configuration parameters */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
@@ -81,12 +83,13 @@
{CONFIG_STRING_L1_PRACH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=150, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=50, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_SRS_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=30, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_NUM_ANTENNAS_PER_THREAD, HLP_NUM_ARX,0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_ANALOG_DAS, NULL, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
}
// clang-format on
#define L1_CC_IDX 0
@@ -109,6 +112,7 @@
#define L1_TX_AMP_BACKOFF_dB 17
#define L1_PHASE_COMP 18
#define NUM_ANTENNAS_PER_THREAD 19
#define L1_ANALOG_DAS 20
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
#endif
+6 -2
View File
@@ -76,6 +76,7 @@
#define CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING "set_analog_beamforming"
#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration"
#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period"
#define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights"
#define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold"
@@ -143,6 +144,7 @@
{CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, PARAMFLAG_BOOL, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \
{CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \
@@ -189,8 +191,9 @@
#define MACRLC_ANALOG_BEAMFORMING_IDX 36
#define MACRLC_ANALOG_BEAM_DURATION_IDX 37
#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38
#define MACRLC_PUSCH_RSSI_THRES_IDX 39
#define MACRLC_PUCCH_RSSI_THRES_IDX 40
#define MACRLC_BEAMWEIGHTS_IDX 39
#define MACRLC_PUSCH_RSSI_THRES_IDX 40
#define MACRLC_PUCCH_RSSI_THRES_IDX 41
#define MACRLCPARAMS_CHECK { \
{ .s5 = { NULL } }, \
@@ -232,6 +235,7 @@
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \
}
+22 -13
View File
@@ -1067,6 +1067,7 @@ void RCconfig_NR_L1(void)
gNB->TX_AMP = min(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)), INT16_MAX);
gNB->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr;
gNB->dmrs_num_antennas_per_thread = *(L1_ParamList.paramarray[j][NUM_ANTENNAS_PER_THREAD].uptr);
gNB->enable_analog_das = *(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr);
LOG_I(NR_PHY, "TX_AMP = %d (-%d dBFS)\n", gNB->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr);
AssertFatal(gNB->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", gNB->TX_AMP);
// Midhaul configuration
@@ -1621,19 +1622,6 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
config.timer_config.n311,
config.timer_config.t319);
if (config_isparamset(GNBParamList.paramarray[0], GNB_BEAMWEIGHTS_IDX)) {
int n = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].numelt;
AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n");
// each beam is described by a set of weights (one for each antenna)
// on the other hand in case of analog beamforming an index to the RU beam identifier is provided
config.nb_bfw[0] = num_tx; // number of tx antennas
config.nb_bfw[1] = n / num_tx; // number of beams
config.bw_list = malloc16_clear(n * sizeof(*config.bw_list));
for (int b = 0; b < n; b++) {
config.bw_list[b] = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].iptr[b];
}
}
// Construct default aggragation level list or read from config
int uess_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
@@ -1763,6 +1751,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
}
bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr;
if (ab) {
AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n");
NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info;
int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr;
beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *));
@@ -1770,6 +1759,26 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
beam_info->beams_per_period = beams_per_period;
beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration
}
if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) {
if (NFAPI_MODE == NFAPI_MONOLITHIC) {
GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL);
AssertFatal(*(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr) == 0, "No need to set beam weights in case of DAS\n");
}
int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt;
int num_beam = n;
if (!ab) {
AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n");
num_beam = n / num_tx;
}
// each beam is described by a set of weights (one for each antenna)
// in case of analog beamforming an index to the RU beam identifier is provided
// (one for each beam regardless of the number of antennas per beam)
config.nb_bfw[0] = num_tx; // number of tx antennas
config.nb_bfw[1] = num_beam; // number of beams weights/indices
config.bw_list = calloc_or_fail(n, sizeof(*config.bw_list));
for (int b = 0; b < n; b++)
config.bw_list[b] = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].iptr[b];
}
// triggers also PHY initialization in case we have L1 via FAPI
nr_mac_config_scc(RC.nrmac[j], scc, &config);
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
+4 -8
View File
@@ -137,7 +137,6 @@ typedef enum {
#define GNB_CONFIG_STRING_GNB_CU_UP_ID "gNB_CU_UP_ID"
#define GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES "num_dlharq"
#define GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES "num_ulharq"
#define GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST "beam_weights"
#define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels"
#define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs"
#define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs"
@@ -198,7 +197,6 @@ typedef enum {
{GNB_CONFIG_STRING_DISABLE_HARQ, GNB_CONFIG_HLP_DISABLE_HARQ, PARAMFLAG_BOOL, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_DL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_UL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST, \
GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
@@ -243,11 +241,10 @@ typedef enum {
#define GNB_DISABLE_HARQ_IDX 32
#define GNB_NUM_DL_HARQ_IDX 33
#define GNB_NUM_UL_HARQ_IDX 34
#define GNB_BEAMWEIGHTS_IDX 35
#define GNB_UESS_AGG_LEVEL_LIST_IDX 36
#define GNB_CU_SIBS_IDX 37
#define GNB_DU_SIBS_IDX 38
#define GNB_DO_SINR_IDX 39
#define GNB_UESS_AGG_LEVEL_LIST_IDX 35
#define GNB_CU_SIBS_IDX 36
#define GNB_DU_SIBS_IDX 37
#define GNB_DO_SINR_IDX 38
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
#define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32}
@@ -293,7 +290,6 @@ typedef enum {
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
+16 -20
View File
@@ -715,36 +715,32 @@ static void config_common(gNB_MAC_INST *nrmac,
if (cfg->cell_config.frame_duplex_type.value == TDD)
set_tdd_config_nr(cfg, fs);
int nb_tx = config->nb_bfw[0]; // number of tx antennas
int nb_beams = config->nb_bfw[1]; // number of beams
// precoding matrix configuration (to be improved)
cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts);
// beamforming matrix configuration
cfg->dbt_config.num_dig_beams = nb_beams;
if (nb_beams > 0) {
cfg->dbt_config.num_txrus = nb_tx;
cfg->dbt_config.dig_beam_list = malloc16(nb_beams * sizeof(*cfg->dbt_config.dig_beam_list));
AssertFatal(cfg->dbt_config.dig_beam_list, "out of memory\n");
for (int i = 0; i < nb_beams; i++) {
nfapi_nr_dig_beam_t *beam = &cfg->dbt_config.dig_beam_list[i];
beam->beam_idx = i;
beam->txru_list = malloc16(nb_tx * sizeof(*beam->txru_list));
for (int j = 0; j < nb_tx; j++) {
nfapi_nr_txru_t *txru = &beam->txru_list[j];
txru->dig_beam_weight_Re = config->bw_list[j + i * nb_tx] & 0xffff;
txru->dig_beam_weight_Im = (config->bw_list[j + i * nb_tx] >> 16) & 0xffff;
LOG_D(NR_MAC, "Beam %d Tx %d Weight (%d, %d)\n", i, j, txru->dig_beam_weight_Re, txru->dig_beam_weight_Im);
}
}
}
int nb_beams = config->nb_bfw[1]; // number of beams
if (nrmac->beam_info.beam_allocation) {
LOG_I(NR_MAC, "Configuring analog beamforming in config_request message\n");
cfg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag = NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG;
cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value = nrmac->beam_info.beams_per_period;
cfg->num_tlv++;
cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG;
cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled
cfg->num_tlv++;
cfg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG;
cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams;
cfg->num_tlv++;
cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list));
for (int i = 0; i < nb_beams; i++) {
cfg->analog_beamforming_ve.analog_beam_list[i].tl.tag = NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG;
cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i];
}
} else {
cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled
if (NFAPI_MODE == NFAPI_MONOLITHIC) {
cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG;
cfg->num_tlv++;
}
}
}
+38 -34
View File
@@ -356,10 +356,11 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
NR_COMMON_channels_t *cc = gNB->common_channels;
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_BWP_UplinkCommon_t *initialUplinkBWP = scc->uplinkConfigCommon->initialUplinkBWP;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
msgacc = initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
int slots_frame = gNB->frame_structure.numb_slots_frame;
int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size);
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index];
@@ -371,7 +372,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
int slot_index = 0;
uint16_t prach_occasion_id = -1;
int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
int bwp_start = NRRIV2PRBOFFSET(initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
@@ -399,6 +400,16 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
uint32_t N_t_slot = cc->prach_info.N_t_slot;
uint32_t start_symb = cc->prach_info.start_symbol;
for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]),
"Invalid UL_tti_req->n_pdus %d\n",
UL_tti_req->n_pdus);
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
memset(prach_pdu, 0, sizeof(nfapi_nr_prach_pdu_t));
UL_tti_req->n_pdus += 1;
int num_td_occ = 0;
for (int td_index = 0; td_index < N_t_slot; td_index++) {
uint32_t config_period = cc->prach_info.x;
prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
@@ -407,6 +418,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
if (prach_occasion_id >= cc->total_prach_occasions) // to be confirmed: unused occasion?
continue;
num_td_occ++;
float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];
int beam_index = 0;
if(num_ssb_per_RO <= 1) {
@@ -417,8 +429,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
// multi-beam allocation structure
beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_frame);
AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to %d SSB transmitted in any available beam\n", n_ssb + 1);
}
else {
} else {
int first_ssb_index = (prach_occasion_id * (int)num_ssb_per_RO) % cc->num_active_ssb;
for(int j = first_ssb_index; j < first_ssb_index + num_ssb_per_RO; j++) {
// fapi beam index
@@ -428,40 +439,15 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", j);
}
}
if(td_index == 0) {
AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]),
"Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus);
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t));
UL_tti_req->n_pdus+=1;
if(num_td_occ == 1) {
// filling the prach fapi structure
prach_pdu->phys_cell_id = *scc->physCellId;
prach_pdu->num_prach_ocas = N_t_slot;
gNB->num_scheduled_prach_rx += N_t_slot;
prach_pdu->prach_start_symbol = start_symb;
prach_pdu->num_ra = fdm_index;
prach_pdu->num_cs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig,
format0,
rach_ConfigCommon->restrictedSetConfig);
prach_pdu->beamforming.num_prgs = 0;
prach_pdu->beamforming.prg_size = 0;
prach_pdu->beamforming.dig_bf_interface = 1;
prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index;
LOG_D(NR_MAC,
"Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
frameP,
slotP,
prach_occasion_id,
prach_pdu->num_ra,
start_symb,
slot_index,
RA_sfn_index);
// SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
// We added 9 = A1/B1 10 = A2/B2 11 A3/B3
if (format1!=0xff) {
@@ -518,8 +504,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
AssertFatal(1==0,"Invalid PRACH format");
}
}
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1
&& scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) {
if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16) {
if (gNB->UE_info.connected_ue_list[0] == NULL)
schedule_nr_MsgA_pusch(scc->uplinkConfigCommon,
gNB,
@@ -531,7 +516,26 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
*scc->physCellId);
}
}
prach_pdu->num_prach_ocas = num_td_occ;
prach_pdu->beamforming.num_prgs = 0;
prach_pdu->beamforming.prg_size = 0;
prach_pdu->beamforming.dig_bf_interface = num_td_occ;
prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = beam_index;
LOG_D(NR_MAC,
"Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
frameP,
slotP,
prach_occasion_id,
prach_pdu->num_ra,
prach_pdu->prach_start_symbol,
slot_index,
RA_sfn_index);
}
if (num_td_occ == 0) // no TD PRACH occasion -> no PRACH PDU
UL_tti_req->n_pdus -= 1;
else
gNB->num_scheduled_prach_rx += num_td_occ;
}
// block resources in vrb_map_UL
+2
View File
@@ -225,6 +225,8 @@ typedef struct openair0_config {
int rx_num_channels;
//! number of TX channels (=TX antennas)
int tx_num_channels;
//! number of distributed radio-units
int num_distributed_ru;
//! rx daughter card
char* rx_subdev;
//! tx daughter card
+2 -2
View File
@@ -834,7 +834,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
{
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0);
DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0 && oai0->num_distributed_ru > 0);
DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0);
DevAssert(oai0->tx_freq[0] > 0);
for (int i = 1; i < oai0->tx_num_channels; ++i)
@@ -879,7 +879,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
fh_config->dpdk_port = ru_idx; // DPDK port number used for FH
fh_config->sector_id = 0; // Band sector ID for FH; not used in xran
fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info
fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH)
fh_config->neAxc = RTE_MAX(oai0->num_distributed_ru * oai0->tx_num_channels / num_rus, oai0->num_distributed_ru * oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH)
fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B
fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B
fh_config->nDLFftSize = 0; // DL FFT size; not used in xran
+2 -2
View File
@@ -208,7 +208,7 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
ru_info_t ru_info;
ru_info.nb_rx = ru->nb_rx;
ru_info.nb_rx = ru->nb_rx * ru->num_beams_period;
ru_info.rxdataF = ru->common.rxdataF;
ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id]
@@ -262,7 +262,7 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
{
start_meas(&ru->tx_fhaul);
ru_info_t ru_info;
ru_info.nb_tx = ru->nb_tx;
ru_info.nb_tx = ru->nb_tx * ru->num_beams_period;
ru_info.txdataF_BF = ru->common.txdataF_BF;
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);