Newer
Older
/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/*! \file ue_procedures.c
* \author Navid Nikaein and Raymond Knopp
* \date 2010 - 2014
* \version 1
* \email: navid.nikaein@eurecom.fr
* @ingroup _mac

Florian Kaltenberger
committed
#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 "OCG.h"
#include "OCG_extern.h"
#ifdef PHY_EMUL
#endif

Florian Kaltenberger
committed
#include "pdcp.h"
#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif
#define DEBUG_HEADER_PARSING 1
#define ENABLE_MAC_PAYLOAD_DEBUG
/*
#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}
};
extern inline unsigned int taus(void);
nikaeinn
committed
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_sf2560;
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.drx_config=NULL;
UE_mac_inst[module_idP].scheduling_info.phr_config=NULL;
UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer);
UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer);
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);
nikaeinn
committed
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]=0;
}
}
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_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) {
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)
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 < 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;
}
// determin the measurement gap
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);
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;
//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].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)))
){
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
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 defined(USER_MODE) && defined(OAI_EMU)
if (oai_emulation.info.opt_enabled) {
trace_pdu(1, sdu, sdu_len, module_idP, 3, UE_mac_inst[module_idP].crnti,
UE_mac_inst[module_idP].subframe, 0, 0);
}
#endif
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
for (i=0;i<num_ce;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);
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;
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,payload_ptr[0]);
payload_ptr++;
break;
case DRX_CMD:
#ifdef DEBUG_HEADER_PARSING
#endif
}
}
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
LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-CCCH, RRC message (eNB %d, %d bytes)\n",module_idP,frameP, eNB_index, rx_lengths[i]);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_T(MAC,"%x.",(uint8_t)payload_ptr[j]);
#endif
(uint8_t *)payload_ptr,rx_lengths[i],0,eNB_index,0);
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]);
DCCH,
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
}
else if (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]);
DCCH1,
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
}
else if (rx_lcids[i] == DTCH) {
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
DTCH,
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);
}
payload_ptr+= rx_lengths[i];
}
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);
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);
}
#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;
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
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;
}
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]);
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]);
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 %d] MBSFN synchronization area %d out of range for eNB %d\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;
LOG_W(MAC,"[UE %d] MBSFN Subframe Config pattern %d 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 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);
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->lte_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->lte_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->lte_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->lte_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->lte_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->lte_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->lte_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->lte_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);
else {// four-frameP format
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;
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",
((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;