eNB_scheduler.c 34 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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
 */
21 22

/*! \file eNB_scheduler.c
23
 * \brief eNB scheduler top level function operates on per subframe basis
24 25
 * \author  Navid Nikaein and Raymond Knopp
 * \date 2010 - 2014
26
 * \email: navid.nikaein@eurecom.fr
27 28
 * \version 0.5
 * @ingroup _mac
29

30
 */
31

32
#include "assertions.h"
33
#include "targets/RT/USER/lte-softmodem.h"
34 35
#include "LAYER2/MAC/mac.h"
#include "LAYER2/MAC/mac_extern.h"
36

37
#include "LAYER2/MAC/mac_proto.h"
38 39
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
40 41 42
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
43

44
#include "RRC/LTE/rrc_extern.h"
45
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
46

47 48
//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"
49

50
//Agent-related headers
51 52
#include "flexran_agent_extern.h"
#include "flexran_agent_mac.h"
53

54 55 56
/* for fair round robin SCHED */
#include "eNB_scheduler_fairRR.h"

57
#if defined(ENABLE_ITTI)
58
#include "intertask_interface.h"
59 60
#endif

61 62
#include "assertions.h"

63 64
#define ENABLE_MAC_PAYLOAD_DEBUG
#define DEBUG_eNB_SCHEDULER 1
65

66
extern RAN_CONTEXT_t RC;
67

68

69
uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
70

71

72 73
void
schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
74
{
75

76 77 78 79 80 81

  eNB_MAC_INST *eNB = RC.mac[module_idP];
  UE_list_t *UE_list = &eNB->UE_list;
  nfapi_ul_config_request_body_t *ul_req;
  int CC_id, UE_id;
  COMMON_channels_t *cc = RC.mac[module_idP]->common_channels;
82 83
  LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon;
  struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated;
84 85 86 87
  uint8_t TSFC;
  uint16_t deltaTSFC;		// bitmap
  uint8_t srs_SubframeConfig;
  
88 89 90
  // 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
91
  
92
  uint16_t srsPeriodicity, srsOffset;
93
  
94 95 96 97 98 99 100
  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];
101
	TSFC = deltaTSFCTabType1[srs_SubframeConfig][1];
102 103
      } else {		// TDD
	deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0];
104
	TSFC = deltaTSFCTabType2[srs_SubframeConfig][1];
105 106 107
      }
      // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC
      uint16_t tmp = (subframeP % TSFC);
108
      
109 110
      if ((1 << tmp) & deltaTSFC) {
	// This is an SRS subframe, loop over UEs
111 112
	for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
	  if (!RC.mac[module_idP]->UE_list.active[UE_id]) continue;
113 114 115
	  ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body;
	  // 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;
116
	  
117 118 119
	  AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
		      "physicalConfigDedicated is null for UE %d\n",
		      UE_id);
120
	  
121
	  if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) {
122
	    if (soundingRS_UL_ConfigDedicated->present == LTE_SoundingRS_UL_ConfigDedicated_PR_setup) {
123 124 125 126 127 128 129
	      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;
130 131 132 133 134 135 136 137 138 139 140 141 142
		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_list->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;		//              ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port                   = ;//
143
		//              ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs                = ;//
144 145
		RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
		RC.mac[module_idP]->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST;
146 147 148
		ul_req->number_of_pdus++;
	      }	// if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset)
	    }	// if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup)
149 150 151 152 153 154
	  }		// if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL)
	}		// for (UE_id ...
      }			// if((1<<tmp) & deltaTSFC)
      
    }			// SRS config
  }
155 156
}

157 158
void
schedule_CSI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
159
{
160 161 162 163 164
  eNB_MAC_INST                   *eNB = RC.mac[module_idP];
  UE_list_t                      *UE_list = &eNB->UE_list;
  COMMON_channels_t              *cc;
  nfapi_ul_config_request_body_t *ul_req;
  int                            CC_id, UE_id;
165
  struct LTE_CQI_ReportPeriodic  *cqi_ReportPeriodic;
166 167 168 169 170 171
  uint16_t                       Npd, N_OFFSET_CQI;
  int                            H;

  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {

    cc = &eNB->common_channels[CC_id];
172 173
    for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
      if (!UE_list->active[UE_id]) continue;
174 175 176 177 178 179 180 181 182 183 184 185 186 187

      ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body;

      // 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;

      AssertFatal(UE_list->
		  UE_template[CC_id][UE_id].physicalConfigDedicated
		  != NULL,
		  "physicalConfigDedicated is null for UE %d\n",
		  UE_id);

      if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) {
	if ((cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) != NULL
188
	    && (cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_release)) {
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
	  //Rel8 Periodic CQI/PMI/RI reporting

	  get_csi_params(cc, cqi_ReportPeriodic, &Npd,
			 &N_OFFSET_CQI, &H);

	  if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) {	// CQI opportunity
	    UE_list->UE_sched_ctrl[UE_id].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_list->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_list->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;
211

212
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
213
	    // PUT rel10-13 UCI options here
214
#endif
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
	  } else
	    if ((cqi_ReportPeriodic->choice.setup.ri_ConfigIndex)
		&& ((((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_list->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 ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) {
      }			// if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig)
    }			// for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {
  }				// for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
237 238
}

239 240
void
schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
241
{
242 243 244 245 246 247
  eNB_MAC_INST                   *eNB = RC.mac[module_idP];
  UE_list_t                      *UE_list = &eNB->UE_list;
  nfapi_ul_config_request_t      *ul_req;
  nfapi_ul_config_request_body_t *ul_req_body;
  int                            CC_id;
  int                            UE_id;
248
  LTE_SchedulingRequestConfig_t  *SRconfig;
249 250 251 252 253 254 255 256
  int                            skip_ue;
  int                            is_harq;
  nfapi_ul_config_sr_information sr;
  int                            i;

  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
    RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP;

257 258
    for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
      if (!RC.mac[module_idP]->UE_list.active[UE_id]) continue;
259 260 261 262 263 264 265 266 267 268 269 270 271

      ul_req        = &RC.mac[module_idP]->UL_req[CC_id];
      ul_req_body   = &ul_req->ul_config_request_body;

      // 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;

      AssertFatal(UE_list->
		  UE_template[CC_id][UE_id].physicalConfigDedicated!= NULL,
		  "physicalConfigDedicated is null for UE %d\n",
		  UE_id);

      if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) {
272
	if (SRconfig->present == LTE_SchedulingRequestConfig_PR_setup) {
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	  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;
	  }
	}		// SRconfig->present == SchedulingRequestConfig_PR_setup)
      }			// SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL)

      // if we get here there is some PUCCH1 reception to schedule for SR

      skip_ue = 0;
      is_harq = 0;
      // check that there is no existing UL grant for ULSCH which overrides the SR
      for (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_list->UE_template[CC_id][UE_id].rnti)) {
	  skip_ue = 1;
	  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_list->UE_template[CC_id][UE_id].rnti)) {
	  is_harq = 1;
	  break;
	}
      }
308

309 310
      // drop the allocation because ULSCH with handle it with BSR
      if (skip_ue == 1) continue;
311

312
      LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti, is_harq);
313

314
      // check Rel10 or Rel8 SR
315
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
316 317 318 319 320 321 322 323
      if ((UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2)
	  && (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)
	  && (UE_list->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_list->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
324
#endif
325 326 327 328 329
	{
	  sr.sr_information_rel8.tl.tag                   = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG;
	  sr.sr_information_rel8.pucch_index              = UE_list->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);
	}
330

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
      /* if there is already an HARQ pdu, convert to SR_HARQ */
      if (is_harq) {
	nfapi_ul_config_harq_information h                                                                                 = ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.harq_information;
	ul_req_body->ul_config_pdu_list[i].pdu_type                                                                        = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE;
	ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information                                                  = sr;
	ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information                                                = h;
      } 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_list->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 (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id])
  }				// for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++)
349 350
}

351 352
extern uint8_t nfapi_mode;

353 354 355
void
check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
		 frame_t frameP, sub_frame_t subframeP)
