Files
openairinterface5g/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
T
Cedric Roux 922b5b595a Fix NFAPI integration
This commit fixes issues introduced by the previous commit.

Summary of work:
- cleanup:
  - fix LOG_XX to be less verbose
  - fix cmake_targets/CMakeLists.txt
  - fix oaienv
  - remove dead code
- bug fixes:
  - in openair1/SCHED/fapi_l1.c we had:
      eNB->pdcch_vars[subframe&1].num_dci           = number_dci;
    should be:
      eNB->pdcch_vars[subframe&1].num_dci           = 0;
    This bug let the PHY send more DCIs than what should have been
    sent because num_dci is incremented later on in the code.
    This fix may be a problem for fapi mode, to be checked.
  - add new T VCD traces
  - revert openair1/PHY/TOOLS/file_output.c to 'develop' version
  - remove thread_id in logRecord/logRecord_mt
  - revert (and adapt) configuration files
  - be careful when doing frame++, we need to % 1024
  - revert target_rx_power in openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
- NFAPI:
  - the open-nFAPI code has been included in the repository. See nfapi/README.
    Maybe we should "git clone" the Cisco repository instead. We have to be
    careful of availability though.

What has been tested:
- monolithic eNB FDD 5/10MHz with one UE, iperf UDP/TCP uplink/downlink

Anything else may fail to work, especially the FAPI mode, which has not
been tested at all.
2018-01-15 15:24:50 +01:00

