handling beam switching via TCI state indication MAC CE

This commit is contained in:
francescomani
2025-12-26 12:08:16 +01:00
parent 4edc5c2d33
commit 8d857ab794
4 changed files with 68 additions and 23 deletions
@@ -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);
@@ -1254,6 +1254,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 +1375,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;
@@ -3573,6 +3573,14 @@ 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)
{
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
int new_beam_index = sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.tciStateId;
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];
@@ -3611,6 +3619,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);
}
}
}
@@ -3742,14 +3754,26 @@ 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;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
tciStateInd_t *tci = &sched_ctrl->UE_mac_ce_ctrl.tci_state_ind;
RSRP_report_t *rsrp_report = &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)
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] 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;
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);
}
+7 -8
View File
@@ -351,13 +351,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 +394,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 +514,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 +693,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