Compare commits

...

5 Commits

Author SHA1 Message Date
Sakthivel Velumani
44532e7139 beamforming: enable mu-mimo in phytest 2025-09-19 04:09:05 +00:00
Sakthivel Velumani
399544f8fb beamforming: pass fapi beam id to oru
change default beam id from -1 to 0 to be consistent with ORAN.
update phytest scheduler to send PDSCH on differnt beams beased on SSB index
beam allocation.
2025-09-04 05:34:52 +00:00
Sakthivel Velumani
d3836862f5 oran: allow mulitple sections in a slot 2025-09-03 04:16:50 +00:00
Sakthivel Velumani
77c0263841 bugfix: allocation when PRB split at DC 2025-08-29 03:40:45 +00:00
Sakthivel Velumani
8f815255c5 oran: in tx function change loop order
first sections then symbols
2025-08-29 03:40:39 +00:00
33 changed files with 555 additions and 265 deletions

View File

@@ -173,7 +173,7 @@ index eccc4ae..a97fdc6 100644
CPP_FLAGS_FULL := $(CPP_FLAGS) $(CPP_COMP) $(INC) $(DEF)
CPP_FLAGS_FULL_SNC := $(CPP_FLAGS) $(CPP_COMP_SNC) $(INC) $(DEF)
diff --git a/fhi_lib/lib/api/xran_fh_o_du.h b/fhi_lib/lib/api/xran_fh_o_du.h
index bacf597..1dd6d66 100644
index bacf597..1cd8764 100644
--- a/fhi_lib/lib/api/xran_fh_o_du.h
+++ b/fhi_lib/lib/api/xran_fh_o_du.h
@@ -141,7 +141,7 @@ extern "C" {
@@ -193,6 +193,15 @@ index bacf597..1dd6d66 100644
int32_t bbdev_mode; /**< DPDK for BBDev */
uint32_t dpdkIoVaMode; /**< IOVA Mode */
uint32_t dpdkMemorySize; /**< DPDK max memory allocation */
@@ -555,7 +556,7 @@ struct xran_prb_map {
uint16_t tti_id; /**< xRAN slot id [0 - (max tti-1)] */
uint8_t start_sym_id; /**< start symbol Id [0-13] */
uint32_t nPrbElm; /**< total number of PRB elements for given map [0- (XRAN_MAX_SECTIONS_PER_SLOT-1)] */
- struct xran_prb_elm prbMap[1];
+ struct xran_prb_elm prbMap[XRAN_MIN_SECTIONS_PER_SLOT];
};
/* PRACH config required for XRAN based FH */
@@ -1193,6 +1194,31 @@ int32_t xran_reg_physide_cb_by_dev_id(void *pHandle, xran_fh_tti_callback_fn Cb,
*/
int32_t xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, uint32_t *nSlotIdx, uint64_t *nSecond);
@@ -688,7 +697,7 @@ index 4498b33..8a2984f 100644
/* convert byte order */
tmp = (uint64_t *)ext3_f;
diff --git a/fhi_lib/lib/src/xran_cp_proc.c b/fhi_lib/lib/src/xran_cp_proc.c
index 789c6fd..a768efb 100644
index 789c6fd..a3929e1 100644
--- a/fhi_lib/lib/src/xran_cp_proc.c
+++ b/fhi_lib/lib/src/xran_cp_proc.c
@@ -35,7 +35,10 @@
@@ -702,6 +711,19 @@ index 789c6fd..a768efb 100644
#include <rte_common.h>
#include <rte_eal.h>
@@ -304,6 +307,12 @@ xran_cp_create_and_send_section(void *pHandle, uint8_t ru_port_id, int dir, int
return (-1);
}
+ if(prbMap->nPrbElm == 0)
+ {
+ print_dbg("No section to process\n");
+ return (-1);
+ }
+
if(0== prbElmProcInfo->numSymsRemaining)
{ /* new slot */
prbElmProcInfo->numSymsRemaining = p_x_ctx->numSymsForDlCP;
diff --git a/fhi_lib/lib/src/xran_delay_measurement.c b/fhi_lib/lib/src/xran_delay_measurement.c
index 4c943c8..7db51a8 100644
--- a/fhi_lib/lib/src/xran_delay_measurement.c

View File

@@ -177,6 +177,15 @@ uint64_t reverse_bits(uint64_t in, int n_bits)
return rev_bits;
}
uint8_t get_first_set_bit_idx(const uint32_t a)
{
uint8_t i = 0;
while (!IS_BIT_SET(a, i) && (i < 32)) {
i++;
}
return i;
}
#define NUM_BW_ENTRIES 15
static const int tables_5_3_2[5][NUM_BW_ENTRIES] = {
@@ -731,14 +740,10 @@ int get_dmrs_port(int nl, uint16_t dmrs_ports)
if (dmrs_ports == 0)
return 0; // dci 1_0
int p = -1;
int found = -1;
for (int i = 0; i < 12; i++) { // loop over dmrs ports
if((dmrs_ports >> i) & 0x01) { // check if current bit is 1
found++;
if (found == nl) { // found antenna port number corresponding to current layer
p = i;
break;
}
p = i;
break;
}
}
AssertFatal(p > -1, "No dmrs port corresponding to layer %d found\n", nl);

View File

@@ -260,6 +260,7 @@ static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t
uint64_t reverse_bits(uint64_t in, int n_bits);
void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out);
uint8_t get_first_set_bit_idx(const uint32_t a);
uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t dl_nrarfcn);
uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw);

View File

