Commit bcd8ad26 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch...

Merge remote-tracking branch 'origin/fix_building_rach_occasions_for_multiple_bwps' into integration_2024_w02
parents 31cc7a07 3bb6457f
...@@ -1923,7 +1923,7 @@ static void configure_BWPs(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd) ...@@ -1923,7 +1923,7 @@ static void configure_BWPs(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd)
} }
if (scd->uplinkConfig->firstActiveUplinkBWP_Id) { if (scd->uplinkConfig->firstActiveUplinkBWP_Id) {
mac->current_UL_BWP = get_ul_bwp_structure(mac, *scd->uplinkConfig->firstActiveUplinkBWP_Id, false); mac->current_UL_BWP = get_ul_bwp_structure(mac, *scd->uplinkConfig->firstActiveUplinkBWP_Id, false);
AssertFatal(mac->current_UL_BWP, "Couldn't find DL-BWP %ld\n", *scd->uplinkConfig->firstActiveUplinkBWP_Id); AssertFatal(mac->current_UL_BWP, "Couldn't find UL-BWP %ld\n", *scd->uplinkConfig->firstActiveUplinkBWP_Id);
} }
} }
} }
...@@ -1957,7 +1957,9 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, ...@@ -1957,7 +1957,9 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
} }
// Setup the SSB to Rach Occasions mapping according to the config // Setup the SSB to Rach Occasions mapping according to the config
build_ssb_to_ro_map(mac); // Only if RACH is configured for current BWP
if (mac->current_UL_BWP->rach_ConfigCommon)
build_ssb_to_ro_map(mac);
if (!mac->dl_config_request || !mac->ul_config_request) if (!mac->dl_config_request || !mac->ul_config_request)
ue_init_config_request(mac, mac->current_DL_BWP->scs); ue_init_config_request(mac, mac->current_DL_BWP->scs);
......
...@@ -69,8 +69,8 @@ ...@@ -69,8 +69,8 @@
// ========== // ==========
#define NB_NR_UE_MAC_INST 1 #define NB_NR_UE_MAC_INST 1
#define MAX_NUM_BWP_UE 4 #define MAX_NUM_BWP_UE 5
#define NUM_SLOT_FRAME 10 #define NUM_SLOT_FRAME 10
/*!\brief value for indicating BSR Timer is not running */ /*!\brief value for indicating BSR Timer is not running */
#define NR_MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) #define NR_MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF)
...@@ -461,12 +461,13 @@ typedef struct { ...@@ -461,12 +461,13 @@ typedef struct {
NR_MIB_t *mib; NR_MIB_t *mib;
struct NR_SI_SchedulingInfo *si_SchedulingInfo; struct NR_SI_SchedulingInfo *si_SchedulingInfo;
int si_window_start; int si_window_start;
ssb_list_info_t ssb_list; ssb_list_info_t ssb_list[MAX_NUM_BWP_UE];
prach_association_pattern_t prach_assoc_pattern[MAX_NUM_BWP_UE];
NR_UE_ServingCell_Info_t sc_info; NR_UE_ServingCell_Info_t sc_info;
A_SEQUENCE_OF(NR_UE_DL_BWP_t) dl_BWPs; A_SEQUENCE_OF(NR_UE_DL_BWP_t) dl_BWPs;
A_SEQUENCE_OF(NR_UE_UL_BWP_t) ul_BWPs; A_SEQUENCE_OF(NR_UE_UL_BWP_t) ul_BWPs;
NR_BWP_PDCCH_t config_BWP_PDCCH[5]; NR_BWP_PDCCH_t config_BWP_PDCCH[MAX_NUM_BWP_UE];
NR_UE_DL_BWP_t *current_DL_BWP; NR_UE_DL_BWP_t *current_DL_BWP;
NR_UE_UL_BWP_t *current_UL_BWP; NR_UE_UL_BWP_t *current_UL_BWP;
......
...@@ -74,6 +74,13 @@ void nr_ue_init_mac(module_id_t module_idP) ...@@ -74,6 +74,13 @@ void nr_ue_init_mac(module_id_t module_idP)
mac->servCellIndex = 0; mac->servCellIndex = 0;
mac->harq_ACK_SpatialBundlingPUCCH = false; mac->harq_ACK_SpatialBundlingPUCCH = false;
mac->harq_ACK_SpatialBundlingPUSCH = false; mac->harq_ACK_SpatialBundlingPUSCH = false;
memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements));
memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment));
for (int i = 0; i < MAX_NUM_BWP_UE; i++) {
memset(&mac->ssb_list[i], 0, sizeof(mac->ssb_list[i]));
memset(&mac->prach_assoc_pattern[i], 0, sizeof(mac->prach_assoc_pattern[i]));
}
} }
void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac)
...@@ -103,9 +110,6 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) ...@@ -103,9 +110,6 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac)
for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++)
mac->UL_ndi[k] = -1; // initialize to invalid value mac->UL_ndi[k] = -1; // initialize to invalid value
} }
memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements));
memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment));
} }
NR_UE_MAC_INST_t *nr_l2_init_ue() NR_UE_MAC_INST_t *nr_l2_init_ue()
......
...@@ -410,6 +410,7 @@ bool monitior_dci_for_other_SI(NR_UE_MAC_INST_t *mac, ...@@ -410,6 +410,7 @@ bool monitior_dci_for_other_SI(NR_UE_MAC_INST_t *mac,
return false; return false;
const int si_window_slots = 5 << si_SchedulingInfo->si_WindowLength; const int si_window_slots = 5 << si_SchedulingInfo->si_WindowLength;
const int abs_slot = frame * slots_per_frame + slot; const int abs_slot = frame * slots_per_frame + slot;
const int bwp_id = mac->current_DL_BWP->bwp_id;
for (int n = 0; n < si_SchedulingInfo->schedulingInfoList.list.count; n++) { for (int n = 0; n < si_SchedulingInfo->schedulingInfoList.list.count; n++) {
struct NR_SchedulingInfo *sched_Info = si_SchedulingInfo->schedulingInfoList.list.array[n]; struct NR_SchedulingInfo *sched_Info = si_SchedulingInfo->schedulingInfoList.list.array[n];
if(mac->si_window_start == -1) { if(mac->si_window_start == -1) {
...@@ -434,10 +435,10 @@ bool monitior_dci_for_other_SI(NR_UE_MAC_INST_t *mac, ...@@ -434,10 +435,10 @@ bool monitior_dci_for_other_SI(NR_UE_MAC_INST_t *mac,
get_monitoring_period_offset(ss, &period, &offset); get_monitoring_period_offset(ss, &period, &offset);
for (int i = 0; i < duration; i++) { for (int i = 0; i < duration; i++) {
if (((frame * slots_per_frame + slot - offset - i) % period) == 0) { if (((frame * slots_per_frame + slot - offset - i) % period) == 0) {
int N = mac->ssb_list.nb_tx_ssb; int N = mac->ssb_list[bwp_id].nb_tx_ssb;
int K = 0; // k_th transmitted SSB int K = 0; // k_th transmitted SSB
for (int i = 0; i < mac->mib_ssb; i++) { for (int i = 0; i < mac->mib_ssb; i++) {
if(mac->ssb_list.tx_ssb[i].transmitted) if(mac->ssb_list[bwp_id].tx_ssb[i].transmitted)
K++; K++;
} }
// numbering current frame and slot in terms of monitoring occasions in window // numbering current frame and slot in terms of monitoring occasions in window
......
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
//#define SRS_DEBUG //#define SRS_DEBUG
static prach_association_pattern_t prach_assoc_pattern;
static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t slotP); static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t slotP);
void fill_ul_config(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx, uint8_t pdu_type) void fill_ul_config(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx, uint8_t pdu_type)
...@@ -1494,8 +1493,8 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t curren ...@@ -1494,8 +1493,8 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t curren
} }
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config // 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_UE_MAC_INST_t *mac) { static void build_ro_list(NR_UE_MAC_INST_t *mac)
{
int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers 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 int y2; // PRACH Configuration Index table additional variable used to compute the valid frame numbers
uint8_t slot_shift_for_map; uint8_t slot_shift_for_map;
...@@ -1506,7 +1505,6 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) { ...@@ -1506,7 +1505,6 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) {
uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols 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 N_dur; // Duration of a PRACH occasion (nb of symbols)
uint8_t frame; // Maximum is NB_FRAMES_IN_MAX_ASSOCIATION_PATTERN_PERIOD 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; uint16_t format = 0xffff;
uint8_t format2 = 0xff; uint8_t format2 = 0xff;
int nb_fdm; int nb_fdm;
...@@ -1514,9 +1512,7 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) { ...@@ -1514,9 +1512,7 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) {
uint8_t config_index; uint8_t config_index;
int msg1_FDM; int msg1_FDM;
uint8_t prach_conf_period_idx;
uint8_t nb_of_frames_per_prach_conf_period; uint8_t nb_of_frames_per_prach_conf_period;
uint8_t prach_conf_period_frame_idx;
NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
...@@ -1597,71 +1593,72 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) { ...@@ -1597,71 +1593,72 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) {
even_slot_invalid = false; even_slot_invalid = false;
} // FR2 / FR1 } // FR2 / FR1
prach_assoc_pattern.nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x; const int bwp_id = mac->current_UL_BWP->bwp_id;
prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
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; nb_of_frames_per_prach_conf_period = x;
LOG_D(NR_MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern.nb_of_prach_conf_period_in_max_period); LOG_D(NR_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 // 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 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++) { for (int period_idx = 0; period_idx < prach_assoc_pattern->nb_of_prach_conf_period_in_max_period; period_idx++) {
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion = 0; prach_conf_period_t *prach_conf_period_list = &prach_assoc_pattern->prach_conf_period_list[period_idx];
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_frame = nb_of_frames_per_prach_conf_period; prach_conf_period_list->nb_of_prach_occasion = 0;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_slot = nr_slots_per_frame[mu]; prach_conf_period_list->nb_of_frame = nb_of_frames_per_prach_conf_period;
prach_conf_period_list->nb_of_slot = nr_slots_per_frame[mu];
LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", prach_conf_period_idx); LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", period_idx);
// For every frames in a PRACH configuration period // 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++) { for (int frame_idx = 0; frame_idx < nb_of_frames_per_prach_conf_period; frame_idx++) {
frame = (prach_conf_period_idx * nb_of_frames_per_prach_conf_period) + prach_conf_period_frame_idx; frame = (period_idx * nb_of_frames_per_prach_conf_period) + frame_idx;
LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", prach_conf_period_frame_idx, frame); LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", frame_idx, frame);
// Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y) // Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
if ( (frame%x)==y || (frame%x)==y2 ) { if ((frame%x)==y || (frame%x)==y2) {
// For every slot in a frame // For every slot in a frame
// ------------------------- // -------------------------
for (slot=0; slot<nr_slots_per_frame[mu]; slot++) { for (int slot = 0; slot < nr_slots_per_frame[mu]; slot++) {
// Is it a valid slot? // Is it a valid slot?
map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
if ( (s_map>>map_shift)&0x01 ) { if ((s_map>>map_shift) & 0x01) {
// Valid slot // Valid slot
// Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also // Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
if ( even_slot_invalid && (slot%2 == 0) ) if (even_slot_invalid && (slot%2 == 0))
continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
// We're good: valid frame and valid slot // We're good: valid frame and valid slot
// Compute all the PRACH occasions in the slot // Compute all the PRACH occasions in the slot
uint8_t n_prach_occ_in_time; prach_occasion_slot_t *slot_map = &prach_conf_period_list->prach_occasion_slot_map[frame_idx][slot];
uint8_t n_prach_occ_in_freq; slot_map->nb_of_prach_occasion_in_time = N_t_slot;
slot_map->nb_of_prach_occasion_in_freq = nb_fdm;
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; for (int n_prach_occ_in_time = 0; n_prach_occ_in_time < N_t_slot; n_prach_occ_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 = 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; uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
LOG_D(NR_MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time); LOG_D(NR_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++) { for (int 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_info_t *prach_occasion_p = &slot_map->prach_occasion[n_prach_occ_in_time][n_prach_occ_in_freq];
prach_occasion_p->start_symbol = start_symbol; prach_occasion_p->start_symbol = start_symbol;
prach_occasion_p->fdm = n_prach_occ_in_freq; prach_occasion_p->fdm = n_prach_occ_in_freq;
prach_occasion_p->frame = frame; prach_occasion_p->frame = frame;
prach_occasion_p->slot = slot; prach_occasion_p->slot = slot;
prach_occasion_p->format = format; prach_occasion_p->format = format;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion++; prach_assoc_pattern->prach_conf_period_list[period_idx].nb_of_prach_occasion++;
LOG_D(NR_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", LOG_D(NR_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, frame, slot, start_symbol, n_prach_occ_in_time, n_prach_occ_in_freq, prach_conf_period_list->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, slot_map->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); slot_map->nb_of_prach_occasion_in_freq);
} // For every freq in the slot } // For every freq in the slot
} // For every time occasions in the slot } // For every time occasions in the slot
} // Valid slot? } // Valid slot?
...@@ -1672,11 +1669,11 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) { ...@@ -1672,11 +1669,11 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) {
} }
// Build the list of all the valid/transmitted SSBs according to the config // Build the list of all the valid/transmitted SSBs according to the config
static void build_ssb_list(NR_UE_MAC_INST_t *mac) { static void build_ssb_list(NR_UE_MAC_INST_t *mac)
{
// Create the list of transmitted SSBs // Create the list of transmitted SSBs
// =================================== const int bwp_id = mac->current_UL_BWP->bwp_id;
ssb_list_info_t *ssb_list = &mac->ssb_list; ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
ssb_list->nb_tx_ssb = 0; ssb_list->nb_tx_ssb = 0;
...@@ -1748,6 +1745,9 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1748,6 +1745,9 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
} }
LOG_D(NR_MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro); LOG_D(NR_MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro);
const int bwp_id = mac->current_UL_BWP->bwp_id;
ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
// Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period // Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
// ============================================================================================================== // ==============================================================================================================
// WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same number of PRACH occasions // WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same number of PRACH occasions
...@@ -1755,56 +1755,56 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1755,56 +1755,56 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
// There is only one possible association period which can contain up to 16 PRACH configuration periods // There is only one possible association period which can contain up to 16 PRACH configuration periods
LOG_D(NR_MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n"); LOG_D(NR_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) { if (true == multiple_ssb_per_ro) {
required_nb_of_prach_occasion = ((mac->ssb_list.nb_tx_ssb-1) + ssb_rach_ratio) / ssb_rach_ratio; required_nb_of_prach_occasion = ((ssb_list->nb_tx_ssb - 1) + ssb_rach_ratio) / ssb_rach_ratio;
} }
else { else {
required_nb_of_prach_occasion = mac->ssb_list.nb_tx_ssb * ssb_rach_ratio; required_nb_of_prach_occasion = ssb_list->nb_tx_ssb * ssb_rach_ratio;
} }
AssertFatal(prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion>0, prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
"prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion shouldn't be 0 (ssb_list.nb_tx_ssb %d, ssb_rach_ratio %d\n", prach_association_period_t *prach_association_period_list = &prach_assoc_pattern->prach_association_period_list[0];
mac->ssb_list.nb_tx_ssb,ssb_rach_ratio); AssertFatal(prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion > 0,
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 shouldn't be 0 (nb_tx_ssb %d, ssb_rach_ratio %d)\n",
prach_assoc_pattern.prach_conf_period_list[0].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) { if (required_nb_of_prach_conf_period == 1) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 1; prach_association_period_list->nb_of_prach_conf_period = 1;
} }
else if (required_nb_of_prach_conf_period == 2) { else if (required_nb_of_prach_conf_period == 2) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 2; prach_association_period_list->nb_of_prach_conf_period = 2;
} }
else if (required_nb_of_prach_conf_period <= 4) { else if (required_nb_of_prach_conf_period <= 4) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 4; prach_association_period_list->nb_of_prach_conf_period = 4;
} }
else if (required_nb_of_prach_conf_period <= 8) { else if (required_nb_of_prach_conf_period <= 8) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 8; prach_association_period_list->nb_of_prach_conf_period = 8;
} }
else if (required_nb_of_prach_conf_period <= 16) { else if (required_nb_of_prach_conf_period <= 16) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 16; prach_association_period_list->nb_of_prach_conf_period = 16;
} }
else { else {
AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period); 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: only one possible association period prach_assoc_pattern->nb_of_assoc_period = 1; // WIP: 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_association_period_list->nb_of_frame = prach_association_period_list->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; prach_assoc_pattern->nb_of_frame = prach_association_period_list->nb_of_frame;
LOG_D(NR_MAC,"Assoc period %d, Nb of frames in assoc period %d\n", LOG_D(NR_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_association_period_list->nb_of_prach_conf_period,
prach_assoc_pattern.prach_association_period_list[0].nb_of_frame); prach_association_period_list->nb_of_frame);
// Proceed to the SSB to RO mapping // 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 ssb_idx = 0;
uint8_t prach_configuration_period_idx; // PRACH Configuration period index within the association pattern uint8_t prach_configuration_period_idx; // PRACH Configuration period index within the association pattern
prach_conf_period_t *prach_conf_period_p; prach_conf_period_t *prach_conf_period_p;
// Map all the association periods within the association pattern period // Map all the association periods within the association pattern period
LOG_D(NR_MAC,"Proceed to the SSB to RO mapping\n"); LOG_D(NR_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++) { for (int 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 frame=0;
uint8_t slot=0; uint8_t slot=0;
uint8_t ro_in_time=0; uint8_t ro_in_time=0;
...@@ -1826,10 +1826,11 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1826,10 +1826,11 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
ssb_idx = 0; ssb_idx = 0;
// Go through the list of PRACH config periods within this association period // 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++) { prach_association_period_list = &prach_assoc_pattern->prach_association_period_list[association_period_idx];
for (int n_prach_conf=0; n_prach_conf < prach_association_period_list->nb_of_prach_conf_period; n_prach_conf++, prach_configuration_period_idx++) {
// Build the association period with its association PRACH Configuration indexes // 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_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; prach_association_period_list->prach_conf_period_list[n_prach_conf] = prach_conf_period_p;
// Go through all the ROs within the PRACH config period // Go through all the ROs within the PRACH config period
for (frame=0; frame<prach_conf_period_p->nb_of_frame; frame++) { for (frame=0; frame<prach_conf_period_p->nb_of_frame; frame++) {
...@@ -1843,20 +1844,20 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1843,20 +1844,20 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule // 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++) { for (; ssb_idx<MAX_NB_SSB; ssb_idx++) {
// Map only the transmitted ssb_idx // Map only the transmitted ssb_idx
if (true == mac->ssb_list.tx_ssb[ssb_idx].transmitted) { if (true == ssb_list->tx_ssb[ssb_idx].transmitted) {
ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx; ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
ro_p->nb_mapped_ssb++; ro_p->nb_mapped_ssb++;
mac->ssb_list.tx_ssb[ssb_idx].mapped_ro[mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p; ssb_list->tx_ssb[ssb_idx].mapped_ro[ssb_list->tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++; ssb_list->tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > mac->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", "Too many mapped ROs (%d) to a single SSB\n",
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro); ssb_list->tx_ssb[ssb_idx].nb_mapped_ro);
LOG_D(NR_MAC, "Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", LOG_D(NR_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, 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); prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(NR_MAC, "Nb mapped ROs for this ssb idx: in the association period only %u\n", LOG_D(NR_MAC, "Nb mapped ROs for this ssb idx: in the association period only %u\n",
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro); 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 all the required SSBs are mapped to this RO, exit the loop of SSBs
if (ro_p->nb_mapped_ssb == ssb_rach_ratio) { if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
...@@ -1897,24 +1898,22 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1897,24 +1898,22 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
// -------------------- // --------------------
// -------------------- // --------------------
n_prach_conf = 0;
// Go through the list of transmitted SSBs // Go through the list of transmitted SSBs
for (ssb_idx=0; ssb_idx<MAX_NB_SSB; ssb_idx++) { 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 uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index
LOG_D(NR_MAC,"Checking ssb_idx %d => %d\n", LOG_D(NR_MAC,"Checking ssb_idx %d => %d\n",
ssb_idx, mac->ssb_list.tx_ssb[ssb_idx].transmitted); ssb_idx, ssb_list->tx_ssb[ssb_idx].transmitted);
// Map only the transmitted ssb_idx // Map only the transmitted ssb_idx
if (true == mac->ssb_list.tx_ssb[ssb_idx].transmitted) { if (true == ssb_list->tx_ssb[ssb_idx].transmitted) {
// Map all the required ROs to this SSB // Map all the required ROs to this SSB
// Go through the list of PRACH config periods within this association period // 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++) { for (int 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 // 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_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; 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 (; frame<prach_conf_period_p->nb_of_frame; frame++) {
for (; slot<prach_conf_period_p->nb_of_slot; slot++) { for (; slot<prach_conf_period_p->nb_of_slot; slot++) {
...@@ -1924,18 +1923,18 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1924,18 +1923,18 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
ro_p->mapped_ssb_idx[0] = ssb_idx; ro_p->mapped_ssb_idx[0] = ssb_idx;
ro_p->nb_mapped_ssb = 1; ro_p->nb_mapped_ssb = 1;
mac->ssb_list.tx_ssb[ssb_idx].mapped_ro[mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p; ssb_list->tx_ssb[ssb_idx].mapped_ro[ssb_list->tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++; ssb_list->tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > mac->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", "Too many mapped ROs (%d) to a single SSB\n",
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro); ssb_list->tx_ssb[ssb_idx].nb_mapped_ro);
nb_mapped_ro_in_association_period++; nb_mapped_ro_in_association_period++;
LOG_D(NR_MAC,"Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", LOG_D(NR_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, 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); prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(NR_MAC, "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n", LOG_D(NR_MAC, "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n",
mac->ssb_list.tx_ssb[ssb_idx].nb_mapped_ro, nb_mapped_ro_in_association_period); 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 // 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: // WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an association period:
...@@ -1982,7 +1981,8 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) ...@@ -1982,7 +1981,8 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
} }
// Returns a RACH occasion if any matches the SSB idx, the frame and the slot // Returns a RACH occasion if any matches the SSB idx, the frame and the slot
static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx, static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_assoc_pattern,
uint8_t ssb_idx,
int frame, int frame,
int slot, int slot,
ssb_list_info_t *ssb_list, ssb_list_info_t *ssb_list,
...@@ -2001,14 +2001,14 @@ static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx, ...@@ -2001,14 +2001,14 @@ static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx,
ssb_info_p = &ssb_list->tx_ssb[ssb_idx]; ssb_info_p = &ssb_list->tx_ssb[ssb_idx];
LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro); LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro);
for (uint8_t n_mapped_ro=0; n_mapped_ro<ssb_info_p->nb_mapped_ro; n_mapped_ro++) { for (uint8_t n_mapped_ro=0; n_mapped_ro<ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
LOG_D(NR_MAC,"%d.%d: mapped_ro[%d]->frame.slot %d.%d, prach_assoc_pattern.nb_of_frame %d\n", LOG_D(NR_MAC,"%d.%d: mapped_ro[%d]->frame.slot %d.%d, prach_assoc_pattern->nb_of_frame %d\n",
frame,slot,n_mapped_ro,ssb_info_p->mapped_ro[n_mapped_ro]->frame,ssb_info_p->mapped_ro[n_mapped_ro]->slot,prach_assoc_pattern.nb_of_frame); frame,slot,n_mapped_ro,ssb_info_p->mapped_ro[n_mapped_ro]->frame,ssb_info_p->mapped_ro[n_mapped_ro]->slot,prach_assoc_pattern->nb_of_frame);
if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && 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))) { (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 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; 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]; 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];
} }
} }
...@@ -2064,8 +2064,9 @@ static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx, ...@@ -2064,8 +2064,9 @@ static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx,
void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac) void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac)
{ {
// Clear all the lists and maps // Clear all the lists and maps
memset(&prach_assoc_pattern, 0, sizeof(prach_association_pattern_t)); const int bwp_id = mac->current_UL_BWP->bwp_id;
memset(&mac->ssb_list, 0, sizeof(ssb_list_info_t)); memset(&mac->ssb_list[bwp_id], 0, sizeof(ssb_list_info_t));
memset(&mac->prach_assoc_pattern[bwp_id], 0, sizeof(prach_association_pattern_t));
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config // Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
LOG_D(NR_MAC,"Build RO list\n"); LOG_D(NR_MAC,"Build RO list\n");
...@@ -2463,7 +2464,7 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr ...@@ -2463,7 +2464,7 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
const int bwp_id = mac->current_UL_BWP->bwp_id;
NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon; NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
if (is_nr_UL_slot(tdd_config, slotP, mac->frame_type)) { if (is_nr_UL_slot(tdd_config, slotP, mac->frame_type)) {
...@@ -2474,10 +2475,11 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr ...@@ -2474,10 +2475,11 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
// Get any valid PRACH occasion in the current slot for the selected SSB index // Get any valid PRACH occasion in the current slot for the selected SSB index
prach_occasion_info_t *prach_occasion_info_p; prach_occasion_info_t *prach_occasion_info_p;
int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(selected_gnb_ssb_idx, int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(&mac->prach_assoc_pattern[bwp_id],
selected_gnb_ssb_idx,
(int)frameP, (int)frameP,
(int)slotP, (int)slotP,
&mac->ssb_list, &mac->ssb_list[bwp_id],
&prach_occasion_info_p); &prach_occasion_info_p);
if (is_nr_prach_slot) { if (is_nr_prach_slot) {
......
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