1773 lines
55 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_dlsch.c
* \brief procedures related to eNB for the DLSCH transport channel
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _mac
*/
#include "assertions.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/proto.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"
#include "SIMULATION/TOOLS/defs.h" // for taus
#if defined(ENABLE_ITTI)
#include "intertask_interface.h"
#endif
#include "T.h"
#define ENABLE_MAC_PAYLOAD_DEBUG
//#define DEBUG_eNB_SCHEDULER 1
extern RAN_CONTEXT_t RC;
extern uint8_t nfapi_mode;
//------------------------------------------------------------------------------
void
add_ue_dlsch_info(module_id_t module_idP,
int CC_id,
int UE_id, sub_frame_t subframeP, UE_DLSCH_STATUS status)
//------------------------------------------------------------------------------
{
//LOG_D(MAC, "%s(module_idP:%d, CC_id:%d, UE_id:%d, subframeP:%d, status:%d) serving_num:%d rnti:%x\n", __FUNCTION__, module_idP, CC_id, UE_id, subframeP, status, eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num, UE_RNTI(module_idP,UE_id));
eNB_dlsch_info[module_idP][CC_id][UE_id].rnti =
UE_RNTI(module_idP, UE_id);
// eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight;
eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP;
eNB_dlsch_info[module_idP][CC_id][UE_id].status = status;
eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++;
}
//------------------------------------------------------------------------------
int
schedule_next_dlue(module_id_t module_idP, int CC_id,
sub_frame_t subframeP)
//------------------------------------------------------------------------------
{
int next_ue;
UE_list_t *UE_list = &RC.mac[module_idP]->UE_list;
for (next_ue = UE_list->head; next_ue >= 0;
next_ue = UE_list->next[next_ue]) {
if (eNB_dlsch_info[module_idP][CC_id][next_ue].status ==
S_DL_WAITING) {
return next_ue;
}
}
for (next_ue = UE_list->head; next_ue >= 0;
next_ue = UE_list->next[next_ue]) {
if (eNB_dlsch_info[module_idP][CC_id][next_ue].status ==
S_DL_BUFFERED) {
eNB_dlsch_info[module_idP][CC_id][next_ue].status =
S_DL_WAITING;
}
}
return (-1); //next_ue;
}
//------------------------------------------------------------------------------
unsigned char
generate_dlsch_header(unsigned char *mac_header,
unsigned char num_sdus,
unsigned short *sdu_lengths,
unsigned char *sdu_lcids,
unsigned char drx_cmd,
unsigned short timing_advance_cmd,
unsigned char *ue_cont_res_id,
unsigned char short_padding,
unsigned short post_padding)
//------------------------------------------------------------------------------
{
SCH_SUBHEADER_FIXED *mac_header_ptr =
(SCH_SUBHEADER_FIXED *) mac_header;
uint8_t first_element = 0, last_size = 0, i;
uint8_t mac_header_control_elements[16], *ce_ptr;
ce_ptr = &mac_header_control_elements[0];
// compute header components
if ((short_padding == 1) || (short_padding == 2)) {
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
first_element = 1;
last_size = 1;
}
if (short_padding == 2) {
mac_header_ptr->E = 1;
mac_header_ptr++;
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
last_size = 1;
}
if (drx_cmd != 255) {
if (first_element > 0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = DRX_CMD;
last_size = 1;
}
if (timing_advance_cmd != 31) {
if (first_element > 0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = TIMING_ADV_CMD;
last_size = 1;
// msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0;
AssertFatal(timing_advance_cmd < 64,
"timing_advance_cmd %d > 63\n", timing_advance_cmd);
((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f;
LOG_D(MAC, "timing advance =%d (%d)\n", timing_advance_cmd,
((TIMING_ADVANCE_CMD *) ce_ptr)->TA);
ce_ptr += sizeof(TIMING_ADVANCE_CMD);
//msg("offset %d\n",ce_ptr-mac_header_control_elements);
}
if (ue_cont_res_id) {
if (first_element > 0) {
mac_header_ptr->E = 1;
/*
printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr++;
} else {
first_element = 1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = UE_CONT_RES;
last_size = 1;
LOG_T(MAC,
"[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n",
ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2],
ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]);
memcpy(ce_ptr, ue_cont_res_id, 6);
ce_ptr += 6;
// msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
}
//msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
for (i = 0; i < num_sdus; i++) {
LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n",
num_sdus, sdu_lengths[i]);
if (first_element > 0) {
mac_header_ptr->E = 1;
/*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr += last_size;
//msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
} else {
first_element = 1;
}
if (sdu_lengths[i] < 128) {
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0;
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i];
((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L =
(unsigned char) sdu_lengths[i];
last_size = 2;
} else {
((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i];
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB =
((unsigned short) sdu_lengths[i] >> 8) & 0x7f;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB =
(unsigned short) sdu_lengths[i] & 0xff;
((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00;
last_size = 3;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,
"[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n",
sdu_lengths[i],
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB,
((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB);
#endif
}
}
/*
printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) {
if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0)
printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L));
else
printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L));
}
*/
if (post_padding > 0) { // we have lots of padding at the end of the packet
mac_header_ptr->E = 1;
mac_header_ptr += last_size;
// add a padding element
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_PADDING;
mac_header_ptr++;
} else { // no end of packet padding
// last SDU subhead is of fixed type (sdu length implicitly to be computed at UE)
mac_header_ptr++;
}
//msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header);
if ((ce_ptr - mac_header_control_elements) > 0) {
// printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements);
memcpy((void *) mac_header_ptr, mac_header_control_elements,
ce_ptr - mac_header_control_elements);
mac_header_ptr +=
(unsigned char) (ce_ptr - mac_header_control_elements);
}
//msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header);
return ((unsigned char *) mac_header_ptr - mac_header);
}
//------------------------------------------------------------------------------
void
set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP,
int subframeP)
//------------------------------------------------------------------------------
{
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_list_t *UE_list = &eNB->UE_list;
unsigned char DAI;
COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
if (cc->tdd_Config != NULL) { //TDD
DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3;
LOG_D(MAC,
"[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n",
module_idP, CC_idP, frameP, subframeP, DAI, UE_idP);
// Save DAI for Format 0 DCI
switch (cc->tdd_Config->subframeAssignment) {
case 0:
// if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6))
break;
case 1:
switch (subframeP) {
case 1:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI;
break;
case 4:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI;
break;
case 6:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
break;
case 9:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
break;
}
case 2:
// if ((subframeP==3)||(subframeP==8))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 3:
//if ((subframeP==6)||(subframeP==8)||(subframeP==0)) {
// LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1);
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI;
//}
switch (subframeP) {
case 5:
case 6:
case 1:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
break;
case 7:
case 8:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
break;
case 9:
case 0:
UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI;
break;
default:
break;
}
break;
case 4:
// if ((subframeP==8)||(subframeP==9))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 5:
// if (subframeP==8)
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
case 6:
// if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9))
// UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
break;
default:
break;
}
}
}
// changes to pre-processor for eMTC
//------------------------------------------------------------------------------
void
schedule_ue_spec(module_id_t module_idP,
frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag)
//------------------------------------------------------------------------------
{
uint8_t CC_id;
int UE_id;
unsigned char aggregation;
mac_rlc_status_resp_t rlc_status;
unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0;
unsigned char header_len_dtch = 0, header_len_dtch_tmp =
0, header_len_dtch_last = 0;
unsigned char ta_len = 0;
unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0;
uint16_t nb_rb, nb_rb_temp, nb_available_rb;
uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding =
0, post_padding = 0;
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
unsigned char round = 0;
unsigned char harq_pid = 0;
eNB_UE_STATS *eNB_UE_stats = NULL;
uint16_t sdu_length_total = 0;
eNB_MAC_INST *eNB = RC.mac[module_idP];
COMMON_channels_t *cc = eNB->common_channels;
UE_list_t *UE_list = &eNB->UE_list;
int continue_flag = 0;
int32_t normalized_rx_power, target_rx_power;
int32_t tpc = 1;
static int32_t tpc_accumulated = 0;
UE_sched_ctrl *ue_sched_ctl;
int mcs;
int i;
int min_rb_unit[MAX_NUM_CCs];
int N_RB_DL[MAX_NUM_CCs];
int total_nb_available_rb[MAX_NUM_CCs];
int N_RBG[MAX_NUM_CCs];
nfapi_dl_config_request_body_t *dl_req;
nfapi_dl_config_request_pdu_t *dl_config_pdu;
int tdd_sfa;
int ta_update;
#if 0
if (UE_list->head == -1) {
return;
}
#endif
start_meas(&eNB->schedule_dlsch);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN);
// for TDD: check that we have to act here, otherwise return
if (cc[0].tdd_Config) {
tdd_sfa = cc[0].tdd_Config->subframeAssignment;
switch (subframeP) {
case 0:
// always continue
break;
case 1:
return;
break;
case 2:
return;
break;
case 3:
if ((tdd_sfa != 2) && (tdd_sfa != 5))
return;
break;
case 4:
if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 5:
break;
case 6:
case 7:
if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 8:
if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4)
&& (tdd_sfa != 5))
return;
break;
case 9:
if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4)
&& (tdd_sfa != 6))
return;
break;
}
}
//weight = get_ue_weight(module_idP,UE_id);
aggregation = 2;
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth);
min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id);
// get number of PRBs less those used by common channels
total_nb_available_rb[CC_id] = N_RB_DL[CC_id];
for (i = 0; i < N_RB_DL[CC_id]; i++)
if (cc[CC_id].vrb_map[i] != 0)
total_nb_available_rb[CC_id]--;
N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth);
// store the global enb stats:
eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs;
eNB->eNB_stats[CC_id].available_prbs =
total_nb_available_rb[CC_id];
eNB->eNB_stats[CC_id].total_available_prbs +=
total_nb_available_rb[CC_id];
eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0;
eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0;
}
/// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN);
start_meas(&eNB->schedule_dlsch_preprocessor);
dlsch_scheduler_pre_processor(module_idP,
frameP, subframeP, N_RBG, mbsfn_flag);
stop_meas(&eNB->schedule_dlsch_preprocessor);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT);
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id);
dl_req = &eNB->DL_req[CC_id].dl_config_request_body;
if (mbsfn_flag[CC_id] > 0)
continue;
for (UE_id = UE_list->head; UE_id >= 0;
UE_id = UE_list->next[UE_id]) {
continue_flag = 0; // reset the flag to allow allocation for the remaining UEs
rnti = UE_RNTI(module_idP, UE_id);
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
if (rnti == NOT_A_RNTI) {
LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n",
UE_id, UE_list->num_UEs);
continue_flag = 1;
}
if (eNB_UE_stats == NULL) {
LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n");
continue_flag = 1;
}
if (continue_flag != 1) {
switch (get_tmode(module_idP, CC_id, UE_id)) {
case 1:
case 2:
case 7:
aggregation =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
break;
case 3:
aggregation =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format2A);
break;
default:
LOG_W(MAC, "Unsupported transmission mode %d\n",
get_tmode(module_idP, CC_id, UE_id));
aggregation = 2;
}
}
/* if (continue_flag != 1 */
if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated
CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP,
aggregation, rnti)) {
LOG_D(MAC,
"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
module_idP, frameP, UE_id, CC_id);
continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5
}
if (cc[CC_id].tdd_Config != NULL) { //TDD
set_ue_dai(subframeP,
UE_id,
CC_id,
cc[CC_id].tdd_Config->subframeAssignment,
UE_list);
// update UL DAI after DLSCH scheduling
set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
}
if (continue_flag == 1) {
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP, S_DL_NONE);
continue;
}
#warning RK->CR This old API call has to be revisited for FAPI, or logic must be changed
#if 0
/* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */
/* if we don't add it, next allocations may succeed but overall allocations may fail */
/* will be removed at the end of this function */
add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, &(char[]) {
0}, rnti, 1, aggregation, 1, format1, 0);
#endif
nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id];
if (cc->tdd_Config)
harq_pid = ((frameP * 10) + subframeP) % 10;
else
harq_pid = ((frameP * 10) + subframeP) & 7;
round = ue_sched_ctl->round[CC_id][harq_pid];
UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti;
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status =
mac_eNB_get_rrc_status(module_idP, rnti);
UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid;
UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;
if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status <
RRC_CONNECTED)
continue;
sdu_length_total = 0;
num_sdus = 0;
/*
DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)),
eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
*/
if (nfapi_mode) {
eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
}
else {
eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
}
eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
// store stats
//UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi;
// initializing the rb allocation indicator for each UE
for (j = 0; j < N_RBG[CC_id]; j++) {
UE_list->
UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]
= 0;
}
LOG_D(MAC,
"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n",
module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round,
nb_available_rb, ue_sched_ctl->dl_cqi[CC_id],
eNB_UE_stats->dlsch_mcs1,
UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status);
/* process retransmission */
if (round != 8) {
// get freq_allocation
nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
TBS =
get_TBS_DL(UE_list->
UE_template[CC_id][UE_id].oldmcs1[harq_pid],
nb_rb);
if (nb_rb <= nb_available_rb) {
if (cc[CC_id].tdd_Config != NULL) {
UE_list->UE_template[CC_id][UE_id].DAI++;
update_ul_dci(module_idP, CC_id, rnti,
UE_list->UE_template[CC_id][UE_id].
DAI);
LOG_D(MAC,
"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n",
CC_id, subframeP, UE_id,
UE_list->UE_template[CC_id][UE_id].DAI);
}
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
UE_list->UE_template[CC_id][UE_id].
rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
}
} else {
nb_rb_temp = nb_rb;
j = 0;
while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] ==
1) {
if (UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j])
printf
("WARN: rballoc_subband not free for retrans?\n");
UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
if ((j == N_RBG[CC_id] - 1) &&
((N_RB_DL[CC_id] == 25) ||
(N_RB_DL[CC_id] == 50))) {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id] +
1;
} else {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id];
}
}
j = j + 1;
}
}
nb_available_rb -= nb_rb;
/*
eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];
for(j=0; j<N_RBG[CC_id]; j++) {
eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j];
}
*/
switch (get_tmode(module_idP, CC_id, UE_id)) {
case 1:
case 2:
case 7:
default:
LOG_D(MAC,"retransmission DL_REQ: rnti:%x\n",rnti);
dl_config_pdu =
&dl_req->dl_config_pdu_list[dl_req->
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_1;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level =
get_aggregation(get_bw_index
(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
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
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
harq_process = harq_pid;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.new_data_indicator_1 =
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 =
UE_list->UE_template[CC_id][UE_id].
oldmcs1[harq_pid];
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_1 =
round & 3;
if (cc[CC_id].tdd_Config != NULL) { //TDD
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.downlink_assignment_index =
(UE_list->UE_template[CC_id][UE_id].DAI -
1) & 3;
LOG_D(MAC,
"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n",
module_idP, CC_id, harq_pid, round,
(UE_list->UE_template[CC_id][UE_id].DAI -
1),
UE_list->
UE_template[CC_id][UE_id].oldmcs1
[harq_pid]);
} else {
LOG_D(MAC,
"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n",
module_idP, CC_id, harq_pid, round,
UE_list->
UE_template[CC_id][UE_id].oldmcs1
[harq_pid]);
}
if (!CCE_allocation_infeasible
(module_idP, CC_id, 1, subframeP,
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, rnti)) {
dl_req->number_dci++;
dl_req->number_pdu++;
dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1
/* retransmission, no pdu_index */
, rnti, 0, // type 0 allocation from 7.1.6 in 36.213
0, // virtual_resource_block_assignment_flag, unused here
0, // resource_block_coding, to be filled in later
getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), round & 3, // redundancy version
1, // transport blocks
0, // transport block to codeword swap flag
cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme
1, // number of layers
1, // number of subbands
// uint8_t codebook_index,
4, // UE category capacity
UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5
0, // ngap
0, // nprb
cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode
0, //number of PRBs treated as one subband, not used here
0 // number of beamforming vectors, not used here
);
LOG_D(MAC,
"Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n",
eNB->pdu_index[CC_id], round);
program_dlsch_acknak(module_idP, CC_id, UE_id,
frameP, subframeP,
dl_config_pdu->
dci_dl_pdu.dci_dl_pdu_rel8.
cce_idx);
// No TX request for retransmission (check if null request for FAPI)
} else {
LOG_W(MAC,
"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n",
frameP, subframeP, UE_id, rnti);
}
}
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP,
S_DL_SCHEDULED);
//eNB_UE_stats->dlsch_trials[round]++;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_retransmission += 1;
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx =
nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].
total_rbs_used_retx += nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 =
eNB_UE_stats->dlsch_mcs1;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 =
eNB_UE_stats->dlsch_mcs1;
} else {
LOG_D(MAC,
"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
module_idP, frameP, CC_id, UE_id);
}
} else { /* This is a potentially new SDU opportunity */
rlc_status.bytes_in_buffer = 0;
// Now check RLC information to compute number of required RBs
// get maximum TBS size for RLC request
TBS =
get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
// check first for RLC data on DCCH
// add the length for all the control elements (timing adv, drx, etc) : header + payload
if (ue_sched_ctl->ta_timer == 0) {
ta_update = ue_sched_ctl->ta_update;
/* if we send TA then set timer to not send it for a while */
if (ta_update != 31)
ue_sched_ctl->ta_timer = 20;
/* reset ta_update */
ue_sched_ctl->ta_update = 31;
} else {
ta_update = 31;
}
ta_len = (ta_update != 31) ? 2 : 0;
header_len_dcch = 2; // 2 bytes DCCH SDU subheader
if (TBS - ta_len - header_len_dcch > 0) {
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size
sdu_lengths[0] = 0;
if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit
LOG_D(MAC,
"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
module_idP, frameP, CC_id,
TBS - header_len_dcch);
sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used
(char *)
&dlsch_buffer
[0]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH),
T_INT(sdu_lengths[0]));
LOG_D(MAC,
"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",
module_idP, CC_id, sdu_lengths[0]);
sdu_length_total = sdu_lengths[0];
sdu_lcids[0] = DCCH;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_pdu_tx[DCCH] += 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH]
+= sdu_lengths[0];
num_sdus = 1;
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC,
"[eNB %d][DCCH] CC_id %d Got %d bytes :",
module_idP, CC_id, sdu_lengths[0]);
for (j = 0; j < sdu_lengths[0]; j++) {
LOG_T(MAC, "%x ", dlsch_buffer[j]);
}
LOG_T(MAC, "\n");
#endif
} else {
header_len_dcch = 0;
sdu_length_total = 0;
}
}
// check for DCCH1 and update header information (assume 2 byte sub-header)
if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) {
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and
// DCCH SDU
sdu_lengths[num_sdus] = 0;
if (rlc_status.bytes_in_buffer > 0) {
LOG_D(MAC,
"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
module_idP, frameP, CC_id,
TBS - header_len_dcch - sdu_length_total);
sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used
(char *)
&dlsch_buffer
[sdu_length_total]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus]));
sdu_lcids[num_sdus] = DCCH1;
sdu_length_total += sdu_lengths[num_sdus];
header_len_dcch += 2;
UE_list->eNB_UE_stats[CC_id][UE_id].
num_pdu_tx[DCCH1] += 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]
+= sdu_lengths[num_sdus];
num_sdus++;
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC,
"[eNB %d][DCCH1] CC_id %d Got %d bytes :",
module_idP, CC_id, sdu_lengths[num_sdus]);
for (j = 0; j < sdu_lengths[num_sdus]; j++) {
LOG_T(MAC, "%x ", dlsch_buffer[j]);
}
LOG_T(MAC, "\n");
#endif
}
}
// assume the max dtch header size, and adjust it later
header_len_dtch = 0;
header_len_dtch_last = 0; // the header length of the last mac sdu
// lcid has to be sorted before the actual allocation (similar struct as ue_list).
for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
// TBD: check if the lcid is active
header_len_dtch += 3;
header_len_dtch_last = 3;
LOG_D(MAC,
"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
module_idP, frameP, lcid, TBS,
TBS - ta_len - header_len_dcch -
sdu_length_total - header_len_dtch);
if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ?
rlc_status = mac_rlc_status_ind(module_idP,
rnti,
module_idP,
frameP,
subframeP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
TBS - ta_len -
header_len_dcch -
sdu_length_total -
header_len_dtch);
if (rlc_status.bytes_in_buffer > 0) {
LOG_D(MAC,
"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
module_idP, frameP,
TBS - header_len_dcch -
sdu_length_total - header_len_dtch, lcid,
header_len_dtch);
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used
(char
*)
&dlsch_buffer
[sdu_length_total]);
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_INT(lcid), T_INT(sdu_lengths[num_sdus]));
LOG_D(MAC,
"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",
module_idP, sdu_lengths[num_sdus], lcid);
sdu_lcids[num_sdus] = lcid;
sdu_length_total += sdu_lengths[num_sdus];
UE_list->
eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]
+= 1;
UE_list->
eNB_UE_stats[CC_id][UE_id].num_bytes_tx
[lcid] += sdu_lengths[num_sdus];
if (sdu_lengths[num_sdus] < 128) {
header_len_dtch--;
header_len_dtch_last--;
}
num_sdus++;
} // no data for this LCID
else {
header_len_dtch -= 3;
}
} // no TBS left
else {
header_len_dtch -= 3;
break;
}
}
if (header_len_dtch == 0)
header_len_dtch_last = 0;
// there is at least one SDU
// if (num_sdus > 0 ){
if ((sdu_length_total + header_len_dcch +
header_len_dtch) > 0) {
// Now compute number of required RBs for total sdu length
// Assume RAH format 2
// adjust header lengths
header_len_dcch_tmp = header_len_dcch;
header_len_dtch_tmp = header_len_dtch;
if (header_len_dtch == 0) {
header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field
} else {
header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU
header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU
}
mcs = eNB_UE_stats->dlsch_mcs1;
if (mcs == 0) {
nb_rb = 4; // don't let the TBS get too small
} else {
nb_rb = min_rb_unit[CC_id];
}
TBS = get_TBS_DL(mcs, nb_rb);
while (TBS <
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len)) {
nb_rb += min_rb_unit[CC_id]; //
if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs
// (can happen if N_RB_DL is odd)
TBS =
get_TBS_DL(eNB_UE_stats->dlsch_mcs1,
nb_available_rb);
nb_rb = nb_available_rb;
break;
}
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb);
}
if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
UE_list->UE_template[CC_id][UE_id].
rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
}
} else {
nb_rb_temp = nb_rb;
j = 0;
while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] ==
1) {
UE_list->
UE_template[CC_id]
[UE_id].rballoc_subband[harq_pid][j] =
ue_sched_ctl->rballoc_sub_UE[CC_id][j];
if ((j == N_RBG[CC_id] - 1) &&
((N_RB_DL[CC_id] == 25) ||
(N_RB_DL[CC_id] == 50))) {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id] +
1;
} else {
nb_rb_temp =
nb_rb_temp - min_rb_unit[CC_id];
}
}
j = j + 1;
}
}
// decrease mcs until TBS falls below required length
while ((TBS >
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len)) && (mcs > 0)) {
mcs--;
TBS = get_TBS_DL(mcs, nb_rb);
}
// if we have decreased too much or we don't have enough RBs, increase MCS
while ((TBS <
(sdu_length_total + header_len_dcch +
header_len_dtch + ta_len))
&& (((ue_sched_ctl->dl_pow_off[CC_id] > 0)
&& (mcs < 28))
|| ((ue_sched_ctl->dl_pow_off[CC_id] == 0)
&& (mcs <= 15)))) {
mcs++;
TBS = get_TBS_DL(mcs, nb_rb);
}
LOG_D(MAC,
"dlsch_mcs before and after the rate matching = (%d, %d)\n",
eNB_UE_stats->dlsch_mcs1, mcs);
#ifdef DEBUG_eNB_SCHEDULER
LOG_D(MAC,
"[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
module_idP, CC_id, mcs, TBS, nb_rb);
// msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
// TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
#endif
if ((TBS - header_len_dcch - header_len_dtch -
sdu_length_total - ta_len) <= 2) {
padding =
(TBS - header_len_dcch - header_len_dtch -
sdu_length_total - ta_len);
post_padding = 0;
} else {
padding = 0;
// adjust the header len
if (header_len_dtch == 0) {
header_len_dcch = header_len_dcch_tmp;
} else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
header_len_dtch = header_len_dtch_tmp;
}
post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header
}
offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus
sdu_lengths, //
sdu_lcids, 255, // no drx
ta_update, // timing advance
NULL, // contention res id
padding, post_padding);
//#ifdef DEBUG_eNB_SCHEDULER
if (ta_update != 31) {
LOG_D(MAC,
"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
module_idP, frameP, UE_id, CC_id,
sdu_length_total, num_sdus, sdu_lengths[0],
sdu_lcids[0], offset, ta_update, padding,
post_padding, mcs, TBS, nb_rb,
header_len_dcch, header_len_dtch);
}
//#endif
#ifdef DEBUG_eNB_SCHEDULER
LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n");
for (i = 0; i < 16; i++) {
LOG_T(MAC, "%x.", dlsch_buffer[i]);
}
LOG_T(MAC, "\n");
#endif
// cycle through SDUs and place in dlsch_buffer
memcpy(&UE_list->
DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],
dlsch_buffer, sdu_length_total);
// memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);
// fill remainder of DLSCH with random data
for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0][offset + sdu_length_total + j] =
(char) (taus() & 0xff);
}
if (opt_enabled == 1) {
trace_pdu(1, (uint8_t *)
UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0], TBS, module_idP, 3,
UE_RNTI(module_idP, UE_id), eNB->frame,
eNB->subframe, 0, 0);
LOG_D(OPT,
"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n",
module_idP, CC_id, frameP,
UE_RNTI(module_idP, UE_id), TBS);
}
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP),
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
T_INT(subframeP), T_INT(harq_pid),
T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].
payload[0], TBS));
UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] =
nb_rb;
add_ue_dlsch_info(module_idP,
CC_id, UE_id, subframeP,
S_DL_SCHEDULED);
// store stats
eNB->eNB_stats[CC_id].dlsch_bytes_tx +=
sdu_length_total;
eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1;
UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used +=
nb_rb;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 =
eNB_UE_stats->dlsch_mcs1;
UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs;
UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS;
UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes =
TBS - sdu_length_total;
UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes +=
sdu_length_total;
UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes +=
TBS;
UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus +=
1;
if (cc[CC_id].tdd_Config != NULL) { // TDD
UE_list->UE_template[CC_id][UE_id].DAI++;
update_ul_dci(module_idP, CC_id, rnti,
UE_list->UE_template[CC_id][UE_id].
DAI);
}
// do PUCCH power control
// this is the normalized RX power
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
/* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */
normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id];
target_rx_power = 208;
// this assumes accumulated tpc
// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
int32_t framex10psubframe =
UE_list->UE_template[CC_id][UE_id].
pucch_tpc_tx_frame * 10 +
UE_list->UE_template[CC_id][UE_id].
pucch_tpc_tx_subframe;
if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case
((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around
if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) {
ue_sched_ctl->pucch1_cqi_update[CC_id] = 0;
UE_list->
UE_template[CC_id]
[UE_id].pucch_tpc_tx_frame = frameP;
UE_list->
UE_template[CC_id]
[UE_id].pucch_tpc_tx_subframe = subframeP;
if (normalized_rx_power >
(target_rx_power + 4)) {
tpc = 0; //-1
tpc_accumulated--;
} else if (normalized_rx_power <
(target_rx_power - 4)) {
tpc = 2; //+1
tpc_accumulated++;
} else {
tpc = 1; //0
}
LOG_D(MAC,
"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
module_idP, frameP, subframeP, harq_pid,
tpc, tpc_accumulated,
normalized_rx_power, target_rx_power);
} // Po_PUCCH has been updated
else {
tpc = 1; //0
} // time to do TPC update
else {
tpc = 1; //0
}
dl_config_pdu =
&dl_req->dl_config_pdu_list[dl_req->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.dci_format =
NFAPI_DL_DCI_FORMAT_1;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level =
get_aggregation(get_bw_index(module_idP, CC_id),
ue_sched_ctl->dl_cqi[CC_id],
format1);
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.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
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
harq_process = harq_pid;
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.new_data_indicator_1 =
1 -
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_1 = 0;
//deactivate second codeword
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0;
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.redundancy_version_2 = 1;
if (cc[CC_id].tdd_Config != NULL) { //TDD
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.downlink_assignment_index =
(UE_list->UE_template[CC_id][UE_id].DAI -
1) & 3;
LOG_D(MAC,
"[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n",
module_idP, CC_id, harq_pid,
(UE_list->UE_template[CC_id][UE_id].DAI - 1),
mcs);
} else {
LOG_D(MAC,
"[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n",
module_idP, CC_id, harq_pid, mcs);
}
LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n",
dl_req->number_pdu);
if (!CCE_allocation_infeasible
(module_idP, CC_id, 1, subframeP,
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.aggregation_level, rnti)) {
ue_sched_ctl->round[CC_id][harq_pid] = 0;
dl_req->number_dci++;
dl_req->number_pdu++;
dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
// Toggle NDI for next time
LOG_D(MAC,
"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n",
CC_id, frameP, subframeP, UE_id, rnti,
harq_pid,
UE_list->
UE_template[CC_id][UE_id].oldNDI[harq_pid]);
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid] =
1 -
UE_list->UE_template[CC_id][UE_id].
oldNDI[harq_pid];
UE_list->UE_template[CC_id][UE_id].
oldmcs1[harq_pid] = mcs;
UE_list->UE_template[CC_id][UE_id].
oldmcs2[harq_pid] = 0;
AssertFatal(UE_list->UE_template[CC_id]
[UE_id].physicalConfigDedicated !=
NULL,
"physicalConfigDedicated is NULL\n");
AssertFatal(UE_list->UE_template[CC_id]
[UE_id].
physicalConfigDedicated->pdsch_ConfigDedicated
!= NULL,
"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
fill_nfapi_dlsch_config(eNB, dl_req, TBS, eNB->pdu_index[CC_id], rnti, 0, // type 0 allocation from 7.1.6 in 36.213
0, // virtual_resource_block_assignment_flag, unused here
0, // resource_block_coding, to be filled in later
getQm(mcs), 0, // redundancy version
1, // transport blocks
0, // transport block to codeword swap flag
cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme
1, // number of layers
1, // number of subbands
// uint8_t codebook_index,
4, // UE category capacity
UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5
0, // ngap
0, // nprb
cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode
0, //number of PRBs treated as one subband, not used here
0 // number of beamforming vectors, not used here
);
eNB->TX_req[CC_id].sfn_sf =
fill_nfapi_tx_req(&eNB->
TX_req
[CC_id].tx_request_body,
(frameP * 10) + subframeP,
TBS, eNB->pdu_index[CC_id],
eNB->
UE_list.DLSCH_pdu[CC_id][0][(unsigned char)
UE_id].payload
[0]);
LOG_D(MAC,
"Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n",
eNB->pdu_index[CC_id]);
eNB->pdu_index[CC_id]++;
program_dlsch_acknak(module_idP, CC_id, UE_id,
frameP, subframeP,
dl_config_pdu->
dci_dl_pdu.dci_dl_pdu_rel8.
cce_idx);
} else {
LOG_W(MAC,
"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n",
frameP, subframeP, UE_id, rnti);
}
} else { // There is no data from RLC or MAC header, so don't schedule
}
}
if (cc[CC_id].tdd_Config != NULL) { // TDD
set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
}
} // UE_id loop
} // CC_id loop
fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag);
stop_meas(&eNB->schedule_dlsch);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);
}
//------------------------------------------------------------------------------
void
fill_DLSCH_dci(module_id_t module_idP,
frame_t frameP, sub_frame_t subframeP, int *mbsfn_flagP)
//------------------------------------------------------------------------------
{
// loop over all allocated UEs and compute frequency allocations for PDSCH
int UE_id = -1;
uint8_t /* first_rb, */ nb_rb = 3;
rnti_t rnti;
//unsigned char *vrb_map;
uint8_t rballoc_sub[25];
//uint8_t number_of_subbands=13;
//unsigned char round;
unsigned char harq_pid;
int i;
int CC_id;
eNB_MAC_INST *eNB = RC.mac[module_idP];
UE_list_t *UE_list = &eNB->UE_list;
int N_RBG;
int N_RB_DL;
COMMON_channels_t *cc;
start_meas(&eNB->fill_DLSCH_dci);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN);
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id);
if (mbsfn_flagP[CC_id] > 0)
continue;
cc = &eNB->common_channels[CC_id];
N_RBG = to_rbg(cc->mib->message.dl_Bandwidth);
N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);
// UE specific DCIs
for (UE_id = UE_list->head; UE_id >= 0;
UE_id = UE_list->next[UE_id]) {
LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", CC_id, UE_id,
eNB_dlsch_info[module_idP][CC_id][UE_id].status);
if (eNB_dlsch_info[module_idP][CC_id][UE_id].status ==
S_DL_SCHEDULED) {
// clear scheduling flag
eNB_dlsch_info[module_idP][CC_id][UE_id].status =
S_DL_WAITING;
rnti = UE_RNTI(module_idP, UE_id);
if (cc->tdd_Config)
harq_pid = ((frameP * 10) + subframeP) % 10;
else
harq_pid = ((frameP * 10) + subframeP) & 7;
nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
/// Synchronizing rballoc with rballoc_sub
for (i = 0; i < N_RBG; i++) {
rballoc_sub[i] =
UE_list->
UE_template[CC_id][UE_id].rballoc_subband[harq_pid]
[i];
}
nfapi_dl_config_request_t *DL_req =
&RC.mac[module_idP]->DL_req[0];
nfapi_dl_config_request_pdu_t *dl_config_pdu;
for (i = 0;
i < DL_req[CC_id].dl_config_request_body.number_pdu;
i++) {
dl_config_pdu =
&DL_req[CC_id].
dl_config_request_body.dl_config_pdu_list[i];
if ((dl_config_pdu->pdu_type ==
NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)
&& (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.
rnti == rnti)
&& (dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.dci_format != 1)) {
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.resource_block_coding =
allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,
rballoc_sub);
dl_config_pdu->dci_dl_pdu.
dci_dl_pdu_rel8.resource_allocation_type = 0;
} else
if ((dl_config_pdu->pdu_type ==
NFAPI_DL_CONFIG_DLSCH_PDU_TYPE)
&& (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.
rnti == rnti)
&& (dl_config_pdu->dlsch_pdu.
dlsch_pdu_rel8.resource_allocation_type ==
0)) {
dl_config_pdu->dlsch_pdu.
dlsch_pdu_rel8.resource_block_coding =
allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,
rballoc_sub);
}
}
}
}
}
stop_meas(&eNB->fill_DLSCH_dci);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_OUT);
}
//------------------------------------------------------------------------------
unsigned char *get_dlsch_sdu(module_id_t module_idP,
int CC_id, frame_t frameP, rnti_t rntiP,
uint8_t TBindex)
//------------------------------------------------------------------------------
{
int UE_id;
eNB_MAC_INST *eNB = RC.mac[module_idP];
if (rntiP == SI_RNTI) {
LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n",
module_idP, CC_id, frameP);
return ((unsigned char *) &eNB->common_channels[CC_id].
BCCH_pdu.payload[0]);
}
UE_id = find_UE_id(module_idP, rntiP);
if (UE_id != -1) {
LOG_D(MAC,
"[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n",
module_idP, frameP, CC_id, rntiP, UE_id);
return ((unsigned char *) &eNB->
UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]);
} else {
LOG_E(MAC,
"[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n",
module_idP, frameP, CC_id, rntiP);
return NULL;
}
}
//------------------------------------------------------------------------------
void
update_ul_dci(module_id_t module_idP,
uint8_t CC_idP, rnti_t rntiP, uint8_t daiP)
//------------------------------------------------------------------------------
{
nfapi_hi_dci0_request_t *HI_DCI0_req =
&RC.mac[module_idP]->HI_DCI0_req[CC_idP];
nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu =
&HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0];
COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP];
int i;
if (cc->tdd_Config != NULL) { // TDD
for (i = 0;
i <
HI_DCI0_req->hi_dci0_request_body.number_of_dci +
HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) {
if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) &&
(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP))
hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index =
(daiP - 1) & 3;
}
}
}
//------------------------------------------------------------------------------
void
set_ue_dai(sub_frame_t subframeP,
int UE_id, uint8_t CC_id, uint8_t tdd_config,
UE_list_t * UE_list)
//------------------------------------------------------------------------------
{
switch (tdd_config) {
case 0:
if ((subframeP == 0) || (subframeP == 1) || (subframeP == 3)
|| (subframeP == 5) || (subframeP == 6) || (subframeP == 8)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 1:
if ((subframeP == 0) || (subframeP == 4) || (subframeP == 5)
|| (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 2:
if ((subframeP == 4) || (subframeP == 5)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 3:
if ((subframeP == 5) || (subframeP == 7) || (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 4:
if ((subframeP == 0) || (subframeP == 6)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 5:
if (subframeP == 9) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
case 6:
if ((subframeP == 0) || (subframeP == 1) || (subframeP == 5)
|| (subframeP == 6) || (subframeP == 9)) {
UE_list->UE_template[CC_id][UE_id].DAI = 0;
}
break;
default:
UE_list->UE_template[CC_id][UE_id].DAI = 0;
LOG_N(MAC, "unknow TDD config %d\n", tdd_config);
break;
}
}