@@ -33,7 +33,8 @@ extern "C" {
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#define IS_BIT_SET(a,b) ((a >> b) & 1)
#define SET_BIT(a,b) (a | (1 << b))
#ifdef __cplusplus

View File

@@ -58,6 +58,7 @@ extern "C"
#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n"
#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n"
#define CONFIG_HLP_MU_MIMO "Enable MU-MIMO in phy-test mode\n"
#define CONFIG_HLP_DORA "test gNB and UE with RA procedures\n"
#define CONFIG_HLP_SA "run gNB in standalone mode\n"
#define CONFIG_HLP_SL_MODE "sets the NR sidelink mode (0: not in sidelink mode, 1: in-coverage/gNB, 2: out-of-coverage/no gNB)\n"
@@ -123,6 +124,7 @@ extern "C"
#define TP_CONFIG softmodem_params.threadPoolConfig
#define CONTINUOUS_TX softmodem_params.continuous_tx
#define PHY_TEST softmodem_params.phy_test
#define MU_MIMO softmodem_params.mu_mimo
#define DO_RA softmodem_params.do_ra
#define SL_MODE softmodem_params.sl_mode
#define CHAIN_OFFSET softmodem_params.chain_offset
@@ -152,6 +154,7 @@ extern int usrp_tx_thread;
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, .strptr=&RF_CONFIG_FILE, .defstrval=NULL, TYPE_STRING, 0}, \
{"thread-pool", CONFIG_HLP_TPOOL, 0, .strptr=&TP_CONFIG, .defstrval="-1,-1,-1,-1,-1,-1,-1,-1", TYPE_STRING, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, .iptr=&PHY_TEST, .defintval=0, TYPE_INT, 0}, \
{"mu-mimo", CONFIG_HLP_MU_MIMO, PARAMFLAG_BOOL, .iptr=&MU_MIMO, .defintval=0, TYPE_INT, 0}, \
{"do-ra", CONFIG_HLP_DORA, PARAMFLAG_BOOL, .iptr=&DO_RA, .defintval=0, TYPE_INT, 0}, \
{"sl-mode", CONFIG_HLP_SL_MODE, 0, .u8ptr=&SL_MODE, .defintval=0, TYPE_UINT8, 0}, \
{"clock-source", CONFIG_HLP_CLK, 0, .uptr=&CLOCK_SOURCE, .defintval=0, TYPE_UINT, 0}, \
@@ -218,6 +221,7 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \
{NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \
@@ -318,6 +322,7 @@ typedef struct {
char *rf_config_file;
char *threadPoolConfig;
int phy_test;
int mu_mimo;
int do_ra;
uint8_t sl_mode;
int emulate_rf;

View File

@@ -80,14 +80,18 @@ static 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->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
frame_parms->symbols_per_slot,
bitmap);
rb_offset,
n_rb,
cset_start_symb,
cset_nsymb,
1,
0);
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,

View File

@@ -460,12 +460,14 @@ static inline void do_txdataF(c16_t **txdataF,
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
int ant,
int start_sc,
int txdataF_offset_per_symbol)
int txdataF_offset_per_symbol,
int nl)
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
int rb = 0;
uint16_t subCarrier = start_sc;
nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming;
const int dmrs_port = get_dmrs_port(ant, rel15->dmrsPorts);
while (rb < rel15->rbSize) {
// get pmi info
const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0;
@@ -477,29 +479,25 @@ static inline void do_txdataF(c16_t **txdataF,
const int re_cnt = NR_NB_SC_PER_RB * rb_step;
if (pmi == 0) { // unitary Precoding
if (subCarrier + re_cnt <= symbol_sz) { // RB does not cross DC
if (ant < rel15->nrOfLayers)
// For no precoding, use only as many number of antennas as layers
// and prevents overwriting txdataF with 0
if (ant == dmrs_port) {
if (subCarrier + re_cnt <= symbol_sz) { // RB does not cross DC
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][subCarrier],
&txdataF_precoding[nl][subCarrier],
re_cnt * sizeof(**txdataF));
else
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, re_cnt * sizeof(**txdataF));
} else { // RB does cross DC
const int neg_length = symbol_sz - subCarrier;
const int pos_length = re_cnt - neg_length;
if (ant < rel15->nrOfLayers) {
} else { // RB does cross DC
const int neg_length = symbol_sz - subCarrier;
const int pos_length = re_cnt - neg_length;
memcpy(&txdataF[ant][txdataF_offset_per_symbol + subCarrier],
&txdataF_precoding[ant][subCarrier],
&txdataF_precoding[nl][subCarrier],
neg_length * sizeof(**txdataF));
memcpy(&txdataF[ant][txdataF_offset_per_symbol], &txdataF_precoding[ant], pos_length * sizeof(**txdataF));
} else {
memset(&txdataF[ant][txdataF_offset_per_symbol + subCarrier], 0, neg_length * sizeof(**txdataF));
memset(&txdataF[ant][txdataF_offset_per_symbol], 0, pos_length * sizeof(**txdataF));
memcpy(&txdataF[ant][txdataF_offset_per_symbol], &txdataF_precoding[nl], pos_length * sizeof(**txdataF));
}
subCarrier += re_cnt;
if (subCarrier >= symbol_sz) {
subCarrier -= symbol_sz;
}
}
subCarrier += re_cnt;
if (subCarrier >= symbol_sz) {
subCarrier -= symbol_sz;
}
} else { // non-unitary Precoding
AssertFatal(frame_parms->nb_antennas_tx > 1, "No precoding can be done with a single antenna port\n");
@@ -679,14 +677,18 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
start_meas(&gNB->dlsch_precoding_stats);
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->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
frame_parms->symbols_per_slot,
bitmap);
rel15->rbStart,
rel15->rbSize,
rel15->StartSymbolIndex,
rel15->NrOfSymbols,
rel15->nrOfLayers,
get_first_set_bit_idx(rel15->dmrsPorts));
c16_t **txdataF = gNB->common_vars.txdataF[beam_nb];
@@ -760,7 +762,15 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz + txdataF_offset;
do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol);
do_txdataF(txdataF,
symbol_sz,
txdataF_precoding,
gNB,
rel15,
ant,
start_sc,
txdataF_offset_per_symbol,
ant % rel15->nrOfLayers);
}
}

View File

@@ -84,14 +84,19 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr
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);
// tmp: no dbf for prach
0,
273,
start_symb,
n_symb,
1,
0);
}
}
LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id);

View File

@@ -75,14 +75,18 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t
ulsch->beam_nb = 0;
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(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_pdu->rb_start,
ulsch_pdu->rb_size,
ulsch_pdu->start_symbol_index,
ulsch_pdu->nr_of_symbols,
ulsch_pdu->nrOfLayers,
get_first_set_bit_idx(ulsch_pdu->dmrs_ports));
}
ulsch->frame = frame;
ulsch->slot = slot;

View File

@@ -69,14 +69,18 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t
pucch->beam_nb = 0;
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->gNB_config.analog_beamforming_ve,
&gNB->common_vars,
slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
pucch_pdu->prb_start,
pucch_pdu->prb_size,
pucch_pdu->start_symbol_index,
pucch_pdu->nr_of_symbols,
1,
0);
}
memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t));
LOG_D(PHY,

View File

@@ -57,7 +57,6 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu
srs->active = true;
srs->beam_nb = 0;
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(gNB->enable_analog_das,
fapi_beam_idx,
@@ -65,7 +64,12 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu
&gNB->common_vars,
slot,
NR_NUMBER_OF_SYMBOLS_PER_SLOT,
bitmap);
srs_pdu->bwp_start,
srs_pdu->bwp_size,
srs_pdu->time_start_position,
1 << srs_pdu->num_symbols,
1,
0);
}
memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t));
break;

View File

@@ -91,6 +91,22 @@ typedef enum {
synch_to_mobipass_standalone // special case for mobipass in standalone mode
} node_timing_t;
struct oai_ofh_section_def {
uint16_t start_symbol;
uint16_t num_symbols;
uint16_t start_prb;
uint16_t num_prb;
uint16_t re_offset;
uint16_t beam_id;
uint16_t num_ports;
uint16_t start_port;
};
#define NR_MAX_OFH_SECTIONS 6
struct oai_ofh_section {
uint16_t num_sections;
struct oai_ofh_section_def sec[NR_MAX_OFH_SECTIONS];
};
typedef struct {
/// \brief Holds the transmit data in the frequency domain (1 frame).
@@ -133,9 +149,10 @@ typedef struct {
/// - first index: concurrent beam
/// - second index: beam_id [0.. symbols_per_frame[
int **beam_id;
/// \brief Holds tx data section details relevant for xran interface
struct oai_ofh_section tx_sections;
} RU_COMMON;
typedef struct {
/// \brief Received frequency-domain signal after extraction.
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx

View File

@@ -291,6 +291,7 @@ typedef struct {
bool analog_bf;
int32_t *debugBuff;
int32_t debugBuff_sample_offset;
struct oai_ofh_section tx_sections;
} NR_gNB_COMMON;
typedef struct {

View File

@@ -94,7 +94,7 @@ void nr_schedule_dl_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_dl_tti_request_t *DL_req
for (int i = 0; i < number_dl_pdu; i++) {
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu = &DL_req->dl_tti_request_body.dl_tti_pdu_list[i];
LOG_D(NR_PHY, "NFAPI: dl_pdu %d : type %d\n", i, dl_tti_pdu->PDUType);
LOG_D(NR_PHY, "frame %d, slot %d, NFAPI: dl_pdu %d : type %d\n", frame, slot, i, dl_tti_pdu->PDUType);
switch (dl_tti_pdu->PDUType) {
case NFAPI_NR_DL_TTI_SSB_PDU_TYPE:
handle_nr_nfapi_ssb_pdu(msgTx, frame, slot, dl_tti_pdu);

View File

@@ -196,6 +196,9 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx)
}
}
memcpy(&ru->common.tx_sections, &gNB->common_vars.tx_sections, sizeof(ru->common.tx_sections));
memset(&gNB->common_vars.tx_sections, 0, sizeof(gNB->common_vars.tx_sections));
// 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++) {

View File

@@ -53,38 +53,76 @@ int beam_index_allocation(bool das,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols)
int start_rb,
int num_rb,
int start_symb,
int num_symb,
int num_ports,
int start_port)
{
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++) {
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;
/* According to SCF nfapi spec, MSB of beam-Id indicates if beamforming is
applied at L1 or if it should be passed down to RU */
const bool is_lophy_bf = IS_BIT_SET(fapi_beam_index, 15);
if (!is_lophy_bf) {
/* Only analog BF for now because of L2 implementation. This could also be digital BF
in which case L1 has to apply the pre-defined beam weights before OFDM modulation or
sending freq domain data to RU. */
AssertFatal(common_vars->beam_id, "L1 should do beamforming but no weights preconfigured: slot %d, beam id %d\n", slot, 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++) {
int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i];
if (current_beam <= 0 || current_beam == ru_beam_idx)
idx = j;
else {
idx = -1;
break;
}
}
if (idx != -1)
break;
}
if (idx != -1)
break;
}
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))
AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", ru_beam_idx);
for (int j = start_symb; j < start_symb + num_symb; j++) {
common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx;
}
LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot);
} else {
// Digital or analog BF we don't care because L1 has to pass the beam index down to O-RU
int ru_beam_idx = (fapi_beam_index & 0x7fff);
update_ofh_section_info(&common_vars->tx_sections, ru_beam_idx, start_rb, num_rb, start_symb, num_symb, start_port, num_ports);
// in this case the beam number is not relevant for L1 as mulitple beams are handled in multiple sections
idx = 0;
}
LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot);
return idx;
}
void update_ofh_section_info(struct oai_ofh_section *tx_s,
int beam_id,
int start_rb,
int num_rb,
int start_symb,
int num_symb,
int start_port,
int num_ports)
{
struct oai_ofh_section_def *sec = tx_s->sec + tx_s->num_sections;
sec->beam_id = beam_id;
sec->start_prb = start_rb;
sec->num_prb = num_rb;
sec->start_symbol = start_symb;
sec->num_symbols = num_symb;
sec->start_port = start_port;
sec->num_ports = num_ports;
tx_s->num_sections++;
}
void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_dl_tti_ssb_pdu ssb_pdu)
{
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
@@ -140,14 +178,18 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n
c16_t ***txdataF = gNB->common_vars.txdataF;
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(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,
bitmap);
fp->ssb_start_subcarrier / NR_NB_SC_PER_RB,
20 + (fp->ssb_start_subcarrier % NR_NB_SC_PER_RB != 0),
ssb_start_symbol,
4,
1,
0);
nr_generate_pss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
nr_generate_sss(&txdataF[beam_nb][0][txdataF_offset], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
@@ -173,14 +215,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n
}
#endif
nr_generate_pbch(gNB,
&ssb_pdu,
&txdataF[beam_nb][0][txdataF_offset],
ssb_start_symbol,
n_hf,
frame,
cfg,
fp);
nr_generate_pbch(gNB, &ssb_pdu, &txdataF[beam_nb][0][txdataF_offset], ssb_start_symbol, n_hf, frame, cfg, fp);
}
// clearing beam information to be provided to RU for all slots (DL and UL)
@@ -280,17 +315,22 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx,
csi_params->symb_l0,
csi_params->symb_l1);
nfapi_nr_tx_precoding_and_beamforming_t *pb = &csi_params->precodingAndBeamforming;
int 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,
&cfg->analog_beamforming_ve,
&gNB->common_vars,
slot,
fp->symbols_per_slot,
csi_bitmap);
int beam_nb = 0;
for (int j = 0; j < mapping_parms.size; j++) {
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,
csi_params->start_rb,
csi_params->nr_of_rbs,
mapping_parms.loverline[j],
lprime_num,
1,
0);
}
nr_generate_csi_rs(&gNB->frame_parms,
&mapping_parms,

View File

@@ -53,5 +53,18 @@ int beam_index_allocation(bool das,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols);
int start_rb,
int num_rb,
int start_symb,
int num_symb,
int num_ports,
int start_port);
void update_ofh_section_info(struct oai_ofh_section *tx_s,
int beam_id,
int start_rb,
int num_rb,
int start_symb,
int num_symb,
int start_port,
int num_port);
#endif

