Commit bab13b80 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/dynamic-pdcch' into integration_2025_w07 (!3055)

Dynamic PDCCH aggregation level

The aggregation level search order for PDCCH candidates is modified:

- the search starts from desired_agg_level_index, which is a value from
  0 to 4 proportial to pdcch_cl_adjust.
- pdcch_cl_adjust is a value between 0 and 1 that indicates PDCCH
  channel quality by averaging HARQ DTX rate. A value of 0 means perfect
  channel, a value o 1 means impaired channel.

Also added configuration option for number of PDCCH candidates per
aggregation level.
parents ff58b5e1 095b7919
......@@ -150,6 +150,15 @@ typedef enum ip_traffic_type_e {
TRAFFIC_PC5S_SESSION_INIT = 10
} ip_traffic_type_t;
typedef enum {
PDCCH_AGG_LEVEL1 = 0,
PDCCH_AGG_LEVEL2,
PDCCH_AGG_LEVEL4,
PDCCH_AGG_LEVEL8,
PDCCH_AGG_LEVEL16,
NUM_PDCCH_AGG_LEVELS
} Pdcch_Aggregation_Level_t;
typedef struct net_ip_address_s {
unsigned ipv4: 1;
unsigned ipv6: 1;
......
......@@ -551,6 +551,18 @@ void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) {
*n_rb = 6*count;
}
// According to 38.211 7.3.2.2
int get_coreset_num_cces(uint8_t *FreqDomainResource, int duration)
{
int num_rbs;
int rb_offset;
get_coreset_rballoc(FreqDomainResource, &num_rbs, &rb_offset);
int total_resource_element_groups = num_rbs * duration;
int reg_per_cce = 6;
int total_cces = total_resource_element_groups / reg_per_cce;
return total_cces;
}
int get_nb_periods_per_frame(uint8_t tdd_period)
{
......
......@@ -245,6 +245,7 @@ uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, ui
int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, const int N_regs);
int get_SLIV(uint8_t S, uint8_t L);
void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset);
int get_coreset_num_cces(uint8_t *FreqDomainResource, int duration);
int get_nr_table_idx(int nr_bandP, uint8_t scs_index);
int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index);
frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index);
......
......@@ -38,6 +38,33 @@ The actual scheduler implementation can be found in functions `pf_dl()` and
[`gNB_scheduler_ulsch.c`](../../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c)
(for UL), respectively.
## PDDCH aggregation level
PDCCH aggregation level is selected using closed loop controller, where DL HARQ
feedback is the controller feedback signal. It is used to increment `pdcch_cl_adjust`
variable if no feedback is detected and decrement the variable when feedback is detected.
`pdcch_cl_adjust` is later mapped to the PDCCH aggregation level range.
The value of `pdcch_cl_adjust` is clamped to range <0,1>, the increment value is 0.05 while
the decrement value is 0.01. These values are selected to ensure PDCCH success rate is high.
See Examples below for futher explaination.
The possible values of aggregation level on UE SS can be configured via `uess_agg_levels` configuration
option. By default the gNB uses only aggregation level 2 which translates to `uess_agg_levels` set to
`[0, 1, 0, 0, 0]`. For example, to enable aggregation level 2 and 4 set `uess_agg_levels` to `[0, 1, 1, 0, 0]`.
### Examples:
#### Example 1:
Say we have 90% PDCCH success rate at aggregation level 1, `pdcch_cl_adjust` will stay at 0
for most of the time. 2 consecutive PDCCH failures will not result in increasing the aggregation
level (because (0.05 + 0.05) * 4 = 0.4 which is closer to 0 than to 1). If PDCCH fails 3 times
in a row the aggregation level will change to 2 and hopefully back to 1 once more PDDCH successes
happen.
### Example 2
Say we have 0% PDCCH success rate (radio link failure scenario) but `pdcch_cl_adjust` is 0 indicating
perfect PDCCH channel. it would take ~18 PDCCH failures to reach maximum aggregation level.
# Periodic output and interpretation
The scheduler periodically outputs statistics that can help you judge the radio
......
......@@ -99,7 +99,7 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB,
if (dci_pdu->RNTI != 0xFFFF)
LOG_D(NR_PHY_DCI,
"DL_DCI : rb_offset %d, nb_rb %d, DMRS length per symbol %d\t DCI encoded length %d (precoder_granularity %d, "
"reg_mapping %d), Scrambling_Id %d, ScramblingRNTI %x, PayloadSizeBits %d\n",
"reg_mapping %d), Scrambling_Id %d, ScramblingRNTI %x, PayloadSizeBits %d AggregationLevel %d\n",
rb_offset,
n_rb,
dmrs_length,
......@@ -108,7 +108,8 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB,
pdcch_pdu_rel15->CceRegMappingType,
dci_pdu->ScramblingId,
dci_pdu->ScramblingRNTI,
dci_pdu->PayloadSizeBits);
dci_pdu->PayloadSizeBits,
dci_pdu->AggregationLevel);
dmrs_length += rb_offset*6; // To accommodate more DMRS symbols in case of rb offset
/// DMRS QPSK modulation
......
......@@ -671,7 +671,8 @@ printf("%d\n", slot);
.timer_config.n310 = 10,
.timer_config.t311 = 3000,
.timer_config.n311 = 1,
.timer_config.t319 = 400};
.timer_config.t319 = 400,
.num_agg_level_candidates = {0, 0, 1, 1, 0}};
RC.nb_nr_macrlc_inst = 1;
RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int));
......
......@@ -1129,11 +1129,25 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf
AssertFatal(pcc != NULL && pcc->commonSearchSpaceList == NULL, "memory leak\n");
pcc->commonSearchSpaceList = calloc_or_fail(1, sizeof(*pcc->commonSearchSpaceList));
NR_SearchSpace_t *ss1 = rrc_searchspace_config(true, 1, 0);
// TODO: Make CSS aggregation levels configurable
int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
css_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
if (get_softmodem_params()->usim_test) {
css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n1;
} else {
css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
}
css_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
NR_SearchSpace_t *ss1 = rrc_searchspace_config(true, 1, 0, css_num_agg_level_candidates);
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss1);
NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, 2, 0);
NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, 2, 0, css_num_agg_level_candidates);
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss2);
NR_SearchSpace_t *ss3 = rrc_searchspace_config(true, 3, 0);
NR_SearchSpace_t *ss3 = rrc_searchspace_config(true, 3, 0, css_num_agg_level_candidates);
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss3);
asn1cCallocOne(pcc->searchSpaceSIB1, 0);
......@@ -1501,6 +1515,34 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
}
}
// Construct default aggragation level list or read from config
int uess_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
if (get_softmodem_params()->usim_test) {
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n1;
} else {
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2;
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0;
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
}
uess_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
int* agg_level_list = uess_num_agg_level_candidates;
int num_agg_levels = 5;
if (GNBParamList.paramarray[0][GNB_UESS_AGG_LEVEL_LIST_IDX].numelt > 0) {
agg_level_list = GNBParamList.paramarray[0][GNB_UESS_AGG_LEVEL_LIST_IDX].iptr;
num_agg_levels = GNBParamList.paramarray[0][GNB_UESS_AGG_LEVEL_LIST_IDX].numelt;
}
memcpy(config.num_agg_level_candidates, agg_level_list, sizeof(int) * num_agg_levels);
LOG_I(NR_MAC,
"Candidates per PDCCH aggregation level on UESS: L1: %d, L2: %d, L4: %d, L8: %d, L16: %d\n",
config.num_agg_level_candidates[PDCCH_AGG_LEVEL1],
config.num_agg_level_candidates[PDCCH_AGG_LEVEL2],
config.num_agg_level_candidates[PDCCH_AGG_LEVEL4],
config.num_agg_level_candidates[PDCCH_AGG_LEVEL8],
config.num_agg_level_candidates[PDCCH_AGG_LEVEL16]);
NR_ServingCellConfigCommon_t *scc = get_scc_config(cfg, config.minRXTXTIME);
//xer_fprint(stdout, &asn_DEF_NR_ServingCellConfigCommon, scc);
NR_ServingCellConfig_t *scd = get_scd_config(cfg);
......
......@@ -138,6 +138,7 @@ typedef enum {
#define GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES "num_dlharq"
#define GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES "num_ulharq"
#define GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST "beam_weights"
#define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels"
#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n"
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
......@@ -148,6 +149,7 @@ typedef enum {
#define GNB_CONFIG_HLP_GNB_CU_UP_ID "defines the gNB-CU-UP ID (only applicable for CU-UP)"
#define GNB_CONFIG_HLP_NUM_DL_HARQ "Set Num DL harq processes. Valid values 2,4,6,8,10,12,16,32. Default 16"
#define GNB_CONFIG_HLP_NUM_UL_HARQ "Set Num UL harq processes. Valid values 16,32. Default 16"
#define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1"
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
/* cell configuration parameters */
......@@ -191,6 +193,8 @@ typedef enum {
{GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_DL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_UL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST, \
GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
}
// clang-format on
......@@ -231,6 +235,7 @@ typedef enum {
#define GNB_NUM_DL_HARQ_IDX 33
#define GNB_NUM_UL_HARQ_IDX 34
#define GNB_BEAMWEIGHTS_IDX 35
#define GNB_UESS_AGG_LEVEL_LIST_IDX 36
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
#define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32}
......@@ -273,6 +278,7 @@ typedef enum {
{ .s1 = { config_check_intval, NUM_DL_HARQ_OKVALUES,8 } }, \
{ .s1 = { config_check_intval, NUM_UL_HARQ_OKVALUES,2 } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
......
......@@ -874,7 +874,8 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP,
ss,
coreset,
&ra->sched_pdcch,
true);
true,
0);
if (CCEIndex < 0) {
LOG_E(NR_MAC, "UE %04x cannot find free CCE!\n", ra->rnti);
return;
......@@ -1484,7 +1485,7 @@ static void nr_generate_Msg2(module_id_t module_idP,
}
uint8_t aggregation_level;
int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &ra->sched_pdcch, true);
int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &ra->sched_pdcch, true, 0);
if (CCEIndex < 0) {
LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", ra->rnti, frameP, slotP);
......@@ -2006,7 +2007,8 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
ss,
coreset,
&ra->sched_pdcch,
true);
true,
0);
if (CCEIndex < 0) {
LOG_E(NR_MAC, "Cannot find free CCE for RA RNTI 0x%04x!\n", ra->rnti);
......
......@@ -553,7 +553,8 @@ static bool allocate_dl_retransmission(module_id_t module_id,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
sched_ctrl->pdcch_cl_adjust);
if (CCEIndex<0) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n", UE->rnti, frame, slot);
return false;
......@@ -817,7 +818,8 @@ static void pf_dl(module_id_t module_id,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
sched_ctrl->pdcch_cl_adjust);
if (CCEIndex < 0) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI\n", rnti, frame, slot);
reset_beam_status(&mac->beam_info,
......
......@@ -148,7 +148,8 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t s
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
0);
AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti);
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
......@@ -312,7 +313,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
0);
if (CCEIndex < 0) {
LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
return false;
......
......@@ -119,6 +119,9 @@ static const uint16_t cqi_table3[16][2] = {{0, 0},
{6, 6660},
{6, 7720}};
static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS],
float pdcch_cl_adjust);
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl,
const nr_dci_format_t dci_format) {
......@@ -550,15 +553,18 @@ int get_cce_index(const gNB_MAC_INST *nrmac,
const NR_SearchSpace_t *ss,
const NR_ControlResourceSet_t *coreset,
NR_sched_pdcch_t *sched_pdcch,
bool is_common)
bool is_common,
float pdcch_cl_adjust)
{
const uint32_t Y = is_common ? 0 : get_Y(ss, slot, rnti);
uint8_t nr_of_candidates;
for (int i = 0; i < 5; i++) {
// for now taking the lowest value among the available aggregation levels
find_aggregation_candidates(aggregation_level, &nr_of_candidates, ss, 1 << i);
if(nr_of_candidates > 0)
int agg_level_search_order[NUM_PDCCH_AGG_LEVELS];
determine_aggregation_level_search_order(agg_level_search_order, pdcch_cl_adjust);
for (int i = 0; i < NUM_PDCCH_AGG_LEVELS; i++) {
find_aggregation_candidates(aggregation_level, &nr_of_candidates, ss, 1 << agg_level_search_order[i]);
if (nr_of_candidates > 0)
break;
}
int CCEIndex = find_pdcch_candidate(nrmac, CC_id, *aggregation_level, nr_of_candidates, beam_idx, sched_pdcch, coreset, Y);
......@@ -2516,6 +2522,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf
sched_ctrl->ta_update = 31;
sched_ctrl->sched_srs.frame = -1;
sched_ctrl->sched_srs.slot = -1;
sched_ctrl->pdcch_cl_adjust = 0;
// initialize LCID structure
seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t));
......@@ -3524,3 +3531,31 @@ bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rn
} while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue));
return loop < 100; // nothing found: loop count 100
}
/// @brief Orders PDCCH aggregation levels so that we first check desired aggregation level according to
/// pdcch_cl_adjust
/// @param agg_level_search_order in/out 5-element array of aggregation levels from 0 to 4
/// @param pdcch_cl_adjust value from 0 to 1 indication channel impariments (0 - good channel, 1 - bad channel)
static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], float pdcch_cl_adjust)
{
int desired_agg_level_index = round(4 * pdcch_cl_adjust);
int agg_level_search_index = 0;
for (int i = desired_agg_level_index; i < NUM_PDCCH_AGG_LEVELS; i++) {
agg_level_search_order[agg_level_search_index++] = i;
}
for (int i = desired_agg_level_index - 1; i >= 0; i--) {
agg_level_search_order[agg_level_search_index++] = i;
}
}
/// @brief Update PDCCH closed loop adjust for UE depending on detection of feedback.
/// @param sched_ctrl UE scheduling control info
/// @param feedback_not_detected Whether feedback (PUSCH or HARQ) was detected
void nr_mac_update_pdcch_closed_loop_adjust(NR_UE_sched_ctrl_t *sched_ctrl, bool feedback_not_detected)
{
if (feedback_not_detected) {
sched_ctrl->pdcch_cl_adjust = min(1, sched_ctrl->pdcch_cl_adjust + 0.05);
} else {
sched_ctrl->pdcch_cl_adjust = max(0, sched_ctrl->pdcch_cl_adjust - 0.01);
}
}
......@@ -787,6 +787,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
const int8_t pid = sched_ctrl->feedback_dl_harq.head;
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value);
nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0);
handle_dl_harq(UE, pid, harq_value == 0 && harq_confidence == 0, nrmac->dl_bler.harq_round_max);
if (!UE->Msg4_MsgB_ACKed && harq_value == 0 && harq_confidence == 0)
UE->Msg4_MsgB_ACKed = true;
......
......@@ -1742,7 +1742,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
sched_ctrl->pdcch_cl_adjust);
if (CCEIndex<0) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", UE->rnti, frame, slot);
return false;
......@@ -1926,7 +1927,8 @@ static void pf_ul(module_id_t module_id,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
sched_ctrl->pdcch_cl_adjust);
if (CCEIndex < 0) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI (BSR 0)\n", UE->rnti, frame, slot);
reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, n, beam.new_beam);
......@@ -2073,7 +2075,8 @@ static void pf_ul(module_id_t module_id,
sched_ctrl->search_space,
sched_ctrl->coreset,
&sched_ctrl->sched_pdcch,
false);
false,
sched_ctrl->pdcch_cl_adjust);
if (CCEIndex < 0) {
reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, n_dl, dci_beam.new_beam);
......
......@@ -433,7 +433,8 @@ int get_cce_index(const gNB_MAC_INST *nrmac,
const NR_SearchSpace_t *ss,
const NR_ControlResourceSet_t *coreset,
NR_sched_pdcch_t *sched_pdcch,
bool is_common);
bool is_common,
float pdcch_cl_adjust);
bool nr_find_nb_rb(uint16_t Qm,
uint16_t R,
......@@ -493,5 +494,6 @@ bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c);
bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid);
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti);
void nr_mac_update_pdcch_closed_loop_adjust(NR_UE_sched_ctrl_t *sched_ctrl, bool feedback_not_detected);
#endif /*__LAYER2_NR_MAC_PROTO_H__*/
......@@ -172,6 +172,7 @@ typedef struct nr_mac_config_t {
/// beamforming weight matrix size
int nb_bfw[2];
int32_t *bw_list;
int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
} nr_mac_config_t;
typedef struct NR_preamble_ue {
......@@ -675,6 +676,10 @@ typedef struct {
/// per-LC configuration
seq_arr_t lc_config;
// pdcch closed loop adjust for PDCCH aggregation level, range <0, 1>
// 0 - good channel, 1 - bad channel
float pdcch_cl_adjust;
} NR_UE_sched_ctrl_t;
typedef struct {
......
......@@ -72,6 +72,50 @@ static NR_BWP_t clone_generic_parameters(const NR_BWP_t *gp)
return clone;
}
/**
* @brief Verifies the aggregation level candidates
*
* This function checks the input aggregation level candidates and translates the value provided
* in the config to a valid field in RRC message.
*
* @param[in] num_cce_in_coreset number of CCE in coreset
* @param[in] in_num_agg_level_candidates input array of aggregation level candidates, interpreted as number of candidates.
* @param[in] coresetid coreset id
* @param[in] searchspaceid searchspace id
* @param[out] out_num_agg_level_candidates array of aggregation level candidates, output is a valid 3gpp field value.
*
*/
static void verify_agg_levels(int num_cce_in_coreset,
const int in_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS],
int coresetid,
int searchspaceid,
int out_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS])
{
int agg_level_to_n_cces[] = {1, 2, 4, 8, 16};
for (int i = 0; i < NUM_PDCCH_AGG_LEVELS; i++) {
// 7 is not a valid value, the mapping in 38.331 is from 0-7 mapped to 0-8 candidates and value 7 means 8 candidates instead. If
// the user wants 7 candidates round it up to 8.
int num_agg_level_candidates = in_num_agg_level_candidates[i];
if (num_agg_level_candidates == 7) {
num_agg_level_candidates = 8;
}
if (num_agg_level_candidates * agg_level_to_n_cces[i] > num_cce_in_coreset) {
int new_agg_level_candidates = num_cce_in_coreset / agg_level_to_n_cces[i];
LOG_E(NR_RRC,
"Invalid configuration: Not enough CCEs in coreset %d, searchspace %d, agg_level %d, number of requested "
"candidates = %d, number of CCES in coreset %d. Aggregation level candidates limited to %d\n",
coresetid,
searchspaceid,
agg_level_to_n_cces[i],
in_num_agg_level_candidates[i],
num_cce_in_coreset,
new_agg_level_candidates);
num_agg_level_candidates = new_agg_level_candidates;
}
out_num_agg_level_candidates[i] = min(num_agg_level_candidates, 7);
}
}
static NR_SetupRelease_RACH_ConfigCommon_t *clone_rach_configcommon(const NR_SetupRelease_RACH_ConfigCommon_t *rcc)
{
if (rcc == NULL || rcc->present == NR_SetupRelease_RACH_ConfigCommon_PR_NOTHING)
......@@ -208,9 +252,11 @@ static int get_nb_pucch2_per_slot(const NR_ServingCellConfigCommon_t *scc, int b
return nb_pucch2;
}
NR_SearchSpace_t *rrc_searchspace_config(bool is_common, int searchspaceid, int coresetid)
NR_SearchSpace_t *rrc_searchspace_config(bool is_common,
int searchspaceid,
int coresetid,
const int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS])
{
NR_SearchSpace_t *ss = calloc(1,sizeof(*ss));
ss->searchSpaceId = searchspaceid;
ss->controlResourceSetId = calloc(1,sizeof(*ss->controlResourceSetId));
......@@ -226,23 +272,12 @@ NR_SearchSpace_t *rrc_searchspace_config(bool is_common, int searchspaceid, int
ss->monitoringSymbolsWithinSlot->buf[1] = 0x0;
ss->monitoringSymbolsWithinSlot->bits_unused = 2;
ss->nrofCandidates = calloc(1,sizeof(*ss->nrofCandidates));
// TODO temporary hardcoded implementation
ss->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
if (get_softmodem_params()->usim_test) {
ss->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
ss->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
ss->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n1;
} else {
if (is_common) {
ss->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
ss->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
} else {
ss->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2;
ss->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0;
}
ss->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
}
ss->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
ss->nrofCandidates->aggregationLevel1 = num_agg_level_candidates[PDCCH_AGG_LEVEL1];
ss->nrofCandidates->aggregationLevel2 = num_agg_level_candidates[PDCCH_AGG_LEVEL2];
ss->nrofCandidates->aggregationLevel4 = num_agg_level_candidates[PDCCH_AGG_LEVEL4];
ss->nrofCandidates->aggregationLevel8 = num_agg_level_candidates[PDCCH_AGG_LEVEL8];
ss->nrofCandidates->aggregationLevel16 = num_agg_level_candidates[PDCCH_AGG_LEVEL16];
ss->searchSpaceType = calloc(1,sizeof(*ss->searchSpaceType));
if (is_common) {
ss->searchSpaceType->present = NR_SearchSpace__searchSpaceType_PR_common;
......@@ -1545,7 +1580,8 @@ static void config_downlinkBWP(NR_BWP_Downlink_t *bwp,
int dl_antenna_ports,
bool force_256qam_off,
int bwp_loop,
bool is_SA)
bool is_SA,
const int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS])
{
bwp->bwp_Common = calloc(1,sizeof(*bwp->bwp_Common));
......@@ -1577,8 +1613,12 @@ static void config_downlinkBWP(NR_BWP_Downlink_t *bwp,
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList=NULL;
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList=calloc(1,sizeof(*bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList));
NR_SearchSpace_t *ss = rrc_searchspace_config(true, 5+bwp->bwp_Id, coreset->controlResourceSetId);
asn1cSeqAdd(&bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list,ss);
int searchspaceid = 5 + bwp->bwp_Id;
int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration);
verify_agg_levels(num_cces, num_agg_level_candidates, coreset->controlResourceSetId, searchspaceid, rrc_num_agg_level_candidates);
NR_SearchSpace_t *ss = rrc_searchspace_config(true, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates);
asn1cSeqAdd(&bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list, ss);
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1=NULL;
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation=NULL;
......@@ -1613,7 +1653,11 @@ static void config_downlinkBWP(NR_BWP_Downlink_t *bwp,
NR_ControlResourceSet_t *coreset2 = get_coreset_config(bwp->bwp_Id, curr_bwp, ssb_bitmap);
asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset2);
NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, 10+bwp->bwp_Id, coreset2->controlResourceSetId);
searchspaceid = 10 + bwp->bwp_Id;
num_cces = get_coreset_num_cces(coreset2->frequencyDomainResources.buf, coreset2->duration);
verify_agg_levels(num_cces, num_agg_level_candidates, coreset->controlResourceSetId, searchspaceid, rrc_num_agg_level_candidates);
NR_SearchSpace_t *ss2 =
rrc_searchspace_config(false, searchspaceid, coreset2->controlResourceSetId, rrc_num_agg_level_candidates);
asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2);
bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToReleaseList = NULL;
......@@ -3069,7 +3113,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset);
NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, 5, coreset->controlResourceSetId);
int searchspaceid = 5;
int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration);
verify_agg_levels(num_cces,
configuration->num_agg_level_candidates,
coreset->controlResourceSetId,
searchspaceid,
rrc_num_agg_level_candidates);
NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates);
asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2);
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts);
......@@ -3113,7 +3165,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList));
for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) {
NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp));
config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true);
config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true, configuration->num_agg_level_candidates);
asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp);
}
const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id;
......@@ -3575,7 +3627,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
dl_antenna_ports,
configuration->force_256qam_off,
bwp_loop,
false);
false,
configuration->num_agg_level_candidates);
asn1cSeqAdd(&secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp);
}
secondaryCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id =
......
......@@ -55,7 +55,10 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc
NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon,
int curr_bwp);
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay);
NR_SearchSpace_t *rrc_searchspace_config(bool is_common, int searchspaceid, int coresetid);
NR_SearchSpace_t *rrc_searchspace_config(bool is_common,
int searchspaceid,
int coresetid,
const int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]);
void prepare_sim_uecap(NR_UE_NR_Capability_t *cap,
NR_ServingCellConfigCommon_t *scc,
......
......@@ -20,6 +20,7 @@ gNBs =
do_CSIRS = 1;
do_SRS = 1;
#uess_agg_levels = [0,1,2,2,1]
servingCellConfigCommon = (
{
#spCellConfigCommon
......
......@@ -19,6 +19,7 @@ gNBs:
# Physical parameters:
do_CSIRS: 1
do_SRS: 1
#uess_agg_levels: [0,1,1,1,1]
servingCellConfigCommon:
#spCellConfigCommon
- physCellId: 0
......
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