356
{
357 358 359 360 361 362 363 364
  UE_list_t                 *UE_list = &RC.mac[module_idP]->UE_list;
  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_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) &&
      (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) {
365 366 367
    if (UE_list->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_list->UE_sched_ctrl[UE_id].ul_failure_timer);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) {
      UE_list->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_list->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;
392
      LOG_D(MAC,
393 394 395 396 397 398
	    "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",
	    UE_id, rnti,
	    UE_list->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
399
      LOG_D(MAC,
400 401 402
	    "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",
	    UE_id, rnti,
	    UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
403
      if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0;	// resend every 8 frames
404
    }
405

406 407
    UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++;
    // check threshold
408 409
    if (UE_list->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)
410 411 412 413 414 415 416
      // 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_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0;
      UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync   = 1;
417 418 419 420 421 422 423

      //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future
      if (rrc_agent_registered[module_idP]) {
        LOG_W(MAC, "notify flexran Agent of UE state change\n");
        agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP,
            rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED);
      }
424 425
    }
  }				// ul_failure_timer>0
426
}
427

428 429 430
void
clear_nfapi_information(eNB_MAC_INST * eNB, int CC_idP,
			frame_t frameP, sub_frame_t subframeP)
431
{
432 433
  nfapi_dl_config_request_t      *DL_req = &eNB->DL_req[0];
  nfapi_ul_config_request_t      *UL_req = &eNB->UL_req[0];
434
  nfapi_hi_dci0_request_t   *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframeP];
435
  nfapi_tx_request_t             *TX_req = &eNB->TX_req[0];
436

437
  eNB->pdu_index[CC_idP] = 0;
438

439
  if (nfapi_mode==0 || nfapi_mode == 1) { // monolithic or PNF
440

441 442 443 444 445
    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;
446

447 448
    HI_DCI0_req->hi_dci0_request_body.sfnsf                                   = subframeP + (frameP<<4);
    HI_DCI0_req->hi_dci0_request_body.number_of_dci                           = 0;
449

450

451 452 453
    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
454

455
    TX_req[CC_idP].tx_request_body.number_of_pdus                 = 0;
456

457
  }
458 459
}

460 461
void
copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
462
{
463 464
  int CC_id;
  eNB_MAC_INST *mac = RC.mac[module_idP];
465

466
  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
467

468 469 470
    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;
471

472
    *ul_req = *ul_req_tmp;
473

474 475 476 477
    // 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;
478

479
    if (ul_req->ul_config_request_body.number_of_pdus>0)
480 481 482 483
      {
        LOG_D(PHY, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus);
      }

484 485 486
    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));
487
  }
488 489
}

490 491 492
void
eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP,
			  sub_frame_t subframeP)
493
{
494

495 496
  int               mbsfn_status[MAX_NUM_CCs];
  protocol_ctxt_t   ctxt;
497

498
  int               CC_id, i = -1;
499 500
  UE_list_t         *UE_list = &RC.mac[module_idP]->UE_list;
  rnti_t            rnti;
501

502
  COMMON_channels_t *cc      = RC.mac[module_idP]->common_channels;
503

504 505 506 507
  start_meas(&RC.mac[module_idP]->eNB_scheduler);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
    (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,
     VCD_FUNCTION_IN);
508

509 510
  RC.mac[module_idP]->frame    = frameP;
  RC.mac[module_idP]->subframe = subframeP;
511

512 513
  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
    mbsfn_status[CC_id] = 0;
514

515 516 517
    // clear vrb_maps
    memset(cc[CC_id].vrb_map, 0, 100);
    memset(cc[CC_id].vrb_map_UL, 0, 100);
518

519

520
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
521
    cc[CC_id].mcch_active        = 0;
522
#endif
523

524 525
    clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP);
  }
526

527
  // refresh UE list based on UEs dropped by PHY in previous subframe
528 529 530 531 532 533 534 535 536 537 538 539 540
  for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
    if (UE_list->active[i]) {
      rnti = UE_RNTI(module_idP, i);
      CC_id = UE_PCCID(module_idP, i);
      
      if (((frameP&127) == 0) && (subframeP == 0)) {
	LOG_I(MAC,
	      "UE  rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n",
	      rnti,
	      UE_list->UE_sched_ctrl[i].ul_out_of_sync ==
	      0 ? "in synch" : "out of sync",
	      UE_list->UE_template[CC_id][i].phr_info,
	      UE_list->UE_sched_ctrl[i].dl_cqi[CC_id],
541 542
	      (5*UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 640) / 10,
	      (5*UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 640) / 10);
543
      }
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
      
      RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) +
						    subframeP] = -63;
      if (i == UE_list->head)
	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME
	  (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,
	   RC.eNB[module_idP][CC_id]->
	   pusch_stats_bsr[i][(frameP * 10) + subframeP]);
      // increment this, it is cleared when we receive an sdu
      RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++;
      
      RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++;
      LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", i, rnti,
	    RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].
	    ul_inactivity_timer,
	    RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer);
      check_ul_failure(module_idP, CC_id, i, frameP, subframeP);
      
      if (RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer > 0) {
	RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer++;
	if(RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer >=
	   RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer_thres) {
	  RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer = 0;
567 568 569 570 571 572 573 574 575
          //clear reestablish_rnti_map
          if(RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].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;
	      }
576
	    }