View File

@@ -5144,3 +5144,27 @@ int get_j_for_k2(int mu)
AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu);
return j_table[mu];
}
// TODO: Only supports dmrs-Type 1 and one codeword
uint16_t get_dmrs_ports_from_dci(const uint8_t table_idx)
{
DevAssert(table_idx < 11);
// TODO: This table already in mac_tables.c need to move it here
const uint8_t table_7_3_2_3_3_1[12][5] = {
{1,1,0,0,0},
{1,0,1,0,0},
{1,1,1,0,0},
{2,1,0,0,0},
{2,0,1,0,0},
{2,0,0,1,0},
{2,0,0,0,1},
{2,1,1,0,0},
{2,0,0,1,1},
{2,1,1,1,0},
{2,1,1,1,1},
{2,1,0,1,0}
};
const uint8_t *t = table_7_3_2_3_3_1[table_idx];
return (t[1] | t[2] << 1 | t[3] << 2 | t[4] << 3);
}

View File

@@ -303,4 +303,6 @@ int get_delta_for_k2(int mu);
int get_j_for_k2(int mu);
uint16_t get_dmrs_ports_from_dci(const uint8_t table_idx);
#endif

View File

@@ -784,7 +784,7 @@ static void initialize_beam_information(NR_beam_info_t *beam_info, int mu, int s
for (int i = 0; i < beam_info->beams_per_period; i++) {
beam_info->beam_allocation[i] = malloc16(beam_info->beam_allocation_size * sizeof(int));
for (int j = 0; j < beam_info->beam_allocation_size; j++)
beam_info->beam_allocation[i][j] = -1;
beam_info->beam_allocation[i][j] = 0;
}
}

View File

@@ -118,7 +118,7 @@ static void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slo
// resetting previous period allocation
LOG_D(NR_MAC, "%d.%d Clear beam information for index %d\n", frame, slot, idx_to_clear);
for (int i = 0; i < beam_info->beams_per_period; i++)
beam_info->beam_allocation[i][idx_to_clear] = -1;
beam_info->beam_allocation[i][idx_to_clear] = 0;
}
}

View File

@@ -180,6 +180,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi
int beam_index = get_fapi_beamforming_index(gNB, i_ssb);
NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame);
AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb);
beam_index = get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx);
const int prb_offset = offset_pointa >> scs;
schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu);
fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx);
@@ -212,6 +213,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi
int beam_index = get_fapi_beamforming_index(gNB, i_ssb);
NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame);
AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb);
beam_index = get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx);
const int prb_offset = offset_pointa >> scs;
schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu);
fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx);
@@ -244,6 +246,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi
int beam_index = get_fapi_beamforming_index(gNB, i_ssb);
NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame);
AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb);
beam_index = get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx);
const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz
schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu);
fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset >> (scs - 2), ssb_start_symbol, CC_id, beam.idx);

