From c7c1cb2dbf2a9b249cdc4c8b1bea15730fe9531f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 26 Jun 2024 16:54:16 +0200 Subject: [PATCH] Enable PHR reporting for NR UE --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 16 ++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 41 ++++-- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 6 +- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 9 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 18 ++- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 128 ++++++++++++++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 12 +- 7 files changed, 184 insertions(+), 46 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index e28f7dce93..50244f2d2b 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1879,7 +1879,21 @@ static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroup } } if (mcg->phr_Config) { - // TODO configuration when PHR is implemented + nr_phr_info_t *phr_info = &si->phr_info; + phr_info->is_configured = mcg->phr_Config->choice.setup != NULL; + if (phr_info->is_configured) { + int slots_per_subframe = nr_slots_per_frame[scs] / 10; + struct NR_PHR_Config *config = mcg->phr_Config->choice.setup; + AssertFatal(config->multiplePHR == 0, "mulitplePHR not supported"); + phr_info->PathlossChange_db = config->phr_Tx_PowerFactorChange; + const int periodic_timer_sf_enum_to_sf[] = {10, 20, 50, 100, 200, 500, 1000, UINT_MAX}; + int periodic_timer_sf = periodic_timer_sf_enum_to_sf[config->phr_PeriodicTimer]; + nr_timer_setup(&phr_info->periodicPHR_Timer, periodic_timer_sf * slots_per_subframe, 1); + const int prohibit_timer_sf_enum_to_sf[] = {0, 10, 20, 50, 100, 200, 500, 1000}; + int prohibit_timer_sf = prohibit_timer_sf_enum_to_sf[config->phr_ProhibitTimer]; + nr_timer_setup(&phr_info->prohibitPHR_Timer, prohibit_timer_sf * slots_per_subframe, 1); + phr_info->phr_reporting = (1 << phr_cause_phr_config); + } } } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 781192fbc2..bec9d84dca 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -172,6 +172,12 @@ UE_STATE(UE_CONNECTED) \ UE_STATE(UE_DETACHING) +typedef enum { + phr_cause_prohibit_timer = 0, + phr_cause_periodic_timer, + phr_cause_phr_config, +} NR_UE_PHR_Reporting_cause_t; + /*!\brief UE layer 2 status */ typedef enum { #define UE_STATE(state) state, @@ -222,6 +228,24 @@ typedef struct { uint32_t maxTransmissions; } nr_sr_info_t; +typedef struct { + bool is_configured; + ///timer before triggering a periodic PHR + NR_timer_t periodicPHR_Timer; + ///timer before triggering a prohibit PHR + NR_timer_t prohibitPHR_Timer; + ///DL Pathloss change value + uint16_t PathlossLastValue; + ///number of subframe before triggering a periodic PHR + int16_t periodicPHR_SF; + ///number of subframe before triggering a prohibit PHR + int16_t prohibitPHR_SF; + ///DL Pathloss Change in db + uint16_t PathlossChange_db; + int phr_reporting; + bool was_mac_reset; +} nr_phr_info_t; + // LTE structure, might need to be adapted for NR typedef struct { // lcs scheduling info @@ -240,18 +264,8 @@ typedef struct { NR_timer_t retxBSR_Timer; /// periodicBSR-Timer NR_timer_t periodicBSR_Timer; - ///timer before triggering a periodic PHR - uint16_t periodicPHR_Timer; - ///timer before triggering a prohibit PHR - uint16_t prohibitPHR_Timer; - ///DL Pathloss change value - uint16_t PathlossChange; - ///number of subframe before triggering a periodic PHR - int16_t periodicPHR_SF; - ///number of subframe before triggering a prohibit PHR - int16_t prohibitPHR_SF; - ///DL Pathloss Change in db - uint16_t PathlossChange_db; + + nr_phr_info_t phr_info; } NR_UE_SCHEDULING_INFO; typedef enum { @@ -560,9 +574,6 @@ typedef struct NR_UE_MAC_INST_s { NR_UE_SCHEDULING_INFO scheduling_info; - /// PHR - uint8_t PHR_reporting_active; - int dmrs_TypeA_Position; int p_Max; int p_Max_alt; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 396294fc97..9a0bc8e911 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -173,7 +173,7 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac,nr_downlink_indication_t *dl_in int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, - uint8_t power_headroom, // todo: NR_POWER_HEADROOM_CMD *power_headroom, + NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom, uint16_t *crnti, NR_BSR_SHORT *truncated_bsr, NR_BSR_SHORT *short_bsr, @@ -193,7 +193,9 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, sub_frame_t subframe, uint8_t gNB_index, uint8_t *ulsch_buffer, - uint32_t buflen); + uint32_t buflen, + int16_t tx_power, + int16_t P_CMAX); void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t pucch_id, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index b6a289cc45..73f85c9535 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -118,8 +118,10 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) nr_timer_setup(&mac->scheduling_info.retxBSR_Timer, 80 * subframes_per_slot, 1); // 1 slot update rate nr_timer_setup(&mac->scheduling_info.periodicBSR_Timer, 10 * subframes_per_slot, 1); // 1 slot update rate - mac->scheduling_info.periodicPHR_Timer = NR_PHR_Config__phr_PeriodicTimer_sf10; - mac->scheduling_info.prohibitPHR_Timer = NR_PHR_Config__phr_ProhibitTimer_sf10; + mac->scheduling_info.phr_info.is_configured = true; + mac->scheduling_info.phr_info.PathlossChange_db = 1; + nr_timer_setup(&mac->scheduling_info.phr_info.periodicPHR_Timer, 10 * subframes_per_slot, 1); + nr_timer_setup(&mac->scheduling_info.phr_info.prohibitPHR_Timer, 10 * subframes_per_slot, 1); } void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req) @@ -229,7 +231,8 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) nr_mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE; // cancel any triggered Power Headroom Reporting procedure - // TODO PHR not implemented yet + nr_mac->scheduling_info.phr_info.phr_reporting = 0; + nr_mac->scheduling_info.phr_info.was_mac_reset = true; // flush the soft buffers for all DL HARQ processes for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index c7903a9666..59495bd2c3 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3668,30 +3668,28 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i */ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, - uint8_t power_headroom, // todo: NR_POWER_HEADROOM_CMD *power_headroom, + NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom, uint16_t *crnti, NR_BSR_SHORT *truncated_bsr, NR_BSR_SHORT *short_bsr, NR_BSR_LONG *long_bsr) { int mac_ce_len = 0; - uint8_t mac_ce_size = 0; uint8_t *pdu = mac_ce; if (power_headroom) { - // MAC CE fixed subheader ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0; ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_SINGLE_ENTRY_PHR; mac_ce++; // PHR MAC CE (1 octet) - ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PH = power_headroom; + ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PH = power_headroom->PH; ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R1 = 0; - ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PCMAX = 0; // todo + ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PCMAX = power_headroom->PCMAX; ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R2 = 0; // update pointer and length - mac_ce_size = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE); + int mac_ce_size = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : power_headroom pdu %p mac_ce %p b\n", @@ -3710,7 +3708,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, memcpy(mac_ce, crnti, sizeof(*crnti)); // update pointer and length - mac_ce_size = sizeof(uint16_t); + int mac_ce_size = sizeof(uint16_t); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); } @@ -3727,7 +3725,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, ((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> LcgID = truncated_bsr->LcgID;; // update pointer and length - mac_ce_size = sizeof(NR_BSR_SHORT_TRUNCATED); + int mac_ce_size = sizeof(NR_BSR_SHORT_TRUNCATED); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : truncated_bsr Buffer_size %d LcgID %d pdu %p mac_ce %p\n", @@ -3745,7 +3743,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, ((NR_BSR_SHORT *) mac_ce)->LcgID = short_bsr->LcgID; // update pointer and length - mac_ce_size = sizeof(NR_BSR_SHORT); + int mac_ce_size = sizeof(NR_BSR_SHORT); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : short_bsr Buffer_size %d LcgID %d pdu %p mac_ce %p\n", @@ -3812,7 +3810,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, ((NR_BSR_LONG *) mac_ce)->LcgID7 = 1; *Buffer_size_ptr++ = long_bsr->Buffer_size7; } - ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_subheader_ptr)->L = mac_ce_size = (uint8_t*) Buffer_size_ptr - (uint8_t*) mac_ce; + int mac_ce_size = ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_subheader_ptr)->L = (uint8_t*) Buffer_size_ptr - (uint8_t*) mac_ce; LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : long_bsr size %d Lcgbit 0x%02x Buffer_size %d %d %d %d %d %d %d %d\n", mac_ce_size, *((uint8_t*) mac_ce), ((NR_BSR_LONG *) mac_ce)->Buffer_size0, ((NR_BSR_LONG *) mac_ce)->Buffer_size1, ((NR_BSR_LONG *) mac_ce)->Buffer_size2, ((NR_BSR_LONG *) mac_ce)->Buffer_size3, ((NR_BSR_LONG *) mac_ce)->Buffer_size4, ((NR_BSR_LONG *) mac_ce)->Buffer_size5, ((NR_BSR_LONG *) mac_ce)->Buffer_size6, ((NR_BSR_LONG *) mac_ce)->Buffer_size7); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 315f1ef522..b3f9ff5ffc 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -64,6 +64,12 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP); static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment); +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 frameP, + sub_frame_t subframe); void clear_ul_config_request(NR_UE_MAC_INST_t *mac, int scs) { @@ -176,6 +182,21 @@ void update_mac_timers(NR_UE_MAC_INST_t *mac) AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer), "Bj timer for LCID %d expired! That should never happen\n", i); + + nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info; + if (phr_info->is_configured) { + bool prohibit_expired = nr_timer_tick(&phr_info->prohibitPHR_Timer); + if (prohibit_expired) { + int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + if (abs(pathloss - phr_info->PathlossLastValue) > phr_info->PathlossChange_db) { + phr_info->phr_reporting |= (1 << phr_cause_prohibit_timer); + } + } + bool periodic_expired = nr_timer_tick(&phr_info->periodicPHR_Timer); + if (periodic_expired) { + phr_info->phr_reporting |= (1 << phr_cause_periodic_timer); + } + } } void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu) @@ -942,6 +963,16 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, return -1; } + // 38.321 5.4.6 + // if it is the first UL resource allocated for a new transmission since the last MAC reset: + // 2> start phr-PeriodicTimer; + if (mac->scheduling_info.phr_info.is_configured) { + if (mac->scheduling_info.phr_info.was_mac_reset && pusch_config_pdu->pusch_data.new_data_indicator) { + mac->scheduling_info.phr_info.was_mac_reset = false; + nr_timer_start(&mac->scheduling_info.phr_info.periodicPHR_Timer); + } + } + return 0; } @@ -1185,7 +1216,6 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, // Performs : // 1. TODO: Call RRC for link status return to PHY // 2. TODO: Perform SR/BSR procedures for scheduling feedback -// 3. TODO: Perform PHR procedures void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info) { frame_t rx_frame = dl_info->frame; @@ -1422,10 +1452,24 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) { // Getting IP traffic to be transmitted - nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes); - ulcfg_pdu->pusch_config_pdu.tx_request_body.fapiTxPdu = ulsch_input_buffer; - ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes; - number_of_pdus++; + int tx_power = ulcfg_pdu->pusch_config_pdu.tx_power; + int P_CMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frame_type, + mac->frequency_range, + mac->current_UL_BWP->channel_bandwidth, + ulcfg_pdu->pusch_config_pdu.qam_mod_order, + false, + mac->current_UL_BWP->scs, + mac->current_UL_BWP->BWPSize, + ulcfg_pdu->pusch_config_pdu.transform_precoding, + ulcfg_pdu->pusch_config_pdu.rb_size, + ulcfg_pdu->pusch_config_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); + ulcfg_pdu->pusch_config_pdu.tx_request_body.fapiTxPdu = ulsch_input_buffer; + ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes; + number_of_pdus++; } } @@ -2735,6 +2779,7 @@ typedef struct { NR_BSR_SHORT *bsr_s; NR_BSR_LONG *bsr_l; NR_BSR_SHORT *bsr_t; + NR_SINGLE_ENTRY_PHR_MAC_CE* phr; //NR_POWER_HEADROOM_CMD *phr_pr; int tot_mac_ce_len; uint8_t total_mac_pdu_header_len; @@ -2758,12 +2803,13 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, uint8_t gNB_index, uint8_t *ulsch_buffer, uint32_t buflen, + int16_t tx_power, + int16_t P_CMAX, NR_UE_MAC_CE_INFO *mac_ce_p) { int num_lcg_id_with_data = 0; // Preparing the MAC CEs sub-PDUs and get the total size mac_ce_p->bsr_header_len = 0; - mac_ce_p->phr_header_len = 0; //sizeof(SCH_SUBHEADER_FIXED); int lcg_id = 0; while (lcg_id != NR_INVALID_LCGID) { if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { @@ -2794,8 +2840,23 @@ static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, } } } - mac_ce_p->bsr_len = mac_ce_p->bsr_ce_len + mac_ce_p->bsr_header_len; + + + nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info; + mac_ce_p->phr_header_len = 0; + mac_ce_p->phr_ce_len = 0; + if (phr_info->is_configured && phr_info->phr_reporting > 0) { + if (buflen >= (mac_ce_p->bsr_len + sizeof(NR_MAC_SUBHEADER_FIXED) + sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE))) { + if (mac->scheduling_info.phr_info.phr_reporting) { + mac_ce_p->phr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); + mac_ce_p->phr_ce_len = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE); + nr_ue_fill_phr(mac, mac_ce_p->phr, P_CMAX, tx_power, frameP, subframe); + } + } + } + mac_ce_p->phr_len = mac_ce_p->phr_header_len + mac_ce_p->phr_ce_len; + return (mac_ce_p->bsr_len + mac_ce_p->phr_len); } @@ -3234,7 +3295,9 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, slot_t slot, uint8_t gNB_index, uint8_t *ulsch_buffer, - uint32_t buflen) + uint32_t buflen, + int16_t tx_power, + int16_t P_CMAX) { NR_UE_MAC_CE_INFO mac_ce_info; NR_UE_MAC_CE_INFO *mac_ce_p=&mac_ce_info; @@ -3253,8 +3316,9 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, mac_ce_p->bsr_s = &bsr_short; mac_ce_p->bsr_l = &bsr_long; mac_ce_p->bsr_t = &bsr_truncated; - //NR_POWER_HEADROOM_CMD phr; - //mac_ce_p->phr_p = &phr; + + NR_SINGLE_ENTRY_PHR_MAC_CE phr; + mac_ce_p->phr = &phr; //int highest_priority = 16; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); @@ -3273,7 +3337,7 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, // because as per standard(TS38.321), all equal priority channels should be served equally // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length - mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, mac_ce_p); + mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, tx_power, P_CMAX, mac_ce_p); mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len; LOG_D(NR_MAC, "[UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", mac->ue_id, frame, slot, buflen); @@ -3373,9 +3437,8 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, nr_ue_get_sdu_mac_ce_post(mac, frame, slot, ulsch_buffer, buflen, mac_ce_p); if (mac_ce_p->tot_mac_ce_len > 0) { - LOG_D(NR_MAC, "In %s copying %d bytes of MAC CEs to the UL PDU \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len); - int size = nr_write_ce_ulsch_pdu(pdu, mac, 0, NULL, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l); + int size = nr_write_ce_ulsch_pdu(pdu, mac, mac_ce_p->phr_ce_len ? mac_ce_p->phr : NULL, 0, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l); if (size != mac_ce_p->tot_mac_ce_len) LOG_E(NR_MAC, "MAC CE size computed by nr_write_ce_ulsch_pdu is %d while the one assumed before is %d\n", size, mac_ce_p->tot_mac_ce_len); pdu += (unsigned char) mac_ce_p->tot_mac_ce_len; @@ -3436,3 +3499,42 @@ static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TI dl_config->number_pdus += 1; ul_time_alignment->ta_apply = no_ta; } + +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 frameP, + sub_frame_t subframe) +{ + 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->PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f; + // Value mapping according to 38.133 10.1.17.1.1 + const int POWER_HEADROOM_55 = 22; + int headroom = P_CMAX - tx_power; + if (headroom < POWER_HEADROOM_55) { + const int POWER_HEADROOM_0 = -32; + phr->PH = max(0, headroom - POWER_HEADROOM_0); + } else { + phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2); + } + + LOG_D(NR_MAC, + "PHR Reporting sfn.subframe %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n", + frameP, + subframe, + phr_info->phr_reporting, + phr->PCMAX, + P_CMAX, + phr->PH, + headroom, + tx_power); + + phr_info->PathlossLastValue = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + // 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; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 772b9bf582..dce6d3b71b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -331,8 +331,16 @@ static int nr_process_mac_pdu(instance_t module_idP, sched_ctrl->ph0 = PH; /* 38.133 Table10.1.18.1-1 */ sched_ctrl->pcmax = PCMAX - 29; - LOG_D(NR_MAC, "SINGLE ENTRY PHR R1 %d PH %d (%d dB) R2 %d PCMAX %d (%d dBm)\n", - phr->R1, PH, sched_ctrl->ph, phr->R2, PCMAX, sched_ctrl->pcmax); + LOG_D(NR_MAC, + "SINGLE ENTRY PHR %d.%d R1 %d PH %d (%d dB) R2 %d PCMAX %d (%d dBm)\n", + frameP, + slot, + phr->R1, + PH, + sched_ctrl->ph, + phr->R2, + PCMAX, + sched_ctrl->pcmax); break; case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT: