Commit b1d92796 authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/more_static_cleanup' into integration_2026_w02 (!3828)

L2 UE files code cleanup for static functions

No functional change, just re-arranging code
parents 9b0bb594 90d4d272
......@@ -38,7 +38,7 @@
#include "executables/softmodem-common.h"
#include <stdio.h>
void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y)
static void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y)
{
LOG_T(NR_MAC_DCI, "Filling search candidates for DCI\n");
......@@ -89,7 +89,7 @@ void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dc
rel15->number_of_candidates = i;
}
NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id)
static NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id)
{
if (config->commonControlResourceSet && coreset_id == config->commonControlResourceSet->controlResourceSetId)
return config->commonControlResourceSet;
......@@ -362,12 +362,12 @@ bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per
return monitor;
}
bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
const NR_SearchSpace_t *ss,
const int abs_slot,
const int frame,
const int slot,
const int slots_per_frame)
static bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
const NR_SearchSpace_t *ss,
const int abs_slot,
const int frame,
const int slot,
const int slots_per_frame)
{
const int duration = ss->duration ? *ss->duration : 1;
int period, offset;
......
......@@ -58,13 +58,6 @@ static const int nb_symbols_excluding_dmrs[11][2][2]
/* 14 */ {{ 12 , 12 } , { 10 , 10 }},
};
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI);
// ∆MPR according to Table 6.2.2-3 38.101-1
static float get_delta_mpr(uint16_t nr_band, frame_type_t frame_type, int scs, int channel_bandwidth, int n_prbs, int start_prb, int power_class)
{
......@@ -256,6 +249,28 @@ int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame)
return delta_tpc_sum;
}
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI)
{
int DELTA_TF;
int O_CRC = compute_pucch_crc_size(O_UCI);
int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag];
float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb;
float K1 = 6;
if (O_UCI + O_CRC < 12)
DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE)));
else {
float K2 = 2.4;
float BPRE = (O_UCI + O_CRC) / N_RE;
DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1));
}
return DELTA_TF;
}
// PUCCH Power control according to 38.213 section 7.2.1
int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
int scs,
......@@ -399,28 +414,6 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
return pucch_power;
}
static int get_deltatf(uint16_t nb_of_prbs,
uint8_t N_symb_PUCCH,
uint8_t freq_hop_flag,
uint8_t add_dmrs_flag,
int N_sc_ctrl_RB,
int O_UCI)
{
int DELTA_TF;
int O_CRC = compute_pucch_crc_size(O_UCI);
int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag];
float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb;
float K1 = 6;
if (O_UCI + O_CRC < 12)
DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE)));
else {
float K2 = 2.4;
float BPRE = (O_UCI + O_CRC) / N_RE;
DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1));
}
return DELTA_TF;
}
// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
// Assumptions:
......
......@@ -104,58 +104,7 @@ static const int sequence_cyclic_shift_2_harq_ack_bits[4]
/* HARQ-ACK Value (0,0) (0,1) (1,0) (1,1) */
/* Sequence cyclic shift */ = { 0, 3, 9, 6 };
/* \brief Function called by PHY to process the received RAR and check that the preamble matches what was sent by the gNB. It
provides the timing advance and t-CRNTI.
@param Mod_id Index of UE instance
@param CC_id Index to a component carrier
@param frame Frame index
@param ra_rnti RA_RNTI value
@param dlsch_buffer Pointer to dlsch_buffer containing RAR PDU
@param t_crnti Pointer to PHY variable containing the T_CRNTI
@param preamble_index Preamble Index used by PHY to transmit the PRACH. This should match the received RAR to trigger the rest of
random-access procedure
@param selected_rar_buffer the output buffer for storing the selected RAR header and RAR payload
@returns timing advance or 0xffff if preamble doesn't match
*/
static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id);
/*! \fn int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id);
\brief This function schedules a positive or negative SR for schedulingRequestID sr_id
depending on the presence of any active SR and the prohibit timer.
If the max number of retransmissions is reached, it triggers a new RA */
static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id);
static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
NR_CSI_MeasConfig_t *csi_MeasConfig);
static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
NR_CSI_MeasConfig_t *csi_MeasConfig,
CSI_mapping_t mapping_type);
static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
const NR_CSI_MeasConfig_t *csi_MeasConfig);
static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp);
static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id);
static void set_harq_status(NR_UE_MAC_INST_t *mac,
uint8_t pucch_id,
uint8_t harq_id,
int8_t delta_pucch,
uint16_t data_toul_fb,
uint8_t dai,
int n_CCE,
int N_CCE,
frame_t frame,
int slot);
int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload)
static int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload)
{
int mcs = 0;
if (O_SR == 0 || sr_payload == 0) { /* only ack is transmitted TS 36.213 9.2.3 UE procedure for reporting HARQ-ACK */
......@@ -197,14 +146,6 @@ const initial_pucch_resource_t initial_pucch_resource[16] = {
/* 15 */ { 1, 0, 14, 0, 4, { 0, 3, 6, 9 } },
};
static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
const nfapi_nr_dci_formats_e dci_format,
const uint8_t dci_size,
const uint16_t rnti,
const int ss_type,
const uint8_t *dci_pdu,
const int slot);
int get_rnti_type(const NR_UE_MAC_INST_t *mac, const uint16_t rnti)
{
const RA_config_t *ra = &mac->ra;
......@@ -523,6 +464,71 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p
return 0;
}
static void set_harq_status(NR_UE_MAC_INST_t *mac,
uint8_t pucch_id,
uint8_t harq_id,
int8_t delta_pucch,
uint16_t data_toul_fb,
uint8_t dai,
int n_CCE,
int N_CCE,
frame_t frame,
int slot)
{
NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_id];
current_harq->active = true;
current_harq->ack_received = false;
current_harq->pucch_resource_indicator = pucch_id;
current_harq->n_CCE = n_CCE;
current_harq->N_CCE = N_CCE;
current_harq->dai_cumul = 0;
current_harq->delta_pucch = delta_pucch;
// FIXME k0 != 0 currently not taken into consideration
int slots_per_frame = mac->frame_structure.numb_slots_frame;
current_harq->ul_frame = frame;
current_harq->ul_slot = slot + data_toul_fb;
if (current_harq->ul_slot >= slots_per_frame) {
current_harq->ul_frame = (frame + current_harq->ul_slot / slots_per_frame) % MAX_FRAME_NUMBER;
current_harq->ul_slot %= slots_per_frame;
}
// counter DAI in DCI ranges from 0 to 3
// we might have more than 4 HARQ processes to report per PUCCH
// we need to keep track of how many DAI we received in a slot (dai_cumul) despite the modulo operation
int highest_dai = -1;
int temp_dai = dai;
const int num_dl_harq = get_nrofHARQ_ProcessesForPDSCH(&mac->sc_info);
for (int i = 0; i < num_dl_harq; i++) {
// looking for other active HARQ processes with feedback in the same frame/slot
if (i == harq_id)
continue;
NR_UE_DL_HARQ_STATUS_t *harq = &mac->dl_harq_info[i];
if (harq->active &&
harq->ul_frame == current_harq->ul_frame &&
harq->ul_slot == current_harq->ul_slot) {
// highest_dai is the largest cumulative dai in the set of HARQ allocations for a given slot
if (harq->dai_cumul > highest_dai)
highest_dai = harq->dai_cumul - 1;
}
}
current_harq->dai_cumul = temp_dai + 1; // DAI = 0 (temp_dai) corresponds to 1st assignment and so on
// if temp_dai is less or equal than cumulative highest dai for given slot
// it's an indication dai was reset due to modulo 4 operation
if (temp_dai <= highest_dai) {
int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4)
current_harq->dai_cumul += (mod4_count * 4);
}
LOG_D(NR_MAC,
"Setting harq_status for harq_id %d, dl %d.%d, sched ul %d.%d fb time %d total dai %d\n",
harq_id,
frame,
slot,
current_harq->ul_frame,
current_harq->ul_slot,
data_toul_fb,
current_harq->dai_cumul);
}
static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
......@@ -1486,27 +1492,6 @@ static int8_t nr_ue_process_dci(NR_UE_MAC_INST_t *mac,
return -1;
}
nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci)
{
LOG_D(NR_MAC,
"Received dci indication (rnti %x, dci format %d, n_CCE %d, payloadSize %d, payload %llx)\n",
dci->rnti,
dci->dci_format,
dci->n_CCE,
dci->payloadSize,
*(unsigned long long *)dci->payloadBits);
const nr_dci_format_t format =
nr_extract_dci_info(mac, dci->dci_format, dci->payloadSize, dci->rnti, dci->ss_type, dci->payloadBits, slot);
if (format == NR_DCI_NONE)
return NR_DCI_NONE;
int ret = nr_ue_process_dci(mac, frame, slot, mac->def_dci_pdu_rel15[slot] + format, dci, format);
if (ret < 0) {
mac->stats.bad_dci++;
return NR_DCI_NONE;
}
return format;
}
void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements)
{
LOG_D(NR_MAC, "(%d.%d) Received measurements from L1\n", frame, slot);
......@@ -1530,71 +1515,6 @@ void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slo
l1_measurements->rsrp_dBm);
}
static void set_harq_status(NR_UE_MAC_INST_t *mac,
uint8_t pucch_id,
uint8_t harq_id,
int8_t delta_pucch,
uint16_t data_toul_fb,
uint8_t dai,
int n_CCE,
int N_CCE,
frame_t frame,
int slot)
{
NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_id];
current_harq->active = true;
current_harq->ack_received = false;
current_harq->pucch_resource_indicator = pucch_id;
current_harq->n_CCE = n_CCE;
current_harq->N_CCE = N_CCE;
current_harq->dai_cumul = 0;
current_harq->delta_pucch = delta_pucch;
// FIXME k0 != 0 currently not taken into consideration
int slots_per_frame = mac->frame_structure.numb_slots_frame;
current_harq->ul_frame = frame;
current_harq->ul_slot = slot + data_toul_fb;
if (current_harq->ul_slot >= slots_per_frame) {
current_harq->ul_frame = (frame + current_harq->ul_slot / slots_per_frame) % MAX_FRAME_NUMBER;
current_harq->ul_slot %= slots_per_frame;
}
// counter DAI in DCI ranges from 0 to 3
// we might have more than 4 HARQ processes to report per PUCCH
// we need to keep track of how many DAI we received in a slot (dai_cumul) despite the modulo operation
int highest_dai = -1;
int temp_dai = dai;
const int num_dl_harq = get_nrofHARQ_ProcessesForPDSCH(&mac->sc_info);
for (int i = 0; i < num_dl_harq; i++) {
// looking for other active HARQ processes with feedback in the same frame/slot
if (i == harq_id)
continue;
NR_UE_DL_HARQ_STATUS_t *harq = &mac->dl_harq_info[i];
if (harq->active &&
harq->ul_frame == current_harq->ul_frame &&
harq->ul_slot == current_harq->ul_slot) {
// highest_dai is the largest cumulative dai in the set of HARQ allocations for a given slot
if (harq->dai_cumul > highest_dai)
highest_dai = harq->dai_cumul - 1;
}
}
current_harq->dai_cumul = temp_dai + 1; // DAI = 0 (temp_dai) corresponds to 1st assignment and so on
// if temp_dai is less or equal than cumulative highest dai for given slot
// it's an indication dai was reset due to modulo 4 operation
if (temp_dai <= highest_dai) {
int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4)
current_harq->dai_cumul += (mod4_count * 4);
}
LOG_D(NR_MAC,
"Setting harq_status for harq_id %d, dl %d.%d, sched ul %d.%d fb time %d total dai %d\n",
harq_id,
frame,
slot,
current_harq->ul_frame,
current_harq->ul_slot,
data_toul_fb,
current_harq->dai_cumul);
}
initial_pucch_resource_t get_initial_pucch_resource(const int idx)
{
return initial_pucch_resource[idx];
......@@ -2566,51 +2486,11 @@ bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sche
return (number_harq_feedback > 0);
}
bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, frame_t frame, int slot)
{
NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
if(!pucch_Config ||
!pucch_Config->schedulingRequestResourceToAddModList ||
pucch_Config->schedulingRequestResourceToAddModList->list.count == 0)
return false; // SR not configured
int sr_count = 0;
for (int id = 0; id < pucch_Config->schedulingRequestResourceToAddModList->list.count; id++) {
NR_SchedulingRequestResourceConfig_t *sr_Config = pucch_Config->schedulingRequestResourceToAddModList->list.array[id];
int SR_period; int SR_offset;
find_period_offset_SR(sr_Config, &SR_period, &SR_offset);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
int sfn_sf = frame * n_slots_frame + slot;
if ((sfn_sf - SR_offset) % SR_period == 0) {
LOG_D(MAC, "Scheduling Request active in frame %d slot %d \n", frame, slot);
if (!sr_Config->resource) {
LOG_E(MAC, "No resource associated with SR. SR not scheduled\n");
break;
}
NR_PUCCH_Resource_t *sr_pucch =
find_pucch_resource_from_list(pucch_Config->resourceToAddModList, *sr_Config->resource);
AssertFatal(sr_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n");
pucch->pucch_resource = sr_pucch;
pucch->n_sr = 1;
/* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */
int ret = nr_ue_get_SR(mac, frame, slot, sr_Config->schedulingRequestID);
if (ret < 0) {
memset(pucch, 0, sizeof(*pucch));
return false;
}
pucch->sr_payload = ret;
sr_count++;
AssertFatal(sr_count < 2, "Cannot handle more than 1 SR per slot yet\n");
}
}
return sr_count > 0;
}
static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id)
/*! \fn int nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id);
\brief This function schedules a positive or negative SR for schedulingRequestID sr_id
depending on the presence of any active SR and the prohibit timer.
If the max number of retransmissions is reached, it triggers a new RA */
static int nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id)
{
// no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti
NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info;
......@@ -2660,32 +2540,76 @@ static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR
return -1;
}
// section 5.2.5 of 38.214
int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep)
{
int y = 4 - csirep->reportConfigType.present;
int k = csirep->reportQuantity.present == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP
|| csirep->reportQuantity.present == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
? 0
: 1;
int Ncells = 32; // maxNrofServingCells
int c = mac->servCellIndex;
int s = csirep->reportConfigId;
int Ms = 48; // maxNrofCSI-ReportConfigurations
return 2 * Ncells * Ms * y + Ncells * Ms * k + Ms * c + s;
}
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch)
bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, frame_t frame, int slot)
{
NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
int num_csi = 0;
if (mac->sc_info.csi_MeasConfig) {
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
int csi_priority = INT_MAX;
if(!pucch_Config ||
!pucch_Config->schedulingRequestResourceToAddModList ||
pucch_Config->schedulingRequestResourceToAddModList->list.count == 0)
return false; // SR not configured
int sr_count = 0;
for (int id = 0; id < pucch_Config->schedulingRequestResourceToAddModList->list.count; id++) {
NR_SchedulingRequestResourceConfig_t *sr_Config = pucch_Config->schedulingRequestResourceToAddModList->list.array[id];
int SR_period; int SR_offset;
find_period_offset_SR(sr_Config, &SR_period, &SR_offset);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
int sfn_sf = frame * n_slots_frame + slot;
if ((sfn_sf - SR_offset) % SR_period == 0) {
LOG_D(MAC, "Scheduling Request active in frame %d slot %d \n", frame, slot);
if (!sr_Config->resource) {
LOG_E(MAC, "No resource associated with SR. SR not scheduled\n");
break;
}
NR_PUCCH_Resource_t *sr_pucch =
find_pucch_resource_from_list(pucch_Config->resourceToAddModList, *sr_Config->resource);
AssertFatal(sr_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n");
pucch->pucch_resource = sr_pucch;
pucch->n_sr = 1;
/* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */
int ret = nr_ue_get_SR(mac, frame, slot, sr_Config->schedulingRequestID);
if (ret < 0) {
memset(pucch, 0, sizeof(*pucch));
return false;
}
pucch->sr_payload = ret;
sr_count++;
AssertFatal(sr_count < 2, "Cannot handle more than 1 SR per slot yet\n");
}
}
return sr_count > 0;
}
// section 5.2.5 of 38.214
int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep)
{
int y = 4 - csirep->reportConfigType.present;
int k = csirep->reportQuantity.present == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP
|| csirep->reportQuantity.present == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
? 0
: 1;
int Ncells = 32; // maxNrofServingCells
int c = mac->servCellIndex;
int s = csirep->reportConfigId;
int Ms = 48; // maxNrofCSI-ReportConfigurations
return 2 * Ncells * Ms * y + Ncells * Ms * k + Ms * c + s;
}
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch)
{
NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
int num_csi = 0;
if (mac->sc_info.csi_MeasConfig) {
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
int csi_priority = INT_MAX;
for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
......@@ -2855,52 +2779,6 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
return csi;
}
csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
int csi_report_id,
CSI_mapping_t mapping_type,
NR_CSI_MeasConfig_t *csi_MeasConfig)
{
AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n");
csi_payload_t csi = {0};
struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement;
if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) {
switch (csi_reportconfig->ext2->reportQuantity_r16->present) {
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16:
csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16:
LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n");
break;
default:
AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present);
}
} else {
switch (csi_reportconfig->reportQuantity.present) {
case NR_CSI_ReportConfig__reportQuantity_PR_none:
break;
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present);
break;
default:
AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present);
}
}
return csi;
}
// Comparison function for sorting SSB RSRP measurements in descending order
static int compare_ssb_rsrp(const void *a, const void *b)
{
......@@ -2909,6 +2787,16 @@ static int compare_ssb_rsrp(const void *a, const void *b)
return mb->ssb_rsrp_dBm - ma->ssb_rsrp_dBm;
}
// returns index from differential RSRP
// according to Table 10.1.6.1-2 in 38.133
static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp)
{
int diff = best_rsrp-current_rsrp;
if (diff>30)
return 15;
else
return (diff>>1);
}
static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
......@@ -3121,49 +3009,300 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
return csi;
}
// returns index from differential RSRP
// according to Table 10.1.6.1-2 in 38.133
static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp)
csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
int csi_report_id,
CSI_mapping_t mapping_type,
NR_CSI_MeasConfig_t *csi_MeasConfig)
{
int diff = best_rsrp-current_rsrp;
if (diff>30)
return 15;
else
return (diff>>1);
AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n");
csi_payload_t csi = {0};
struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement;
if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) {
switch (csi_reportconfig->ext2->reportQuantity_r16->present) {
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16:
csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16:
LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n");
break;
default:
AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present);
}
} else {
switch (csi_reportconfig->reportQuantity.present) {
case NR_CSI_ReportConfig__reportQuantity_PR_none:
break;
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present);
break;
default:
AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present);
}
}
return csi;
}
void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id)
static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, int frame, int slot)
{
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN);
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment;
ul_time_alignment->ta_command = ta;
ul_time_alignment->ta_apply = type;
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER;
ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame;
// start or restart the timeAlignmentTimer associated with the indicated TAG
nr_timer_start(&mac->time_alignment_timer);
}
LOG_D(NR_MAC,
"In [%d.%d] Handling DLSCH PDU type %d\n",
dl_info->frame,
dl_info->slot,
dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type);
static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot)
{
RAR_grant_t rar_grant;
RA_config_t *ra = &mac->ra;
#ifdef DEBUG_RAR
// CSI
unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01);
#endif
// Processing MAC PDU
// it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs
switch (dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type) {
case FAPI_NR_RX_PDU_TYPE_DLSCH :
// start or restart dataInactivityTimer if any MAC entity receives a MAC SDU for DTCH logical channel,
// DCCH logical channel, or CCCH logical channel
if (mac->data_inactivity_timer)
nr_timer_start(mac->data_inactivity_timer);
// DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
trigger_MAC_UE_RA(mac, NULL);
// TPC
unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07);
ra->Msg3_TPC = (tpc_command << 1) - 6;
// MCS
rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4);
// time alloc
rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f);
// frequency alloc
rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12));
// frequency hopping
rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2);
// Schedule Msg3
const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id];
const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id);
NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP,
*ra_SS->controlResourceSetId,
ra_SS->searchSpaceType->present,
TYPE_RA_RNTI_,
rar_grant.Msg3_t_alloc);
if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) {
LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n");
// resume RAR response window timer if MSG2 decoding failed
nr_timer_suspension(&mac->ra.response_window_timer);
return;
}
frame_t frame_tx = 0;
int slot_tx = 0;
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs);
int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset);
// TA command
// if the timeAlignmentTimer associated with this TAG is not running
if (!nr_timer_is_active(&mac->time_alignment_timer)) {
const int ta = rar->TA2 + (rar->TA1 << 5);
set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx);
LOG_W(MAC, "received TA command %d\n", 31 + ta);
}
// else ignore the received Timing Advance Command
#ifdef DEBUG_RAR
LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E);
LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T);
LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID);
LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R);
LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1);
LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2);
LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1);
LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2);
LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3);
LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4);
LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1);
LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2);
LOG_I(NR_MAC,
"[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n",
frame,
slot,
mac->ue_id,
rar_grant.Msg3_t_alloc,
rar_grant.Msg3_f_alloc,
ta_command,
rar_grant.mcs,
rar_grant.freq_hopping,
tpc_command);
#endif
if (ret != -1) {
uint16_t rnti = mac->crnti;
// Upon successful reception, set the T-CRNTI to the RAR value
// if the RA preamble is selected among the contention-based RA Preambles
if (!ra->cfra) {
ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8);
rnti = ra->t_crnti;
if (!mac->msg3_C_RNTI)
nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false);
}
fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
if (!pdu)
return;
// Config Msg3 PDU
int ret = nr_config_pusch_pdu(mac,
&tda_info,
&pdu->pusch_config_pdu,
NULL,
NULL,
&rar_grant,
rnti,
NR_SearchSpace__searchSpaceType_PR_common,
NR_DCI_NONE);
if (ret != 0)
remove_ul_config_last_item(pdu);
release_ul_config(pdu, false);
}
}
/////////////////////////////////////
// Random Access Response PDU //
// TS 38.213 ch 8.2 //
// TS 38.321 ch 6.2.3 //
/////////////////////////////////////
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise
//| E | T | R A P I D |//
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |//
//| R | T A |//
//| T A | UL grant |//
//| UL grant |//
//| UL grant |//
//| UL grant |//
//| T C - R N T I |//
//| T C - R N T I |//
/////////////////////////////////////
// UL grant (27 bits) //
/////////////////////////////////////
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise
//|-------------------|FHF|F_alloc|//
//| Freq allocation |//
//| F_alloc |Time allocation|//
//| MCS | TPC |CSI|//
/////////////////////////////////////
// TbD WIP Msg3 development ongoing
// - apply UL grant freq alloc & time alloc as per 8.2 TS 38.213
// - apply tpc command
// WIP fix:
// - time domain indication hardcoded to 0 for k2 offset
// - extend TS 38.213 ch 8.3 Msg3 PUSCH
// - b buffer
// - ulsch power offset
// - optimize: mu_pusch, j and table_6_1_2_1_1_2_time_dom_res_alloc_A are already defined in nr_ue_procedures
static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id)
{
frame_t frame = dl_info->frame;
int slot = dl_info->slot;
if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack == 0) {
LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] CRC check failed on RAR (NAK)\n", mac->ue_id, frame, slot);
return;
}
RA_config_t *ra = &mac->ra;
ra->t_crnti = 0;
uint8_t n_subPDUs = 0; // number of RAR payloads
uint8_t n_subheaders = 0; // number of MAC RAR subheaders
uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu;
NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer
NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer
uint8_t preamble_index = ra->ra_PreambleIndex;
uint16_t rnti = mac->ra.ra_rnti;
T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot),
T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length));
ra->RA_backoff_limit = 0;
LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index);
while (1) {
n_subheaders++;
if (rarh->T == 1) {
n_subPDUs++;
LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti);
} else {
int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi;
int slots_per_ms = mac->frame_structure.numb_slots_frame / 10;
ra->RA_backoff_limit = bi_ms * slots_per_ms;
LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms);
if (((NR_RA_HEADER_BI *)rarh)->E == 1) {
rarh += sizeof(NR_RA_HEADER_BI);
continue;
} else {
break;
}
nr_ue_process_mac_pdu(mac, dl_info, pdu_id);
}
if (rarh->RAPID == preamble_index) {
// The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after
// successful reception of a Random Access Response containing Random Access Preamble identifiers
// that matches the transmitted PREAMBLE_INDEX.
nr_timer_stop(&ra->response_window_timer);
LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID);
rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR));
handle_rar_reception(mac, rar, frame, slot);
if (ra->cfra)
nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot);
break;
case FAPI_NR_RX_PDU_TYPE_RAR :
nr_ue_process_rar(mac, dl_info, pdu_id);
}
if (rarh->E == 0) {
LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] Received RAR preamble (%d) doesn't match the intended RAPID (%d)\n",
mac->ue_id,
frame,
slot,
rarh->RAPID,
preamble_index);
// resume RAR response window timer if MSG2 decoding failed
nr_timer_suspension(&mac->ra.response_window_timer);
break;
default :
AssertFatal(false, "Invalid DLSCH PDU type\n");
} else {
rarh += sizeof(NR_MAC_RAR) + 1;
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
#ifdef DEBUG_RAR
LOG_D(NR_MAC,
"[DEBUG_RAR] (%d,%d) number of RAR subheader %d; number of RAR pyloads %d\n",
frame,
slot,
n_subheaders,
n_subPDUs);
LOG_D(NR_MAC,
"[DEBUG_RAR] Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n",
*(uint8_t *) rarh,
rar[0],
rar[1],
rar[2],
rar[3],
rar[4],
rar[5],
rarh->RAPID,
preamble_index);
#endif
return;
}
// #define EXTRACT_DCI_ITEM(val,size) val= readBits(dci_pdu, &pos, size);
......@@ -3615,17 +3754,25 @@ static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
return format;
}
static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, int frame, int slot)
nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci)
{
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment;
ul_time_alignment->ta_command = ta;
ul_time_alignment->ta_apply = type;
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER;
ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame;
// start or restart the timeAlignmentTimer associated with the indicated TAG
nr_timer_start(&mac->time_alignment_timer);
LOG_D(NR_MAC,
"Received dci indication (rnti %x, dci format %d, n_CCE %d, payloadSize %d, payload %llx)\n",
dci->rnti,
dci->dci_format,
dci->n_CCE,
dci->payloadSize,
*(unsigned long long *)dci->payloadBits);
const nr_dci_format_t format =
nr_extract_dci_info(mac, dci->dci_format, dci->payloadSize, dci->rnti, dci->ss_type, dci->payloadBits, slot);
if (format == NR_DCI_NONE)
return NR_DCI_NONE;
int ret = nr_ue_process_dci(mac, frame, slot, mac->def_dci_pdu_rel15[slot] + format, dci, format);
if (ret < 0) {
mac->stats.bad_dci++;
return NR_DCI_NONE;
}
return format;
}
static bool check_ra_contention_resolution(const uint8_t *pdu, const uint8_t *cont_res)
......@@ -4055,240 +4202,36 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
return mac_ce - pdu;
}
static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot)
{
RAR_grant_t rar_grant;
RA_config_t *ra = &mac->ra;
#ifdef DEBUG_RAR
// CSI
unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01);
#endif
// TPC
unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07);
ra->Msg3_TPC = (tpc_command << 1) - 6;
// MCS
rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4);
// time alloc
rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f);
// frequency alloc
rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12));
// frequency hopping
rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2);
// Schedule Msg3
const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id];
const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id);
NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP,
*ra_SS->controlResourceSetId,
ra_SS->searchSpaceType->present,
TYPE_RA_RNTI_,
rar_grant.Msg3_t_alloc);
if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) {
LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n");
// resume RAR response window timer if MSG2 decoding failed
nr_timer_suspension(&mac->ra.response_window_timer);
return;
}
frame_t frame_tx = 0;
int slot_tx = 0;
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs);
int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset);
// TA command
// if the timeAlignmentTimer associated with this TAG is not running
if (!nr_timer_is_active(&mac->time_alignment_timer)) {
const int ta = rar->TA2 + (rar->TA1 << 5);
set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx);
LOG_W(MAC, "received TA command %d\n", 31 + ta);
}
// else ignore the received Timing Advance Command
#ifdef DEBUG_RAR
LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E);
LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T);
LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID);
LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R);
LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1);
LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2);
LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1);
LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2);
LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3);
LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4);
LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1);
LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2);
LOG_I(NR_MAC,
"[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n",
frame,
slot,
mac->ue_id,
rar_grant.Msg3_t_alloc,
rar_grant.Msg3_f_alloc,
ta_command,
rar_grant.mcs,
rar_grant.freq_hopping,
tpc_command);
#endif
if (ret != -1) {
uint16_t rnti = mac->crnti;
// Upon successful reception, set the T-CRNTI to the RAR value
// if the RA preamble is selected among the contention-based RA Preambles
if (!ra->cfra) {
ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8);
rnti = ra->t_crnti;
if (!mac->msg3_C_RNTI)
nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false);
}
fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
if (!pdu)
return;
// Config Msg3 PDU
int ret = nr_config_pusch_pdu(mac,
&tda_info,
&pdu->pusch_config_pdu,
NULL,
NULL,
&rar_grant,
rnti,
NR_SearchSpace__searchSpaceType_PR_common,
NR_DCI_NONE);
if (ret != 0)
remove_ul_config_last_item(pdu);
release_ul_config(pdu, false);
}
}
/////////////////////////////////////
// Random Access Response PDU //
// TS 38.213 ch 8.2 //
// TS 38.321 ch 6.2.3 //
/////////////////////////////////////
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise
//| E | T | R A P I D |//
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |//
//| R | T A |//
//| T A | UL grant |//
//| UL grant |//
//| UL grant |//
//| UL grant |//
//| T C - R N T I |//
//| T C - R N T I |//
/////////////////////////////////////
// UL grant (27 bits) //
/////////////////////////////////////
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise
//|-------------------|FHF|F_alloc|//
//| Freq allocation |//
//| F_alloc |Time allocation|//
//| MCS | TPC |CSI|//
/////////////////////////////////////
// TbD WIP Msg3 development ongoing
// - apply UL grant freq alloc & time alloc as per 8.2 TS 38.213
// - apply tpc command
// WIP fix:
// - time domain indication hardcoded to 0 for k2 offset
// - extend TS 38.213 ch 8.3 Msg3 PUSCH
// - b buffer
// - ulsch power offset
// - optimize: mu_pusch, j and table_6_1_2_1_1_2_time_dom_res_alloc_A are already defined in nr_ue_procedures
static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id)
void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id)
{
frame_t frame = dl_info->frame;
int slot = dl_info->slot;
if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack == 0) {
LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] CRC check failed on RAR (NAK)\n", mac->ue_id, frame, slot);
return;
}
RA_config_t *ra = &mac->ra;
ra->t_crnti = 0;
uint8_t n_subPDUs = 0; // number of RAR payloads
uint8_t n_subheaders = 0; // number of MAC RAR subheaders
uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu;
NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer
NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer
uint8_t preamble_index = ra->ra_PreambleIndex;
uint16_t rnti = mac->ra.ra_rnti;
T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot),
T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN);
ra->RA_backoff_limit = 0;
LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index);
LOG_D(NR_MAC,
"In [%d.%d] Handling DLSCH PDU type %d\n",
dl_info->frame,
dl_info->slot,
dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type);
while (1) {
n_subheaders++;
if (rarh->T == 1) {
n_subPDUs++;
LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti);
} else {
int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi;
int slots_per_ms = mac->frame_structure.numb_slots_frame / 10;
ra->RA_backoff_limit = bi_ms * slots_per_ms;
LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms);
if (((NR_RA_HEADER_BI *)rarh)->E == 1) {
rarh += sizeof(NR_RA_HEADER_BI);
continue;
} else {
// Processing MAC PDU
// it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs
switch (dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type) {
case FAPI_NR_RX_PDU_TYPE_DLSCH :
// start or restart dataInactivityTimer if any MAC entity receives a MAC SDU for DTCH logical channel,
// DCCH logical channel, or CCCH logical channel
if (mac->data_inactivity_timer)
nr_timer_start(mac->data_inactivity_timer);
// DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
trigger_MAC_UE_RA(mac, NULL);
break;
}
}
if (rarh->RAPID == preamble_index) {
// The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after
// successful reception of a Random Access Response containing Random Access Preamble identifiers
// that matches the transmitted PREAMBLE_INDEX.
nr_timer_stop(&ra->response_window_timer);
LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID);
rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR));
handle_rar_reception(mac, rar, frame, slot);
if (ra->cfra)
nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot);
nr_ue_process_mac_pdu(mac, dl_info, pdu_id);
break;
}
if (rarh->E == 0) {
LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] Received RAR preamble (%d) doesn't match the intended RAPID (%d)\n",
mac->ue_id,
frame,
slot,
rarh->RAPID,
preamble_index);
// resume RAR response window timer if MSG2 decoding failed
nr_timer_suspension(&mac->ra.response_window_timer);
case FAPI_NR_RX_PDU_TYPE_RAR :
nr_ue_process_rar(mac, dl_info, pdu_id);
break;
} else {
rarh += sizeof(NR_MAC_RAR) + 1;
}
default :
AssertFatal(false, "Invalid DLSCH PDU type\n");
}
#ifdef DEBUG_RAR
LOG_D(NR_MAC,
"[DEBUG_RAR] (%d,%d) number of RAR subheader %d; number of RAR pyloads %d\n",
frame,
slot,
n_subheaders,
n_subPDUs);
LOG_D(NR_MAC,
"[DEBUG_RAR] Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n",
*(uint8_t *) rarh,
rar[0],
rar[1],
rar[2],
rar[3],
rar[4],
rar[5],
rarh->RAPID,
preamble_index);
#endif
return;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
}
......@@ -57,30 +57,6 @@
AssertFatal(ret == 0, "Failure in mutex management ret=%d\n", a); \
}
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP);
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac);
static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac,
NR_SINGLE_ENTRY_PHR_MAC_CE *phr,
float P_CMAX,
float tx_power,
frame_t frame,
slot_t slot);
static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac,
int cc_id,
frame_t frame,
slot_t slot,
uint8_t gNB_index,
uint8_t *ulsch_buffer,
const uint32_t buflen,
int tx_power,
int P_MAX,
bool *BSRsent);
static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP);
static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot);
static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot);
static void clear_ul_config_request(NR_UE_MAC_INST_t *mac)
{
int slots = mac->frame_structure.numb_slots_frame;
......@@ -1131,6 +1107,205 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame,
return srs_scheduled;
}
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac)
{
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment;
fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu;
ta->ta_frame = ul_time_alignment->frame;
ta->ta_slot = ul_time_alignment->slot;
ta->is_rar = ul_time_alignment->ta_apply == rar_ta;
ta->ta_command = ul_time_alignment->ta_command;
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND;
dl_config->number_pdus += 1;
ul_time_alignment->ta_apply = no_ta;
}
static NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measconfig,
NR_BWP_Id_t dl_bwp_id,
NR_NZP_CSI_RS_ResourceId_t csi_id)
{
bool found = false;
for (int csi_list = 0; csi_list < csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list];
if(csires->bwp_Id != dl_bwp_id)
continue;
struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList *resset = &csires->csi_RS_ResourceSetList;
if(resset->present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB)
continue;
if(!resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)
continue;
for(int i = 0; i < resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count; i++) {
NR_NZP_CSI_RS_ResourceSetId_t *res_id = resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[i];
AssertFatal(res_id, "NR_NZP_CSI_RS_ResourceSetId shouldn't be NULL\n");
struct NR_CSI_MeasConfig__nzp_CSI_RS_ResourceSetToAddModList *res_list = csi_measconfig->nzp_CSI_RS_ResourceSetToAddModList;
AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n");
for (int j = 0; j < res_list->list.count; j++) {
NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j];
if (*res_id != csi_res->nzp_CSI_ResourceSetId)
continue;
for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) {
AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) {
found = true;
break;
}
}
if (found && csi_res->trs_Info)
// CRI-RS for Tracking (not implemented yet)
// in this case we there is no associated CSI report
// therefore to signal this we return a value higher than
// maxNrofCSI-ResourceConfigurations
return NR_maxNrofCSI_ResourceConfigurations + 1;
else if (found)
return csires->csi_ResourceConfigId;
}
}
}
return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID
}
static uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id)
{
uint8_t meas_bitmap = 0;
if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
return meas_bitmap; // CSI-RS for tracking
for(int i = 0; i < csi_measconfig->csi_ReportConfigToAddModList->list.count; i++) {
NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i];
if(report_config->resourcesForChannelMeasurement != csi_res_id)
continue;
// bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1
switch (report_config->reportQuantity.present) {
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
meas_bitmap += (1 << 1) + (1 << 5);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
meas_bitmap += (1 << 1) + (1 << 4);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
meas_bitmap += 1;
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4);
break;
default:
AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
}
}
return meas_bitmap;
}
static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
if (!mac->sc_info.csi_MeasConfig)
return;
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL)
return;
fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id;
int mu = current_DL_BWP->scs;
uint16_t bwp_size = current_DL_BWP->BWPSize;
uint16_t bwp_start = current_DL_BWP->BWPStart;
for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++) {
NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id];
int period, offset;
csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset);
if((frame * mac->frame_structure.numb_slots_frame + slot-offset) % period != 0)
continue;
NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId);
// do not schedule reseption of this CSI-RS if not associated with current BWP
if(csi_res_id < 0)
continue;
LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot);
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csirs_config_pdu.csirs_config_rel15;
csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id);
csirs_config_pdu->subcarrier_spacing = mu;
csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0;
if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
csirs_config_pdu->csi_type = 0; // TRS
else
csirs_config_pdu->csi_type = 1; // NZP-CSI-RS
csirs_config_pdu->scramb_id = nzpcsi->scramblingID;
csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8;
if (nzpcsi->powerControlOffsetSS)
csirs_config_pdu->power_control_offset_ss = *nzpcsi->powerControlOffsetSS;
else
csirs_config_pdu->power_control_offset_ss = 1; // 0 dB
configure_csi_resource_mapping(csirs_config_pdu, &nzpcsi->resourceMapping, bwp_size, bwp_start);
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS;
dl_config->number_pdus += 1;
}
}
static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
if (!mac->sc_info.csi_MeasConfig)
return;
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (csi_measconfig->csi_IM_ResourceToAddModList == NULL)
return;
fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
NR_CSI_IM_Resource_t *imcsi;
int period, offset;
NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
int mu = current_DL_BWP->scs;
uint16_t bwp_size = current_DL_BWP->BWPSize;
uint16_t bwp_start = current_DL_BWP->BWPStart;
for (int id = 0; id < csi_measconfig->csi_IM_ResourceToAddModList->list.count; id++){
imcsi = csi_measconfig->csi_IM_ResourceToAddModList->list.array[id];
csi_period_offset(NULL,imcsi->periodicityAndOffset,&period,&offset);
if((frame * mac->frame_structure.numb_slots_frame + slot - offset ) %period != 0)
continue;
fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csiim_config_pdu.csiim_config_rel15;
csiim_config_pdu->bwp_size = bwp_size;
csiim_config_pdu->bwp_start = bwp_start;
csiim_config_pdu->subcarrier_spacing = mu;
csiim_config_pdu->start_rb = imcsi->freqBand->startingRB;
csiim_config_pdu->nr_of_rbs = imcsi->freqBand->nrofRBs;
// As specified in 5.2.2.4 of 38.214
switch (imcsi->csi_IM_ResourceElementPattern->present) {
case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0:
for (int i = 0; i < 4; i++) {
csiim_config_pdu->k_csiim[i] =
(imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1);
csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2);
}
break;
case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1:
for (int i = 0; i < 4; i++) {
csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i;
csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1;
}
break;
default:
AssertFatal(1 == 0, "Invalid CSI-IM pattern\n");
}
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM;
dl_config->number_pdus += 1;
}
}
// Performs :
// 1. TODO: Call RRC for link status return to PHY
// 2. TODO: Perform SR/BSR procedures for scheduling feedback
......@@ -1341,770 +1516,36 @@ static void nr_update_bsr(NR_UE_MAC_INST_t *mac, uint32_t *LCG_bytes)
}
}
void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods)
{
int cc_id = ul_info->cc_id;
frame_t frame_tx = ul_info->frame;
slot_t slot_tx = ul_info->slot;
uint32_t gNB_index = ul_info->gNB_index;
int config_period = prach_occasion_info->frame_info[0];
int frame_period = config_period * association_periods;
int frame_in_period = frame % frame_period;
if (association_periods > 1) {
int current_assoc_period = frame_in_period / config_period;
if (current_assoc_period != prach_occasion_info->association_period_idx)
return false;
frame_in_period %= config_period;
}
if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211)
return true;
else
return false;
}
// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
// - todo:
// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP)
{
RA_config_t *ra = &mac->ra;
if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) {
init_RA(mac, frame_tx);
// perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a)
ra_resource_selection(mac);
}
if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE)
nr_ue_prach_scheduler(mac, frame_tx, slot_tx);
// Get any valid PRACH occasion in the current slot for the selected SSB index
prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info;
bool BSRsent = false;
if (mac->state == UE_CONNECTED) {
nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx);
nr_update_rlc_buffers_status(mac, frame_tx, slot_tx, gNB_index);
}
// Schedule ULSCH only if the current frame and slot match those in ul_config_req
// AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus)
uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
int number_of_pdus = 0;
fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
if (!ulcfg_pdu)
return;
LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx);
while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus];
if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
nfapi_nr_ue_pusch_pdu_t *pdu = &ulcfg_pdu->pusch_config_pdu;
uint32_t TBS_bytes = pdu->pusch_data.tb_size;
LOG_D(NR_MAC,
"harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n",
pdu->pusch_data.harq_process_id,
pdu->pusch_data.new_data_indicator,
TBS_bytes,
ra->ra_state);
pdu->tx_request_body.fapiTxPdu = NULL;
if ((ra->ra_state == nrRA_WAIT_RAR || ra->ra_state == nrRA_WAIT_MSGB) && !ra->cfra) {
nr_get_Msg3_MsgA_PUSCH_payload(mac, ulsch_input_buffer, TBS_bytes);
for (int k = 0; k < TBS_bytes; k++) {
LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]);
}
pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer;
pdu->tx_request_body.pdu_length = TBS_bytes;
number_of_pdus++;
T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx),
T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes));
} else {
if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator
&& (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) {
if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
// UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
trigger_MAC_UE_RA(mac, NULL);
return;
}
// Getting IP traffic to be transmitted
int tx_power = pdu->tx_power;
int P_CMAX = nr_get_Pcmax(mac->p_Max,
mac->nr_band,
mac->frame_structure.frame_type,
mac->frequency_range,
mac->current_UL_BWP->channel_bandwidth,
pdu->qam_mod_order,
false,
mac->current_UL_BWP->scs,
mac->current_UL_BWP->BWPSize,
pdu->transform_precoding,
pdu->rb_size,
pdu->rb_start);
nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes, tx_power, P_CMAX, &BSRsent);
pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer;
pdu->tx_request_body.pdu_length = TBS_bytes;
number_of_pdus++;
T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx),
T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes));
// start or restart dataInactivityTimer if any MAC entity transmits a MAC SDU for DTCH logical channel,
// or DCCH logical channel
if (mac->data_inactivity_timer)
nr_timer_start(mac->data_inactivity_timer);
}
}
if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) {
LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx);
// 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3
// transmission
nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
}
if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
}
if (ra->ra_state == nrRA_WAIT_MSGB && !ra->cfra) {
LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-MsgA-PUSCH transmitted\n", frame_tx, slot_tx);
}
}
ulcfg_pdu++;
}
release_ul_config(ulcfg_pdu, false);
if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING)
nr_ue_pucch_scheduler(mac, frame_tx, slot_tx);
if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx,
.mac = mac,
.module_id = mac->ue_id,
.CC_id = cc_id,
.phy_data = ul_info->phy_data};
mac->if_module->scheduled_response(&scheduled_response);
}
if(mac->state == UE_CONNECTED)
nr_update_sr(mac, BSRsent);
// Global variables implicit logic
// far away, BSR_reporting_active is set
mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE;
// update Bj for all active lcids before LCP procedure
if (mac->current_UL_BWP) {
LOG_D(NR_MAC, "%4d.%2d Logical Channel Prioritization\n", frame_tx, slot_tx);
for (int i = 0; i < mac->lc_ordered_list.count; i++) {
nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
int lcid = lc_info->lcid;
// max amount of data that can be buffered/accumulated in a logical channel buffer
uint32_t bucketSize_max = lc_info->bucket_size;
// measure Bj increment the value of Bj by product PBR * T
NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
int32_t bj = sched_info->Bj;
if (lc_info->pbr < UINT_MAX) {
uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented
// it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s
uint32_t pbr_ms = lc_info->pbr / 1000;
bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms
}
else
bj = INT_MAX;
// bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization
sched_info->Bj = min(bj, bucketSize_max);
// reset bj timer
nr_timer_start(&sched_info->Bj_timer);
}
}
}
static uint8_t nr_locate_BsrIndexByBufferSize(int size, int value)
{
if (value == 0) {
return 0; //elseif (value > 150000) return 63;
}
uint32_t (*get_bsr_value)(int);
if (size == NR_SHORT_BSR_TABLE_SIZE)
get_bsr_value = &get_short_bsr_value;
else
get_bsr_value = &get_long_bsr_value;
int jl = 0; // lower bound
int ju = size - 1; // upper bound
// determine the order of the the table: 1 if ascending order of table, 0 otherwise
bool ascend = (*get_bsr_value)(ju) >= (*get_bsr_value)(jl) ? 1 : 0;
while (ju - jl > 1) { //If we are not yet done,
int jm = (ju + jl) / 2; // compute a midpoint,
if ((value >= (*get_bsr_value)(jm)) == ascend) {
jl = jm; // replace the lower limit
} else {
ju = jm; //replace the upper limit
}
LOG_T(NR_MAC,
"[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n",
jm,
(*get_bsr_value)(jm),
value);
}
if (value == (*get_bsr_value)(jl)) {
return jl;
} else {
return jl + 1; //equally ju
}
}
// PUSCH scheduler:
// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// - where K2 is the offset between the slot in which UL DCI is received and the slot
// - in which ULSCH should be scheduled. K2 is configured in RRC configuration.
// PUSCH Msg3 scheduler:
// - scheduled by RAR UL grant according to 8.3 of TS 38.213
// Note: Msg3 tx in the uplink symbols of mixed slot
int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
const uint8_t is_Msg3,
const frame_t current_frame,
const int current_slot,
frame_t *frame_tx,
int *slot_tx,
const long k2)
{
int delta = 0;
const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
// Get the numerology to calculate the Tx frame and slot
int mu = current_UL_BWP->scs;
int slots_per_frame = mac->frame_structure.numb_slots_frame;
// k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1
// PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon
if (is_Msg3) {
delta = get_delta_for_k2(mu);
AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
"Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to "
"%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
k2,
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu));
*slot_tx = (current_slot + k2 + delta) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER;
} else {
AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in "
"gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
k2,
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu));
if (k2 < 0) { // This can happen when a false DCI is received
LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2);
return -1;
}
// Calculate TX slot and frame
*slot_tx = (current_slot + k2) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER;
}
LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta);
return 0;
}
static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac,
frame_t frame_tx,
int slot_tx,
const PUCCH_sched_t *pucch,
NR_UE_UL_BWP_t *current_UL_BWP)
{
fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
if (!ulcfg_pdu)
return NULL;
nfapi_nr_ue_pusch_pdu_t *pusch_pdu = NULL;
while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
int start_pusch = ulcfg_pdu->pusch_config_pdu.start_symbol_index;
int nsymb_pusch = ulcfg_pdu->pusch_config_pdu.nr_of_symbols;
int end_pusch = start_pusch + nsymb_pusch;
NR_PUCCH_Resource_t *pucchres = pucch->pucch_resource;
int nr_of_symbols = 0;
int start_symbol_index = 0;
if (pucch->initial_pucch_id > -1 && pucch->pucch_resource == NULL) {
const int idx = *current_UL_BWP->pucch_ConfigCommon->pucch_ResourceCommon;
const initial_pucch_resource_t pucch_resourcecommon = get_initial_pucch_resource(idx);
start_symbol_index = pucch_resourcecommon.startingSymbolIndex;
nr_of_symbols = pucch_resourcecommon.nrofSymbols;
}
else {
switch(pucchres->format.present) {
case NR_PUCCH_Resource__format_PR_format0 :
nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format1 :
nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format2 :
nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format3 :
nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format4 :
nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
break;
default :
AssertFatal(false, "Undefined PUCCH format \n");
}
}
int final_symbol = nr_of_symbols + start_symbol_index;
// PUCCH overlapping in time with PUSCH
if (start_symbol_index < end_pusch && final_symbol > start_pusch) {
pusch_pdu = &ulcfg_pdu->pusch_config_pdu;
break;
}
}
ulcfg_pdu++;
}
if (!pusch_pdu) {
release_ul_config(ulcfg_pdu, false);
return false;
}
// If a UE would transmit on a serving cell a PUSCH without UL-SCH that overlaps with a PUCCH transmission
// on a serving cell that includes positive SR information, the UE does not transmit the PUSCH.
if (pusch_pdu && pusch_pdu->ulsch_indicator == 0 && pucch->sr_payload == 1) {
release_ul_config(ulcfg_pdu, false);
return false;
}
// - UE multiplexes only HARQ-ACK information, if any, from the UCI in the PUSCH transmission
// and does not transmit the PUCCH if the UE multiplexes aperiodic or semi-persistent CSI reports in the PUSCH
// - UE multiplexes only HARQ-ACK information and CSI reports, if any, from the UCI in the PUSCH transmission
// and does not transmit the PUCCH if the UE does not multiplex aperiodic or semi-persistent CSI reports in the PUSCH
bool mux_done = false;
if (pucch->n_harq > 0) {
NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
if (pusch_Config && pusch_Config->uci_OnPUSCH) {
NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
AssertFatal(onPusch &&
onPusch->betaOffsets &&
onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
"Only semistatic beta offset is supported\n");
NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;
pusch_pdu->pusch_uci.harq_ack_bit_length = pucch->n_harq;
pusch_pdu->pusch_uci.harq_payload = pucch->ack_payload;
pusch_pdu->pusch_uci.beta_offset_harq_ack = pucch->n_harq > 2 ?
(pucch->n_harq < 12 ? *beta_offsets->betaOffsetACK_Index2 :
*beta_offsets->betaOffsetACK_Index3) :
*beta_offsets->betaOffsetACK_Index1;
pusch_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
mux_done = true;
} else {
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule UCI on PUSCH\n");
}
}
if (pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0) {
// To support this we would need to shift some bits into CSI part2 -> need to change the logic
AssertFatal(pucch->n_csi == 0, "Multiplexing periodic CSI on PUSCH not supported\n");
}
release_ul_config(ulcfg_pdu, false);
// only use PUSCH if any mux is done otherwise send PUCCH
return mux_done;
}
static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot)
{
PUCCH_sched_t pucch[3] = {0}; // TODO the size might change in the future in case of multiple SR or multiple CSI in a slot
int num_res = 0;
if (mac->ra.ra_pucch) {
// scheduling PUCCH prepared in advance for MSG4
RA_PUCCH_SCHED_t *ra_pucch = mac->ra.ra_pucch;
if (ra_pucch->sched_frame == frame && ra_pucch->sched_slot == slot) {
pucch[0] = ra_pucch->pucch_sched;
num_res++;
free_and_zero(mac->ra.ra_pucch);
}
} else {
// SR
if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frame, slot)) {
num_res++;
// TODO check if the PUCCH resource for the SR transmission occasion overlap with a UL-SCH resource
}
// CSI
int csi_res = 0;
if (mac->state == UE_CONNECTED)
csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res]);
if (csi_res > 0) {
num_res += csi_res;
}
// ACKNACK
bool any_harq = get_downlink_ack(mac, frame, slot, &pucch[num_res]);
if (any_harq)
num_res++;
if (num_res == 0)
return;
// do no transmit pucch if only SR scheduled and it is negative
if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0)
return;
if (num_res > 1)
multiplex_pucch_resource(mac, pucch, num_res);
}
for (int j = 0; j < num_res; j++) {
if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) {
LOG_D(NR_MAC,
"%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n",
frame,
slot,
pucch[j].n_harq,
pucch[j].n_sr,
pucch[j].n_csi);
// checking if we need to schedule pucch[j] on PUSCH
if (schedule_uci_on_pusch(mac, frame, slot, &pucch[j], mac->current_UL_BWP))
continue;
fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
if (!pdu) {
LOG_E(NR_MAC, "Error in pucch allocation\n");
return;
}
int ret = nr_ue_configure_pucch(mac,
slot,
frame,
mac->crnti, // FIXME not sure this is valid for all pucch instances
&pucch[j],
&pdu->pucch_config_pdu);
if (ret != 0)
remove_ul_config_last_item(pdu);
release_ul_config(pdu, false);
}
}
}
static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
if (!mac->sc_info.csi_MeasConfig)
return;
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (csi_measconfig->csi_IM_ResourceToAddModList == NULL)
return;
fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
NR_CSI_IM_Resource_t *imcsi;
int period, offset;
NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
int mu = current_DL_BWP->scs;
uint16_t bwp_size = current_DL_BWP->BWPSize;
uint16_t bwp_start = current_DL_BWP->BWPStart;
for (int id = 0; id < csi_measconfig->csi_IM_ResourceToAddModList->list.count; id++){
imcsi = csi_measconfig->csi_IM_ResourceToAddModList->list.array[id];
csi_period_offset(NULL,imcsi->periodicityAndOffset,&period,&offset);
if((frame * mac->frame_structure.numb_slots_frame + slot - offset ) %period != 0)
continue;
fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csiim_config_pdu.csiim_config_rel15;
csiim_config_pdu->bwp_size = bwp_size;
csiim_config_pdu->bwp_start = bwp_start;
csiim_config_pdu->subcarrier_spacing = mu;
csiim_config_pdu->start_rb = imcsi->freqBand->startingRB;
csiim_config_pdu->nr_of_rbs = imcsi->freqBand->nrofRBs;
// As specified in 5.2.2.4 of 38.214
switch (imcsi->csi_IM_ResourceElementPattern->present) {
case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0:
for (int i = 0; i < 4; i++) {
csiim_config_pdu->k_csiim[i] =
(imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1);
csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2);
}
break;
case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1:
for (int i = 0; i < 4; i++) {
csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i;
csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1;
}
break;
default:
AssertFatal(1 == 0, "Invalid CSI-IM pattern\n");
}
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM;
dl_config->number_pdus += 1;
}
}
NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measconfig,
NR_BWP_Id_t dl_bwp_id,
NR_NZP_CSI_RS_ResourceId_t csi_id)
{
bool found = false;
for (int csi_list = 0; csi_list < csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list];
if(csires->bwp_Id != dl_bwp_id)
continue;
struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList *resset = &csires->csi_RS_ResourceSetList;
if(resset->present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB)
continue;
if(!resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)
continue;
for(int i = 0; i < resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count; i++) {
NR_NZP_CSI_RS_ResourceSetId_t *res_id = resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[i];
AssertFatal(res_id, "NR_NZP_CSI_RS_ResourceSetId shouldn't be NULL\n");
struct NR_CSI_MeasConfig__nzp_CSI_RS_ResourceSetToAddModList *res_list = csi_measconfig->nzp_CSI_RS_ResourceSetToAddModList;
AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n");
for (int j = 0; j < res_list->list.count; j++) {
NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j];
if (*res_id != csi_res->nzp_CSI_ResourceSetId)
continue;
for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) {
AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) {
found = true;
break;
}
}
if (found && csi_res->trs_Info)
// CRI-RS for Tracking (not implemented yet)
// in this case we there is no associated CSI report
// therefore to signal this we return a value higher than
// maxNrofCSI-ResourceConfigurations
return NR_maxNrofCSI_ResourceConfigurations + 1;
else if (found)
return csires->csi_ResourceConfigId;
}
}
}
return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID
}
uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id)
{
uint8_t meas_bitmap = 0;
if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
return meas_bitmap; // CSI-RS for tracking
for(int i = 0; i < csi_measconfig->csi_ReportConfigToAddModList->list.count; i++) {
NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i];
if(report_config->resourcesForChannelMeasurement != csi_res_id)
continue;
// bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1
switch (report_config->reportQuantity.present) {
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
meas_bitmap += (1 << 1) + (1 << 5);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
meas_bitmap += (1 << 1) + (1 << 4);
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
meas_bitmap += 1;
break;
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4);
break;
default:
AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
}
}
return meas_bitmap;
}
void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
const NR_CSI_RS_ResourceMapping_t *resourceMapping,
uint32_t bwp_size,
uint32_t bwp_start)
{
// According to last paragraph of TS 38.214 5.2.2.3.1
if (resourceMapping->freqBand.startingRB < bwp_start)
csirs_config_pdu->start_rb = bwp_start;
else
csirs_config_pdu->start_rb = resourceMapping->freqBand.startingRB;
if (resourceMapping->freqBand.nrofRBs > (bwp_start + bwp_size - csirs_config_pdu->start_rb))
csirs_config_pdu->nr_of_rbs = bwp_start + bwp_size - csirs_config_pdu->start_rb;
else
csirs_config_pdu->nr_of_rbs = resourceMapping->freqBand.nrofRBs;
AssertFatal(csirs_config_pdu->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_config_pdu->nr_of_rbs);
csirs_config_pdu->symb_l0 = resourceMapping->firstOFDMSymbolInTimeDomain;
if (resourceMapping->firstOFDMSymbolInTimeDomain2)
csirs_config_pdu->symb_l1 = *resourceMapping->firstOFDMSymbolInTimeDomain2;
csirs_config_pdu->cdm_type = resourceMapping->cdm_Type;
csirs_config_pdu->freq_density = resourceMapping->density.present;
if ((resourceMapping->density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5)
&& (resourceMapping->density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs))
csirs_config_pdu->freq_density--;
switch(resourceMapping->frequencyDomainAllocation.present){
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
csirs_config_pdu->row = 1;
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
csirs_config_pdu->row = 2;
csirs_config_pdu->freq_domain = (((resourceMapping->frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f)
| ((resourceMapping->frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0));
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
csirs_config_pdu->row = 4;
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f;
// determining the row of table 7.4.1.5.3-1 in 38.211
switch (resourceMapping->nrofPorts) {
case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n");
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
csirs_config_pdu->row = 3;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
csirs_config_pdu->row = 5;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p8:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 8;
else {
int num_k = 0;
for (int k = 0; k < 6; k++)
num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01);
if (num_k == 4)
csirs_config_pdu->row = 6;
else
csirs_config_pdu->row = 7;
}
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p12:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 10;
else
csirs_config_pdu->row = 9;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p16:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 12;
else
csirs_config_pdu->row = 11;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 14;
else {
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
csirs_config_pdu->row = 15;
else
csirs_config_pdu->row = 13;
}
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 17;
else {
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
csirs_config_pdu->row = 18;
else
csirs_config_pdu->row = 16;
}
break;
default:
AssertFatal(false, "Invalid number of ports in CSI-RS resource\n");
}
break;
default:
AssertFatal(false, "Invalid freqency domain allocation in CSI-RS resource\n");
}
}
static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
if (!mac->sc_info.csi_MeasConfig)
return;
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL)
return;
fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id;
int mu = current_DL_BWP->scs;
uint16_t bwp_size = current_DL_BWP->BWPSize;
uint16_t bwp_start = current_DL_BWP->BWPStart;
for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++) {
NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id];
int period, offset;
csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset);
if((frame * mac->frame_structure.numb_slots_frame + slot-offset) % period != 0)
continue;
NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId);
// do not schedule reseption of this CSI-RS if not associated with current BWP
if(csi_res_id < 0)
continue;
LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot);
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csirs_config_pdu.csirs_config_rel15;
csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id);
csirs_config_pdu->subcarrier_spacing = mu;
csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0;
if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
csirs_config_pdu->csi_type = 0; // TRS
else
csirs_config_pdu->csi_type = 1; // NZP-CSI-RS
csirs_config_pdu->scramb_id = nzpcsi->scramblingID;
csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8;
if (nzpcsi->powerControlOffsetSS)
csirs_config_pdu->power_control_offset_ss = *nzpcsi->powerControlOffsetSS;
else
csirs_config_pdu->power_control_offset_ss = 1; // 0 dB
configure_csi_resource_mapping(csirs_config_pdu, &nzpcsi->resourceMapping, bwp_size, bwp_start);
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS;
dl_config->number_pdus += 1;
}
}
static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods)
{
int config_period = prach_occasion_info->frame_info[0];
int frame_period = config_period * association_periods;
int frame_in_period = frame % frame_period;
if (association_periods > 1) {
int current_assoc_period = frame_in_period / config_period;
if (current_assoc_period != prach_occasion_info->association_period_idx)
return false;
frame_in_period %= config_period;
}
if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211)
return true;
else
return false;
}
// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
// - todo:
// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP)
{
RA_config_t *ra = &mac->ra;
// Get any valid PRACH occasion in the current slot for the selected SSB index
prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info;
if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods))
return;
if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods))
return;
if (is_ul_slot(slotP, &mac->frame_structure)) {
if (slotP == prach_occasion_info->slot) {
......@@ -2250,6 +1691,230 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
} // if is_nr_UL_slot
}
static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac,
frame_t frame_tx,
int slot_tx,
const PUCCH_sched_t *pucch,
NR_UE_UL_BWP_t *current_UL_BWP)
{
fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
if (!ulcfg_pdu)
return NULL;
nfapi_nr_ue_pusch_pdu_t *pusch_pdu = NULL;
while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
int start_pusch = ulcfg_pdu->pusch_config_pdu.start_symbol_index;
int nsymb_pusch = ulcfg_pdu->pusch_config_pdu.nr_of_symbols;
int end_pusch = start_pusch + nsymb_pusch;
NR_PUCCH_Resource_t *pucchres = pucch->pucch_resource;
int nr_of_symbols = 0;
int start_symbol_index = 0;
if (pucch->initial_pucch_id > -1 && pucch->pucch_resource == NULL) {
const int idx = *current_UL_BWP->pucch_ConfigCommon->pucch_ResourceCommon;
const initial_pucch_resource_t pucch_resourcecommon = get_initial_pucch_resource(idx);
start_symbol_index = pucch_resourcecommon.startingSymbolIndex;
nr_of_symbols = pucch_resourcecommon.nrofSymbols;
}
else {
switch(pucchres->format.present) {
case NR_PUCCH_Resource__format_PR_format0 :
nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format1 :
nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format2 :
nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format3 :
nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
break;
case NR_PUCCH_Resource__format_PR_format4 :
nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
break;
default :
AssertFatal(false, "Undefined PUCCH format \n");
}
}
int final_symbol = nr_of_symbols + start_symbol_index;
// PUCCH overlapping in time with PUSCH
if (start_symbol_index < end_pusch && final_symbol > start_pusch) {
pusch_pdu = &ulcfg_pdu->pusch_config_pdu;
break;
}
}
ulcfg_pdu++;
}
if (!pusch_pdu) {
release_ul_config(ulcfg_pdu, false);
return false;
}
// If a UE would transmit on a serving cell a PUSCH without UL-SCH that overlaps with a PUCCH transmission
// on a serving cell that includes positive SR information, the UE does not transmit the PUSCH.
if (pusch_pdu && pusch_pdu->ulsch_indicator == 0 && pucch->sr_payload == 1) {
release_ul_config(ulcfg_pdu, false);
return false;
}
// - UE multiplexes only HARQ-ACK information, if any, from the UCI in the PUSCH transmission
// and does not transmit the PUCCH if the UE multiplexes aperiodic or semi-persistent CSI reports in the PUSCH
// - UE multiplexes only HARQ-ACK information and CSI reports, if any, from the UCI in the PUSCH transmission
// and does not transmit the PUCCH if the UE does not multiplex aperiodic or semi-persistent CSI reports in the PUSCH
bool mux_done = false;
if (pucch->n_harq > 0) {
NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
if (pusch_Config && pusch_Config->uci_OnPUSCH) {
NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
AssertFatal(onPusch &&
onPusch->betaOffsets &&
onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
"Only semistatic beta offset is supported\n");
NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;
pusch_pdu->pusch_uci.harq_ack_bit_length = pucch->n_harq;
pusch_pdu->pusch_uci.harq_payload = pucch->ack_payload;
pusch_pdu->pusch_uci.beta_offset_harq_ack = pucch->n_harq > 2 ?
(pucch->n_harq < 12 ? *beta_offsets->betaOffsetACK_Index2 :
*beta_offsets->betaOffsetACK_Index3) :
*beta_offsets->betaOffsetACK_Index1;
pusch_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
mux_done = true;
} else {
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule UCI on PUSCH\n");
}
}
if (pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0) {
// To support this we would need to shift some bits into CSI part2 -> need to change the logic
AssertFatal(pucch->n_csi == 0, "Multiplexing periodic CSI on PUSCH not supported\n");
}
release_ul_config(ulcfg_pdu, false);
// only use PUSCH if any mux is done otherwise send PUCCH
return mux_done;
}
static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot)
{
PUCCH_sched_t pucch[3] = {0}; // TODO the size might change in the future in case of multiple SR or multiple CSI in a slot
int num_res = 0;
if (mac->ra.ra_pucch) {
// scheduling PUCCH prepared in advance for MSG4
RA_PUCCH_SCHED_t *ra_pucch = mac->ra.ra_pucch;
if (ra_pucch->sched_frame == frame && ra_pucch->sched_slot == slot) {
pucch[0] = ra_pucch->pucch_sched;
num_res++;
free_and_zero(mac->ra.ra_pucch);
}
} else {
// SR
if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frame, slot)) {
num_res++;
// TODO check if the PUCCH resource for the SR transmission occasion overlap with a UL-SCH resource
}
// CSI
int csi_res = 0;
if (mac->state == UE_CONNECTED)
csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res]);
if (csi_res > 0) {
num_res += csi_res;
}
// ACKNACK
bool any_harq = get_downlink_ack(mac, frame, slot, &pucch[num_res]);
if (any_harq)
num_res++;
if (num_res == 0)
return;
// do no transmit pucch if only SR scheduled and it is negative
if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0)
return;
if (num_res > 1)
multiplex_pucch_resource(mac, pucch, num_res);
}
for (int j = 0; j < num_res; j++) {
if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) {
LOG_D(NR_MAC,
"%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n",
frame,
slot,
pucch[j].n_harq,
pucch[j].n_sr,
pucch[j].n_csi);
// checking if we need to schedule pucch[j] on PUSCH
if (schedule_uci_on_pusch(mac, frame, slot, &pucch[j], mac->current_UL_BWP))
continue;
fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
if (!pdu) {
LOG_E(NR_MAC, "Error in pucch allocation\n");
return;
}
int ret = nr_ue_configure_pucch(mac,
slot,
frame,
mac->crnti, // FIXME not sure this is valid for all pucch instances
&pucch[j],
&pdu->pucch_config_pdu);
if (ret != 0)
remove_ul_config_last_item(pdu);
release_ul_config(pdu, false);
}
}
}
static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac,
NR_SINGLE_ENTRY_PHR_MAC_CE *phr,
float P_CMAX,
float tx_power,
frame_t frame,
slot_t slot)
{
nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info;
// Value mapping according to 38.133 10.1.18.1
const int PC_MAX_00 = -29;
*phr = (NR_SINGLE_ENTRY_PHR_MAC_CE){.PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f};
// Value mapping according to 38.133 10.1.17.1.1
const int POWER_HEADROOM_55 = 22;
int headroom = P_CMAX - tx_power;
if (headroom < POWER_HEADROOM_55) {
const int POWER_HEADROOM_0 = -32;
phr->PH = max(0, headroom - POWER_HEADROOM_0);
} else {
phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2);
}
LOG_D(NR_MAC,
"PHR Reporting sfn.slot %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n",
frame,
slot,
phr_info->phr_reporting,
phr->PCMAX,
P_CMAX,
phr->PH,
headroom,
tx_power);
phr_info->PathlossLastValue = compute_nr_SSB_PL(mac);
// Restart both timers according to 38.321
nr_timer_start(&phr_info->periodicPHR_Timer);
nr_timer_start(&phr_info->prohibitPHR_Timer);
phr_info->phr_reporting = 0;
}
typedef struct {
uint8_t phr_len;
uint sdu_length_total;
......@@ -2265,6 +1930,44 @@ typedef struct {
uint32_t lcp_allocation_counter;
} NR_UE_MAC_CE_INFO;
static uint8_t nr_locate_BsrIndexByBufferSize(int size, int value)
{
if (value == 0) {
return 0; //elseif (value > 150000) return 63;
}
uint32_t (*get_bsr_value)(int);
if (size == NR_SHORT_BSR_TABLE_SIZE)
get_bsr_value = &get_short_bsr_value;
else
get_bsr_value = &get_long_bsr_value;
int jl = 0; // lower bound
int ju = size - 1; // upper bound
// determine the order of the the table: 1 if ascending order of table, 0 otherwise
bool ascend = (*get_bsr_value)(ju) >= (*get_bsr_value)(jl) ? 1 : 0;
while (ju - jl > 1) { //If we are not yet done,
int jm = (ju + jl) / 2; // compute a midpoint,
if ((value >= (*get_bsr_value)(jm)) == ascend) {
jl = jm; // replace the lower limit
} else {
ju = jm; //replace the upper limit
}
LOG_T(NR_MAC,
"[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n",
jm,
(*get_bsr_value)(jm),
value);
}
if (value == (*get_bsr_value)(jl)) {
return jl;
} else {
return jl + 1; //equally ju
}
}
static void nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac,
int CC_id,
frame_t frame,
......@@ -2759,132 +2462,407 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac,
continue;
}
// count number of lc with same priority as lcid
if (!num_lcids_same_priority) {
num_lcids_same_priority = count_same_priority_lcids = get_count_lcids_same_priority(id, avail_lcids_count, lcids_bj_pos);
}
// count number of lc with same priority as lcid
if (!num_lcids_same_priority) {
num_lcids_same_priority = count_same_priority_lcids = get_count_lcids_same_priority(id, avail_lcids_count, lcids_bj_pos);
}
int remain = mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr;
LOG_D(NR_MAC,
"[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x buflen_remain %d bytes)\n",
mac->ue_id,
frame,
slot,
lcid,
remain);
if (num_lcids_same_priority == count_same_priority_lcids) {
buflen_ep = remain < count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG)
? 0
: (remain - (count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG))) / count_same_priority_lcids;
}
while (mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr > 0) {
/*
loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes
depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all
active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates
the target number of bytes to request from RLC via 'mac_rlc_data_req'
*/
if (!fill_mac_sdu(mac,
frame,
slot,
gNB_index,
lcid,
count_same_priority_lcids,
buflen_ep,
lcids_bytes_tot,
&mac_ce_info,
&num_lcids_same_priority,
LCG_bytes)) {
break;
}
}
}
mac_ce_info.lcp_allocation_counter++;
} while (mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr > sizeof(NR_MAC_SUBHEADER_LONG)
&& get_dataavailability_buffers(avail_lcids_count, lcids_bj_pos, mac_ce_info.lcids_data_status));
nr_ue_get_sdu_mac_ce_post(mac, frame, slot, &mac_ce_info, LCG_bytes, BSRsent);
// Compute final offset for padding and fill remainder of ULSCH with 0
int remain = mac_ce_info.pdu_end - mac_ce_info.cur_ptr;
if (remain) {
LOG_D(NR_MAC, "Filling remainder %d bytes to the UL PDU \n", remain);
*(NR_MAC_SUBHEADER_FIXED *)mac_ce_info.cur_ptr = (NR_MAC_SUBHEADER_FIXED){.R = 0, .LCID = UL_SCH_LCID_PADDING};
mac_ce_info.cur_ptr++;
if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
uint8_t *buf = mac_ce_info.cur_ptr;
uint8_t *end = mac_ce_info.pdu_end;
for (; buf < end && ((intptr_t)buf) % 4; buf++)
*buf = lrand48() & 0xff;
for (; buf < end - 3; buf += 4) {
uint32_t *buf32 = (uint32_t *)buf;
*buf32 = lrand48();
}
for (; buf < end; buf++)
*buf = lrand48() & 0xff;
} else {
memset(mac_ce_info.cur_ptr, 0, mac_ce_info.pdu_end - mac_ce_info.cur_ptr);
}
}
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
LOG_I(NR_MAC, "MAC PDU %ld bytes\n", mac_ce_info.cur_ptr - ulsch_buffer);
log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
#endif
return mac_ce_info.num_sdus > 0; // success if we got at least one sdu
}
void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
{
int cc_id = ul_info->cc_id;
frame_t frame_tx = ul_info->frame;
slot_t slot_tx = ul_info->slot;
uint32_t gNB_index = ul_info->gNB_index;
RA_config_t *ra = &mac->ra;
if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) {
init_RA(mac, frame_tx);
// perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a)
ra_resource_selection(mac);
}
if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE)
nr_ue_prach_scheduler(mac, frame_tx, slot_tx);
bool BSRsent = false;
if (mac->state == UE_CONNECTED) {
nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx);
nr_update_rlc_buffers_status(mac, frame_tx, slot_tx, gNB_index);
}
// Schedule ULSCH only if the current frame and slot match those in ul_config_req
// AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus)
uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
int number_of_pdus = 0;
fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
if (!ulcfg_pdu)
return;
LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx);
while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus];
if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
nfapi_nr_ue_pusch_pdu_t *pdu = &ulcfg_pdu->pusch_config_pdu;
uint32_t TBS_bytes = pdu->pusch_data.tb_size;
LOG_D(NR_MAC,
"harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n",
pdu->pusch_data.harq_process_id,
pdu->pusch_data.new_data_indicator,
TBS_bytes,
ra->ra_state);
pdu->tx_request_body.fapiTxPdu = NULL;
if ((ra->ra_state == nrRA_WAIT_RAR || ra->ra_state == nrRA_WAIT_MSGB) && !ra->cfra) {
nr_get_Msg3_MsgA_PUSCH_payload(mac, ulsch_input_buffer, TBS_bytes);
for (int k = 0; k < TBS_bytes; k++) {
LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]);
}
pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer;
pdu->tx_request_body.pdu_length = TBS_bytes;
number_of_pdus++;
T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx),
T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes));
} else {
if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator
&& (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) {
if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
// UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
trigger_MAC_UE_RA(mac, NULL);
return;
}
// Getting IP traffic to be transmitted
int tx_power = pdu->tx_power;
int P_CMAX = nr_get_Pcmax(mac->p_Max,
mac->nr_band,
mac->frame_structure.frame_type,
mac->frequency_range,
mac->current_UL_BWP->channel_bandwidth,
pdu->qam_mod_order,
false,
mac->current_UL_BWP->scs,
mac->current_UL_BWP->BWPSize,
pdu->transform_precoding,
pdu->rb_size,
pdu->rb_start);
nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes, tx_power, P_CMAX, &BSRsent);
pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer;
pdu->tx_request_body.pdu_length = TBS_bytes;
number_of_pdus++;
T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx),
T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes));
// start or restart dataInactivityTimer if any MAC entity transmits a MAC SDU for DTCH logical channel,
// or DCCH logical channel
if (mac->data_inactivity_timer)
nr_timer_start(mac->data_inactivity_timer);
}
}
if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) {
LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx);
// 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3
// transmission
nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
}
if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
}
if (ra->ra_state == nrRA_WAIT_MSGB && !ra->cfra) {
LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-MsgA-PUSCH transmitted\n", frame_tx, slot_tx);
}
}
ulcfg_pdu++;
}
release_ul_config(ulcfg_pdu, false);
if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING)
nr_ue_pucch_scheduler(mac, frame_tx, slot_tx);
if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx,
.mac = mac,
.module_id = mac->ue_id,
.CC_id = cc_id,
.phy_data = ul_info->phy_data};
mac->if_module->scheduled_response(&scheduled_response);
}
if(mac->state == UE_CONNECTED)
nr_update_sr(mac, BSRsent);
// Global variables implicit logic
// far away, BSR_reporting_active is set
mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE;
// update Bj for all active lcids before LCP procedure
if (mac->current_UL_BWP) {
LOG_D(NR_MAC, "%4d.%2d Logical Channel Prioritization\n", frame_tx, slot_tx);
for (int i = 0; i < mac->lc_ordered_list.count; i++) {
nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
int lcid = lc_info->lcid;
// max amount of data that can be buffered/accumulated in a logical channel buffer
uint32_t bucketSize_max = lc_info->bucket_size;
// measure Bj increment the value of Bj by product PBR * T
NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
int32_t bj = sched_info->Bj;
if (lc_info->pbr < UINT_MAX) {
uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented
// it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s
uint32_t pbr_ms = lc_info->pbr / 1000;
bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms
}
else
bj = INT_MAX;
// bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization
sched_info->Bj = min(bj, bucketSize_max);
// reset bj timer
nr_timer_start(&sched_info->Bj_timer);
}
}
}
// PUSCH scheduler:
// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// - where K2 is the offset between the slot in which UL DCI is received and the slot
// - in which ULSCH should be scheduled. K2 is configured in RRC configuration.
// PUSCH Msg3 scheduler:
// - scheduled by RAR UL grant according to 8.3 of TS 38.213
// Note: Msg3 tx in the uplink symbols of mixed slot
int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
const uint8_t is_Msg3,
const frame_t current_frame,
const int current_slot,
frame_t *frame_tx,
int *slot_tx,
const long k2)
{
int delta = 0;
const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
// Get the numerology to calculate the Tx frame and slot
int mu = current_UL_BWP->scs;
int slots_per_frame = mac->frame_structure.numb_slots_frame;
int remain = mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr;
LOG_D(NR_MAC,
"[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x buflen_remain %d bytes)\n",
mac->ue_id,
frame,
slot,
lcid,
remain);
// k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1
// PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon
if (num_lcids_same_priority == count_same_priority_lcids) {
buflen_ep = remain < count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG)
? 0
: (remain - (count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG))) / count_same_priority_lcids;
}
if (is_Msg3) {
while (mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr > 0) {
/*
loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes
depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all
active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates
the target number of bytes to request from RLC via 'mac_rlc_data_req'
*/
if (!fill_mac_sdu(mac,
frame,
slot,
gNB_index,
lcid,
count_same_priority_lcids,
buflen_ep,
lcids_bytes_tot,
&mac_ce_info,
&num_lcids_same_priority,
LCG_bytes)) {
break;
}
}
}
delta = get_delta_for_k2(mu);
mac_ce_info.lcp_allocation_counter++;
} while (mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr > sizeof(NR_MAC_SUBHEADER_LONG)
&& get_dataavailability_buffers(avail_lcids_count, lcids_bj_pos, mac_ce_info.lcids_data_status));
AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
"Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to "
"%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
k2,
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu));
nr_ue_get_sdu_mac_ce_post(mac, frame, slot, &mac_ce_info, LCG_bytes, BSRsent);
// Compute final offset for padding and fill remainder of ULSCH with 0
int remain = mac_ce_info.pdu_end - mac_ce_info.cur_ptr;
if (remain) {
LOG_D(NR_MAC, "Filling remainder %d bytes to the UL PDU \n", remain);
*(NR_MAC_SUBHEADER_FIXED *)mac_ce_info.cur_ptr = (NR_MAC_SUBHEADER_FIXED){.R = 0, .LCID = UL_SCH_LCID_PADDING};
mac_ce_info.cur_ptr++;
if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
uint8_t *buf = mac_ce_info.cur_ptr;
uint8_t *end = mac_ce_info.pdu_end;
for (; buf < end && ((intptr_t)buf) % 4; buf++)
*buf = lrand48() & 0xff;
for (; buf < end - 3; buf += 4) {
uint32_t *buf32 = (uint32_t *)buf;
*buf32 = lrand48();
}
for (; buf < end; buf++)
*buf = lrand48() & 0xff;
} else {
memset(mac_ce_info.cur_ptr, 0, mac_ce_info.pdu_end - mac_ce_info.cur_ptr);
*slot_tx = (current_slot + k2 + delta) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER;
} else {
AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in "
"gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
k2,
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu));
if (k2 < 0) { // This can happen when a false DCI is received
LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2);
return -1;
}
// Calculate TX slot and frame
*slot_tx = (current_slot + k2) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER;
}
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
LOG_I(NR_MAC, "MAC PDU %ld bytes\n", mac_ce_info.cur_ptr - ulsch_buffer);
log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
#endif
return mac_ce_info.num_sdus > 0; // success if we got at least one sdu
LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta);
return 0;
}
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac)
void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
const NR_CSI_RS_ResourceMapping_t *resourceMapping,
uint32_t bwp_size,
uint32_t bwp_start)
{
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment;
fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu;
ta->ta_frame = ul_time_alignment->frame;
ta->ta_slot = ul_time_alignment->slot;
ta->is_rar = ul_time_alignment->ta_apply == rar_ta;
ta->ta_command = ul_time_alignment->ta_command;
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND;
dl_config->number_pdus += 1;
ul_time_alignment->ta_apply = no_ta;
}
// According to last paragraph of TS 38.214 5.2.2.3.1
if (resourceMapping->freqBand.startingRB < bwp_start)
csirs_config_pdu->start_rb = bwp_start;
else
csirs_config_pdu->start_rb = resourceMapping->freqBand.startingRB;
if (resourceMapping->freqBand.nrofRBs > (bwp_start + bwp_size - csirs_config_pdu->start_rb))
csirs_config_pdu->nr_of_rbs = bwp_start + bwp_size - csirs_config_pdu->start_rb;
else
csirs_config_pdu->nr_of_rbs = resourceMapping->freqBand.nrofRBs;
AssertFatal(csirs_config_pdu->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_config_pdu->nr_of_rbs);
static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac,
NR_SINGLE_ENTRY_PHR_MAC_CE *phr,
float P_CMAX,
float tx_power,
frame_t frame,
slot_t slot)
{
nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info;
// Value mapping according to 38.133 10.1.18.1
const int PC_MAX_00 = -29;
*phr = (NR_SINGLE_ENTRY_PHR_MAC_CE){.PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f};
// Value mapping according to 38.133 10.1.17.1.1
const int POWER_HEADROOM_55 = 22;
int headroom = P_CMAX - tx_power;
if (headroom < POWER_HEADROOM_55) {
const int POWER_HEADROOM_0 = -32;
phr->PH = max(0, headroom - POWER_HEADROOM_0);
} else {
phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2);
}
csirs_config_pdu->symb_l0 = resourceMapping->firstOFDMSymbolInTimeDomain;
if (resourceMapping->firstOFDMSymbolInTimeDomain2)
csirs_config_pdu->symb_l1 = *resourceMapping->firstOFDMSymbolInTimeDomain2;
csirs_config_pdu->cdm_type = resourceMapping->cdm_Type;
LOG_D(NR_MAC,
"PHR Reporting sfn.slot %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n",
frame,
slot,
phr_info->phr_reporting,
phr->PCMAX,
P_CMAX,
phr->PH,
headroom,
tx_power);
csirs_config_pdu->freq_density = resourceMapping->density.present;
if ((resourceMapping->density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5)
&& (resourceMapping->density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs))
csirs_config_pdu->freq_density--;
phr_info->PathlossLastValue = compute_nr_SSB_PL(mac);
// Restart both timers according to 38.321
nr_timer_start(&phr_info->periodicPHR_Timer);
nr_timer_start(&phr_info->prohibitPHR_Timer);
phr_info->phr_reporting = 0;
switch(resourceMapping->frequencyDomainAllocation.present){
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
csirs_config_pdu->row = 1;
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
csirs_config_pdu->row = 2;
csirs_config_pdu->freq_domain = (((resourceMapping->frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f)
| ((resourceMapping->frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0));
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
csirs_config_pdu->row = 4;
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07;
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f;
// determining the row of table 7.4.1.5.3-1 in 38.211
switch (resourceMapping->nrofPorts) {
case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n");
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
csirs_config_pdu->row = 3;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
csirs_config_pdu->row = 5;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p8:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 8;
else {
int num_k = 0;
for (int k = 0; k < 6; k++)
num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01);
if (num_k == 4)
csirs_config_pdu->row = 6;
else
csirs_config_pdu->row = 7;
}
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p12:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 10;
else
csirs_config_pdu->row = 9;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p16:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 12;
else
csirs_config_pdu->row = 11;
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 14;
else {
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
csirs_config_pdu->row = 15;
else
csirs_config_pdu->row = 13;
}
break;
case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
csirs_config_pdu->row = 17;
else {
if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
csirs_config_pdu->row = 18;
else
csirs_config_pdu->row = 16;
}
break;
default:
AssertFatal(false, "Invalid number of ports in CSI-RS resource\n");
}
break;
default:
AssertFatal(false, "Invalid freqency domain allocation in CSI-RS resource\n");
}
}
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