View File

@@ -966,7 +966,7 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu
pdsch_pdu->SCID = dmrs_parms->n_scid;
pdsch_pdu->dlDmrsScramblingId = dmrs_parms->scrambling_id;
pdsch_pdu->numDmrsCdmGrpsNoData = dmrs_parms->numDmrsCdmGrpsNoData;
pdsch_pdu->dmrsPorts = (1 << sched_pdsch->nrOfLayers) - 1; // FIXME with a better implementation
pdsch_pdu->dmrsPorts = get_dmrs_ports_from_dci(dmrs_parms->dmrs_ports_id);
// Pdsch Allocation in frequency domain
pdsch_pdu->resourceAlloc = 1;
pdsch_pdu->rbStart = sched_pdsch->rbStart;

View File

@@ -54,6 +54,20 @@ uint32_t target_dl_Nl = 1;
uint32_t target_dl_bw = 50;
uint64_t dlsch_slot_bitmap = (1<<1);
static uint8_t get_next_mu_mimo_beam(const int layer, const int num_ssb, const BIT_STRING_t *ssbBitmap)
{
int sum = 0;
for (int i = 0; i < num_ssb; i++) {
if (IS_BIT_SET(ssbBitmap->buf[0], (7 - i))) {
if (layer == sum)
return i;
sum++;
}
}
return 0;
}
/* schedules whole bandwidth for first user, all the time */
void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
{
@@ -62,146 +76,187 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
int slot_period = slot % mac->frame_structure.numb_slots_period;
if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period))
return;
NR_UE_info_t *UE = mac->UE_info.connected_ue_list[0];
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
const int CC_id = 0;
/* return if all DL HARQ processes wait for feedback */
if (sched_ctrl->retrans_dl_harq.head == -1 && sched_ctrl->available_dl_harq.head == -1) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UE has no free DL HARQ process, skipping\n", UE->rnti, frame, slot);
return;
}
bool is_mu_mimo = get_softmodem_params()->mu_mimo;
AssertFatal((is_mu_mimo && (target_dl_Nl > 1)) || (!is_mu_mimo), "No of layers has to be more than 1 for MU-MIMO\n");
uint8_t num_layers_per_ue = (is_mu_mimo) ? 1 : target_dl_Nl; // Limit MU-MIMO layer to 1 per UE
// Tmp hack to scheduler MU-MIMO
uint8_t layer_indicator = 0;
const int tda = get_dl_tda(mac, slot);
NR_tda_info_t tda_info = get_dl_tda_info(dl_bwp,
sched_ctrl->search_space->searchSpaceType->present,
tda,
scc->dmrs_TypeA_Position,
1,
TYPE_C_RNTI_,
sched_ctrl->coreset->controlResourceSetId,
false);
if(!tda_info.valid_tda)
return;
UE_iterator (mac->UE_info.connected_ue_list, UE) {
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
const int CC_id = 0;
sched_ctrl->sched_pdsch.tda_info = tda_info;
sched_ctrl->sched_pdsch.time_domain_allocation = tda;
/* find largest unallocated chunk */
const int bwpSize = dl_bwp->BWPSize;
const int BWPStart = dl_bwp->BWPStart;
// TODO implement beam procedures for phy-test mode
int beam = 0;
int rbStart = 0;
int rbSize = 0;
if (target_dl_bw>bwpSize)
target_dl_bw = bwpSize;
uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam];
/* loop ensures that we allocate exactly target_dl_bw, or return */
while (true) {
/* advance to first free RB */
while (rbStart < bwpSize &&
(vrb_map[rbStart + BWPStart]&SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)))
rbStart++;
rbSize = 1;
/* iterate until we are at target_dl_bw or no available RBs */
while (rbStart + rbSize < bwpSize &&
!(vrb_map[rbStart + rbSize + BWPStart]&SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) &&
rbSize < target_dl_bw)
rbSize++;
/* found target_dl_bw? */
if (rbSize == target_dl_bw)
break;
/* at end and below target_dl_bw? */
if (rbStart + rbSize >= bwpSize)
return;
rbStart += rbSize;
}
sched_ctrl->num_total_bytes = 0;
DevAssert(seq_arr_size(&sched_ctrl->lc_config) == 1);
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, 0);
const int lcid = c->lcid;
const uint16_t rnti = UE->rnti;
/* update sched_ctrl->num_total_bytes so that postprocessor schedules data,
* if available */
sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid);
sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
int CCEIndex = get_cce_index(mac,
CC_id, slot, UE->rnti,
&sched_ctrl->aggregation_level,
beam,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false,
0);
AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti);
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
if (sched_pdsch->dl_harq_pid == -1)
sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head;
int alloc = -1;
if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) {
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex);
alloc = nr_acknack_scheduling(mac, UE, frame, slot, 0, r_pucch, 0);
if (alloc < 0) {
LOG_D(NR_MAC, "Could not find PUCCH for UE %04x@%d.%d\n", rnti, frame, slot);
/* return if all DL HARQ processes wait for feedback */
if (sched_ctrl->retrans_dl_harq.head == -1 && sched_ctrl->available_dl_harq.head == -1) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UE has no free DL HARQ process, skipping\n", UE->rnti, frame, slot);
return;
}
const int tda = get_dl_tda(mac, slot);
NR_tda_info_t tda_info = get_dl_tda_info(dl_bwp,
sched_ctrl->search_space->searchSpaceType->present,
tda,
scc->dmrs_TypeA_Position,
1,
TYPE_C_RNTI_,
sched_ctrl->coreset->controlResourceSetId,
false);
if (!tda_info.valid_tda)
return;
sched_ctrl->sched_pdsch.tda_info = tda_info;
sched_ctrl->sched_pdsch.time_domain_allocation = tda;
/* find largest unallocated chunk */
const int bwpSize = dl_bwp->BWPSize;
const int BWPStart = dl_bwp->BWPStart;
// TODO implement beam procedures for phy-test mode
int num_ssb = 0;
const BIT_STRING_t *ssbBitmap = NULL;
switch (scc->ssb_PositionsInBurst->present) {
case 1:
num_ssb = 4;
ssbBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap;
break;
case 2:
num_ssb = 8;
ssbBitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap;
break;
default:
AssertFatal(0, "SSB burst len in burst not supported\n");
}
int ssb_idx_beam = 0;
for (int i_ssb = 0; i_ssb < num_ssb; i_ssb++) {
if (IS_BIT_SET(ssbBitmap->buf[0], (7 - i_ssb))) {
NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing;
const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb);
// select beam for PDSCH in current slot based on SSB beam
if ((ssb_start_symbol / 14) == (slot % mac->frame_structure.numb_slots_period)) {
ssb_idx_beam = i_ssb;
break;
}
}
}
// If MU-MIMO, set first UE's beam to be the first beam idx available
const int start_beam_idx = (is_mu_mimo) ? get_next_mu_mimo_beam(layer_indicator, num_ssb, ssbBitmap) : ssb_idx_beam;
int beam_idx = get_fapi_beamforming_index(mac, start_beam_idx);
NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, frame, slot, beam_idx, mac->frame_structure.numb_slots_frame);
AssertFatal(beam.idx > -1, "Can't allocate beam %d in phytest scheduler\n", beam_idx);
UE->UE_beam_index = get_allocated_beam(&mac->beam_info, frame, slot, mac->frame_structure.numb_slots_frame, beam.idx);
int rbStart = 0;
int rbSize = 0;
if (target_dl_bw > bwpSize)
target_dl_bw = bwpSize;
uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam.idx];
/* loop ensures that we allocate exactly target_dl_bw, or return */
while (true) {
/* advance to first free RB */
while (rbStart < bwpSize && (vrb_map[rbStart + BWPStart] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)))
rbStart++;
rbSize = 1;
/* iterate until we are at target_dl_bw or no available RBs */
while (rbStart + rbSize < bwpSize
&& !(vrb_map[rbStart + rbSize + BWPStart] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols))
&& rbSize < target_dl_bw)
rbSize++;
/* found target_dl_bw? */
if (rbSize == target_dl_bw)
break;
/* at end and below target_dl_bw? */
if (rbStart + rbSize >= bwpSize)
return;
rbStart += rbSize;
}
sched_ctrl->num_total_bytes = 0;
DevAssert(seq_arr_size(&sched_ctrl->lc_config) == 1);
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, 0);
const int lcid = c->lcid;
const uint16_t rnti = UE->rnti;
/* update sched_ctrl->num_total_bytes so that postprocessor schedules data,
* if available */
sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid);
sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
int CCEIndex = get_cce_index(mac,
CC_id,
slot,
UE->rnti,
&sched_ctrl->aggregation_level,
beam.idx,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false,
0);
AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti);
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
if (sched_pdsch->dl_harq_pid == -1)
sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head;
int alloc = -1;
if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) {
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex);
alloc = nr_acknack_scheduling(mac, UE, frame, slot, 0, r_pucch, 0);
if (alloc < 0) {
LOG_D(NR_MAC, "Could not find PUCCH for UE %04x@%d.%d\n", rnti, frame, slot);
return;
}
}
sched_ctrl->cce_index = CCEIndex;
fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx);
// AssertFatal(alloc,
// "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n",
// rnti, frame, slot);
sched_pdsch->pucch_allocation = alloc;
sched_pdsch->rbStart = rbStart;
sched_pdsch->rbSize = rbSize;
sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, UE);
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, num_layers_per_ue);
// Assign the right antenna port
if (is_mu_mimo) {
DevAssert((sched_pdsch->dmrs_parms.dmrs_ports_id == 0) || (sched_pdsch->dmrs_parms.dmrs_ports_id == 3));
sched_pdsch->dmrs_parms.dmrs_ports_id += layer_indicator++;
}
sched_pdsch->mcs = target_dl_mcs;
sched_pdsch->nrOfLayers = num_layers_per_ue;
sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
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,
sched_pdsch->rbSize,
tda_info.nrOfSymbols,
sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
sched_pdsch->nrOfLayers)
>> 3;
/* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */
sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head;
/* mark the corresponding RBs as used */
for (int rb = 0; rb < sched_pdsch->rbSize; rb++)
vrb_map[rb + sched_pdsch->rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
if ((frame & 127) == 0)
LOG_D(MAC, "phytest: %d.%d DL mcs %d, DL rbStart %d, DL rbSize %d\n", frame, slot, sched_pdsch->mcs, rbStart, rbSize);
}
sched_ctrl->cce_index = CCEIndex;
fill_pdcch_vrb_map(mac,
CC_id,
&sched_ctrl->sched_pdcch,
CCEIndex,
sched_ctrl->aggregation_level,
beam);
//AssertFatal(alloc,
// "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n",
// rnti, frame, slot);
sched_pdsch->pucch_allocation = alloc;
sched_pdsch->rbStart = rbStart;
sched_pdsch->rbSize = rbSize;
sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, UE);
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc,
dl_bwp,
&tda_info,
target_dl_Nl);
sched_pdsch->mcs = target_dl_mcs;
sched_pdsch->nrOfLayers = target_dl_Nl;
sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
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,
sched_pdsch->rbSize,
tda_info.nrOfSymbols,
sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
sched_pdsch->nrOfLayers)
>> 3;
/* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */
sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head;
/* mark the corresponding RBs as used */
for (int rb = 0; rb < sched_pdsch->rbSize; rb++)
vrb_map[rb + sched_pdsch->rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
if ((frame&127) == 0) LOG_D(MAC,"phytest: %d.%d DL mcs %d, DL rbStart %d, DL rbSize %d\n", frame, slot, sched_pdsch->mcs, rbStart,rbSize);
}
uint32_t target_ul_mcs = 9;
@@ -218,8 +273,6 @@ void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_p
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
NR_UE_info_t *UE = nr_mac->UE_info.connected_ue_list[0];
AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL,
"cannot handle more than one UE\n");
if (UE == NULL)
return;

