diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 55596ea556..831561e025 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -305,6 +305,7 @@ Furthermore, the gNB and UE support - HARQ procedures * ULSCH scheduler - Configuration of fapi PDU according to DCI + - Logical channel prioritization of 'data from any logical channel' * NR-CSIRS scheduler - Scheduling of NR-CSIRS reception - Fill UCI for CSI measurement reporting diff --git a/executables/nr-ue.c b/executables/nr-ue.c index aaeda3df9a..9f1400ae47 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -975,7 +975,7 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf nr_rrc_mac_config_req_ue_logicalChannelBearer(0, &rlc_toadd_list, NULL); // free memory - free_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig); + free_nr_noS1_bearer_config(&rbconfig, NULL); } } } diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 8de21221f1..537349ac34 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -30,6 +30,8 @@ * \warning */ +#define _GNU_SOURCE + //#include "mac_defs.h" #include #include "NR_MAC_UE/mac_proto.h" @@ -39,6 +41,32 @@ #include "executables/softmodem-common.h" #include "SCHED_NR/phy_frame_config_nr.h" +const long logicalChannelGroup0_NR = 0; +typedef struct NR_LogicalChannelConfig__ul_SpecificParameters LcConfig_UlParamas_t; + +const LcConfig_UlParamas_t NR_LCSRB1 = { + .priority = 1, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +const LcConfig_UlParamas_t NR_LCSRB2 = { + .priority = 3, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +const LcConfig_UlParamas_t NR_LCSRB3 = { + .priority = 1, + .prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity, + .logicalChannelGroup = (long *)&logicalChannelGroup0_NR}; + +// these are the default values for SRB configurations(SRB1 and SRB2) as mentioned in 36.331 pg 258-259 +const NR_LogicalChannelConfig_t NR_SRB1_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB1}; +const NR_LogicalChannelConfig_t NR_SRB2_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB2}; +const NR_LogicalChannelConfig_t NR_SRB3_logicalChannelConfig_defaultValue = {.ul_SpecificParameters = + (LcConfig_UlParamas_t *)&NR_LCSRB3}; + void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, int mu, NR_TDD_UL_DL_Pattern_t *pattern) @@ -511,26 +539,145 @@ void configure_ss_coreset(NR_UE_MAC_INST_t *mac, mac->BWP_coresets[i] = NULL; } +static int lcid_cmp(const void *lc1, const void *lc2, void *mac_inst) +{ + uint8_t id1 = ((nr_lcordered_info_t *)lc1)->lcids_ordered; + uint8_t id2 = ((nr_lcordered_info_t *)lc2)->lcids_ordered; + NR_UE_MAC_INST_t *mac = (NR_UE_MAC_INST_t *)mac_inst; + + NR_LogicalChannelConfig_t **lc_config = &mac->logicalChannelConfig[0]; + + AssertFatal(id1 > 0 && id2 > 0, "undefined logical channel identity\n"); + AssertFatal(lc_config[id1 - 1] != NULL || lc_config[id2 - 1] != NULL, "logical channel configuration should be available\n"); + + return (lc_config[id1 - 1]->ul_SpecificParameters->priority - lc_config[id2 - 1]->ul_SpecificParameters->priority); +} + +void nr_release_mac_config_logicalChannelBearer(module_id_t module_id, long channel_identity) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + if (mac->logicalChannelConfig[channel_identity - 1] != NULL) { + mac->logicalChannelConfig[channel_identity - 1] = NULL; + memset(&mac->scheduling_info.lc_sched_info[channel_identity - 1], 0, sizeof(NR_LC_SCHEDULING_INFO)); + } else { + LOG_E(NR_MAC, "Trying to release a non configured logical channel bearer %li\n", channel_identity); + } +} + +static uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration) +{ + switch (bucketsizeduration) { + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: + return 50; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: + return 100; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: + return 150; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: + return 300; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: + return 500; + + case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: + return 1000; + + default: + return 0; + } +} + +void nr_configure_mac_config_logicalChannelBearer(module_id_t module_id, + long channel_identity, + NR_LogicalChannelConfig_t *lc_config) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + + LOG_I(NR_MAC, "[MACLogicalChannelConfig]Applying RRC Logical Channel Config %d to lcid %li\n", module_id, channel_identity); + mac->logicalChannelConfig[channel_identity - 1] = lc_config; + + // initialize the variable Bj for every LCID + mac->scheduling_info.lc_sched_info[channel_identity - 1].Bj = 0; + + // store the bucket size + int pbr = nr_get_pbr(lc_config->ul_SpecificParameters->prioritisedBitRate); + int bsd = nr_get_ms_bucketsizeduration(lc_config->ul_SpecificParameters->bucketSizeDuration); + + // in infinite pbr, the bucket is saturated by pbr + if (lc_config->ul_SpecificParameters->prioritisedBitRate + == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) { + bsd = 1; + } + mac->scheduling_info.lc_sched_info[channel_identity - 1].bucket_size = pbr * bsd; + + if (lc_config->ul_SpecificParameters->logicalChannelGroup != NULL) + mac->scheduling_info.lc_sched_info[channel_identity - 1].LCGID = *lc_config->ul_SpecificParameters->logicalChannelGroup; + else + mac->scheduling_info.lc_sched_info[channel_identity - 1].LCGID = 0; +} + void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list, struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); - if (rlc_toadd_list) { - for (int i = 0; i < rlc_toadd_list->list.count; i++) { - NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; - int id = rlc_bearer->logicalChannelIdentity - 1; - mac->active_RLC_bearer[id] = true; - } - } if (rlc_torelease_list) { for (int i = 0; i < rlc_torelease_list->list.count; i++) { if (rlc_torelease_list->list.array[i]) { - int id = *rlc_torelease_list->list.array[i] - 1; - mac->active_RLC_bearer[id] = false; + int lc_identity = *rlc_torelease_list->list.array[i]; + nr_release_mac_config_logicalChannelBearer(module_id, lc_identity); } } } + if (rlc_toadd_list) { + for (int i = 0; i < rlc_toadd_list->list.count; i++) { + NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; + int lc_identity = rlc_bearer->logicalChannelIdentity; + mac->lc_ordered_info[i].lcids_ordered = lc_identity; + NR_LogicalChannelConfig_t *mac_lc_config; + if (mac->logicalChannelConfig[lc_identity - 1] == NULL) { + /* setup of new LCID*/ + LOG_D(NR_MAC, "Establishing the logical channel %d\n", lc_identity); + AssertFatal(rlc_bearer->servedRadioBearer, "servedRadioBearer should be present for LCID establishment\n"); + if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */ + NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; + if (rlc_bearer->mac_LogicalChannelConfig != NULL) { + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + } else { + LOG_I(NR_RRC, "Applying the default logicalChannelConfig for SRB\n"); + if (srb_id == 1) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB1_logicalChannelConfig_defaultValue; + else if (srb_id == 2) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB2_logicalChannelConfig_defaultValue; + else if (srb_id == 3) + mac_lc_config = (NR_LogicalChannelConfig_t *)&NR_SRB3_logicalChannelConfig_defaultValue; + else + AssertFatal(1 == 0, "The logical id %d is not a valid SRB id %li\n", lc_identity, srb_id); + } + } else { /* DRB */ + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + AssertFatal(mac_lc_config != NULL, "For DRB, it should be mandatorily present\n"); + } + } else { + /* LC is already established, reconfiguring the LC */ + LOG_D(NR_MAC, "Logical channel %d is already established, Reconfiguring now\n", lc_identity); + if (rlc_bearer->mac_LogicalChannelConfig != NULL) { + mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; + } else { + /* Need M - Maintains current value */ + continue; + } + } + mac->lc_ordered_info[i].logicalChannelConfig_ordered = mac_lc_config; + nr_configure_mac_config_logicalChannelBearer(module_id, lc_identity, mac_lc_config); + } + + // reorder the logical channels as per its priority + qsort_r(mac->lc_ordered_info, rlc_toadd_list->list.count, sizeof(nr_lcordered_info_t), lcid_cmp, mac); + } } void configure_scc(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 32c1bb94e0..18560f3e92 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -170,24 +170,38 @@ typedef enum { RA_4STEP } nr_ra_type_e; +typedef struct { + // after multiplexing buffer remain for each lcid + int32_t LCID_buffer_remain; + // buffer status for each lcid + uint8_t LCID_status; + // Bj bucket usage per lcid + int32_t Bj; + // Bucket size per lcid + int32_t bucket_size; + // logical channel group id for each LCID + uint8_t LCGID; +} NR_LC_SCHEDULING_INFO; + +typedef struct { + // buffer status for each lcgid + uint8_t BSR; // should be more for mesh topology + // keep the number of bytes in rlc buffer for each lcgid + int32_t BSR_bytes; +} NR_LCG_SCHEDULING_INFO; + // LTE structure, might need to be adapted for NR typedef struct { - /// buffer status for each lcgid - uint8_t BSR[NR_MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcgid - int32_t BSR_bytes[NR_MAX_NUM_LCGID]; - /// after multiplexing buffer remain for each lcid - int32_t LCID_buffer_remain[NR_MAX_NUM_LCID]; + // lcs scheduling info + NR_LC_SCHEDULING_INFO lc_sched_info[NR_MAX_NUM_LCID]; + // lcg scheduling info + NR_LCG_SCHEDULING_INFO lcg_sched_info[NR_MAX_NUM_LCGID]; /// sum of all lcid buffer size - uint16_t All_lcid_buffer_size_lastTTI; - /// buffer status for each lcid - uint8_t LCID_status[NR_MAX_NUM_LCID]; + uint16_t All_lcid_buffer_size_lastTTI; /// SR pending as defined in 38.321 uint8_t SR_pending; /// SR_COUNTER as defined in 38.321 uint16_t SR_COUNTER; - /// logical channel group ide for each LCID - uint8_t LCGID[NR_MAX_NUM_LCID]; /// retxBSR-Timer, default value is sf2560 uint16_t retxBSR_Timer; /// retxBSR_SF, number of subframe before triggering a regular BSR @@ -225,11 +239,6 @@ typedef struct { uint16_t extendedBSR_Sizes_r10; /// default value is false uint16_t extendedPHR_r10; - - //Bj bucket usage per lcid - int16_t Bj[NR_MAX_NUM_LCID]; - // Bucket size per lcid - int16_t bucket_size[NR_MAX_NUM_LCID]; } NR_UE_SCHEDULING_INFO; typedef enum { @@ -423,6 +432,14 @@ typedef struct ssb_list_info { uint8_t nb_tx_ssb; } ssb_list_info_t; +typedef struct nr_lcordered_info_s { + // logical channels ids ordered as per priority + int lcids_ordered; + + // logical channel configurations reordered as per priority + NR_LogicalChannelConfig_t *logicalChannelConfig_ordered; +} nr_lcordered_info_t; + /*!\brief Top level UE MAC structure */ typedef struct { NR_UE_L2_STATE_t state; @@ -503,8 +520,11 @@ typedef struct { /// BSR report flag management uint8_t BSR_reporting_active; - /// LogicalChannelConfig has bearer. - bool active_RLC_bearer[NR_MAX_NUM_LCID]; + // Pointers to LogicalChannelConfig indexed by LogicalChannelIdentity. Note NULL means LCHAN is inactive. + NR_LogicalChannelConfig_t *logicalChannelConfig[NR_MAX_NUM_LCID]; + + // order lc info + nr_lcordered_info_t lc_ordered_info[NR_MAX_NUM_LCID]; NR_UE_SCHEDULING_INFO scheduling_info; /// PHR diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 1ac8de42b2..cb00daa6ef 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -145,6 +145,13 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value); +/*! \fn int nr_get_pbr(uint8_t prioritizedbitrate) + \brief get the rate in kbps from the rate configured by the higher layer +\param[in] prioritizedbitrate +\return the rate in kbps +*/ +uint32_t nr_get_pbr(uint8_t prioritizedbitrate); + /*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) \brief get the number of subframe from the periodic BSR timer configured by the higher layers \param[in] periodicBSR_Timer timer for periodic BSR diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index e7a3b4b812..e4bf6a0d26 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -191,17 +191,11 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) for (int i = 0; i < NR_MAX_NUM_LCID; i++) { LOG_D(NR_MAC, "Applying default logical channel config for LCGID %d\n", i); - mac->scheduling_info.Bj[i] = -1; - mac->scheduling_info.bucket_size[i] = -1; - - if (i < UL_SCH_LCID_DTCH) { // initialize all control channels lcgid to 0 - mac->scheduling_info.LCGID[i] = 0; - } else { // initialize all the data channels lcgid to 1 - mac->scheduling_info.LCGID[i] = 1; - } - - mac->scheduling_info.LCID_status[i] = LCID_EMPTY; - mac->scheduling_info.LCID_buffer_remain[i] = 0; + mac->scheduling_info.lc_sched_info[i].Bj = -1; + mac->scheduling_info.lc_sched_info[i].bucket_size = -1; + mac->scheduling_info.lc_sched_info[i].LCGID = 0; // defaults to 0 irrespective of SRB or DRB + mac->scheduling_info.lc_sched_info[i].LCID_status = LCID_EMPTY; + mac->scheduling_info.lc_sched_info[i].LCID_buffer_remain = 0; for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) mac->first_ul_tx[k] = 1; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index fb36badb4d..83ad5e88b1 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1094,6 +1094,31 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info) pthread_mutex_unlock(&ul_config->mutex_ul_config); } + // update Bj for all active lcids before LCP procedure + LOG_D(NR_MAC, "====================[Frame %d][Slot %d]Logical Channel Prioritization===========\n", frame_tx, slot_tx); + for (nr_lcordered_info_t *lc_bearer = mac->lc_ordered_info; lc_bearer->logicalChannelConfig_ordered != NULL; lc_bearer++) { + int lcid = lc_bearer->lcids_ordered; + NR_LogicalChannelConfig_t *lcconfig = mac->logicalChannelConfig[lcid - 1]; + NR_LC_SCHEDULING_INFO *sched_lc = &mac->scheduling_info.lc_sched_info[lcid - 1]; + int32_t bucketSize_max = + sched_lc->bucket_size; // max amount of data that can be buffered/accumulated in a logical channel buffer + + /* + measure Bj + increment the value of Bj by product PBR * T + */ + int T = 1; // time elapsed since Bj was last incremented + int32_t bj = sched_lc->Bj; + bj += nr_get_pbr(lcconfig->ul_SpecificParameters->prioritisedBitRate) * T; + if (lcconfig->ul_SpecificParameters->prioritisedBitRate + == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) { + bj = nr_get_pbr(lcconfig->ul_SpecificParameters->prioritisedBitRate); + } + + // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization + sched_lc->Bj = min(bj, bucketSize_max); + } + // Call BSR procedure as described in Section 5.4.5 in 38.321 // First check ReTxBSR Timer because it is always configured @@ -1146,23 +1171,23 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { // Reset transmission status lcid_bytes_in_buffer[lcid - 1] = 0; - mac->scheduling_info.LCID_status[lcid - 1] = LCID_EMPTY; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_status = LCID_EMPTY; } for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { // Reset Buffer Info - mac->scheduling_info.BSR[lcgid] = 0; - mac->scheduling_info.BSR_bytes[lcgid] = 0; + mac->scheduling_info.lcg_sched_info[lcgid].BSR = 0; + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0; } //Get Buffer Occupancy and fill lcid_reordered_array for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - if (mac->active_RLC_bearer[lcid - 1]) { // todo - int lcgid = mac->scheduling_info.LCGID[lcid - 1]; + if (mac->logicalChannelConfig[lcid - 1] != NULL) { // todo + int lcgid = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; // Store already available data to transmit per Group if (lcgid < NR_MAX_NUM_LCGID) { - lcgid_buffer_remain[lcgid] += mac->scheduling_info.LCID_buffer_remain[lcid - 1]; + lcgid_buffer_remain[lcgid] += mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain; } mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(module_idP, mac->crnti,gNB_index,frameP,slotP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, 0, 0); @@ -1172,13 +1197,13 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t if (rlc_status.bytes_in_buffer > 0) { LOG_D(NR_MAC,"[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d slot %d\n", module_idP, lcid,lcgid,rlc_status.bytes_in_buffer,frameP,slotP); - mac->scheduling_info.LCID_status[lcid - 1] = LCID_NOT_EMPTY; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_status = LCID_NOT_EMPTY; //Update BSR_bytes and position in lcid_reordered_array only if Group is defined if (lcgid < NR_MAX_NUM_LCGID) { num_lcid_with_data ++; // sum lcid buffer which has same lcgid - mac->scheduling_info.BSR_bytes[lcgid] += rlc_status.bytes_in_buffer; + mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer; //Fill in the array array_index = 0; @@ -1221,7 +1246,7 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d slot %d\n", module_idP, lcid, - mac->scheduling_info.LCGID[lcid - 1], + mac->scheduling_info.lc_sched_info[lcid - 1].LCGID, frameP, slotP); break; @@ -1241,7 +1266,7 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t //Store Buffer Occupancy in remain buffers for next TTI for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - mac->scheduling_info.LCID_buffer_remain[lcid - 1] = lcid_bytes_in_buffer[lcid - 1]; + mac->scheduling_info.lc_sched_info[lcid - 1].LCID_buffer_remain = lcid_bytes_in_buffer[lcid - 1]; } return bsr_regular_triggered; @@ -2629,7 +2654,7 @@ int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP, mac_ce_p->phr_header_len = 0; //sizeof(SCH_SUBHEADER_FIXED); int lcg_id = 0; while (lcg_id < NR_MAX_NUM_LCGID) { - if (mac->scheduling_info.BSR_bytes[lcg_id]) { + if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; } @@ -2710,11 +2735,17 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, int lcg_id_bsr_trunc = 0; for (lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) { if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) { - mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, NR_SHORT_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, + NR_SHORT_BSR_TABLE_SIZE, + mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); } else { - mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, NR_LONG_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + mac->scheduling_info.lcg_sched_info[lcg_id].BSR = + nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, + NR_LONG_BSR_TABLE_SIZE, + mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes); } - if (mac->scheduling_info.BSR_bytes[lcg_id]) { + if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) { num_lcg_id_with_data++; lcg_id_bsr_trunc = lcg_id; } @@ -2748,8 +2779,8 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, // REPORT SHORT TRUNCATED BSR //Get LCGID of highest priority LCID with data (todo) for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - lcg_id = mac->scheduling_info.LCGID[lcid - 1]; - if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.BSR_bytes[lcg_id])) { + lcg_id = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID; + if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) { lcg_id_bsr_trunc = lcg_id; } } @@ -2775,25 +2806,29 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_SHORT)) { mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t = NULL; - mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.BSR[0]; - mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.BSR[1]; - mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.BSR[2]; - mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.BSR[3]; - mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.BSR[4]; - mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.BSR[5]; - mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.BSR[6]; - mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.BSR[7]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.lcg_sched_info[0].BSR; + mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.lcg_sched_info[1].BSR; + mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.lcg_sched_info[2].BSR; + mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.lcg_sched_info[3].BSR; + mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.lcg_sched_info[4].BSR; + mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.lcg_sched_info[5].BSR; + mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.lcg_sched_info[6].BSR; + mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.lcg_sched_info[7].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 " + "%d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[0], - mac->scheduling_info.BSR[1], - mac->scheduling_info.BSR[2], - mac->scheduling_info.BSR[3], - mac->scheduling_info.BSR[4], - mac->scheduling_info.BSR[5], - mac->scheduling_info.BSR[6], - mac->scheduling_info.BSR[7]); + mac->scheduling_info.lcg_sched_info[0].BSR, + mac->scheduling_info.lcg_sched_info[1].BSR, + mac->scheduling_info.lcg_sched_info[2].BSR, + mac->scheduling_info.lcg_sched_info[3].BSR, + mac->scheduling_info.lcg_sched_info[4].BSR, + mac->scheduling_info.lcg_sched_info[5].BSR, + mac->scheduling_info.lcg_sched_info[6].BSR, + mac->scheduling_info.lcg_sched_info[7].BSR); } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) { mac_ce_p->bsr_l = NULL; @@ -2801,19 +2836,27 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, //Truncated BSR mac_ce_p->bsr_s = NULL; mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + lcg_id_bsr_trunc); } else { mac_ce_p->bsr_t = NULL; mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc; - mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, + mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR; + LOG_D(NR_MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + module_idP, + frameP, + subframe, mac->BSR_reporting_active, - mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + mac->scheduling_info.lcg_sched_info[lcg_id_bsr_trunc].BSR, + lcg_id_bsr_trunc); } } @@ -2842,6 +2885,237 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, } } +uint32_t get_count_lcids_same_priority(NR_UE_MAC_INST_t *mac, uint8_t start, uint8_t total_active_lcids, int *lcid_ordered_array) +{ + // count number of logical channels with same priority as curr_lcid + uint8_t same_priority_count = 0; + uint8_t curr_lcid = lcid_ordered_array[start]; + NR_LogicalChannelConfig_t *lc_config_curr = mac->logicalChannelConfig[curr_lcid - 1]; + for (uint8_t index = start; index < total_active_lcids; index++) { + uint8_t next_lcid = lcid_ordered_array[index]; + NR_LogicalChannelConfig_t *lc_config_next = mac->logicalChannelConfig[next_lcid - 1]; + if (lc_config_curr->ul_SpecificParameters->priority == lc_config_next->ul_SpecificParameters->priority) { + same_priority_count++; + } + } + LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", curr_lcid, same_priority_count); + return same_priority_count; +} + +long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, + uint8_t same_priority_count, + uint8_t lc_num, + uint16_t buflen_remain_ep, + int16_t buflen_remain, + uint8_t round_id, + uint32_t *bytes_read_fromlc, + long *target) +{ + /* Calculates the number of bytes the logical channel should request from the correcponding RLC buffer*/ + NR_LogicalChannelConfig_t *lc_config = mac->logicalChannelConfig[lc_num - 1]; + long pbr = nr_get_pbr(lc_config->ul_SpecificParameters->prioritisedBitRate); + int32_t lcid_remain_buffer = mac->scheduling_info.lc_sched_info[lc_num - 1].LCID_buffer_remain; + *target = (same_priority_count > 1) ? min(buflen_remain_ep, pbr) : pbr; + + long num_remaining_bytes = 0; + long num_bytes_requested = 0; + if (round_id == 0) { // initial round + uint16_t pdu_remain = (same_priority_count > 1) ? buflen_remain_ep : buflen_remain; + num_bytes_requested = (pdu_remain < pbr) ? min(pdu_remain, lcid_remain_buffer) : min(pbr, lcid_remain_buffer); + num_remaining_bytes = *target - bytes_read_fromlc[lc_num - 1]; + num_bytes_requested = min(num_bytes_requested, num_remaining_bytes); + } else { // from first round + if (same_priority_count > 1) { + num_bytes_requested = min(buflen_remain_ep, lcid_remain_buffer); + num_remaining_bytes = buflen_remain_ep - bytes_read_fromlc[lc_num - 1]; + num_bytes_requested = min(num_bytes_requested, num_remaining_bytes); + } else { + num_bytes_requested = min(buflen_remain, lcid_remain_buffer); + } + } + AssertFatal(num_remaining_bytes >= 0, "the total number of bytes allocated until target length is greater than expected\n"); + LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lc_num, num_bytes_requested); + + return num_bytes_requested; +} + +bool get_dataavailability_buffers(uint8_t total_active_lcids, int *lcid_ordered_array, bool *data_status_lcbuffers) +{ + // check whether there is any data in the rlc buffer corresponding to active lcs + for (uint8_t id = 0; id < total_active_lcids; id++) { + int lcid = lcid_ordered_array[id]; + if (data_status_lcbuffers[lcid - 1]) { + return true; + } + } + return false; +} + +uint8_t select_logical_channels(NR_UE_MAC_INST_t *mac, uint8_t *num_active_lcids, int *active_lcids) +{ + // (TODO: selection of logical channels for logical channel prioritization procedure as per 5.4.3.1.2 Selection of logical + // channels, TS38.321) + + // selection of logical channels with Bj > 0 + for (nr_lcordered_info_t *lc_bearer = mac->lc_ordered_info; lc_bearer->logicalChannelConfig_ordered != NULL; lc_bearer++) { + uint8_t lcid = lc_bearer->lcids_ordered; + if (mac->scheduling_info.lc_sched_info[lcid - 1].Bj > 0) { + active_lcids[*num_active_lcids] = lcid; + (*num_active_lcids)++; + LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, *num_active_lcids); + } + } + return 0; +} + +static bool fill_mac_sdu(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframe, + uint8_t gNB_index, + uint16_t buflen, + int16_t *buflen_remain, + int lcid, + uint8_t **pdu, + uint32_t *counter, + uint8_t count_same_priority_lcids, + uint16_t buflen_ep, + uint32_t *lcids_bytes_tot, + uint16_t *num_sdus, + NR_UE_MAC_CE_INFO *mac_ce_p, + bool *lcids_data_status, + uint8_t *num_lcids_same_priority) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; + const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); + + /* prepare the MAC sdu */ + int32_t lcid_remain_buffer = sched_info->lc_sched_info[lcid - 1].LCID_buffer_remain; + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n", + __FUNCTION__, + module_idP, + frameP, + subframe, + *counter, + *buflen_remain, + lcid_remain_buffer, + lcid); + + // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)(*pdu); + + *pdu += sh_size; + + // number of bytes requested from RLC for each LCID + long target = 0; + long bytes_requested = + get_num_bytes_to_reqlc(mac, count_same_priority_lcids, lcid, buflen_ep, *buflen_remain, *counter, lcids_bytes_tot, &target); + + uint16_t sdu_length = mac_rlc_data_req(module_idP, + mac->crnti, + gNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + bytes_requested, + (char *)(*pdu), + 0, + 0); + + AssertFatal(bytes_requested >= sdu_length, + "In %s: LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n", + __FUNCTION__, + lcid, + sdu_length, + bytes_requested); + + // Decrement Bj by the total size of MAC SDUs(RLC PDU) served to logical channel + // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there + // will be more chance for lower priority logical channels to be served in the next TTI + // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds + sched_info->lc_sched_info[lcid - 1].Bj -= sdu_length; + LOG_D(NR_MAC, + "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n", + lcid, + sdu_length, + lcid, + sched_info->lc_sched_info[lcid - 1].Bj); + + if (sdu_length > 0) { + LOG_D(NR_MAC, + "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID " + "0x%02x (buflen (TBS) %d bytes)\n", + __FUNCTION__, + module_idP, + frameP, + subframe, + (*num_sdus) + 1, + sdu_length, + lcid, + buflen); + + header->R = 0; + header->F = 1; + header->LCID = lcid; + header->L = htons(sdu_length); + +#ifdef ENABLE_MAC_PAYLOAD_DEBUG + LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); + log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); + log_dump(NR_MAC, *pdu, sdu_length, LOG_DUMP_CHAR, "\n"); +#endif + + *pdu += sdu_length; + mac_ce_p->sdu_length_total += sdu_length; + mac_ce_p->total_mac_pdu_header_len += sh_size; + + (*num_sdus)++; + } else { + *pdu -= sh_size; + lcids_data_status[lcid - 1] = false; + (*num_lcids_same_priority)--; + LOG_D(NR_MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n and hence set to false", __FUNCTION__, lcid); + return 0; + } + + *buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + + // Update Buffer remain and BSR bytes after transmission + NR_LC_SCHEDULING_INFO *lc_info = &sched_info->lc_sched_info[0] + lcid - 1; + NR_LCG_SCHEDULING_INFO *lcg_info = &sched_info->lcg_sched_info[0]; + lc_info->LCID_buffer_remain -= sdu_length; + (lcg_info + lc_info->LCGID)->BSR_bytes -= sdu_length; + LOG_D(NR_MAC, + "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d = %d\n", + module_idP, + frameP, + subframe, + lc_info->LCGID, + (lcg_info + lc_info->LCGID)->BSR_bytes); + if ((lcg_info + lc_info->LCGID)->BSR_bytes < 0) + (lcg_info + lc_info->LCGID)->BSR_bytes = 0; + + // update number of bytes served from the current lcid + lcids_bytes_tot[lcid - 1] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size); + + if ((*counter == 0 && lcids_bytes_tot[lcid - 1] >= target) + || (count_same_priority_lcids > 1 + && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in + // the first lcp run except when infinity + LOG_D(NR_MAC, + "In %s: total number bytes read from rlc buffer for lcid %d are %d\n", + __FUNCTION__, + lcid, + lcids_bytes_tot[lcid - 1]); + (*num_lcids_same_priority)--; + return 0; + } + return 1; +} + /** * Function: to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321) @@ -2872,7 +3146,6 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, //mac_ce_p->phr_ce_len = 0; //mac_ce_p->phr_header_len = 0; - uint16_t sdu_length = 0; uint16_t num_sdus = 0; mac_ce_p->sdu_length_total = 0; NR_BSR_SHORT bsr_short, bsr_truncated; @@ -2883,113 +3156,120 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, //NR_POWER_HEADROOM_CMD phr; //mac_ce_p->phr_p = &phr; NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + + NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info; //int highest_priority = 16; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); // Pointer used to build the MAC PDU by placing the RLC SDUs in the ULSCH buffer uint8_t *pdu = ulsch_buffer; - //nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length + // variable used to build the lcids with positive Bj + int lcids_bj_pos[NR_MAX_NUM_LCID] = {0}; + uint8_t avail_lcids_count = 0; + + // variable used to store the lcid data status during lcp + bool lcids_data_status[NR_MAX_NUM_LCID] = {0}; + memset(lcids_data_status, 1, NR_MAX_NUM_LCID); + + uint32_t lcp_allocation_counter = + 0; // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider + // bj and prioritized bit rate but just consider priority + uint16_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present + // 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(module_idP, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len; LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", __FUNCTION__, module_idP, frameP, subframe, buflen); - // Check for DCCH first - // TO DO: Multiplex in the order defined by the logical channel prioritization - for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) { - if (!mac->active_RLC_bearer[lcid - 1]) - continue; - buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + // selection of logical channels + select_logical_channels(mac, &avail_lcids_count, lcids_bj_pos); - LOG_D(NR_MAC, - "[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header len %d " - "bytes, buflen_remain %d bytes)\n", - module_idP, - frameP, - subframe, - lcid, - buflen, - mac_ce_p->sdu_length_total, - mac_ce_p->tot_mac_ce_len, - buflen_remain); + // multiplex in the order of highest priority + do { + /* + go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels + */ + uint8_t num_lcids_same_priority = 0; + uint8_t count_same_priority_lcids = 0; - while (buflen_remain > 0) { - // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU - NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) pdu; + // variable used to store the total bytes read from rlc for each lcid + uint32_t lcids_bytes_tot[NR_MAX_NUM_LCID] = {0}; - pdu += sh_size; + for (uint8_t id = 0; id < avail_lcids_count; id++) { + /* + loop over all logical channels in the order of priority. As stated in TS138.321 Section 5.4.3.1, in the first run, only + prioritized number of bytes are taken out from the corresponding RLC buffers of all active logical channels and if there is + still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel + is placed in the MAC PDU before going on to next high priority logical channel + */ + int lcid = lcids_bj_pos[id]; - sdu_length = mac_rlc_data_req(module_idP, - mac->crnti, - gNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - buflen_remain, - (char *)pdu, - 0, - 0); + // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to + // MAC PDU + if (!sched_info->lc_sched_info[lcid - 1].LCID_status || !lcids_data_status[lcid - 1]) { + lcids_data_status[lcid - 1] = false; + continue; + } - AssertFatal(buflen_remain >= sdu_length, - "LCID = 0x%02x RLC has segmented %d bytes but MAC has max %d remaining bytes\n", - lcid, - sdu_length, - buflen_remain); - - if (sdu_length > 0) { - LOG_D(NR_MAC, - "[UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID 0x%02x " - "(buflen (TBS) %d bytes)\n", - module_idP, - frameP, - subframe, - num_sdus + 1, - sdu_length, - lcid, - buflen); - - header->R = 0; - header->F = 1; - header->LCID = lcid; - header->L = htons(sdu_length); - - #ifdef ENABLE_MAC_PAYLOAD_DEBUG - LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size); - log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n"); - LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_length); - log_dump(NR_MAC, pdu, sdu_length, LOG_DUMP_CHAR, "\n"); - #endif - - pdu += sdu_length; - mac_ce_p->sdu_length_total += sdu_length; - mac_ce_p->total_mac_pdu_header_len += sh_size; - - num_sdus++; - - } else { - pdu -= sh_size; - LOG_D(NR_MAC, "no data to transmit for RB with LCID 0x%02x\n", lcid); - break; + // count number of lc with same priority as lcid + if (!num_lcids_same_priority) { + num_lcids_same_priority = count_same_priority_lcids = + get_count_lcids_same_priority(mac, id, avail_lcids_count, lcids_bj_pos); } buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); - //Update Buffer remain and BSR bytes after transmission - mac->scheduling_info.LCID_buffer_remain[lcid - 1] -= sdu_length; - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] -= sdu_length; LOG_D(NR_MAC, - "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d=%d\n", + "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header " + "len %d bytes," + "buflen_remain %d bytes)\n", + __FUNCTION__, module_idP, frameP, subframe, - mac->scheduling_info.LCGID[lcid - 1], - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]]); - if (mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] < 0) - mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid - 1]] = 0; + lcid, + buflen, + mac_ce_p->sdu_length_total, + mac_ce_p->tot_mac_ce_len, + buflen_remain); + + if (num_lcids_same_priority == count_same_priority_lcids) { + buflen_ep = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids; + } + + while (buflen_remain > 0) { + /* + loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes + depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all + active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates + the target number of bytes to request from RLC via 'mac_rlc_data_req' + */ + if (!fill_mac_sdu(module_idP, + frameP, + subframe, + gNB_index, + buflen, + &buflen_remain, + lcid, + &pdu, + &lcp_allocation_counter, + count_same_priority_lcids, + buflen_ep, + lcids_bytes_tot, + &num_sdus, + mac_ce_p, + lcids_data_status, + &num_lcids_same_priority)) { + break; + } + } } - } + + lcp_allocation_counter++; + } while (buflen_remain > 0 && get_dataavailability_buffers(avail_lcids_count, lcids_bj_pos, lcids_data_status)); //nr_ue_get_sdu_mac_ce_post recalculates all mac_ce related header fields since buffer has been changed after mac_rlc_data_req. //Also, BSR padding is handled here after knowing mac_ce_p->sdu_length_total. @@ -3058,3 +3338,80 @@ void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIG dl_config->number_pdus += 1; ul_time_alignment->ta_apply = false; } + +uint32_t nr_get_pbr(uint8_t prioritizedbitrate) +{ + int32_t pbr = -1; + switch (prioritizedbitrate) { + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps0: + pbr = 0; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8: + pbr = 8; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16: + pbr = 16; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32: + pbr = 32; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps64: + pbr = 64; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps128: + pbr = 128; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps256: + pbr = 256; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps512: + pbr = 512; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps1024: + pbr = 1024; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps2048: + pbr = 2048; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps4096: + pbr = 4096; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8192: + pbr = 8192; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16384: + pbr = 16384; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32768: + pbr = 32768; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps65536: + pbr = 65536; + break; + + case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity: + pbr = INT32_MAX; + break; + + default: + pbr = -1; + } + AssertFatal(pbr >= 0, "The proritized bit rate value is not one of the enum values\n"); + uint32_t pbr_bytes = + (prioritizedbitrate < NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) ? pbr * 1000 : pbr; + return pbr_bytes; +} diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c6115c555d..f5e060e251 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -460,8 +460,10 @@ void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, { ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, *rbconfig); *rbconfig = NULL; - ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig); - *rlc_rbconfig = NULL; + if (rlc_rbconfig != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig); + *rlc_rbconfig = NULL; + } } //------------------------------------------------------------------------------