- import RRC ASN.1 defintions from the specifications (file openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e10.asn) contrary to rel8/10, all modules have been imported, maybe it's too much to refine in case of problems - deal with rel14 in fix_asn1 - all code that was for Rel10 is now for Rel10/Rel14 - some incompatible changes (mostly in naming) were resolved in favor of rel14, see in openair2/RRC/LITE/defs.h - unsure about the rlc layer, some arrays have changed (values appended), I only changed the definition and in tests in the code, I changed the index limit, maybe it's not enough Rel14 is the default compilation mode.
1204 lines
34 KiB
C
1204 lines
34 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.0 (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_primitives.c
|
|
* \brief primitives used by eNB for BCH, RACH, ULSCH, DLSCH scheduling
|
|
* \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/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
|
|
|
|
#define ENABLE_MAC_PAYLOAD_DEBUG
|
|
#define DEBUG_eNB_SCHEDULER 1
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void init_ue_sched_info(void)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
module_id_t i,j,k;
|
|
|
|
for (i=0; i<NUMBER_OF_eNB_MAX; i++) {
|
|
for (k=0; k<MAX_NUM_CCs; k++) {
|
|
for (j=0; j<NUMBER_OF_UE_MAX; j++) {
|
|
// init DL
|
|
eNB_dlsch_info[i][k][j].weight = 0;
|
|
eNB_dlsch_info[i][k][j].subframe = 0;
|
|
eNB_dlsch_info[i][k][j].serving_num = 0;
|
|
eNB_dlsch_info[i][k][j].status = S_DL_NONE;
|
|
// init UL
|
|
eNB_ulsch_info[i][k][j].subframe = 0;
|
|
eNB_ulsch_info[i][k][j].serving_num = 0;
|
|
eNB_ulsch_info[i][k][j].status = S_UL_NONE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
unsigned char get_ue_weight(module_id_t module_idP, int CC_id, int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
|
|
return(eNB_dlsch_info[module_idP][CC_id][ue_idP].weight);
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
DCI_PDU *get_dci_sdu(module_id_t module_idP, int CC_id,frame_t frameP, sub_frame_t subframeP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
|
|
return(&eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu);
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int find_UE_id(module_id_t mod_idP, rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int UE_id;
|
|
UE_list_t *UE_list = &eNB_mac_inst[mod_idP].UE_list;
|
|
|
|
for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) {
|
|
if (UE_list->active[UE_id] != TRUE) continue;
|
|
if (UE_list->UE_template[UE_PCCID(mod_idP,UE_id)][UE_id].rnti==rntiP) {
|
|
return(UE_id);
|
|
}
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int UE_num_active_CC(UE_list_t *listP,int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return(listP->numactiveCCs[ue_idP]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int UE_PCCID(module_id_t mod_idP,int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return(eNB_mac_inst[mod_idP].UE_list.pCC_id[ue_idP]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
|
|
rnti_t rnti = eNB_mac_inst[mod_idP].UE_list.UE_template[UE_PCCID(mod_idP,ue_idP)][ue_idP].rnti;
|
|
|
|
if (rnti>0) {
|
|
return (rnti);
|
|
}
|
|
|
|
LOG_D(MAC,"[eNB %d] Couldn't find RNTI for UE %d\n",mod_idP,ue_idP);
|
|
//display_backtrace();
|
|
return(NOT_A_RNTI);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
boolean_t is_UE_active(module_id_t mod_idP, int ue_idP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
return(eNB_mac_inst[mod_idP].UE_list.active[ue_idP]);
|
|
}
|
|
|
|
/*
|
|
uint8_t find_active_UEs(module_id_t module_idP,int CC_id){
|
|
|
|
module_id_t ue_mod_id = 0;
|
|
rnti_t rnti = 0;
|
|
uint8_t nb_active_ue = 0;
|
|
|
|
for (ue_mod_id=0;ue_mod_id<NUMBER_OF_UE_MAX;ue_mod_id++) {
|
|
|
|
if (((rnti=eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].rnti) !=0)&&(eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].ul_active==TRUE)){
|
|
|
|
if (mac_xface->get_eNB_UE_stats(module_idP,rnti) != NULL){ // check at the phy enb_ue state for this rnti
|
|
nb_active_ue++;
|
|
}
|
|
else { // this ue is removed at the phy => remove it at the mac as well
|
|
mac_remove_ue(module_idP, CC_id, ue_mod_id);
|
|
}
|
|
}
|
|
}
|
|
return(nb_active_ue);
|
|
}
|
|
*/
|
|
|
|
|
|
// get aggregation (L) form phy for a give UE
|
|
unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt)
|
|
{
|
|
unsigned char aggregation=3;
|
|
|
|
switch (dci_fmt){
|
|
|
|
case format0:
|
|
aggregation = cqi2fmt0_agg[bw_index][cqi];
|
|
break;
|
|
case format1:
|
|
case format1A:
|
|
case format1B:
|
|
case format1D:
|
|
aggregation = cqi2fmt1x_agg[bw_index][cqi];
|
|
break;
|
|
case format2:
|
|
case format2A:
|
|
case format2B:
|
|
case format2C:
|
|
case format2D:
|
|
aggregation = cqi2fmt2x_agg[bw_index][cqi];
|
|
break;
|
|
case format1C:
|
|
case format1E_2A_M10PRB:
|
|
case format3:
|
|
case format3A:
|
|
case format4:
|
|
default:
|
|
LOG_W(MAC,"unsupported DCI format %d\n",dci_fmt);
|
|
}
|
|
|
|
LOG_D(MAC,"Aggregation level %d (cqi %d, bw_index %d, format %d)\n",
|
|
1<<aggregation, cqi,bw_index,dci_fmt);
|
|
|
|
return aggregation;
|
|
}
|
|
#ifdef CBA
|
|
/*
|
|
uint8_t find_num_active_UEs_in_cbagroup(module_id_t module_idP, int CC_id,unsigned char group_id){
|
|
|
|
module_id_t UE_id;
|
|
rnti_t rnti;
|
|
unsigned char nb_ue_in_pusch=0;
|
|
LTE_eNB_UE_stats* eNB_UE_stats;
|
|
|
|
for (UE_id=group_id;UE_id<NUMBER_OF_UE_MAX;UE_id+=eNB_mac_inst[module_idP].common_channels[CC_id].num_active_cba_groups) {
|
|
|
|
if (((rnti=eNB_mac_inst[module_idP][CC_id].UE_template[UE_id].rnti) !=0) &&
|
|
(eNB_mac_inst[module_idP][CC_id].UE_template[UE_id].ul_active==TRUE) &&
|
|
(mac_get_rrc_status(module_idP,1,UE_id) > RRC_CONNECTED)){
|
|
// && (UE_is_to_be_scheduled(module_idP,UE_id)))
|
|
// check at the phy enb_ue state for this rnti
|
|
if ((eNB_UE_stats= mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti)) != NULL){
|
|
if ((eNB_UE_stats->mode == PUSCH) && (UE_is_to_be_scheduled(module_idP,UE_id) == 0)){
|
|
nb_ue_in_pusch++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(nb_ue_in_pusch);
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
void dump_ue_list(UE_list_t *listP, int ul_flag)
|
|
{
|
|
int j;
|
|
|
|
if ( ul_flag == 0 ) {
|
|
for (j=listP->head; j>=0; j=listP->next[j]) {
|
|
LOG_T(MAC,"node %d => %d\n",j,listP->next[j]);
|
|
}
|
|
} else {
|
|
for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) {
|
|
LOG_T(MAC,"node %d => %d\n",j,listP->next_ul[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP)
|
|
{
|
|
int UE_id;
|
|
int i, j;
|
|
|
|
UE_list_t *UE_list = &eNB_mac_inst[mod_idP].UE_list;
|
|
|
|
LOG_D(MAC,"[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",mod_idP,cc_idP,rntiP,UE_list->avail,UE_list->num_UEs);
|
|
dump_ue_list(UE_list,0);
|
|
|
|
for (i = 0; i < NUMBER_OF_UE_MAX; i++) {
|
|
if (UE_list->active[i] == TRUE) continue;
|
|
printf("MAC: new UE id %d rnti %x\n", i, rntiP);
|
|
UE_id = i;
|
|
UE_list->UE_template[cc_idP][UE_id].rnti = rntiP;
|
|
UE_list->UE_template[cc_idP][UE_id].configured = FALSE;
|
|
UE_list->numactiveCCs[UE_id] = 1;
|
|
UE_list->numactiveULCCs[UE_id] = 1;
|
|
UE_list->pCC_id[UE_id] = cc_idP;
|
|
UE_list->ordered_CCids[0][UE_id] = cc_idP;
|
|
UE_list->ordered_ULCCids[0][UE_id] = cc_idP;
|
|
UE_list->num_UEs++;
|
|
UE_list->active[UE_id] = TRUE;
|
|
memset((void*)&UE_list->UE_sched_ctrl[UE_id],0,sizeof(UE_sched_ctrl));
|
|
|
|
for (j=0; j<8; j++) {
|
|
UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j==0)?1:0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0
|
|
UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j==harq_pidP)?0:1; // 1st transmission is with Msg3;
|
|
}
|
|
|
|
eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING;
|
|
eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING;
|
|
LOG_D(MAC,"[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n",mod_idP,UE_id,cc_idP,rntiP);
|
|
dump_ue_list(UE_list,0);
|
|
return(UE_id);
|
|
}
|
|
|
|
printf("MAC: cannot add new UE for rnti %x\n", rntiP);
|
|
LOG_E(MAC,"error in add_new_ue(), could not find space in UE_list, Dumping UE list\n");
|
|
dump_ue_list(UE_list,0);
|
|
return(-1);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP)
|
|
//------------------------------------------------------------------------------
|
|
{
|
|
int i;
|
|
UE_list_t *UE_list = &eNB_mac_inst[mod_idP].UE_list;
|
|
int UE_id = find_UE_id(mod_idP,rntiP);
|
|
int pCC_id;
|
|
|
|
if (UE_id == -1) {
|
|
printf("MAC: cannot remove UE rnti %x\n", rntiP);
|
|
LOG_W(MAC,"rrc_mac_remove_ue: UE %x not found\n", rntiP);
|
|
mac_phy_remove_ue(mod_idP, rntiP);
|
|
return 0;
|
|
}
|
|
|
|
pCC_id = UE_PCCID(mod_idP,UE_id);
|
|
|
|
printf("MAC: remove UE %d rnti %x\n", UE_id, rntiP);
|
|
LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",UE_id,pCC_id, rntiP);
|
|
dump_ue_list(UE_list,0);
|
|
|
|
UE_list->active[UE_id] = FALSE;
|
|
UE_list->num_UEs--;
|
|
|
|
// clear all remaining pending transmissions
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0;
|
|
|
|
UE_list->UE_template[pCC_id][UE_id].ul_SR = 0;
|
|
UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE;
|
|
eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE;
|
|
eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI;
|
|
eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE;
|
|
|
|
mac_phy_remove_ue(mod_idP,rntiP);
|
|
|
|
// check if this has an RA process active
|
|
RA_TEMPLATE *RA_template;
|
|
for (i=0;i<NB_RA_PROC_MAX;i++) {
|
|
RA_template = (RA_TEMPLATE *)&eNB_mac_inst[mod_idP].common_channels[pCC_id].RA_template[i];
|
|
if (RA_template->rnti == rntiP){
|
|
RA_template->RA_active=FALSE;
|
|
RA_template->generate_rar=0;
|
|
RA_template->generate_Msg4=0;
|
|
RA_template->wait_ack_Msg4=0;
|
|
RA_template->timing_offset=0;
|
|
RA_template->RRC_timer=20;
|
|
RA_template->rnti = 0;
|
|
//break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int prev(UE_list_t *listP, int nodeP, int ul_flag)
|
|
{
|
|
int j;
|
|
|
|
if (ul_flag == 0 ) {
|
|
if (nodeP==listP->head) {
|
|
return(nodeP);
|
|
}
|
|
|
|
for (j=listP->head; j>=0; j=listP->next[j]) {
|
|
if (listP->next[j]==nodeP) {
|
|
return(j);
|
|
}
|
|
}
|
|
} else {
|
|
if (nodeP==listP->head_ul) {
|
|
return(nodeP);
|
|
}
|
|
|
|
for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) {
|
|
if (listP->next_ul[j]==nodeP) {
|
|
return(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_E(MAC,"error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n",
|
|
nodeP, (ul_flag == 0)? "DL" : "UL");
|
|
dump_ue_list(listP, ul_flag);
|
|
|
|
|
|
return(-1);
|
|
}
|
|
|
|
void swap_UEs(UE_list_t *listP,int nodeiP, int nodejP, int ul_flag)
|
|
{
|
|
|
|
int prev_i,prev_j,next_i,next_j;
|
|
|
|
LOG_T(MAC,"Swapping UE %d,%d\n",nodeiP,nodejP);
|
|
dump_ue_list(listP,ul_flag);
|
|
|
|
prev_i = prev(listP,nodeiP,ul_flag);
|
|
prev_j = prev(listP,nodejP,ul_flag);
|
|
|
|
if ((prev_i<0) || (prev_j<0)) {
|
|
mac_xface->macphy_exit("swap_UEs: problem");
|
|
return; // not reached
|
|
}
|
|
|
|
if (ul_flag == 0) {
|
|
next_i = listP->next[nodeiP];
|
|
next_j = listP->next[nodejP];
|
|
} else {
|
|
next_i = listP->next_ul[nodeiP];
|
|
next_j = listP->next_ul[nodejP];
|
|
}
|
|
|
|
LOG_T(MAC,"[%s] next_i %d, next_i, next_j %d, head %d \n",
|
|
(ul_flag == 0)? "DL" : "UL",
|
|
next_i,next_j,listP->head);
|
|
|
|
if (ul_flag == 0 ) {
|
|
|
|
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
|
|
LOG_T(MAC,"Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
|
|
|
|
listP->next[nodeiP] = next_j;
|
|
listP->next[nodejP] = nodeiP;
|
|
|
|
if (nodeiP==listP->head) { // case i j n(j)
|
|
listP->head = nodejP;
|
|
} else {
|
|
listP->next[prev_i] = nodejP;
|
|
}
|
|
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
|
|
LOG_T(MAC,"Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
|
|
listP->next[nodejP] = next_i;
|
|
listP->next[nodeiP] = nodejP;
|
|
|
|
if (nodejP==listP->head) { // case j i n(i)
|
|
listP->head = nodeiP;
|
|
} else {
|
|
listP->next[prev_j] = nodeiP;
|
|
}
|
|
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
|
|
listP->next[nodejP] = next_i;
|
|
listP->next[nodeiP] = next_j;
|
|
|
|
|
|
if (nodeiP==listP->head) {
|
|
LOG_T(MAC,"changing head to %d\n",nodejP);
|
|
listP->head=nodejP;
|
|
listP->next[prev_j] = nodeiP;
|
|
} else if (nodejP==listP->head) {
|
|
LOG_D(MAC,"changing head to %d\n",nodeiP);
|
|
listP->head=nodeiP;
|
|
listP->next[prev_i] = nodejP;
|
|
} else {
|
|
listP->next[prev_i] = nodejP;
|
|
listP->next[prev_j] = nodeiP;
|
|
}
|
|
}
|
|
} else { // ul_flag
|
|
|
|
if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...
|
|
LOG_T(MAC,"[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n");
|
|
|
|
listP->next_ul[nodeiP] = next_j;
|
|
listP->next_ul[nodejP] = nodeiP;
|
|
|
|
if (nodeiP==listP->head_ul) { // case i j n(j)
|
|
listP->head_ul = nodejP;
|
|
} else {
|
|
listP->next_ul[prev_i] = nodejP;
|
|
}
|
|
} else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...
|
|
LOG_T(MAC,"[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n");
|
|
listP->next_ul[nodejP] = next_i;
|
|
listP->next_ul[nodeiP] = nodejP;
|
|
|
|
if (nodejP==listP->head_ul) { // case j i n(i)
|
|
listP->head_ul = nodeiP;
|
|
} else {
|
|
listP->next_ul[prev_j] = nodeiP;
|
|
}
|
|
} else { // case ... p(i) i n(i) ... p(j) j n(j) ...
|
|
|
|
listP->next_ul[nodejP] = next_i;
|
|
listP->next_ul[nodeiP] = next_j;
|
|
|
|
|
|
if (nodeiP==listP->head_ul) {
|
|
LOG_T(MAC,"[UL]changing head to %d\n",nodejP);
|
|
listP->head_ul=nodejP;
|
|
listP->next_ul[prev_j] = nodeiP;
|
|
} else if (nodejP==listP->head_ul) {
|
|
LOG_T(MAC,"[UL]changing head to %d\n",nodeiP);
|
|
listP->head_ul=nodeiP;
|
|
listP->next_ul[prev_i] = nodejP;
|
|
} else {
|
|
listP->next_ul[prev_i] = nodejP;
|
|
listP->next_ul[prev_j] = nodeiP;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_T(MAC,"After swap\n");
|
|
dump_ue_list(listP,ul_flag);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
#if defined(Rel10) || defined(Rel14)
|
|
unsigned char generate_mch_header( unsigned char *mac_header,
|
|
unsigned char num_sdus,
|
|
unsigned short *sdu_lengths,
|
|
unsigned char *sdu_lcids,
|
|
unsigned char msi,
|
|
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[2*num_sdus],*ce_ptr;
|
|
|
|
ce_ptr = &mac_header_control_elements[0];
|
|
|
|
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;
|
|
}
|
|
|
|
// SUBHEADER for MSI CE
|
|
if (msi != 0) {// there is MSI MAC Control Element
|
|
if (first_element>0) {
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr+=last_size;
|
|
}
|
|
else {
|
|
first_element = 1;
|
|
}
|
|
if (num_sdus*2 < 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 = MCH_SCHDL_INFO;
|
|
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = num_sdus*2;
|
|
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 = MCH_SCHDL_INFO;
|
|
((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (num_sdus*2)&0x7fff;
|
|
last_size=3;
|
|
}
|
|
// Create the MSI MAC Control Element here
|
|
}
|
|
|
|
// SUBHEADER for MAC SDU (MCCH+MTCHs)
|
|
for (i=0;i<num_sdus;i++) {
|
|
if (first_element>0) {
|
|
mac_header_ptr->E = 1;
|
|
mac_header_ptr+=last_size;
|
|
}
|
|
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 = (unsigned short) sdu_lengths[i]&0x7fff;
|
|
last_size=3;
|
|
}
|
|
}
|
|
|
|
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++;
|
|
}
|
|
|
|
// Copy MSI Control Element to the end of the MAC Header if it presents
|
|
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);
|
|
}
|
|
|
|
return((unsigned char*)mac_header_ptr - mac_header);
|
|
}
|
|
#endif
|
|
*/
|
|
void add_common_dci(DCI_PDU *DCI_pdu,
|
|
void *pdu,
|
|
rnti_t rnti,
|
|
unsigned char dci_size_bytes,
|
|
unsigned char aggregation,
|
|
unsigned char dci_size_bits,
|
|
unsigned char dci_fmt,
|
|
uint8_t ra_flag)
|
|
{
|
|
|
|
memcpy(&DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].dci_pdu[0],pdu,dci_size_bytes);
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].dci_length = dci_size_bits;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].L = aggregation;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].rnti = rnti;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].format = dci_fmt;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci].ra_flag = ra_flag;
|
|
|
|
|
|
DCI_pdu->Num_common_dci++;
|
|
LOG_D(MAC,"add common dci format %d for rnti %x \n",dci_fmt,rnti);
|
|
}
|
|
|
|
void add_ue_spec_dci(DCI_PDU *DCI_pdu,void *pdu,rnti_t rnti,unsigned char dci_size_bytes,unsigned char aggregation,unsigned char dci_size_bits,unsigned char dci_fmt,uint8_t ra_flag)
|
|
{
|
|
|
|
memcpy(&DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].dci_pdu[0],pdu,dci_size_bytes);
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].dci_length = dci_size_bits;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].L = aggregation;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].rnti = rnti;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].format = dci_fmt;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci].ra_flag = ra_flag;
|
|
|
|
DCI_pdu->Num_ue_spec_dci++;
|
|
|
|
LOG_D(MAC,"add ue specific dci format %d for rnti %x \n",dci_fmt,rnti);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This has to be updated to include BSR information
|
|
uint8_t UE_is_to_be_scheduled(module_id_t module_idP,int CC_id,uint8_t UE_id)
|
|
{
|
|
|
|
UE_TEMPLATE *UE_template = &eNB_mac_inst[module_idP].UE_list.UE_template[CC_id][UE_id];
|
|
UE_sched_ctrl *UE_sched_ctl = &eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[UE_id];
|
|
|
|
|
|
// do not schedule UE if UL is not working
|
|
if (UE_sched_ctl->ul_failure_timer>0)
|
|
return(0);
|
|
if (UE_sched_ctl->ul_out_of_sync>0)
|
|
return(0);
|
|
|
|
LOG_D(MAC,"[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id));
|
|
|
|
if ((UE_template->bsr_info[LCGID0]>0) ||
|
|
(UE_template->bsr_info[LCGID1]>0) ||
|
|
(UE_template->bsr_info[LCGID2]>0) ||
|
|
(UE_template->bsr_info[LCGID3]>0) ||
|
|
(UE_template->ul_SR>0) || // uplink scheduling request
|
|
((UE_sched_ctl->ul_inactivity_timer>20)&&
|
|
(UE_sched_ctl->ul_scheduled==0))|| // every 2 frames when RRC_CONNECTED
|
|
((UE_sched_ctl->ul_inactivity_timer>10)&&
|
|
(UE_sched_ctl->ul_scheduled==0)&&
|
|
(mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED
|
|
{
|
|
|
|
LOG_D(MAC,"[eNB %d][PUSCH] UE %d/%x should be scheduled\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id));
|
|
return(1);
|
|
} else {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t allocate_prbs(int UE_id,unsigned char nb_rb, uint32_t *rballoc)
|
|
{
|
|
|
|
int i;
|
|
uint32_t rballoc_dci=0;
|
|
unsigned char nb_rb_alloc=0;
|
|
|
|
for (i=0; i<(mac_xface->frame_parms->N_RB_DL-2); i+=2) {
|
|
if (((*rballoc>>i)&3)==0) {
|
|
*rballoc |= (3<<i);
|
|
rballoc_dci |= (1<<((12-i)>>1));
|
|
nb_rb_alloc+=2;
|
|
}
|
|
|
|
if (nb_rb_alloc==nb_rb) {
|
|
return(rballoc_dci);
|
|
}
|
|
}
|
|
|
|
if ((mac_xface->frame_parms->N_RB_DL&1)==1) {
|
|
if ((*rballoc>>(mac_xface->frame_parms->N_RB_DL-1)&1)==0) {
|
|
*rballoc |= (1<<(mac_xface->frame_parms->N_RB_DL-1));
|
|
rballoc_dci |= 1;//(1<<(mac_xface->frame_parms->N_RB_DL>>1));
|
|
}
|
|
}
|
|
|
|
return(rballoc_dci);
|
|
}
|
|
|
|
int get_bw_index(module_id_t module_id, uint8_t CC_id)
|
|
{
|
|
|
|
int bw_index=0;
|
|
LTE_DL_FRAME_PARMS* frame_parms = mac_xface->get_lte_frame_parms(module_id,CC_id);
|
|
|
|
switch (frame_parms->N_RB_DL) {
|
|
case 6: // 1.4 MHz
|
|
bw_index=0;
|
|
break;
|
|
|
|
case 25: // 5HMz
|
|
bw_index=1;
|
|
break;
|
|
|
|
case 50: // 10HMz
|
|
bw_index=2;
|
|
break;
|
|
|
|
case 100: // 20HMz
|
|
bw_index=3;
|
|
break;
|
|
|
|
default:
|
|
bw_index=1;
|
|
LOG_W(MAC,"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting bw_index to 1\n", module_id, frame_parms->N_RB_DL, CC_id);
|
|
break;
|
|
}
|
|
|
|
return bw_index;
|
|
}
|
|
|
|
int get_min_rb_unit(module_id_t module_id, uint8_t CC_id)
|
|
{
|
|
|
|
int min_rb_unit=0;
|
|
LTE_DL_FRAME_PARMS* frame_parms = mac_xface->get_lte_frame_parms(module_id,CC_id);
|
|
|
|
switch (frame_parms->N_RB_DL) {
|
|
case 6: // 1.4 MHz
|
|
min_rb_unit=1;
|
|
break;
|
|
|
|
case 25: // 5HMz
|
|
min_rb_unit=2;
|
|
break;
|
|
|
|
case 50: // 10HMz
|
|
min_rb_unit=3;
|
|
break;
|
|
|
|
case 100: // 20HMz
|
|
min_rb_unit=4;
|
|
break;
|
|
|
|
default:
|
|
min_rb_unit=2;
|
|
LOG_W(MAC,"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n",
|
|
module_id, frame_parms->N_RB_DL, CC_id);
|
|
break;
|
|
}
|
|
|
|
return min_rb_unit;
|
|
}
|
|
|
|
uint32_t allocate_prbs_sub(int nb_rb, uint8_t *rballoc)
|
|
{
|
|
|
|
int check=0;//check1=0,check2=0;
|
|
uint32_t rballoc_dci=0;
|
|
//uint8_t number_of_subbands=13;
|
|
|
|
LOG_T(MAC,"*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n",
|
|
rballoc[3],rballoc[2],rballoc[1],rballoc[0],nb_rb,mac_xface->frame_parms->N_RBG);
|
|
|
|
while((nb_rb >0) && (check < mac_xface->frame_parms->N_RBG)) {
|
|
//printf("rballoc[%d] %d\n",check,rballoc[check]);
|
|
if(rballoc[check] == 1) {
|
|
rballoc_dci |= (1<<((mac_xface->frame_parms->N_RBG-1)-check));
|
|
|
|
switch (mac_xface->frame_parms->N_RB_DL) {
|
|
case 6:
|
|
nb_rb--;
|
|
break;
|
|
|
|
case 25:
|
|
if ((check == mac_xface->frame_parms->N_RBG-1)) {
|
|
nb_rb--;
|
|
} else {
|
|
nb_rb-=2;
|
|
}
|
|
|
|
break;
|
|
|
|
case 50:
|
|
if ((check == mac_xface->frame_parms->N_RBG-1)) {
|
|
nb_rb-=2;
|
|
} else {
|
|
nb_rb-=3;
|
|
}
|
|
|
|
break;
|
|
|
|
case 100:
|
|
nb_rb-=4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// printf("rb_alloc %x\n",rballoc_dci);
|
|
check = check+1;
|
|
// check1 = check1+2;
|
|
}
|
|
|
|
// rballoc_dci = (rballoc_dci)&(0x1fff);
|
|
LOG_T(MAC,"*********RBALLOC : %x\n",rballoc_dci);
|
|
// exit(-1);
|
|
return (rballoc_dci);
|
|
}
|
|
|
|
|
|
int get_nb_subband(void)
|
|
{
|
|
|
|
int nb_sb=0;
|
|
|
|
switch (mac_xface->frame_parms->N_RB_DL) {
|
|
case 6:
|
|
nb_sb=0;
|
|
break;
|
|
|
|
case 15:
|
|
nb_sb = 4; // sb_size =4
|
|
|
|
case 25:
|
|
nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs
|
|
break;
|
|
|
|
case 50: // sb_size =6
|
|
nb_sb = 9;
|
|
break;
|
|
|
|
case 75: // sb_size =8
|
|
nb_sb = 10;
|
|
break;
|
|
|
|
case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs
|
|
nb_sb = 13;
|
|
break;
|
|
|
|
default:
|
|
nb_sb=0;
|
|
break;
|
|
}
|
|
|
|
return nb_sb;
|
|
|
|
}
|
|
|
|
void init_CCE_table(int module_idP,int CC_idP)
|
|
{
|
|
memset(eNB_mac_inst[module_idP].CCE_table[CC_idP],0,800*sizeof(int));
|
|
}
|
|
|
|
|
|
int get_nCCE_offset(int *CCE_table,
|
|
const unsigned char L,
|
|
const int nCCE,
|
|
const int common_dci,
|
|
const unsigned short rnti,
|
|
const unsigned char subframe)
|
|
{
|
|
|
|
int search_space_free,m,nb_candidates = 0,l,i;
|
|
unsigned int Yk;
|
|
/*
|
|
printf("CCE Allocation: ");
|
|
for (i=0;i<nCCE;i++)
|
|
printf("%d.",CCE_table[i]);
|
|
printf("\n");
|
|
*/
|
|
if (common_dci == 1) {
|
|
// check CCE(0 ... L-1)
|
|
nb_candidates = (L==4) ? 4 : 2;
|
|
nb_candidates = min(nb_candidates,nCCE/L);
|
|
|
|
// printf("Common DCI nb_candidates %d, L %d\n",nb_candidates,L);
|
|
|
|
for (m = nb_candidates-1 ; m >=0 ; m--) {
|
|
|
|
search_space_free = 1;
|
|
for (l=0; l<L; l++) {
|
|
|
|
// printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]);
|
|
if (CCE_table[(m*L) + l] == 1) {
|
|
search_space_free = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (search_space_free == 1) {
|
|
|
|
// printf("returning %d\n",m*L);
|
|
|
|
for (l=0; l<L; l++)
|
|
CCE_table[(m*L)+l]=1;
|
|
return(m*L);
|
|
}
|
|
}
|
|
|
|
return(-1);
|
|
|
|
} else { // Find first available in ue specific search space
|
|
// according to procedure in Section 9.1.1 of 36.213 (v. 8.6)
|
|
// compute Yk
|
|
Yk = (unsigned int)rnti;
|
|
|
|
for (i=0; i<=subframe; i++)
|
|
Yk = (Yk*39827)%65537;
|
|
|
|
Yk = Yk % (nCCE/L);
|
|
|
|
|
|
switch (L) {
|
|
case 1:
|
|
case 2:
|
|
nb_candidates = 6;
|
|
break;
|
|
|
|
case 4:
|
|
case 8:
|
|
nb_candidates = 2;
|
|
break;
|
|
|
|
default:
|
|
DevParam(L, nCCE, rnti);
|
|
break;
|
|
}
|
|
|
|
|
|
LOG_D(MAC,"rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n",rnti,Yk,nCCE,nCCE/L,nb_candidates);
|
|
|
|
for (m = 0 ; m < nb_candidates ; m++) {
|
|
search_space_free = 1;
|
|
|
|
for (l=0; l<L; l++) {
|
|
if (CCE_table[(((Yk+m)%(nCCE/L))*L) + l] == 1) {
|
|
search_space_free = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (search_space_free == 1) {
|
|
for (l=0; l<L; l++)
|
|
CCE_table[(((Yk+m)%(nCCE/L))*L)+l]=1;
|
|
|
|
return(((Yk+m)%(nCCE/L))*L);
|
|
}
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
void dump_CCE_table(int *CCE_table,const int nCCE,const unsigned short rnti,const int subframe,int L) {
|
|
|
|
int nb_candidates = 0,i;
|
|
unsigned int Yk;
|
|
|
|
printf("CCE 0: ");
|
|
for (i=0;i<nCCE;i++) {
|
|
printf("%1d.",CCE_table[i]);
|
|
if ((i&7) == 7)
|
|
printf("\n CCE %d: ",i);
|
|
}
|
|
|
|
Yk = (unsigned int)rnti;
|
|
|
|
for (i=0; i<=subframe; i++)
|
|
Yk = (Yk*39827)%65537;
|
|
|
|
Yk = Yk % (nCCE/L);
|
|
|
|
|
|
switch (L) {
|
|
case 1:
|
|
case 2:
|
|
nb_candidates = 6;
|
|
break;
|
|
|
|
case 4:
|
|
case 8:
|
|
nb_candidates = 2;
|
|
break;
|
|
|
|
default:
|
|
DevParam(L, nCCE, rnti);
|
|
break;
|
|
}
|
|
|
|
|
|
printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n",rnti,Yk*L,nCCE,nCCE/L,nb_candidates*L);
|
|
|
|
}
|
|
|
|
// Allocate the CCEs
|
|
int allocate_CCEs(int module_idP,
|
|
int CC_idP,
|
|
int subframeP,
|
|
int test_onlyP) {
|
|
|
|
|
|
int *CCE_table = eNB_mac_inst[module_idP].CCE_table[CC_idP];
|
|
DCI_PDU *DCI_pdu = &eNB_mac_inst[module_idP].common_channels[CC_idP].DCI_pdu;
|
|
int nCCE_max = mac_xface->get_nCCE_max(module_idP,CC_idP,1,subframeP);
|
|
int fCCE;
|
|
int i,j;
|
|
DCI_ALLOC_t *dci_alloc;
|
|
int nCCE=0;
|
|
|
|
LOG_D(MAC,"Allocate CCEs subframe %d, test %d : (common %d,uspec %d)\n",subframeP,test_onlyP,DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci);
|
|
DCI_pdu->num_pdcch_symbols=1;
|
|
|
|
try_again:
|
|
init_CCE_table(module_idP,CC_idP);
|
|
nCCE=0;
|
|
|
|
for (i=0;i<DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci;i++) {
|
|
dci_alloc = &DCI_pdu->dci_alloc[i];
|
|
LOG_D(MAC,"Trying to allocate DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
i,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci,
|
|
DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci,
|
|
dci_alloc->rnti,1<<dci_alloc->L,
|
|
nCCE,nCCE_max,DCI_pdu->num_pdcch_symbols);
|
|
|
|
if (nCCE + (1<<dci_alloc->L) > nCCE_max) {
|
|
if (DCI_pdu->num_pdcch_symbols == 3)
|
|
goto failed;
|
|
DCI_pdu->num_pdcch_symbols++;
|
|
nCCE_max = mac_xface->get_nCCE_max(module_idP,CC_idP,DCI_pdu->num_pdcch_symbols,subframeP);
|
|
goto try_again;
|
|
}
|
|
|
|
// number of CCEs left can potentially hold this allocation
|
|
fCCE = get_nCCE_offset(CCE_table,
|
|
1<<(dci_alloc->L),
|
|
nCCE_max,
|
|
(i<DCI_pdu->Num_common_dci) ? 1 : 0,
|
|
dci_alloc->rnti,
|
|
subframeP);
|
|
if (fCCE == -1) {
|
|
if (DCI_pdu->num_pdcch_symbols == 3) {
|
|
LOG_I(MAC,"subframe %d: Dropping Allocation for RNTI %x\n",
|
|
subframeP,dci_alloc->rnti);
|
|
for (j=0;j<=i;j++){
|
|
LOG_I(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n",
|
|
j,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci,
|
|
DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci,
|
|
DCI_pdu->dci_alloc[j].rnti,DCI_pdu->dci_alloc[j].format,
|
|
1<<DCI_pdu->dci_alloc[j].L,
|
|
nCCE,nCCE_max,DCI_pdu->num_pdcch_symbols);
|
|
}
|
|
//dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L);
|
|
goto failed;
|
|
}
|
|
DCI_pdu->num_pdcch_symbols++;
|
|
nCCE_max = mac_xface->get_nCCE_max(module_idP,CC_idP,DCI_pdu->num_pdcch_symbols,subframeP);
|
|
goto try_again;
|
|
} // fCCE==-1
|
|
|
|
// the allocation is feasible, rnti rule passes
|
|
nCCE += (1<<dci_alloc->L);
|
|
LOG_D(MAC,"Allocating at nCCE %d\n",fCCE);
|
|
if (test_onlyP == 0) {
|
|
dci_alloc->firstCCE=fCCE;
|
|
LOG_D(MAC,"Allocate CCEs subframe %d, test %d\n",subframeP,test_onlyP);
|
|
}
|
|
} // for i = 0 ... num_dcis
|
|
|
|
return 0;
|
|
|
|
failed:
|
|
return -1;
|
|
}
|
|
|
|
boolean_t CCE_allocation_infeasible(int module_idP,
|
|
int CC_idP,
|
|
int common_flag,
|
|
int subframe,
|
|
int aggregation,
|
|
int rnti) {
|
|
|
|
|
|
DCI_PDU *DCI_pdu = &eNB_mac_inst[module_idP].common_channels[CC_idP].DCI_pdu;
|
|
//DCI_ALLOC_t *dci_alloc;
|
|
int ret;
|
|
boolean_t res=FALSE;
|
|
|
|
if (common_flag==1) {
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci].rnti = rnti;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci].L = aggregation;
|
|
DCI_pdu->Num_common_dci++;
|
|
ret = allocate_CCEs(module_idP,CC_idP,subframe,1);
|
|
if (ret==-1)
|
|
res = TRUE;
|
|
DCI_pdu->Num_common_dci--;
|
|
}
|
|
else {
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci].rnti = rnti;
|
|
DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci].L = aggregation;
|
|
DCI_pdu->Num_ue_spec_dci++;
|
|
ret = allocate_CCEs(module_idP,CC_idP,subframe,1);
|
|
if (ret==-1)
|
|
res = TRUE;
|
|
DCI_pdu->Num_ue_spec_dci--;
|
|
}
|
|
return(res);
|
|
}
|
|
|
|
void SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, rnti_t rntiP, sub_frame_t subframeP)
|
|
{
|
|
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
UE_list_t *UE_list = &eNB_mac_inst[mod_idP].UE_list;
|
|
|
|
if (UE_id != -1) {
|
|
if (mac_eNB_get_rrc_status(mod_idP,UE_RNTI(mod_idP,UE_id)) < RRC_CONNECTED)
|
|
LOG_I(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP);
|
|
UE_list->UE_template[cc_idP][UE_id].ul_SR = 1;
|
|
UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE;
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,1);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,0);
|
|
} else {
|
|
// AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP);
|
|
// AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP);
|
|
LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP);
|
|
}
|
|
}
|
|
|
|
void UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, rnti_t rntiP, sub_frame_t subframeP)
|
|
{
|
|
|
|
int UE_id = find_UE_id(mod_idP, rntiP);
|
|
UE_list_t *UE_list = &eNB_mac_inst[mod_idP].UE_list;
|
|
|
|
if (UE_id != -1) {
|
|
LOG_I(MAC,"[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n",
|
|
mod_idP,UE_id,rntiP,frameP,subframeP, UE_id,cc_idP,
|
|
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer);
|
|
if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0)
|
|
UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=1;
|
|
} else {
|
|
// AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP);
|
|
// AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP);
|
|
LOG_W(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP);
|
|
}
|
|
}
|