OAI is riddled with boolean_t, FALSE, TRUE, etc. This makes no sense, as there is a standard bool type, and could lead to nasty bugs if a definition of a bool is non-standard (0 == false, true == !false). This commit removes all non-standard bools in the whole project.
1099 lines
54 KiB
C
1099 lines
54 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 "targets/RT/USER/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"
|
|
|
|
//Agent-related headers
|
|
#include "flexran_agent_extern.h"
|
|
#include "flexran_agent_mac.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)
|
|
if (NODE_IS_DU(RC.rrc[module_idP]->node_type)) {
|
|
MessageDef *m = itti_alloc_new_message(TASK_MAC_ENB, 0, F1AP_UE_CONTEXT_RELEASE_REQ);
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rnti = rnti;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).cause = F1AP_CAUSE_RADIO_NETWORK;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).cause_value = 1; // 1 = F1AP_CauseRadioNetwork_rl_failure
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container = NULL;
|
|
F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container_length = 0;
|
|
itti_send_msg_to_task(TASK_DU_F1, module_idP, m);
|
|
} else {
|
|
// 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))
|
|
if (!NODE_IS_DU(RC.rrc[module_idP]->node_type)) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) {
|
|
flexran_agent_slice_update(module_idP);
|
|
}
|
|
if (flexran_agent_get_mac_xface(module_idP))
|
|
flexran_agent_get_mac_xface(module_idP)->flexran_agent_notify_tick(module_idP);
|
|
|
|
stop_meas(&(eNB->eNB_scheduler));
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT);
|
|
}
|