diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index af6bf37aff..477e39a60a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -38,7 +38,7 @@ #include "executables/softmodem-common.h" #include -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; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 860089165f..a409cbe653 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -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: diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 241a56b180..3ba221386f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -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,6 +2540,50 @@ static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR return -1; } +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; +} + // section 5.2.5 of 38.214 int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep) { @@ -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) +void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) { - 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 + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); - // TPC - unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07); - ra->Msg3_TPC = (tpc_command << 1) - 6; + 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); - // 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 { + // 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); } - diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index c21a0ce3bd..2818c20c37 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -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,260 +1516,179 @@ 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); - } + // 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 (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) + if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods)) 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]); + if (is_ul_slot(slotP, &mac->frame_structure)) { + if (slotP == prach_occasion_info->slot) { + fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH); + if (!pdu) { + LOG_E(NR_MAC, "Error in PRACH allocation\n"); + return; + } + + int format = prach_occasion_info->format; + fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config; + pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){ + .phys_cell_id = mac->physCellId, + .num_prach_ocas = 1, + .prach_slot = prach_occasion_info->slot, + .prach_start_symbol = prach_occasion_info->start_symbol, + .num_ra = prach_occasion_info->fdm, + .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config), + .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index, + .restricted_set = prach_config->restricted_set_config, + .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1}; + + LOG_I(NR_MAC, + "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", + frameP, + pdu->prach_config_pdu.prach_slot, + pdu->prach_config_pdu.prach_start_symbol, + pdu->prach_config_pdu.num_ra); + + switch (format) { // single PRACH format + case 0: + pdu->prach_config_pdu.prach_format = 0; + break; + case 1: + pdu->prach_config_pdu.prach_format = 1; + break; + case 2: + pdu->prach_config_pdu.prach_format = 2; + break; + case 3: + pdu->prach_config_pdu.prach_format = 3; + break; + case 0xa1: + pdu->prach_config_pdu.prach_format = 4; + break; + case 0xa2: + pdu->prach_config_pdu.prach_format = 5; + break; + case 0xa3: + pdu->prach_config_pdu.prach_format = 6; + break; + case 0xb1: + pdu->prach_config_pdu.prach_format = 7; + break; + case 0xb4: + pdu->prach_config_pdu.prach_format = 8; + break; + case 0xc0: + pdu->prach_config_pdu.prach_format = 9; + break; + case 0xc2: + pdu->prach_config_pdu.prach_format = 10; + break; + default: + AssertFatal(false, "Invalid PRACH format"); + } + + pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex; + pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); + release_ul_config(pdu, false); + nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, + .mac = mac, + .module_id = mac->ue_id, + .CC_id = 0 /*TBR fix*/}; + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) + mac->if_module->scheduled_response(&scheduled_response); + + T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot), + T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power)); + + const int n_slots_frame = mac->frame_structure.numb_slots_frame; + if (ra->ra_type == RA_4_STEP) { + ra->ra_state = nrRA_WAIT_RAR; + // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH + // the response window timer should be started at that time + // but for processing reasons it is better to start it here and to add the slot difference + // that also takes into account the rx to tx slot offset + int next_slot = (slotP + 1) % n_slots_frame; + int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER; + int add_slots = 1; + NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id]; + const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); + while (!is_dl_slot(next_slot, &mac->frame_structure) + || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, ra_SS)) { + int temp_slot = (next_slot + 1) % n_slots_frame; + next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER; + next_slot = temp_slot; + add_slots++; } - 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)); + add_slots += GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mac->current_DL_BWP->scs); + nr_timer_setup(&ra->response_window_timer, ra->response_window_setup_time + add_slots, 1); + nr_timer_start(&ra->response_window_timer); + } else if (ra->ra_type == RA_2_STEP) { + NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource = + mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16; + slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame; + frame_t msgA_pusch_frame = + (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024; + + fapi_nr_ul_config_request_pdu_t *pdu = + lockGet_ul_config(mac, msgA_pusch_frame, msgA_pusch_slot, FAPI_NR_UL_CONFIG_TYPE_PUSCH); + if (!pdu) + return; + + // Config Msg3/MsgA-PUSCH PDU + NR_tda_info_t tda_info = {0}; + AssertFatal(msgA_PUSCH_Resource->startSymbolAndLengthMsgA_PO_r16, + "Only SLIV based on startSymbolAndLengthMsgA_PO_r16 implemented\n"); + + int ret = nr_config_pusch_pdu(mac, + &tda_info, + &pdu->pusch_config_pdu, + NULL, + NULL, + NULL, + mac->ra.ra_rnti, + NR_SearchSpace__searchSpaceType_PR_common, + NR_DCI_NONE); + + if (ret != 0) + remove_ul_config_last_item(pdu); + release_ul_config(pdu, false); + + LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]); + ra->ra_state = nrRA_WAIT_MSGB; + ra->t_crnti = 0; + mac->crnti = 0; + ra->ra_rnti = 0; } 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); - } + AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type); } - - 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; + } // is_nr_prach_slot + } // if is_nr_UL_slot } static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, @@ -1782,472 +1876,43 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot } } -static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot) +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) { - 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_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); } -} -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 -} + 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); -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_ul_slot(slotP, &mac->frame_structure)) { - if (slotP == prach_occasion_info->slot) { - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH); - if (!pdu) { - LOG_E(NR_MAC, "Error in PRACH allocation\n"); - return; - } - - int format = prach_occasion_info->format; - fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config; - pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){ - .phys_cell_id = mac->physCellId, - .num_prach_ocas = 1, - .prach_slot = prach_occasion_info->slot, - .prach_start_symbol = prach_occasion_info->start_symbol, - .num_ra = prach_occasion_info->fdm, - .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config), - .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index, - .restricted_set = prach_config->restricted_set_config, - .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1}; - - LOG_I(NR_MAC, - "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", - frameP, - pdu->prach_config_pdu.prach_slot, - pdu->prach_config_pdu.prach_start_symbol, - pdu->prach_config_pdu.num_ra); - - switch (format) { // single PRACH format - case 0: - pdu->prach_config_pdu.prach_format = 0; - break; - case 1: - pdu->prach_config_pdu.prach_format = 1; - break; - case 2: - pdu->prach_config_pdu.prach_format = 2; - break; - case 3: - pdu->prach_config_pdu.prach_format = 3; - break; - case 0xa1: - pdu->prach_config_pdu.prach_format = 4; - break; - case 0xa2: - pdu->prach_config_pdu.prach_format = 5; - break; - case 0xa3: - pdu->prach_config_pdu.prach_format = 6; - break; - case 0xb1: - pdu->prach_config_pdu.prach_format = 7; - break; - case 0xb4: - pdu->prach_config_pdu.prach_format = 8; - break; - case 0xc0: - pdu->prach_config_pdu.prach_format = 9; - break; - case 0xc2: - pdu->prach_config_pdu.prach_format = 10; - break; - default: - AssertFatal(false, "Invalid PRACH format"); - } - - pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex; - pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); - release_ul_config(pdu, false); - nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, - .mac = mac, - .module_id = mac->ue_id, - .CC_id = 0 /*TBR fix*/}; - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) - mac->if_module->scheduled_response(&scheduled_response); - - T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot), - T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power)); - - const int n_slots_frame = mac->frame_structure.numb_slots_frame; - if (ra->ra_type == RA_4_STEP) { - ra->ra_state = nrRA_WAIT_RAR; - // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH - // the response window timer should be started at that time - // but for processing reasons it is better to start it here and to add the slot difference - // that also takes into account the rx to tx slot offset - int next_slot = (slotP + 1) % n_slots_frame; - int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER; - int add_slots = 1; - NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id]; - const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); - while (!is_dl_slot(next_slot, &mac->frame_structure) - || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, ra_SS)) { - int temp_slot = (next_slot + 1) % n_slots_frame; - next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER; - next_slot = temp_slot; - add_slots++; - } - add_slots += GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mac->current_DL_BWP->scs); - nr_timer_setup(&ra->response_window_timer, ra->response_window_setup_time + add_slots, 1); - nr_timer_start(&ra->response_window_timer); - } else if (ra->ra_type == RA_2_STEP) { - NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource = - mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16; - slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame; - frame_t msgA_pusch_frame = - (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024; - - fapi_nr_ul_config_request_pdu_t *pdu = - lockGet_ul_config(mac, msgA_pusch_frame, msgA_pusch_slot, FAPI_NR_UL_CONFIG_TYPE_PUSCH); - if (!pdu) - return; - - // Config Msg3/MsgA-PUSCH PDU - NR_tda_info_t tda_info = {0}; - AssertFatal(msgA_PUSCH_Resource->startSymbolAndLengthMsgA_PO_r16, - "Only SLIV based on startSymbolAndLengthMsgA_PO_r16 implemented\n"); - - int ret = nr_config_pusch_pdu(mac, - &tda_info, - &pdu->pusch_config_pdu, - NULL, - NULL, - NULL, - mac->ra.ra_rnti, - NR_SearchSpace__searchSpaceType_PR_common, - NR_DCI_NONE); - - if (ret != 0) - remove_ul_config_last_item(pdu); - release_ul_config(pdu, false); - - LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]); - ra->ra_state = nrRA_WAIT_MSGB; - ra->t_crnti = 0; - mac->crnti = 0; - ra->ra_rnti = 0; - } else { - AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type); - } - } // is_nr_prach_slot - } // if is_nr_UL_slot + 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 { @@ -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, @@ -2837,54 +2540,329 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, return mac_ce_info.num_sdus > 0; // success if we got at least one sdu } -static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) +void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) { - 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; -} + 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; -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); + 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); } - 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); + if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE) + nr_ue_prach_scheduler(mac, frame_tx, slot_tx); - 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; + 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; + + // 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; +} + +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"); + } }