/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \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 "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.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"
#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif
#include "T.h"
#define ENABLE_MAC_PAYLOAD_DEBUG
#define DEBUG_eNB_SCHEDULER 1
//#define DEBUG_HEADER_PARSING 1
//#define DEBUG_PACKET_TRACE 1
/*
#ifndef USER_MODE
#define msg debug_msg
#endif
*/
#if FAPI
/* global variables to deal with TPC command - we send one only once per frame maximum */
static long global_subframe; /* global subframe - incremented at each TTI */
static long ue_last_pucch_tpc[NUMBER_OF_UE_MAX]; /* last global subframe where a PUCCH TPC was sent to the UE */
static long ue_last_pusch_tpc[NUMBER_OF_UE_MAX]; /* last global subframe where a PUSCH TPC was sent to the UE */
static void fapi_dl_tpc(int module_id, int CC_id, struct DlDciListElement_s *dci)
{
int UE_id = find_UE_id(module_id, dci->rnti);
LTE_eNB_UE_stats *eNB_UE_stats = NULL;
int32_t normalized_rx_power;
int32_t target_rx_power;
static int tpc_accumulated = 0;
if (UE_id == -1) {
#if MEGALOG
printf("SCHEDULER fapi_dl_tpc rnti %x (%d) not existing in MAC\n", dci->rnti, dci->rnti);
#endif
dci->tpc = 0;
return;
}
if (UE_id == -1) { printf("%s:%d: rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); }
// this assumes accumulated tpc
// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
if (global_subframe < ue_last_pucch_tpc[UE_id] + 10) {
#if MEGALOG
printf("TPC PUCCH global sf %ld (%ld/%ld) UE %x: no TPC, last one is too recent (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, tpc_accumulated);
#endif
dci->tpc = 0;
return;
}
eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_id, CC_id, dci->rnti);
if (eNB_UE_stats == NULL) { printf("%s:%d: stats for rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); }
normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm;
target_rx_power = mac_xface->get_target_pucch_rx_power(module_id, CC_id) + 20;
if (eNB_UE_stats->Po_PUCCH_update == 1) {
eNB_UE_stats->Po_PUCCH_update = 0;
ue_last_pucch_tpc[UE_id] = global_subframe;
if (normalized_rx_power > target_rx_power + 1) {
dci->tpc = -1;
tpc_accumulated--;
} else if (normalized_rx_power < target_rx_power - 1) {
dci->tpc = 1;
tpc_accumulated++;
} else {
dci->tpc = 0;
}
}
#if MEGALOG
printf("TPC PUCCH global sf %ld (%ld/%ld) UE %x: TPC %d (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, dci->tpc, tpc_accumulated);
#endif
}
static void fapi_ul_tpc(int module_id, int CC_id, struct UlDciListElement_s *dci)
{
int UE_id = find_UE_id(module_id, dci->rnti);
LTE_eNB_UE_stats *eNB_UE_stats = NULL;
int32_t normalized_rx_power;
int32_t target_rx_power;
static int tpc_accumulated = 0;
if (UE_id == -1) {
#if MEGALOG
printf("SCHEDULER fapi_ul_tpc rnti %x (%d) not existing in MAC\n", dci->rnti, dci->rnti);
#endif
dci->tpc = 0;
return;
}
if (UE_id == -1) { printf("%s:%d: rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); }
// this assumes accumulated tpc
// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
if (global_subframe < ue_last_pusch_tpc[UE_id] + 10) {
#if MEGALOG
printf("TPC PUSCH global sf %ld (%ld/%ld) UE %x: no TPC, last one is too recent (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, tpc_accumulated);
#endif
dci->tpc = 0;
return;
}
eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_id, CC_id, dci->rnti);
if (eNB_UE_stats == NULL) { printf("%s:%d: stats for rnti %x not found\n", __FILE__, __LINE__, dci->rnti); abort(); }
normalized_rx_power = eNB_UE_stats->UL_rssi[0];
target_rx_power = mac_xface->get_target_pusch_rx_power(module_id, CC_id);
if (normalized_rx_power > target_rx_power + 1) {
dci->tpc = -1;
tpc_accumulated--;
} else if (normalized_rx_power < target_rx_power - 1) {
dci->tpc = 1;
tpc_accumulated++;
} else {
dci->tpc = 0;
}
if (dci->tpc != 0) {
ue_last_pusch_tpc[UE_id] = global_subframe;
}
#if MEGALOG
printf("TPC PUSCH global sf %ld (%ld/%ld) UE %x: TPC %d (accumulated %d)\n", global_subframe, global_subframe/10, global_subframe%10, dci->rnti, dci->tpc, tpc_accumulated);
#endif
}
/* this structure is used to store downlink ack/nack information
* to be sent to FAPI by SchedDlTriggerReq
*/
/* TODO: lock access to it or not? */
static struct {
struct {
int rnti;
int CC_id;
int harq_pid;
int ack[MAX_TB_LIST];
int ack_count;
} ack[MAX_DL_INFO_LIST];
int count;
} fapi_dl_ack_nack_data;
/* this array is used to store uplink ack/nack information
* to be sent to FAPI by SchedUlTriggerReq
* one element per TTI
*/
/* TODO: do it per CC */
static struct {
struct {
int reception_frame; /* the frame where the ACK/NACK has been received */
int reception_subframe; /* the subframe where the ACK/NACK has been received */
int rnti;
int ack;
int length[MAX_LC_LIST+1];
} ack[MAX_UL_INFO_LIST];
int count;
} fapi_ul_ack_nack_data[10];
/* this function is called by the PHY to signal UE's ACK/NACK */
void fapi_dl_ack_nack(int CC_id, int rnti, int harq_pid, int transport_block, int ack)
{
int pos = fapi_dl_ack_nack_data.count;
#if MEGALOG
printf("GOT DOWNLINK ack %d for rnti %x harq_pid %d cc %d transport_block %d\n", ack, rnti, harq_pid, CC_id, transport_block);
#endif
/* TODO: handle more than 1 TB */
if (transport_block) { printf("%s:%d:%s: TODO: tb != 0\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (pos == MAX_DL_INFO_LIST) {
LOG_E(MAC, "fapi_dl_ack_nack: full!\n");
abort();
}
fapi_dl_ack_nack_data.ack[pos].rnti = rnti;
fapi_dl_ack_nack_data.ack[pos].CC_id = CC_id;
fapi_dl_ack_nack_data.ack[pos].harq_pid = harq_pid;
fapi_dl_ack_nack_data.ack[pos].ack[0] = ack; /* TODO: use transport_block here */
fapi_dl_ack_nack_data.ack[pos].ack_count = 1; /* TODO: take care of transport block */
fapi_dl_ack_nack_data.count++;
}
/* this array is used to deal with Msg4 ack/nack
* once we get an ACK, the UE is considered configured
* if we get a NACK, we have to deal with retransmission of Msg4 (TODO)
*/
unsigned char waiting_for_msg4_ack[65536];
/* this function is called by the PHY to inform about correct or wrong
* reception by the eNodeB of an uplink UE transmission
*/
/* TODO: do it per CC */
void fapi_ul_ack_nack(int frame, int subframe, int harq_pid, int rnti, int ack)
{
#if MEGALOG
printf("GOT UPLINK ack %d for rnti %x harq_pid %d (f/sf %d/%d)\n", ack, rnti, harq_pid, frame, subframe);
#endif
int pos = fapi_ul_ack_nack_data[subframe].count;
if (pos == MAX_UL_INFO_LIST) {
LOG_E(MAC, "fapi_ul_ack_nack: full! (f/sf %d/%d)\n", frame, subframe);
abort();
}
fapi_ul_ack_nack_data[subframe].ack[pos].reception_frame = frame;
fapi_ul_ack_nack_data[subframe].ack[pos].reception_subframe = subframe;
fapi_ul_ack_nack_data[subframe].ack[pos].rnti = rnti;
fapi_ul_ack_nack_data[subframe].ack[pos].ack = ack;
if (waiting_for_msg4_ack[rnti] == 1) {
/* TODO: deal with module_id != 0, CC_id != 0 */
eNB_MAC_INST *eNB = &eNB_mac_inst[0 /*module_idP*/];
RA_TEMPLATE *RA_template;
int i, UE_id;
waiting_for_msg4_ack[rnti] = 0;
for (i = 0; i < NB_RA_PROC_MAX; i++) {
RA_template = (RA_TEMPLATE *)&eNB->common_channels[0 /* CC_id */].RA_template[i];
if (RA_template->RA_active != TRUE) continue;
if (RA_template->rnti != rnti) continue;
break;
}
if (i == NB_RA_PROC_MAX) { printf("%s:%d:%s: possible?\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
RA_template->RA_active = FALSE;
RA_template->wait_ack_Msg4=0;
fprintf(stderr, "f/sf %d/%d got ack value %d for RA Msg4 for UE %d\n", frame, subframe, ack, rnti);
UE_id = find_UE_id(0 /*module_idP */,RA_template->rnti);
if (UE_id == -1) abort();
eNB_mac_inst[0 /* module_idP */].UE_list.UE_template[UE_PCCID(0 /* module_idP */,UE_id)][UE_id].configured=TRUE;
}
/* the values in length are set later in the function fapi_ul_lc_length */
memset(fapi_ul_ack_nack_data[subframe].ack[pos].length, 0, sizeof(int) * MAX_LC_LIST+1);
fapi_ul_ack_nack_data[subframe].count++;
/* TODO: get proper SINR information
* for the moment: let's report a sinr of 20 (arbitrary)
* for every RBs
*/
fapi_interface_t *fapi = eNB_mac_inst[0 /* TODO: get correct module_id*/].fapi;
struct SchedUlCqiInfoReqParameters params;
struct UlCqi_s cqi;
int i;
cqi.rnti = rnti;
for (i = 0; i < 100; i++)
cqi.sinr[i] = 20<<3;
cqi.type = ff_PUSCH;
cqi.servCellIndex = 0; /* TODO: get correct cell index */
params.sfnSf = frame * 16 + subframe;
params.nr_ulCqiList = 1;
params.ulCqiList = &cqi;
params.nr_vendorSpecificList = 0;
params.vendorSpecificList = NULL;
SchedUlCqiInfoReq(fapi->sched, ¶ms);
}
/* this function is called by rx_sdu to indicate the number of
* bytes received by the given Logical Channel
*/
void fapi_ul_lc_length(int frame, int subframe, int lcid, int length, int rnti)
{
#if MEGALOG
printf("GOT lcid %d length %d (f/sf %d/%d)\n", lcid, length, frame, subframe);
#endif
int pos = fapi_ul_ack_nack_data[subframe].count - 1;
if (pos < 0) { printf("%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* TODO: remove this check (and the rnti parameter)? */
if (rnti != fapi_ul_ack_nack_data[subframe].ack[pos].rnti) {
printf("%s:%d:%s: fatal error: LCID %d wrong RNTI %x (expected %x)\n",
__FILE__, __LINE__, __FUNCTION__, lcid,
rnti, fapi_ul_ack_nack_data[subframe].ack[pos].rnti);
abort();
}
if (lcid < 0 || lcid > 3)
{ printf("%s:%d:%s: fatal error: unhandled LCID %d\n", __FILE__, __LINE__, __FUNCTION__, lcid); abort(); }
fapi_ul_ack_nack_data[subframe].ack[pos].length[lcid] = length;
}
void fapi_dl_cqi_report(int module_id, int rnti, int frame, int subframe, int cqi_wideband, int *cqi_subband, int rank_indication)
{
/* TODO: 2 TBs, other reporting modes - we suppose 3-0 (see 36.213 7.2.1) */
fapi_interface_t *fapi;
struct SchedDlCqiInfoReqParameters params;
struct CqiListElement_s cqi;
int i;
fapi = eNB_mac_inst[module_id].fapi;
cqi.rnti = rnti;
cqi.csiReport.ri = rank_indication;
cqi.csiReport.mode = A30; /* TODO: get real value */
cqi.csiReport.report.A30Csi.wbCqi = cqi_wideband;
for (i = 0; i < MAX_HL_SB; i++)
cqi.csiReport.report.A30Csi.sbCqi[i] = cqi_subband[i];
/* TODO: remove this oaisim fix
* value 0 is not allowed in wideband CQI reporting,
* see 36.213 7.2.3 table 7.2.3-1
* but we get value 0 in oaisim
*/
if (cqi.csiReport.report.A30Csi.wbCqi == 0) cqi.csiReport.report.A30Csi.wbCqi++;
cqi.servCellIndex = 0; /* TODO: get correct value */
params.sfnSf = frame * 16 + subframe;
params.nrcqiList = 1;
params.cqiList = &cqi;
params.nr_vendorSpecificList = 0;
params.vendorSpecificList = NULL;
//fprintf(stderr, "fsf %d/%d CQI wideband %d rank_indication %d\n", frame, subframe, cqi_wideband, rank_indication);
//for (i = 0; i < MAX_HL_SB; i++)
//fprintf(stderr, " subband %d: %d\n", i, cqi_subband[i]);
SchedDlCqiInfoReq(fapi->sched, ¶ms);
/* TODO: get rid of this hack */
cqi.rnti = rnti;
cqi.csiReport.ri = rank_indication;
cqi.csiReport.mode = A30; /* TODO: get real value */
cqi.csiReport.report.A30Csi.wbCqi = cqi_wideband;
for (i = 0; i < MAX_HL_SB; i++)
cqi.csiReport.report.A30Csi.sbCqi[i] = cqi_subband[i];
if (cqi.csiReport.report.A30Csi.wbCqi == 0) cqi.csiReport.report.A30Csi.wbCqi++;
cqi.servCellIndex = 1; /* TODO: get correct value */
params.sfnSf = frame * 16 + subframe;
params.nrcqiList = 1;
params.cqiList = &cqi;
params.nr_vendorSpecificList = 0;
params.vendorSpecificList = NULL;
SchedDlCqiInfoReq(fapi->sched, ¶ms);
}
#define CONVERT_DL_1A_FDD(bandwidth) \
static void fapi_convert_dl_1A_ ## bandwidth ## MHz_FDD(struct DlDciListElement_s *dci, DCI_ALLOC_t *a) \
{ \
DCI1A_ ## bandwidth ## MHz_FDD_t *d = (DCI1A_ ## bandwidth ## MHz_FDD_t *)a->dci_pdu; \
\
if (dci->nr_of_tbs != 1) { printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); exit(1); } \
\
d->type = 1; /* type = 0 => DCI Format 0, type = 1 => DCI Format 1A */ \
d->vrb_type = dci->vrbFormat == VRB_LOCALIZED ? 0 : \
dci->vrbFormat == VRB_DISTRIBUTED ? 1 : \
(printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0); \
d->rballoc = dci->rbBitmap; \
d->mcs = dci->mcs[0]; /* TODO: take care of transport block index */ \
d->harq_pid = dci->harqProcess; \
d->ndi = dci->ndi[0]; /* TODO: take care of transport block index */ \
d->rv = dci->rv[0]; /* TODO: take care of transport block index */ \
d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.2.1-1 */ \
dci->tpc == 0 ? 1 : \
dci->tpc == 1 ? 2 : \
dci->tpc == 3 ? 3 : \
(printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0); \
d->padding = 0; \
\
a->dci_length = sizeof_DCI1A_ ## bandwidth ## MHz_FDD_t; \
a->format = format1A; \
}
CONVERT_DL_1A_FDD(5); /* defines fapi_convert_dl_1A_5MHz_FDD */
CONVERT_DL_1A_FDD(10); /* defines fapi_convert_dl_1A_10MHz_FDD */
CONVERT_DL_1A_FDD(20); /* defines fapi_convert_dl_1A_20MHz_FDD */
static uint32_t revert(uint32_t x, int len)
{return x;
int i;
int ret = 0;
for (i = 0; i < len; i++) {
ret <<= 1;
ret |= x & 1;
x >>= 1;
}
return ret;
}
int cqi_ready[65536];
#define CONVERT_DL_1_FDD(bandwidth) \
static void fapi_convert_dl_1_ ## bandwidth ## MHz_FDD(struct DlDciListElement_s *dci, DCI_ALLOC_t *a) \
{ \
DCI1_ ## bandwidth ## MHz_FDD_t *d = (DCI1_ ## bandwidth ## MHz_FDD_t *)a->dci_pdu; \
\
if (dci->nr_of_tbs != 1) { printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); exit(1); } \
\
d->rah = dci->resAlloc == 0 ? 0 : \
dci->resAlloc == 1 ? 1 : \
(printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0); \
d->rballoc = revert(dci->rbBitmap, 13); \
d->mcs = dci->mcs[0]; /* TODO: take care of transport block index */ \
d->harq_pid = dci->harqProcess; \
d->ndi = dci->ndi[0]; /* TODO: take care of transport block index */ \
d->rv = dci->rv[0]; /* TODO: take care of transport block index */ \
d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.2.1-1 */ \
dci->tpc == 0 ? 1 : \
dci->tpc == 1 ? 2 : \
dci->tpc == 3 ? 3 : \
(printf("%s:%d: error (dci->tpc = %d)\n", __FUNCTION__, __LINE__, dci->tpc), abort(), 0); \
d->dummy = 0; \
\
a->dci_length = sizeof_DCI1_ ## bandwidth ## MHz_FDD_t; \
a->format = format1; \
}
CONVERT_DL_1_FDD(5); /* defines fapi_convert_dl_1_5MHz_FDD */
CONVERT_DL_1_FDD(10); /* defines fapi_convert_dl_1_10MHz_FDD */
CONVERT_DL_1_FDD(20); /* defines fapi_convert_dl_1_20MHz_FDD */
static void fapi_convert_dl_dci(int module_id, int CC_id,
struct DlDciListElement_s *dci, DCI_ALLOC_t *a)
{
/* set TPC in the DCI */
/* TODO: remove it if/when the scheduler does it */
if (dci->rnti != 0)
fapi_dl_tpc(module_id, CC_id, dci);
if (dci->format == ONE && dci->resAlloc != 0) { printf("ERROR: resAlloc must be 0\n"); abort(); }
/* TODO: handle all bandwidths */
switch (PHY_vars_eNB_g[module_id][CC_id]->lte_frame_parms.N_RB_DL) {
case 25:
switch (dci->format) {
case ONE_A: fapi_convert_dl_1A_5MHz_FDD(dci, a); break;
case ONE: fapi_convert_dl_1_5MHz_FDD(dci, a); break;
default: printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); abort();
}
break;
case 50:
switch (dci->format) {
case ONE_A: fapi_convert_dl_1A_10MHz_FDD(dci, a); break;
case ONE: fapi_convert_dl_1_10MHz_FDD(dci, a); break;
default: printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); abort();
}
break;
case 100:
switch (dci->format) {
case ONE_A: fapi_convert_dl_1A_20MHz_FDD(dci, a); break;
case ONE: fapi_convert_dl_1_20MHz_FDD(dci, a); break;
default: printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); abort();
}
break;
default: printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); abort();
}
a->L = dci->aggrLevel == 1 ? 0 :
dci->aggrLevel == 2 ? 1 :
dci->aggrLevel == 4 ? 2 :
dci->aggrLevel == 8 ? 3 :
(printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0);
a->firstCCE = dci->cceIndex;
a->ra_flag = 0; /* TODO: set to 1 only by fapi_schedule_RAR, is it ok? */
a->rnti = dci->rnti;
}
#define CONVERT_UL_FDD(bandwidth) \
static void fapi_convert_ul_ ## bandwidth ## MHz_FDD(module_id_t module_idP, int CC_id, \
struct UlDciListElement_s *dci, DCI_ALLOC_t *a) \
{ \
DCI0_ ## bandwidth ## MHz_FDD_t *d = (DCI0_ ## bandwidth ## MHz_FDD_t *)a->dci_pdu; \
\
d->type = 0; /* type = 0 => DCI Format 0, type = 1 => DCI Format 1A */ \
d->hopping = dci->hopping; \
d->rballoc = mac_xface->computeRIV(PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.N_RB_DL, dci->rbStart, dci->rbLen); \
d->mcs = dci->mcs; \
d->ndi = dci->ndi; \
d->TPC = dci->tpc == -1 ? 0 : /* see 36.213 table 5.1.1.1-2, accumulated case supposed */ \
dci->tpc == 0 ? 1 : \
dci->tpc == 1 ? 2 : \
dci->tpc == 3 ? 3 : \
(printf("%s:%d: error (tpc = %d)\n", __FUNCTION__, __LINE__, dci->tpc), abort(), 0); \
d->cshift = dci->n2Dmrs; /* TODO: this may be wrong, */ \
/* see openair1/PHY/LTE_TRANSPORT/dci_tools.c:generate_eNB_ulsch_params_from_dci */ \
/* there is a translation between those */ \
d->cqi_req = dci->cqiRequest; \
if (!cqi_ready[dci->rnti]) d->cqi_req = 0; \
/* TODO: do not disable CQI request */ \
d->cqi_req = 0; \
/*if (dci->cqiRequest) fprintf(stderr, "cqi req (ready %d) (d->cqi_req %d)!!\n", cqi_ready[dci->rnti], d->cqi_req);*/ \
d->padding = 0; \
\
a->dci_length = sizeof_DCI0_ ## bandwidth ## MHz_FDD_t; \
a->format = format0; \
}
CONVERT_UL_FDD(5); /* defines fapi_convert_ul_5MHz_FDD */
CONVERT_UL_FDD(10); /* defines fapi_convert_ul_10MHz_FDD */
CONVERT_UL_FDD(20); /* defines fapi_convert_ul_20MHz_FDD */
static void fapi_convert_ul_dci(module_id_t module_idP, int CC_id,
struct UlDciListElement_s *dci, DCI_ALLOC_t *a)
{
/* set TPC in the DCI */
/* TODO: remove it if/when the scheduler does it */
fapi_ul_tpc(module_idP, CC_id, dci);
if (dci->hopping != 0) { printf("ERROR: hopping must be 0\n"); abort(); }
/* TODO: handle all bandwidths */
switch (PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.N_RB_UL) {
case 25: fapi_convert_ul_5MHz_FDD(module_idP, CC_id, dci, a); break;
case 50: fapi_convert_ul_10MHz_FDD(module_idP, CC_id, dci, a); break;
case 100: fapi_convert_ul_20MHz_FDD(module_idP, CC_id, dci, a); break;
default: printf("%s:%d: TODO\n", __FUNCTION__, __LINE__); abort();
}
a->L = dci->aggrLevel == 1 ? 0 :
dci->aggrLevel == 2 ? 1 :
dci->aggrLevel == 4 ? 2 :
dci->aggrLevel == 8 ? 3 :
(printf("%s:%d: error\n", __FUNCTION__, __LINE__), abort(), 0);
a->firstCCE = dci->cceIndex;
a->ra_flag = 0;
a->rnti = dci->rnti;
#if MEGALOG
printf("FAPI to MAC ul DCI ue %d rbStart %d rbLen %d tbs %d CCE %d mcs %d ndi %d tpc %d cshift %d cqi_req %d aggrLevel %d\n",
dci->rnti, dci->rbStart, dci->rbLen, dci->tbSize, dci->cceIndex, dci->mcs, dci->ndi, dci->tpc, dci->n2Dmrs, dci->cqiRequest, dci->aggrLevel);
#endif
}
/* index 0 for SIB1, 1 for SIB23 */
static void fapi_schedule_SI(module_id_t module_idP, int CC_id, frame_t frameP,
sub_frame_t subframeP, uint8_t index, struct DlDciListElement_s *dci)
{
eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP];
DCI_PDU *dci_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
int bcch_sdu_length;
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
fapi_convert_dl_dci(module_idP, CC_id, dci, a);
/* bug in libscheduler.a? rnti is 0 */
a->rnti = SI_RNTI;
if (index == 0)
bcch_sdu_length = mac_rrc_get_SIB1(module_idP, CC_id, &eNB->common_channels[CC_id].BCCH_pdu.payload[0]);
else if (index == 1)
bcch_sdu_length = mac_rrc_get_SIB23(module_idP, CC_id, &eNB->common_channels[CC_id].BCCH_pdu.payload[0]);
else { printf("%s:%d: fatal error\n", __FUNCTION__, __LINE__); abort(); }
eNB->eNB_stats[CC_id].total_num_bcch_pdu+=1;
eNB->eNB_stats[CC_id].bcch_buffer=bcch_sdu_length;
eNB->eNB_stats[CC_id].total_bcch_buffer+=bcch_sdu_length;
eNB->eNB_stats[CC_id].bcch_mcs=dci->mcs[0]; /* TODO: take care of transport block index */
}
static void fapi_schedule_RAR(int module_idP, int CC_id, frame_t frameP,
sub_frame_t subframeP, uint16_t rnti, uint32_t grant,
struct DlDciListElement_s *dci)
{
eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP];
DCI_PDU *dci_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
RA_TEMPLATE *RA_template = NULL;
int i;
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
for (i = 0; i < NB_RA_PROC_MAX; i++) {
RA_template = (RA_TEMPLATE *)&eNB->common_channels[CC_id].RA_template[i];
if (RA_template->RA_active != TRUE) continue;
if (RA_template->rnti != rnti) continue;
break;
}
if (i == NB_RA_PROC_MAX) { printf("%s:%d:%s: possible?\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (grant & 0x80000) {
LOG_E(MAC, "uplink grant has hopping flag set (0x%x)\n", grant);
exit(1);
grant &= ~0x80000;
}
RA_template->generate_rar = 1;
RA_template->UL_grant = grant;
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
fapi_convert_dl_dci(module_idP, CC_id, dci, a);
a->ra_flag = 1;
/* bug in libscheduler.a? rnti is 0 */
a->rnti = RA_template->RA_rnti;
}
static void fapi_schedule_RA_Msg4(int module_idP, int CC_id, int RA,
int frameP, int subframeP, struct DlDciListElement_s *dci, int pdu_maxsize)
{
int UE_id;
int rrc_sdu_length;
eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP];
RA_TEMPLATE *RA_template;
int msg4_header_length;
int msg4_padding, msg4_post_padding;
int TBsize;
DCI_PDU *dci_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
int offset;
unsigned char lcid;
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
RA_template = (RA_TEMPLATE *)&eNB->common_channels[CC_id].RA_template[RA];
UE_id = find_UE_id(module_idP,RA_template->rnti);
if (UE_id == -1) abort();
rrc_sdu_length = mac_rrc_data_req(module_idP,
CC_id,
frameP,
CCCH,
1, // 1 transport block
&eNB->common_channels[CC_id].CCCH_pdu.payload[0],
ENB_FLAG_YES,
module_idP,
0); // not used in this case
if (rrc_sdu_length <= 0) {
LOG_E(MAC, "fapi_schedule_RA_Msg4: rrc_sdu_length (%d) is not > 0\n", rrc_sdu_length);
abort();
}
if (rrc_sdu_length > pdu_maxsize) {
LOG_E(MAC, "fapi_schedule_RA_Msg4: rrc_sdu_length (%d) > pdu_maxsize (%d)\n", rrc_sdu_length, pdu_maxsize);
// abort();
}
msg4_header_length = 1+6+1; // CR header, CR CE, SDU header
TBsize = dci->tbsSize[CC_id] / 8;
if (TBsize < msg4_header_length+rrc_sdu_length) abort();
if ((TBsize - rrc_sdu_length - msg4_header_length) <= 2) {
msg4_padding = TBsize - rrc_sdu_length - msg4_header_length;
msg4_post_padding = 0;
} else {
msg4_padding = 0;
msg4_post_padding = TBsize - rrc_sdu_length - msg4_header_length -1;
}
LOG_I(RRC,"[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n",
module_idP, CC_id, frameP, subframeP, TBsize, rrc_sdu_length, msg4_header_length, msg4_padding, msg4_post_padding);
lcid = 0;
offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
1, //num_sdus
(unsigned short*)&rrc_sdu_length, //
&lcid, // sdu_lcid
255, // no drx
0, // no timing advance
RA_template->cont_res_id, // contention res id
msg4_padding, // no padding
msg4_post_padding,
/* TODO: scell bitmap command */
0, 0);
memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],
&eNB->common_channels[CC_id].CCCH_pdu.payload[0],
rrc_sdu_length);
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP),
T_INT(0), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0], TBsize));
RA_template->generate_Msg4=0;
RA_template->wait_ack_Msg4=1;
//RA_template->RA_active = FALSE;
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
waiting_for_msg4_ack[RA_template->rnti] = 1;
fapi_convert_dl_dci(module_idP, CC_id, dci, a);
}
/* returns 1 if the given LCID has a MAC header of fixed size (for DL-SCH) */
static int fixed_size(int lcid)
{
/* see 36.321, especially table 6.2.1-1 (rel. 10 is used here) */
return lcid >= 27;
}
/* TODO: deal with MCS 29-31 in the PHY layer
* in the meantime, this array stores the latest mcs used for each rnti/servcell/harq_pid
*/
static unsigned char latest_mcs[65536][2][10];
static unsigned int latest_rbbitmap[65536][2][10];
/* TODO: deal with more than one transport block */
static void fapi_schedule_retransmission_ue(int module_id, int CC_id, int frame, int subframe, struct BuildDataListElement_s *d)
{
int header_size;
int payload_size;
int padding_size;
int tbs;
int i;
mac_rlc_status_resp_t rlc_status;
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
int dlsch_filled = 0;
int output_length;
int UE_id;
eNB_MAC_INST *eNB = &eNB_mac_inst[module_id];
UE_list_t *UE_list = &eNB->UE_list;
int num_sdus;
unsigned short sdu_lengths[MAX_RLC_PDU_LIST];
unsigned char sdu_lcids[MAX_RLC_PDU_LIST];
int offset;
DCI_PDU *dci_pdu = &eNB->common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
/* generate DCI */
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
/* TODO: handle the case where CC_id != servCellIndex */
if (CC_id != d->servCellIndex) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
#if MEGALOG
static char *X[] = {"ONE", "ONE_A", "ONE_B", "ONE_C", "ONE_D", "TWO", "TWO_A", "TWO_B"};
static char *Y[] = {"VRB_DISTRIBUTED", "VRB_LOCALIZED"};
printf("RETR fsf %d/%d rnti %d rbBitmap %x rbShift %d rbgSubset %d resAlloc %d nr_of_tbs %d tbsSize[0] %d mcs[0] %d (latest %d) ndi[0] %d rv[0] %d cceIndex %d aggrLevel %d precodingInfo %d format %s tpc %d harqProcess %d vrbFormat %s tbSwap %d spsRelease %d preambleIndex %d prachMaskIndex %d nGap %d dlPowerOffset %d pdcchPowerOffset %d cifPresent %d\n",
frame,
subframe,
d->dci.rnti,
d->dci.rbBitmap,
d->dci.rbShift,
d->dci.rbgSubset,
d->dci.resAlloc,
d->dci.nr_of_tbs,
d->dci.tbsSize[0],
d->dci.mcs[0],
latest_mcs[d->rnti][CC_id][d->dci.harqProcess],
d->dci.ndi[0],
d->dci.rv[0],
d->dci.cceIndex,
d->dci.aggrLevel,
d->dci.precodingInfo,
X[d->dci.format],
d->dci.tpc,
d->dci.harqProcess,
Y[d->dci.vrbFormat],
d->dci.tbSwap,
d->dci.spsRelease,
d->dci.preambleIndex,
d->dci.prachMaskIndex,
d->dci.nGap+1,
d->dci.dlPowerOffset,
d->dci.pdcchPowerOffset,
d->dci.cifPresent);
#endif
/* TODO: deal with MCS 29-31 in the PHY layer
* in the meantime, let's replace with the last used MCS
*/
d->dci.mcs[0] = latest_mcs[d->rnti][CC_id][d->dci.harqProcess];
/* TODO: remove this terrible hack! */
d->dci.rbBitmap = latest_rbbitmap[d->rnti][CC_id][d->dci.harqProcess];
fapi_convert_dl_dci(module_id, CC_id, &d->dci, a);
#if MEGALOG
printf("RUN fapi_schedule_retransmission_ue\n");
#endif
if (d->nr_rlcPDU_List[0] != 0) { /*printf("%s:%d:%s: error?\n", __FILE__, __LINE__, __FUNCTION__);*/ /*abort();*/ }
if (d->nr_rlcPDU_List[1] != 0) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (d->ceBitmap[1]) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (d->servCellIndex != 0 &&
d->servCellIndex != 1) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* activate/deactive 2nd cell
* TODO: do it better, only activate at subframe+8 if ACK received at subframe +4
*/
if (d->ceBitmap[0]) {
if (d->ceBitmap[0] != ff_AD) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); /*abort();*/ }
LOG_I(MAC, "FAPI: f/sf %d/%d rnti %d ca_activate %2.2x\n", frame, subframe, d->rnti, d->activationDeactivationCE);
//mac_xface->ca_activate(module_id, d->rnti, d->activationDeactivationCE);
/* TODO: remove this hack */
if (d->ceBitmap[0] == ff_AD)
mac_xface->ca_activate(module_id, d->rnti, 2);
}
UE_id = find_UE_id(module_id, d->rnti);
if (UE_id == -1) {
#if MEGALOG
printf("SCHEDULER fapi_schedule_retransmission_ue rnti %x (%d) not existing in MAC\n", d->rnti, d->rnti);
#endif
abort();
}
add_ue_dlsch_info(module_id,
CC_id,
UE_id,
subframe,
/* S_DL_SCHEDULED */ S_DL_WAITING);
}
/* TODO: deal with more than one transport block */
static void fapi_schedule_ue(int module_id, int CC_id, int frame, int subframe, struct BuildDataListElement_s *d)
{
int header_size;
int payload_size;
int padding_size;
int tbs;
int i;
mac_rlc_status_resp_t rlc_status;
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
int dlsch_filled = 0;
int output_length;
int UE_id;
eNB_MAC_INST *eNB = &eNB_mac_inst[module_id];
UE_list_t *UE_list = &eNB->UE_list;
int num_sdus;
unsigned short sdu_lengths[MAX_RLC_PDU_LIST];
unsigned char sdu_lcids[MAX_RLC_PDU_LIST];
int offset;
DCI_PDU *dci_pdu = &eNB->common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
/* retransmission? */
if (d->dci.mcs[0] >= 29 && d->dci.mcs[0] <= 31) {
fapi_schedule_retransmission_ue(module_id, CC_id, frame, subframe, d);
return;
}
if (d->nr_rlcPDU_List[0] > 1) { printf("%s:%d:%s: TODO (d->nr_rlcPDU_List[0] %d)\n", __FILE__, __LINE__, __FUNCTION__, d->nr_rlcPDU_List[0]); return; }
#if MEGALOG
static char *X[] = {"ONE", "ONE_A", "ONE_B", "ONE_C", "ONE_D", "TWO", "TWO_A", "TWO_B"};
static char *Y[] = {"VRB_DISTRIBUTED", "VRB_LOCALIZED"};
printf("fsf %d/%d rnti %d rbBitmap %x rbShift %d rbgSubset %d resAlloc %d nr_of_tbs %d tbsSize[0] %d mcs[0] %d ndi[0] %d rv[0] %d cceIndex %d aggrLevel %d precodingInfo %d format %s tpc %d harqProcess %d vrbFormat %s tbSwap %d spsRelease %d preambleIndex %d prachMaskIndex %d nGap %d dlPowerOffset %d pdcchPowerOffset %d cifPresent %d\n",
frame,
subframe,
d->dci.rnti,
d->dci.rbBitmap,
d->dci.rbShift,
d->dci.rbgSubset,
d->dci.resAlloc,
d->dci.nr_of_tbs,
d->dci.tbsSize[0],
d->dci.mcs[0],
d->dci.ndi[0],
d->dci.rv[0],
d->dci.cceIndex,
d->dci.aggrLevel,
d->dci.precodingInfo,
X[d->dci.format],
d->dci.tpc,
d->dci.harqProcess,
Y[d->dci.vrbFormat],
d->dci.tbSwap,
d->dci.spsRelease,
d->dci.preambleIndex,
d->dci.prachMaskIndex,
d->dci.nGap+1,
d->dci.dlPowerOffset,
d->dci.pdcchPowerOffset,
d->dci.cifPresent);
#endif
/* generate DCI */
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
fapi_convert_dl_dci(module_id, CC_id, &d->dci, a);
#if MEGALOG
printf("RUN fapi_schedule_ue\n");
#endif
/* TODO: support more than one RLC PDU */
if (d->nr_rlcPDU_List[0] > 1) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (d->nr_rlcPDU_List[1] != 0) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (d->ceBitmap[1]) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
if (d->servCellIndex != 0 &&
d->servCellIndex != 1) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* TODO: handle the case where CC_id != servCellIndex */
if (CC_id != d->servCellIndex) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* activate/deactive 2nd cell
* TODO: do it better, only activate at subframe+8 if ACK received at subframe +4
*/
if (d->ceBitmap[0]) {
if (d->ceBitmap[0] != ff_AD) { printf("%s:%d:%s: TODO (bitmap %d)\n", __FILE__, __LINE__, __FUNCTION__, d->ceBitmap[0]); /*abort();*/ }
LOG_I(MAC, "FAPI: f/sf %d/%d rnti %d ca_activate %2.2x\n", frame, subframe, d->rnti, d->activationDeactivationCE);
//mac_xface->ca_activate(module_id, d->rnti, d->activationDeactivationCE);
/* TODO: remove this hack */
if (d->ceBitmap[0] == ff_AD)
mac_xface->ca_activate(module_id, d->rnti, 2);
}
/* TODO: deal with MCS 29-31
* in the meantime, we store the latest used mcs for each rnti/harq_pid
*/
latest_mcs[d->rnti][CC_id][d->dci.harqProcess] = d->dci.mcs[0];
latest_rbbitmap[d->rnti][CC_id][d->dci.harqProcess] = d->dci.rbBitmap;
tbs = d->dci.tbsSize[0] / 8;
num_sdus = 0;
/* get DLSCH buffer and adjust size according to what RLC says */
for (i = 0; i < d->nr_rlcPDU_List[0]; i++) {
if (d->rlcPduList[0][i].logicalChannelIdentity > 3) { printf("%s:%d:%s: bad lcid %d\n", __FILE__, __LINE__, __FUNCTION__, d->rlcPduList[0][i].logicalChannelIdentity); abort(); }
rlc_status = mac_rlc_status_ind(
module_id,
d->rnti,
module_id,
frame,
ENB_FLAG_YES,
MBMS_FLAG_NO,
d->rlcPduList[0][i].logicalChannelIdentity,
d->rlcPduList[0][i].size);
#if MEGALOG
printf("RLC_SIZE in fapi_schedule_ue %d (asked %d) lcid %d rnti %x f/sf %d/%d\n", rlc_status.bytes_in_buffer, d->rlcPduList[0][i].size, d->rlcPduList[0][i].logicalChannelIdentity, d->rnti, frame, subframe);
#endif
/* TODO: what if we get 0? */
if (rlc_status.bytes_in_buffer < 0) { printf("%s:%d:%s: error\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
// if (rlc_status.bytes_in_buffer > d->rlcPduList[0][i].size) abort(); /* that can't happen */
if (dlsch_filled + d->rlcPduList[0][i].size > MAX_DLSCH_PAYLOAD_BYTES) {
printf("dlsch buffer filled too much\n");
abort();
}
//if (d->rlcPduList[0][i].size == 2) {
// printf("yo\n");
//}
output_length = mac_rlc_data_req(
module_id,
d->rnti,
module_id,
frame,
ENB_FLAG_YES,
MBMS_FLAG_NO,
d->rlcPduList[0][i].logicalChannelIdentity,
(char *)&dlsch_buffer[dlsch_filled]);
if (output_length == 0)
LOG_W(MAC, "FAPI f/sf %d/%d: RLC returned length 0 while asked %d for channel ID %d\n",
frame, subframe,
d->rlcPduList[0][i].size, d->rlcPduList[0][i].logicalChannelIdentity);
if (output_length < 0 || output_length > d->rlcPduList[0][i].size) abort();
d->rlcPduList[0][i].size = output_length;
dlsch_filled += output_length;
sdu_lengths[num_sdus] = output_length;
sdu_lcids[num_sdus] = d->rlcPduList[0][i].logicalChannelIdentity;
num_sdus++;
#if MEGALOG
printf("FILLED %d bytes\n", output_length);
#endif
}
/* get size of header and payload */
header_size = 0;
payload_size = 0;
/* TODO: 2nd TB */
if (d->ceBitmap[0] & ff_AD) {
header_size++;
payload_size++;
}
if (d->nr_rlcPDU_List[0]) {
header_size++;
payload_size += d->rlcPduList[0][0].size;
}
for (i = 1; i < d->nr_rlcPDU_List[0]; i++) {
if (!fixed_size(d->rlcPduList[0][i-1].logicalChannelIdentity)) {
header_size++;
if (d->rlcPduList[0][i-1].size >= 128)
header_size++;
}
header_size++;
payload_size += d->rlcPduList[0][i].size;
}
padding_size = tbs - header_size - payload_size;
#if MEGALOG
printf("PADDING_SIZE %d\n", padding_size);
#endif
//if (padding_size == 3) { printf("padding size 3\n"); abort(); }
UE_id = find_UE_id(module_id, d->rnti);
if (UE_id == -1) {
#if MEGALOG
printf("SCHEDULER fapi_schedule_ue rnti %x (%d) not existing in MAC\n", d->rnti, d->rnti);
#endif
abort();
}
/* generate dlsch header */
offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
num_sdus,
sdu_lengths,
sdu_lcids,
255, // no drx
0, /* TODO: timing advance */
NULL, // contention res id
padding_size <= 2 ? padding_size : 0,
padding_size > 2 ? padding_size : 0,
/* TODO: remove this hack */
2 /*d->activationDeactivationCE*/, (d->ceBitmap[0] & ff_AD) != 0);
/* fill payload */
memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], dlsch_buffer, dlsch_filled);
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(d->rnti), T_INT(frame), T_INT(subframe),
T_INT(d->dci.harqProcess), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], tbs));
#if MEGALOG
printf("BLOCK (%d)", tbs);
for (i = 0; i < tbs; i++) printf(" %2.2x", (unsigned char)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][i]);
printf("\n");
#endif
add_ue_dlsch_info(module_id,
CC_id,
UE_id,
subframe,
/* S_DL_SCHEDULED */ S_DL_WAITING);
}
static void fapi_schedule_uplink(int module_idP, int CC_id, struct UlDciListElement_s *dci)
{
DCI_PDU *dci_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu;
DCI_ALLOC_t *a = &dci_pdu->dci_alloc[dci_pdu->Num_common_dci];
if (dci_pdu->Num_common_dci >= NUM_DCI_MAX) { printf("%s:%d:%s: too much DCIs\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
/* we can increment Num_common_dci or Num_ue_spec_dci, there is no difference */
dci_pdu->Num_common_dci++;
fapi_convert_ul_dci(module_idP, CC_id, dci, a);
}
char *binary(unsigned x)
{
static char r[33];
char *s = r+31;
int i;
r[32] = 0;
for (i = 0; i < 32; i++) {
*s = '0' + (x&1);
s--;
x >>= 1;
}
return r;
}
static char *dci_format_to_string(DCI_format_t f)
{
switch (f) {
case format0: return "format 0";
case format1: return "format 1";
case format1A: return "format 1A";
case format1B: return "format 1B";
case format1C: return "format 1C";
case format1D: return "format 1D";
case format1E_2A_M10PRB: return "format 1E_2A_M10PRB";
case format2: return "format 2";
case format2A: return "format 2A";
case format2B: return "format 2B";
case format2C: return "format 2C";
case format2D: return "format 2D";
case format3: return "format 3";
}
printf("%s:%d: unhandled DCI format\n", __FILE__, __LINE__);
abort();
}
static int next_frame = 0;
static int next_subframe = 0;
static pthread_mutex_t fmut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t fcond = PTHREAD_COND_INITIALIZER;
void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, frame_t frameP, sub_frame_t subframeP) //, int calibration_flag) {
{
if (pthread_mutex_lock(&fmut)) abort();
int CC_id;
int i, j;
DCI_PDU *DCI_pdu[MAX_NUM_CCs];
int mbsfn_status[MAX_NUM_CCs];
UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list;
fapi_interface_t *fapi;
struct SchedDlTriggerReqParameters dlreq;
struct SchedDlConfigIndParameters dlind;
struct DlInfoListElement_s dlinfo[MAX_DL_INFO_LIST];
protocol_ctxt_t ctxt;
int UE_id;
eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP];
struct SchedUlTriggerReqParameters ulreq;
struct SchedUlConfigIndParameters ulind;
struct UlInfoListElement_s ulinfo[MAX_UL_INFO_LIST];
int ulsf;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
#if MEGALOG
printf("SCHEDULER called for f/sf %d/%d\n", frameP, subframeP);
#endif
#if defined(ENABLE_ITTI)
while (1) {
// Checks if a message has been sent to MAC sub-task
MessageDef *msg_p;
int result;
itti_poll_msg (TASK_MAC_ENB, &msg_p);
if (msg_p == NULL) break;
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
}
#endif
for (CC_id=0; CC_idnCCE=0;
DCI_pdu[CC_id]->num_pdcch_symbols=1;
mbsfn_status[CC_id]=0;
// clear vrb_map
memset(eNB_mac_inst[module_idP].common_channels[CC_id].vrb_map,0,100);
}
// refresh UE list based on UEs dropped by PHY in previous subframe
i = UE_list->head;
while (i>=0) {
int rnti, next_i;
rnti = UE_RNTI(module_idP, i);
CC_id = UE_PCCID(module_idP, i);
next_i= UE_list->next[i];
if (mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti)==NULL) {
/* TODO: try to sync this part with develop */
//mac_remove_ue(module_idP, i, frameP, subframeP);
printf("%s:%d: TODO: sync with develop\n", __FILE__, __LINE__);
abort();
}
i = next_i;
}
// clear DCI and BCCH contents before scheduling
for (CC_id=0; CC_idNum_common_dci = 0;
DCI_pdu[CC_id]->Num_ue_spec_dci = 0;
#ifdef Rel10
eNB_mac_inst[module_idP].common_channels[CC_id].mcch_active = 0;
#endif
eNB_mac_inst[module_idP].frame = frameP;
eNB_mac_inst[module_idP].subframe = subframeP;
}
/* run PDCP */
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, 0, module_idP);
pdcp_run(&ctxt);
// check HO
rrc_rx_tx(&ctxt,
0, // eNB index, unused in eNB
CC_id);
/* MBMS thing not done */
mbsfn_status[0]++; /* avoid gcc warning */
/* let's FAPI schedule! */
fapi = eNB_mac_inst[module_idP].fapi;
/*************************************************/
/* downlink scheduling */
/*************************************************/
/* check RA - is there one in generate_Msg4 mode with some CCCH data ready in the RRC Srb0? */
for (CC_id=0; CC_idcommon_channels[CC_id].RA_template[i].RA_active == TRUE &&
eNB->common_channels[CC_id].RA_template[i].generate_Msg4 == 1 &&
mac_rrc_get_ccch_size(module_idP, CC_id) > 0) {
struct SchedDlRlcBufferReqParameters rlc;
memset(&rlc, 0, sizeof(rlc));
rlc.rnti = eNB->common_channels[CC_id].RA_template[i].rnti;
rlc.logicalChannelIdentity = CCCH;
rlc.rlcTransmissionQueueSize = mac_rrc_get_ccch_size(module_idP, CC_id) + 1;
LOG_D(MAC, "calling SchedDlRlcBufferReq on CCCH rnti %x queue_size %d\n", rlc.rnti, rlc.rlcTransmissionQueueSize);
#if MEGALOG
printf("MAC to FAPI downlink BUF CCCH %d\n", rlc.rlcTransmissionQueueSize);
#endif
SchedDlRlcBufferReq(fapi->sched, &rlc);
/* let's report only once, so put generate_Msg4 to 2
* (we will generate later on, when FAPI tells us to do so)
*/
eNB->common_channels[CC_id].RA_template[i].generate_Msg4 = 2;
}
}
}
/* update RLC buffers status in the scheduler */
for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
struct SchedDlRlcBufferReqParameters rlc;
mac_rlc_status_resp_t rlc_status;
memset(&rlc, 0, sizeof(rlc));
rlc.rnti = UE_RNTI(module_idP, UE_id);
/* this code is wrong: we should loop over all configured RaB */
/* DCCH (srb 1, lcid 1) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, 0);
rlc.logicalChannelIdentity = DCCH;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
if (rlc.rlcTransmissionQueueSize == 2) rlc.rlcTransmissionQueueSize = 10;
LOG_D(MAC, "calling SchedDlRlcBufferReq on DCCH rnti %x queue_size %d\n", rlc.rnti, rlc_status.bytes_in_buffer);
SchedDlRlcBufferReq(fapi->sched, &rlc);
#if MEGALOG
printf("MAC to FAPI downlink BUF DCCH %d\n", rlc_status.bytes_in_buffer);
#endif
/* DCCH+1 (srb 2, lcid 2) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, 0);
rlc.logicalChannelIdentity = DCCH+1;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
LOG_D(MAC, "calling SchedDlRlcBufferReq on DCCH+1 rnti %x queue_size %d\n", rlc.rnti, rlc_status.bytes_in_buffer);
SchedDlRlcBufferReq(fapi->sched, &rlc);
#if MEGALOG
printf("MAC to FAPI downlink BUF DCCH+1 %d\n", rlc_status.bytes_in_buffer);
#endif
/* DTCH (drb 1, lcid 3) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DTCH, 0);
rlc.logicalChannelIdentity = DTCH;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
LOG_D(MAC, "calling SchedDlRlcBufferReq on DTCH rnti %x queue_size %d\n", rlc.rnti, rlc_status.bytes_in_buffer);
SchedDlRlcBufferReq(fapi->sched, &rlc);
#if MEGALOG
printf("MAC to FAPI downlink BUF DTCH %d\n", rlc_status.bytes_in_buffer);
#endif
}
dlreq.sfnSf = frameP * 16 + subframeP;
dlreq.nr_dlInfoList = 0;
dlreq.dlInfoList = NULL;
dlreq.nr_vendorSpecificList = 0;
dlreq.vendorSpecificList = NULL;
/* fill harq feedback data */
/* TODO: deal with more than one TB */
for (i = 0; i < fapi_dl_ack_nack_data.count; i++) {
dlinfo[i].rnti = fapi_dl_ack_nack_data.ack[i].rnti;
dlinfo[i].harqProcessId = fapi_dl_ack_nack_data.ack[i].harq_pid;
dlinfo[i].nr_harqStatus = 1; /* TODO: deal with more than 1 TB */
dlinfo[i].harqStatus[0] = fapi_dl_ack_nack_data.ack[i].ack[0] ? ff_ACK : ff_NACK; /* TODO: more than 1 TB */
dlinfo[i].servCellIndex = fapi_dl_ack_nack_data.ack[i].CC_id; /* TODO: get real value for the servCellIndex */
#if MEGALOG
printf("MAC to FAPI downlink ack/nack from PHY CC %d f/sf %d/%d rnti %x harq %d ack %d\n", dlinfo[i].servCellIndex, frameP, subframeP, dlinfo[i].rnti, dlinfo[i].harqProcessId, fapi_dl_ack_nack_data.ack[i].ack[0]);
#endif
}
if (fapi_dl_ack_nack_data.count) {
dlreq.nr_dlInfoList = fapi_dl_ack_nack_data.count;
dlreq.dlInfoList = dlinfo;
}
fapi_dl_ack_nack_data.count = 0;
LOG_D(MAC, "calling SchedDlTriggerReq\n");
SchedDlTriggerReq(fapi->sched, &dlreq);
LOG_D(MAC, "calling SchedDlConfigInd\n");
SchedDlConfigInd(fapi, &dlind);
LOG_D(MAC, "SchedDlConfigInd returns dlind.nr_buildDataList %d f/sf %d/%d\n", dlind.nr_buildDataList, frameP, subframeP);
LOG_D(MAC, "SchedDlConfigInd returns dlind.nr_buildRARList %d f/sf %d/%d\n", dlind.nr_buildRARList, frameP, subframeP);
LOG_D(MAC, "SchedDlConfigInd returns dlind.nr_buildBroadcastList %d f/sf %d/%d\n", dlind.nr_buildBroadcastList, frameP, subframeP);
/* TODO: rewrite. All should go into fapi_schedule_ue where special cases should be handled */
for (i = 0; i < dlind.nr_buildDataList; i++) {
if (dlind.buildDataList[i].ceBitmap[1] != 0 || dlind.buildDataList[i].nr_rlcPDU_List[1] != 0) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
#if MEGALOG
printf("FAPI to MAC downlink schedule ue %x channel %d f/sf %d/%d\n", dlind.buildDataList[i].rnti, dlind.buildDataList[i].rlcPduList[0][0].logicalChannelIdentity, frameP, subframeP);
#endif
switch (dlind.buildDataList[i].rlcPduList[0][0].logicalChannelIdentity) {
case 0: /* CCCH */
if (dlind.buildDataList[i].nr_rlcPDU_List[0] == 1) {
/* TODO: get the right CC_id from servCellIndex, depending on the UE rnti/pcell/scell settings */
CC_id = dlind.buildDataList[i].servCellIndex;
/* look for an active RA with generate_Msg4 == 2 for this rnti */
for (j=0; j < NB_RA_PROC_MAX; j++) {
if (eNB->common_channels[CC_id].RA_template[j].RA_active == TRUE &&
eNB->common_channels[CC_id].RA_template[j].generate_Msg4 == 2 &&
eNB->common_channels[CC_id].RA_template[j].rnti == dlind.buildDataList[i].rnti) {
if (dlind.buildDataList[i].ceBitmap[CC_id] != ff_CR) { printf("%s:%d:%s: TODO)\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
fapi_schedule_RA_Msg4(module_idP, CC_id, j, frameP, subframeP,
&dlind.buildDataList[i].dci, dlind.buildDataList[i].rlcPduList[0][0].size);
break;
}
}
if (j == NB_RA_PROC_MAX) { printf("%s:%d:%s: possible?\n", __FILE__, __LINE__, __FUNCTION__); /*abort();*/ }
}
else
printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__);
break;
case 1: /* DCCH (SRB1) */
case 2: /* DCCH+1 (SRB2) */
case 3: /* DTCH (DRB1) */
/* TODO: get the correct CC_id from servCellIndex */
fapi_schedule_ue(module_idP, dlind.buildDataList[i].servCellIndex /* CC_id */, frameP, subframeP, &dlind.buildDataList[i]);
break;
default: printf("%s:%d:%s: bad channel ID (%d)\n", __FILE__, __LINE__, __FUNCTION__, dlind.buildDataList[i].rlcPduList[0][0].logicalChannelIdentity); abort();
}
}
if (dlind.nr_buildRARList) {
if (dlind.nr_buildRARList != 1) { printf("%s:%d: more than 1 RAR, todo\n", __FUNCTION__, __LINE__); exit(0); }
if (dlind.buildRarList[0].carrierIndex != 0) { printf("%s:%d: 2nd CC: todo properly\n", __FUNCTION__, __LINE__); exit(0); }
#if MEGALOG
printf("FAPI to MAC downlink schedule RAR ue %x f/sf %d/%d\n", dlind.buildRarList[0].rnti, frameP, subframeP);
#endif
dlind.buildRarList[0].grant &= ~1;
fapi_schedule_RAR(module_idP, dlind.buildRarList[0].carrierIndex, frameP, subframeP,
dlind.buildRarList[0].rnti, dlind.buildRarList[0].grant, &dlind.buildRarList[0].dci);
}
for (i = 0; i < dlind.nr_buildBroadcastList; i++) {
if (dlind.buildBroadcastList[i].type == ff_PCCH) { printf("%s:%d: PCCH: todo\n", __FUNCTION__, __LINE__); exit(0); }
#if MEGALOG
printf("FAPI to MAC downlink schedule SI %d CC %d f/sf %d/%d\n", dlind.buildBroadcastList[i].index, dlind.buildBroadcastList[i].carrierIndex, frameP, subframeP);
#endif
fapi_schedule_SI(module_idP, dlind.buildBroadcastList[i].carrierIndex, frameP, subframeP,
dlind.buildBroadcastList[i].index,
&dlind.buildBroadcastList[i].dci);
}
/* TODO: do it correctly */
if (dlind.nr_ofdmSymbolsCount != 0) {
if (dlind.nr_ofdmSymbolsCount != MAX_NUM_CCs) { printf("%s:%d:%s: what to do?\n", __FILE__, __LINE__, __FUNCTION__); abort(); }
for (CC_id=0; CC_idcarrierIndex;
DCI_pdu[cc]->num_pdcch_symbols = dlind.nrOfPdcchOfdmSymbols[CC_id]->pdcchOfdmSymbolCount;
#if MEGALOG
printf("FAPI to MAC downlink DCI_pdu[%d]->num_pdcch_symbols %d f/sf %d/%d\n", cc, DCI_pdu[cc]->num_pdcch_symbols, frameP, subframeP);
#endif
}
}
}
#if 0
// Allocate CCEs for good after scheduling is done
for (CC_id=0;CC_idsched, &ulreq);
LOG_D(MAC, "calling SchedUlConfigInd\n");
SchedUlConfigInd(fapi, &ulind);
/* a hack to report nice CQI all the time it's asked */
for (i = 0; i < ulind.nr_dciList; i++) {
struct UlDciListElement_s *dci = &ulind.dciList[i];
if (dci->cqiRequest) {
int cqi_subband[13];
int k;
for (k = 0; k < 13; k++)
cqi_subband[k] = 14;
fapi_dl_cqi_report(0, dci->rnti, frameP + (subframeP > 6 ? 1 : 0), (subframeP + 4) % 10, 14, cqi_subband, 0);
}
}
#if MEGALOG
printf("FAPI to MAC uplink nr_dclList %d nr_phichList %d\n", ulind.nr_dciList, ulind.nr_phichList);
#endif
for (i = 0; i < ulind.nr_dciList; i++) {
/* TODO: get the right CC_id from servCellIndex, depending on the UE rnti/pcell/scell settings */
CC_id = ulind.dciList[i].servCellIndex;
#if MEGALOG
printf("FAPI to MAC uplink schedule ue %x ndi %d (fsf %d %d) rbstart %d rblen %d tbsize %d mcs %d\n", ulind.dciList[i].rnti, ulind.dciList[i].ndi, frameP, subframeP, ulind.dciList[i].rbStart, ulind.dciList[i].rbLen, ulind.dciList[i].tbSize, ulind.dciList[i].mcs);
#endif
fapi_schedule_uplink(module_idP, CC_id, &ulind.dciList[i]);
}
#if MEGALOG
int cc;
for (cc = 0; cc < 2; cc++) {
printf("RECAP dci pdu count %d cc %d\n", eNB_mac_inst[0].common_channels[cc].DCI_pdu.Num_common_dci, cc);
for (i = 0; i < eNB_mac_inst[0].common_channels[cc].DCI_pdu.Num_common_dci; i++) {
printf(" RECAP %i rnti %x %s dci pdu %s\n", i,
eNB_mac_inst[0].common_channels[cc].DCI_pdu.dci_alloc[i].rnti,
dci_format_to_string(eNB_mac_inst[0].common_channels[cc].DCI_pdu.dci_alloc[i].format),
binary(*(uint32_t *)eNB_mac_inst[0].common_channels[cc].DCI_pdu.dci_alloc[i].dci_pdu)
);
}
}
printf("RECAP phich count %d\n", ulind.nr_phichList);
for (i = 0; i < ulind.nr_phichList; i++) {
printf(" RECAP %i rnti %x %s\n", i,
ulind.phichList[i].rnti,
ulind.phichList[i].phich == ACK ? "ACK" : "NACK");
}
#endif
global_subframe++;
if (pthread_mutex_unlock(&fmut)) abort();
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT);
}
#else /* FAPI */
void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, frame_t frameP, sub_frame_t subframeP) //, int calibration_flag) {
{
int mbsfn_status[MAX_NUM_CCs];
protocol_ctxt_t ctxt;
#ifdef EXMIMO
//int ret;
#endif
#if defined(ENABLE_ITTI)
MessageDef *msg_p;
const char *msg_name;
instance_t instance;
int result;
#endif
DCI_PDU *DCI_pdu[MAX_NUM_CCs];
int CC_id,i,next_i;
UE_list_t *UE_list=&eNB_mac_inst[module_idP].UE_list;
rnti_t rnti;
void *DLSCH_dci=NULL;
int size_bits=0,size_bytes=0;
LOG_D(MAC,"[eNB %d] Frame %d, Subframe %d, entering MAC scheduler (UE_list->head %d)\n",module_idP, frameP, subframeP,UE_list->head);
start_meas(&eNB_mac_inst[module_idP].eNB_scheduler);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
for (CC_id=0; CC_idhead;
while (i>=0) {
rnti = UE_RNTI(module_idP, i);
CC_id = UE_PCCID(module_idP, i);
LOG_D(MAC,"UE %d: rnti %x (%p)\n", i, rnti,
mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti));
next_i= UE_list->next[i];
PHY_vars_eNB_g[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,PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_bsr[i][(frameP*10)+subframeP]);
// increment this, it is cleared when we receive an sdu
eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[i].ul_inactivity_timer++;
eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[i].cqi_req_timer++;
if (mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti)==NULL) {
// mac_remove_ue(module_idP, i, frameP, subframeP);
}
else {
// check uplink failure
if ((UE_list->UE_sched_ctrl[i].ul_failure_timer>0)&&
(UE_list->UE_sched_ctrl[i].ul_out_of_sync==0)) {
LOG_D(MAC,"UE %d rnti %x: UL Failure timer %d \n",i,rnti,UE_list->UE_sched_ctrl[i].ul_failure_timer);
if (UE_list->UE_sched_ctrl[i].ra_pdcch_order_sent==0) {
UE_list->UE_sched_ctrl[i].ra_pdcch_order_sent=1;
// add a format 1A dci for this UE to request an RA procedure (only one UE per subframe)
LOG_D(MAC,"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d) \n",i,rnti,UE_list->UE_sched_ctrl[i].ul_failure_timer);
DLSCH_dci = (void *)UE_list->UE_template[CC_id][i].DLSCH_DCI[0];
*(uint32_t*)DLSCH_dci = 0;
if (PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.frame_type == TDD) {
switch (PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.N_RB_DL) {
case 6:
((DCI1A_1_5MHz_TDD_1_6_t*)DLSCH_dci)->type = 1;
((DCI1A_1_5MHz_TDD_1_6_t*)DLSCH_dci)->rballoc = 31;
size_bytes = sizeof(DCI1A_1_5MHz_TDD_1_6_t);
size_bits = sizeof_DCI1A_1_5MHz_TDD_1_6_t;
break;
case 25:
((DCI1A_5MHz_TDD_1_6_t*)DLSCH_dci)->type = 1;
((DCI1A_5MHz_TDD_1_6_t*)DLSCH_dci)->rballoc = 511;
size_bytes = sizeof(DCI1A_5MHz_TDD_1_6_t);
size_bits = sizeof_DCI1A_5MHz_TDD_1_6_t;
break;
case 50:
((DCI1A_10MHz_TDD_1_6_t*)DLSCH_dci)->type = 1;
((DCI1A_10MHz_TDD_1_6_t*)DLSCH_dci)->rballoc = 2047;
size_bytes = sizeof(DCI1A_10MHz_TDD_1_6_t);
size_bits = sizeof_DCI1A_10MHz_TDD_1_6_t;
break;
case 100:
((DCI1A_20MHz_TDD_1_6_t*)DLSCH_dci)->type = 1;
((DCI1A_20MHz_TDD_1_6_t*)DLSCH_dci)->rballoc = 8191;
size_bytes = sizeof(DCI1A_20MHz_TDD_1_6_t);
size_bits = sizeof_DCI1A_20MHz_TDD_1_6_t;
break;
}
}
else { // FDD
switch (PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.N_RB_DL) {
case 6:
((DCI1A_1_5MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = 31;
size_bytes = sizeof(DCI1A_1_5MHz_FDD_t);
size_bits = sizeof_DCI1A_1_5MHz_FDD_t;
break;
case 15:/*
((DCI1A_2_5MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_2_5MHz_FDD_t*)DLSCH_dci)->rballoc = 31;
size_bytes = sizeof(DCI1A_1_5MHz_FDD_t);
size_bits = sizeof_DCI1A_1_5MHz_FDD_t;*/
break;
case 25:
((DCI1A_5MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_5MHz_FDD_t*)DLSCH_dci)->rballoc = 511;
size_bytes = sizeof(DCI1A_5MHz_FDD_t);
size_bits = sizeof_DCI1A_5MHz_FDD_t;
break;
case 50:
((DCI1A_10MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_10MHz_FDD_t*)DLSCH_dci)->rballoc = 2047;
size_bytes = sizeof(DCI1A_10MHz_FDD_t);
size_bits = sizeof_DCI1A_10MHz_FDD_t;
break;
case 75:
/* ((DCI1A_15MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_15MHz_FDD_t*)DLSCH_dci)->rballoc = 2047;
size_bytes = sizeof(DCI1A_10MHz_FDD_t);
size_bits = sizeof_DCI1A_10MHz_FDD_t;*/
break;
case 100:
((DCI1A_20MHz_FDD_t*)DLSCH_dci)->type = 1;
((DCI1A_20MHz_FDD_t*)DLSCH_dci)->rballoc = 8191;
size_bytes = sizeof(DCI1A_20MHz_FDD_t);
size_bits = sizeof_DCI1A_20MHz_FDD_t;
break;
}
}
add_ue_spec_dci(DCI_pdu[CC_id],
DLSCH_dci,
rnti,
size_bytes,
process_ue_cqi (module_idP,i),//aggregation,
size_bits,
format1A,
0);
}
else { // ra_pdcch_sent==1
LOG_D(MAC,"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",i,rnti,UE_list->UE_sched_ctrl[i].ul_failure_timer);
if ((UE_list->UE_sched_ctrl[i].ul_failure_timer % 40) == 0)
UE_list->UE_sched_ctrl[i].ra_pdcch_order_sent=0; // resend every 4 frames
}
UE_list->UE_sched_ctrl[i].ul_failure_timer++;
// check threshold
if (UE_list->UE_sched_ctrl[i].ul_failure_timer > 200) {
// inform RRC of failure and clear timer
LOG_I(MAC,"UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n",i,rnti,UE_list->UE_sched_ctrl[i].ul_failure_timer);
mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti);
UE_list->UE_sched_ctrl[i].ul_failure_timer=0;
UE_list->UE_sched_ctrl[i].ul_out_of_sync=1;
}
}
} // ul_failure_timer>0
i = next_i;
}
#if defined(ENABLE_ITTI)
do {
// Checks if a message has been sent to MAC sub-task
itti_poll_msg (TASK_MAC_ENB, &msg_p);
if (msg_p != NULL) {
msg_name = ITTI_MSG_NAME (msg_p);
instance = ITTI_MSG_INSTANCE (msg_p);
switch (ITTI_MSG_ID(msg_p)) {
case MESSAGE_TEST:
LOG_D(MAC, "Received %s\n", ITTI_MSG_NAME(msg_p));
break;
case RRC_MAC_BCCH_DATA_REQ:
LOG_D(MAC, "Received %s from %s: instance %d, frameP %d, eNB_index %d\n",
msg_name, ITTI_MSG_ORIGIN_NAME(msg_p), instance,
RRC_MAC_BCCH_DATA_REQ (msg_p).frame, RRC_MAC_BCCH_DATA_REQ (msg_p).enb_index);
// TODO process BCCH data req.
break;
case RRC_MAC_CCCH_DATA_REQ:
LOG_D(MAC, "Received %s from %s: instance %d, frameP %d, eNB_index %d\n",
msg_name, ITTI_MSG_ORIGIN_NAME(msg_p), instance,
RRC_MAC_CCCH_DATA_REQ (msg_p).frame, RRC_MAC_CCCH_DATA_REQ (msg_p).enb_index);
// TODO process CCCH data req.
break;
#ifdef Rel10
case RRC_MAC_MCCH_DATA_REQ:
LOG_D(MAC, "Received %s from %s: instance %d, frameP %d, eNB_index %d, mbsfn_sync_area %d\n",
msg_name, ITTI_MSG_ORIGIN_NAME(msg_p), instance,
RRC_MAC_MCCH_DATA_REQ (msg_p).frame, RRC_MAC_MCCH_DATA_REQ (msg_p).enb_index, RRC_MAC_MCCH_DATA_REQ (msg_p).mbsfn_sync_area);
// TODO process MCCH data req.
break;
#endif
default:
LOG_E(MAC, "Received unexpected message %s\n", msg_name);
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
}
} while(msg_p != NULL);
#endif
// clear DCI and BCCH contents before scheduling
for (CC_id=0; CC_idNum_common_dci = 0;
DCI_pdu[CC_id]->Num_ue_spec_dci = 0;
#ifdef Rel10
eNB_mac_inst[module_idP].common_channels[CC_id].mcch_active =0;
#endif
eNB_mac_inst[module_idP].frame = frameP;
eNB_mac_inst[module_idP].subframe = subframeP;
}
//if (subframeP%5 == 0)
//#ifdef EXMIMO
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, 0,module_idP);
pdcp_run(&ctxt);
//#endif
// check HO
rrc_rx_tx(&ctxt,
0, // eNB index, unused in eNB
CC_id);
#ifdef Rel10
for (CC_id=0; CC_id0) {
start_meas(&eNB_mac_inst[module_idP].schedule_mch);
mbsfn_status[CC_id] = schedule_MBMS(module_idP,CC_id,frameP,subframeP);
stop_meas(&eNB_mac_inst[module_idP].schedule_mch);
}
}
#endif
// refresh UE list based on UEs dropped by PHY in previous subframe
/*
i=UE_list->head;
while (i>=0) {
next_i = UE_list->next[i];
LOG_T(MAC,"UE %d : rnti %x, stats %p\n",i,UE_RNTI(module_idP,i),mac_xface->get_eNB_UE_stats(module_idP,0,UE_RNTI(module_idP,i)));
if (mac_xface->get_eNB_UE_stats(module_idP,0,UE_RNTI(module_idP,i))==NULL) {
mac_remove_ue(module_idP,i,frameP);
}
i=next_i;
}
*/
switch (subframeP) {
case 0:
// FDD/TDD Schedule Downlink RA transmissions (RA response, Msg4 Contention resolution)
// Schedule ULSCH for FDD or subframeP 4 (TDD config 0,3,6)
// Schedule Normal DLSCH
schedule_RA(module_idP,frameP,subframeP,2);
if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,0,4);//,calibration_flag);
} else if ((mac_xface->lte_frame_parms->tdd_config == TDD) || //TDD
(mac_xface->lte_frame_parms->tdd_config == 3) ||
(mac_xface->lte_frame_parms->tdd_config == 6)) {
//schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag);
}
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 1:
// TDD, schedule UL for subframeP 7 (TDD config 0,1) / subframeP 8 (TDD Config 6)
// FDD, schedule normal UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == TDD) { // TDD
switch (mac_xface->lte_frame_parms->tdd_config) {
case 0:
case 1:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 6:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,1,5);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 2:
// TDD, nothing
// FDD, normal UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,2,6);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 3:
// TDD Config 2, ULSCH for subframeP 7
// TDD Config 2/5 normal DLSCH
// FDD, normal UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == TDD) {
switch (mac_xface->lte_frame_parms->tdd_config) {
case 2:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7);
// no break here!
case 5:
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,3,7);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 4:
// TDD Config 1, ULSCH for subframeP 8
// TDD Config 1/2/4/5 DLSCH
// FDD UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == 1) { // TDD
switch (mac_xface->lte_frame_parms->tdd_config) {
case 1:
// schedule_RA(module_idP,frameP,subframeP);
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8);
// no break here!
case 2:
// no break here!
case 4:
// no break here!
case 5:
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else {
if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD
schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8);
schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status);
fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status);
}
}
break;
case 5:
// TDD/FDD Schedule SI
// TDD Config 0,6 ULSCH for subframes 9,3 resp.
// TDD normal DLSCH
// FDD normal UL/DLSCH
schedule_SI(module_idP,frameP,subframeP);
//schedule_RA(module_idP,frameP,subframeP,5);
if (mac_xface->lte_frame_parms->frame_type == FDD) {
schedule_RA(module_idP,frameP,subframeP,1);
schedule_ulsch(module_idP,frameP,cooperation_flag,5,9);
schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
} else if ((mac_xface->lte_frame_parms->tdd_config == 0) || // TDD Config 0
(mac_xface->lte_frame_parms->tdd_config == 6)) { // TDD Config 6
//schedule_ulsch(module_idP,cooperation_flag,subframeP);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
} else {
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 6:
// TDD Config 0,1,6 ULSCH for subframes 2,3
// TDD Config 3,4,5 Normal DLSCH
// FDD normal ULSCH/DLSCH
if (mac_xface->lte_frame_parms->frame_type == TDD) { // TDD
switch (mac_xface->lte_frame_parms->tdd_config) {
case 0:
break;
case 1:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2);
// schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 6:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3);
// schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 5:
schedule_RA(module_idP,frameP,subframeP,2);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 3:
case 4:
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,6,0);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 7:
// TDD Config 3,4,5 Normal DLSCH
// FDD Normal UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == TDD) { // TDD
switch (mac_xface->lte_frame_parms->tdd_config) {
case 3:
case 4:
schedule_RA(module_idP,frameP,subframeP,3); // 3 = Msg3 subframeP, not
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 5:
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,7,1);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 8:
// TDD Config 2,3,4,5 ULSCH for subframeP 2
//
// FDD Normal UL/DLSCH
if (mac_xface->lte_frame_parms->frame_type == TDD) { // TDD
switch (mac_xface->lte_frame_parms->tdd_config) {
case 2:
case 3:
case 4:
case 5:
// schedule_RA(module_idP,subframeP);
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,8,2);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
case 9:
// TDD Config 1,3,4,6 ULSCH for subframes 3,3,3,4
if (mac_xface->lte_frame_parms->frame_type == TDD) {
switch (mac_xface->lte_frame_parms->tdd_config) {
case 1:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3);
schedule_RA(module_idP,frameP,subframeP,7); // 7 = Msg3 subframeP, not
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 3:
case 4:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 6:
schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);
//schedule_RA(module_idP,frameP,subframeP);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
case 2:
case 5:
//schedule_RA(module_idP,frameP,subframeP);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
break;
default:
break;
}
} else { //FDD
schedule_ulsch(module_idP,frameP,cooperation_flag,9,3);
schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status);
fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status);
}
break;
}
LOG_D(MAC,"FrameP %d, subframeP %d : Scheduling CCEs\n",frameP,subframeP);
// Allocate CCEs for good after scheduling is done
for (CC_id=0;CC_idNum_common_dci+DCI_pdu[CC_id]->Num_ue_spec_dci;
i++)
if (DCI_pdu[CC_id]->dci_alloc[i].rnti==2)
dummy=1;
if (dummy==1)
for (i=0;
iNum_common_dci+DCI_pdu[CC_id]->Num_ue_spec_dci;
i++)
LOG_I(MAC,"Frame %d, subframe %d: DCI %d/%d, format %d, rnti %x, NCCE %d(num_pdcch_symb %d)\n",
frameP,subframeP,i,DCI_pdu[CC_id]->Num_common_dci+DCI_pdu[CC_id]->Num_ue_spec_dci,
DCI_pdu[CC_id]->dci_alloc[i].format,
DCI_pdu[CC_id]->dci_alloc[i].rnti,
DCI_pdu[CC_id]->dci_alloc[i].firstCCE,
DCI_pdu[CC_id]->num_pdcch_symbols);
LOG_D(MAC,"frameP %d, subframeP %d\n",frameP,subframeP);
*/
stop_meas(&eNB_mac_inst[module_idP].eNB_scheduler);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT);
}
#endif /* FAPI */