View File

@@ -3380,7 +3380,7 @@ void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_
mac->fapi_beam_index[i] = fapi_index;
index++;
} else
mac->fapi_beam_index[i] = -1;
mac->fapi_beam_index[i] = 0;
}
}
@@ -3399,7 +3399,7 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame,
for (int i = 0; i < beam_info->beams_per_period; i++) {
NR_beam_alloc_t beam_struct = {.new_beam = false, .idx = i};
int *beam = &beam_info->beam_allocation[i][index];
if (*beam == -1) {
if (*beam == 0) { // beamId 0 is no BF as per O-RAN spec
beam_struct.new_beam = true;
*beam = beam_index;
}
@@ -3412,6 +3412,13 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame,
return (NR_beam_alloc_t) {.new_beam = false, .idx = -1};
}
int get_allocated_beam(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame, int beam_number_in_period)
{
const int index = get_beam_index(beam_info, frame, slot, slots_per_frame);
uint16_t beam_idx = beam_info->beam_allocation[beam_number_in_period][index];
return (beam_info->beam_mode == LOPHY_BEAM_IDX) ? SET_BIT(beam_idx, 15) : beam_idx;
}
void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam)
{
if(!new_beam) // need to reset only if the beam was allocated specifically for this instance

View File

@@ -456,6 +456,7 @@ int ul_buffer_index(int frame, int slot, int slots_per_frame, int size);
void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP);
void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac);
int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx);
int get_allocated_beam(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame, int beam_number_in_period);
NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame);
void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam);
void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE);

