Commit d4984dc7 authored by Florian Kaltenberger's avatar Florian Kaltenberger

Merge remote-tracking branch 'origin/NR_MAC_SSB_RO_UE_IDCC' into NR_MAC_SSB_RO_GlobalEdge

parents f07ef482 b0b5825c
......@@ -101,11 +101,11 @@ static inline uint64_t BIT_STRING_to_uint64(BIT_STRING_t *asn) {
shift = ((asn->size - 1) * 8) - asn->bits_unused;
for (index = 0; index < (asn->size - 1); index++) {
result |= asn->buf[index] << shift;
result |= ((uint64_t)asn->buf[index]) << shift;
shift -= 8;
}
result |= asn->buf[index] >> asn->bits_unused;
result |= ((uint64_t)asn->buf[index]) >> asn->bits_unused;
return result;
}
......
......@@ -693,6 +693,7 @@ int main( int argc, char **argv ) {
}
init_symbol_rotation(frame_parms[CC_id],frame_parms[CC_id]->dl_CarrierFreq);
init_nr_ue_vars(UE[CC_id],frame_parms[CC_id],0,abstraction_flag);
UE[CC_id]->mac_enabled = 1;
......@@ -751,7 +752,7 @@ int main( int argc, char **argv ) {
UE[CC_id]->N_TA_offset = (int)(N_TA_offset * factor);
LOG_I(PHY,"UE %d Setting N_TA_offset to %d samples (factor %f, UL Freq %lu, N_RB %d)\n", UE[CC_id]->Mod_id, UE[CC_id]->N_TA_offset, factor, UE[CC_id]->frame_parms.ul_CarrierFreq, N_RB);
}
}
}
// printf("tx_max_power = %d -> amp %d\n",tx_max_power[0],get_tx_amp(tx_max_poHwer,tx_max_power));
init_openair0();
......
......@@ -170,6 +170,7 @@ typedef struct {
uint8_t prach_format;
/// Num RA
uint8_t num_ra;
uint8_t prach_slot;
uint8_t prach_start_symbol;
/// 38.211 (NCS 38.211 6.3.3.1).
uint16_t num_cs;
......@@ -179,6 +180,8 @@ typedef struct {
uint8_t restricted_set;
/// see TS 38.211 (6.3.3.2).
uint16_t freq_msg1;
// When multiple SSBs per RO is configured, this indicates which one is selected in this RO -> this is used to properly compute the PRACH preamble
uint8_t ssb_nb_in_ro;
// nfapi_nr_ul_beamforming_t beamforming;
} fapi_nr_ul_config_prach_pdu;
......
......@@ -385,7 +385,7 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
fp->Lmax = 64;
}
fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[1].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[1].ssb_mask;
fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[0].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[1].ssb_mask;
fp->N_ssb = 0;
for (int p=0; p<fp->Lmax; p++)
......
......@@ -483,9 +483,15 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
dft(dftsize,(int16_t *)&tmp_dft_in,
(int16_t *)&rxdataF[symbol * frame_parms->ofdm_symbol_size], 1);
}
else
dft(dftsize,(int16_t *)&rxdata[rxdata_offset-sample_offset],
else{
//dft(dftsize,(int16_t *)&rxdata[rxdata_offset-sample_offset],
// (int16_t *)&rxdataF[symbol * frame_parms->ofdm_symbol_size], 1);
memcpy((void *)tmp_dft_in,
(void *) &rxdata[rxdata_offset-sample_offset],
(frame_parms->ofdm_symbol_size)*sizeof(int));
dft(dftsize,(int16_t *)&tmp_dft_in,
(int16_t *)&rxdataF[symbol * frame_parms->ofdm_symbol_size], 1);
}
// clear DC carrier from OFDM symbols
rxdataF[symbol * frame_parms->ofdm_symbol_size] = 0;
......
......@@ -4376,7 +4376,7 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
ue->ulsch_Msg3_active[i] = 0;
}
}
nr_prach = nr_ue_get_rach(ue->prach_resources[gNB_id], mod_id, ue->CC_id, UE_mode, frame_tx, gNB_id, nr_tti_tx);
nr_prach = nr_ue_get_rach(ue->prach_resources[gNB_id], ue->prach_vars[0], mod_id, ue->CC_id, UE_mode, frame_tx, gNB_id, nr_tti_tx);
}
}
......
......@@ -223,20 +223,12 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused = 4;
scc->ssb_PositionsInBurst->choice.shortBitmap.buf = CALLOC(1,1);
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = 0;
for (int i=0; i<8; i++) {
if (i<scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused)
curr_bit = 0;
else
curr_bit = (ssbmap>>(7-i))&0x01;
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<<i;
}
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = ssbmap & 0xF0;
}else if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap){
scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1);
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0;
for (int i=0; i<8; i++)
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] |= (((ssbmap>>(7-i))&0x01)<<i);
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = ssbmap;
}else {
scc->ssb_PositionsInBurst->choice.longBitmap.size = 8;
scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0;
......@@ -244,8 +236,7 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
for (int j=0; j<8; j++) {
scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] = 0;
curr_bit = (ssbmap>>(j<<3))&(0xff);
for (int i=0; i<8; i++)
scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] |= (((curr_bit>>(7-i))&0x01)<<i);
scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] = curr_bit;
}
}
......
......@@ -31,8 +31,72 @@
*/
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
#include "asn1_conversions.h"
#include <limits.h>
/* Tools */
#include "SIMULATION/TOOLS/sim.h" // for taus
// ================================================
// SSB to RO mapping private defines and structures
// ================================================
#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD (16) // Maximum association period is 16
#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max association pattern period is 160ms and minimum PRACH configuration period is 10ms
#define MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max nb of association periods in an association pattern period of 160ms
#define MAX_NB_FRAME_IN_PRACH_CONF_PERIOD (16) // Max PRACH configuration period is 160ms and frame is 10ms
#define MAX_NB_SLOT_IN_FRAME (160) // Max number of slots in a frame (@ SCS 240kHz = 160)
#define MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD (16) // Maximum number of frames in the maximum association pattern period
#define MAX_NB_SSB (64) // Maximum number of possible SSB indexes
#define MAX_RO_PER_SSB (8) // Maximum number of consecutive ROs that can be mapped to an SSB according to the ssb_per_RACH config
// Maximum number of ROs that can be mapped to an SSB in an association pattern
// This is to reserve enough elements in the SSBs list for each mapped ROs for a single SSB
// An arbitrary maximum number is chosen to be safe: maximum number of slots in an association pattern * maximum number of ROs in a slot
#define MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN (MAX_TDM*MAX_FDM*MAX_NB_SLOT_IN_FRAME*MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD)
// The PRACH Config period is a series of selected slots in one or multiple frames
typedef struct prach_conf_period {
prach_occasion_slot_t prach_occasion_slot_map[MAX_NB_FRAME_IN_PRACH_CONF_PERIOD][MAX_NB_SLOT_IN_FRAME];
uint16_t nb_of_prach_occasion; // Total number of PRACH occasions in the PRACH Config period
uint8_t nb_of_frame; // Size of the PRACH Config period in number of 10ms frames
uint8_t nb_of_slot; // Nb of slots in each frame
} prach_conf_period_t;
// The association period is a series of PRACH Config periods
typedef struct prach_association_period {
prach_conf_period_t *prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD];
uint8_t nb_of_prach_conf_period; // Nb of PRACH configuration periods within the association period
uint8_t nb_of_frame; // Total number of frames included in the association period
} prach_association_period_t;
// The association pattern is a series of Association periods
typedef struct prach_association_pattern {
prach_association_period_t prach_association_period_list[MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD];
prach_conf_period_t prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD];
uint8_t nb_of_assoc_period; // Nb of association periods within the association pattern
uint8_t nb_of_prach_conf_period_in_max_period; // Nb of PRACH configuration periods within the maximum association pattern period (according to the size of the configured PRACH
uint8_t nb_of_frame; // Total number of frames included in the association pattern period (after mapping the SSBs and determining the real association pattern length)
} prach_association_pattern_t;
// SSB details
typedef struct ssb_info {
boolean_t transmitted; // True if the SSB index is transmitted according to the SSB positions map configuration
prach_occasion_info_t *mapped_ro[MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN]; // List of mapped RACH Occasions to this SSB index
uint16_t nb_mapped_ro; // Total number of mapped ROs to this SSB index
} ssb_info_t;
// List of all the possible SSBs and their details
typedef struct ssb_list_info {
ssb_info_t tx_ssb[MAX_NB_SSB];
uint8_t nb_tx_ssb;
} ssb_list_info_t;
static prach_association_pattern_t prach_assoc_pattern;
static ssb_list_info_t ssb_list;
// ===============================================
// ===============================================
const uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160};
// Table 6.3.3.1-5 (38.211) NCS for preamble formats with delta_f_RA = 1.25 KHz
......@@ -1169,9 +1233,629 @@ switch(prach_format){
default :
AssertFatal(1==0,"Invalid Prach format\n");
break;
}
}
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
static void build_ro_list(NR_ServingCellConfigCommon_t *scc, uint8_t unpaired) {
int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers
int y2; // PRACH Configuration Index table additional variable used to compute the valid frame numbers
uint8_t slot_shift_for_map;
uint8_t map_shift;
boolean_t even_slot_invalid;
int64_t s_map;
uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot
uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot
uint8_t N_dur; // Duration of a PRACH occasion (nb of symbols)
uint8_t frame; // Maximum is NB_FRAMES_IN_MAX_ASSOCIATION_PATTERN_PERIOD
uint8_t slot; // Maximum is the number of slots in a frame @ SCS 240kHz
uint16_t format = 0xffff;
uint8_t format2 = 0xff;
int nb_fdm;
uint8_t config_index, mu;
uint32_t pointa;
int msg1_FDM;
uint8_t prach_conf_period_idx;
uint8_t nb_of_frames_per_prach_conf_period;
uint8_t prach_conf_period_frame_idx;
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
if (setup->msg1_SubcarrierSpacing)
mu = *setup->msg1_SubcarrierSpacing;
else
mu = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
pointa = frequencyInfoDL->absoluteFrequencyPointA;
msg1_FDM = rach_ConfigGeneric->msg1_FDM;
switch (msg1_FDM){
case 0:
case 1:
case 2:
case 3:
nb_fdm = 1 << msg1_FDM;
break;
default:
AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", msg1_FDM);
}
// Create the PRACH occasions map
// ==============================
// WIP-IDCC: For now assume no rejected PRACH occasions because of conflict with SSB or TDD_UL_DL_ConfigurationCommon schedule
// Identify the proper PRACH Configuration Index table according to the operating frequency
LOG_D(MAC,"Pointa %u, mu = %u, PRACH config index = %u, unpaired = %u\n", pointa, mu, config_index, unpaired);
if (pointa > 2016666) { //FR2
x = table_6_3_3_2_4_prachConfig_Index[config_index][2];
y = table_6_3_3_2_4_prachConfig_Index[config_index][3];
y2 = table_6_3_3_2_4_prachConfig_Index[config_index][4];
s_map = table_6_3_3_2_4_prachConfig_Index[config_index][5];
prach_conf_start_symbol = table_6_3_3_2_4_prachConfig_Index[config_index][6];
N_t_slot = table_6_3_3_2_4_prachConfig_Index[config_index][8];
N_dur = table_6_3_3_2_4_prachConfig_Index[config_index][9];
if (table_6_3_3_2_4_prachConfig_Index[config_index][1] != -1)
format2 = (uint8_t) table_6_3_3_2_4_prachConfig_Index[config_index][1];
format = ((uint8_t) table_6_3_3_2_4_prachConfig_Index[config_index][0]) | (format2<<8);
slot_shift_for_map = mu-2;
if ( (mu == 3) && (table_6_3_3_2_4_prachConfig_Index[config_index][7] == 1) )
even_slot_invalid = true;
else
even_slot_invalid = false;
}
else { // FR1
if (unpaired) {
x = table_6_3_3_2_3_prachConfig_Index[config_index][2];
y = table_6_3_3_2_3_prachConfig_Index[config_index][3];
s_map = table_6_3_3_2_3_prachConfig_Index[config_index][4];
prach_conf_start_symbol = table_6_3_3_2_3_prachConfig_Index[config_index][5];
N_t_slot = table_6_3_3_2_3_prachConfig_Index[config_index][7];
N_dur = table_6_3_3_2_3_prachConfig_Index[config_index][8];
if (table_6_3_3_2_3_prachConfig_Index[config_index][1] != -1)
format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[config_index][1];
format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[config_index][0]) | (format2<<8);
}
else { // FDD
x = table_6_3_3_2_2_prachConfig_Index[config_index][2];
y = table_6_3_3_2_2_prachConfig_Index[config_index][3];
s_map = table_6_3_3_2_2_prachConfig_Index[config_index][4];
prach_conf_start_symbol = table_6_3_3_2_2_prachConfig_Index[config_index][5];
N_t_slot = table_6_3_3_2_2_prachConfig_Index[config_index][7];
N_dur = table_6_3_3_2_2_prachConfig_Index[config_index][8];
if (table_6_3_3_2_2_prachConfig_Index[config_index][1] != -1)
format2 = (uint8_t) table_6_3_3_2_2_prachConfig_Index[config_index][1];
format = ((uint8_t) table_6_3_3_2_2_prachConfig_Index[config_index][0]) | (format2<<8);
}
y2 = y;
slot_shift_for_map = mu;
if ( (mu == 1) && (table_6_3_3_2_3_prachConfig_Index[config_index][6] <= 1) )
even_slot_invalid = true;
else
even_slot_invalid = false;
} // FR2 / FR1
prach_assoc_pattern.nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x;
nb_of_frames_per_prach_conf_period = x;
LOG_D(MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern.nb_of_prach_conf_period_in_max_period);
// Fill in the PRACH occasions table for every slot in every frame in every PRACH configuration periods in the maximum association pattern period
// ----------------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------------------------------------
// For every PRACH configuration periods
// -------------------------------------
for (prach_conf_period_idx=0; prach_conf_period_idx<prach_assoc_pattern.nb_of_prach_conf_period_in_max_period; prach_conf_period_idx++) {
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion = 0;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_frame = nb_of_frames_per_prach_conf_period;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_slot = nr_slots_per_frame[mu];
LOG_D(MAC,"PRACH Conf Period Idx %d\n", prach_conf_period_idx);
// For every frames in a PRACH configuration period
// ------------------------------------------------
for (prach_conf_period_frame_idx=0; prach_conf_period_frame_idx<nb_of_frames_per_prach_conf_period; prach_conf_period_frame_idx++) {
frame = (prach_conf_period_idx * nb_of_frames_per_prach_conf_period) + prach_conf_period_frame_idx;
LOG_D(MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", prach_conf_period_frame_idx, frame);
// Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
if ( (frame%x)==y || (frame%x)==y2 ) {
// For every slot in a frame
// -------------------------
for (slot=0; slot<nr_slots_per_frame[mu]; slot++) {
// Is it a valid slot?
map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
if ( (s_map>>map_shift)&0x01 ) {
// Valid slot
// Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
if ( even_slot_invalid && (slot%2 == 0) )
continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
// We're good: valid frame and valid slot
// Compute all the PRACH occasions in the slot
uint8_t n_prach_occ_in_time;
uint8_t n_prach_occ_in_freq;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_time = N_t_slot;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_freq = nb_fdm;
for (n_prach_occ_in_time=0; n_prach_occ_in_time<N_t_slot; n_prach_occ_in_time++) {
uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
LOG_D(MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time);
for (n_prach_occ_in_freq=0; n_prach_occ_in_freq<nb_fdm; n_prach_occ_in_freq++) {
prach_occasion_info_t *prach_occasion_p = &prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].prach_occasion[n_prach_occ_in_time][n_prach_occ_in_freq];
prach_occasion_p->start_symbol = start_symbol;
prach_occasion_p->fdm = n_prach_occ_in_freq;
prach_occasion_p->frame = frame;
prach_occasion_p->slot = slot;
prach_occasion_p->format = format;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion++;
LOG_D(MAC,"Adding a PRACH occasion: frame %u, slot-symbol %d-%d, occ_in_time-occ_in-freq %d-%d, nb ROs in conf period %d, for this slot: RO# in time %d, RO# in freq %d\n",
frame, slot, start_symbol, n_prach_occ_in_time, n_prach_occ_in_freq, prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion,
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_time,
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_freq);
} // For every freq in the slot
} // For every time occasions in the slot
} // Valid slot?
} // For every slots in a frame
} // Valid frame?
} // For every frames in a prach configuration period
} // For every prach configuration periods in the maximum association pattern period (160ms)
}
// Build the list of all the valid/transmitted SSBs according to the config
static void build_ssb_list(NR_ServingCellConfigCommon_t *scc) {
// Create the list of transmitted SSBs
// ===================================
BIT_STRING_t *ssb_bitmap;
uint64_t ssb_positionsInBurst;
uint8_t ssb_idx = 0;
switch (scc->ssb_PositionsInBurst->present) {
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint8(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=3; bit_nb<=3; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint8(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=7; bit_nb<=7; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.longBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint64(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=63; bit_nb<=63; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
default:
AssertFatal(false,"ssb_PositionsInBurst not present\n");
break;
}
}
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
static void map_ssb_to_ro(NR_ServingCellConfigCommon_t *scc) {
// Map SSBs to PRACH occasions
// ===========================
// WIP-IDCC: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB
uint16_t required_nb_of_prach_occasion; // Nb of RACH occasions required to map all the SSBs
uint8_t required_nb_of_prach_conf_period; // Nb of PRACH configuration periods required to map all the SSBs
// Determine the SSB to RACH mapping ratio
// =======================================
switch (ssb_perRACH_config){
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 8;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 4;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 2;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 1;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 2;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 4;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 8;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 16;
break;
default:
AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config);
break;
}
LOG_D(MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro);
// Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
// ==============================================================================================================
// WIP-IDCC: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same number of PRACH occasions
// (No PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule)
// There is only one possible association period which can contain up to 16 PRACH configuration periods
LOG_D(MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n");
if (true == multiple_ssb_per_ro) {
required_nb_of_prach_occasion = ((ssb_list.nb_tx_ssb-1) + ssb_rach_ratio) / ssb_rach_ratio;
}
else {
required_nb_of_prach_occasion = ssb_list.nb_tx_ssb * ssb_rach_ratio;
}
required_nb_of_prach_conf_period = ((required_nb_of_prach_occasion-1) + prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion) / prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion;
if (required_nb_of_prach_conf_period == 1) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 1;
}
else if (required_nb_of_prach_conf_period == 2) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 2;
}
else if (required_nb_of_prach_conf_period <= 4) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 4;
}
else if (required_nb_of_prach_conf_period <= 8) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 8;
}
else if (required_nb_of_prach_conf_period <= 16) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 16;
}
else {
AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period);
}
prach_assoc_pattern.nb_of_assoc_period = 1; // WIP-IDCC: only one possible association period
prach_assoc_pattern.prach_association_period_list[0].nb_of_frame = prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period * prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
prach_assoc_pattern.nb_of_frame = prach_assoc_pattern.prach_association_period_list[0].nb_of_frame;
LOG_D(MAC,"Assoc period %d, Nb of frames in assoc period %d\n",
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period,
prach_assoc_pattern.prach_association_period_list[0].nb_of_frame);
// Proceed to the SSB to RO mapping
// ================================
uint8_t association_period_idx; // Association period index within the association pattern
uint8_t ssb_idx = 0;
uint8_t prach_configuration_period_idx; // PRACH Configuration period index within the association pattern
prach_conf_period_t *prach_conf_period_p;
// Map all the association periods within the association pattern period
LOG_D(MAC,"Proceed to the SSB to RO mapping\n");
for (association_period_idx=0; association_period_idx<prach_assoc_pattern.nb_of_assoc_period; association_period_idx++) {
uint8_t n_prach_conf=0; // PRACH Configuration period index within the association period
uint8_t frame=0;
uint8_t slot=0;
uint8_t ro_in_time=0;
uint8_t ro_in_freq=0;
// Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
prach_configuration_period_idx = 0; // WIP-IDCC: only one possible association period so the starting PRACH configuration period is automatically 0
// Check if we need to map multiple SSBs per RO or multiple ROs per SSB
if (true == multiple_ssb_per_ro) {
// --------------------
// --------------------
// Multiple SSBs per RO
// --------------------
// --------------------
// WIP-IDCC: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
ssb_idx = 0;
// Go through the list of PRACH config periods within this association period
for (n_prach_conf=0; n_prach_conf<prach_assoc_pattern.prach_association_period_list[association_period_idx].nb_of_prach_conf_period; n_prach_conf++, prach_configuration_period_idx++) {
// Build the association period with its association PRACH Configuration indexes
prach_conf_period_p = &prach_assoc_pattern.prach_conf_period_list[prach_configuration_period_idx];
prach_assoc_pattern.prach_association_period_list[association_period_idx].prach_conf_period_list[n_prach_conf] = prach_conf_period_p;
// Go through all the ROs within the PRACH config period
for (frame=0; frame<prach_conf_period_p->nb_of_frame; frame++) {
for (slot=0; slot<prach_conf_period_p->nb_of_slot; slot++) {
for (ro_in_time=0; ro_in_time<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_time; ro_in_time++) {
for (ro_in_freq=0; ro_in_freq<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *ro_p = &prach_conf_period_p->prach_occasion_slot_map[frame][slot].prach_occasion[ro_in_time][ro_in_freq];
// Go through the list of transmitted SSBs and map the required amount of SSBs to this RO
// WIP-IDCC: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
for (; ssb_idx<MAX_NB_SSB; ssb_idx++) {
// Map only the transmitted ssb_idx
if (true == ssb_list.tx_ssb[ssb_idx].transmitted) {
ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
ro_p->nb_mapped_ssb++;
ssb_list.tx_ssb[ssb_idx].mapped_ro[ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > ssb_list.tx_ssb[ssb_idx].nb_mapped_ro,"Too many mapped ROs (%d) to a single SSB\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
LOG_D(MAC,"Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", ssb_idx, ro_p->slot, ro_p->start_symbol, slot, ro_in_time, ro_in_freq, prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(MAC,"Nb mapped ROs for this ssb idx: in the association period only %u\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
// If all the required SSBs are mapped to this RO, exit the loop of SSBs
if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
ssb_idx++;
break;
}
} // if ssb_idx is transmitted
} // for ssb_idx
// Exit the loop of ROs if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for ro_in_freq
// Exit the loop of ROs if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for ro_in_time
// Exit the loop of slots if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for slot
// Exit the loop frames if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for frame
// Exit the loop of PRACH configurations if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for n_prach_conf
// WIP-IDCC: note that there is no re-mapping of the SSBs within the association period since there is no invalid ROs in the PRACH config periods that would create this situation
} // if multiple_ssbs_per_ro
else {
// --------------------
// --------------------
// Multiple ROs per SSB
// --------------------
// --------------------
n_prach_conf = 0;
// Go through the list of transmitted SSBs
for (ssb_idx=0; ssb_idx<MAX_NB_SSB; ssb_idx++) {
uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index
// Map only the transmitted ssb_idx
if (true == ssb_list.tx_ssb[ssb_idx].transmitted) {
// Map all the required ROs to this SSB
// Go through the list of PRACH config periods within this association period
for (; n_prach_conf<prach_assoc_pattern.prach_association_period_list[association_period_idx].nb_of_prach_conf_period; n_prach_conf++, prach_configuration_period_idx++) {
// Build the association period with its association PRACH Configuration indexes
prach_conf_period_p = &prach_assoc_pattern.prach_conf_period_list[prach_configuration_period_idx];
prach_assoc_pattern.prach_association_period_list[association_period_idx].prach_conf_period_list[n_prach_conf] = prach_conf_period_p;
for (; frame<prach_conf_period_p->nb_of_frame; frame++) {
for (; slot<prach_conf_period_p->nb_of_slot; slot++) {
for (; ro_in_time<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_time; ro_in_time++) {
for (; ro_in_freq<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *ro_p = &prach_conf_period_p->prach_occasion_slot_map[frame][slot].prach_occasion[ro_in_time][ro_in_freq];
ro_p->mapped_ssb_idx[0] = ssb_idx;
ro_p->nb_mapped_ssb = 1;
ssb_list.tx_ssb[ssb_idx].mapped_ro[ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > ssb_list.tx_ssb[ssb_idx].nb_mapped_ro,"Too many mapped ROs (%d) to a single SSB\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
nb_mapped_ro_in_association_period++;
LOG_D(MAC,"Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", ssb_idx, ro_p->slot, ro_p->start_symbol, slot, ro_in_time, ro_in_freq, prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(MAC,"Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro, nb_mapped_ro_in_association_period);
// Exit the loop if this SSB has been mapped to all the required ROs
// WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an association period:
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
ro_in_freq++;
break;
}
} // for ro_in_freq
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else ro_in_freq = 0; // else go to the next time symbol in that slot and reset the freq index
} // for ro_in_time
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else ro_in_time = 0; // else go to the next slot in that PRACH config period and reset the symbol index
} // for slot
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else slot = 0; // else go to the next frame in that PRACH config period and reset the slot index
} // for frame
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else frame = 0; // else go to the next PRACH config period in that association period and reset the frame index
} // for n_prach_conf
} // if ssb_idx is transmitted
} // for ssb_idx
} // else if multiple_ssbs_per_ro
} // for association_period_index
}
// Build the SSB to RO mapping upon RRC configuration update
void build_ssb_to_ro_map(NR_ServingCellConfigCommon_t *scc, uint8_t unpaired){
// Clear all the lists and maps
memset(&prach_assoc_pattern, 0, sizeof(prach_association_pattern_t));
memset(&ssb_list, 0, sizeof(ssb_list_info_t));
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
LOG_D(MAC,"Build RO list\n");
build_ro_list(scc, unpaired);
// Build the list of all the valid/transmitted SSBs according to the config
LOG_D(MAC,"Build SSB list\n");
build_ssb_list(scc);
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
LOG_D(MAC,"Map SSB to RO\n");
map_ssb_to_ro(scc);
LOG_D(MAC,"Map SSB to RO done\n");
}
// Returns a RACH occasion if any matches the SSB idx, the frame and the slot
int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx,
int frame,
int slot,
prach_occasion_info_t **prach_occasion_info_pp) {
ssb_info_t *ssb_info_p;
prach_occasion_slot_t *prach_occasion_slot_p = NULL;
*prach_occasion_info_pp = NULL;
// Search for a matching RO slot in the SSB_to_RO map
// A valid RO slot will match:
// - ssb_idx mapped to one of the ROs in that RO slot
// - exact slot number
// - frame offset
ssb_info_p = &ssb_list.tx_ssb[ssb_idx];
for (uint8_t n_mapped_ro=0; n_mapped_ro<ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) &&
(ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern.nb_of_frame))) {
uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
prach_occasion_slot_p = &prach_assoc_pattern.prach_conf_period_list[prach_config_period_nb].prach_occasion_slot_map[frame_nb_in_prach_config_period][slot];
}
}
// If there is a matching RO slot in the SSB_to_RO map
if (NULL != prach_occasion_slot_p)
{
// A random RO mapped to the SSB index should be selected in the slot
// First count the number of times the SSB index is found in that RO
uint8_t nb_mapped_ssb = 0;
for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *prach_occasion_info_p = &prach_occasion_slot_p->prach_occasion[ro_in_time][ro_in_freq];
for (uint8_t ssb_nb=0; ssb_nb<prach_occasion_info_p->nb_mapped_ssb; ssb_nb++) {
if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
nb_mapped_ssb++;
}
}
}
}
// Choose a random SSB nb
uint8_t random_ssb_nb = 0;
random_ssb_nb = ((taus()) % nb_mapped_ssb);
// Select the RO according to the chosen random SSB nb
nb_mapped_ssb=0;
for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *prach_occasion_info_p = &prach_occasion_slot_p->prach_occasion[ro_in_time][ro_in_freq];
for (uint8_t ssb_nb=0; ssb_nb<prach_occasion_info_p->nb_mapped_ssb; ssb_nb++) {
if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
if (nb_mapped_ssb == random_ssb_nb) {
*prach_occasion_info_pp = prach_occasion_info_p;
return 1;
}
else {
nb_mapped_ssb++;
}
}
}
}
}
}
return 0;
}
int get_nr_prach_info_from_index(uint8_t index,
......@@ -1331,6 +2015,7 @@ int get_nr_prach_info_from_index(uint8_t index,
}
}
//Table 6.3.3.1-3: Mapping from logical index i to sequence number u for preamble formats with L_RA = 839
uint16_t table_63313[838] = {
129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84 , 755, 105, 734, 93 , 746, 70 , 769, 60 , 779,
......
......@@ -36,6 +36,36 @@
#include "NR_CellGroupConfig.h"
#include "nr_mac.h"
// ===============================================
// SSB to RO mapping public defines and structures
// ===============================================
#define MAX_SSB_PER_RO (16) // Maximum number of SSBs that can be mapped to a single RO
#define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot
#define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot
// PRACH occasion details
typedef struct prach_occasion_info {
uint8_t start_symbol; // 0 - 13 (14 symbols in a slot)
uint8_t fdm; // 0-7 (possible values of msg1-FDM: 1, 2, 4 or 8)
uint8_t slot; // 0 - 159 (maximum number of slots in a 10ms frame - @ 240kHz)
uint8_t frame; // 0 - 15 (maximum number of frames in a 160ms association pattern)
uint8_t mapped_ssb_idx[MAX_SSB_PER_RO]; // List of mapped SSBs
uint8_t nb_mapped_ssb;
uint16_t format; // RO preamble format
} prach_occasion_info_t;
// PRACH occasion slot details
// A PRACH occasion slot is a series of PRACH occasions in time (symbols) and frequency
typedef struct prach_occasion_slot {
prach_occasion_info_t prach_occasion[MAX_TDM][MAX_FDM]; // Starting symbol of each PRACH occasions in a slot
uint8_t nb_of_prach_occasion_in_time;
uint8_t nb_of_prach_occasion_in_freq;
} prach_occasion_slot_t;
// ========================================
typedef enum {
NR_DL_DCI_FORMAT_1_0 = 0,
NR_DL_DCI_FORMAT_1_1,
......@@ -89,6 +119,9 @@ void find_monitoring_periodicity_offset_common(NR_SearchSpace_t *ss,
uint16_t *slot_period,
uint16_t *offset);
void build_ssb_to_ro_map(NR_ServingCellConfigCommon_t *scc, uint8_t unpaired);
int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx, int frame, int slot, prach_occasion_info_t **prach_occasion_info_pp);
int get_nr_prach_info_from_index(uint8_t index,
int frame,
int slot,
......
......@@ -204,7 +204,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
uint16_t band;
int32_t offset;
get_band((cfg->carrier_config.dl_frequency)*1000,
get_band((uint64_t)(cfg->carrier_config.dl_frequency)*1000,
&band,
&offset,
&frame_type);
......@@ -243,8 +243,8 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
cfg->ssb_table.ssb_mask_list[0].ssb_mask = 0;
cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
for (i=0; i<4; i++) {
cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
}
break;
default:
......@@ -433,6 +433,9 @@ int nr_rrc_mac_config_req_ue(
LOG_I(MAC,"Configuring CRNTI %x\n",mac->crnti);
}
// Setup the SSB to Rach Occasions mapping according to the config
build_ssb_to_ro_map(mac->scc, mac->phy_config.config_req.cell_config.frame_duplex_type);
/*
if(mac_cell_group_configP != NULL){
if(mac_cell_group_configP->drx_Config != NULL ){
......
......@@ -237,6 +237,7 @@ andom-access to transmit a BSR along with the C-RNTI control element (see 5.1.4
@param nr_tti_tx slot for PRACH transmission
@returns indication to generate PRACH to phy */
uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
NR_UE_PRACH *prach_vars,
module_id_t mod_id,
int CC_id,
UE_MODE_t UE_mode,
......@@ -254,9 +255,9 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
void nr_get_prach_resources(module_id_t mod_id,
int CC_id,
uint8_t gNB_id,
uint8_t t_id,
uint8_t first_Msg3,
NR_PRACH_RESOURCES_t *prach_resources,
NR_UE_PRACH *prach_vars,
NR_RACH_ConfigDedicated_t * rach_ConfigDedicated);
void nr_Msg1_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint8_t gNB_id);
......
......@@ -75,9 +75,9 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac);
void nr_get_prach_resources(module_id_t mod_id,
int CC_id,
uint8_t gNB_id,
uint8_t t_id,
uint8_t first_Msg3,
NR_PRACH_RESOURCES_t *prach_resources,
NR_UE_PRACH *prach_vars,
NR_RACH_ConfigDedicated_t * rach_ConfigDedicated){
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
......@@ -87,8 +87,8 @@ void nr_get_prach_resources(module_id_t mod_id,
// NR_BeamFailureRecoveryConfig_t *beam_failure_recovery_config = &mac->RA_BeamFailureRecoveryConfig; // todo
int messagePowerOffsetGroupB = 0, messageSizeGroupA, PLThreshold, sizeOfRA_PreamblesGroupA = 0, numberOfRA_Preambles, i, deltaPreamble_Msg3 = 0;
uint8_t noGroupB = 0, s_id, f_id, ul_carrier_id, prach_ConfigIndex, SFN_nbr, Msg3_size;
int messagePowerOffsetGroupB = 0, messageSizeGroupA, PLThreshold, sizeOfRA_PreamblesGroupA = 0, numberOfRA_Preambles, deltaPreamble_Msg3 = 0;
uint8_t noGroupB = 0, s_id, t_id, f_id, ul_carrier_id, Msg3_size;
AssertFatal(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup != NULL, "[UE %d] FATAL nr_rach_ConfigCommon is NULL !!!\n", mod_id);
nr_rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
......@@ -100,6 +100,7 @@ void nr_get_prach_resources(module_id_t mod_id,
//////////* UE Random Access Resource Selection *//////////
///////////////////////////////////////////////////////////
// todo:
// - switch initialisation cases
// -- RA initiated by beam failure recovery operation (subclause 5.17 TS 38.321)
......@@ -129,12 +130,81 @@ void nr_get_prach_resources(module_id_t mod_id,
// rsrp_ThresholdSSB = *nr_rach_ConfigCommon->rsrp_ThresholdSSB;
// Determine the SSB to RACH mapping ratio
// =======================================
NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB
long cb_preambles_per_ssb; // Nb of preambles per SSB
int total_preambles_per_ssb;
int starting_preamble_nb = 0;
uint8_t ssb_nb_in_ro;
switch (ssb_perRACH_config){
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 8;
cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneEighth + 1);
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 4;
cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneFourth + 1);
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 2;
cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneHalf + 1);
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 1;
cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one + 1);
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 2;
cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.two + 1);
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 4;
cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.four;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 8;
cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.eight;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 16;
cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.sixteen;
break;
default:
AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config);
break;
}
Msg3_size = mac->RA_Msg3_size;
numberOfRA_Preambles = 64;
if(nr_rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
numberOfRA_Preambles = *(nr_rach_ConfigCommon->totalNumberOfRA_Preambles);
// Compute the proper Preamble selection params according to the selected SSB and the ssb_perRACH_OccasionAndCB_PreamblesPerSSB configuration
if ((true == multiple_ssb_per_ro) &&
(ssb_rach_ratio > 1)) {
total_preambles_per_ssb = numberOfRA_Preambles / ssb_rach_ratio;
ssb_nb_in_ro = prach_vars->prach_pdu.ssb_nb_in_ro;
starting_preamble_nb = total_preambles_per_ssb * ssb_nb_in_ro;
}
else {
total_preambles_per_ssb = numberOfRA_Preambles;
starting_preamble_nb = 0;
}
if (!nr_rach_ConfigCommon->groupBconfigured) {
noGroupB = 1;
} else {
......@@ -220,29 +290,30 @@ void nr_get_prach_resources(module_id_t mod_id,
if (first_Msg3 == 1) {
if (noGroupB == 1) {
// use Group A preamble
prach_resources->ra_PreambleIndex = (taus()) % numberOfRA_Preambles;
prach_resources->ra_PreambleIndex = starting_preamble_nb + ((taus()) % cb_preambles_per_ssb);
mac->RA_usedGroupA = 1;
} else if ((Msg3_size < messageSizeGroupA) && (get_nr_PL(mod_id, CC_id, gNB_id) > PLThreshold)) {
// Group B is configured and RA preamble Group A is used
// - todo add condition on CCCH_sdu_size for initiation by CCCH
prach_resources->ra_PreambleIndex = (taus()) % sizeOfRA_PreamblesGroupA;
prach_resources->ra_PreambleIndex = starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA);
mac->RA_usedGroupA = 1;
} else {
// Group B preamble is configured and used
// the first sizeOfRA_PreamblesGroupA RA preambles belong to RA Preambles Group A
// the remaining belong to RA Preambles Group B
prach_resources->ra_PreambleIndex = sizeOfRA_PreamblesGroupA + (taus()) % (numberOfRA_Preambles - sizeOfRA_PreamblesGroupA);
prach_resources->ra_PreambleIndex = starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
mac->RA_usedGroupA = 0;
}
} else { // Msg3 is being retransmitted
if (mac->RA_usedGroupA == 1 && noGroupB == 1) {
prach_resources->ra_PreambleIndex = (taus()) % numberOfRA_Preambles;
prach_resources->ra_PreambleIndex = starting_preamble_nb + ((taus()) % cb_preambles_per_ssb);
} else if (mac->RA_usedGroupA == 1 && noGroupB == 0){
prach_resources->ra_PreambleIndex = (taus()) % sizeOfRA_PreamblesGroupA;
prach_resources->ra_PreambleIndex = starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA);
} else {
prach_resources->ra_PreambleIndex = sizeOfRA_PreamblesGroupA + (taus()) % (numberOfRA_Preambles - sizeOfRA_PreamblesGroupA);
prach_resources->ra_PreambleIndex = starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
}
}
LOG_D(MAC, "[RAPROC] - Selected RA preamble index %d for contention-based random access procedure... \n", prach_resources->ra_PreambleIndex);
}
......@@ -268,27 +339,16 @@ void nr_get_prach_resources(module_id_t mod_id,
// 1) this does not apply to contention-free RA Preamble for beam failure recovery request
// 2) getting star_symb, SFN_nbr from table 6.3.3.2-3 (TDD and FR1 scenario)
prach_ConfigIndex = rach_ConfigGeneric->prach_ConfigurationIndex;
// ra_RNTI computation
// - todo: this is for TDD FR1 only
// - ul_carrier_id: UL carrier used for RA preamble transmission, hardcoded for NUL carrier
// - f_id: index of the PRACH occasion in the frequency domain
// - s_id is starting symbol of the PRACH occasion [0...14]
// - t_id is the first slot of the PRACH occasion in a system frame [0...80]
ul_carrier_id = 0; // NUL
f_id = rach_ConfigGeneric->msg1_FrequencyStart;
SFN_nbr = table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][4];
s_id = table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][5];
f_id = prach_vars->prach_pdu.num_ra;
t_id = prach_vars->prach_pdu.prach_slot;
s_id = prach_vars->prach_pdu.prach_start_symbol;
// Pick the first slot of the PRACH occasion in a system frame
for (i = 0; i < 10; i++){
if (((SFN_nbr & (1 << i)) >> i) == 1){
t_id = 2*i;
break;
}
}
prach_resources->ra_RNTI = 1 + s_id + 14 * t_id + 1120 * f_id + 8960 * ul_carrier_id;
mac->ra_rnti = prach_resources->ra_RNTI;
......@@ -335,6 +395,7 @@ void nr_Msg3_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint
// - add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator)
uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
NR_UE_PRACH *prach_vars,
module_id_t mod_id,
int CC_id,
UE_MODE_t UE_mode,
......@@ -449,7 +510,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
// Fill in preamble and PRACH resources
if (mac->generate_nr_prach == 1)
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, 1, prach_resources, rach_ConfigDedicated);
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, prach_resources, prach_vars, rach_ConfigDedicated);
offset = nr_generate_ulsch_pdu((uint8_t *) mac_sdus, // sdus buffer
(uint8_t *) payload, // UL MAC pdu pointer
......@@ -572,7 +633,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
// Fill in preamble and PRACH resources
if (mac->generate_nr_prach == 1)
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, 0, prach_resources, rach_ConfigDedicated);
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, prach_resources, prach_vars, rach_ConfigDedicated);
} else {
......@@ -586,7 +647,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
// Fill in preamble and PRACH resources
if (mac->generate_nr_prach == 1)
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, 0, prach_resources, rach_ConfigDedicated);
nr_get_prach_resources(mod_id, CC_id, gNB_id, nr_tti_tx, prach_resources, prach_vars, rach_ConfigDedicated);
}
}
......
......@@ -935,18 +935,14 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
}
// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
// It fills the PRACH PDU per each FD occasion.
// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
// - todo:
// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config
void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) {
uint8_t config_index, mu, N_dur, N_t_slot, start_symbol;
uint16_t RA_sfn_index;
uint8_t N_RA_slot;
uint8_t config_period;
uint16_t format, format0, format1, ncs;
int msg1_FDM, is_nr_prach_slot, fdm;
int is_nr_prach_slot;
prach_occasion_info_t *prach_occasion_info_p;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
......@@ -957,59 +953,35 @@ void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t s
NR_ServingCellConfigCommon_t *scc = mac->scc;
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
mac->RA_offset = 2; // to compensate the rx frame offset at the gNB
mac->generate_nr_prach = 0; // Reset flag for PRACH generation
if (is_nr_UL_slot(scc, slotP)) {
if (setup->msg1_SubcarrierSpacing)
mu = *setup->msg1_SubcarrierSpacing;
else
mu = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
// WIP-IDCC Need to get the proper selected ssb_idx
// Initial beam selection functionality is not available yet
uint8_t selected_gnb_ssb_idx = 0;
is_nr_prach_slot = get_nr_prach_info_from_index(config_index,
// Get any valid PRACH occasion in the current slot for the selected SSB index
is_nr_prach_slot = get_nr_prach_info_from_ssb_index(selected_gnb_ssb_idx,
(int)frameP,
(int)slotP,
frequencyInfoDL->absoluteFrequencyPointA,
mu,
cfg->cell_config.frame_duplex_type,
&format,
&start_symbol,
&N_t_slot,
&N_dur,
&RA_sfn_index,
&N_RA_slot,
&config_period);
&prach_occasion_info_p);
if (is_nr_prach_slot && mac->ra_state == RA_UE_IDLE) {
AssertFatal(NULL != prach_occasion_info_p,"PRACH Occasion Info not returned in a valid NR Prach Slot\n");
mac->generate_nr_prach = 1;
fdm = rach_ConfigGeneric->msg1_FDM;
switch (fdm){
case 0:
case 1:
case 2:
case 3:
msg1_FDM = 1 << fdm;
break;
default:
AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", fdm);
}
format = prach_occasion_info_p->format;
format0 = format & 0xff; // single PRACH format
format1 = (format >> 8) & 0xff; // dual PRACH format
ul_config->sfn = frameP;
ul_config->slot = slotP;
for (int n = 0; n < msg1_FDM; n++) { // one structure per frequency domain occasion
ul_config->ul_config_list[ul_config->number_pdus].pdu_type = FAPI_NR_UL_CONFIG_TYPE_PRACH;
prach_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].prach_config_pdu;
memset(prach_config_pdu, 0, sizeof(fapi_nr_ul_config_prach_pdu));
......@@ -1017,15 +989,26 @@ void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t s
ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig);
// filling PRACH PDU for FAPI config request
prach_config_pdu->phys_cell_id = *scc->physCellId;
prach_config_pdu->num_prach_ocas = N_t_slot;
prach_config_pdu->prach_start_symbol = start_symbol;
prach_config_pdu->num_ra = n;
prach_config_pdu->num_prach_ocas = 1;
prach_config_pdu->prach_slot = prach_occasion_info_p->slot;
prach_config_pdu->prach_start_symbol = prach_occasion_info_p->start_symbol;
prach_config_pdu->num_ra = prach_occasion_info_p->fdm;
prach_config_pdu->num_cs = ncs;
prach_config_pdu->root_seq_id = prach_config->num_prach_fd_occasions_list[n].prach_root_sequence_index;
prach_config_pdu->root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index;
prach_config_pdu->restricted_set = prach_config->restricted_set_config;
prach_config_pdu->freq_msg1 = prach_config->num_prach_fd_occasions_list[n].k1;
prach_config_pdu->freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1;
LOG_D(MAC,"Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", frameP, prach_config_pdu->prach_slot, prach_config_pdu->prach_start_symbol, prach_config_pdu->num_ra);
// Search which SSB is mapped in the RO (among all the SSBs mapped to this RO)
for (prach_config_pdu->ssb_nb_in_ro=0; prach_config_pdu->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb; prach_config_pdu->ssb_nb_in_ro++) {
if (prach_occasion_info_p->mapped_ssb_idx[prach_config_pdu->ssb_nb_in_ro] == selected_gnb_ssb_idx)
break;
}
AssertFatal(prach_config_pdu->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb, "%u not found in the mapped SSBs to the PRACH occasion", selected_gnb_ssb_idx);
if (format1 != 0xff) {
switch(format0) { // dual PRACH format
......@@ -1073,19 +1056,17 @@ void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t s
case 0xc0:
prach_config_pdu->prach_format = 9;
break;
case 0xc2:
prach_config_pdu->prach_format = 10;
break;
default:
AssertFatal(1 == 0, "Invalid PRACH format");
}
}
}
} // if format1
} else if (mac->ra_state == RA_SUCCEEDED){
mac->generate_nr_prach = 2;
}
} // if-else is_nr_prach_slot
mac->scheduled_response.ul_config = ul_config;
}
} // if is_nr_UL_slot
}
////////////////////////////////////////////////////////////////////////////
......
......@@ -125,7 +125,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
uint16_t band;
int32_t offset;
get_band((cfg->carrier_config.dl_frequency.value)*1000,
get_band((uint64_t)(cfg->carrier_config.dl_frequency.value)*1000,
&band,
&offset,
&frame_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment