Files
openairinterface5g/openair2/LAYER2/MAC/eNB_scheduler.c
T
2023-02-20 11:38:53 +01:00

1071 lines
53 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file eNB_scheduler.c
* \brief eNB scheduler top level function operates on per subframe basis
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \email: navid.nikaein@eurecom.fr
* \version 0.5
* @ingroup _mac
*/
#include "assertions.h"
#include "executables/lte-softmodem.h"
#include "LAYER2/MAC/mac.h"
#include "LAYER2/MAC/mac_extern.h"
#include "LAYER2/MAC/mac_proto.h"
#include "common/utils/LOG/log.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#include "RRC/LTE/rrc_extern.h"
#include "RRC/NR/nr_rrc_extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"
/* for fair round robin SCHED */
#include "eNB_scheduler_fairRR.h"
#include "intertask_interface.h"
#include "assertions.h"
#define ENABLE_MAC_PAYLOAD_DEBUG
#define DEBUG_eNB_SCHEDULER 1
extern RAN_CONTEXT_t RC;
uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
//-----------------------------------------------------------------------------
/*
* Schedule periodic SRS
*/
void schedule_SRS(module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP)
//-----------------------------------------------------------------------------
{
int CC_id = 0;
int UE_id = -1;
uint8_t TSFC = 0;
uint8_t srs_SubframeConfig = 0;
uint16_t srsPeriodicity = 0;
uint16_t srsOffset = 0;
uint16_t deltaTSFC = 0; // bitmap
// table for TSFC (Period) and deltaSFC (offset)
const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD
const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_info_t *UE_info = &eNB->UE_info;
nfapi_ul_config_request_body_t *ul_req = NULL;
UE_sched_ctrl_t *UE_scheduling_control = NULL;
COMMON_channels_t *cc = eNB->common_channels;
LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon = NULL;
struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated = NULL;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
soundingRS_UL_ConfigCommon = &(cc[CC_id].radioResourceConfigCommon->soundingRS_UL_ConfigCommon);
/* Check if SRS is enabled in this frame/subframe */
if (soundingRS_UL_ConfigCommon) {
srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig;
if (cc[CC_id].tdd_Config == NULL) { // FDD
deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0];
TSFC = deltaTSFCTabType1[srs_SubframeConfig][1];
} else { // TDD
deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0];
TSFC = deltaTSFCTabType2[srs_SubframeConfig][1];
}
/* Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC) */
uint16_t tmp = (subframeP % TSFC);
if ((1 << tmp) & deltaTSFC) {
/* This is an SRS subframe, loop over UEs */
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
if (!UE_info->active[UE_id]) {
continue;
}
/* Drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet */
if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) {
continue;
}
if(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) {
LOG_E(MAC,"physicalConfigDedicated is null for UE %d\n",UE_id);
printf("physicalConfigDedicated is null for UE %d\n",UE_id);
return;
}
/* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
/* Test if Active Time not running since 6+ subframes */
if (UE_scheduling_control->cdrx_configured == true && UE_scheduling_control->in_active_time == false) {
/*
* TODO: 6+ subframes condition not checked here
*/
continue;
}
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
if ((soundingRS_UL_ConfigDedicated = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) {
if (soundingRS_UL_ConfigDedicated->present == LTE_SoundingRS_UL_ConfigDedicated_PR_setup) {
get_srs_pos(&cc[CC_id],
soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex,
&srsPeriodicity,
&srsOffset);
if (((10 * frameP + subframeP) % srsPeriodicity) == srsOffset) {
// Program SRS
ul_req->srs_present = 1;
nfapi_ul_config_request_pdu_t *ul_config_pdu = &(ul_req->ul_config_pdu_list[ul_req->number_of_pdus]);
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE;
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_srs_pdu));
ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG;
ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu);
ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth;
ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition;
ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;;
ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb;
ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex;
ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift;
eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
eNB->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST;
ul_req->number_of_pdus++;
} // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset)
} // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup)
} // if ((soundingRS_UL_ConfigDedicated = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL)
} // end for loop on UE_id
} // if((1<<tmp) & deltaTSFC)
} // SRS config not NULL
} // end for loop on CC_id
}
//-----------------------------------------------------------------------------
/*
* Schedule the CSI (CQI/PMI/RI/PTI/CRI) periodic reception
*/
void schedule_CSI(module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP)
//-----------------------------------------------------------------------------
{
int CC_id = 0;
int UE_id = 0;
int H = 0;
uint16_t Npd = 0;
uint16_t N_OFFSET_CQI = 0;
struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = NULL;
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_info_t *UE_info = &eNB->UE_info;
COMMON_channels_t *cc = NULL;
nfapi_ul_config_request_body_t *ul_req = NULL;
UE_sched_ctrl_t *UE_scheduling_control = NULL;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
cc = &eNB->common_channels[CC_id];
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
if (UE_info->active[UE_id] == false) {
continue;
}
/* Drop the allocation if the UE hasn't sent RRCConnectionSetupComplete yet */
if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) {
continue;
}
AssertFatal(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
"physicalConfigDedicated is null for UE %d\n",
UE_id);
/*
* CDRX condition on Active Time and CSI report on PUCCH (36.321 5.7).
* Here we consider classic periodic reports on PUCCH without PUSCH simultaneous transmission condition.
* TODO: add the handling or test on simultaneous PUCCH/PUSCH transmission
*/
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
if (UE_scheduling_control->cdrx_configured == true) {
/* Test if CQI masking activated */
if (UE_scheduling_control->cqi_mask_boolean == true) {
// CQI masking => test if onDurationTime not running since 6+ subframe
if (UE_scheduling_control->on_duration_timer == 0) {
/*
* TODO: 6+ subframes condition not checked here
*/
continue;
}
} else { // No CQI masking => test if Active Time not running since 6+ subframe
if (UE_scheduling_control->in_active_time == false) {
/*
* TODO: 6+ subframes condition not checked here
*/
continue;
}
}
}
ul_req = &(eNB->UL_req[CC_id].ul_config_request_body);
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) {
cqi_ReportPeriodic = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic;
if (cqi_ReportPeriodic != NULL) {
/* Rel8 Periodic CSI (CQI/PMI/RI) reporting */
if (cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_release) {
get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H);
if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI periodic opportunity
UE_scheduling_control->feedback_cnt[CC_id] = (((frameP * 10) + subframeP) / Npd) % H;
// Program CQI
nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus];
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE;
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu));
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_info->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id),
cqi_ReportPeriodic);
ul_req->number_of_pdus++;
ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
// PUT rel10-13 UCI options here
} else if (cqi_ReportPeriodic->choice.setup.ri_ConfigIndex != NULL) {
if ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) ==
N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161)) { // RI opportunity
// Program RI
nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus];
memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t));
ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE;
ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu));
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex;
ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2;
RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
ul_req->number_of_pdus++;
ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
}
}
} // if CSI Periodic is not release state
} // if (cqi_ReportPeriodic != NULL)
} // if cqi_ReportConfig != NULL
} // for (UE_id=UE_info->head; UE_id>=0; UE_id=UE_info->next[UE_id]) {
} // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
}
//-----------------------------------------------------------------------------
/*
* Schedule a possible Scheduling Request reception
*/
void
schedule_SR (module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP)
//-----------------------------------------------------------------------------
{
int skip_ue = 0;
int is_harq = 0;
int pdu_list_index = 0;
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_info_t *UE_info = &eNB->UE_info;
nfapi_ul_config_request_t *ul_req = NULL;
nfapi_ul_config_request_body_t *ul_req_body = NULL;
LTE_SchedulingRequestConfig_t *SRconfig = NULL;
nfapi_ul_config_sr_information sr;
memset(&sr, 0, sizeof(sr));
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
if (!UE_info->active[UE_id]) {
continue;
}
if (UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue;
if ((SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) {
if (SRconfig->present == LTE_SchedulingRequestConfig_PR_setup) {
if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period
if ((subframeP % 5) != SRconfig->choice.setup.sr_ConfigIndex) continue;
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period
if (subframeP != (SRconfig->choice.setup.sr_ConfigIndex - 5)) continue;
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period
if ((10 * (frameP & 1) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 15)) continue;
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period
if ((10 * (frameP & 3) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 35)) continue;
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period
if ((10 * (frameP & 7) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 75)) continue;
} else if (SRconfig->choice.setup.sr_ConfigIndex <= 156) { // 2ms SR period
if ((subframeP % 2) != (SRconfig->choice.setup.sr_ConfigIndex - 155)) continue;
}
} // SRconfig->present == SchedulingRequestConfig_PR_setup)
} // SRconfig = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL)
/* If we get here there is some PUCCH1 reception to schedule for SR */
ul_req = &(eNB->UL_req[CC_id]);
ul_req_body = &(ul_req->ul_config_request_body);
skip_ue = 0;
is_harq = 0;
pdu_list_index = 0;
/* Check that there is no existing UL grant for ULSCH which overrides the SR */
for (int i = 0; i < ul_req_body->number_of_pdus; i++) {
if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) ||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) ||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) ||
(ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) &&
(ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
skip_ue = 1;
pdu_list_index = i;
break;
}
/* If there is already an HARQ pdu, convert to SR_HARQ */
else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) &&
(ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_info->UE_template[CC_id][UE_id].rnti)) {
is_harq = 1;
pdu_list_index = i;
break;
}
}
/* Drop the allocation because ULSCH will handle it with BSR */
if (skip_ue == 1) continue;
LOG_D(MAC, "Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d \n",
frameP,
subframeP,
UE_id,
UE_info->UE_template[CC_id][UE_id].rnti,
is_harq);
/* Check Rel10 or Rel8 SR */
if ((UE_info-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) &&
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) &&
(UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) {
sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG;
sr.sr_information_rel10.number_of_pucch_resources = 1;
sr.sr_information_rel10.pucch_index_p1 = *UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10;
LOG_D(MAC, "REL10 PUCCH INDEX P1:%d \n", sr.sr_information_rel10.pucch_index_p1);
} else {
sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG;
sr.sr_information_rel8.pucch_index = UE_info->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex;
LOG_D(MAC, "REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index);
}
/* If there is already an HARQ pdu, convert to SR_HARQ */
if (is_harq) {
nfapi_ul_config_harq_information harq = ul_req_body->ul_config_pdu_list[pdu_list_index].uci_harq_pdu.harq_information;
ul_req_body->ul_config_pdu_list[pdu_list_index].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE;
ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.sr_information = sr;
ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.harq_information = harq;
} else {
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE;
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_info->UE_template[CC_id][UE_id].rnti;
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0;
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0;
ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr;
ul_req_body->number_of_pdus++;
} // if (is_harq)
ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG;
} // for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++)
} // for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
}
void
check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
frame_t frameP, sub_frame_t subframeP) {
UE_info_t *UE_info = &RC.mac[module_idP]->UE_info;
nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0];
uint16_t rnti = UE_RNTI(module_idP, UE_id);
COMMON_channels_t *cc = RC.mac[module_idP]->common_channels;
// check uplink failure
if ((UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 0) &&
(UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) {
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer == 1)
LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti,
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
if (UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) {
UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1;
// add a format 1A dci for this UE to request an RA procedure (only one UE per subframe)
nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu];
memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t));
dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu));
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id),
UE_info->UE_sched_ctrl[UE_id].
dl_cqi[CC_id], format1A);
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power
AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) && (cc[CC_id].mib->message.dl_Bandwidth < 6),
"illegal dl_Bandwidth %d\n",
(int) cc[CC_id].mib->message.dl_Bandwidth);
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth];
DL_req[CC_id].dl_config_request_body.number_dci++;
DL_req[CC_id].dl_config_request_body.number_pdu++;
DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
LOG_D(MAC,
"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",
UE_id, rnti,
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer,
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.resource_block_coding);
} else { // ra_pdcch_sent==1
LOG_D(MAC,
"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",
UE_id, rnti,
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer);
if ((UE_info->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_info->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames
}
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer++;
// check threshold
if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) {
// note: probably ul_failure_timer should be less than UE radio link failure time(see T310/N310/N311)
// inform RRC of failure and clear timer
LOG_I(MAC, "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", UE_id, rnti);
mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, subframeP, rnti);
UE_info->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync = 1;
}
} // ul_failure_timer>0
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer++;
if((U_PLANE_INACTIVITY_VALUE != 0) && (UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE * 10))) {
LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti);
mac_eNB_rrc_uplane_failure(module_idP,CC_id,frameP,subframeP,rnti);
UE_info->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
}// time > 60s
}
void
clear_nfapi_information(eNB_MAC_INST *eNB, int CC_idP,
frame_t frameP, sub_frame_t subframeP) {
nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0];
nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0];
nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframeP];
nfapi_tx_request_t *TX_req = &eNB->TX_req[0];
eNB->pdu_index[CC_idP] = 0;
if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MONOLITHIC) { // monolithic or PNF
DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1;
DL_req[CC_idP].dl_config_request_body.number_dci = 0;
DL_req[CC_idP].dl_config_request_body.number_pdu = 0;
DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0;
DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000;
DL_req[CC_idP].sfn_sf = subframeP + (frameP<<4);
HI_DCI0_req->hi_dci0_request_body.sfnsf = subframeP + (frameP<<4);
HI_DCI0_req->hi_dci0_request_body.number_of_dci = 0;
UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0;
UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now
UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now
TX_req[CC_idP].tx_request_body.number_of_pdus = 0;
}
}
void
copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) {
int CC_id;
eNB_MAC_INST *mac = RC.mac[module_idP];
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP];
nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id];
nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list;
*ul_req = *ul_req_tmp;
// Restore the pointer
ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu;
ul_req->sfn_sf = (frameP<<4) + subframeP;
ul_req_tmp->ul_config_request_body.number_of_pdus = 0;
if (ul_req->ul_config_request_body.number_of_pdus>0) {
LOG_D(MAC, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus);
}
memcpy((void *)ul_req->ul_config_request_body.ul_config_pdu_list,
(void *)ul_req_tmp->ul_config_request_body.ul_config_pdu_list,
ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t));
}
}
#include <openair1/PHY/LTE_TRANSPORT/transport_proto.h>
void
eNB_dlsch_ulsch_scheduler(module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP) {
int mbsfn_status[MAX_NUM_CCs];
protocol_ctxt_t ctxt;
rnti_t rnti = 0;
int CC_id = 0;
int UE_id = -1;
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_info_t *UE_info = &(eNB->UE_info);
COMMON_channels_t *cc = eNB->common_channels;
UE_sched_ctrl_t *UE_scheduling_control = NULL;
start_meas(&(eNB->eNB_scheduler));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_IN);
// TODO: Better solution needed this is the first
// 3 indications of this function on startup
// 1303275.278188 [MAC] XXX 0.0 -> 0.4 = 4
// 1303275.279443 [MAC] XXX 0.4 -> 639.5 = 6391
// 1303275.348686 [MAC] XXX 646.3 -> 646.3 = 0
int delta = (frameP * 10 + subframeP) - (eNB->frame * 10 + eNB->subframe);
if (delta < 0)
{
delta += 10240; // sfn_sf decimal values range from 0 to 10239
}
// If we ever see a difference this big something is very wrong
// This threshold is arbitrary
if (delta > 8500 || delta == 0) // 850 frames
{
LOG_I(MAC, "scheduler ignoring outerspace %d.%d -> %d.%d = %d\n",
eNB->frame, eNB->subframe, frameP, subframeP, delta);
return;
}
LOG_D(MAC, "Entering dlsch_ulsch scheduler %d.%d -> %d.%d = %d\n",
eNB->frame, eNB->subframe, frameP, subframeP, delta);
eNB->frame = frameP;
eNB->subframe = subframeP;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
mbsfn_status[CC_id] = 0;
/* Clear vrb_maps */
memset(cc[CC_id].vrb_map, 0, 100);
memset(cc[CC_id].vrb_map_UL, 0, 100);
cc[CC_id].mcch_active = 0;
clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP);
/* hack: skip BCH RBs in subframe 0 for DL scheduling,
* because with high MCS we may exceed code rate 0.93
* when using those RBs (36.213 7.1.7 says the UE may
* skip decoding if the code rate is higher than 0.93)
* TODO: remove this hack, deal with physical bits properly
* i.e. reduce MCS in the scheduler if code rate > 0.93
*/
if (subframeP == 0) {
int i;
int bw = cc[CC_id].mib->message.dl_Bandwidth;
/* start and count defined for RBs: 6, 15, 25, 50, 75, 100 */
int start[6] = { 0, 4, 9, 22, 34, 47 };
int count[6] = { 6, 7, 7, 6, 7, 6 };
for (i = 0; i < count[bw]; i++)
cc[CC_id].vrb_map[start[bw] + i] = 1;
}
}
/* Refresh UE list based on UEs dropped by PHY in previous subframe */
for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
if (UE_info->active[UE_id]) {
rnti = UE_RNTI(module_idP, UE_id);
CC_id = UE_PCCID(module_idP, UE_id);
UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]);
/* to be merged with MAC_stats.log generation. probably redundant
if (((frameP & 127) == 0) && (subframeP == 0)) {
double total_bler;
if(UE_scheduling_control->pusch_rx_num[CC_id] == 0 && UE_scheduling_control->pusch_rx_error_num[CC_id] == 0) {
total_bler = 0;
}
else {
total_bler = (double)UE_scheduling_control->pusch_rx_error_num[CC_id] / (double)(UE_scheduling_control->pusch_rx_error_num[CC_id] + UE_scheduling_control->pusch_rx_num[CC_id]) * 100;
}
LOG_I(MAC,"UE %x : %s, PHR %d DLCQI %d PUSCH %d PUCCH %d RLC disc %d UL-stat rcv %lu err %lu bler %lf mcsoff %d bsr %u sched %u tbs %lu cnt %u , DL-stat tbs %lu cnt %u rb %u buf %u 1st %u ret %u ri %d\n",
rnti,
UE_scheduling_control->ul_out_of_sync == 0 ? "in synch" : "out of sync",
UE_info->UE_template[CC_id][UE_id].phr_info,
UE_scheduling_control->dl_cqi[CC_id],
UE_scheduling_control->pusch_snr_avg[CC_id],
UE_scheduling_control->pucch1_snr[CC_id],
UE_scheduling_control->rlc_out_of_resources_cnt,
UE_scheduling_control->pusch_rx_num[CC_id],
UE_scheduling_control->pusch_rx_error_num[CC_id],
total_bler,
UE_scheduling_control->mcs_offset[CC_id],
UE_info->UE_template[CC_id][UE_id].estimated_ul_buffer,
UE_info->UE_template[CC_id][UE_id].scheduled_ul_bytes,
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes_rx,
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus_rx,
UE_info->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes,
UE_info->eNB_UE_stats[CC_id][UE_id].total_num_pdus,
UE_info->eNB_UE_stats[CC_id][UE_id].total_rbs_used,
#if defined(PRE_SCD_THREAD)
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
#else
0,
#endif
UE_scheduling_control->first_cnt[CC_id],
UE_scheduling_control->ret_cnt[CC_id],
UE_scheduling_control->aperiodic_ri_received[CC_id]
);
}
*/
RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = -63;
if (UE_id == UE_info->list.head) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP]);
}
/* Set and increment CDRX related timers */
if (UE_scheduling_control->cdrx_configured == true) {
bool harq_active_time_condition = false;
UE_TEMPLATE *UE_template = NULL;
unsigned long active_time_condition = 0; // variable used only for tracing purpose
/* (UL and DL) HARQ RTT timers and DRX retransmission timers */
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
/* DL asynchronous HARQ process */
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) {
UE_scheduling_control->drx_retransmission_timer[harq_process_id]++;
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > UE_scheduling_control->drx_retransmission_timer_thres[harq_process_id]) {
UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 0;
}
}
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) {
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++;
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) {
/* Note: here drx_retransmission_timer is restarted instead of started in the specification */
UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 1; // started when HARQ RTT timer expires
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0;
}
}
/* UL asynchronous HARQ process: only UL HARQ RTT timer is implemented (hence not implemented) */
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) {
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++;
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) {
/*
* TODO: implement the handling of UL asynchronous HARQ
* drx_ULRetransmissionTimer should be (re)started here
*/
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0;
}
}
/* UL synchronous HARQ process */
if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 0) {
UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id]++;
if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 5) {
harq_active_time_condition = true;
UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] = 0;
active_time_condition = 5; // for tracing purpose
}
}
}
/* On duration timer */
if (UE_scheduling_control->on_duration_timer > 0) {
UE_scheduling_control->on_duration_timer++;
if (UE_scheduling_control->on_duration_timer > UE_scheduling_control->on_duration_timer_thres) {
UE_scheduling_control->on_duration_timer = 0;
}
}
/* DRX inactivity timer */
if (UE_scheduling_control->drx_inactivity_timer > 0) {
UE_scheduling_control->drx_inactivity_timer++;
if (UE_scheduling_control->drx_inactivity_timer > (UE_scheduling_control->drx_inactivity_timer_thres + 1)) {
/* Note: the +1 on the threshold is due to information in table C-1 of 36.321 */
UE_scheduling_control->drx_inactivity_timer = 0;
/* When timer expires switch into short or long DRX cycle */
if (UE_scheduling_control->drx_shortCycle_timer_thres > 0) {
UE_scheduling_control->in_short_drx_cycle = true;
UE_scheduling_control->drx_shortCycle_timer = 0;
UE_scheduling_control->in_long_drx_cycle = false;
} else {
UE_scheduling_control->in_long_drx_cycle = true;
}
}
}
/* Short DRX Cycle */
if (UE_scheduling_control->in_short_drx_cycle == true) {
UE_scheduling_control->drx_shortCycle_timer++;
/* When the Short DRX cycles are over, switch to long DRX cycle */
if (UE_scheduling_control->drx_shortCycle_timer > UE_scheduling_control->drx_shortCycle_timer_thres) {
UE_scheduling_control->drx_shortCycle_timer = 0;
UE_scheduling_control->in_short_drx_cycle = false;
UE_scheduling_control->in_long_drx_cycle = true;
UE_scheduling_control->drx_longCycle_timer = 0;
}
} else {
UE_scheduling_control->drx_shortCycle_timer = 0;
}
/* Long DRX Cycle */
if (UE_scheduling_control->in_long_drx_cycle == true) {
UE_scheduling_control->drx_longCycle_timer++;
if (UE_scheduling_control->drx_longCycle_timer > UE_scheduling_control->drx_longCycle_timer_thres) {
UE_scheduling_control->drx_longCycle_timer = 1;
}
} else {
UE_scheduling_control->drx_longCycle_timer = 0;
}
/* Check for error cases */
if ((UE_scheduling_control->in_short_drx_cycle == true) && (UE_scheduling_control->in_long_drx_cycle == true)) {
LOG_E(MAC, "Error in C-DRX: UE id %d is in both short and long DRX cycle. Should not happen. Back it to long cycle only\n", UE_id);
UE_scheduling_control->in_short_drx_cycle = false;
}
/* Condition to start On Duration Timer */
if (UE_scheduling_control->in_short_drx_cycle == true && UE_scheduling_control->on_duration_timer == 0) {
if (((frameP * 10) + subframeP) % (UE_scheduling_control->short_drx_cycle_duration) ==
(UE_scheduling_control->drx_start_offset) % (UE_scheduling_control->short_drx_cycle_duration)) {
UE_scheduling_control->on_duration_timer = 1;
}
} else if (UE_scheduling_control->in_long_drx_cycle == true && UE_scheduling_control->on_duration_timer == 0) {
if (((frameP * 10) + subframeP) % (UE_scheduling_control->drx_longCycle_timer_thres) ==
(UE_scheduling_control->drx_start_offset)) {
UE_scheduling_control->on_duration_timer = 1;
}
}
/* Update Active Time status of UE
* Based on 36.321 5.7 the differents conditions for the UE to be in Acttive Should be check ONLY
* here for the current subframe. The variable 'UE_scheduling_control->in_active_time' should be updated
* ONLY here. The variable can then be used for testing the actual state of the UE for scheduling purpose.
*/
UE_template = &(UE_info->UE_template[CC_id][UE_id]);
/* (a)synchronous HARQ processes handling for Active Time */
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) {
harq_active_time_condition = true;
active_time_condition = 2; // for tracing purpose
break;
}
}
/* Active time conditions */
if (UE_scheduling_control->on_duration_timer > 0 ||
UE_scheduling_control->drx_inactivity_timer > 1 ||
harq_active_time_condition ||
UE_template->ul_SR > 0) {
UE_scheduling_control->in_active_time = true;
} else {
UE_scheduling_control->in_active_time = false;
}
/* BEGIN VCD */
if (UE_id == 0) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ON_DURATION_TIMER, (unsigned long) UE_scheduling_control->on_duration_timer);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_INACTIVITY, (unsigned long) UE_scheduling_control->drx_inactivity_timer);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_SHORT_CYCLE, (unsigned long) UE_scheduling_control->drx_shortCycle_timer);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_LONG_CYCLE, (unsigned long) UE_scheduling_control->drx_longCycle_timer);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_RETRANSMISSION_HARQ0, (unsigned long) UE_scheduling_control->drx_retransmission_timer[0]);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME, (unsigned long) UE_scheduling_control->in_active_time);
/* For tracing purpose */
if (UE_template->ul_SR > 0) {
active_time_condition = 1;
} else if ((UE_scheduling_control->on_duration_timer > 0) && (active_time_condition == 0)) {
active_time_condition = 3;
} else if ((UE_scheduling_control->drx_inactivity_timer > 1) && (active_time_condition == 0)) {
active_time_condition = 4;
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME_CONDITION, (unsigned long) active_time_condition);
}
/* END VCD */
/* DCI0 ongoing timer */
if (UE_scheduling_control->dci0_ongoing_timer > 0) {
if (UE_scheduling_control->dci0_ongoing_timer > 7) {
UE_scheduling_control->dci0_ongoing_timer = 0;
} else {
UE_scheduling_control->dci0_ongoing_timer++;
}
}
} else { // else: CDRX not configured
/* Note: (UL) HARQ RTT timers processing is done here and can be used by other features than CDRX */
/* HARQ RTT timers */
for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) {
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) {
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++;
if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) {
UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0;
}
}
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) {
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++;
if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) {
UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0;
}
}
} // end loop harq process
} // end else CDRX not configured
/* Increment these timers, they are cleared when we receive an sdu */
UE_scheduling_control->ul_inactivity_timer++;
UE_scheduling_control->cqi_req_timer++;
LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n",
UE_id,
rnti,
UE_scheduling_control->ul_inactivity_timer,
UE_scheduling_control->cqi_req_timer);
check_ul_failure(module_idP, CC_id, UE_id, frameP, subframeP);
if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) {
UE_scheduling_control->ue_reestablishment_reject_timer++;
if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) {
UE_scheduling_control->ue_reestablishment_reject_timer = 0;
/* Clear reestablish_rnti_map */
if (UE_scheduling_control->ue_reestablishment_reject_timer_thres > 20) {
for (int ue_id_l = 0; ue_id_l < MAX_MOBILES_PER_ENB; ue_id_l++) {
if (reestablish_rnti_map[ue_id_l][0] == rnti) {
/* Clear currentC-RNTI from map */
reestablish_rnti_map[ue_id_l][0] = 0;
reestablish_rnti_map[ue_id_l][1] = 0;
break;
}
}
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rnti, 0, 0,module_idP);
rrc_rlc_remove_ue(&ctxt);
pdcp_remove_UE(&ctxt);
}
/* Note: This should not be done in the MAC! */
/*
for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) {
LTE_eNB_ULSCH_t *ulsch = RC.eNB[module_idP][CC_id]->ulsch[ii];
if((ulsch != NULL) && (ulsch->rnti == rnti)) {
void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti);
clean_eNb_ulsch(ulsch);
}
}
for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) {
LTE_eNB_DLSCH_t *dlsch = RC.eNB[module_idP][CC_id]->dlsch[ii][0];
if((dlsch != NULL) && (dlsch->rnti == rnti)) {
void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch);
LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti);
clean_eNb_dlsch(dlsch);
}
}
*/
int id;
// clean ULSCH entries for rnti
id = find_ulsch(rnti,RC.eNB[module_idP][CC_id],SEARCH_EXIST);
if (id>=0) clean_eNb_ulsch(RC.eNB[module_idP][CC_id]->ulsch[id]);
// clean DLSCH entries for rnti
id = find_dlsch(rnti,RC.eNB[module_idP][CC_id],SEARCH_EXIST);
if (id>=0) clean_eNb_dlsch(RC.eNB[module_idP][CC_id]->dlsch[id][0]);
for (int j = 0; j < 10; j++) {
nfapi_ul_config_request_body_t *ul_req_tmp = NULL;
ul_req_tmp = &(eNB->UL_req_tmp[CC_id][j].ul_config_request_body);
if (ul_req_tmp) {
int pdu_number = ul_req_tmp->number_of_pdus;
for (int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) {
if (ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) {
LOG_I(MAC, "remove UE %x from ul_config_pdu_list %d/%d\n",
rnti,
pdu_index,
pdu_number);
if (pdu_index < pdu_number -1) {
memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index],
&ul_req_tmp->ul_config_pdu_list[pdu_index+1],
(pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t));
}
ul_req_tmp->number_of_pdus--;
}
} // end for pdu_index
} // end if (ul_req_tmp)
} // end for j
rrc_mac_remove_ue(module_idP,rnti);
} // end if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres)
} // end if (UE_scheduling_control->ue_reestablishment_reject_timer > 0)
} // end if UE active
} // end for loop on UE_id
#if (!defined(PRE_SCD_THREAD))
void rlc_tick(int, int);
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP);
rlc_tick(frameP, subframeP);
pdcp_run(&ctxt);
pdcp_mbms_run(&ctxt);
rrc_rx_tx(&ctxt, CC_id);
#endif
int do_fembms_si=0;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
if (cc[CC_id].MBMS_flag > 0) {
start_meas(&RC.mac[module_idP]->schedule_mch);
int(*schedule_mch)(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframe) = NULL;
schedule_mch = schedule_MBMS_NFAPI;
if(schedule_mch){
mbsfn_status[CC_id] = schedule_mch(module_idP, CC_id, frameP, subframeP);
}
stop_meas(&RC.mac[module_idP]->schedule_mch);
}
if (cc[CC_id].FeMBMS_flag > 0) {
do_fembms_si = 1;
}
}
static int debug_flag = 0;
void (*schedule_ulsch_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe) = NULL;
void (*schedule_ue_spec_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, int *mbsfn_flag) = NULL;
if (eNB->scheduler_mode == SCHED_MODE_DEFAULT) {
schedule_ulsch_p = schedule_ulsch;
schedule_ue_spec_p = schedule_dlsch;
} else if (eNB->scheduler_mode == SCHED_MODE_FAIR_RR) {
memset(dlsch_ue_select, 0, sizeof(dlsch_ue_select));
schedule_ulsch_p = schedule_ulsch_fairRR;
schedule_ue_spec_p = schedule_ue_spec_fairRR;
}
if(debug_flag == 0) {
LOG_E(MAC,"SCHED_MODE = %d\n", eNB->scheduler_mode);
debug_flag = 1;
}
/* This schedules MIB */
if(!do_fembms_si/*get_softmodem_params()->fembms*/){
if ((subframeP == 0) && (frameP & 3) == 0)
schedule_mib(module_idP, frameP, subframeP);
}else{
if ((subframeP == 0) && (frameP & 15) == 0 ){
schedule_fembms_mib(module_idP, frameP, subframeP);
//schedule_SI_MBMS(module_idP, frameP, subframeP);
}
}
if (get_softmodem_params()->phy_test == 0) {
/* This schedules SI for legacy LTE and eMTC starting in subframeP */
if(!do_fembms_si/*get_softmodem_params()->fembms*/)
schedule_SI(module_idP, frameP, subframeP);
else
schedule_SI_MBMS(module_idP, frameP, subframeP);
/* This schedules Paging in subframeP */
schedule_PCH(module_idP,frameP,subframeP);
/* This schedules Random-Access for legacy LTE and eMTC starting in subframeP */
schedule_RA(module_idP, frameP, subframeP);
/* Copy previously scheduled UL resources (ULSCH + HARQ) */
copy_ulreq(module_idP, frameP, subframeP);
/* This schedules SRS in subframeP */
schedule_SRS(module_idP, frameP, subframeP);
/* This schedules ULSCH in subframeP (dci0) */
if (schedule_ulsch_p != NULL) {
schedule_ulsch_p(module_idP, frameP, subframeP);
} else {
LOG_E(MAC," %s %d: schedule_ulsch_p is NULL, function not called\n",
__FILE__,
__LINE__);
}
/* This schedules UCI_SR in subframeP */
schedule_SR(module_idP, frameP, subframeP);
/* This schedules UCI_CSI in subframeP */
schedule_CSI(module_idP, frameP, subframeP);
/* This schedules DLSCH in subframeP for BR UE*/
schedule_ue_spec_br(module_idP, frameP, subframeP);
/* This schedules DLSCH in subframeP */
if (schedule_ue_spec_p != NULL) {
schedule_ue_spec_p(module_idP, frameP, subframeP, mbsfn_status);
} else {
LOG_E(MAC," %s %d: schedule_ue_spec_p is NULL, function not called\n",
__FILE__,
__LINE__);
}
} else {
schedule_ulsch_phy_test(module_idP,frameP,subframeP);
schedule_ue_spec_phy_test(module_idP,frameP,subframeP,mbsfn_status);
}
/* Allocate CCEs for good after scheduling is done */
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
if (cc[CC_id].tdd_Config == NULL || !(is_UL_sf(&cc[CC_id],subframeP))) {
int rc = allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
if (rc < 0)
LOG_E(MAC, "%s() %4d.%d ERROR ALLOCATING CCEs\n", __func__, frameP, subframeP);
}
}
stop_meas(&(eNB->eNB_scheduler));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT);
}