Merge remote-tracking branch 'origin/NR_TCI_states' into integration_2026_w04 (!3430)

NR gNB handling TCI state indication for beam switching

This MR implements the procedure to send in DLSCH MAC-CE for TCI state
indication to UE
- if new beam is reported via SSB RSRP, gNB allocates MAC-CE with TCI
  indication
- DLSCH is scheduled to be transmitted with priority
- a timer is started when receiving ACK according to the delay mandated
  by standard (8.10.3 of 38.133)
- at timer expiry the gNB switches beam
This commit is contained in:
Jaroslava Fiedlerova
2026-01-21 17:37:15 +01:00
committed by Robert Schmidt
9 changed files with 172 additions and 84 deletions
+2
View File
@@ -699,6 +699,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
verify_gnb_param_notset(gnbp, GNB_PDSCH_ANTENNAPORTS_XP_IDX, GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP);
verify_gnb_param_notset(gnbp, GNB_PUSCH_ANTENNAPORTS_IDX, GNB_CONFIG_STRING_PUSCHANTENNAPORTS);
verify_gnb_param_notset(gnbp, GNB_MINRXTXTIME_IDX, GNB_CONFIG_STRING_MINRXTXTIME);
verify_gnb_param_notset(gnbp, GNB_DO_TCI_IDX, GNB_CONFIG_STRING_DOTCI);
verify_gnb_param_notset(gnbp, GNB_DO_CSIRS_IDX, GNB_CONFIG_STRING_DOCSIRS);
verify_gnb_param_notset(gnbp, GNB_DO_SRS_IDX, GNB_CONFIG_STRING_DOSRS);
verify_gnb_param_notset(gnbp, GNB_FORCE256QAMOFF_IDX, GNB_CONFIG_STRING_FORCE256QAMOFF);
@@ -1435,6 +1436,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
}
config.minRXTXTIME = *GNBParamList.paramarray[0][GNB_MINRXTXTIME_IDX].iptr;
LOG_I(GNB_APP, "minTXRXTIME %d\n", config.minRXTXTIME);
config.do_TCI = *GNBParamList.paramarray[0][GNB_DO_TCI_IDX].iptr;
config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr;
config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr;
config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr;
+27 -23
View File
@@ -114,6 +114,7 @@ typedef enum {
#define GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N2 "pdsch_AntennaPorts_N2"
#define GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP "pdsch_AntennaPorts_XP"
#define GNB_CONFIG_STRING_PUSCHANTENNAPORTS "pusch_AntennaPorts"
#define GNB_CONFIG_STRING_DOTCI "do_TCI"
#define GNB_CONFIG_STRING_DOCSIRS "do_CSIRS"
#define GNB_CONFIG_STRING_DOSRS "do_SRS"
#define GNB_CONFIG_STRING_NRCELLID "nr_cellid"
@@ -178,6 +179,7 @@ typedef enum {
{GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N2, "vert. log. antenna ports", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP, "XP log. antenna ports", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_PUSCHANTENNAPORTS, NULL, 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_DOTCI, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_DOCSIRS, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_DOSRS, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_NRCELLID, NULL, 0, .u64ptr=NULL,.defint64val=1, TYPE_UINT64, 0}, \
@@ -223,29 +225,30 @@ typedef enum {
#define GNB_PDSCH_ANTENNAPORTS_N2_IDX 14
#define GNB_PDSCH_ANTENNAPORTS_XP_IDX 15
#define GNB_PUSCH_ANTENNAPORTS_IDX 16
#define GNB_DO_CSIRS_IDX 17
#define GNB_DO_SRS_IDX 18
#define GNB_NRCELLID_IDX 19
#define GNB_MINRXTXTIME_IDX 20
#define GNB_ULPRBBLACKLIST_IDX 21
#define GNB_UMONDEFAULTDRB_IDX 22
#define GNB_FORCE256QAMOFF_IDX 23
#define GNB_ENABLE_SDAP_IDX 24
#define GNB_DRBS 25
#define GNB_GNB_DU_ID_IDX 26
#define GNB_GNB_CU_UP_ID_IDX 27
#define GNB_USE_DELTA_MCS_IDX 28
#define GNB_FORCEUL256QAMOFF_IDX 29
#define GNB_MAXMIMOLAYERS_IDX 30
#define GNB_DISABLE_HARQ_IDX 31
#define GNB_NUM_DL_HARQ_IDX 32
#define GNB_NUM_UL_HARQ_IDX 33
#define GNB_UESS_AGG_LEVEL_LIST_IDX 34
#define GNB_CU_SIBS_IDX 35
#define GNB_DU_SIBS_IDX 36
#define GNB_CONFIG_REP_IDX 37
#define GNB_1ST_ACTIVE_BWP_IDX 38
#define GNB_LIMIT_RSRP_REPORT_IDX 39
#define GNB_DO_TCI_IDX 17
#define GNB_DO_CSIRS_IDX 18
#define GNB_DO_SRS_IDX 19
#define GNB_NRCELLID_IDX 20
#define GNB_MINRXTXTIME_IDX 21
#define GNB_ULPRBBLACKLIST_IDX 22
#define GNB_UMONDEFAULTDRB_IDX 23
#define GNB_FORCE256QAMOFF_IDX 24
#define GNB_ENABLE_SDAP_IDX 25
#define GNB_DRBS 26
#define GNB_GNB_DU_ID_IDX 27
#define GNB_GNB_CU_UP_ID_IDX 28
#define GNB_USE_DELTA_MCS_IDX 29
#define GNB_FORCEUL256QAMOFF_IDX 30
#define GNB_MAXMIMOLAYERS_IDX 31
#define GNB_DISABLE_HARQ_IDX 32
#define GNB_NUM_DL_HARQ_IDX 33
#define GNB_NUM_UL_HARQ_IDX 34
#define GNB_UESS_AGG_LEVEL_LIST_IDX 35
#define GNB_CU_SIBS_IDX 36
#define GNB_DU_SIBS_IDX 37
#define GNB_CONFIG_REP_IDX 38
#define GNB_1ST_ACTIVE_BWP_IDX 39
#define GNB_LIMIT_RSRP_REPORT_IDX 40
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
#define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32}
@@ -284,6 +287,7 @@ typedef enum {
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s1 = { config_check_intval, NUM_DL_HARQ_OKVALUES,8 } }, \
{ .s1 = { config_check_intval, NUM_UL_HARQ_OKVALUES,2 } }, \
{ .s5 = { NULL } }, \
+2 -1
View File
@@ -828,7 +828,8 @@ static void config_sched_ctrlSIB1(gNB_MAC_INST *nr_mac)
// we need to configure a commonControlResourceSet != 0
// because CSET0 would start from a symbol != 0 and that's unwanted for anything but SIB1
// The network configures the commonControlResourceSet in SIB1 so that it is contained in the bandwidth of CSET0
configure_coreset_for_mux23(scc, nr_mac->cset0_bwp_start - bwp_start, nr_mac->cset0_bwp_size, bwp_start, bwp_size);
bool do_TCI = nr_mac->radio_config.do_TCI;
configure_coreset_for_mux23(scc, nr_mac->cset0_bwp_start - bwp_start, nr_mac->cset0_bwp_size, bwp_start, bwp_size, do_TCI);
}
}
@@ -71,8 +71,7 @@ int get_dl_tda(const gNB_MAC_INST *nrmac, int slot)
return 0; // if FDD or not mixed slot in TDD, for now use default TDA
}
// Compute and write all MAC CEs and subheaders, and return number of written
// bytes
// Compute and write all MAC CEs and subheaders, and return number of written bytes
int nr_write_ce_dlsch_pdu(module_id_t module_idP,
const NR_UE_sched_ctrl_t *ue_sched_ctl,
unsigned char *mac_pdu,
@@ -151,19 +150,20 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP,
}
//TS 38.321 Sec 6.1.3.15 TCI State indication for UE Specific PDCCH MAC CE SubPDU generation
if (ue_sched_ctl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled) {
if (ue_sched_ctl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled) {
//filling subheader
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH;
mac_pdu_ptr++;
//Creating the instance of CE structure
NR_TCI_PDCCH nr_UESpec_TCI_StateInd_PDCCH;
//filling the CE structre
nr_UESpec_TCI_StateInd_PDCCH.CoresetId1 = ((ue_sched_ctl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId) & 0xF) >> 1; //extracting MSB 3 bits from LS nibble
nr_UESpec_TCI_StateInd_PDCCH.ServingCellId = (ue_sched_ctl->UE_mac_ce_ctrl.pdcch_state_ind.servingCellId) & 0x1F; //extracting LSB 5 Bits
nr_UESpec_TCI_StateInd_PDCCH.TciStateId = (ue_sched_ctl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId) & 0x7F; //extracting LSB 7 bits
nr_UESpec_TCI_StateInd_PDCCH.CoresetId2 = (ue_sched_ctl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId) & 0x1; //extracting LSB 1 bit
LOG_D(NR_MAC, "NR MAC CE TCI state indication for UE Specific PDCCH = %d \n", nr_UESpec_TCI_StateInd_PDCCH.TciStateId);
const tciStateInd_t *tcisi = &ue_sched_ctl->UE_mac_ce_ctrl.tci_state_ind;
NR_TCI_PDCCH nr_UESpec_TCI_StateInd_PDCCH = {
.CoresetId1 = (tcisi->coresetId & 0xF) >> 1,
.ServingCellId = 0, // TODO this is likely ServingCellIndex, see 38.331
.TciStateId = tcisi->tciStateId & 0x7F,
.CoresetId2 = tcisi->coresetId & 0x1,
};
LOG_I(NR_MAC, "NR MAC CE TCI state indication for UE Specific PDCCH = %d \n", nr_UESpec_TCI_StateInd_PDCCH.TciStateId);
mac_ce_size = sizeof(NR_TCI_PDCCH);
// Copying bytes for MAC CEs to the mac pdu pointer
memcpy((void *) mac_pdu_ptr, (void *)&nr_UESpec_TCI_StateInd_PDCCH, mac_ce_size);
@@ -609,6 +609,19 @@ static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE)
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
}
static bool dlsch_to_schedule(const NR_UE_sched_ctrl_t *sched_ctrl, int frame)
{
/* Check DL buffer, TA to be sent and beam switch needed*/
if (sched_ctrl->num_total_bytes > 0)
return true;
if (sched_ctrl->ta_apply == true)
return true;
if (sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled)
return true;
// if none of the condition for dlsch to be scheduled are met
return false;
}
typedef struct UEsched_s {
float coef;
NR_UE_info_t * UE;
@@ -705,8 +718,7 @@ static void pf_dl(gNB_MAC_INST *mac,
update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, UE);
/* Check DL buffer and skip this UE if no bytes and no TA necessary */
if (sched_ctrl->num_total_bytes == 0 && sched_ctrl->ta_apply == false)
if (!dlsch_to_schedule(sched_ctrl, frame))
continue;
/* Calculate coeff */
@@ -1254,6 +1266,8 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize;
} else { /* initial transmission */
LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot);
// Flag HARQ process to start TCI timer at ACK
harq->start_tci_timer = sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled;
uint8_t *buf = allocate_transportBlock_buffer(&harq->transportBlock, TBS);
/* first, write all CEs that might be there */
int written = nr_write_ce_dlsch_pdu(module_id,
@@ -1373,6 +1387,11 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
* retransmissions */
harq->sched_pdsch.time_domain_allocation = sched_pdsch->time_domain_allocation;
// reset TCI state
if (sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled)
sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled = false;
// ta command is sent, values are reset
if (sched_ctrl->ta_apply) {
sched_ctrl->ta_apply = false;
@@ -3571,6 +3571,12 @@ void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti)
mac_remove_nr_ue(mac, rnti);
}
static void beam_switching_procedure(NR_UE_info_t *UE, int new_beam_index)
{
LOG_I(NR_MAC, "[UE %x] Switching to beam with ID %d (from %d)\n", UE->rnti, new_beam_index, UE->UE_beam_index);
UE->UE_beam_index = new_beam_index;
}
void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
{
gNB_MAC_INST *mac = RC.nrmac[module_id];
@@ -3609,6 +3615,10 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
LOG_W(NR_MAC, "UE %04x UL failure after transmission timeout\n", UE->rnti);
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
}
if (nr_timer_tick(&sched_ctrl->tci_beam_switch)) {
nr_timer_stop(&sched_ctrl->tci_beam_switch);
beam_switching_procedure(UE, sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.tciStateId);
}
}
}
@@ -3740,14 +3750,33 @@ void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE)
// do not perform beam procedures if there is no beam information
if (mac->beam_info.beam_mode == NO_BEAM_MODE)
return;
RSRP_report_t *rsrp_report = &UE->UE_sched_ctrl.CSI_report.ssb_rsrp_report;
// simple beam switching algorithm -> we select beam with highest RSRP from CSI report
int new_bf_index = get_beam_from_ssbidx(mac, rsrp_report->resource_id[0]);
if (UE->UE_beam_index == new_bf_index)
return; // no beam change needed
LOG_I(NR_MAC, "[UE %x] Switching to beam with ID %d (SSB number %d)\n", UE->rnti, new_bf_index, rsrp_report->resource_id[0]);
UE->UE_beam_index = new_bf_index;
// simple beam switching algorithm -> we select beam with highest RSRP from CSI report
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
RSRP_report_t *rsrp_report = &sched_ctrl->CSI_report.ssb_rsrp_report;
int new_bf_index = get_beam_from_ssbidx(mac, rsrp_report->resource_id[0]);
if (!mac->radio_config.do_TCI) { // if not TCI is configure we switch beam directly
if (UE->UE_beam_index != new_bf_index)
beam_switching_procedure(UE, new_bf_index);
return;
}
tciStateInd_t *tci = &sched_ctrl->UE_mac_ce_ctrl.tci_state_ind;
if (UE->UE_beam_index == new_bf_index) {
if (tci->is_scheduled) {
LOG_I(NR_MAC, "[UE %x] Stopping procedure to switch beam, old beam reported as best again\n", UE->rnti);
tci->is_scheduled = false;
}
return; // no beam change needed
}
LOG_I(NR_MAC, "[UE %x] Starting procedure to switch beam\n", UE->rnti);
// Start procedure to switch beam via
// TCI State Indication for UE-specific PDCCH
tci->is_scheduled = true;
tci->coresetId = sched_ctrl->coreset->controlResourceSetId;
tci->tciStateId = new_bf_index; // assumption: this correspond to the TCI index
}
void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data)
+16 -1
View File
@@ -935,6 +935,13 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
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);
bool success = harq_value == 0 && harq_confidence == 0;
// TCI state switch occurs at the first slot that is after slot n_+ T_HARQ + 3N_sf_slot (8.10.3 of 38.133)
if (success && harq->start_tci_timer) {
int slots = 3 * nrmac->frame_structure.numb_slots_frame / 10;
nr_timer_setup(&sched_ctrl->tci_beam_switch, slots, 1);
nr_timer_start(&sched_ctrl->tci_beam_switch);
harq->start_tci_timer = false;
}
handle_dl_harq(nrmac, UE, pid, success, nrmac->dl_bler.harq_round_max);
if (is_ra) {
bool ue_rejected = nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success);
@@ -1009,7 +1016,15 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, frame_t frame, slot_t slot, c
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, acknack);
handle_dl_harq(nrmac, UE, pid, uci_234->harq.harq_crc != 1 && acknack, nrmac->dl_bler.harq_round_max);
// TCI state switch occurs at the first slot that is after slot n_+ T_HARQ + 3N_sf_slot (8.10.3 of 38.133)
bool success = uci_234->harq.harq_crc != 1 && acknack;
if (success && harq->start_tci_timer) {
int slots = 3 * nrmac->frame_structure.numb_slots_frame / 10;
nr_timer_setup(&sched_ctrl->tci_beam_switch, slots, 1);
nr_timer_start(&sched_ctrl->tci_beam_switch);
harq->start_tci_timer = false;
}
handle_dl_harq(nrmac, UE, pid, success, nrmac->dl_bler.harq_round_max);
}
free(uci_234->harq.harq_payload);
}
+8 -8
View File
@@ -191,6 +191,7 @@ typedef struct nr_mac_config_t {
int minRXTXTIME;
int do_CSIRS;
int do_SRS;
int do_TCI;
int max_num_rsrp;
bool force_256qam_off;
bool force_UL256qam_off;
@@ -351,13 +352,11 @@ typedef struct csi_rs_im {
uint8_t tci_state_id [ MAX_CSI_RESOURCE_SET ];
} csi_rs_im_t;
typedef struct pdcchStateInd {
typedef struct tciStateInd {
bool is_scheduled;
uint8_t servingCellId;
uint8_t coresetId;
uint8_t tciStateId;
bool tci_present_inDCI;
} pdcchStateInd_t;
uint32_t coresetId;
uint32_t tciStateId;
} tciStateInd_t;
typedef struct pucchSpatialRelation {
bool is_scheduled;
@@ -396,7 +395,7 @@ typedef struct pdschTciStatesActDeact {
typedef struct UE_info {
sp_zp_csirs_t sp_zp_csi_rs;
csi_rs_im_t csi_im;
pdcchStateInd_t pdcch_state_ind;
tciStateInd_t tci_state_ind;
pucchSpatialRelation_t pucch_spatial_relation;
SPCSIReportingpucch_t SP_CSI_reporting_pucch;
aperiodicCSI_triggerStateSelection_t aperi_CSI_trigger;
@@ -516,7 +515,7 @@ typedef struct NR_UE_harq {
/* Transport block to be sent using this HARQ process */
byte_array_t transportBlock;
uint32_t tb_size; // size of currently stored TB
bool start_tci_timer;
/// sched_pdsch keeps information on MCS etc used for the initial transmission
NR_sched_pdsch_t sched_pdsch;
} NR_UE_harq_t;
@@ -695,6 +694,7 @@ typedef struct {
/// Timer for RRC processing procedures and transmission activity
NR_timer_t transm_interrupt;
NR_timer_t tci_beam_switch;
/// Timer for timeout before UE is set to UL failure (e.g.,
/// "TransmissionActionIndicator" handling
+44 -31
View File
@@ -278,7 +278,8 @@ static NR_ControlResourceSet_t *get_coreset_config(int bwp_id,
int cset_limit,
int bwp_start,
int bwp_size,
uint64_t ssb_bitmap)
uint64_t ssb_bitmap,
bool doTCI)
{
NR_ControlResourceSet_t *coreset = calloc(1, sizeof(*coreset));
AssertFatal(coreset != NULL, "out of memory\n");
@@ -317,13 +318,15 @@ static NR_ControlResourceSet_t *get_coreset_config(int bwp_id,
// The ID space is used across the BWPs of a Serving Cell as per 38.331
coreset->controlResourceSetId = bwp_id + 1;
coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
NR_TCI_StateId_t *tci[64];
for (int i=0;i<64;i++) {
if ((ssb_bitmap>>(63-i))&0x01){
tci[i]=calloc(1,sizeof(*tci[i]));
*tci[i] = i;
asn1cSeqAdd(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
if (doTCI) {
coreset->tci_StatesPDCCH_ToAddList = calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
int num_ssb = 0;
for (int i = 0; i < 64; i++) {
if ((ssb_bitmap >> (63 - i)) & 0x01) {
NR_TCI_StateId_t *tci = calloc(1, sizeof(*tci));
*tci = num_ssb++;
asn1cSeqAdd(&coreset->tci_StatesPDCCH_ToAddList->list, tci);
}
}
}
coreset->tci_StatesPDCCH_ToReleaseList = NULL;
@@ -1693,7 +1696,11 @@ static NR_PTRS_DownlinkConfig_t *config_dlptrs(const nr_ptrs_config_t *ptrs)
return ptrs_config;
}
static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp_Id, int dl_antenna_ports, nr_ptrs_config_t *ptrs)
static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap,
int bwp_Id,
int dl_antenna_ports,
bool do_TCI,
nr_ptrs_config_t *ptrs)
{
NR_SetupRelease_PDSCH_Config_t *setup_pdsch_Config = calloc(1,sizeof(*setup_pdsch_Config));
setup_pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup;
@@ -1726,19 +1733,21 @@ static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp
pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize = calloc(1, sizeof(*pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize));
*pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband;
int n_ssb = 0;
if (!pdsch_Config->tci_StatesToAddModList)
pdsch_Config->tci_StatesToAddModList=calloc(1,sizeof(*pdsch_Config->tci_StatesToAddModList));
for (int i = 0; i < 64; i++) {
if (((ssb_bitmap >> (63 - i)) & 0x01) == 0)
continue;
asn1cSequenceAdd(pdsch_Config->tci_StatesToAddModList->list, NR_TCI_State_t, tcid);
tcid->tci_StateId = n_ssb++;
tcid->qcl_Type1.cell = NULL;
asn1cCallocOne(tcid->qcl_Type1.bwp_Id, bwp_Id);
tcid->qcl_Type1.referenceSignal.present = NR_QCL_Info__referenceSignal_PR_ssb;
tcid->qcl_Type1.referenceSignal.choice.ssb = i;
tcid->qcl_Type1.qcl_Type = NR_QCL_Info__qcl_Type_typeC;
if (do_TCI) {
int n_ssb = 0;
if (!pdsch_Config->tci_StatesToAddModList)
pdsch_Config->tci_StatesToAddModList=calloc(1,sizeof(*pdsch_Config->tci_StatesToAddModList));
for (int i = 0; i < 64; i++) {
if (((ssb_bitmap >> (63 - i)) & 0x01) == 0)
continue;
asn1cSequenceAdd(pdsch_Config->tci_StatesToAddModList->list, NR_TCI_State_t, tcid);
tcid->tci_StateId = n_ssb++;
tcid->qcl_Type1.cell = NULL;
asn1cCallocOne(tcid->qcl_Type1.bwp_Id, bwp_Id);
tcid->qcl_Type1.referenceSignal.present = NR_QCL_Info__referenceSignal_PR_ssb;
tcid->qcl_Type1.referenceSignal.choice.ssb = i;
tcid->qcl_Type1.qcl_Type = NR_QCL_Info__qcl_Type_typeC;
}
}
return setup_pdsch_Config;
}
@@ -1772,7 +1781,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t
int bwp_size = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
int bwp_start = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
uint64_t ssb_bitmap = get_ssb_bitmap(scc);
NR_ControlResourceSet_t *coreset = get_coreset_config(bwp->bwp_Id, 0, 0, bwp_start, bwp_size, ssb_bitmap);
NR_ControlResourceSet_t *coreset = get_coreset_config(bwp->bwp_Id, 0, 0, bwp_start, bwp_size, ssb_bitmap, configuration->do_TCI);
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet = coreset;
bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceZero=NULL;
@@ -1825,7 +1834,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t
bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList = calloc(1,sizeof(*bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList));
// coreset2 is identical to coreset above, but reallocated to prevent double frees
NR_ControlResourceSet_t *coreset2 = get_coreset_config(bwp->bwp_Id, 0, 0, bwp_start, bwp_size, ssb_bitmap);
NR_ControlResourceSet_t *coreset2 = get_coreset_config(bwp->bwp_Id, 0, 0, bwp_start, bwp_size, ssb_bitmap, configuration->do_TCI);
asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset2);
int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
int num_cces = get_coreset_num_cces(coreset2->frequencyDomainResources.buf, coreset2->duration);
@@ -1841,7 +1850,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t
asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss3);
bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToReleaseList = NULL;
bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, dl_antenna_ports, configuration->ptrs);
bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, dl_antenna_ports, configuration->do_TCI, configuration->ptrs);
set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing,
force_256qam_off ? NULL : uecap,
@@ -2730,10 +2739,14 @@ static BIT_STRING_t bit_string_clone(const BIT_STRING_t *orig)
return bs;
}
void configure_coreset_for_mux23(const NR_ServingCellConfigCommon_t *scc, int offset, int limit, int bwp_start, int bwp_size)
void configure_coreset_for_mux23(const NR_ServingCellConfigCommon_t *scc,
int offset,
int limit,
int bwp_start,
int bwp_size,
bool do_TCI)
{
NR_ControlResourceSet_t *coreset = get_coreset_config(5, offset, limit, bwp_start, bwp_size, get_ssb_bitmap(scc));
NR_ControlResourceSet_t *coreset = get_coreset_config(5, offset, limit, bwp_start, bwp_size, get_ssb_bitmap(scc), do_TCI);
NR_PDCCH_ConfigCommon_t *pdcch_common = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup;
pdcch_common->commonControlResourceSet = coreset;
for (int i = 0; i < pdcch_common->commonSearchSpaceList->list.count; i++) {
@@ -3367,7 +3380,7 @@ static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCell
NR_BWP_t *genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
int bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
int bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
NR_ControlResourceSet_t *coreset = get_coreset_config(0, 0, 0, bwp_start, bwp_size, bitmap);
NR_ControlResourceSet_t *coreset = get_coreset_config(0, 0, 0, bwp_start, bwp_size, bitmap, configuration->do_TCI);
asn1cSeqAdd(&pdcch_Config->controlResourceSetToAddModList->list, coreset);
int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
@@ -3387,7 +3400,7 @@ static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCell
asn1cSeqAdd(&pdcch_Config->searchSpacesToAddModList->list, ss2);
bwp_Dedicated->pdcch_Config->choice.setup = pdcch_Config;
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts, configuration->ptrs);
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts, configuration->do_TCI, configuration->ptrs);
// we might call configuration of initial BWP for BWP switch when we already have UE capabilities
set_dl_mcs_table(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing,
configuration->force_256qam_off ? NULL : uecap,
@@ -4038,7 +4051,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
configDedicated->initialDownlinkBWP = calloc(1, sizeof(*configDedicated->initialDownlinkBWP));
configDedicated->initialDownlinkBWP->pdcch_Config = NULL;
configDedicated->initialDownlinkBWP->pdsch_Config =
config_pdsch(bitmap, 0, dl_antenna_ports, configuration->ptrs);
config_pdsch(bitmap, 0, dl_antenna_ports, configuration->do_TCI, configuration->ptrs);
configDedicated->initialDownlinkBWP->sps_Config = NULL; // calloc(1,sizeof(struct NR_SetupRelease_SPS_Config));
configDedicated->initialDownlinkBWP->radioLinkMonitoringConfig = NULL;
+6 -1
View File
@@ -68,7 +68,12 @@ NR_BCCH_BCH_Message_t *get_new_MIB_NR(const NR_ServingCellConfigCommon_t *scc);
void free_MIB_NR(NR_BCCH_BCH_Message_t *mib);
int encode_MIB_NR(NR_BCCH_BCH_Message_t *mib, int frame, uint8_t *buf, int buf_size);
int encode_MIB_NR_setup(NR_MIB_t *mib, int frame, uint8_t *buf, int buf_size);
void configure_coreset_for_mux23(const NR_ServingCellConfigCommon_t *scc, int offset, int limit, int bwp_start, int bwp_size);
void configure_coreset_for_mux23(const NR_ServingCellConfigCommon_t *scc,
int offset,
int limit,
int bwp_start,
int bwp_size,
bool do_TCI);
struct NR_MeasurementTimingConfiguration;
struct NR_MeasurementTimingConfiguration *get_new_MeasurementTimingConfiguration(const NR_ServingCellConfigCommon_t *scc);
int encode_MeasurementTimingConfiguration(const struct NR_MeasurementTimingConfiguration *mtc, uint8_t *buf, int buf_len);