Something went wrong on our end
Forked from
oai / openairinterface5G
24018 commits behind the upstream repository.
ue_procedures.c 93.72 KiB
/*
* 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 ue_procedures.c
* \brief procedures related to UE
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \version 1
* \email: navid.nikaein@eurecom.fr
* @ingroup _mac
*/
#ifdef EXMIMO
#include <pthread.h>
#endif
#include "extern.h"
#include "defs.h"
#include "proto.h"
#ifdef PHY_EMUL
# include "SIMULATION/PHY_EMULATION/impl_defs.h"
#else
# include "SCHED/defs.h"
# include "PHY/impl_defs_top.h"
#endif
#include "PHY_INTERFACE/defs.h"
#include "PHY_INTERFACE/extern.h"
#include "COMMON/mac_rrc_primitives.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "RRC/LITE/extern.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#ifdef PHY_EMUL
# include "SIMULATION/simulation_defs.h"
#endif
#include "pdcp.h"
#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif
#include "assertions.h"
#include "SIMULATION/TOOLS/defs.h" // for taus
#define DEBUG_HEADER_PARSING 1
#define ENABLE_MAC_PAYLOAD_DEBUG 1
/*
#ifndef USER_MODE
#define msg debug_msg
#endif
*/
mapping BSR_names[] = {
{"NONE", 0},
{"SHORT BSR", 1},
{"TRUNCATED BSR", 2},
{"LONG BSR", 3},
{"PADDING BSR", 4},
{NULL, -1}
};
void ue_init_mac(module_id_t module_idP)
{
int i;
// default values as deined in 36.331 sec 9.2.2
LOG_I(MAC,"[UE%d] Applying default macMainConfig\n",module_idP);
//UE_mac_inst[module_idP].scheduling_info.macConfig=NULL;
UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf10240;
UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer=MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity;
UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20;
UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20;
UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1;
UE_mac_inst[module_idP].PHR_state = MAC_MainConfig__phr_Config_PR_setup;
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0;
UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer=0;
UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0;
UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5;
UE_mac_inst[module_idP].scheduling_info.ttiBundling=0;
UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0;
UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0;
UE_mac_inst[module_idP].scheduling_info.drx_config=NULL;
UE_mac_inst[module_idP].scheduling_info.phr_config=NULL;
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING;
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING;
UE_mac_inst[module_idP].BSR_reporting_active = 0;
UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer);
UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer);
UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange);
UE_mac_inst[module_idP].PHR_reporting_active = 0;
for (i=0; i < MAX_NUM_LCID; i++) {
LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i);
UE_mac_inst[module_idP].scheduling_info.Bj[i]=-1;
UE_mac_inst[module_idP].scheduling_info.bucket_size[i]=-1;
if (i < DTCH) { // initilize all control channels lcgid to 0
UE_mac_inst[module_idP].scheduling_info.LCGID[i]=0;
} else { // initialize all the data channels lcgid to 1
UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1;
}
UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY;
}
#ifdef CBA
for (i=0; i <NUM_MAX_CBA_GROUP; i++) {
UE_mac_inst[module_idP].cba_last_access[i]= round(uniform_rngen(1,30));
}
#endif
}
unsigned char *parse_header(unsigned char *mac_header,
unsigned char *num_ce,
unsigned char *num_sdu,
unsigned char *rx_ces,
unsigned char *rx_lcids,
unsigned short *rx_lengths,
unsigned short tb_length)
{
unsigned char not_done=1,num_ces=0,num_cont_res = 0,num_padding = 0,num_sdus=0,lcid, num_sdu_cnt;
unsigned char *mac_header_ptr = mac_header;
unsigned short length,ce_len=0;
while (not_done==1) {
if (((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E == 0) {
// printf("E=0\n");
not_done = 0;
}
lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID;
if (lcid < UE_CONT_RES) {
//printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]);
if (not_done==0) {// last MAC SDU, length is implicit
mac_header_ptr++;
length = tb_length-(mac_header_ptr-mac_header)-ce_len;
for (num_sdu_cnt=0; num_sdu_cnt < num_sdus ; num_sdu_cnt++) {
length -= rx_lengths[num_sdu_cnt];
}
} else {
if (((SCH_SUBHEADER_LONG *)mac_header_ptr)->F == 1) {
length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff);
mac_header_ptr += 3;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] parse long sdu, size %x \n",length);
#endif
} else { //if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) {
length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L;
mac_header_ptr += 2;
}
}
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] sdu %d lcid %d length %d (offset now %d)\n",
num_sdus,lcid,length,mac_header_ptr-mac_header);
#endif
rx_lcids[num_sdus] = lcid;
rx_lengths[num_sdus] = length;
num_sdus++;
} else { // This is a control element subheader
if (lcid == SHORT_PADDING) {
num_padding ++;
mac_header_ptr++;
} else {
rx_ces[num_ces] = lcid;
num_ces++;
mac_header_ptr ++;
if (lcid==TIMING_ADV_CMD) {
ce_len++;
} else if (lcid==UE_CONT_RES) {
// FNA: check MAC Header is one of thoses defined in Annex B of 36.321
// Check there is only 1 Contention Resolution
if (num_cont_res) {
LOG_W(MAC,"[UE] Msg4 Wrong received format: More than 1 Contention Resolution\n");
// exit parsing
return NULL;
}
// UE_CONT_RES shall never be the last subheader unless this is the only MAC subheader
if ((not_done == 0) && ((num_sdus) || (num_ces > 1) || (num_padding))) {
LOG_W(MAC,"[UE] Msg4 Wrong received format: Contention Resolution after num_ces=%d num_sdus=%d num_padding=%d\n",num_ces,num_sdus,num_padding);
// exit parsing
return NULL;
}
num_cont_res ++;
ce_len+=6;
}
}
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] ce %d lcid %d (offset now %d)\n",num_ces,lcid,mac_header_ptr-mac_header);
#endif
}
}
*num_ce = num_ces;
*num_sdu = num_sdus;
return(mac_header_ptr);
}
uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_id,uint16_t rnti, sub_frame_t subframe)
{
// no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti
// int MGL=6;// measurement gap length in ms
int MGRP = 0; // measurement gap repetition period in ms
int gapOffset = -1;
int T = 0;
DevCheck(module_idP < (int)NB_UE_INST, module_idP, NB_UE_INST, 0);
if (CC_id>0) {
LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n");
mac_xface->macphy_exit("MAC FATAL CC_id>0");
return 0;
}
// determin the measurement gap
if (UE_mac_inst[module_idP].measGapConfig !=NULL) {
if (UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) {
MGRP= 40;
gapOffset= UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.choice.gp0;
} else if (UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) {
MGRP= 80;
gapOffset= UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.choice.gp1;
} else {
LOG_W(MAC, "Measurement GAP offset is unknown\n");
}
T=MGRP/10;
DevAssert( T != 0 );
//check the measurement gap and sr prohibit timer
if ((subframe == gapOffset %10) && ((frameP %T) == (floor(gapOffset/10)))
&& (UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running ==0)) {
UE_mac_inst[module_idP].scheduling_info.SR_pending=1;
return(0);
}
}
if ((UE_mac_inst[module_idP].physicalConfigDedicated != NULL) &&
(UE_mac_inst[module_idP].scheduling_info.SR_pending==1) &&
(UE_mac_inst[module_idP].scheduling_info.SR_COUNTER <
(1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax)))
) {
LOG_D(MAC,"[UE %d][SR %x] Frame %d subframe %d PHY asks for SR (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n",
module_idP,rnti,frameP,subframe,
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER,
(1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax)),
UE_mac_inst[module_idP].scheduling_info.SR_pending);
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER++;
// start the sr-prohibittimer : rel 9 and above
if (UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer > 0) { // timer configured
UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer--;
UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=1;
} else {
UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0;
}
LOG_D(MAC,"[UE %d][SR %x] Frame %d subframe %d send SR indication (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n",
module_idP,rnti,frameP,subframe,
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER,
(1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax)),
UE_mac_inst[module_idP].scheduling_info.SR_pending);
//UE_mac_inst[module_idP].ul_active =1;
return(1); //instruct phy to signal SR
} else {
// notify RRC to relase PUCCH/SRS
// clear any configured dl/ul
// initiate RA
if (UE_mac_inst[module_idP].scheduling_info.SR_pending){
// release all pucch resource
UE_mac_inst[module_idP].physicalConfigDedicated = NULL;
UE_mac_inst[module_idP].ul_active=0;
UE_mac_inst[module_idP].BSR_reporting_active=0;
LOG_I(MAC,"[UE %d] Release all SRs \n", module_idP);
}
UE_mac_inst[module_idP].scheduling_info.SR_pending=0;
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0;
return(0);
}
}
//------------------------------------------------------------------------------
void
ue_send_sdu(
module_id_t module_idP,
uint8_t CC_id,
frame_t frameP,
uint8_t* sdu,
uint16_t sdu_len,
uint8_t eNB_index
)
//------------------------------------------------------------------------------
{
unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr;
unsigned char rx_lcids[NB_RB_MAX];
unsigned short rx_lengths[NB_RB_MAX];
unsigned char *tx_sdu;
start_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN);
LOG_T(MAC,"sdu: %x.%x.%x\n",sdu[0],sdu[1],sdu[2]);
if (opt_enabled) {
trace_pdu(1, sdu, sdu_len, module_idP, 3, UE_mac_inst[module_idP].crnti,
UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0);
LOG_D(OPT,"[UE %d][DLSCH] Frame %d trace pdu for rnti %x with size %d\n",
module_idP, frameP, UE_mac_inst[module_idP].crnti, sdu_len);
}
payload_ptr = parse_header(sdu,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_len);
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE %d] ue_send_sdu : Frame %d eNB_index %d : num_ce %d num_sdu %d\n",module_idP,
frameP,eNB_index,num_ce,num_sdu);
#endif
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_T(MAC,"[eNB %d] First 32 bytes of DLSCH : \n");
for (i=0; i<32; i++) {
LOG_T(MAC,"%x.",sdu[i]);
}
LOG_T(MAC,"\n");
#endif
if (payload_ptr != NULL) {
for (i=0; i<num_ce; i++) {
// printf("ce %d : %d\n",i,rx_ces[i]);
switch (rx_ces[i]) {
case UE_CONT_RES:
LOG_I(MAC,"[UE %d][RAPROC] Frame %d : received contention resolution msg: %x.%x.%x.%x.%x.%x, Terminating RA procedure\n",
module_idP,frameP,payload_ptr[0],payload_ptr[1],payload_ptr[2],payload_ptr[3],payload_ptr[4],payload_ptr[5]);
if (UE_mac_inst[module_idP].RA_active == 1) {
LOG_I(MAC,"[UE %d][RAPROC] Frame %d : Clearing RA_active flag\n");
UE_mac_inst[module_idP].RA_active=0;
// check if RA procedure has finished completely (no contention)
tx_sdu = &UE_mac_inst[module_idP].CCCH_pdu.payload[3];
//Note: 3 assumes sizeof(SCH_SUBHEADER_SHORT) + PADDING CE, which is when UL-Grant has TBS >= 9 (64 bits)
// (other possibility is 1 for TBS=7 (SCH_SUBHEADER_FIXED), or 2 for TBS=8 (SCH_SUBHEADER_FIXED+PADDING or SCH_SUBHEADER_SHORT)
for (i=0; i<6; i++)
if (tx_sdu[i] != payload_ptr[i]) {
LOG_E(MAC,"[UE %d][RAPROC] Contention detected, RA failed\n",module_idP);
mac_xface->ra_failed(module_idP,CC_id,eNB_index);
UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
return;
}
LOG_I(MAC,"[UE %d][RAPROC] Frame %d : Clearing contention resolution timer\n");
UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0;
mac_xface->ra_succeeded(module_idP,CC_id,eNB_index);
}
payload_ptr+=6;
break;
case TIMING_ADV_CMD:
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] CE %d : UE Timing Advance : %d\n",i,payload_ptr[0]);
#endif
mac_xface->process_timing_advance(module_idP,CC_id,payload_ptr[0]);
payload_ptr++;
break;
case DRX_CMD:
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] CE %d : UE DRX :",i);
#endif
payload_ptr++;
break;
}
}
for (i=0; i<num_sdu; i++) {
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] SDU %d : LCID %d, length %d\n",i,rx_lcids[i],rx_lengths[i]);
#endif
if (rx_lcids[i] == CCCH) {
LOG_D(MAC,"[UE %d] rnti %x Frame %d : DLSCH -> DL-CCCH, RRC message (eNB %d, %d bytes)\n",
module_idP,
UE_mac_inst[module_idP].crnti,
frameP,
eNB_index,
rx_lengths[i]);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
int j;
for (j=0; j<rx_lengths[i]; j++) {
LOG_T(MAC,"%x.",(uint8_t)payload_ptr[j]);
}
LOG_T(MAC,"\n");
#endif
mac_rrc_data_ind(module_idP,
CC_id,
frameP,0, // unknown subframe
UE_mac_inst[module_idP].crnti,
CCCH,
(uint8_t*)payload_ptr,
rx_lengths[i],
ENB_FLAG_NO,
eNB_index,
0);
} else if ((rx_lcids[i] == DCCH) || (rx_lcids[i] == DCCH1)) {
LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-DCCH%d, RRC message (eNB %d, %d bytes)\n", module_idP, frameP, rx_lcids[i],eNB_index,rx_lengths[i]);
mac_rlc_data_ind(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
rx_lcids[i],
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
} else if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1 )) {
LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", module_idP, frameP,rx_lcids[i], eNB_index,rx_lengths[i]);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
int j;
for (j=0;j<rx_lengths[i];j++)
LOG_T(MAC,"%x.",(unsigned char)payload_ptr[j]);
LOG_T(MAC,"\n");
#endif
mac_rlc_data_ind(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
rx_lcids[i],
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
} else {
LOG_E(MAC,"[UE %d] Frame %d : unknown LCID %d (eNB %d)\n", module_idP, frameP,rx_lcids[i], eNB_index);
}
payload_ptr+= rx_lengths[i];
}
} // end if (payload_ptr != NULL)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu);
}
void ue_decode_si(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_index, void *pdu,uint16_t len)
{
start_meas(&UE_mac_inst[module_idP].rx_si);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_IN);
LOG_D(MAC,"[UE %d] Frame %d Sending SI to RRC (LCID Id %d,len %d)\n",module_idP,frameP,BCCH,len);
mac_rrc_data_ind(module_idP,
CC_id,
frameP,0, // unknown subframe
SI_RNTI,
BCCH,
(uint8_t *)pdu,
len,
ENB_FLAG_NO,
eNB_index,
0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].rx_si);
if (opt_enabled == 1) {
trace_pdu(0,
(uint8_t *)pdu,
len,
module_idP,
4,
0xffff,
UE_mac_inst[module_idP].frame,
UE_mac_inst[module_idP].subframe,
0,
0);
LOG_D(OPT,"[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n",
module_idP, frameP, CC_id, 0xffff, len);
}
}
void ue_decode_p(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_index, void *pdu,uint16_t len)
{
start_meas(&UE_mac_inst[module_idP].rx_p);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_IN);
LOG_D(MAC,"[UE %d] Frame %d Sending Paging message to RRC (LCID Id %d,len %d)\n",module_idP,frameP,PCCH,len);
mac_rrc_data_ind(module_idP,
CC_id,
frameP,0, // unknown subframe
P_RNTI,
PCCH,
(uint8_t *)pdu,
len,
ENB_FLAG_NO,
eNB_index,
0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].rx_p);
if (opt_enabled == 1) {
trace_pdu(0,
(uint8_t *)pdu,
len,
module_idP,
4,
P_RNTI,
UE_mac_inst[module_idP].frame,
UE_mac_inst[module_idP].subframe,
0,
0);
LOG_D(OPT,"[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n",
module_idP, frameP, CC_id, P_RNTI, len);
}
}
#ifdef Rel10
unsigned char *parse_mch_header(unsigned char *mac_header,
unsigned char *num_sdu,
unsigned char *rx_lcids,
unsigned short *rx_lengths,
unsigned short tb_length)
{
unsigned char not_done=1, num_sdus=0, lcid, i;
unsigned char *mac_header_ptr = mac_header;
unsigned short length;
while (not_done == 1) {
if (((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E == 0) {
not_done = 0;
}
lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID;
if (lcid < SHORT_PADDING) {// subheader for MSI, MCCH or MTCH
if (not_done == 0) { // last MAC SDU, length is implicit
mac_header_ptr++;
length = tb_length- (mac_header_ptr - mac_header);
for (i=0; i<num_sdus; i++) {
length -= rx_lengths[i];
}
} else { // not the last MAC SDU
if ( ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F == 1) {// subheader has length of 3octets
// length = ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L;
length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff);
mac_header_ptr += 3;
} else { // subheader has length of 2octets
length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L;
mac_header_ptr += 2;
}
}
rx_lcids[num_sdus] = lcid;
rx_lengths[num_sdus] = length;
num_sdus++;
} else { // subheader for padding
// if (lcid == SHORT_PADDING)
mac_header_ptr++;
}
}
*num_sdu = num_sdus;
return(mac_header_ptr);
}
// this function is for sending mch_sdu from phy to mac
void ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, uint8_t *sdu, uint16_t sdu_len, uint8_t eNB_index, uint8_t sync_area)
{
unsigned char num_sdu, i, *payload_ptr;
unsigned char rx_lcids[NB_RB_MAX];
unsigned short rx_lengths[NB_RB_MAX];
start_meas(&UE_mac_inst[module_idP].rx_mch_sdu);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_IN);
LOG_D(MAC,"[UE %d] Frame %d : process the mch PDU for sync area %d \n",module_idP,frameP, sync_area);
LOG_D(MAC,"[UE %d] sdu: %x.%x\n", module_idP,sdu[0], sdu[1]);
LOG_D(MAC,"[UE %d] parse_mch_header, demultiplex\n",module_idP);
payload_ptr = parse_mch_header(sdu, &num_sdu, rx_lcids, rx_lengths, sdu_len);
LOG_D(MAC,"[UE %d] parse_mch_header, found %d sdus\n",module_idP,num_sdu);
for (i=0; i<num_sdu; i++) {
if (rx_lcids[i] == MCH_SCHDL_INFO) {
if (UE_mac_inst[module_idP].mcch_status==1) {
LOG_I(MAC,"[UE %d] Frame %d : MCH->MSI for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, sync_area, eNB_index, rx_lengths[i]);
// ??store necessary scheduling info to ue_mac_inst in order to
// calculate exact position of interested service (for the complex case has >1 mtch)
// set msi_status to 1
UE_mac_inst[module_idP].msi_status = 1;
}
} else if (rx_lcids[i] == MCCH_LCHANID) {
LOG_I(MAC,"[UE %d] Frame %d : SDU %d MCH->MCCH for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, i, sync_area, eNB_index, rx_lengths[i]);
mac_rrc_data_ind(module_idP,
CC_id,
frameP,0, // unknown subframe
M_RNTI,
MCCH,
payload_ptr, rx_lengths[i], 0, eNB_index, sync_area);
} else if (rx_lcids[i] == MTCH) {
if (UE_mac_inst[module_idP].msi_status==1) {
LOG_I(MAC,"[UE %d] Frame %d : MCH->MTCH for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, sync_area, eNB_index, rx_lengths[i]);
mac_rlc_data_ind(
module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_YES,
MTCH, /*+ (maxDRB + 3),*/
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
}
} else {
LOG_W(MAC,"[UE %d] Frame %d : unknown sdu %d rx_lcids[%d]=%d mcch status %d eNB %d \n",
module_idP,
frameP,
rx_lengths[i],
i,
rx_lcids[i],
UE_mac_inst[module_idP].mcch_status, eNB_index);
}
payload_ptr += rx_lengths[i];
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].rx_mch_sdu);
}
int8_t ue_get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t mbsfn_sync_area, unsigned char eNB_index)
{
// currently there is one-to-one mapping between sf allocation pattern and sync area
if (mbsfn_sync_area >= MAX_MBSFN_AREA) {
LOG_W( MAC, "[UE %"PRIu8"] MBSFN synchronization area %"PRIu8" out of range for eNB %"PRIu8"\n", module_idP, mbsfn_sync_area, eNB_index );
return -1;
} else if (UE_mac_inst[module_idP].mbsfn_SubframeConfig[mbsfn_sync_area] != NULL) {
return mbsfn_sync_area;
} else {
LOG_W( MAC, "[UE %"PRIu8"] MBSFN Subframe Config pattern %"PRIu8" not found \n", module_idP, mbsfn_sync_area );
return -1;
}
}
int ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, uint32_t subframe, uint8_t eNB_index,uint8_t *sync_area, uint8_t *mcch_active)
{
int i=0, j=0, ii=0, msi_pos=0, mcch_mcs = - 1;
int mcch_flag=0, mtch_flag=0, msi_flag=0;
int mbsfn_period = 0;// 1<<(UE_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod);
int mcch_period = 0;// 32<<(UE_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9);
int mch_scheduling_period = -1;
start_meas(&UE_mac_inst[module_idP].ue_query_mch);
if (UE_mac_inst[module_idP].pmch_Config[0]) {
mch_scheduling_period = 8<<(UE_mac_inst[module_idP].pmch_Config[0]->mch_SchedulingPeriod_r9);
}
for (i=0;
i< UE_mac_inst[module_idP].num_active_mbsfn_area;
i++ ) {
// assume, that there is always a mapping
if ((j=ue_get_mbsfn_sf_alloction(module_idP,i,eNB_index)) == -1) {
return -1; // continue;
}
ii=0;
msi_pos=0;
mbsfn_period = 1<<(UE_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod);
mcch_period = 32<<(UE_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9);
LOG_D(MAC,
"[UE %d] Frame %d subframe %d: Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d,mac sched period (%d,%d))\n",
module_idP,frameP, subframe,i,UE_mac_inst[module_idP].num_active_mbsfn_area,
j,UE_mac_inst[module_idP].num_sf_allocation_pattern,mbsfn_period,mcch_period,
mch_scheduling_period,UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset);
// get the real MCS value
switch (UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) {
case 0:
mcch_mcs = 2;
break;
case 1:
mcch_mcs = 7;
break;
case 2:
mcch_mcs = 13;
break;
case 3:
mcch_mcs = 19;
break;
}
if (frameP % mbsfn_period == UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP
if (UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format
if (UE_mac_inst[module_idP].pmch_Config[0]) {
// Find the first subframe in this MCH to transmit MSI
if (frameP % mch_scheduling_period == UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset ) {
while (ii == 0) {
ii = UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & (0x80>>msi_pos);
msi_pos++;
}
}
}
// Check if the subframe is for MSI, MCCH or MTCHs and Set the correspoding flag to 1
switch (subframe) {
case 1:
if (mac_xface->frame_parms->frame_type == FDD) {
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) {
if (msi_pos == 1) {
msi_flag = 1;
}
if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 2:
if (mac_xface->frame_parms->frame_type == FDD) {
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) {
if (msi_pos == 2) {
msi_flag = 1;
}
if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 3:
if (mac_xface->frame_parms->frame_type == TDD) { // TDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) {
if (msi_pos == 1) {
msi_flag = 1;
}
if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
} else { // FDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) {
if (msi_pos == 3) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 4:
if (mac_xface->frame_parms->frame_type == TDD) {
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) {
if (msi_pos == 2) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 6:
if (mac_xface->frame_parms->frame_type == FDD) {
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) {
if (msi_pos == 4) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 7:
if (mac_xface->frame_parms->frame_type == TDD) { // TDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) {
if (msi_pos == 3) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
} else { // FDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) {
if (msi_pos == 5) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 8:
if (mac_xface->frame_parms->frame_type == TDD) { //TDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) {
if (msi_pos == 4) {
msi_flag = 1;
}
if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
} else { // FDD
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) {
if (msi_pos == 6) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
case 9:
if (mac_xface->frame_parms->frame_type == TDD) {
if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) {
if (msi_pos == 5) {
msi_flag = 1;
}
if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) &&
((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) ) {
mcch_flag = 1;
}
mtch_flag = 1;
}
}
break;
}// end switch
// sf allocation is non-overlapping
if ((msi_flag==1) || (mcch_flag==1) || (mtch_flag==1)) {
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n",
module_idP, frameP, subframe,i,j,msi_flag,mcch_flag,mtch_flag);
*sync_area=i;
break;
}
} else { // four-frameP format
}
}
} // end of for
stop_meas(&UE_mac_inst[module_idP].ue_query_mch);
if ( (mcch_flag==1)) { // || (msi_flag==1))
*mcch_active=1;
}
if ( (mcch_flag==1) || ((msi_flag==1) && (UE_mac_inst[module_idP].mcch_status==1)) ) {
return mcch_mcs;
} else if ((mtch_flag==1) && (UE_mac_inst[module_idP].msi_status==1)) {
return UE_mac_inst[module_idP].pmch_Config[0]->dataMCS_r9;
} else {
return -1;
}
}
#endif
unsigned char generate_ulsch_header(uint8_t *mac_header,
uint8_t num_sdus,
uint8_t short_padding,
uint16_t *sdu_lengths,
uint8_t *sdu_lcids,
POWER_HEADROOM_CMD *power_headroom,
uint16_t *crnti,
BSR_SHORT *truncated_bsr,
BSR_SHORT *short_bsr,
BSR_LONG *long_bsr,
unsigned short post_padding)
{
SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header;
unsigned char first_element=0,last_size=0,i;
unsigned char mac_header_control_elements[16],*ce_ptr;
LOG_D(MAC,"[UE] Generate ULSCH : num_sdus %d\n",num_sdus);
#ifdef DEBUG_HEADER_PARSING
for (i=0; i<num_sdus; i++) {
LOG_T(MAC,"[UE] sdu %d : lcid %d length %d",i,sdu_lcids[i],sdu_lengths[i]);
}
LOG_T(MAC,"\n");
#endif
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;
}
if (power_headroom) {
if (first_element>0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element=1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = POWER_HEADROOM;
last_size=1;
*((POWER_HEADROOM_CMD *)ce_ptr)=(*power_headroom);
ce_ptr+=sizeof(POWER_HEADROOM_CMD);
LOG_D(MAC, "phr header size %d\n",sizeof(POWER_HEADROOM_CMD));
}
if (crnti) {
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] CRNTI : %x (first_element %d)\n",*crnti,first_element);
#endif
if (first_element>0) {
mac_header_ptr->E = 1;
mac_header_ptr++;
} else {
first_element=1;
}
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = CRNTI;
last_size=1;
*((uint16_t *)ce_ptr)=(*crnti);
ce_ptr+=sizeof(uint16_t);
// printf("offset %d\n",ce_ptr-mac_header_control_elements);
}
if (truncated_bsr) {
if (first_element>0) {
mac_header_ptr->E = 1;
/*
printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr++;
} else {
first_element=1;
}
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] Scheduler Truncated BSR Header\n");
#endif
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = TRUNCATED_BSR;
last_size=1;
*((BSR_TRUNCATED *)ce_ptr)=(*truncated_bsr);
ce_ptr+=sizeof(BSR_TRUNCATED);
// printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
} else if (short_bsr) {
if (first_element>0) {
mac_header_ptr->E = 1;
/*
printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr++;
} else {
first_element=1;
}
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] Scheduler SHORT BSR Header\n");
#endif
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = SHORT_BSR;
last_size=1;
*((BSR_SHORT *)ce_ptr)=(*short_bsr);
ce_ptr+=sizeof(BSR_SHORT);
// printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
} else if (long_bsr) {
if (first_element>0) {
mac_header_ptr->E = 1;
/*
printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
*/
mac_header_ptr++;
} else {
first_element=1;
}
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] Scheduler Long BSR Header\n");
#endif
mac_header_ptr->R = 0;
mac_header_ptr->E = 0;
mac_header_ptr->LCID = LONG_BSR;
last_size=1;
*(ce_ptr) = (long_bsr->Buffer_size0 << 2) | ((long_bsr->Buffer_size1 & 0x30) >> 4);
*(ce_ptr + 1) = ((long_bsr->Buffer_size1 & 0x0F) << 4) | ((long_bsr->Buffer_size2 & 0x3C) >> 2);
*(ce_ptr + 2) = ((long_bsr->Buffer_size2 & 0x03) << 2) | (long_bsr->Buffer_size3 & 0x3F);
/* Padding */
*(ce_ptr + 3) = 0;
ce_ptr += BSR_LONG_SIZE;
// printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
}
// printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
for (i=0; i<num_sdus; i++) {
#ifdef DEBUG_HEADER_PARSING
LOG_T(MAC,"[UE] sdu subheader %d (lcid %d, %d bytes)\n",i,sdu_lcids[i],sdu_lengths[i]);
#endif
if ((first_element>0)) {
mac_header_ptr->E = 1;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
#endif
mac_header_ptr+=last_size;
// printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
} else {
first_element=1;
}
if (sdu_lengths[i] < 128) {
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; // 3
((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;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] short sdu\n");
LOG_T(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d,F%d,L%d)\n",
((uint16_t*)mac_header_ptr)[0],
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R,
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E,
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID,
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F,
((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L);
#endif
} else {
((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0;
((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0;
((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1;
((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i];
((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f;
((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff;
((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00;
last_size=3;
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC,"[UE] long sdu\n");
#endif
}
}
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++;
//mac_header_ptr=last_size; // FIXME: should be ++
}
if ((ce_ptr-mac_header_control_elements) > 0) {
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);
}
#ifdef DEBUG_HEADER_PARSING
LOG_T(MAC," [UE %d] header : ", crnti);
for (i=0; i<((unsigned char*)mac_header_ptr - mac_header); i++) {
LOG_T(MAC,"%2x.",mac_header[i]);
}
LOG_T(MAC,"\n");
#endif
return((unsigned char*)mac_header_ptr - mac_header);
}
void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint8_t *ulsch_buffer,uint16_t buflen, uint8_t *access_mode)
{
mac_rlc_status_resp_t rlc_status;
uint8_t dcch_header_len=0,dcch1_header_len=0,dtch_header_len=0,dtch_header_len_last=0;
uint8_t dcch_header_len_tmp=0, dtch_header_len_tmp=0;
uint8_t bsr_header_len=0, bsr_ce_len=0, bsr_len=0;
uint8_t phr_header_len=0, phr_ce_len=0,phr_len=0;
uint8_t lcid=0;
uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t payload_offset=0,num_sdus=0;
uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES];
uint16_t sdu_length_total=0;
BSR_SHORT bsr_short;
BSR_LONG bsr_long;
BSR_SHORT *bsr_s=&bsr_short;
BSR_LONG *bsr_l=&bsr_long;
POWER_HEADROOM_CMD phr;
POWER_HEADROOM_CMD *phr_p=&phr;
unsigned short short_padding=0, post_padding=0, padding_len=0;
int j; // used for padding
// Compute header length
int all_pdu_len;
int lcg_id = 0;
int lcg_id_bsr_short = 0;
int num_lcg_id_with_data = 0;
LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n",
module_idP, frameP, subframe, buflen);
if (CC_id>0) {
LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n");
mac_xface->macphy_exit("MAC FATAL CC_id>0");
return;
}
start_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_IN);
#ifdef CBA
if (*access_mode==CBA_ACCESS) {
LOG_D(MAC,"[UE %d] frameP %d subframe %d try CBA transmission\n",
module_idP, frameP, subframe);
//if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DTCH] == LCID_EMPTY)
if (cba_access(module_idP,frameP,subframe,eNB_index,buflen)==0) {
*access_mode=POSTPONED_ACCESS;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT);
return;
}
LOG_I(MAC,"[UE %d] frameP %d subframe %d CBA transmission oppurtunity, tbs %d\n",
module_idP, frameP, subframe,buflen);
}
#endif
dcch_header_len=2;//sizeof(SCH_SUBHEADER_SHORT);
dcch1_header_len=2;//sizeof(SCH_SUBHEADER_SHORT);
// hypo length,in case of long header skip the padding byte
dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT);
bsr_header_len = 0;
phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED);
while (lcg_id < MAX_NUM_LCGID) {
if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]){
num_lcg_id_with_data ++;
lcg_id_bsr_short = lcg_id;
}
lcg_id ++;
}
if (num_lcg_id_with_data){
LOG_I(MAC,"[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d LCG0 bytes=%d BSR Trigger status =%d TBS=%d\n",
module_idP, frameP, subframe, num_lcg_id_with_data, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0],UE_mac_inst[module_idP].BSR_reporting_active, buflen);
}
// ReTxBSR-Timer expires, trigger BSR
if ((num_lcg_id_with_data) && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0)){
// If the UE has data to transmit, trigger a BSR
UE_mac_inst[module_idP].BSR_reporting_active = 1;
LOG_I(MAC,"[UE %d] MAC BSR Triggered ReTxBSR Timer expiry at frame%d subframe %d TBS=%d\n",
module_idP, frameP, subframe, buflen);
}
// periodicBSR-Timer expires, trigger BSR
if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)
&& (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == 0)){
// Trigger BSR
UE_mac_inst[module_idP].BSR_reporting_active = 1;
LOG_I(MAC,"[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n",
module_idP, frameP, subframe, buflen);
}
//Compute BSR Length
if (UE_mac_inst[module_idP].BSR_reporting_active){
if (buflen >= 4){
if (num_lcg_id_with_data <= 1){
bsr_ce_len = sizeof(BSR_SHORT); //1 byte
}
else{
bsr_ce_len = sizeof(BSR_LONG); //3 bytes
}
bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED);
// Reset Periodic and ReTx BSR Timer
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer);
LOG_I(MAC,"[UE %d] MAC ReTx BSR Timer Reset =%d\n",
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF);
if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity){
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer);
LOG_I(MAC,"[UE %d] MAC Periodic BSR Timer Reset =%d\n",
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF);
}
LOG_I(MAC,"[UE %d] MAC BSR Triggered !! bsr (ce%d,hdr%d) buff_len %d\n",
module_idP, bsr_ce_len, bsr_header_len, buflen);
}
else {
// Cancel Regular and Periodic BSR if Grant is smaller than 4 bytes
UE_mac_inst[module_idP].BSR_reporting_active = 0;
bsr_header_len = 0;
}
}
bsr_len = bsr_ce_len + bsr_header_len;
#if 0
bsr_ce_len = get_bsr_len (module_idP, eNB_index, frameP, buflen);
// retxBSR-Timer expires or periodicBSR-Timer expires and Regular BSR trigger
if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) {
bsr_len = bsr_ce_len + bsr_header_len;
LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n",
module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_ce_len, bsr_header_len, buflen);
} else {
bsr_len=0;
//LOG_D(MAC,"[UE %d] Empty buffers, send a long BSR to reset the bsr at eNB \n ",Mod_id);
// bsr_ce_len = sizeof(BSR_LONG);
//bsr_len = bsr_ce_len + bsr_header_len;
}
#endif
phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0;
if (phr_ce_len > 0) {
phr_len = phr_ce_len + phr_header_len;
LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n",
module_idP, phr_len, phr_ce_len, phr_header_len, buflen);
} else {
phr_len=0;
}
// check for UL bandwidth requests and add SR control element
// check for UL bandwidth requests and add SR control element
// Check for DCCH first
if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] == LCID_NOT_EMPTY) {
rlc_status = mac_rlc_status_ind(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO, // eNB_index
DCCH,
(buflen-dcch_header_len-bsr_len-phr_len));
LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB1 has %d bytes to "
"send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d)\n",
module_idP,frameP, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,sdu_length_total,dcch_header_len);
/* Update BSR : substract transmitted data */
if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] >= rlc_status.bytes_in_buffer){
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= rlc_status.bytes_in_buffer;
}
else if (rlc_status.bytes_in_buffer){
LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%d for LCID%d\n",
module_idP,frameP,subframe,
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]],
UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH],
rlc_status.bytes_in_buffer,DCCH);
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0;
}
sdu_lengths[0] += mac_rlc_data_req(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
DCCH,
(char *)&ulsch_buff[sdu_lengths[0]]);
sdu_length_total += sdu_lengths[0];
sdu_lcids[0] = DCCH;
LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB1\n",module_idP,sdu_lengths[0]);
num_sdus = 1;
//update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]);
//header_len +=2;
UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY;
#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0
UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0];
#endif
} else {
dcch_header_len=0;
num_sdus = 0;
}
// if the RLC AM is used, then RLC will only provide 2 bytes for ACK
// in this case, we sould add bsr
// DCCH1
if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] == LCID_NOT_EMPTY) {
rlc_status = mac_rlc_status_ind(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO, // eNB_index
DCCH1,
(buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-sdu_length_total));
LOG_D(MAC,"[UE %d] Frame %d subframe %d: UL-DCCH1 -> ULSCH, RLC SRB2 has %d bytes to"
" send (Transport Block size %d BSR size=%d PHR=%d SRB1 Hdr %d SDU Length Total %d , mac header len %d)\n",
module_idP,frameP, subframe, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,dcch_header_len,sdu_length_total,dcch1_header_len);
/* Update BSR : substract transmitted data */
if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] >= rlc_status.bytes_in_buffer){
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= rlc_status.bytes_in_buffer;
}
else if (rlc_status.bytes_in_buffer){
LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%d for LCID%d\n",
module_idP,frameP,subframe,
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]],
UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1],
rlc_status.bytes_in_buffer,DCCH1);
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0;
}
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
DCCH1,
(char *)&ulsch_buff[sdu_lengths[num_sdus]]);
sdu_length_total += sdu_lengths[num_sdus];
sdu_lcids[num_sdus] = DCCH1;
LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU Got %d bytes for SRB2\n",module_idP,sdu_lengths[num_sdus]);
//update_bsr(module_idP, frameP, DCCH1);
//dcch_header_len +=2; // include dcch1
UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY;
#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0
UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus];
#endif
num_sdus++;
} else {
dcch1_header_len =0;
}
dtch_header_len=0;
dtch_header_len_last=0;
for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){
dtch_header_len+=3;
dtch_header_len_last=3;
all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total;
if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) &&
(all_pdu_len <= buflen)) {
// optimize the dtch header lenght
//if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) &&
/* if (((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] >= 128) &&
((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH]+bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len) > buflen)&&
buflen >=128 ))
dtch_header_len = 3;//sizeof(SCH_SUBHEADER_LONG);
else
dtch_header_len = 2;//sizeof(SCH_SUBHEADER_SHORT);
*/
rlc_status = mac_rlc_status_ind(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO, // eNB_index
lcid,
buflen-all_pdu_len);
LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n",
module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len,
lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]);
if (rlc_status.bytes_in_buffer > 0) {
/* Update BSR : substract transmitted data */
if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= rlc_status.bytes_in_buffer){
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= rlc_status.bytes_in_buffer;
}
else {
LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%d for LCID%d\n",
module_idP,frameP,subframe,
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]],
UE_mac_inst[module_idP].scheduling_info.LCGID[lcid],
rlc_status.bytes_in_buffer,lcid);
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0;
}
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
UE_mac_inst[module_idP].crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO, // eNB_index
lcid,
(char *)&ulsch_buff[sdu_length_total]);
//adjust dtch header
LOG_D(MAC,"[UE %d] TX Got %d bytes for DTCH\n",module_idP,sdu_lengths[num_sdus]);
sdu_lcids[num_sdus] = lcid;
sdu_length_total += sdu_lengths[num_sdus];
if (sdu_lengths[num_sdus] < 128) {
dtch_header_len --;
dtch_header_len_last --;
}
#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0
UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus];
#endif
num_sdus++;
//UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]);
} else {
dtch_header_len -= 3;
}
UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY;
} else { // no rlc pdu : generate the dummy header
dtch_header_len -= 3;
}
}
//lcgid= get_bsr_lcgid(module_idP);
// Compute BSR Values
for (lcg_id=0;lcg_id<MAX_NUM_LCGID;lcg_id++){
UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]);
}
if (bsr_ce_len == 0 ) {
bsr_s = NULL;
bsr_l = NULL ;
//TO DO : compute padding or truncated BSR
} else if (bsr_ce_len == sizeof(BSR_LONG)) {
bsr_s = NULL;
bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0];
bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1];
bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2];
bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3];
LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP,
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0],
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1],
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2],
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]);
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0;
} else if (bsr_ce_len == sizeof(BSR_SHORT)) {
bsr_l = NULL;
bsr_s->LCGID = lcg_id_bsr_short;
bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short];
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id_bsr_short] = 0;
UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short] = 0;
LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n",
module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short],lcg_id_bsr_short);
} else {
bsr_s = NULL;
bsr_l = NULL;
}
// build PHR and update the timers
if (phr_ce_len == sizeof(POWER_HEADROOM_CMD)) {
phr_p->PH = get_phr_mapping(module_idP,CC_id,eNB_index);
phr_p->R = 0;
LOG_D(MAC,"[UE %d] Frame %d report PHR with mapping (%d->%d) for LCID %d\n",
module_idP,frameP, mac_xface->get_PHR(module_idP,CC_id,eNB_index), phr_p->PH,POWER_HEADROOM);
update_phr(module_idP,CC_id);
} else {
phr_p=NULL;
}
LOG_T(MAC,"[UE %d] Frame %d: bsr s %p bsr_l %p, phr_p %p\n", module_idP,frameP,bsr_s, bsr_l, phr_p);
if (dtch_header_len == 0 )
dtch_header_len_last =0;
// adjust the header length
dcch_header_len_tmp = dcch_header_len;
dtch_header_len_tmp = dtch_header_len;
if (dtch_header_len==0) {
dcch_header_len = (dcch_header_len>0)? 1: dcch_header_len;
} else {
dtch_header_len_last-=1;
dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len;
}
// 1-bit padding or 2-bit padding special padding subheader
padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total;
if (padding_len <= 2) {
short_padding = padding_len;
// only add padding header
post_padding = 0;
} else {
if (padding_len == buflen) {// nona mac pdu
*access_mode=CANCELED_ACCESS;
}
short_padding = 0;
if (dtch_header_len==0) {
dcch_header_len = dcch_header_len_tmp;
} else {
dtch_header_len= dtch_header_len_tmp;
}
post_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total -1 ;
}
// Generate header
// if (num_sdus>0) {
payload_offset = generate_ulsch_header(ulsch_buffer, // mac header
num_sdus, // num sdus
short_padding, // short pading
sdu_lengths, // sdu length
sdu_lcids, // sdu lcid
phr_p, // power headroom
NULL, // crnti
NULL, // truncated bsr
bsr_s, // short bsr
bsr_l,
post_padding); // long_bsr
LOG_D(MAC,
"[UE %d] Generate header :bufflen %d sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d, dcch_header_len %d, dtch_header_len %d, padding %d,post_padding %d, bsr len %d, phr len %d, reminder %d \n",
module_idP,buflen, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],payload_offset, dcch_header_len, dtch_header_len,
short_padding,post_padding, bsr_len, phr_len,buflen-sdu_length_total-payload_offset);
// cycle through SDUs and place in ulsch_buffer
memcpy(&ulsch_buffer[payload_offset],ulsch_buff,sdu_length_total);
// fill remainder of DLSCH with random data
for (j=0; j<(buflen-sdu_length_total-payload_offset); j++) {
ulsch_buffer[payload_offset+sdu_length_total+j] = (char)(taus()&0xff);
}
LOG_D(MAC,"[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n",
module_idP,payload_offset, sdu_length_total);
UE_mac_inst[module_idP].scheduling_info.SR_pending=0;
UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0;
UE_mac_inst[module_idP].BSR_reporting_active=0;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu);
if (opt_enabled) {
trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0);
LOG_D(OPT,"[UE %d][ULSCH] Frame %d trace pdu for rnti %x with size %d\n",
module_idP, UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, UE_mac_inst[module_idP].crnti, buflen);
}
}
//------------------------------------------------------------------------------
// called at each subframe
// Performs :
// 1. Trigger PDCP every 5ms
// 2. Call RRC for link status return to PHY
// 3. Perform SR/BSR procedures for scheduling feedback
// 4. Perform PHR procedures
UE_L2_STATE_t
ue_scheduler(
const module_id_t module_idP,
const frame_t frameP,
const sub_frame_t subframeP,
const lte_subframe_t directionP,
const uint8_t eNB_indexP,
const int CC_id)
//------------------------------------------------------------------------------
{
int lcid; // lcid index
int TTI= 1;
int bucketsizeduration = -1;
int bucketsizeduration_max = -1;
// mac_rlc_status_resp_t rlc_status[MAX_NUM_LCGID]; // 4
// int8_t lcg_id;
struct RACH_ConfigCommon *rach_ConfigCommon = (struct RACH_ConfigCommon *)NULL;
protocol_ctxt_t ctxt;
#if defined(ENABLE_ITTI)
MessageDef *msg_p;
const char *msg_name;
instance_t instance;
int result;
#endif
start_meas(&UE_mac_inst[module_idP].ue_scheduler);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_IN);
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_NO, UE_mac_inst[module_idP].crnti, frameP, subframeP,eNB_indexP);
#if defined(ENABLE_ITTI)
do {
// Checks if a message has been sent to MAC sub-task
itti_poll_msg (TASK_MAC_UE, &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 RRC_MAC_CCCH_DATA_REQ:
LOG_I(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;
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
//Mac_rlc_xface->frameP=frameP;
//Rrc_xface->Frame_index=Mac_rlc_xface->frameP;
//if (subframe%5 == 0)
//LG#ifdef EXMIMO
pdcp_run(&ctxt);
//#endif
UE_mac_inst[module_idP].frame = frameP;
UE_mac_inst[module_idP].subframe = subframeP;
#ifdef CELLULAR
rrc_rx_tx(module_idP, frameP, 0, eNB_indexP);
#else
switch (rrc_rx_tx(&ctxt,
eNB_indexP,
CC_id)) {
case RRC_OK:
break;
case RRC_ConnSetup_failed:
LOG_E(MAC,"RRCConnectionSetup failed, returning to IDLE state\n");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
return(CONNECTION_LOST);
break;
case RRC_PHY_RESYNCH:
LOG_E(MAC,"RRC Loss of synch, returning PHY_RESYNCH\n");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
return(PHY_RESYNCH);
case RRC_Handover_failed:
LOG_N(MAC,"Handover failure for UE %d eNB_index %d\n",module_idP,eNB_indexP);
//Invalid...need to add another MAC UE state for re-connection procedure
mac_xface->phy_config_afterHO_ue(module_idP,0,eNB_indexP,(MobilityControlInfo_t *)NULL,1);
//return(3);
break;
case RRC_HO_STARTED:
LOG_I(MAC,"RRC handover, Instruct PHY to start the contention-free PRACH and synchronization\n");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
return(PHY_HO_PRACH);
default:
break;
}
#endif
// Check Contention resolution timer (put in a function later)
if (UE_mac_inst[module_idP].RA_contention_resolution_timer_active == 1) {
if (UE_mac_inst[module_idP].radioResourceConfigCommon) {
rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon;
} else {
LOG_E(MAC,"FATAL: radioResourceConfigCommon is NULL!!!\n");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
mac_xface->macphy_exit("");
//return(RRC_OK);
}
LOG_I(MAC,"Frame %d: Contention resolution timer %d/%d\n",frameP,UE_mac_inst[module_idP].RA_contention_resolution_cnt,
((1+rach_ConfigCommon->ra_SupervisionInfo.mac_ContentionResolutionTimer)<<3));
UE_mac_inst[module_idP].RA_contention_resolution_cnt++;
if (UE_mac_inst[module_idP].RA_contention_resolution_cnt ==
((1+rach_ConfigCommon->ra_SupervisionInfo.mac_ContentionResolutionTimer)<<3)) {
UE_mac_inst[module_idP].RA_active = 0;
UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0;
// Signal PHY to quit RA procedure
LOG_E(MAC,"Module id %u Contention resolution timer expired, RA failed\n", module_idP);
mac_xface->ra_failed(module_idP,0,eNB_indexP);
}
}
// call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures
// outlined in Sections 5.4.4 an 5.4.5 of 36.321
// Call BSR procedure as described in Section 5.4.5 in 36.321
// TODO : Fix Periodic and ReTx BSR Timers
// First check ReTxBSR Timer because it is always configured
#if 1
// Decrement ReTxBSR Timer if it is running and not null
if ((UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING)
&& (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != 0)){
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF --;
}
// Decrement Periodic Timer if it is running and not null
if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING)
&& (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != 0)){
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF --;
}
#else
if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)) {
UE_mac_inst[module_idP].BSR_reporting_active = 1;
} else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ){
// trigger BSR and reset the timer later when the BSR report is sent
UE_mac_inst[module_idP].BSR_reporting_active = 1;
} else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) {
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--;
}
if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF <= 0){
// trigger BSR and reset the timer later when the BSR report is sent
UE_mac_inst[module_idP].BSR_reporting_active = 1;
} else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) {
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--;
}
#endif
// Get RLC status info and update Bj for all lcids that are active
for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) {
if ((lcid == 0) ||(UE_mac_inst[module_idP].logicalChannelConfig[lcid])) {
// meausre the Bj
if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) {
if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters) {
bucketsizeduration = UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->prioritisedBitRate * TTI;
bucketsizeduration_max = get_ms_bucketsizeduration(UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->bucketSizeDuration);
} else {
LOG_E(MAC,"[UE %d] lcid %d, NULL ul_SpecificParameters\n",module_idP,lcid);
mac_xface->macphy_exit("");
}
if ( UE_mac_inst[module_idP].scheduling_info.Bj[lcid] > bucketsizeduration_max ) {
UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = bucketsizeduration_max;
} else {
UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = bucketsizeduration;
}
}
if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) {
UE_mac_inst[module_idP].scheduling_info.SR_pending= 1;
// Regular BSR trigger
UE_mac_inst[module_idP].BSR_reporting_active = 1;
LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n",
module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid],
UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]],
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]);
}
}
}
// UE has no valid phy config dedicated || no valid/released SR
if ((UE_mac_inst[module_idP].physicalConfigDedicated == NULL)) {
// cancel all pending SRs
UE_mac_inst[module_idP].scheduling_info.SR_pending=0;
UE_mac_inst[module_idP].ul_active=0;
LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
return(CONNECTION_OK);
}
if ((UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig == NULL) ||
(UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->present == SchedulingRequestConfig_PR_release)) {
// initiate RA with CRNTI included in msg3 (no contention) as descibed in 36.321 sec 5.1.5
// cancel all pending SRs
UE_mac_inst[module_idP].scheduling_info.SR_pending=0;
UE_mac_inst[module_idP].ul_active=0;
LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP);
}
// Put this in a function
// Call PHR procedure as described in Section 5.4.6 in 36.321
if (UE_mac_inst[module_idP].PHR_state == MAC_MainConfig__phr_Config_PR_setup) { // normal operation
if (UE_mac_inst[module_idP].PHR_reconfigured == 1) { // upon (re)configuration of the power headroom reporting functionality by upper layers
UE_mac_inst[module_idP].PHR_reporting_active = 1;
UE_mac_inst[module_idP].PHR_reconfigured = 0;
} else {
//LOG_D(MAC,"PHR normal operation %d active %d \n", UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].PHR_reporting_active);
if ((UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF <= 0) &&
((mac_xface->get_PL(module_idP,0,eNB_indexP) < UE_mac_inst[module_idP].scheduling_info.PathlossChange_db) ||
(UE_mac_inst[module_idP].power_backoff_db[eNB_indexP] > UE_mac_inst[module_idP].scheduling_info.PathlossChange_db)))
// trigger PHR and reset the timer later when the PHR report is sent
{
UE_mac_inst[module_idP].PHR_reporting_active = 1;
} else if (UE_mac_inst[module_idP].PHR_reporting_active ==0 ) {
UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF--;
}
if (UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF <= 0 )
// trigger PHR and reset the timer later when the PHR report is sent
{
UE_mac_inst[module_idP].PHR_reporting_active = 1;
} else if (UE_mac_inst[module_idP].PHR_reporting_active == 0 ) {
UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF--;
}
}
} else { // release / nothing
UE_mac_inst[module_idP].PHR_reporting_active = 0; // release PHR
}
//If the UE has UL resources allocated for new transmission for this TTI here:
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT);
stop_meas(&UE_mac_inst[module_idP].ue_scheduler);
return(CONNECTION_OK);
}
// to be improved
#ifdef CBA
extern int cba_backoff;
double uniform_rngen(int min, int max)
{
double random = (double)taus()/((double)0xffffffff);
return (max - min) * random + min;
}
int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint16_t buflen)
{
mac_rlc_status_resp_t rlc_status;
int header_offset=4;
int rv =0;
/*
if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) )
// && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive
&& (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) { // backoff
// LOG_D(MAC,"[UE %d] Frame %d Subframe %d: the current CBA backoff is %d \n", module_idP, frameP, subframe,
// UE_mac_inst[module_idP].cba_last_access[0] );
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,40));
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
rv=1;
} else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) )
// && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive
&& (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){
UE_mac_inst[module_idP].cba_last_access[0]-=1;
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: CBA backoff is decreased by one to %d UL active state %d \n",
module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
} else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] == 0 )) &&
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] == 0 )) &&
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] == 0 )) )
&& (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){
UE_mac_inst[module_idP].cba_last_access[0]-=1;
}*/
if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]<64) ) {
return 0;
}
if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] <= 0 ) &&
(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] <= 0 ) &&
(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] <= 0 ) ) {
return 0;
}
if (cba_backoff == 0 ) { // apply probablisitc method
UE_mac_inst[module_idP].cba_last_access[0]= uniform_rngen(0,1);
if (uniform_rngen(0,1) > 0.6 ) {
LOG_I(MAC,"[UE %d] Frame %d Subframe %d: CBA probability-based backoff (%d), UL active state %d \n", module_idP, frameP, subframe,
cba_backoff,UE_mac_inst[module_idP].ul_active);
rv=1;
}
} else {
if (UE_mac_inst[module_idP].cba_last_access[0] <= 0) {
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,cba_backoff));
LOG_I(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], cba_backoff,UE_mac_inst[module_idP].ul_active);
rv = 1;
/*
rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index
DTCH,
0);
if ((
// (rlc_status.pdus_in_buffer > 0 ) &&
// (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive
(rlc_status.head_sdu_is_segmented == 0 ) &&
((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen )
)){
rv = 1;
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30));
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
*/
} else {
UE_mac_inst[module_idP].cba_last_access[0]-=1;
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n",
module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
}
}
return rv;
/*
if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) )
// && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive
&& (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) {
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,cba_backoff));
LOG_I(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], cba_backoff,UE_mac_inst[module_idP].ul_active);
rv = 1;
rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index
DTCH,
0);
if ((
// (rlc_status.pdus_in_buffer > 0 ) &&
// (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive
(rlc_status.head_sdu_is_segmented == 0 ) &&
((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen )
)){
rv = 1;
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30));
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
} else
UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,5));
} else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) ||
((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) )
// && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive
&& (UE_mac_inst[module_idP].cba_last_access[0]> 0) )
{
UE_mac_inst[module_idP].cba_last_access[0]-=1;
LOG_D(MAC,"[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n",
module_idP, frameP, subframe,
UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active);
}
}
*/
}
#endif
int get_bsr_lcgid (module_id_t module_idP)
{
int lcgid, lcgid_tmp=-1;
int num_active_lcgid = 0;
for (lcgid = 0 ; lcgid < MAX_NUM_LCGID; lcgid++) {
if (UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] > 0 ) {
lcgid_tmp = lcgid;
num_active_lcgid+=1;
}
}
if (num_active_lcgid == 0) {
return -1;
} else if (num_active_lcgid == 1) {
return lcgid_tmp;
} else {
return MAX_NUM_LCGID;
}
}
uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen)
{
int lcid;
uint8_t bsr_len=0, num_lcid=0;
int pdu = 0;
mac_rlc_status_resp_t rlc_status;
for (lcid=DCCH; lcid<NB_RB_MAX ; lcid++){
rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, 0);
if (rlc_status.bytes_in_buffer > 0 ) {
pdu += rlc_status.bytes_in_buffer + sizeof(SCH_SUBHEADER_SHORT) + bsr_len;
if (rlc_status.bytes_in_buffer > 128 ) {
pdu += 1; //sizeof(SCH_SUBHEADER_LONG)
}
}
if ( (pdu > buflen) && (rlc_status.bytes_in_buffer > 0 ) ) {
num_lcid +=1;
bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ;
}
else if (rlc_status.bytes_in_buffer) {
LOG_I(MAC,"pdu smaller than TBS! pdu=%d TBS=%d lcid=%d rlc buffer=%d bsr len=%d num lcid=%d\n",pdu,buflen,lcid,rlc_status.bytes_in_buffer,bsr_len, num_lcid);
}
LOG_D(MAC,"LC buffer Bytes %d for lcid %d bsr len %d num lcid %d\n", rlc_status.bytes_in_buffer, lcid, bsr_len, num_lcid);
}
if ( bsr_len > 0 )
{
LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n",
module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu);
}
else if (rlc_status.bytes_in_buffer){
LOG_I(MAC,"[UE %d] UL Transport Block size is 0 while RLC has pending data=%d pdu=%d\n",
module_idP, rlc_status.bytes_in_buffer,pdu);
}
return bsr_len;
}
boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcg_id)
{
mac_rlc_status_resp_t rlc_status;
boolean_t sr_pending = FALSE;
if ((lcg_id < 0) || (lcg_id >= MAX_NUM_LCGID) ) {
return sr_pending;
}
// fixme: need a better way to reset
if ((lcid == DCCH) || (lcid == DTCH)) {
UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id]=0;
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]=0;
}
// for (lcid =0 ; lcid < MAX_NUM_LCID; lcid++) {
if (UE_mac_inst[module_idP].scheduling_info.LCGID[lcid] == lcg_id) {
rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,ENB_FLAG_NO,MBMS_FLAG_NO,
lcid,
0);
if ((rlc_status.bytes_in_buffer > 0 )
#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0
&& (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid])
#endif
){
//BSR trigger SR
sr_pending = TRUE;
UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY;
// sum lcid buffer which has same lcgid
UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer;
UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]);
// UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr
LOG_D(MAC,"[UE %d] SR Triggered BSR level %d (LCID %d LCGID %d, rlc buffer=%d byte Total BO=%d)\n",
module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcid,lcg_id, rlc_status.bytes_in_buffer, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]);
} else {
UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid]=LCID_EMPTY;
}
}
//}
return sr_pending;
}
uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value)
{
uint8_t ju, jm, jl;
int ascend;
DevAssert( size > 0 );
DevAssert( size <= 256 );
if (value == 0) {
return 0; //elseif (value > 150000) return 63;
}
jl = 0; // lower bound
ju = size - 1; // upper bound
ascend = (table[ju] >= table[jl]) ? 1 : 0; // determine the order of the the table: 1 if ascending order of table, 0 otherwise
while (ju-jl > 1) { //If we are not yet done,
jm = (ju+jl) >> 1; //compute a midpoint,
if ((value >= table[jm]) == ascend) {
jl=jm; // replace the lower limit
} else {
ju=jm; //replace the upper limit
}
LOG_T(MAC,"[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", jm, table[jm], value);
}
if (value == table[jl]) {
return jl;
} else {
return jl+1; //equally ju
}
}
int get_sf_periodicBSRTimer(uint8_t sf_offset)
{
switch (sf_offset) {
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf5:
return 5;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf10:
return 10;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf16:
return 16;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf20:
return 20;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf32:
return 32;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf40:
return 40;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf64:
return 64;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf80:
return 80;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf128:
return 128;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf160:
return 160;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf320:
return 320;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf640:
return 640;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf1280:
return 1280;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf2560:
return 2560;
break;
case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity:
default:
return -1;
break;
}
}
int get_sf_retxBSRTimer(uint8_t sf_offset)
{
switch (sf_offset) {
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf320:
return 320;
break;
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf640:
return 640;
break;
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf1280:
return 1280;
break;
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560:
return 2560;
break;
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf5120:
return 5120;
break;
case MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf10240:
return 10240;
break;
default:
return -1;
break;
}
}
int get_ms_bucketsizeduration(uint8_t bucketsizeduration)
{
switch (bucketsizeduration) {
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50:
return 50;
break;
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100:
return 100;
break;
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150:
return 150;
break;
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300:
return 300;
break;
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500:
return 500;
break;
case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000:
return 1000;
break;
default:
return 0;
break;
}
}
void update_phr(module_id_t module_idP,int CC_id)
{
if (CC_id>0) {
LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n");
mac_xface->macphy_exit("MAC FATAL CC_id>0");
return;
}
UE_mac_inst[module_idP].PHR_reporting_active =0;
UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer);
UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer);
// LOG_D(MAC,"phr %d %d\n ",UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF);
}
uint8_t get_phr_mapping (module_id_t module_idP, int CC_id, uint8_t eNB_index)
{
if (CC_id>0) {
LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n");
mac_xface->macphy_exit("MAC FATAL CC_id>0");
return 0; // not reached
}
//power headroom reporting range is from -23 ...+40 dB, as described in 36313
//note: mac_xface->get_Po_NOMINAL_PUSCH(module_idP) is float
if (mac_xface->get_PHR(module_idP,CC_id,eNB_index) < -23) {
return 0;
} else if (mac_xface->get_PHR(module_idP,CC_id,eNB_index) >= 40) {
return 63;
} else { // -23 to 40
return (uint8_t) mac_xface->get_PHR(module_idP,CC_id,eNB_index) + PHR_MAPPING_OFFSET;
}
}
int get_sf_perioidicPHR_Timer(uint8_t perioidicPHR_Timer)
{
return (perioidicPHR_Timer+1)*10;
}
int get_sf_prohibitPHR_Timer(uint8_t prohibitPHR_Timer)
{
return (prohibitPHR_Timer)*10;
}
int get_db_dl_PathlossChange(uint8_t dl_PathlossChange)
{
switch (dl_PathlossChange) {
case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1:
return 1;
break;
case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3:
return 3;
break;
case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB6:
return 6;
break;
case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_infinity:
default:
return -1;
break;
}
}