View File

@@ -551,8 +551,11 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C
int CC_id = 0;
rnti_t rnti;
if (get_softmodem_params()->phy_test) {
AssertFatal(mac->UE_info.connected_ue_list[0] == NULL, "phytest: UE already present\n");
rnti = 0x1234;
NR_UE_info_t *prev_UE = NULL;
UE_iterator (mac->UE_info.connected_ue_list, UE) {
prev_UE = UE;
}
rnti = (prev_UE) ? prev_UE->rnti + 1 : 0x1234;
} else {
bool found = nr_mac_get_new_rnti(&mac->UE_info, &rnti);
if (!found)

View File

@@ -756,7 +756,7 @@ typedef struct {
NR_UE_NR_Capability_t *capability;
measgap_config_t measgap_config;
// UE selected beam index
uint8_t UE_beam_index;
uint16_t UE_beam_index;
float ul_thr_ue;
float dl_thr_ue;
long pdsch_HARQ_ACK_Codebook;

View File

@@ -440,8 +440,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
free_f1ap_setup_response(&resp);
/* we need to setup one default UE for phy-test and do-ra modes in the MAC */
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0)
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) {
rrc_add_nsa_user(rrc, NULL, assoc_id);
// Schedule one more UE if MU-MIMO flag activated
if (get_softmodem_params()->mu_mimo > 0)
rrc_add_nsa_user(rrc, NULL, assoc_id);
}
}
static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)

View File