577

578 579 580 581
            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);
          }
582 583 584 585
	  // 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)){
586
              void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
587 588 589
	      LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti);
	      clean_eNb_ulsch(ulsch);
	    }
590
	  }
591 592 593
	  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)){
594
              void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch);
595 596 597
	      LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti);
	      clean_eNb_dlsch(dlsch);
	    }
598
	  }
599 600 601 602 603 604 605 606 607 608 609 610 611
	  
	  for(int j = 0; j < 10; j++){
	    nfapi_ul_config_request_body_t *ul_req_tmp = NULL;
	    ul_req_tmp = &RC.mac[module_idP]->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--;
612 613 614 615 616
		}
	      }
	    }
	  }
	rrc_mac_remove_ue(module_idP,rnti);
617
	}
618
      }
619
    }
620
  }
621

622
#if (!defined(PRE_SCD_THREAD))
623 624 625 626
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES,
				 NOT_A_RNTI, frameP, subframeP,
				 module_idP);
  pdcp_run(&ctxt);
627

Raymond Knopp's avatar
Raymond Knopp committed
628
  rrc_rx_tx(&ctxt, CC_id);
629
#endif
630

631
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
632

633 634 635 636 637
  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);
      mbsfn_status[CC_id] = schedule_MBMS(module_idP, CC_id, frameP, subframeP);
      stop_meas(&RC.mac[module_idP]->schedule_mch);
Raymond Knopp's avatar
 
Raymond Knopp committed
638
    }
639
  }
640

641
#endif
642

643
  static int debug_flag=0;
644 645
  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;
646 647 648 649 650 651 652 653 654 655 656 657 658
  if(RC.mac[module_idP]->scheduler_mode == SCHED_MODE_DEFAULT){
    schedule_ulsch_p = schedule_ulsch;
    schedule_ue_spec_p = schedule_dlsch;
  }else if(RC.mac[module_idP]->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",RC.mac[module_idP]->scheduler_mode);
    debug_flag=1;
  }

659
  // This schedules MIB
660

661
  if ((subframeP == 0) && (frameP & 3) == 0)
662
      schedule_mib(module_idP, frameP, subframeP);
663
  if (get_softmodem_params()->phy_test == 0){
664 665
    // This schedules SI for legacy LTE and eMTC starting in subframeP
    schedule_SI(module_idP, frameP, subframeP);
666 667
    // This schedules Paging in subframeP
    schedule_PCH(module_idP,frameP,subframeP);
668 669 670 671 672 673 674
    // 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)
675 676 677 678 679
    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__); 
    }
680 681 682 683
    // This schedules UCI_SR in subframeP
    schedule_SR(module_idP, frameP, subframeP);
    // This schedules UCI_CSI in subframeP
    schedule_CSI(module_idP, frameP, subframeP);
684
    // This schedules DLSCH in subframeP
685 686 687 688 689 690
    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__); 
    }

691
  }
692
  else{
Wang Tsu-Han's avatar
Wang Tsu-Han committed
693
    schedule_ulsch_phy_test(module_idP,frameP,subframeP);
694 695
    schedule_ue_spec_phy_test(module_idP,frameP,subframeP,mbsfn_status);
  }
696

697 698
  if (RC.flexran[module_idP]->enabled)
    flexran_agent_send_update_stats(module_idP);
699
  
700
  // Allocate CCEs for good after scheduling is done
701 702 703 704
  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)))
      allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2);
  }
705

706 707 708 709
  if (mac_agent_registered[module_idP] && subframeP == 9) {
    flexran_agent_slice_update(module_idP);
  }

710
  stop_meas(&RC.mac[module_idP]->eNB_scheduler);
711

712 713 714
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
      (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,
      VCD_FUNCTION_OUT);
715
}