@@ -467,6 +467,25 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
return (0);
}
#define MAX_NR_PRBS 273
/* numPrbc can range only till 255. If more than 255 PRBs used, the section
is split into two */
static void fragment_sections_if_needed(struct oai_ofh_section *s)
{
const uint8_t max_numPrbc = UINT8_MAX;
for (int_fast16_t i = 0; i < s->num_sections; i++) {
if (s->sec[i].num_prb == MAX_NR_PRBS)
continue;
else if (s->sec[i].num_prb > max_numPrbc) {
s->sec[s->num_sections] = s->sec[i];
s->sec[s->num_sections].num_prb -= max_numPrbc;
s->sec[s->num_sections].start_prb = max_numPrbc;
s->sec[i].num_prb = max_numPrbc;
s->num_sections++;
}
}
}
/** @details Write PDSCH IQ-data from OAI txdataF_BF buffer to xran buffers. If
* I/Q compression (bitwidth < 16 bits) is configured, compresses the data
* before writing. */
@@ -484,34 +503,58 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
int nPRBs = fh_cfg->nDLRBs;
int fftsize = 1 << fh_cfg->ru_conf.fftSize;
int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports;
uint8_t *last_data_pointer[ru->nb_tx][XRAN_NUM_OF_SYMBOL_PER_SLOT];
memset(last_data_pointer, 0, sizeof(last_data_pointer));
fragment_sections_if_needed(&ru->tx_sections);
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) {
oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_tx_per_ru);
// This loop would better be more inner to avoid confusion and maybe also errors.
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
uint8_t *pData =
bufs->src[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT].pData;
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;
ptr = pData;
pos = &ru->txdataF_BF[ant_id][sym_idx * fftsize];
uint8_t *pPrbMapData = bufs->srccp[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
struct xran_prb_map *pRbMap = (struct xran_prb_map *)pPrbMapData;
struct xran_prb_map *txd = (struct xran_prb_map *)bufs->bufs.tx_prbmap[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pData;
const int num_elm = ru->tx_sections.num_sections;
int num_port_elm = 0;
for (int_fast32_t idxElm = 0; idxElm < num_elm; idxElm++) {
struct oai_ofh_section_def *l1_s = ru->tx_sections.sec + idxElm;
// Tmp hack for mu-mimo
if (l1_s->start_port != ant_id) {
continue;
}
struct xran_prb_elm *p_prbMapElm = &pRbMap->prbMap[num_port_elm];
p_prbMapElm->nRBStart = l1_s->start_prb;
p_prbMapElm->nRBSize = l1_s->num_prb;
p_prbMapElm->nStartSymb = l1_s->start_symbol;
p_prbMapElm->numSymb = l1_s->num_symbols;
p_prbMapElm->nBeamIndex = l1_s->beam_id;
p_prbMapElm->compMethod = fh_cfg->ru_conf.compMeth;
p_prbMapElm->iqWidth = fh_cfg->ru_conf.iqWidth;
LOG_D(PHY,
"%d.%d sec id:%ld, start rb:%d, num rb:%d, start sym:%d, num sym:%d\n",
frame,
slot,
idxElm,
p_prbMapElm->nRBStart,
p_prbMapElm->nRBSize,
p_prbMapElm->nStartSymb,
p_prbMapElm->numSymb);
for (int32_t sym_idx = p_prbMapElm->nStartSymb; sym_idx < p_prbMapElm->nStartSymb + p_prbMapElm->numSymb; sym_idx++) {
uint8_t *pData =
bufs->src[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT].pData;
ptr = pData;
pos = &ru->txdataF_BF[ant_id][sym_idx * fftsize];
uint8_t *u8dptr;
struct xran_prb_map *pRbMap = pPrbMap;
int32_t sym_id = sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT;
if (ptr && pos) {
uint32_t idxElm = 0;
u8dptr = (uint8_t *)ptr;
int16_t payload_len = 0;
uint8_t *u8dptr;
int32_t sym_id = sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT;
if (ptr && pos) {
u8dptr = (uint8_t *)ptr;
int16_t payload_len = 0;
uint8_t *dst = (uint8_t *)u8dptr;
uint8_t *dst = (uint8_t *)u8dptr;
dst = last_data_pointer[ant_id][sym_idx] != NULL ? last_data_pointer[ant_id][sym_idx] : dst;
struct xran_prb_elm *p_prbMapElm = &pRbMap->prbMap[idxElm];
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
struct xran_section_desc *p_sec_desc = NULL;
p_prbMapElm = &pRbMap->prbMap[idxElm];
// assumes one fragment per symbol
#ifdef E_RELEASE
p_sec_desc = p_prbMapElm->p_sec_desc[sym_id][0];
@@ -530,7 +573,7 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
int pos_len = 0;
int neg_len = 0;
if (p_prbMapElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
if (p_prbMapElm->nRBStart <= (nPRBs >> 1)) // there are PRBs left of DC
neg_len = min((nPRBs * 6) - (p_prbMapElm->nRBStart * 12), p_prbMapElm->nRBSize * N_SC_PER_PRB);
pos_len = (p_prbMapElm->nRBSize * N_SC_PER_PRB) - neg_len;
// Calculation of the pointer for the section in the buffer.
@@ -581,16 +624,20 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
dst += payload_len;
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
last_data_pointer[ant_id][sym_idx] = dst;
// The tti should be updated as it increased.
pRbMap->tti_id = tti;
} else {
printf("ptr ==NULL\n");
exit(-1); // fails here??
}
// The tti should be updated as it increased.
pRbMap->tti_id = tti;
} else {
printf("ptr ==NULL\n");
exit(-1); // fails here??
}
num_port_elm++;
}
pRbMap->nPrbElm = num_port_elm;
xran_init_PrbMap_from_cfg(pRbMap, txd, fh_init->mtu);
}
}
return (0);

View File

@@ -94,16 +94,19 @@ static struct xran_prb_map get_xran_prb_map(const struct xran_fh_config *f, cons
.cc_id = 0,
.ru_port_id = 0,
.tti_id = 0,
.nPrbElm = 1,
.nPrbElm = XRAN_MIN_SECTIONS_PER_SLOT,
};
struct xran_prb_elm *e = &prbmap.prbMap[0];
e->nStartSymb = start_sym;
e->numSymb = num_sym;
e->nRBStart = 0;
e->nRBSize = (dir == XRAN_DIR_DL) ? f->nDLRBs : f->nULRBs;
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
for (int i = 0; i < prbmap.nPrbElm; i++) {
struct xran_prb_elm *e = &prbmap.prbMap[0];
e->nStartSymb = start_sym;
e->numSymb = num_sym;
e->nRBStart = 0;
e->nRBSize = 0;
e->nBeamIndex = 0;
e->compMethod = f->ru_conf.compMeth;
e->iqWidth = f->ru_conf.iqWidth;
}
return prbmap;
}

View File

@@ -269,6 +269,7 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
ru_info_t ru_info;
ru_info.nb_tx = ru->nb_tx * ru->num_beams_period;
ru_info.txdataF_BF = ru->common.txdataF_BF;
memcpy(&ru_info.tx_sections, &ru->common.tx_sections, sizeof(ru_info.tx_sections));
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);
int ret = xran_fh_tx_send_slot(&ru_info, frame, slot, timestamp);

View File

@@ -29,6 +29,8 @@
#include "xran_fh_o_du.h"
#include "openair1/PHY/defs_RU.h"
/*
* Structure added to bear the information needed from OAI RU
*/
@@ -43,6 +45,7 @@ typedef struct ru_info_s {
// Needed for Prach
int16_t **prach_buf;
struct oai_ofh_section tx_sections;
} ru_info_t;
/** @brief Reads RX data (PRACH/PUSCH) of next slot.