Commit 4269152f authored by Nick Ho's avatar Nick Ho

MAC LAYER NB-IoT function first added

parent 5da7305f
/*! \file config_NB_IoT.c
* \brief configuration primitives between RRC and MAC
* \author NTUST BMW Lab./
* \date 2019
* \email:
* \version 2.0
*
*/
#include "LAYER2/MAC/defs_NB_IoT.h"
#include "LAYER2/MAC/proto_NB_IoT.h"
#include "LAYER2/MAC/extern_NB_IoT.h"
#include "LTE_BCCH-DL-SCH-Message-NB.h"
#include "LTE_RRCConnectionSetup-NB.h"
#include "LTE_BCCH-BCH-Message-NB.h"
//#include "SIB-Type-NB-r13.h"
typedef struct eutra_bandentry_NB_s {
//this should be the colum order of the table below (eutra_bandtable)
int16_t band;
uint32_t ul_min;
uint32_t ul_max;
uint32_t dl_min;
uint32_t dl_max;
uint32_t N_OFFs_DL;
} eutra_bandentry_NB_IoT_t;
typedef struct band_info_s {
int nbands;
eutra_bandentry_NB_IoT_t band_info[100];
} band_info_t;
//[BAND] [FUL_low] [FUL_hi] [FDL_low] [FDL_hig] [NOFF_DL]
static const eutra_bandentry_NB_IoT_t eutra_bandtable[] = {
{ 1, 19200, 19800, 21100, 21700, 0},
{ 2, 18500, 19100, 19300, 19900, 6000},
{ 3, 17100, 17850, 18050, 18800, 12000},
{ 5, 8240, 8490, 8690, 8940, 24000},
{ 8, 8800, 9150, 9250, 9600, 34500},
{11, 14279, 14529, 14759, 15009, 47500},
{12, 6980, 7160, 7280, 7460, 50100},
{13, 7770, 7870, 7460, 7560, 51800},
{17, 7040, 7160, 7340, 7460, 57300},
{18, 8150, 9650, 8600, 10100, 58500},
{19, 8300, 8450, 8750, 8900, 60000},
{20, 8320, 8620, 7910, 8210, 61500},
{25, 18500, 19150, 19300, 19950, 80400},
{26, 8140, 8490, 8590, 8940, 86900},
{28, 7030, 7580, 7580, 8130, 92100},
{31, 45250, 34900, 46250, 35900, 98700},
{66, 17100, 18000, 21100, 22000, 664360},
{70, 16950 , 17100, 19950, 20200, 683360}}; //may not used for Rel.13 equipment
//used for getting the DL Carrier Frequency from the EARFCN
uint32_t from_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_earfcn, float m_dl) {
int i;
// float m_dl = 0; //for the moment we fix but maybe should be dynamic (anyway the 0 works for any case)
AssertFatal(eutra_bandP <= 70,"eutra_band %d > 70\n",eutra_bandP);
for (i=0;i<= 70 && eutra_bandtable[i].band!=eutra_bandP;i++);
// this function is given by TS 36.104 Release 13.2 CH 5.7.3
return(eutra_bandtable[i].dl_min + 0.0025*(2*m_dl+1)+(dl_earfcn-(eutra_bandtable[i].N_OFFs_DL/10)))*100000;
}
int32_t get_uldl_offset_NB_IoT(int eutra_band) {
return(-eutra_bandtable[eutra_band].dl_min + eutra_bandtable[eutra_band].ul_min);
}
uint32_t to_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_CarrierFreq, float m_dl) {
uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq/100000;
int i;
AssertFatal(eutra_bandP < 70,"eutra_band %d > 70\n",eutra_bandP);
for (i=0;i<69 && eutra_bandtable[i].band!=eutra_bandP;i++);
AssertFatal(dl_CarrierFreq_by_100k>=eutra_bandtable[i].dl_min,
"Band %d : DL carrier frequency %u Hz < %u\n",
eutra_bandP,dl_CarrierFreq,eutra_bandtable[i].dl_min);
//based on formula TS 36.101 5.7.3F
return(dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min - 0.0025*(2*m_dl+ 1)+ (eutra_bandtable[i].N_OFFs_DL/10));
}
void config_mib_fapi_NB_IoT(int physCellId,
uint8_t eutra_band,
int Ncp,
int Ncp_UL,
int p_eNB,
int p_rx_eNB,
int dl_CarrierFreq,
int ul_CarrierFreq,
long *eutraControlRegionSize,
LTE_BCCH_BCH_Message_NB_t *mib_NB_IoT
)
{
nfapi_config_request_t *cfg = &mac_inst->config;
cfg->sch_config.physical_cell_id.value = physCellId;
cfg->nfapi_config.rf_bands.rf_band[0] = eutra_band;
cfg->subframe_config.dl_cyclic_prefix_type.value = Ncp;
cfg->subframe_config.ul_cyclic_prefix_type.value = Ncp_UL;
cfg->rf_config.tx_antenna_ports.value = p_eNB;
cfg->nfapi_config.earfcn.value = 9370; // value from taiwan commercial base station, just setting for now, will use formula to calculate it layer
//cfg->nb_iot_config.prb_index.value = // need to set in thread part
switch (mib_NB_IoT->message.operationModeInfo_r13.present)
{
//FAPI specs pag 135
case LTE_MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_SamePCI_r13:
cfg->nb_iot_config.operating_mode.value = 0;
cfg->nb_iot_config.prb_index.value = mib_NB_IoT->message.operationModeInfo_r13.choice.inband_SamePCI_r13.eutra_CRS_SequenceInfo_r13; //see TS 36.213 ch 16.0
cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
if(eutraControlRegionSize == NULL)
LOG_E(RRC, "rrc_mac_config_req_eNB_NB_IoT: operation mode is in-band but eutraControlRegionSize is not defined\n");
else
cfg->nb_iot_config.control_region_size.value = *eutraControlRegionSize;
break;
case LTE_MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_DifferentPCI_r13:
cfg->nb_iot_config.operating_mode.value = 1;
//fapi think to define also eutra_CRS_sequenceInfo also for in band with different PCI but the problem is that we don-t have i
cfg->nb_iot_config.assumed_crs_aps.value = mib_NB_IoT->message.operationModeInfo_r13.choice.inband_DifferentPCI_r13.eutra_NumCRS_Ports_r13;
if(eutraControlRegionSize == NULL)
LOG_E(RRC, "rrc_mac_config_req_eNB_NB_IoT: operation mode is in-band but eutraControlRegionSize is not defined\n");
else
cfg->nb_iot_config.control_region_size.value = *eutraControlRegionSize;
break;
case LTE_MasterInformationBlock_NB__operationModeInfo_r13_PR_guardband_r13:
cfg->nb_iot_config.operating_mode.value = 2;
cfg->nb_iot_config.control_region_size.value = -1; //should not being defined so we put a negative value
cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
break;
case LTE_MasterInformationBlock_NB__operationModeInfo_r13_PR_standalone_r13:
cfg->nb_iot_config.operating_mode.value = 3;
cfg->nb_iot_config.prb_index.value = -1; // is not defined for this case (put a negative random value--> will be not considered for encoding, scrambling procedures)
cfg->nb_iot_config.control_region_size.value = -1; //is not defined so we put a negative value
cfg->nb_iot_config.assumed_crs_aps.value = -1; //is not defined so we put a negative value
break;
default:
LOG_E(RRC, "rrc_mac_config_req_eNB_NB_IoT: NB-IoT operating Mode (MIB-NB) not set\n");
break;
}
}
void config_sib2_fapi_NB_IoT(
int physCellId,
LTE_RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon
)
{
nfapi_config_request_t *cfg = &mac_inst->config;
/*
* Following the FAPI like approach:
* 1) fill the PHY_Config_t structure (PHY_INTERFACE/IF_Module_NB_IoT.h)
* 1.1) check for how many NPRACH resources has been set and enable the corresponding parameter
* 1.2) fill the structure PHY_Config_t (shared structure of the IF_Module
* 2) Call the PHY_config_req for trigger the NB_phy_config_sib2_eNB()
*/
/*NPRACH section*/
LTE_NPRACH_Parameters_NB_r13_t* nprach_parameter;
cfg->nb_iot_config.nprach_config_0_enabled.value = 0;
cfg->nb_iot_config.nprach_config_1_enabled.value = 0;
cfg->nb_iot_config.nprach_config_2_enabled.value = 0;
if(radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0]!=NULL&&radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1]!=NULL&&radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[2]!=NULL)
{
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0];
cfg->nb_iot_config.nprach_config_0_enabled.value = 1;
cfg->nb_iot_config.nprach_config_0_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
cfg->nb_iot_config.nprach_config_0_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
cfg->nb_iot_config.nprach_config_0_start_time.value = nprach_parameter->nprach_StartTime_r13;
cfg->nb_iot_config.nprach_config_0_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
cfg->nb_iot_config.nprach_config_0_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
cfg->nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
//rsrp_ThresholdsPrachInfoList_r13 -> optional
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1];
cfg->nb_iot_config.nprach_config_1_enabled.value = 1;
cfg->nb_iot_config.nprach_config_1_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
cfg->nb_iot_config.nprach_config_1_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
cfg->nb_iot_config.nprach_config_1_start_time.value = nprach_parameter->nprach_StartTime_r13;
cfg->nb_iot_config.nprach_config_1_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
cfg->nb_iot_config.nprach_config_1_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
cfg->nb_iot_config.nprach_config_1_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
//rsrp_ThresholdsPrachInfoList_r13 -> optional
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[2];
cfg->nb_iot_config.nprach_config_2_enabled.value = 1;
cfg->nb_iot_config.nprach_config_2_cp_length.value = radioResourceConfigCommon->nprach_Config_r13.nprach_CP_Length_r13;
cfg->nb_iot_config.nprach_config_2_sf_periodicity.value = nprach_parameter->nprach_Periodicity_r13;
cfg->nb_iot_config.nprach_config_2_start_time.value = nprach_parameter->nprach_StartTime_r13;
cfg->nb_iot_config.nprach_config_2_subcarrier_offset.value = nprach_parameter->nprach_SubcarrierOffset_r13;
cfg->nb_iot_config.nprach_config_2_number_of_subcarriers.value = nprach_parameter->nprach_NumSubcarriers_r13;
cfg->nb_iot_config.nprach_config_2_number_of_repetitions_per_attempt.value = nprach_parameter->numRepetitionsPerPreambleAttempt_r13;
//rsrp_ThresholdsPrachInfoList_r13 -> optional
}else
{
LOG_E(MAC,"NPRACH Configuration isn't set properly\n");
}
LOG_I(MAC,"Fill parameters of FAPI NPRACH done\n");
/*NPDSCH ConfigCommon*/
//FAPI specs define a range of value [0-255]==[0db - 63.75db] with 0.25db step -- corrispondence in Ts 36.213 CH 16.2.2
cfg->rf_config.reference_signal_power.value = radioResourceConfigCommon->npdsch_ConfigCommon_r13.nrs_Power_r13;
/*NPUSCH ConfigCommon*/
if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13 != NULL)/* OPTIONAL */
{
/* OPTIONAL */
if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_BaseSequence_r13!= NULL)
cfg->nb_iot_config.three_tone_base_sequence.value = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_BaseSequence_r13);
else
cfg->nb_iot_config.three_tone_base_sequence.value = physCellId%12; //see spec TS 36.331 NPUSCH-Config-NB
/* OPTIONAL */
if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_BaseSequence_r13!= NULL)
cfg->nb_iot_config.six_tone_base_sequence.value = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_BaseSequence_r13);
else
cfg->nb_iot_config.six_tone_base_sequence.value = physCellId%14; //see spec TS 36.331 NPUSCH-Config-NB
/* OPTIONAL */
if(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->twelveTone_BaseSequence_r13!= NULL)
cfg->nb_iot_config.twelve_tone_base_sequence.value = *(radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->twelveTone_BaseSequence_r13);
else
cfg->nb_iot_config.twelve_tone_base_sequence.value = physCellId%30; //see spec TS 36.331 NPUSCH-Config-NB
cfg->nb_iot_config.three_tone_cyclic_shift.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->threeTone_CyclicShift_r13;
cfg->nb_iot_config.six_tone_cyclic_shift.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.dmrs_Config_r13->sixTone_CyclicShift_r13;
}
//NOTE: MP: FAPI specs for UL RS Configurations seems to be targeted for LTE and not for NB-IoT
if(radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13 == TRUE)
cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; //RS_GROUP_HOPPING (FAPI specs pag 127)
else
cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0;//RS_NO_HOPPING
cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommon->npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13;
//srs_SubframeConfig_r13 /* OPTIONAL */
/*DL GAP config */
if(radioResourceConfigCommon->dl_Gap_r13 !=NULL)/* OPTIONAL */
{
cfg->nb_iot_config.dl_gap_config_enable.value = 1;
cfg->nb_iot_config.dl_gap_threshold.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapThreshold_r13;
cfg->nb_iot_config.dl_gap_duration_coefficient.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapDurationCoeff_r13;
cfg->nb_iot_config.dl_gap_periodicity.value = radioResourceConfigCommon->dl_Gap_r13->dl_GapPeriodicity_r13;
}
else
cfg->nb_iot_config.dl_gap_config_enable.value = 0;
/*UL Power Control ConfigCommon*/
//nothing defined in FAPI specs
/*RACH Config Common*/
//nothing defined in FAPI specs
}
// Called by init_testing_NB_IoT, configure and initiate NB-IoT MAC and PHY here
void rrc_mac_config_req_NB_IoT(
module_id_t Mod_idP,
int CC_idP,
int rntiP,
rrc_eNB_carrier_data_NB_IoT_t *carrier,
LTE_SystemInformationBlockType1_NB_t *sib1_NB_IoT,
LTE_RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon,
LTE_PhysicalConfigDedicated_NB_r13_t *physicalConfigDedicated,
LTE_LogicalChannelConfig_NB_r13_t *logicalChannelConfig,
uint8_t ded_flag,
uint8_t ue_list_ded_num)
{
int UE_id = -1;
rrc_config_NB_IoT_t *mac_config=NULL;
mac_top_init_eNB_NB_IoT();
mac_config = &mac_inst->rrc_config;
long schedulingInfoSIB1 = carrier->mib_NB_IoT.message.schedulingInfoSIB1_r13;
if(ded_flag==0)
{
LOG_D(MAC,"Initiate config by system information\n");
}else
{
// now we only have 3 UE list USS for three CE levels
// fix value for RMAX to 8 / 16 / 32
mac_config->npdcch_ConfigDedicated[ue_list_ded_num].R_max = 8 + 8*ue_list_ded_num;
// fix value for G to 8 / 4 / 2
mac_config->npdcch_ConfigDedicated[ue_list_ded_num].G = 2 + (2-ue_list_ded_num)*(3-ue_list_ded_num);
// fix a_offest to 0 / 0 / 0
mac_config->npdcch_ConfigDedicated[ue_list_ded_num].a_offset = 0;
return;
}
if (&carrier->mib_NB_IoT != NULL)
{
/*
* Following the FAPI like approach:
* 1) fill the PHY_Config_t structure (PHY_INTERFACE/IF_Module_NB_IoT.h)
* 2) Call the PHY_config_req for trigger the NB_phy_config_mib_eNB() at the end
*/
//Mapping OAI params into FAPI params
config_mib_fapi_NB_IoT(carrier->physCellId,
sib1_NB_IoT->freqBandIndicator_r13,
carrier->Ncp,
carrier->Ncp_UL,
carrier->p_eNB,
carrier->p_rx_eNB,
carrier->dl_CarrierFreq,
carrier->ul_CarrierFreq,
sib1_NB_IoT->eutraControlRegionSize_r13,
&carrier->mib_NB_IoT
);
}else
{
LOG_E(MAC,"carrier->mib_NB_IoT is NULL\n");
return;
}
if(sib1_NB_IoT != NULL)
{
if(schedulingInfoSIB1 <=11)
{
// the value come from table 16.4.1.3-3 from TS 36.213
switch(schedulingInfoSIB1%3)
{
case 0:
mac_config->sib1_NB_IoT_sched_config.repetitions = 4;
// the value come from table 16.4.1.3-4 from TS 36.213
mac_config->sib1_NB_IoT_sched_config.starting_rf = (carrier->physCellId % 4) * 16;
break;
case 1:
mac_config->sib1_NB_IoT_sched_config.repetitions = 8;
mac_config->sib1_NB_IoT_sched_config.starting_rf = (carrier->physCellId % 2) * 16;
break;
case 2:
mac_config->sib1_NB_IoT_sched_config.repetitions = 16;
mac_config->sib1_NB_IoT_sched_config.starting_rf = carrier->physCellId % 2;
break;
}
}else
LOG_E(MAC,"SchedulinginfoSIB1 value not available!\n");
mac_config->si_window_length = ms160;
///OAI only supports SIB2/3-NB for the system information
mac_config->sibs_NB_IoT_sched[0].si_periodicity = si_Periodicity_rf64 ;
mac_config->sibs_NB_IoT_sched[0].si_repetition_pattern = si_RepetitionPattern_every4thRF;
mac_config->sibs_NB_IoT_sched[0].sib_mapping_info = sib3_v;
mac_config->sibs_NB_IoT_sched[0].si_tb = si_TB_680;
LOG_D(MAC,"si_periodicity:%d, siw: %d, start rf: %d\n",mac_config->sibs_NB_IoT_sched[0].si_periodicity, mac_config->si_window_length,mac_config->sib1_NB_IoT_sched_config.starting_rf);
}else
{
LOG_E(MAC,"sib1_NB_IoT is NULL\n");
}
if (radioResourceConfigCommon!=NULL)
{
//LOG_I(MAC,"[CONFIG]SIB2/3-NB radioResourceConfigCommon Contents (partial)\n");
LTE_NPRACH_Parameters_NB_r13_t* nprach_parameter;
//CE level 0
if ( radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0] != NULL)
{
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[0];
LOG_I(MAC,"NPRACH CE 0 setting: NumRepetition: %ld Period: %ld size of list %d\n",nprach_parameter->numRepetitionsPerPreambleAttempt_r13,nprach_parameter->nprach_Periodicity_r13,radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.size);
mac_config->mac_NPRACH_ConfigSIB[0].mac_numRepetitionsPerPreambleAttempt_NB_IoT = rachrepeat[nprach_parameter->numRepetitionsPerPreambleAttempt_r13];
mac_config->mac_NPRACH_ConfigSIB[0].mac_npdcch_NumRepetitions_RA_NB_IoT = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[0].mac_npdcch_StartSF_CSS_RA_NB_IoT = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[0].mac_npdcch_Offset_RA_NB_IoT = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
mac_inst->npdcch_config_common[0].R_max = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_inst->npdcch_config_common[0].G = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_inst->npdcch_config_common[0].a_offset = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
LOG_I(MAC,"NPRACH CE 0 setting: Rmax: %lu G: %lf a: %lf\n",mac_inst->npdcch_config_common[0].R_max,mac_inst->npdcch_config_common[0].G,mac_inst->npdcch_config_common[0].a_offset);
}
//CE level 1
if ( radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1] != NULL)
{
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[1];
LOG_I(MAC,"NPRACH CE 1 setting: NumRepetiion: %ld size of list %d\n",nprach_parameter->numRepetitionsPerPreambleAttempt_r13,radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.size);
mac_config->mac_NPRACH_ConfigSIB[1].mac_numRepetitionsPerPreambleAttempt_NB_IoT = rachrepeat[nprach_parameter->numRepetitionsPerPreambleAttempt_r13];
mac_config->mac_NPRACH_ConfigSIB[1].mac_npdcch_NumRepetitions_RA_NB_IoT = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[1].mac_npdcch_StartSF_CSS_RA_NB_IoT = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[1].mac_npdcch_Offset_RA_NB_IoT = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
mac_inst->npdcch_config_common[1].R_max = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_inst->npdcch_config_common[1].G = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_inst->npdcch_config_common[1].a_offset = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
LOG_I(MAC,"NPRACH CE 1 setting: Rmax: %lu G: %lf a: %lf\n",mac_inst->npdcch_config_common[1].R_max,mac_inst->npdcch_config_common[1].G,mac_inst->npdcch_config_common[1].a_offset);
}
//CE level 2
if ( radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[2] != NULL)
{
nprach_parameter = radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.array[2];
LOG_I(MAC,"NPRACH CE 2 setting: NumRepetiion: %ld size of list %d\n",nprach_parameter->numRepetitionsPerPreambleAttempt_r13,radioResourceConfigCommon->nprach_Config_r13.nprach_ParametersList_r13.list.size);
mac_config->mac_NPRACH_ConfigSIB[2].mac_numRepetitionsPerPreambleAttempt_NB_IoT = rachrepeat[nprach_parameter->numRepetitionsPerPreambleAttempt_r13];
mac_config->mac_NPRACH_ConfigSIB[2].mac_npdcch_NumRepetitions_RA_NB_IoT = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[2].mac_npdcch_StartSF_CSS_RA_NB_IoT = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_config->mac_NPRACH_ConfigSIB[2].mac_npdcch_Offset_RA_NB_IoT = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
mac_inst->npdcch_config_common[2].R_max = rmax[nprach_parameter->npdcch_NumRepetitions_RA_r13];
mac_inst->npdcch_config_common[2].G = gvalue[nprach_parameter->npdcch_StartSF_CSS_RA_r13];
mac_inst->npdcch_config_common[2].a_offset = pdcchoffset[nprach_parameter->npdcch_Offset_RA_r13];
LOG_I(MAC,"NPRACH CE 2 setting: Rmax: %lu G: %lf a: %lf\n",mac_inst->npdcch_config_common[2].R_max,mac_inst->npdcch_config_common[2].G,mac_inst->npdcch_config_common[2].a_offset);
}
config_sib2_fapi_NB_IoT(carrier->physCellId,radioResourceConfigCommon);
}else
{
LOG_E(MAC,"radioResourceConfigCommon is NULL\n");
}
if (logicalChannelConfig!= NULL) {
if (UE_id == -1)
{
LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__);
}
else
{
//logical channel group not defined for nb-iot --> no UL specific Parameter
// or at least LCGID should be set to 0 for NB-IoT (See TS 36.321 ch 6.1.3.1) so no make sense to store this
}
}
if (physicalConfigDedicated != NULL) {
if (UE_id == -1)
LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__);
else
{
LOG_D(MAC,"UE id = %d\n",UE_id);
}
}
if(mac_inst->if_inst_NB_IoT!=NULL)
{
if (radioResourceConfigCommon!=NULL)
{
AssertFatal( mac_inst->if_inst_NB_IoT->PHY_config_req != NULL, "rrc_mac_config_req_eNB_NB_IoT: PHY_config_req pointer function is NULL\n");
PHY_Config_NB_IoT_t phycfg;
phycfg.mod_id = Mod_idP;
phycfg.cfg = &mac_inst->config;
if (mac_inst->if_inst_NB_IoT->PHY_config_req)
mac_inst->if_inst_NB_IoT->PHY_config_req(&phycfg);
}
}else
{
LOG_E(MAC,"NB-IoT IF INST is NULL, need to fix\n");
}
init_mac_NB_IoT(mac_inst);
LOG_I(MAC,"[NB-IoT] Init_MAC done\n");
}
......@@ -229,7 +229,7 @@ typedef struct sibs_NB_IoT_sched_s{
si_periodicity_t si_periodicity;
si_repetition_pattern_t si_repetition_pattern;
sib_MappingInfo_NB_IoT sib_mapping_info; //bit vector
si_tb_t si_tb;
si_TB_NB_IoT si_tb;
} sibs_NB_IoT_sched_t;
......
......@@ -15,7 +15,7 @@
#endif
//#include "COMMON/openair_defs.h"
#include "COMMON/platform_constants.h"
#include "COMMON/mac_rrc_primitives.h"
//#include "COMMON/mac_rrc_primitives.h"
#include "PHY/NBIoT_TRANSPORT/defs_NB_IoT.h"
//#include "PHY/defs.h"
#include "PHY/defs_L1_NB_IoT.h"
......
/*! \file eNB_scheduler_NB_IoT.c
* \brief top level of the scheduler, it scheduled in pdcch period based.
* \author NTUST BMW Lab./
* \date 2017
* \email:
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
// scheduler
#define flag_css_type1 0x1
#define flag_css_type2 0x2
#define flag_uss_v 0x4
// common
#define flag_mib 0x1
#define flag_sib1 0x2
#define flag_npss 0x4
#define flag_nsss 0x8
unsigned char str22[] = "UL_Data";
unsigned char str23[] = "DCI_N0";
//extern BCCH_DL_SCH_Message_NB_IoT_t SIB;
void eNB_scheduler_computing_flag_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint32_t *scheduler_flags, uint32_t *common_flags, uint32_t *max_subframe){
uint32_t subframe = abs_subframe % 10;
uint32_t frame = abs_subframe / 10;
int i;
uint32_t max = 0;
//NPRACH_Parameters_NB_IoT_r13_t **type2_css_info = SIB.message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.choice.sib2_r13.radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list.array;
// fixed scheduling part (e.g. MIB, NPSS, NSSS, SIB1)
if(subframe == 0){
*common_flags |= flag_mib;
}else if(subframe == 5){
*common_flags |= flag_npss;
}else if(subframe == 9 && (frame&0x1)==0){
*common_flags |= flag_nsss;
}else if(subframe == 4 && mac_inst->sib1_flag[frame%mac_inst->sib1_period]){
*common_flags |= flag_sib1;
}
uint32_t type2_css_pp[3] = { mac_inst->npdcch_config_common[0].R_max*mac_inst->npdcch_config_common[0].G,
mac_inst->npdcch_config_common[1].R_max*mac_inst->npdcch_config_common[1].G,
mac_inst->npdcch_config_common[2].R_max*mac_inst->npdcch_config_common[2].G };
uint32_t start_subframe;
for(i=0; i<1; ++i){ // only CE0
if(mac_inst->npdcch_config_common[i].a_offset==0)
{
start_subframe = 0;
}
else if(mac_inst->npdcch_config_common[i].a_offset==1/8)
{
start_subframe = type2_css_pp[i]>>3;
}
else if(mac_inst->npdcch_config_common[i].a_offset==1/4)
{
start_subframe = type2_css_pp[i]>>2;
}
else if(mac_inst->npdcch_config_common[i].a_offset==3/8)
{
start_subframe = (type2_css_pp[i]>>3)+(type2_css_pp[i]>>2);
}
if(((abs_subframe+1)%type2_css_pp[i])==start_subframe){
*scheduler_flags |= flag_css_type2;
max = MAX(max, extend_space[i]);
LOG_D(MAC,"[%d][computing flags] common searching space: %d, num subframe: %d\n", mac_inst->current_subframe, i, extend_space[i]);
}
}
//USS trigger flag
for(i=0;i<mac_inst->num_uss_list;++i)
{
if(((abs_subframe+1)%mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T)==mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.ss_start_uss)
{
*scheduler_flags |= (flag_uss_v<<i);
max = MAX(max, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T);
LOG_D(MAC,"[%d][computing flags] UE-spec searching space: %d, num subframe: %d\n", mac_inst->current_subframe, i, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T);
}
}
*max_subframe = max; // the maximum subframe to be extend
}
/*function description:
* top level of the scheduler, this will trigger in every subframe,
* and determined if do the schedule by checking this current subframe is the start of the NPDCCH period or not
*/
void eNB_dlsch_ulsch_scheduler_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe){
int i;
uint8_t MIB_flag = 0, SIB1_flag = 0;
uint32_t scheduler_flags, max_subframe, common_flags;
/*Check this subframe should schedule something, set the flag*/
scheduler_flags = 0;
common_flags = 0;
uint32_t h,f,sf,a;
mac_inst->current_subframe = abs_subframe;
eNB_scheduler_computing_flag_NB_IoT(mac_inst, abs_subframe, &scheduler_flags, &common_flags, &max_subframe);
if(scheduler_flags > 0){
extend_available_resource_DL(mac_inst, mac_inst->current_subframe +1 + max_subframe);
}
maintain_available_resource(mac_inst);
if((abs_subframe % nprach_list->nprach_Periodicity) == rachstart[0]){ //TODO, configuration should be pass by configuration module
add_UL_Resource();
}
//Check if type2 searching space scheduling
if((scheduler_flags&flag_css_type2)>0){
schedule_RA_NB_IoT(mac_inst);
scheduler_flags &= ~(flag_css_type2);
}
//Check if type1 searching space scheduling
if((scheduler_flags&flag_css_type1)>0){
// paging, direct indication
scheduler_flags &= ~(flag_css_type1);
}
//The scheduling time is current subframe + 1
convert_system_number(abs_subframe+1, &h, &f, &sf);
// loop all USS period
for(i=0;i<mac_inst->num_uss_list;++i)
{
if((scheduler_flags&(flag_uss_v<<i))>0){
LOG_D(MAC,"--------------[%04d][SchedulerUSS] Schedule USS list %d------------\n", mac_inst->current_subframe, (scheduler_flags&(flag_uss_v<<i))>>3);
schedule_uss_NB_IoT(0, mac_inst,sf, f, h, i);
LOG_D(MAC,"--------------[%04d][SchedulerUSS] Schedule USS list %d end------------\n", mac_inst->current_subframe, (scheduler_flags&(flag_uss_v<<i))>>3);
scheduler_flags &= ~(flag_uss_v<<i);
}
}
if(common_flags == flag_mib)
MIB_flag = 1;
if(common_flags == flag_sib1)
SIB1_flag = 1;
convert_system_number(abs_subframe, &h, &f, &sf);
a = output_handler(mac_inst, 0,0,h,f,sf,MIB_flag,SIB1_flag, abs_subframe);
if(a==-1)
LOG_I(MAC,"[%04d][SchedulerUSS] schedule result is empty------------\n", mac_inst->current_subframe);
}
void USS_scheduling_module(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint8_t total_num_UE_list)
{
int i, max_subframe,MIB_flag,SIB1_flag;
/*Check this subframe should schedule something, set the flag*/
MIB_flag = 0;
SIB1_flag = 0;
max_subframe=0;
uint32_t h,f,sf;
int a;
int UE_list_index;
// how many scheduling is triggered this sunframe
uint8_t num_sched_UE_list=0;
uint8_t *UE_list_flag=(uint8_t*)malloc(total_num_UE_list*sizeof(uint8_t));
//DEBUG("[%04d][USS_scheduling_module] check scheduling trigger\n", mac_inst->current_subframe);
//eNB_scheduler_computing_flag_NB_IoT(mac_inst, abs_subframe, &scheduler_flags, &common_flags, &max_subframe);
// Check which scheduling period of UE_list is triggered
for(i=0;i<total_num_UE_list;++i)
{
if(((abs_subframe+1)%mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T)==mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.ss_start_uss)
//if((abs_subframe+1)%16==0)
{
if(mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T>max_subframe)
{
max_subframe=mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T;
}
UE_list_flag[i]=1;
num_sched_UE_list++;
//*scheduler_flags |= (flag_uss_v<<i);
//max = MAX(max, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T);
LOG_D(MAC,"[%d][USS_scheduling_module] UE_list num: %d, num subframe: %d\n", mac_inst->current_subframe, i, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T);
}
else
{
UE_list_flag[i]=0;
}
}
// Update available resource
if(num_sched_UE_list > 0)
{
LOG_D(MAC,"[%d][USS_scheduling_module] extend resource\n", mac_inst->current_subframe);
//DEBUG("[%04d][USS_scheduling_module] In extend_available_resource_DL\n", mac_inst->current_subframe);
extend_available_resource_DL(mac_inst, mac_inst->current_subframe +1 + max_subframe);
}
maintain_available_resource(mac_inst);
// reserve resource for NPRACH
if((abs_subframe % nprach_list->nprach_Periodicity) == rachstart[0])
{
//DEBUG("[%04d][USS_scheduling_module] In add_UL_Resource\n", mac_inst->current_subframe);
add_UL_Resource();
}
//The scheduling time is current subframe + 1
convert_system_number(abs_subframe+1, &h, &f, &sf);
// loop all USS period
for(UE_list_index=0;UE_list_index<total_num_UE_list;++UE_list_index)
{
//if((scheduler_flags&(flag_uss_v<<i))>0){
if(UE_list_flag[UE_list_index]==1)
{
LOG_D(MAC,"--------------[%04d][USS_scheduling_module] Schedule USS list %d------------\n", mac_inst->current_subframe, UE_list_index);
//USS Scheduling for corresponding index
schedule_uss_NB_IoT(0, mac_inst,sf, f, h, UE_list_index);
LOG_D(MAC,"--------------[%04d][USS_scheduling_module] Schedule USS list %d end------------\n", mac_inst->current_subframe, UE_list_index);
//scheduler_flags &= ~(flag_uss_v<<i);
}
}
// flag for generating SIB1 and MIB message
if(abs_subframe%10 == 0)
MIB_flag = 1;
if(abs_subframe%10 == 4 && mac_inst->sib1_flag[abs_subframe/10%mac_inst->sib1_period])
SIB1_flag = 1;
// handling output to L1
a = output_handler(mac_inst, 0,0,h,f,sf,MIB_flag,SIB1_flag, abs_subframe);
if(a==-1)
LOG_D(MAC,"[%04d][USS_scheduling_module] schedule result is empty------------\n", mac_inst->current_subframe);
}
void schedule_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index)
{
UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info;
UE_TEMPLATE_NB_IoT *UE_template_temp;
DCIFormatN1_t *DCI_N1;
DCIFormatN0_t *DCI_N0;
//SCHEDULE_NB_IoT_t *scheduler = &eNB->scheduler;
mac_inst->scheduling_flag.flag_uss[0]=1;
mac_inst->scheduling_flag.flag_uss[1]=0;
mac_inst->scheduling_flag.flag_uss[2]=0;
mac_inst->scheduling_flag.num_uss_run = 0;
int UE_ID;
//search space index
//int index_ss=0;
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Start processing preprocessor\n", mac_inst->current_subframe);
/***algorithm for USS scheduling***/
preprocessor_uss_NB_IoT(module_id, mac_inst, subframe, frame, hypersfn, UE_list_index);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Finish processing preprocessor\n", mac_inst->current_subframe);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Do USS Final Scheduling\n", mac_inst->current_subframe);
UE_ID = mac_inst->UE_list_spec[UE_list_index].head;
while(UE_ID>-1)
{
UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[UE_ID]);
UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[UE_ID]);
LOG_D(MAC,"------Start Scheduling USS UE RNTI %d------\n", UE_template_temp->rnti);
if((UE_template_temp->RRC_connected==1)&&(UE_sched_ctrl_info->flag_schedule_success==1))
{
switch(UE_template_temp->direction)
{
case 1: // Downlink Scheduling
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] USS DL Final scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDCCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDSCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDSCH_sf_start, UE_sched_ctrl_info->NPDSCH_sf_end);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl HARQ information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->HARQ_sf_start, UE_sched_ctrl_info->HARQ_sf_end);
DCI_N1 = (DCIFormatN1_t*)malloc(sizeof(DCIFormatN1_t));
fill_DCI_N1(DCI_N1, UE_template_temp, UE_sched_ctrl_info);
generate_scheduling_result_DL(UE_sched_ctrl_info->NPDCCH_sf_end, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDSCH_sf_end, UE_sched_ctrl_info->NPDSCH_sf_start, UE_sched_ctrl_info->HARQ_sf_end, UE_sched_ctrl_info->HARQ_sf_start, DCI_N1, UE_template_temp->rnti, UE_sched_ctrl_info->TBS, UE_template_temp->DLSCH_pdu.payload);
UE_template_temp->R_dci=UE_sched_ctrl_info->R_dci;
UE_template_temp->R_dl=UE_sched_ctrl_info->R_dl_data;
UE_template_temp->I_mcs_dl=UE_sched_ctrl_info->dci_n1_index_mcs;
UE_template_temp->DLSCH_pdu_size=UE_sched_ctrl_info->TBS;
if(UE_template_temp->HARQ_round==0)
UE_template_temp->oldNDI_DL=(UE_template_temp->oldNDI_DL+1)%2;
break;
case 0: // Uplink
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] USS UL Final scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDCCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end);
LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPUSCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPUSCH_sf_start, UE_sched_ctrl_info->NPUSCH_sf_end);
DCI_N0 = (DCIFormatN0_t*)malloc(sizeof(DCIFormatN0_t));
//generate DCI-N0 content
fill_DCI_N0(DCI_N0, UE_template_temp, UE_sched_ctrl_info);
generate_scheduling_result_UL(UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end,UE_sched_ctrl_info->NPUSCH_sf_start+3, UE_sched_ctrl_info->NPUSCH_sf_end+3,DCI_N0, UE_template_temp->rnti, str22, str23, 0);
//sotre UE_template
UE_template_temp->R_dci=UE_sched_ctrl_info->R_dci;
UE_template_temp->R_ul=UE_sched_ctrl_info->R_ul_data;
if(UE_template_temp->HARQ_round == 0)
{
UE_template_temp->oldNDI_UL=1-UE_template_temp->oldNDI_UL;
}
UE_template_temp->direction = -1;
break;
case -1: // Idle
//DEBUG("current idle.. \n");
break;
default:
break;
}
}
UE_sched_ctrl_info -> flag_schedule_success = 0;
UE_ID = UE_template_temp->next;
}
}
void preprocessor_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index)
{
int ue_id;
UE_TEMPLATE_NB_IoT *UE_template_temp;
UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info;
ue_id = mac_inst->UE_list_spec[UE_list_index].head;
while(ue_id>-1)
{
UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[ue_id]);
UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[ue_id]);
//determine index of MCS, TBS, R, R_max, R_dci, R_harq
UE_sched_ctrl_info->R_dci=UE_template_temp->R_dci;
//Set repetition number of downlink transmission
if(UE_template_temp->direction==1)
{
UE_sched_ctrl_info->R_dl_data=UE_template_temp->R_dl;
UE_sched_ctrl_info->R_dl_harq=UE_template_temp->R_harq;
UE_sched_ctrl_info->dci_n1_index_mcs=UE_template_temp->I_mcs_dl;
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] Initialze R_dci %d R_data_dl %d R_harq %d \n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->R_dci=UE_template_temp->R_dci, UE_sched_ctrl_info->R_dl_data, UE_sched_ctrl_info->R_dl_harq=UE_template_temp->R_harq);
//determine how many SF for data transmission
//store_rlc_logical_channel_info_dl();
}
//Set repetition number of UL transmission
else
{
UE_sched_ctrl_info->R_ul_data=UE_template_temp->R_ul;
}
ue_id = UE_template_temp->next;
}
//sort all UE regardless DL or UL UEs
sort_UEs_uss();
ue_id = mac_inst->UE_list_spec[UE_list_index].head;
//Resource scheduling algorithm
while(ue_id>-1)
{
UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[ue_id]);
UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[ue_id]);
// UE not finish RA or finish transmission
if(UE_template_temp->RRC_connected!=1)
{
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] rrc not connected\n", mac_inst->current_subframe, UE_template_temp->rnti);
}
// Finish RA
else
{
//DEBUG("[%04d][preprocessor_uss_NB_IoT][UE%d] ", mac_inst->current_subframe, UE_template_temp->rnti);
//DEBUG("[%04d][preprocessor_uss_NB_IoT][UE%d] Start scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti);
switch(UE_template_temp->direction)
{
case 1: // Downlink resource allocation algorithm
LOG_D(MAC,"uss downlink scheduling.. \n");
//schedule_DL_NB_IoT(0, mac_inst, UE_template_temp, hypersfn, frame, subframe);
if(0==schedule_DL_NB_IoT(0, mac_inst, UE_template_temp, hypersfn, frame, subframe, UE_sched_ctrl_info))
{
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] DL scheduling USS is successful\n", mac_inst->current_subframe, UE_template_temp->rnti);
UE_sched_ctrl_info->flag_schedule_success=1;
}
else
{
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] DL scheduling USS is failed\n", mac_inst->current_subframe, UE_template_temp->rnti);
}
break;
case 0: // Uplink resource allocation algorithm
LOG_D(MAC,"uss uplink scheduling.. \n");
if(0==schedule_UL_NB_IoT(mac_inst, UE_template_temp, subframe, frame, hypersfn, UE_sched_ctrl_info))
{
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] UL scheduling USS is successful\n", mac_inst->current_subframe, UE_template_temp->rnti);
UE_sched_ctrl_info->flag_schedule_success=1;
}
else
{
LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] UL scheduling USS is failed\n", mac_inst->current_subframe, UE_template_temp->rnti);
}
break;
//schedule_UL_NB_IoT(mac_inst, UE_template_temp, subframe, frame, hypersfn);
break;
case -1: // Idle state, no data wait to send
//sDEBUG("current idle.. \n");
default:
break;
}
}
ue_id = UE_template_temp->next;
}
}
void sort_UEs_uss()
{
//loop all UE
}
/*! \file eNB_scheduler_RA_NB_IoT.c
* \brief functions used in Random access scheduling
* \author NTUST BMW Lab./
* \date 2017
* \email:
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
unsigned char str1[] = "rar_dci";
unsigned char str2[] = "rar";
unsigned char str3[] = "msg4_dci";
unsigned char str4[] = "msg4";
unsigned char str5[] = "ack_msg4";
unsigned char str6[] = "msg3_dci(retransmit)";
unsigned char str7[] = "msg3(retransmit)";
unsigned char str8[] = "msg4_dci(retransmit)";
unsigned char str9[] = "msg4(retransmit)";
unsigned char str10[] = "ack_msg4(retransmit)";
unsigned char str11[] = "msg3";
unsigned char str12[] = "msg3(retransmit)";
void init_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint8_t preamble_index, ce_level_t ce_level, uint32_t sfn_id, uint16_t ta){
int i;
//RA_TEMPLATE_NB_IoT *msg2_list_tail = mac_inst->RA_msg2_list.tail;
RA_TEMPLATE_NB_IoT *migrate_node;
static int static_count=0;
LOG_D(MAC,"[%04d][RA scheduler][MSG1] RX %d\n", mac_inst->current_subframe, static_count++);
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if(0 == mac_inst->RA_template[i].active){
migrate_node = &mac_inst->RA_template[i];
break;
}
}
if(i==MAX_NUMBER_OF_UE_MAX_NB_IoT){
LOG_D(MAC,"[%04d][RA scheduler][MSG1] number of RA procedures is up to maximum..\n", mac_inst->current_subframe);
return ;
}
migrate_node->active = 1;
migrate_node->preamble_index = preamble_index;
migrate_node->ce_level = ce_level;
migrate_node->ra_rnti = (sfn_id>>2) + 1;
migrate_node->ta = ta;
migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
LOG_D(MAC,"[%04d][RA scheduler][MSG1][CE%d] Receive MSG1 RNTI %d preamble index %d\n", mac_inst->current_subframe, migrate_node->ce_level, migrate_node->ra_rnti, migrate_node->preamble_index);
// insert to end of list
if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg2_list.head){
mac_inst->RA_msg2_list.head = migrate_node;
}else{
// not empty
mac_inst->RA_msg2_list.tail->next = migrate_node;
migrate_node->prev = mac_inst->RA_msg2_list.tail;
}
mac_inst->RA_msg2_list.tail = migrate_node;
}
// triggered time :
// 1) after tx rar, wait msg3 timeout
// 2) number of retransmit msg3 meet maximum or absent of ack/nack
// 3) number of retransmit msg4 meet maximum or absent of ack/nack
void cancel_ra(uint16_t rnti){
//uint32_t i;
}
uint16_t find_suit_i_delay(uint32_t rmax, uint32_t r, uint32_t dci_candidate){
uint32_t i;
uint32_t num_candidates = rmax / r;
uint32_t left_candidates = num_candidates - dci_candidate - 1; // 0-7
uint32_t resource_gap = left_candidates * r;
resource_gap = ((resource_gap * 10)>>3); // x1.125
for(i=0;i<8;++i){
if(resource_gap <= get_scheduling_delay(i, rmax)){
return i;
}
}
return 0;
}
void schedule_rar_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
RA_TEMPLATE_NB_IoT *msg2_nodes = mac_inst->RA_msg2_list.head;
//RA_TEMPLATE_NB_IoT *msg3_list_tail = mac_inst->RA_msg3_list.tail;
RA_TEMPLATE_NB_IoT *migrate_node;
schedule_result_t *dci_result, *msg2_result;
DCIFormatN0_t *dci_n0;
DCIFormatN1_t *dci_n1_rar;
available_resource_DL_t *dci_node, *msg2_node;//, *msg3_node;
int rmax, fail, r, res;
int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
int msg2_subframe, msg2_end_subframe, msg2_first_subframe, num_msg2_subframe;
int msg3_subframe;//, msg3_end_subframe;
int dci_candidate, i, num_candidate;
int msg2_i_delay;
int msg3_scheduling_delay;
static uint16_t tc_rnti = 0x0101;
int rep=1;
sched_temp_UL_NB_IoT_t npusch_info;
int fail_num = 0;
int flag=0;
while((RA_TEMPLATE_NB_IoT *)0 != msg2_nodes){
fail=0;
rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg2_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
num_candidate = 1;//rmax / r;
r = rmax/num_candidate;
num_dci_subframe = r;
dci_subframe = abs_subframe;//mac_inst->current_subframe;
LOG_D(MAC,"rmax : %d, num_dci_subframe : %d, dci_subframe: %d\n",rmax,r,dci_subframe);
print_available_resource_DL(mac_inst);
for(dci_candidate=0; dci_candidate<num_candidate; ++dci_candidate){
while(!is_dlsf(mac_inst, dci_subframe)){
++dci_subframe;
}
dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
if((available_resource_DL_t *)0 != dci_node){
//dci_subframe += dci_candidate*num_dci_subframe;
break;
}
res = num_dci_subframe;
while(res != 0){ // maybe would cost lots of time to search
if(is_dlsf(mac_inst, dci_subframe)){
res--;
}
dci_subframe++;
}
}
if(num_candidate==dci_candidate){
fail|=0x1;
}
// check msg2 resource
uint32_t TBS, I_tbs, I_mcs, I_sf, Nrep, RAR_TBS;
I_mcs = get_I_mcs(msg2_nodes->ce_level);
I_tbs = I_mcs;
TBS = get_tbs(7, I_tbs, &I_sf); // rar 7 bytes
Nrep = dl_rep[msg2_nodes->ce_level];
num_msg2_subframe = get_num_sf(I_sf) * Nrep;
RAR_TBS = TBS*8;
//num_msg2_subframe = 8;
msg2_i_delay = find_suit_i_delay(rmax, r, dci_candidate);
for(i=0; i<8; ++i, ++msg2_i_delay){
msg2_i_delay = (msg2_i_delay==8)?0:msg2_i_delay;
msg2_subframe = dci_end_subframe+4+get_scheduling_delay(msg2_i_delay, rmax);
msg2_node = (available_resource_DL_t *)check_resource_DL(mac_inst, msg2_subframe, num_msg2_subframe, &msg2_end_subframe, &msg2_first_subframe);
if((available_resource_DL_t *)0 != msg2_node){
break;
}
}
if(-1==msg2_i_delay){
fail|=0x2;
}
// check msg3 resource, follow the prach repeat
//rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg2_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
// Set the temp rep
rep = 0;
uint32_t Iru = 0, mcs, Nru;
uint32_t Nrep_UL = 0; // need a table here
uint32_t mappedMcsIndex = 4; // assume all ue supported multi-tone
//mcs = mapped_mcs[msg2_nodes->ce_level][mappedMcsIndex]; // assume all ue supported multi-tone
mcs = 2;
Nrep_UL = ULrep[rep];
TBS = get_TBS_UL_NB_IoT(mcs,1,Iru);
while((TBS<11)&&(Iru<=7)){ // 88 bits
Iru++;
TBS=get_TBS_UL_NB_IoT(mcs,1,Iru);
}
//Nru = RU_table[Iru];
Nru = RU_table_msg3[mcs];
for(msg3_scheduling_delay=0; msg3_scheduling_delay<4; ++msg3_scheduling_delay){
// 36.213 Table 16.3.3-1 Imcs=3'b000 Nru=4
msg3_subframe = msg2_end_subframe+msg3_scheduling_delay_table[msg3_scheduling_delay]+1;
if(0==Check_UL_resource(msg3_subframe, Nru*Nrep_UL, &npusch_info, 0, 0)){ //1: multi-tones 0: single-tone. 1: format 2(ack/nack) 0: format 1
break;
}
}
if(4==msg3_scheduling_delay){
fail|=0x4;
}
if(0 < fail){
fail_num++;
LOG_D(MAC,"[%04d][RA scheduler][MSG2] fail vector %d\n", abs_subframe, fail);
LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] rnti: %d preamble: %d fail vector %d\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->preamble_index, fail);
msg2_nodes = msg2_nodes->next;
}else{
LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] rnti: %d preamble: %d scheduling success\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->preamble_index);
dci_result = (schedule_result_t *)calloc(1, sizeof(schedule_result_t));
msg2_result = (schedule_result_t *)calloc(1, sizeof(schedule_result_t));
dci_n0 = (DCIFormatN0_t *)malloc(sizeof(DCIFormatN0_t));
dci_n1_rar = (DCIFormatN1_t *)malloc(sizeof(DCIFormatN1_t));
msg2_nodes->ue_rnti = tc_rnti;
fill_rar_NB_IoT(mac_inst, msg2_nodes, msg3_scheduling_delay, rep, &npusch_info);
msg2_nodes->wait_msg3_ack = 1;
// dci entity
dci_n1_rar->type = 1;
dci_n1_rar->orderIndicator = 0;
dci_n1_rar->Scheddly = msg2_i_delay;
dci_n1_rar->ResAssign = I_sf;
dci_n1_rar->mcs = I_mcs;
dci_n1_rar->RepNum = msg2_nodes->ce_level; // 36.213 table 16.4.1.3-2, 8 candidates
dci_n1_rar->ndi = 0; // ndi is useless in RAR 36.212 says the feild is reserved
dci_n1_rar->HARQackRes = 0; // no HARQ procedure in RAR 36.212 says the feild is reserved
dci_n1_rar->DCIRep = 2; // 36.213 table 16.6-1 R=Rmax/8
//printf("I_sf = %d,I_mcs = %d, RepNum = %d\n",dci_n1_rar->ResAssign,I_mcs,msg2_nodes->ce_level);
// for dci
dci_result->output_subframe = dci_first_subframe;//dci_subframe;
dci_result->end_subframe = dci_end_subframe;
dci_result->sdu_length = 0;
dci_result->direction = DL;
dci_result->DCI_release = 0;
dci_result->channel = NPDCCH;
dci_result->rnti = msg2_nodes->ra_rnti;//ra_rnti;
dci_result->rnti_type = 1;
dci_result->npusch_format = 0; //useless
dci_result->R_harq = 0;
dci_result->next = (schedule_result_t *)0;
dci_result->DCI_pdu = (void *)dci_n1_rar;
dci_result->dl_sdly = msg2_subframe - dci_end_subframe;
dci_result->ul_sdly = msg3_subframe - msg2_end_subframe;
dci_result->num_sf = msg2_end_subframe - msg2_subframe+1;
// for msg2
msg2_result->output_subframe = msg2_first_subframe;//msg2_subframe;
msg2_result->end_subframe = msg2_end_subframe;
msg2_result->sdu_length = RAR_TBS; // rar size
msg2_result->DLSCH_pdu = msg2_nodes->rar_buffer;
msg2_result->direction = DL;
msg2_result->DCI_release = 1;
msg2_result->channel = NPDSCH;
msg2_result->rnti = msg2_nodes->ra_rnti;//ra_rnti;
msg2_result->rnti_type = 1;
msg2_result->npusch_format = 0; //useless
msg2_result->R_harq = 0;
msg2_result->next = (schedule_result_t *)0;
msg2_result->DCI_pdu = (void *)dci_n1_rar;
msg2_result->rar_buffer = msg2_nodes->rar_buffer;
msg2_result->dl_sdly = -1;
msg2_result->ul_sdly = -1;
// for msg3(fake DCI N0)
dci_n0->type = 0;
dci_n0->scind = npusch_info.subcarrier_indication;
dci_n0->ResAssign = 0;
dci_n0->mcs = 2;
dci_n0->ndi = 1;
dci_n0->Scheddly = msg3_scheduling_delay;
dci_n0->RepNum = rep; //rep
dci_n0->rv = 0;
dci_n0->DCIRep = 1;//get_DCI_REP()
//msg2_nodes->ue_rnti = tc_rnti;
LOG_I(MAC,"[%04d][RA scheduler][MSG2] RARDCI %d-%d RAR %d-%d MSG3 %d-%d Nru = %d, Nrep = %d\n", abs_subframe-1, dci_first_subframe, dci_end_subframe, msg2_first_subframe, msg2_end_subframe, npusch_info.sf_start, npusch_info.sf_end,Nru,Nrep_UL);
LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] Change RA-RNTI %d->T-CRNTI %d\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->ue_rnti);
LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] RAR DCI %d-%d RAR %d-%d MSG3 %d-%d\n", abs_subframe-1, msg2_nodes->ce_level, dci_first_subframe, dci_end_subframe, msg2_first_subframe, msg2_end_subframe, npusch_info.sf_start, npusch_info.sf_end);
print_available_resource_DL(mac_inst);
//LOG_D(MAC,"dci_node:%p dci_node_prev:%p %3d-%3d\n", dci_node, dci_node->prev,dci_node->start_subframe, dci_node->end_subframe);
// fill dci resource
fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);
print_available_resource_DL(mac_inst);
//LOG_D(MAC,"msg2_node:%p msg2_node_prev:%p %3d-%3d\n", msg2_node, msg2_node->prev,msg2_node->start_subframe, msg2_node->end_subframe);
// fill msg2 resource
fill_resource_DL(mac_inst, msg2_node, msg2_first_subframe, msg2_end_subframe, msg2_result);
// fill msg3 resource
generate_scheduling_result_UL(-1, -1, npusch_info.sf_start+3, npusch_info.sf_end+3, dci_n0, tc_rnti, str11, (void *)0, 1); // the last argument is msg3 flag
adjust_UL_resource_list(&npusch_info);
//simulate_rx(&simulate_rx_msg3_list, tc_rnti, npusch_info.sf_start);
migrate_node = msg2_nodes;
//migrate_node->ue_rnti = tc_rnti;
tc_rnti++;
msg2_nodes = msg2_nodes->next;
// maintain list
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
// first node
mac_inst->RA_msg2_list.head = migrate_node->next; // including null
}else{
// not first node
migrate_node->prev->next = migrate_node->next; // including null
}
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
// last node
mac_inst->RA_msg2_list.tail = migrate_node->prev; // including null
}else{
// not last node
migrate_node->next->prev = migrate_node->prev; // including null
}
// migrate to next list
// insert to end of list
migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg3_list.head){
mac_inst->RA_msg3_list.head = migrate_node;
}else{
// not empty
mac_inst->RA_msg3_list.tail->next = migrate_node;
migrate_node->prev = mac_inst->RA_msg3_list.tail;
}
mac_inst->RA_msg3_list.tail = migrate_node;
}
LOG_D(MAC,"RAR schedule Done\n");
}
if(flag==1)
LOG_D(MAC,"[%04d][RA scheduler][MSG2] failed number: %d\n", abs_subframe-1, fail_num);
return ;
}
void msg3_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti){
RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;
//RA_TEMPLATE_NB_IoT *migrate_node;
if((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes)
while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
if(msg3_nodes->ue_rnti == c_rnti){
msg3_nodes->wait_msg3_ack = 0;
msg3_nodes->msg3_retransmit_count++;
return ;
}
msg3_nodes = msg3_nodes->next;
}
return ;
}
void msg4_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti){
RA_TEMPLATE_NB_IoT *msg4_nodes = mac_inst->RA_msg4_list.head;
//RA_TEMPLATE_NB_IoT *migrate_node;
if((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes)
while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){
if(msg4_nodes->ue_rnti == c_rnti){
msg4_nodes->wait_msg4_ack = 0;
msg4_nodes->msg4_retransmit_count++;
return ;
}
msg4_nodes = msg4_nodes->next;
}
return ;
}
void receive_msg3_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti, uint32_t phr, uint32_t ul_total_buffer, uint8_t* ccch_sdu, uint8_t* msg4_rrc_sdu){
// since successful receive msg3, tc-rnti become c-rnti.
RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;
RA_TEMPLATE_NB_IoT *migrate_node;
if((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes)
while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
if(msg3_nodes->ue_rnti == c_rnti){
LOG_D(MAC,"add ue in\n");
add_ue_NB_IoT(mac_inst, c_rnti, msg3_nodes->ce_level, phr, ul_total_buffer);// rnti, ce level
LOG_D(MAC,"[%04d][RA scheduler][MSG3][CE%d] Receive MSG3 T-CRNTI %d Preamble Index %d \n", mac_inst->current_subframe, msg3_nodes->ce_level, msg3_nodes->ue_rnti, msg3_nodes->preamble_index);
msg3_nodes->ccch_buffer = ccch_sdu;
msg3_nodes->msg4_rrc_buffer = msg4_rrc_sdu;
migrate_node = msg3_nodes;
// maintain list
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
// first node
mac_inst->RA_msg3_list.head = migrate_node->next; // including null
}else{
// not first node
migrate_node->prev->next = migrate_node->next; // including null
}
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
// last node
mac_inst->RA_msg3_list.tail = migrate_node->prev; // including null
}else{
// not last node
migrate_node->next->prev = migrate_node->prev; // including null
}
// migrate to next list
// insert to end of list
migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg4_list.head){
mac_inst->RA_msg4_list.head = migrate_node;
}else{
// not empty
mac_inst->RA_msg4_list.tail->next = migrate_node;
migrate_node->prev = mac_inst->RA_msg4_list.tail;
}
mac_inst->RA_msg4_list.tail = migrate_node;
return ;
}
msg3_nodes = msg3_nodes->next;
}
if((RA_TEMPLATE_NB_IoT *)0 == msg3_nodes){
LOG_D(MAC,"[%04d][RA scheduler][MSG3] receive msg3.. can't found the ue from crnti %x\n", mac_inst->current_subframe, c_rnti);
return;
}
}
void schedule_msg3_retransimission_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;
available_resource_DL_t *dci_node;//, *msg3_node;
int rmax, fail, res, r;
int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
int msg3_subframe;//, msg3_end_subframe;
int dci_candidate, num_candidate;
int msg3_scheduling_delay;
schedule_result_t *dci_result;//, *msg3_result;
int rep=1;
//sched_temp_UL_NB_IoT_t npusch_info;
#if 0
// msg3 retransmission pre-processor
RA_TEMPLATE_NB_IoT *iterator, *iterator1;
while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
if(msg3_nodes->wait_msg3_ack == 0){
iterator = msg3_nodes;
while(iterator->prev != (RA_TEMPLATE_NB_IoT *)0 && iterator != mac_inst->RA_msg3_list.head){
if(iterator->prev->msg3_retransmit_count < iterator->msg3_retransmit_count){
//swap
iterator1 = iterator->prev;
if(iterator->prev == mac_inst->RA_msg3_list.head || iterator1->prev == (RA_TEMPLATE_NB_IoT *)0){
mac_inst->RA_msg3_list.head = iterator;
iterator1->prev = (RA_TEMPLATE_NB_IoT *)0; // b->prev
}else{
iterator->prev->prev->next = iterator; // a*->next
iterator->prev = iterator1->prev; // b->prev
}
if(iterator == mac_inst->RA_msg3_list.tail || iterator->next == (RA_TEMPLATE_NB_IoT *)0){
mac_inst->RA_msg3_list.tail = iterator1;
iterator1->next = (RA_TEMPLATE_NB_IoT *)0; // a->next
}else{
iterator->next->prev = iterator->prev; //b*->prev
iterator1->next = iterator->next; // a->next
}
iterator1->prev = iterator; // a->prev
iterator->next = iterator1; // b->next
}else{
break;
}
}
}
msg3_nodes = msg3_nodes->next;
}
#endif
msg3_nodes = mac_inst->RA_msg3_list.head;
while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
if(msg3_nodes->wait_msg3_ack == 0){
fail=0;
// check dci resource
rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg3_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
num_candidate = 8;//rmax / r;
r = rmax/num_candidate;
num_dci_subframe = r;
dci_subframe = abs_subframe;//mac_inst->current_subframe;
for(dci_candidate=0; dci_candidate<8; ++dci_candidate){
while(!is_dlsf(mac_inst, dci_subframe)){
++dci_subframe;
}
dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
if((available_resource_DL_t *)0 != dci_node){
break;
}
res = num_dci_subframe;
while(res != 0){ // cost lot of time to search
if(is_dlsf(mac_inst, dci_subframe)){
res--;
}
dci_subframe++;
}
}
if(8==dci_candidate){
//failed
fail|=0x1;
}
// check msg3 resource
rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg3_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
sched_temp_UL_NB_IoT_t npusch_info;
uint32_t Iru = 0, mcs, Nru;
uint32_t mappedMcsIndex = 4; // assume all ue supported multi-tone
mcs = mapped_mcs[msg3_nodes->ce_level][mappedMcsIndex]; // assume all ue supported multi-tone
int TBS = get_TBS_UL_NB_IoT(mcs,1,Iru);
while((TBS<11)&&(Iru<=7)){
Iru++;
TBS=get_TBS_UL_NB_IoT(mcs,1,Iru);
}
Nru = RU_table[Iru];
for(msg3_scheduling_delay=0; msg3_scheduling_delay<4; ++msg3_scheduling_delay){
msg3_subframe = 8+dci_end_subframe+msg3_scheduling_delay_table[msg3_scheduling_delay];
if(0==Check_UL_resource(msg3_subframe+1, Nru*rep, &npusch_info, 1, 0)){ //1: multi-tones 0: single-tone. 1: format 2(ack/nack) 0: format 1
break;
}
}
if(4==msg3_scheduling_delay){
//failed
fail|=0x2;
}
if(0 == fail){
msg3_nodes->wait_msg3_ack = 1;
DCIFormatN0_t *dci_n0_msg3 = (DCIFormatN0_t *)malloc(sizeof(DCIFormatN0_t));
// dci entity
dci_n0_msg3->type = 0;
dci_n0_msg3->scind = npusch_info.subcarrier_indication;
dci_n0_msg3->ResAssign = 0;
dci_n0_msg3->mcs = 0;
dci_n0_msg3->ndi = 0; // retrnasmit
dci_n0_msg3->Scheddly = msg3_scheduling_delay;
dci_n0_msg3->RepNum = rep;
dci_n0_msg3->rv = 0;
dci_n0_msg3->DCIRep = 1;//get_DCI_REP()
// for dci
dci_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
dci_result->output_subframe = dci_first_subframe;//dci_subframe;
dci_result->end_subframe = dci_end_subframe;
dci_result->sdu_length = 0;
dci_result->direction = UL;
dci_result->DCI_release = 0;
dci_result->channel = NPDCCH;
dci_result->rnti = msg3_nodes->ue_rnti;
dci_result->rnti_type = 1;
dci_result->npusch_format = 0; //useless
dci_result->R_harq = 0;
dci_result->next = (schedule_result_t *)0;
dci_result->DCI_pdu = (void *)dci_n0_msg3;
//----------clare
dci_result->dl_sdly = msg3_subframe - dci_end_subframe + 1;
dci_result->ul_sdly = -1;
dci_result->num_sf = -1;
dci_result->harq_round = msg3_nodes->msg3_retransmit_count;
//----------clare
// fill dci resource
fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);
// fill msg3 resource
generate_scheduling_result_UL(-1, -1, npusch_info.sf_start, npusch_info.sf_end, dci_n0_msg3, msg3_nodes->ue_rnti, str12, (void *)0, 1); // rnti
adjust_UL_resource_list(&npusch_info);
LOG_D(MAC,"[%04d][RA scheduler][MSG3 re] MSG3DCI %d-%d MSG3 %d-%d\n", abs_subframe, dci_first_subframe, dci_end_subframe, npusch_info.sf_start, npusch_info.sf_end );
}else{
LOG_D(MAC,"[%04d][RA scheduler][MSG3 re] fail vector %d\n", abs_subframe, fail );
}
//++msg3_nodes->msg3_retransmit_count;
}
msg3_nodes = msg3_nodes->next;
}
return ;
}
void receive_msg4_ack_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t rnti){
int i;
RA_TEMPLATE_NB_IoT *migrate_node = mac_inst->RA_msg4_list.head;
UE_TEMPLATE_NB_IoT *ue_info = (UE_TEMPLATE_NB_IoT *)0;
if((RA_TEMPLATE_NB_IoT *)0 != migrate_node)
while((RA_TEMPLATE_NB_IoT *)0 != migrate_node){
if(migrate_node->ue_rnti == rnti){
ue_info = mac_inst->UE_list_spec[(uint32_t)migrate_node->ce_level].UE_template_NB_IoT;
// maintain list
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
// first node
mac_inst->RA_msg4_list.head = migrate_node->next; // including null
}else{
// not first node
migrate_node->prev->next = migrate_node->next; // including null
}
if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
// last node
mac_inst->RA_msg4_list.tail = migrate_node->prev; // including null
}else{
// not last node
migrate_node->next->prev = migrate_node->prev; // including null
}
// release ra template
migrate_node->active = 0;
migrate_node->ce_level = 0;
migrate_node->msg3_retransmit_count = 0;
migrate_node->msg4_retransmit_count = 0;
migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
migrate_node->ta = 0;
migrate_node->preamble_index = 0;
migrate_node->ue_rnti = 0x0;
migrate_node->ra_rnti = 0x0;
migrate_node->wait_msg4_ack = 0;
migrate_node->wait_msg3_ack = 0;
break ;
}
migrate_node = migrate_node->next;
}
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if(ue_info[i].rnti == rnti){
if(ue_info[i].ul_total_buffer>0)
{
ue_info[i].direction = 0;
}
else
{
ue_info[i].direction = 1;
}
ue_info[i].RRC_connected = 1;
LOG_D(MAC,"[%04d][RA scheduler][MSG4] received UE:%d direction: %d ul_total_buffer: %d\n", mac_inst->current_subframe, rnti, ue_info[i].direction,ue_info[i].ul_total_buffer);
break;
}
}
return ;
}
// msg4 scheduling: both first time or retransmit would be scheduled in this function(msg4_list).
void schedule_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
RA_TEMPLATE_NB_IoT *msg4_nodes = mac_inst->RA_msg4_list.head;//, *migrate_node;
available_resource_DL_t *dci_node, *msg4_node;
int rmax, fail, r;
int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
int msg4_subframe = 0, msg4_end_subframe, msg4_first_subframe, num_msg4_subframe;
int harq_subframe, harq_end_subframe;
int msg4_length = 0; // return value of msg4 pdu (bits)
int dci_candidate, num_candidate;
int msg4_i_delay, i, res, rep;
int end_flagHARQ, HARQ_delay;
sched_temp_UL_NB_IoT_t HARQ_info;
schedule_result_t *dci_result;
schedule_result_t *msg4_result;
schedule_result_t *harq_result;
uint32_t I_tbs, I_sf,I_mcs;
//Transport block size
int TBS;
int n_sf;
#if 0
// msg4 pre-processor
RA_TEMPLATE_NB_IoT *iterator, *iterator1;
while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){
if(msg4_nodes->wait_msg4_ack == 0){
iterator = msg4_nodes;
while(iterator->prev != (RA_TEMPLATE_NB_IoT *)0 && iterator != mac_inst->RA_msg4_list.head){
if(iterator->prev->msg4_retransmit_count < iterator->msg4_retransmit_count){
//swap
iterator1 = iterator->prev;
if(iterator->prev == mac_inst->RA_msg4_list.head || iterator1->prev == (RA_TEMPLATE_NB_IoT *)0){
mac_inst->RA_msg4_list.head = iterator;
iterator1->prev = (RA_TEMPLATE_NB_IoT *)0; // b->prev
}else{
iterator->prev->prev->next = iterator; // a*->next
iterator->prev = iterator1->prev; // b->prev
}
if(iterator == mac_inst->RA_msg4_list.tail || iterator->next == (RA_TEMPLATE_NB_IoT *)0){
mac_inst->RA_msg4_list.tail = iterator1;
iterator1->next = (RA_TEMPLATE_NB_IoT *)0; // a->next
}else{
iterator->next->prev = iterator->prev; //b*->prev
iterator1->next = iterator->next; // a->next
}
iterator1->prev = iterator; // a->prev
iterator->next = iterator1; // b->next
}else{
break;
}
}
}
msg4_nodes = msg4_nodes->next;
}
#endif
msg4_node = (available_resource_DL_t *)0;
msg4_nodes = mac_inst->RA_msg4_list.head;
while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){
if(msg4_nodes->wait_msg4_ack == 0){
fail=0;
// check dci resource
rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg4_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
num_candidate = 1;//rmax / r;
r = rmax/num_candidate;
num_dci_subframe = r;
dci_subframe = abs_subframe;//mac_inst->current_subframe;
for(dci_candidate=0; dci_candidate<num_candidate; ++dci_candidate){
while(!is_dlsf(mac_inst, dci_subframe)){
++dci_subframe;
}
dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
if((available_resource_DL_t *)0 != dci_node){
LOG_D(MAC,"%d msg4 dci %d - %d\n", abs_subframe, dci_first_subframe, dci_end_subframe);
break;
}
res = num_dci_subframe;
while(res != 0){ // cost lot of time to search
if(is_dlsf(mac_inst, dci_subframe)){
res--;
}
dci_subframe++;
}
}
if(num_candidate==dci_candidate){
//failed
fail|=1;
}
// check msg4 resource
rep = dl_rep[msg4_nodes->ce_level];
msg4_length = fill_msg4_NB_IoT(mac_inst,msg4_nodes);
I_mcs = get_I_mcs(msg4_nodes->ce_level);
//I_mcs = 1;
I_tbs = I_mcs;
TBS = get_max_tbs(I_tbs);
if(TBS > msg4_length)
{
TBS = get_tbs(msg4_length, I_tbs, &I_sf);
LOG_D(MAC,"TBS change to %d because data size is smaller than previous TBS\n", TBS);
}else
LOG_E(MAC,"the size of MSG4 is bigger than max TBS\n");
//Get number of subframe this UE need per repetition
n_sf = get_num_sf(I_sf);
LOG_D(MAC,"n_sf = %d\n", n_sf);
num_msg4_subframe = n_sf*rep; // 4 subframe?
msg4_i_delay = find_suit_i_delay(rmax, r, dci_candidate);
for(i=msg4_i_delay; i<8; ++i){
msg4_i_delay = (msg4_i_delay==8)?0:msg4_i_delay;
msg4_subframe = dci_end_subframe+4+get_scheduling_delay(msg4_i_delay, rmax);
msg4_node = (available_resource_DL_t *)check_resource_DL(mac_inst, msg4_subframe, num_msg4_subframe, &msg4_end_subframe, &msg4_first_subframe);
if((available_resource_DL_t *)0 != msg4_node){
LOG_D(MAC,"%d msg4 %d - %d\n", abs_subframe, msg4_first_subframe, msg4_end_subframe);
break;
}
}
if(8==i){
//failed
fail|=2;
}
rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg4_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
for(HARQ_delay=0;HARQ_delay<4;++HARQ_delay){
end_flagHARQ=Check_UL_resource(msg4_end_subframe+get_HARQ_delay(1, HARQ_delay), rep, &HARQ_info, 0, 1); // RA_template->R
if(0 == end_flagHARQ){
harq_subframe = msg4_end_subframe + get_HARQ_delay(1, HARQ_delay);
harq_end_subframe = harq_subframe + 2*rep -1;
HARQ_info.ACK_NACK_resource_field=get_resource_field_value(HARQ_info.subcarrier_indication, get_scheduling_delay(HARQ_delay, rmax));
break;
}
}
if(4 == HARQ_delay){
fail |= 4;
}
if(0==fail){
LOG_D(MAC,"[%04d][RA scheduler][MSG4][CE%d] rnti: %d scheduling success\n", abs_subframe-1, msg4_nodes->ce_level, msg4_nodes->ue_rnti);
msg4_nodes->wait_msg4_ack = 1;
DCIFormatN1_t *dci_n1_msg4 = (DCIFormatN1_t *)malloc(sizeof(DCIFormatN1_t));
// dci entity
dci_n1_msg4->type = 1;
dci_n1_msg4->orderIndicator = 0;
dci_n1_msg4->Scheddly = msg4_i_delay;
dci_n1_msg4->ResAssign = I_sf;
dci_n1_msg4->mcs = I_mcs;
dci_n1_msg4->RepNum = 2;
dci_n1_msg4->ndi = 1;
dci_n1_msg4->HARQackRes = HARQ_info.ACK_NACK_resource_field;
dci_n1_msg4->DCIRep = 2;
// for dci
dci_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
dci_result->output_subframe = dci_first_subframe;//dci_subframe;
dci_result->end_subframe = dci_end_subframe;
dci_result->sdu_length = 0;
dci_result->direction = DL;
dci_result->DCI_release = 0;
dci_result->channel = NPDCCH;
dci_result->rnti = msg4_nodes->ue_rnti;
dci_result->rnti_type = 3;
dci_result->npusch_format = 0; //useless
dci_result->R_harq = 0;
dci_result->next = (schedule_result_t *)0;
dci_result->DCI_pdu = (void *)dci_n1_msg4;
dci_result->dl_sdly = msg4_subframe - dci_end_subframe;
dci_result->ul_sdly = harq_subframe - msg4_end_subframe;
dci_result->num_sf = msg4_end_subframe - msg4_subframe+1;
dci_result->harq_round = msg4_nodes->msg4_retransmit_count;
// for msg4
msg4_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
msg4_result->output_subframe = msg4_first_subframe;// msg4_subframe;
msg4_result->end_subframe = msg4_end_subframe;
msg4_result->sdu_length = TBS*8;
msg4_result->direction = DL;
msg4_result->DCI_release = 0;
msg4_result->channel = NPDSCH;
msg4_result->rnti = msg4_nodes->ue_rnti;
msg4_result->rnti_type = 1;
msg4_result->npusch_format = 0; //useless
msg4_result->R_harq = 0;
msg4_result->next = (schedule_result_t *)0;
msg4_result->DCI_pdu = (void *)dci_n1_msg4;
msg4_result->DLSCH_pdu = msg4_nodes->msg4_buffer;
harq_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
harq_result->rnti = msg4_nodes->ue_rnti;
harq_result->output_subframe = harq_subframe+3;
harq_result->end_subframe = harq_end_subframe+3;
harq_result->sdu_length = 0;
harq_result->direction = UL;
harq_result->rnti_type = 3;
harq_result->DLSCH_pdu = NULL;
harq_result->DCI_pdu = (void *)dci_n1_msg4;
harq_result->DCI_release = 1;
harq_result->npusch_format = 1;
harq_result->channel = NPUSCH;
harq_result->next = (schedule_result_t *)0;
LOG_I(MAC,"[%04d][RA scheduler][MSG4] UE:%x MSG4DCI %d-%d MSG4 %d-%d HARQ %d-%d, TBS = %d\n", abs_subframe-1, msg4_nodes->ue_rnti, dci_first_subframe, dci_end_subframe, msg4_first_subframe, msg4_end_subframe, HARQ_info.sf_start, HARQ_info.sf_end, TBS*8);
LOG_D(MAC,"[%04d][RA scheduler][MSG4][CE%d] MSG4 DCI %d-%d MSG4 %d-%d HARQ %d-%d\n", abs_subframe-1, msg4_nodes->ce_level, dci_first_subframe, dci_end_subframe, msg4_first_subframe, msg4_end_subframe, HARQ_info.sf_start, HARQ_info.sf_end);
msg4_nodes->msg4_retransmit_count++;
// fill dci resource
fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);
// fill msg4 resource
fill_resource_DL(mac_inst, msg4_node, msg4_first_subframe, msg4_end_subframe, msg4_result);
// fill ack/nack resource
insert_schedule_result(&schedule_result_list_UL, harq_subframe, harq_result);
adjust_UL_resource_list(&HARQ_info);
// active ue_list ul/dl
UE_list_NB_IoT_t *UE_list = mac_inst->UE_list_spec;
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if(UE_list->UE_template_NB_IoT[i].active == 1 && UE_list->UE_template_NB_IoT[i].rnti == msg4_nodes->ue_rnti){
UE_list->UE_template_NB_IoT[i].direction = rand()&1;
}
}
}else{
LOG_D(MAC,"[%04d][RA scheduler][MSG4] fail vector %d\n", abs_subframe, fail );
LOG_D(MAC,"[%04d][RA scheduler][MSG4] rnti: %d preamble: %d fail vector %d\n", abs_subframe-1, msg4_nodes->ra_rnti, msg4_nodes->preamble_index, fail);
}
}
msg4_nodes = msg4_nodes->next;
}
return ;
}
void schedule_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst){
uint32_t schedule_subframe = mac_inst->current_subframe + 1;
schedule_subframe = schedule_subframe % 1048576; // 20 bits, 10 bits + 10 bits
// this is the priority order in current stage.
schedule_msg3_retransimission_NB_IoT(mac_inst, schedule_subframe);
schedule_rar_NB_IoT(mac_inst, schedule_subframe);
schedule_msg4_NB_IoT(mac_inst, schedule_subframe);
return ;
}
// 7bytes TODO: CHECK
void fill_rar_NB_IoT(
eNB_MAC_INST_NB_IoT *inst,
RA_TEMPLATE_NB_IoT *ra_template,
uint8_t msg3_schedule_delay,
uint8_t msg3_rep,
sched_temp_UL_NB_IoT_t *schedule_template
)
//------------------------------------------------------------------------------
{
uint8_t *dlsch_buffer = &ra_template->rar_buffer[0];
RA_HEADER_RAPID_NB_IoT *rarh = (RA_HEADER_RAPID_NB_IoT *)dlsch_buffer;
int i;
for(i=0; i<7; ++i){
dlsch_buffer[i] = 0x0;
}
// subheader fixed
rarh->E = 0; // First and last RAR
rarh->T = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader
rarh->RAPID = ra_template->preamble_index; // Respond to Preamble 0 only for the moment
uint8_t *rar = (uint8_t *)(dlsch_buffer+1);
// ta
ra_template->ta >>= 4;
rar[0] = (uint8_t)(ra_template->ta>>(2+4)); // 7 MSBs of timing advance + divide by 4
rar[1] = (uint8_t)(ra_template->ta<<(4-2))&0xf0; // 4 LSBs of timing advance + divide by 4
// msg3 grant (15bits)
// subcarrier spacing:1 subcarrier indication:6 scheduling delay:2 msg3 repetition:3 MCS index: 3
uint8_t subcarrier_spacing = 1; // 1bit 15kHz
uint8_t subcarrier_indication = schedule_template->subcarrier_indication; // 6bits
uint8_t i_delay = msg3_schedule_delay; // 2bits
uint8_t msg3_repetition = msg3_rep;// 3bit
uint8_t mcs_index = 2;//3bit, msg3 88bits 3'b000
LOG_D(MAC,"Dump UL Grant: subcarrier spacing : %d, subcarrier indication: %d, delay : %d, Rep : %d, MCS : %d\n",subcarrier_spacing,subcarrier_indication,i_delay,msg3_repetition,mcs_index);
rar[1] |= (subcarrier_spacing<<3) | (subcarrier_indication>>3);
rar[2] = (uint8_t)(subcarrier_indication<<5) | (i_delay<<3) | msg3_repetition;
rar[3] = (mcs_index<<5)&0xe0; // maped
// tc-rnti
rar[4] = (uint8_t)(ra_template->ue_rnti>>8);
rar[5] = (uint8_t)(ra_template->ue_rnti&0xff);
}
// Generate MSG4 MAC PDU
int fill_msg4_NB_IoT(
eNB_MAC_INST_NB_IoT *inst,
RA_TEMPLATE_NB_IoT *ra_template
)
{
int length = 0;
uint8_t *dlsch_buffer = &ra_template->msg4_buffer[0];
// we have three subheader here: 1 for Control element of Contention resolution, 2 for CCCH
SCH_SUBHEADER_FIXED_NB_IoT *msg4_sub_1 = (SCH_SUBHEADER_FIXED_NB_IoT*)dlsch_buffer;
msg4_sub_1->R = 0;
msg4_sub_1->E = 1;
msg4_sub_1->LCID = UE_CONTENTION_RESOLUTION;
length+=1;
SCH_SUBHEADER_FIXED_NB_IoT *msg4_sub_2 = (SCH_SUBHEADER_FIXED_NB_IoT *) (msg4_sub_1 +1);
msg4_sub_2->R= 0;
msg4_sub_2->E= 0;
msg4_sub_2->LCID = CCCH_NB_IoT;
length+=1;
uint8_t *con_res = (uint8_t *)(dlsch_buffer+2);
con_res[0] = ra_template->ccch_buffer[0];
con_res[1] = ra_template->ccch_buffer[1];
con_res[2] = ra_template->ccch_buffer[2];
con_res[3] = ra_template->ccch_buffer[3];
con_res[4] = ra_template->ccch_buffer[4];
con_res[5] = ra_template->ccch_buffer[5];
length+=6;
uint8_t *msg4_rrc_sdu = (uint8_t *) (dlsch_buffer+8);
msg4_rrc_sdu[0] = ra_template->msg4_rrc_buffer[0];
msg4_rrc_sdu[1] = ra_template->msg4_rrc_buffer[1];
msg4_rrc_sdu[2] = ra_template->msg4_rrc_buffer[2];
msg4_rrc_sdu[3] = ra_template->msg4_rrc_buffer[3];
msg4_rrc_sdu[4] = ra_template->msg4_rrc_buffer[4];
msg4_rrc_sdu[5] = ra_template->msg4_rrc_buffer[5];
msg4_rrc_sdu[6] = ra_template->msg4_rrc_buffer[6];
length+=7;
/*
printf("MSG4 PDU = ");
for(int i=0; i<length;i++)
printf("%02x ",dlsch_buffer[i]);
printf("\n");
*/
return length;
}
// Generate MSG4 MAC PDU
int fill_msg4_NB_IoT_fixed(
eNB_MAC_INST_NB_IoT *inst,
RA_TEMPLATE_NB_IoT *ra_template
)
{
int length = 0;
uint8_t *dlsch_buffer = &ra_template->msg4_buffer[0];
// we have three subheader here: 1 for Control element of Contention resolution, 2 for CCCH
SCH_SUBHEADER_FIXED_NB_IoT *msg4_sub_1 = (SCH_SUBHEADER_FIXED_NB_IoT*)dlsch_buffer;
msg4_sub_1->R = 0;
msg4_sub_1->E = 0;
msg4_sub_1->LCID = UE_CONTENTION_RESOLUTION;
length+=1;
//dlsch_buffer[0] = 28;
uint8_t *con_res = (uint8_t *)(dlsch_buffer+1);
con_res[0] = ra_template->ccch_buffer[0];
con_res[1] = ra_template->ccch_buffer[1];
con_res[2] = ra_template->ccch_buffer[2];
con_res[3] = ra_template->ccch_buffer[3];
con_res[4] = ra_template->ccch_buffer[4];
con_res[5] = ra_template->ccch_buffer[5];
length+=6;
/*
printf("MSG4 PDU = ");
for(int i=0; i<length;i++)
printf("%02x ",dlsch_buffer[i]);
printf("\n");
*/
return length;
}
/*! \file eNB_scheduler_bch_NB_IoT.c
* \brief schedule functions for SIBs transmission in NB-IoT
* \author NTUST BMW Lab./
* \date 2017
* \email:
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
#include "openair2/RRC/NBIOT/proto_NB_IoT.h"
char str[6][7] = { "SIBs_1", "SIBs_2", "SIBs_3", "SIBs_4", "SIBs_5", "SIBs_6" };
#define num_flags 2
extern int extend_space[num_flags];
extern int extend_alpha_offset[num_flags];
uint32_t get_SIB23_size(void)
{
rrc_config_NB_IoT_t *mac_config = &mac_inst->rrc_config;
uint32_t size_SIB23_in_MAC = 0;
switch(mac_config->sibs_NB_IoT_sched[0].si_tb)
{
case si_TB_56:
size_SIB23_in_MAC = 56;
break;
case si_TB_120:
size_SIB23_in_MAC = 120;
break;
case si_TB_208:
size_SIB23_in_MAC = 208;
break;
case si_TB_256:
size_SIB23_in_MAC = 256;
break;
case si_TB_328:
size_SIB23_in_MAC = 328;
break;
case si_TB_440:
size_SIB23_in_MAC = 440;
break;
case si_TB_552:
size_SIB23_in_MAC = 552;
break;
case si_TB_680:
size_SIB23_in_MAC = 680;
break;
default:
LOG_E(MAC,"No index for SIB23 size from SIB1!\n");
break;
}
return size_SIB23_in_MAC;
}
void schedule_sibs(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t sibs_order, int start_subframe1){
available_resource_DL_t *pt[8] = { (available_resource_DL_t *)0 };
int first_subframe[8] = { -1 };
//uint32_t end_subframe[8] = { -1 };
schedule_result_t *new_node;
DCIFormatN1_t *sibs_dci;
uint32_t j, i, k;
uint32_t SIB23_size = 0;
uint8_t *SIB23_pdu = get_NB_IoT_SIB23();
int residual_subframe, num_subframe, last_subframe;
uint8_t num_subframe_per_SIB = 0;
SIB23_size = get_SIB23_size();
if(SIB23_size > 0 && SIB23_size <= 120)
num_subframe_per_SIB = 2;
else if(SIB23_size > 120 && SIB23_size <= 680)
num_subframe_per_SIB = 8;
else
LOG_E(MAC,"Invalid SIB size\n");
num_subframe = num_subframe_per_SIB *4;
int rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[0].mac_npdcch_NumRepetitions_RA_NB_IoT;
rmax = (rmax * 10) >> 3; // x1.25
for(k=0, i=start_subframe1; i<(start_subframe1+mac_inst->rrc_config.si_window_length); i+=si_repetition_pattern[mac_inst->rrc_config.sibs_NB_IoT_sched[sibs_order].si_repetition_pattern], ++k){
LOG_D(MAC,"[debug][sibs%d] subframe: %d, check %d", sibs_order, i, num_subframe);
LOG_D(MAC,"[%d][%d][%d] [%d][%d]\n", i, start_subframe1, mac_inst->rrc_config.si_window_length, sibs_order, si_repetition_pattern[mac_inst->rrc_config.sibs_NB_IoT_sched[sibs_order].si_repetition_pattern]);
//system("pause");
#if 0 //disable new feature
// avoid to occupied others searching space. TODO: css, uss connect with configuration module
// start start+rmax
// i i+9
int continue_flag=0;
for(l=0; l<num_flags; ++l){
if((extend_space[l]>>extend_alpha_offset[l] <= i%extend_space[l] && ((extend_space[l]>>extend_alpha_offset[l])+rmax) >= i%extend_space[l]) ||
(extend_space[l]>>extend_alpha_offset[l] <= (i+9)%extend_space[l] && ((extend_space[l]>>extend_alpha_offset[l])+rmax) >= (i+9)%extend_space[l])){
continue_flag = 1;
}
}
if(continue_flag == 1)
continue;
#endif
pt[k] = (available_resource_DL_t *)check_sibs_resource(mac_inst, i, i+9, num_subframe, &residual_subframe, &last_subframe, &first_subframe[k]);
num_subframe = residual_subframe;
LOG_D(MAC,"-- rest: %d, last: %d start: %d\n", num_subframe, last_subframe, start_subframe1);
if(0==residual_subframe){LOG_D(MAC,"output\n\n");
sibs_dci = (DCIFormatN1_t *)malloc(sizeof(DCIFormatN1_t));
sibs_dci->type = 1;
sibs_dci->orderIndicator = 0;
sibs_dci->Scheddly = 0;
sibs_dci->ResAssign = 8;
sibs_dci->mcs = 2;
sibs_dci->RepNum = 0;
sibs_dci->ndi = 0;
sibs_dci->HARQackRes = 0;
sibs_dci->DCIRep = 0;
for(k=0, j=start_subframe1;j<=i;++k, j+=si_repetition_pattern[mac_inst->rrc_config.sibs_NB_IoT_sched[sibs_order].si_repetition_pattern]){
LOG_D(MAC,"for1 k=%d j=%d i=%d rep=%d\n", k, j, i, si_repetition_pattern[mac_inst->rrc_config.sibs_NB_IoT_sched[sibs_order].si_repetition_pattern]);
if((available_resource_DL_t *)0 != pt[k]){
new_node = (schedule_result_t *)malloc(sizeof(schedule_result_t));
// fill new node
new_node->output_subframe = first_subframe[k];
new_node->end_subframe = (j==i)?last_subframe:j+9;
new_node->sdu_length = SIB23_size;
new_node->DLSCH_pdu = SIB23_pdu;
new_node->direction = DL;
new_node->DCI_release = (j==i);
new_node->channel = NPDSCH;
new_node->rnti = 65535;
new_node->rnti_type = 1;
new_node->npusch_format = 0; // useless
new_node->R_harq = 0; // useless
new_node->next = (schedule_result_t *)0;
new_node->DCI_pdu = (void *)sibs_dci;
//new_node->debug_str = str[sibs_order];
LOG_D(MAC,"debug: pt[k]->start_subframe:%d output_subframe:%d end_subframe:%d rep:%d\n", pt[k]->start_subframe, first_subframe[k], (j==i)?last_subframe:j+9,si_repetition_pattern[mac_inst->rrc_config.sibs_NB_IoT_sched[sibs_order].si_repetition_pattern]);
fill_resource_DL(mac_inst, pt[k], first_subframe[k], (j==i)?last_subframe:j+9, new_node);
LOG_D(MAC,"for*2\n");
}
LOG_D(MAC,"for2\n");
}
return ;
}
}
return ;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file eNB_scheduler_dlsch_NB_IoT.c
* \brief handle DL UE-specific scheduling
* \author NTUST BMW Lab./Xavier LIU
* \date 2017 - 2018
* \email: sephiroth7277@gmail.com
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
/*DL scheduler*/
int schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info)
{
//number of candidate
int cdd_num;
//Transport block size
int TBS;
//Scheduling result buffer
sched_temp_DL_NB_IoT_t *NPDCCH_info = (sched_temp_DL_NB_IoT_t*)malloc(sizeof(sched_temp_DL_NB_IoT_t));
sched_temp_DL_NB_IoT_t *NPDSCH_info = (sched_temp_DL_NB_IoT_t*)malloc(sizeof(sched_temp_DL_NB_IoT_t));
sched_temp_UL_NB_IoT_t *HARQ_info = (sched_temp_UL_NB_IoT_t*)malloc(sizeof(sched_temp_UL_NB_IoT_t));
//DCI N1
//DCIFormatN1_t *DCI_N1 = (DCIFormatN1_t*)malloc(sizeof(DCIFormatN1_t));
//RLC Status
//mac_rlc_status_resp_NB_IoT_t rlc_status;
/*Index in DCI_N1*/
uint32_t I_mcs, I_tbs, I_delay, I_sf;
/*value for corresponding index*/
/*Number of subframe per repetition*/
int n_sf;
/*flag*/
int end_flagCCH=0;
int end_flagSCH=0;
int end_flagHARQ=0;
int flag_retransmission=0;
int HARQ_delay=0;
uint32_t data_size;
//uint32_t mac_sdu_size;
//uint8_t sdu_temp[SCH_PAYLOAD_SIZE_MAX_NB_IoT];
//logical_chan_id_t logical_channel;
uint32_t subheader_length=2;
//uint32_t payload_offset;
uint32_t search_space_end_sf, h_temp, f_temp, sf_temp;
I_mcs = get_I_mcs(UE_info->CE_level);
I_tbs = I_mcs;
//get max TBS
TBS = get_max_tbs(I_tbs);
if(UE_info->HARQ_round==0)
{
flag_retransmission=0;
data_size=UE_sched_ctrl_info->total_sdu_size;
}
else
{
flag_retransmission=1;
data_size=UE_info->DLSCH_pdu_size;
}
LOG_D(MAC,"[%04d][DLSchedulerUSS] Max TBS %d MCS index %d TBS index %d\n", mac_inst->current_subframe, TBS, I_mcs, I_tbs);
/*set UE data information*/
/*New transmission*/
#if 0
if(UE_info->HARQ_round==0)
{
//Get RLC status
/*
rlc_status = mac_rlc_status_ind_NB_IoT(
module_id,
UE_info->rnti,
module_id,
frame_start,
subframe_start,
1,
0,
DCCH0_NB_IoT,
0);
data_size = rlc_status.bytes_in_buffer;
*/
//data_size = 200;
data_size=0;
int ue_index;
for(ue_index=0;ue_index<UE_NUM_SIM;++ue_index)
{
if(UE_info_sim[ue_index].tc_rnti==UE_info->rnti)
data_size = UE_info_sim[ue_index].data_size;
}
}
/*Retransmission*/
else
{
data_size = UE_info->DLSCH_pdu_size;
flag_retransmission = 1;
if((UE_info->HARQ_round>0)&&(TBS<data_size))
{
LOG_D(MAC,"[%04d][DLSchedulerUSS][Fail] TBS is not enough for retransmission\n", mac_inst->current_subframe);
return;
}
}
#endif
data_size=200; //for testing
LOG_D(MAC,"[%04d][DLSchedulerUSS] UE data size %d\n", mac_inst->current_subframe, data_size);
//Have DCCH data
if(data_size == 0)
{
LOG_D(MAC,"[%04d][DLSchedulerUSS][Fail] No data in DCCH0_NB_IoT\n", mac_inst->current_subframe);
return -1;
}
if(data_size>127)
{
subheader_length=3;
}
if(TBS > data_size+subheader_length)
{
TBS = get_tbs(data_size, I_tbs, &I_sf);
LOG_D(MAC,"[%04d][DLSchedulerUSS] TBS change to %d because data size is smaller than previous TBS\n", mac_inst->current_subframe, TBS);
}
search_space_end_sf=cal_num_dlsf(mac_inst, hyperSF_start, frame_start, subframe_start, &h_temp, &f_temp, &sf_temp, UE_info->R_max);
LOG_D(MAC,"[%04d][DLSchedulerUSS] Search_space_start_sf %d Search_space_end_sf %d\n", convert_system_number_sf(hyperSF_start, frame_start, subframe_start), mac_inst->current_subframe, search_space_end_sf);
//LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] Search_space_start_sf %d Search_space_end_sf %d\n", mac_inst->current_subframe, UE_info->rnti, mac_inst->current_subframe, convert_system_number_sf(hyperSF_start, frame_start, subframe_start), search_space_end_sf);
/*Loop all NPDCCH candidate position*/
for(cdd_num=0;cdd_num<UE_info->R_max/UE_sched_ctrl_info->R_dci;++cdd_num)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Candidate num %d DCI Rep %d\n",mac_inst->current_subframe, cdd_num, UE_sched_ctrl_info->R_dci);
/*Check NPDCCH Resource*/
end_flagCCH = check_resource_NPDCCH_NB_IoT(mac_inst, hyperSF_start, frame_start, subframe_start, NPDCCH_info, cdd_num, UE_info->R_dci);
//This candidate position is available
/*Check NPDSCH Resource*/
if(end_flagCCH!=-1)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Candidate num %d allocate success\n",mac_inst->current_subframe, cdd_num);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Allocate NPDCCH subframe %d to subframe %d cdd index %d\n", mac_inst->current_subframe, NPDCCH_info->sf_start, NPDCCH_info->sf_end, cdd_num);
//Max DL TBS
if(TBS > data_size+subheader_length)
{
TBS = get_tbs(data_size, I_tbs, &I_sf);
LOG_D(MAC,"[%04d][DLSchedulerUSS] [%d] data_size %d TBS change to %d \n", mac_inst->current_subframe,UE_info->rnti, data_size, TBS);
}
//Get number of subframe this UE need per repetition
n_sf = get_num_sf(I_sf);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Number SF %d index SF %d\n",mac_inst->current_subframe, n_sf, I_sf);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Require total %d DL SF Rep %d\n", n_sf*UE_sched_ctrl_info->R_dl, UE_sched_ctrl_info->R_dl);
//Check have enough NPDSCH resource or not
//loop 8 scheduling delay index
for(I_delay=0;I_delay<8;++I_delay)
{
if(search_space_end_sf<NPDCCH_info->sf_end+get_scheduling_delay(I_delay, UE_info->R_max)+5)
{
end_flagSCH = check_resource_NPDSCH_NB_IoT(mac_inst, NPDSCH_info, NPDCCH_info->sf_end, I_delay, UE_info->R_max, UE_sched_ctrl_info->R_dl_data, n_sf);
//Have available resource
/*Check HARQ resource*/
if(end_flagSCH!=-1)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Scheduling delay index: %d value: %d + 4 allocate success\n", mac_inst->current_subframe, I_delay, get_scheduling_delay(I_delay, UE_info->R_max));
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Allocate NPDSCH subframe %d to subframe %d\n", mac_inst->current_subframe, NPDSCH_info->sf_start, NPDSCH_info->sf_end);
for(HARQ_delay=0;HARQ_delay<4;++HARQ_delay)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] HARQ delay %d\n", mac_inst->current_subframe,get_HARQ_delay(1, HARQ_delay) );
end_flagHARQ=Check_UL_resource(NPDSCH_info->sf_end+get_HARQ_delay(1, HARQ_delay), UE_sched_ctrl_info->R_dl_harq, HARQ_info, 0, 1);
if(end_flagHARQ!=-1)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Allocate HARQ feedback subframe %d to subframe %d\n", mac_inst->current_subframe, HARQ_info->sf_start, HARQ_info->sf_end);
HARQ_info->ACK_NACK_resource_field=get_resource_field_value(HARQ_info->subcarrier_indication, get_scheduling_delay(HARQ_delay, UE_info->R_max));
//toggle NDI
if(flag_retransmission==0)
{
UE_info->oldNDI_DL=(UE_info->oldNDI_DL+1)%2;
//New transmission need to request data from RLC and generate new MAC PDU
UE_info->I_mcs_dl = I_mcs;
/*.......
//Request data from RLC layer
rlc_status = mac_rlc_status_ind_NB_IoT(
module_id,
UE_info->rnti,
module_id,
frame_start,
subframe_start,
1,
0,
DCCH0_NB_IoT,
TBS-subheader_length);
*/
//mac_sdu_size = mac_rlc_data_req_eNB_NB_IoT(module_id, UE_info->rnti, 0, frame_start, 0, DCCH0_NB_IoT, sdu_temp);
//channel=DCCH0_NB_IoT;
//Generate header
//payload_offset = generate_dlsch_header_NB_IoT(UE_info->DLSCH_pdu.payload, 1, &logical_channel, &mac_sdu_size, 0, 0, TBS);
//Complete MAC PDU
//memcpy(UE_info->DLSCH_pdu.payload+payload_offset, sdu_temp, mac_sdu_size);
//UE_info->DLSCH_pdu.pdu_size=TBS;
UE_sched_ctrl_info->NPDCCH_sf_end=NPDCCH_info->sf_end;
UE_sched_ctrl_info->NPDCCH_sf_start=NPDCCH_info->sf_start;
UE_sched_ctrl_info->NPDSCH_sf_end=NPDSCH_info->sf_end;
UE_sched_ctrl_info->NPDSCH_sf_start=NPDSCH_info->sf_start;
UE_sched_ctrl_info->HARQ_sf_end=HARQ_info->sf_end;
UE_sched_ctrl_info->HARQ_sf_start=HARQ_info->sf_start;
UE_sched_ctrl_info->TBS=TBS;
UE_sched_ctrl_info->dci_n1_index_mcs=I_mcs;
UE_sched_ctrl_info->index_tbs=I_tbs;
UE_sched_ctrl_info->dci_n1_index_sf=I_sf;
UE_sched_ctrl_info->dci_n1_n_sf=n_sf;
UE_sched_ctrl_info->dci_n1_index_delay=I_delay;
UE_sched_ctrl_info->dci_n1_index_ack_nack=HARQ_info->ACK_NACK_resource_field;
UE_sched_ctrl_info->total_data_size_dl=data_size;
}
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Success] Complete scheduling with data size %d\n", mac_inst->current_subframe, UE_info->rnti, data_size);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] RNTI %d\n", mac_inst->current_subframe, UE_info->rnti);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Success] Allocate NPDCCH subframe %d to subframe %d candidate index %d\n", mac_inst->current_subframe, UE_info->rnti, NPDCCH_info->sf_start, NPDCCH_info->sf_end, cdd_num);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Success] Scheduling delay index: %d value: %d + 4\n", mac_inst->current_subframe, UE_info->rnti, I_delay, get_scheduling_delay(I_delay, UE_info->R_max));
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Success] Allocate NPDSCH subframe %d to subframe %d\n", mac_inst->current_subframe, UE_info->rnti, NPDSCH_info->sf_start, NPDSCH_info->sf_end);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Success] Allocate HARQ feedback subframe %d to subframe %d\n", mac_inst->current_subframe, UE_info->rnti, HARQ_info->sf_start, HARQ_info->sf_end);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] Allocate NPDCCH subframe %d to subframe %d candidate index %d\n", mac_inst->current_subframe, UE_info->rnti, NPDCCH_info->sf_start, NPDCCH_info->sf_end, cdd_num);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] Scheduling delay index: %d value: %d + 4\n", mac_inst->current_subframe, UE_info->rnti, I_delay, get_scheduling_delay(I_delay, UE_info->R_max));
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] Allocate NPDSCH subframe %d to subframe %d\n", mac_inst->current_subframe, UE_info->rnti, NPDSCH_info->sf_start, NPDSCH_info->sf_end);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] Allocate HARQ feedback subframe %d to subframe %d\n", mac_inst->current_subframe, UE_info->rnti, HARQ_info->sf_start, HARQ_info->sf_end);
//Store PDU in UE template for retransmission
//fill_DCI_N1(DCI_N1, UE_info, I_delay, I_sf, HARQ_info->ACK_NACK_resource_field);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] HARQ index %d\n", HARQ_info->ACK_NACK_resource_field);
//LOG_D(MAC,"[%04d][DLSchedulerUSS][%d] DCI N1 type:%d order:%d MCS:%d HARQ index:%d R:%d RscAssign:%d scheddly:%d DCI_R:%d\n", mac_inst->current_subframe, UE_info->rnti, DCI_N1->type, DCI_N1->orderIndicator, DCI_N1->mcs, DCI_N1->HARQackRes, DCI_N1->RepNum, DCI_N1->ResAssign, DCI_N1->Scheddly, DCI_N1->DCIRep);
//Generate Scheduling result for this UE
//generate_scheduling_result_DL(NPDCCH_info->sf_start, NPDSCH_info->sf_start, HARQ_info->sf_start, DCI_N1, UE_info->rnti, TBS, UE_info->DLSCH_pdu.payload);
//generate_scheduling_result_DL(NPDCCH_info, NPDSCH_info, HARQ_info, DCI_N1, UE_info->rnti, TBS, UE_info->DLSCH_pdu.payload);
//LOG_D(MAC,"[%04d][DLSchedulerUSS] finish generate scheduling result\n");
//matain DL avialable resource
maintain_resource_DL(mac_inst, NPDCCH_info, NPDSCH_info);
//available_resource_DL_t *temp = available_resource_DL;
/*
while(temp!=NULL)
{
LOG_D(MAC,"[%04d][DLSchedulerUSS] Available resource node subframe start %d end %d\n", mac_inst->current_subframe, temp->start_subframe, temp->end_subframe);
temp=temp->next;
}
*/
//Do maintain UL resource
adjust_UL_resource_list(HARQ_info);
LOG_D(MAC,"[%04d][DLSchedulerUSS] Complete DL scheduling\n", mac_inst->current_subframe);
//Change the UE state to idle
UE_info->direction = -1;
//LOG_D(MAC,"[%04d][DLSchedulerUSS] RNTI %d complete scheduling\n", mac_inst->current_subframe, UE_info->rnti);
return 0;
}
}
/*harq resource fail*/
if(end_flagHARQ==-1)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] [Fail]HARQ_delay %d HARQ Resource fail\n", mac_inst->current_subframe, HARQ_delay);
}
}
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Scheduling delay index %d allocate fail\n", mac_inst->current_subframe, I_delay);
}
}
/*NPDSCH resource fail*/
if(end_flagSCH==-1)
{
//LOG_D(MAC,"[%04d][DLSchedulerUSS] [Fail]I_delay %d NPDSCH Resource fail\n", mac_inst->current_subframe, I_delay);
}
}
//LOG_D(MAC,"[%04d][DLSchedulerUSS] Candidate %d no resource\n", mac_inst->current_subframe, cdd_num);
}
UE_sched_ctrl_info->flag_schedule_success=0;
/*Resource allocate fail*/
if((end_flagCCH==-1)||(end_flagSCH==-1)||(end_flagHARQ==-1))
{
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Fail] Resource allocate fail\n", mac_inst->current_subframe, UE_info->rnti);
LOG_D(MAC,"[%04d][DLSchedulerUSS][%d][Fail] Resource allocate fail\n", mac_inst->current_subframe, UE_info->rnti);
}
return -1;
}
int check_resource_NPDCCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, sched_temp_DL_NB_IoT_t *NPDCCH_info, uint32_t cdd_num, uint32_t dci_rep)
{
NPDCCH_info->sf_start = cal_num_dlsf(mac_inst, hyperSF_start, frame_start, subframe_start, &(NPDCCH_info->start_h), &(NPDCCH_info->start_f), &(NPDCCH_info->start_sf), dci_rep*cdd_num+1);
//LOG_D(MAC,"[%04d][check_resource_NPDCCH_NB_IoT] NPDCCH sf start %d\n", mac_inst->current_subframe, NPDCCH_info->sf_start);
//LOG_D(MAC,"[check_resource_NPDCCH_NB_IoT]abs start : %d\n", NPDCCH_info->sf_start);
return check_resource_DL_NB_IoT(mac_inst, NPDCCH_info->start_h, NPDCCH_info->start_f, NPDCCH_info->start_sf, dci_rep, NPDCCH_info);
}
int check_resource_NPDSCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDSCH_info, uint32_t sf_end, uint32_t I_delay, uint32_t R_max, uint32_t R_dl, uint32_t n_sf)
{
int sf_temp = sf_end+get_scheduling_delay(I_delay, R_max)+5;
while(is_dlsf(mac_inst, sf_temp)!=1)
{
++sf_temp;
}
NPDSCH_info->sf_start = sf_temp;
//transform sf into Hyper SF, Frame and subframe
convert_system_number(NPDSCH_info->sf_start,&(NPDSCH_info->start_h), &(NPDSCH_info->start_f), &(NPDSCH_info->start_sf));
//check this position available or not
return check_resource_DL_NB_IoT(mac_inst, NPDSCH_info->start_h, NPDSCH_info->start_f, NPDSCH_info->start_sf, R_dl*n_sf, NPDSCH_info);
}
/*Check the available resource is enough or not from input starting position*/
/*return 0:success\1:fail*/
int check_resource_DL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, uint32_t dlsf_require, sched_temp_DL_NB_IoT_t *schedule_info)
{
uint32_t node_start_sf, node_end_sf;
uint32_t rsc_start_sf, rsc_end_sf;
/*calculate the last subframe number for this transmission*/
schedule_info->sf_end= cal_num_dlsf(mac_inst, hyperSF_start, frame_start, subframe_start, &(schedule_info->end_h), &(schedule_info->end_f), &(schedule_info->end_sf), dlsf_require);
//LOG_D(MAC,"abs_end = %d\n", schedule_info->sf_end);
rsc_start_sf = schedule_info->sf_start;
if(schedule_info->sf_start<=schedule_info->sf_end)
{
rsc_end_sf = schedule_info->sf_end;
}
else
{
/*input position + Upper bound of subframe*/
rsc_end_sf = schedule_info->sf_end+(1024*1024*10);
}
//LOG_D(MAC,"check_resource_DL_NB_IoT flag 1\n");
/*initialize*/
schedule_info->node = available_resource_DL;
//LOG_D(MAC,"rsc need start subframe %d end subframe %d\n", rsc_start_sf, rsc_end_sf);
/*Check available resource nodes to find the appropriate resource position*/
while(schedule_info->node!=NULL)
{
//schedule_info->node->start_subframe <= schedule_info->sf_end
//LOG_D(MAC,"check_resource_DL_NB_IoT flag 2\n");
node_start_sf = schedule_info->node->start_subframe;
if(schedule_info->node->start_subframe<=schedule_info->node->end_subframe)
{
node_end_sf = schedule_info->node->end_subframe;
}
else
{
/*input position + Upper bound of subframe*/
node_end_sf = schedule_info->node->end_subframe+(1024*1024*10);
}
//LOG_D(MAC,"node start %d node end %d\n", node_start_sf, node_end_sf);
if((node_start_sf<=rsc_start_sf)&&(node_end_sf>=rsc_end_sf))
{
return 0;
}
schedule_info->node = schedule_info->node->next;
}
//LOG_D(MAC,"check_resource_DL_NB_IoT flag 3\n");
return -1;
}
uint32_t generate_dlsch_header_NB_IoT(uint8_t *pdu, uint32_t num_sdu, logical_chan_id_t *logical_channel, uint32_t *sdu_length, uint8_t flag_drx, uint8_t flag_ta, uint32_t TBS)
{
int i;
uint32_t total_sdu_size=0;
//number of control element
uint32_t num_ce=0;
uint32_t num_subheader=0;
uint32_t num_sdu_L_15;
int32_t padding_size;
uint8_t flag_end_padding=0;
SCH_SUBHEADER_FIXED_NB_IoT *mac_header=(SCH_SUBHEADER_FIXED_NB_IoT*)pdu;
uint32_t offset=0;
for(i=0;i<num_sdu;++i)
{
LOG_D(MAC,"index %d sdu size %d\n", i, sdu_length[i]);
if(sdu_length[i]>127)
{
num_sdu_L_15++;
}
total_sdu_size+=sdu_length[i];
}
if(flag_drx==1)
num_ce++;
if(flag_ta==1)
num_ce++;
num_subheader=num_ce+num_sdu;
padding_size = TBS-total_sdu_size-num_ce;
if(padding_size<0)
{
LOG_D(MAC,"[ERROR]TBS less than require subheader and control element\n");
return -1;
}
LOG_D(MAC,"total SDU size %d\n", total_sdu_size);
LOG_D(MAC,"padding size %d\n", padding_size);
if(padding_size>2)
{
flag_end_padding=1;
}
if((padding_size<=2)&&(padding_size>0))
{
mac_header->LCID=PADDING;
mac_header->E=1;
//mac_header->F2=0;
mac_header->R=0;
mac_header++;
offset++;
}
if(padding_size==2)
{
mac_header->LCID=PADDING;
mac_header->E=1;
//mac_header->F2=0;
mac_header->R=0;
mac_header++;
offset++;
}
if(flag_drx==1)
{
mac_header->LCID=DRX_COMMAND;
mac_header->E=1;
//mac_header->F2=0;
mac_header->R=0;
mac_header++;
num_subheader--;
offset++;
}
for(i=0;i<num_sdu;++i)
{
if((num_subheader==1)&&(flag_end_padding!=1))
{
mac_header->E=0;
mac_header->LCID = logical_channel[i];
//mac_header->F2=0;
mac_header->R=0;
offset++;
LOG_D(MAC,"last sdu\n");
}
else
{
if(sdu_length[i]<128)
{
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->LCID = logical_channel[i];
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->F2=0;
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->R=0;
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->E=1;
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->F=0;
((SCH_SUBHEADER_SHORT_NB_IoT*)mac_header)->L=(uint8_t)sdu_length[i];
num_subheader--;
mac_header+=2;
offset+=2;
}
else
{
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->LCID = logical_channel[i];
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->F2=0;
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->R=0;
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->F=1;
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->E=1;
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->L_MSB=(uint8_t)(sdu_length[i]/256);
((SCH_SUBHEADER_LONG_NB_IoT*)mac_header)->L_LSB=(uint8_t)(sdu_length[i]%256);
mac_header+=3;
num_subheader--;
offset+=3;
}
}
}
if(flag_end_padding==1)
{
mac_header->LCID=PADDING;
mac_header->E=0;
//mac_header->F2=0;
mac_header->R=0;
mac_header++;
offset++;
}
return offset;
}
void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info)
{
DCI_N1->type=1;
DCI_N1->orderIndicator = 0;
DCI_N1->Scheddly = UE_sched_ctrl_info->dci_n1_index_delay;
DCI_N1->ResAssign =UE_sched_ctrl_info->dci_n1_index_sf;
DCI_N1->mcs = UE_sched_ctrl_info->dci_n1_index_mcs;
DCI_N1->RepNum = UE_sched_ctrl_info->dci_n1_index_sf;
DCI_N1->HARQackRes = UE_sched_ctrl_info->dci_n1_index_ack_nack;
//DCI_N1->DCIRep = 3-UE_info->R_max/UE_info->R_dci/2;
DCI_N1->DCIRep=get_DCI_REP(UE_sched_ctrl_info->R_dci, UE_info->R_max);
LOG_D(MAC,"[fill_DCI_N1] Type %d order %d I_delay %d I_SF %d I_mcs %d I_rep %d I_harq %d I_dci %d\n", DCI_N1->type, DCI_N1->orderIndicator, DCI_N1->Scheddly, DCI_N1->ResAssign, DCI_N1->mcs, DCI_N1->RepNum, DCI_N1->HARQackRes, DCI_N1->DCIRep);
}
void generate_scheduling_result_DL(uint32_t NPDCCH_sf_end, uint32_t NPDCCH_sf_start, uint32_t NPDSCH_sf_end, uint32_t NPDSCH_sf_start, uint32_t HARQ_sf_end, uint32_t HARQ_sf_start, DCIFormatN1_t *DCI_pdu, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu)
{
// create the schedule result node for this time transmission
schedule_result_t *NPDCCH_result = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_t *NPDSCH_result = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_t *HARQ_result = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_t *tmp, *tmp1;
/*fill NPDCCH result*/
NPDCCH_result->rnti=rnti;
NPDCCH_result->output_subframe = NPDCCH_sf_start;
NPDCCH_result->end_subframe = NPDCCH_sf_end;
NPDCCH_result->sdu_length = TBS;
NPDCCH_result->direction = 1;
NPDCCH_result->rnti_type = 3;
NPDCCH_result->DLSCH_pdu = NULL;
NPDCCH_result->DCI_pdu = (void*)DCI_pdu;
NPDCCH_result->DCI_release = 0;
NPDCCH_result->channel = NPDCCH;
//NPDCCH_result->debug_str = (uint8_t*)malloc(6*sizeof(uint8_t));
//NPDCCH_result->debug_str = dl_str1;
NPDCCH_result->next = NULL;
/*fill NPDSCH result*/
NPDSCH_result->rnti=rnti;
//NPDSCH_result->output_subframe = NPDSCH_subframe;
NPDSCH_result->output_subframe = NPDSCH_sf_start;
NPDSCH_result->end_subframe = NPDSCH_sf_end;
NPDSCH_result->sdu_length = TBS;
//NPDSCH_result->DLSCH_pdu = DLSCH_pdu;
NPDSCH_result->DLSCH_pdu = NULL;
NPDSCH_result->direction = 1;
NPDSCH_result->rnti_type = 3;
NPDSCH_result->DCI_pdu = (void*)DCI_pdu;
NPDSCH_result->DCI_release = 0;
NPDSCH_result->channel = NPDSCH;
//NPDSCH_result->debug_str = (uint8_t*)malloc(7*sizeof(uint8_t));
//NPDSCH_result->debug_str = dl_str2;
NPDSCH_result->next = NULL;
/*fill HARQ result*/
HARQ_result->rnti=rnti;
//HARQ_result->output_subframe = HARQ_subframe;
HARQ_result->output_subframe = HARQ_sf_start;
HARQ_result->end_subframe = HARQ_sf_end;
HARQ_result->sdu_length = 0;
HARQ_result->direction = 0;
HARQ_result->rnti_type = 3;
HARQ_result->DLSCH_pdu = NULL;
HARQ_result->DCI_pdu = (void*)DCI_pdu;
HARQ_result->DCI_release = 1;
HARQ_result->channel = NPUSCH;
HARQ_result->npusch_format = 1;
//HARQ_result->debug_str = (uint8_t*)malloc(7*sizeof(uint8_t));
//HARQ_result->debug_str = dl_str3;
HARQ_result->next = NULL;
//DEBUG("[generate_scheduling_result_DL] Generate NPDCCH node\n");
/*NPDCCH scheduling result*/
// be the first node of the DL scheduling result
tmp = NULL;
tmp1 = NULL;
if(schedule_result_list_DL == NULL)
{
//schedule_result_list_DL = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_list_DL = NPDCCH_result;
//DEBUG("[generate_scheduling_result_DL] Generate NPDCCH node at head\n");
}
else
{
tmp = schedule_result_list_DL;
while(tmp!=NULL)
{
if(NPDCCH_sf_start < tmp->output_subframe)
{
break;
}
tmp1 = tmp;
tmp = tmp->next;
//DEBUG("[generate_scheduling_result_DL] node output subframe %d at NPDCCH part\n", tmp->output_subframe);
}
/*tail*/
if(tmp==NULL)
{
tmp1->next = NPDCCH_result;
}
else
{
NPDCCH_result->next = tmp;
if(tmp1)
{
tmp1->next = NPDCCH_result;
}
else
{
schedule_result_list_DL = NPDCCH_result;
}
}
}
//DEBUG("[generate_scheduling_result_DL] Generate NPDCSH node\n");
/*NPDSCH scheduling result*/
tmp1 = NULL;
tmp = schedule_result_list_DL;
while(tmp!=NULL)
{
if(NPDSCH_sf_start < tmp->output_subframe)
{
break;
}
//DEBUG("[generate_scheduling_result_DL] node output subframe %d at NPDSCH part\n", tmp->output_subframe);
tmp1 = tmp;
tmp = tmp->next;
}
if(tmp==NULL)
{
tmp1->next = NPDSCH_result;
}
else
{
NPDSCH_result->next = tmp;
if(tmp1)
{
tmp1->next = NPDSCH_result;
}
else
{
schedule_result_list_DL = NPDSCH_result;
}
}
//DEBUG("[generate_scheduling_result_DL] Generate HARQ node\n");
/*HARQ scheduling result*/
// be the first node of UL
// be the first node of UL
#if 1
tmp1 = NULL;
tmp = NULL;
if(schedule_result_list_UL == NULL)
{
//DEBUG("[generate_scheduling_result_DL] LIST NULL, Generate HARQ at HEAD\n");
//schedule_result_list_UL = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_list_UL = HARQ_result;
}
else
{
tmp = schedule_result_list_UL;
while(tmp!=NULL)
{
if(HARQ_sf_start < tmp->output_subframe)
{
break;
}
//DEBUG("[generate_scheduling_result_DL] node output subframe %d at HARQ part\n", tmp->output_subframe);
tmp1 = tmp;
tmp = tmp->next;
}
if(tmp==NULL)
{
//DEBUG("[generate_scheduling_result_DL] Generate HARQ at Tail\n");
tmp1->next = HARQ_result;
}
else
{
HARQ_result->next = tmp;
if(tmp1)
{
//DEBUG("[generate_scheduling_result_DL] Generate HARQ in normal\n");
tmp1->next = HARQ_result;
}else
{
//DEBUG("[generate_scheduling_result_DL] Generate HARQ at Head\n");
schedule_result_list_UL = HARQ_result;
}
}
}
#endif
}
void maintain_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDCCH_info, sched_temp_DL_NB_IoT_t *NPDSCH_info)
{
available_resource_DL_t *temp;
uint8_t flag_same=0;
int align_left;
int align_right;
uint32_t H_temp, f_temp, sf_temp;
uint32_t H_temp_r, f_temp_r, sf_temp_r;
if(NPDSCH_info==NULL)
{
/****Maintain NPDCCH node*******/
// divided into two node
// keep one node(align left or right)
// delete node
convert_system_number(NPDCCH_info->node->start_subframe, &H_temp, &f_temp, &sf_temp);
//align_left = (calculate_DLSF(mac_inst, NPDCCH_info->node->start_subframe, NPDCCH_info->sf_start) == 0);
align_left=(cal_num_dlsf(mac_inst, H_temp, f_temp, sf_temp, &H_temp_r, &f_temp_r, &sf_temp_r, 1)==NPDCCH_info->sf_start);
align_right = ((calculate_DLSF(mac_inst, NPDCCH_info->sf_end, NPDCCH_info->node->end_subframe) == 0)||(NPDCCH_info->sf_end==NPDCCH_info->node->end_subframe));
//align_left = (calculate_DLSF(mac_inst, NPDCCH_info->node->start_subframe, NPDCCH_info->sf_start) == 0);
//LOG_D(MAC,"[maintain_resource_DL] align left %d align right %d\n", align_left, align_right);
switch(align_left+align_right)
{
case 0:
// divided into two nodes, insert after oritinal node.
// A | node | B
// A | node | temp | B
temp = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
if((available_resource_DL_t *)0 == NPDCCH_info->node->next){
available_resource_DL_last = temp;
}else{
NPDCCH_info->node->next->prev = temp;
}
temp->next = NPDCCH_info->node->next;
temp->prev = NPDCCH_info->node;
NPDCCH_info->node->next = temp;
temp->start_subframe = NPDCCH_info->sf_end+1;
temp->end_subframe = NPDCCH_info->node->end_subframe;
NPDCCH_info->node->end_subframe = NPDCCH_info->sf_start - 1;
break;
case 1:
// keep one node
if(align_left)
{
NPDCCH_info->node->start_subframe = NPDCCH_info->sf_end+1;
}
else
{
NPDCCH_info->node->end_subframe = NPDCCH_info->sf_start-1 ;
}
break;
case 2:
// delete
// process next node element.
if(NPDCCH_info->node->prev==NULL){
// first node of list
available_resource_DL = NPDCCH_info->node->next;
}else{
NPDCCH_info->node->prev->next = NPDCCH_info->node->next;
}
// process prev node element.
if(NPDCCH_info->node->next!=NULL){
NPDCCH_info->node->next->prev = NPDCCH_info->node->prev;
}else{
// end node of list
available_resource_DL_last = NPDCCH_info->node->prev;
}
free(NPDCCH_info->node);
break;
default:
//error
break;
free(NPDCCH_info);
}
}
else
{
if(NPDCCH_info->node==NPDSCH_info->node)
{
flag_same=1;
LOG_D(MAC,"[%04d][maintain_resource_DL] NPDCCH and NPDSCH using the same node\n", mac_inst->current_subframe);
}
/****Maintain NPDCCH node*******/
// divided into two node
// keep one node(align left or right)
// delete node
convert_system_number(NPDCCH_info->node->start_subframe, &H_temp, &f_temp, &sf_temp);
//align_left = (calculate_DLSF(mac_inst, NPDCCH_info->node->start_subframe, NPDCCH_info->sf_start) == 0);
align_left=(cal_num_dlsf(mac_inst, H_temp, f_temp, sf_temp, &H_temp_r, &f_temp_r, &sf_temp_r, 1)==NPDCCH_info->sf_start);
align_right = ((calculate_DLSF(mac_inst, NPDCCH_info->sf_end, NPDCCH_info->node->end_subframe) == 0)||(NPDCCH_info->sf_end==NPDCCH_info->node->end_subframe));
//LOG_D(MAC,"[maintain_resource_DL] align left %d align right %d\n", align_left, align_right);
switch(align_left+align_right)
{
case 0:
// divided into two nodes, insert after oritinal node.
// A | node | B
// A | node | temp | B
temp = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
if((available_resource_DL_t *)0 == NPDCCH_info->node->next){
available_resource_DL_last = temp;
}else{
NPDCCH_info->node->next->prev = temp;
}
temp->next = NPDCCH_info->node->next;
temp->prev = NPDCCH_info->node;
NPDCCH_info->node->next = temp;
temp->start_subframe = NPDCCH_info->sf_end+1;
temp->end_subframe = NPDCCH_info->node->end_subframe;
NPDCCH_info->node->end_subframe = NPDCCH_info->sf_start - 1;
if(flag_same==1)
{
NPDSCH_info->node = temp;
}
break;
case 1:
// keep one node
if(align_left)
{
NPDCCH_info->node->start_subframe = NPDCCH_info->sf_end+1;
LOG_D(MAC,"[%04d][maintain_resource_DL] NPDCCH keep one node\n", mac_inst->current_subframe);
}
else
{
NPDCCH_info->node->end_subframe = NPDCCH_info->sf_start-1 ;
}
break;
case 2:
// delete
LOG_D(MAC,"[%04d][maintain_resource_DL] NPDCCH delete node\n", mac_inst->current_subframe);
// calvin add
// delete
// process next node element.
if(NPDCCH_info->node->prev==NULL){
// first node of list
available_resource_DL = NPDCCH_info->node->next;
}else{
NPDCCH_info->node->prev->next = NPDCCH_info->node->next;
}
// process prev node element.
if(NPDCCH_info->node->next!=NULL){
NPDCCH_info->node->next->prev = NPDCCH_info->node->prev;
}else{
// end node of list
available_resource_DL_last = NPDCCH_info->node->prev;
}
free(NPDCCH_info->node);
break;
default:
//error
break;
}
/****Maintain NPDSCH node*******/
align_left = (calculate_DLSF(mac_inst, NPDSCH_info->node->start_subframe, NPDSCH_info->sf_start) == 0);
align_right = ((calculate_DLSF(mac_inst, NPDSCH_info->sf_end, NPDSCH_info->node->end_subframe) == 0)||(NPDSCH_info->sf_end==NPDSCH_info->node->end_subframe));
switch(align_left+align_right)
{
case 0:
// divided into two nodes, insert after oritinal node.
// A | node | B
// A | node | temp | B
temp = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
if((available_resource_DL_t *)0 == NPDSCH_info->node->next){
available_resource_DL_last = temp;
}else{
NPDSCH_info->node->next->prev = temp;
}
temp->next = NPDSCH_info->node->next;
temp->prev = NPDSCH_info->node;
NPDSCH_info->node->next = temp;
temp->start_subframe = NPDSCH_info->sf_end+1;
temp->end_subframe = NPDSCH_info->node->end_subframe;
NPDSCH_info->node->end_subframe = NPDSCH_info->sf_start - 1;
break;
case 1:
// keep one node
if(align_left)
{
NPDSCH_info->node->start_subframe = NPDSCH_info->sf_end+1;
}
else
{
NPDSCH_info->node->end_subframe = NPDSCH_info->sf_start-1 ;
}
break;
case 2:
// delete
if(NPDSCH_info->node->prev==NULL){
// first node of list
available_resource_DL = NPDSCH_info->node->next;
}else{
NPDSCH_info->node->prev->next = NPDSCH_info->node->next;
}
// process prev node element.
if(NPDSCH_info->node->next!=NULL){
NPDSCH_info->node->next->prev = NPDSCH_info->node->prev;
}else{
// end node of list
available_resource_DL_last = NPDSCH_info->node->prev;
}
free(NPDSCH_info->node);
break;
default:
//error
break;
}
free(NPDCCH_info);
free(NPDSCH_info);
}
}
//// get I_TBS for any NPUSCH config
uint8_t I_TBS_index_single_tone[11]= {0,2,1,3,4,5,6,7,8,9,10};
uint8_t get_UL_I_TBS_from_MCS_NB_IoT(uint8_t I_mcs, uint8_t N_sc_RU, uint8_t Msg3_flag)
{
if(Msg3_flag == 1)
{
return I_mcs;
} else {
if(N_sc_RU == 1)
{
return I_TBS_index_single_tone[I_mcs];
} else {
return I_mcs;
}
}
}
/////////////////
///////////////////////////////////////////////
//// function to test if configuration is single or multi-tone //// 1 for single and 0 for multi-tone
uint8_t test_signle_tone_UL_NB_IoT(uint8_t subcarrier_spacing, uint8_t I_sc, uint8_t npush_format)
{
if(npush_format == 0) // format 1
{
if(subcarrier_spacing == 0) // 15 KHz
{
if(I_sc >= 0 && I_sc < 12)
{
return 1;
} else if (I_sc >= 12 && I_sc < 16) {
return 0;
} else if (I_sc >= 16 && I_sc < 18) {
return 0;
} else if (I_sc == 18) {
return 0;
} else {
return 1;
}
} else {
return 1;
}
} else { /// format 2
return 1;
}
}
//////////////////
/*Get MCS index*/
uint32_t get_I_mcs(int CE_level)
{
if(CE_level==0)
{
return 13;
}
else if(CE_level==1)
{
return 10;
}
else
{
return 4;
}
}
uint32_t get_max_tbs(uint32_t I_tbs)
{
return MAC_TBStable_NB_IoT[I_tbs][7]/8;
}
uint32_t get_tbs(uint32_t data_size, uint32_t I_tbs, uint32_t *I_sf)
{
for((*I_sf)=0;(*I_sf)<8;++(*I_sf))
{
//LOG_D(MAC,"[get_tbs]TBS %d SF index %d\n", TBStable_NB_IoT[I_tbs][(*I_sf)], *I_sf);
if(MAC_TBStable_NB_IoT[I_tbs][(*I_sf)]>=data_size*8)
{
return MAC_TBStable_NB_IoT[I_tbs][(*I_sf)]/8;
}
}
LOG_D(MAC,"error\n");
return 0;
}
uint32_t get_num_sf(uint32_t I_sf)
{
if(I_sf==6)
{
return 8;
}
else if(I_sf==7)
{
return 10;
}
else
{
return I_sf+1;
}
}
/*Subcarrier_spacing 0:3.75kHz \ 1 : 15kHz*/
uint32_t get_HARQ_delay(int subcarrier_spacing, uint32_t HARQ_delay_index)
{
if(subcarrier_spacing==1)
{
if(HARQ_delay_index==0)
return 13;
else if(HARQ_delay_index==1)
return 15;
else if(HARQ_delay_index==2)
return 17;
else
return 18;
}
else
{
if((HARQ_delay_index==0)&&(HARQ_delay_index==1))
return 13;
else
return 21;
}
}
uint8_t get_index_Rep_dl(uint16_t R)
{
int i;
if(R<=128)
{
for(i=0;i<16;++i)
{
if(R==R_dl_table[i])
{
return i;
}
}
LOG_D(MAC,"[get_index_Rep] error\n");
}
return 0;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file eNB_scheduler_ulsch_NB_IoT.c
* \brief handle UL UE-specific scheduling
* \author NTUST BMW Lab./Nick HO
* \date 2017 - 2018
* \email: nick133371@gmail.com
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
#include "RRC/NBIOT/proto_NB_IoT.h"
//#include "RRC/NBIOT/extern.h"
//#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
unsigned char str20[] = "DCI_uss";
unsigned char str21[] = "DATA_uss";
// scheduling UL
int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info,uint32_t subframe, uint32_t frame, uint32_t H_SFN, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info){
int i,ndi = 0,check_DCI_result = 0,check_UL_result = 0,candidate;
uint32_t DL_end;
//Scheduling resource temp buffer
sched_temp_DL_NB_IoT_t *NPDCCH_info = (sched_temp_DL_NB_IoT_t*)malloc(sizeof(sched_temp_DL_NB_IoT_t));
candidate = UE_info->R_max/UE_sched_ctrl_info->R_dci;
uint32_t mcs = max_mcs[UE_info->multi_tone];
uint32_t mappedMcsIndex=UE_info->PHR+(4 * UE_info->multi_tone);
int TBS = 0;
int Iru = 0, Nru, I_rep,N_rep,total_ru;
int dly = 0,uplink_time = 0;
if(UE_info->ul_total_buffer<=0)
{
LOG_D(MAC,"[%04d][ULSchedulerUSS][UE:%05d] No UL data in buffer\n", mac_inst->current_subframe, UE_info->rnti);
return -1;
}
TBS=get_TBS_UL_NB_IoT(mcs,UE_info->multi_tone,Iru);
LOG_D(MAC,"Initial TBS : %d UL_buffer: %d\n", TBS, UE_info->ul_total_buffer);
sched_temp_UL_NB_IoT_t *NPUSCH_info = (sched_temp_UL_NB_IoT_t*)malloc(sizeof(sched_temp_UL_NB_IoT_t));
//DCIFormatN0_t *DCI_N0 = (DCIFormatN0_t*)malloc(sizeof(DCIFormatN0_t));
//available_resource_DL_t *node;
// setting of the NDI
/*
if(UE_info->HARQ_round == 0)
{
ndi = 1-UE_info->oldNDI_UL;
UE_info->oldNDI_UL=ndi;
}
*/
ndi = 1;
for (i = 0; i < candidate; i++)
{
/*step 1 : Check DL resource is available for DCI N0 or not*/
check_DCI_result = check_resource_NPDCCH_NB_IoT(mac_inst,H_SFN, frame, subframe, NPDCCH_info, i, UE_sched_ctrl_info->R_dci);
//node = check_resource_DL(mac_inst,);
//just use to check when there is no DL function
//NPDCCH_info->sf_start = H_SFN*10240+frame*10 +subframe + i * UE_sched_ctrl_info->R_dci;
//NPDCCH_info->sf_end = NPDCCH_info->sf_start + (i+1) * UE_sched_ctrl_info->R_dci;
//LOG_D(MAC,"UE : %5d, NPDCCH result: %d ,NPDCCH start: %d,NPDCCH end : %d\n",UE_info->rnti,check_DCI_result,NPDCCH_info->sf_start,NPDCCH_info->sf_end);
if( check_DCI_result != -1)
{
/*step 2 : Determine MCS / TBS / REP / RU number*/
/*while((mapped_mcs[UE_info->CE_level][mappedMcsIndex]< mcs)||((TBS>UE_info->ul_total_buffer)&&(mcs>=0)))
{
--mcs;
TBS=get_TBS_UL_NB_IoT(mcs,UE_info->multi_tone,Iru);
}*/
mcs = mapped_mcs[UE_info->CE_level][mappedMcsIndex];
//mcs = 2;
while((TBS<UE_info->ul_total_buffer)&&(Iru<=7))
{
Iru++;
TBS=get_TBS_UL_NB_IoT(mcs,UE_info->multi_tone,Iru);
}
//LOG_D(MAC,"TBS : %d MCS %d I_RU %d\n", TBS, UE_info->ul_total_buffer, mcs, Iru);
Nru = RU_table[Iru];
DL_end = NPDCCH_info->sf_end;
N_rep = get_N_REP(UE_info->CE_level);
I_rep = get_I_REP(N_rep);
total_ru = Nru * N_rep;
LOG_D(MAC,"[%04d][ULSchedulerUSS][UE:%05d] Multi-tone:%d,MCS:%d,TBS:%d,UL_buffer:%d,DL_start:%d,DL_end:%d,N_rep:%d,N_ru:%d,Total_ru:%d,Iru:%d\n", mac_inst->current_subframe,UE_info->rnti,UE_info->multi_tone,mcs,TBS,UE_info->ul_total_buffer,NPDCCH_info->sf_start,DL_end,N_rep,Nru,total_ru,Iru);
/*step 3 Check UL resource for Uplink data*/
// we will loop the scheduling delay here
for(dly=0;dly<4;dly++)
{
uplink_time = DL_end +scheduling_delay[dly]+1;
check_UL_result = Check_UL_resource(uplink_time,total_ru, NPUSCH_info, UE_info->multi_tone, 0);
if (check_UL_result != -1)
{
//LOG_D(MAC,"[%04d][UL scheduler][UE:%05d] DCI content = scind : %d ResAssign : %d mcs : %d ndi : %d scheddly : %d RepNum : %d rv : %d DCIRep : %d\n", mac_inst->current_subframe,UE_info->rnti,DCI_N0->scind,DCI_N0->ResAssign,DCI_N0->mcs,DCI_N0->ndi,DCI_N0->Scheddly,DCI_N0->RepNum,DCI_N0->rv,DCI_N0->DCIRep);
LOG_D(MAC,"[%04d][ULSchedulerUSS][%d][Success] complete scheduling with data size %d\n", mac_inst->current_subframe, UE_info->rnti, UE_info->ul_total_buffer);
LOG_I(MAC,"[%04d][ULSchedulerUSS][%d] Multi-tone:%d,MCS:%d,TBS:%d,UL_buffer:%d,DL_start:%d,DL_end:%d,N_rep:%d,N_ru:%d,Total_ru:%d\n", mac_inst->current_subframe,UE_info->rnti,UE_info->multi_tone,mcs,TBS,UE_info->ul_total_buffer,NPDCCH_info->sf_start,DL_end,N_rep,Nru,total_ru);
//LOG_D(MAC,"[%04d][ULSchedulerUSS][%d][Success] DCI content = scind : %d ResAssign : %d mcs : %d ndi : %d scheddly : %d RepNum : %d rv : %d DCIRep : %d\n", mac_inst->current_subframe, UE_info->rnti, DCI_N0->scind,DCI_N0->ResAssign,DCI_N0->mcs,DCI_N0->ndi,DCI_N0->Scheddly,DCI_N0->RepNum,DCI_N0->rv,DCI_N0->DCIRep);
// step 5 resource allocation and generate scheduling result
LOG_D(MAC,"[%04d][ULSchedulerUSS][UE:%05d] Generate result\n", mac_inst->current_subframe, UE_info->rnti);
//generate_scheduling_result_UL(NPDCCH_info->sf_start, NPDCCH_info->sf_end,NPUSCH_info->sf_start, NPUSCH_info->sf_end,DCI_N0,UE_info->rnti, str20, str21);
LOG_D(MAC,"[%04d][ULSchedulerUSS][UE:%05d] Maintain resource\n", mac_inst->current_subframe, UE_info->rnti);
//fill_resource_DL();
maintain_resource_DL(mac_inst,NPDCCH_info,NULL);
adjust_UL_resource_list(NPUSCH_info);
/*
//Change the UE state to idle
UE_info->direction = -1;
return 0;
*/
//Fill result to Output structure
UE_sched_ctrl_info->NPDCCH_sf_end=NPDCCH_info->sf_end;
UE_sched_ctrl_info->NPDCCH_sf_start=NPDCCH_info->sf_start;
UE_sched_ctrl_info->NPUSCH_sf_end=NPUSCH_info->sf_end;
UE_sched_ctrl_info->NPUSCH_sf_start=NPUSCH_info->sf_start;
UE_sched_ctrl_info->TBS=TBS;
UE_sched_ctrl_info->dci_n0_index_mcs=mcs;
UE_sched_ctrl_info->index_tbs=mcs;
UE_sched_ctrl_info->dci_n0_index_ru=Iru;
UE_sched_ctrl_info->dci_n0_n_ru=Nru;
UE_sched_ctrl_info->dci_n0_index_delay=dly;
UE_sched_ctrl_info->dci_n0_index_subcarrier=NPUSCH_info->subcarrier_indication;
UE_sched_ctrl_info->dci_n0_index_ndi=ndi;
//UE_sched_ctrl_info->dci_n0_index_R_dci=get_DCI_REP(UE_sched_ctrl_info->R_dci->R_dci,UE_info->R_max);
UE_sched_ctrl_info->dci_n0_index_R_data=I_rep;
LOG_D(MAC,"[%04d][ULSchedulerUSS][%d][Success] Finish UL USS scheduling \n", mac_inst->current_subframe, UE_info->rnti);
return 0;
}
}
}
/*break now, we only loop one candidiate*/
//break;
}
//----Daniel
UE_sched_ctrl_info->flag_schedule_success=0;
//----Daniel
LOG_D(MAC,"[%04d][ULSchedulerUSS][%d][Fail] UL scheduling USS fail\n", mac_inst->current_subframe, UE_info->rnti);
LOG_D(MAC,"[%04d][UL scheduler][UE:%05d] there is no available UL resource\n", mac_inst->current_subframe, UE_info->rnti);
return -1;
}
void rx_sdu_NB_IoT(module_id_t module_id, int CC_id, frame_t frame, sub_frame_t subframe, uint16_t rnti, uint8_t *sdu, uint16_t length)
{
unsigned char rx_ces[5], num_ce = 0, num_sdu = 0, *payload_ptr, i; // MAX Control element
unsigned char rx_lcids[5];//for NB_IoT-IoT, NB_IoT_RB_MAX should be fixed to 5 (2 DRB+ 3SRB)
unsigned short rx_lengths[5];
//int UE_id = 0;
int BSR_index=0;
int DVI_index = 0;
int PHR = 0;
int ul_total_buffer = 0;
//mac_NB_IoT_t *mac_inst;
UE_TEMPLATE_NB_IoT *UE_info;
uint8_t* msg4_rrc_pdu = NULL;
LOG_D(MAC,"RX_SDU_IN\n");
uint8_t* first_6 = (uint8_t*) malloc(6*sizeof(uint8_t));
for(int a = 0; a<6;a++)
first_6[a]=sdu[a+2];
// note: if lcid < 25 this is sdu, otherwise this is CE
payload_ptr = parse_ulsch_header_NB_IoT(sdu, &num_ce, &num_sdu,rx_ces, rx_lcids, rx_lengths, length);
LOG_I(MAC,"num_CE= %d, num_sdu= %d, rx_ces[0] = %d, rx_lcids = %d, rx_lengths[0] = %d, length = %d\n",num_ce,num_sdu,rx_ces[0],rx_lcids[0],rx_lengths[0],length);
for (i = 0; i < num_ce; i++)
{
switch(rx_ces[i])
{
case CRNTI:
// find UE id again, confirm the UE, intial some ue specific parameters
payload_ptr+=2;
break;
case SHORT_BSR:
// update BSR here
LOG_I(MAC,"Update BSR, rnti : %d\n",rnti);
UE_info = get_ue_from_rnti(mac_inst, rnti);
BSR_index = payload_ptr[0] & 0x3f;
if(UE_info != NULL)
{
LOG_I(MAC,"Find UE in CE 2 list, update ul_total_buffer to %d bytes\n",BSR_table[BSR_index]);
UE_info->ul_total_buffer = BSR_table[BSR_index];
}
else
LOG_E(MAC,"UE info empty\n");
payload_ptr+=1;
break;
default:
LOG_D(MAC,"Received unknown MAC header (0x%02x)\n", rx_ces[i]);
break;
}
}
for (i = 0; i < num_sdu; i++)
{
switch(rx_lcids[i])
{
case CCCH_NB_IoT:
// MSG3 content: |R|R|PHR|PHR|DVI|DVI|DVI|DVI|CCCH payload
PHR = ((payload_ptr[0] >> 5) & 0x01)*2+((payload_ptr[0]>>4) & 0x01);
DVI_index = (payload_ptr[0] >>3 & 0x01)*8+ (payload_ptr[0] >>2 & 0x01)*4 + (payload_ptr[0] >>1 & 0x01)*2 +(payload_ptr[0] >>0 & 0x01);
ul_total_buffer = DV_table[DVI_index];
LOG_D(MAC,"PHR = %d, ul_total_buffer = %d\n",PHR,ul_total_buffer);
// go to payload
payload_ptr+=1;
// Note that the first 6 byte (48 bits) of this CCCH SDU should be encoded in the MSG4 for contention resolution
/*printf("CCCH SDU content: ");
for(int a = 0; a<9;a++)
printf("%02x ",payload_ptr[a]);
printf("\n");*/
rx_lengths[i]-=1;
mac_rrc_data_ind(
module_id,
CC_id,
frame,subframe,
rnti,
CCCH,
(uint8_t*)payload_ptr,
rx_lengths[i],
1,
module_id,
0);
LOG_D(MAC,"rx_lengths : %d\n", rx_lengths[i]);
msg4_rrc_pdu = mac_rrc_msg3_ind_NB_IoT(payload_ptr,rnti,rx_lengths[i]);
receive_msg3_NB_IoT(mac_inst,rnti,PHR,ul_total_buffer,first_6,msg4_rrc_pdu);
LOG_I(MAC,"Contention resolution ID = %02x %02x %02x %02x %02x %02x\n",first_6[0],first_6[1],first_6[2],first_6[3],first_6[4],first_6[5]);
//NB_IoT_mac_rrc_data_ind(payload_ptr,mac_inst,rnti);
//NB_IoT_receive_msg3(mac_inst,rnti,PHR,ul_total_buffer);
break;
case DCCH0_NB_IoT:
case DCCH1_NB_IoT:
LOG_I(MAC,"DCCH PDU Here\n");
mac_rlc_data_ind(
module_id,
rnti,
module_id,
frame,
1,
0,
rx_lcids[i],
//1,/* change channel_id equals 1 (SRB) */
(char *)payload_ptr,
rx_lengths[i],
1,
NULL);//(unsigned int*)crc_status);
// UE specific here
//NB_IoT_mac_rlc_data_ind(payload_ptr,mac_inst,rnti);
break;
// all the DRBS
case DTCH0_NB_IoT:
default:
//NB_IoT_mac_rlc_data_ind(payload_ptr,mac_inst,rnti);
break;
}
payload_ptr+=rx_lengths[i];
}
}
uint8_t *parse_ulsch_header_NB_IoT( uint8_t *mac_header,
uint8_t *num_ce,
uint8_t *num_sdu,
uint8_t *rx_ces,
uint8_t *rx_lcids,
uint16_t *rx_lengths,
uint16_t tb_length ){
uint8_t not_done=1, num_ces=0, num_sdus=0, lcid,num_sdu_cnt;
uint8_t *mac_header_ptr = mac_header;
uint16_t length, ce_len=0;
while(not_done==1){
if(((SCH_SUBHEADER_FIXED_NB_IoT*)mac_header_ptr)->E == 0){
not_done = 0;
}
lcid = ((SCH_SUBHEADER_FIXED_NB_IoT*)mac_header_ptr)->LCID;
if(lcid < EXTENDED_POWER_HEADROOM){
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_SHORT_NB_IoT *)mac_header_ptr)->F == 0){
length = ((SCH_SUBHEADER_SHORT_NB_IoT *)mac_header_ptr)->L;
mac_header_ptr += 2;//sizeof(SCH_SUBHEADER_SHORT);
}else{ // F = 1
length = ((((SCH_SUBHEADER_LONG_NB_IoT *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG_NB_IoT *)mac_header_ptr)->L_LSB & 0xff);
mac_header_ptr += 3;//sizeof(SCH_SUBHEADER_LONG);
}
}
rx_lcids[num_sdus] = lcid;
rx_lengths[num_sdus] = length;
num_sdus++;
}else{ // This is a control element subheader POWER_HEADROOM, BSR and CRNTI
if(lcid == SHORT_PADDING){
mac_header_ptr++;
}else{
rx_ces[num_ces] = lcid;
num_ces++;
mac_header_ptr++;
if(lcid==LONG_BSR){
ce_len+=3;
}else if(lcid==CRNTI){
ce_len+=2;
}else if((lcid==POWER_HEADROOM) || (lcid==TRUNCATED_BSR)|| (lcid== SHORT_BSR)) {
ce_len++;
}else{
// wrong lcid
}
}
}
}
*num_ce = num_ces;
*num_sdu = num_sdus;
return(mac_header_ptr);
}
void fill_DCI_N0(DCIFormatN0_t *DCI_N0, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info)
{
DCI_N0->type = 0;
DCI_N0->scind = UE_sched_ctrl_info->dci_n0_index_subcarrier;
DCI_N0->ResAssign = UE_sched_ctrl_info->dci_n0_index_ru;
DCI_N0->mcs = UE_sched_ctrl_info->dci_n0_index_mcs;
DCI_N0->ndi = UE_sched_ctrl_info->dci_n0_index_ndi;
DCI_N0->Scheddly = UE_sched_ctrl_info->dci_n0_index_delay;
DCI_N0->RepNum = UE_sched_ctrl_info->dci_n0_index_R_data;
DCI_N0->rv = (UE_info->HARQ_round%2==0)?0:1; // rv will loop 0 & 2
DCI_N0->DCIRep = get_DCI_REP(UE_sched_ctrl_info->R_dci,UE_info->R_max);
//DCI_N0->DCIRep = UE_sched_ctrl_info->dci_n0_index_R_dci;
LOG_I(MAC,"[fill_DCI_N0] Type %d scind %d I_ru %d I_mcs %d ndi %d I_delay %d I_rep %d RV %d I_dci %d\n", DCI_N0->type, DCI_N0->scind, DCI_N0->ResAssign, DCI_N0->mcs, DCI_N0->ndi, DCI_N0->Scheddly, DCI_N0->RepNum, DCI_N0->rv, DCI_N0->DCIRep);
}
......@@ -30,7 +30,7 @@
#ifndef __MAC_EXTERN_NB_IOT_H__
#define __MAC_EXTERN_NB_IOT_H__
#include "openair2/PHY_INTERFACE/defs_NB_IoT.h"
//#include "openair2/PHY_INTERFACE/defs_NB_IoT.h"
......
/*! \file main_NB_IoT.c
* \brief top init of Layer 2
* \author NTUST BMW LAB./
* \date 2017
* \version 1.0
* \email:
*/
//#include "asn1_constants.h"
#include "LAYER2/MAC/defs_NB_IoT.h"
#include "LAYER2/MAC/proto_NB_IoT.h"
#include "LAYER2/MAC/extern_NB_IoT.h"
#include "vars_NB_IoT.h"
#include "RRC/NBIOT/proto_NB_IoT.h"
#define NUM_USS_PP 3
#define USER_NUM_USS 10
int mac_init_global_param_NB_IoT(void)
{
///// removed since already called by mac_init_global_param //////////////
/*
if (rlc_module_init()!=0) {
return(-1);
}
*/
/////////////////////////////////////////////////////////////////////////////
// LOG_I(MAC,"[MAIN] RRC NB-IoT initialization of global params\n");
// rrc_init_global_param_NB_IoT();
///// removed since already called by mac_init_global_param //////////////
/*
LOG_I(MAC,"[MAIN] PDCP layer init\n");
#ifdef USER_MODE
pdcp_layer_init ();
#else
pdcp_module_init ();
#endif
*/
////////////////////////////////////////////////////////////////////////
return 0;
}
// Initial function of the intialization for NB-IoT MAC
void init_mac_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst)
{
int32_t i, j, k;
LOG_I(MAC,"[NB-IoT] MAC start initialization\n");
mac_inst->current_subframe = 0;
for(i=0;i<64;++i)
{
mac_inst->sib1_flag[i] = 0;
mac_inst->sib1_count[i] = 0;
}
init_tool_sib1(mac_inst);
// output handler
// RA
mac_inst->RA_msg2_list.head = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_msg3_list.head = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_msg4_list.head = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_msg2_list.tail = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_msg3_list.tail = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_msg4_list.tail = (RA_TEMPLATE_NB_IoT *)0;
sib1_NB_IoT_sched_t *config = &mac_inst->rrc_config.sib1_NB_IoT_sched_config;
// DLSF Table
init_dlsf_info(mac_inst, &DLSF_information);
// init sib1 tool
//int repetition_pattern = 1;// 1:every2frame, 2:every4frame, 3:every8frame, 4:every16frame
for(i=0;i<8;++i){
mac_inst->sib1_flag[(i<<1)+config->starting_rf] = 1;
}
for(i=0, j=0;i<64;++i){
if(mac_inst->sib1_flag[i]==1){
++j;
}
mac_inst->sib1_count[i]=j;
}
//printf("%d", mac_inst->sib1_period);
for(i=0, j=0;i<640;++i){
//printf("*%d", i);
if(is_dlsf(mac_inst, i)){
++j;
}
//printf("-");
if(i%10==9){
mac_inst->dlsf_table[i/10] = j;
}
}
for(i=0;i<256;++i){
mac_inst->sibs_table[i] = -1;
}
mac_inst->rrc_config.si_window_length = ms160;
mac_inst->rrc_config.sibs_NB_IoT_sched[0].si_periodicity = rf64;
mac_inst->rrc_config.si_radio_frame_offset = 1;
for(j=0;j<6;++j){
if(0x0 != mac_inst->rrc_config.sibs_NB_IoT_sched[j].sib_mapping_info){
k = mac_inst->rrc_config.sibs_NB_IoT_sched[j].si_periodicity / mac_inst->rrc_config.si_window_length;
for(i=0;i<(256/k);++i){
mac_inst->sibs_table[(i*k)+j] = j;
}
}
}
mac_inst->schedule_subframe_DL = 0;
//mac_inst->schedule_subframe_UL = 0;
available_resource_DL = available_resource_DL_last = (available_resource_DL_t *)0;
// init downlink list 0-100
init_dl_list(mac_inst);
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
mac_inst->RA_template[i].active = 0;
mac_inst->RA_template[i].msg3_retransmit_count = 0;
mac_inst->RA_template[i].msg4_retransmit_count = 0;
mac_inst->RA_template[i].ta = 0;
mac_inst->RA_template[i].preamble_index = 0;
mac_inst->RA_template[i].ue_rnti = 0x0;
mac_inst->RA_template[i].ra_rnti = 0x0;
mac_inst->RA_template[i].next = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_template[i].prev = (RA_TEMPLATE_NB_IoT *)0;
mac_inst->RA_template[i].wait_msg4_ack = 0;
mac_inst->RA_template[i].wait_msg3_ack = 0;
}
//3 CE level USS list
mac_inst->UE_list_spec = (UE_list_NB_IoT_t*)malloc(NUM_USS_PP*sizeof(UE_list_NB_IoT_t));
//initial UE list
LOG_I(MAC,"[init_mac_NB_IoT] Initial UE list\n");
mac_inst->num_uss_list = NUM_USS_PP;
for(i=0;i<NUM_USS_PP;++i)
{
//rrc_mac_config_req(&mac_inst->rrc_config, 0, 0, 1, i);
(mac_inst->UE_list_spec+i)->head = -1;
(mac_inst->UE_list_spec+i)->tail = -1;
//(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.R_max = mac_inst->rrc_config.npdcch_ConfigDedicated[i].R_max;
//(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.G = mac_inst->rrc_config.npdcch_ConfigDedicated[i].G;
//(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.a_offset = mac_inst->rrc_config.npdcch_ConfigDedicated[i].a_offset;
(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.R_max = 16;
(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.G = 4;
(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.a_offset = 0;
(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.T = (uint32_t)((double)(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.R_max * (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.G);
(mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.ss_start_uss = (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.T * (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.a_offset;
//SCHEDULE_LOG("[init_mac_NB_IoT][CE%d] Rmax %d G %d, a_offset %d, PP %d search space start %d\n", i, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.R_max, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.G, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.a_offset, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.T, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.ss_start_uss);
for(j=0;j<MAX_NUMBER_OF_UE_MAX_NB_IoT;++j)
{
(mac_inst->UE_list_spec+i)->UE_template_NB_IoT[j].active=0;
(mac_inst->UE_list_spec+i)->UE_template_NB_IoT[j].RRC_connected=0;
(mac_inst->UE_list_spec+i)->UE_template_NB_IoT[j].direction = -1;
}
LOG_I(MAC,"[init_mac_NB_IoT] List_number %d R_max %d G %.1f a_offset %.1f T %d SS_start %d\n", i, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.R_max, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.G, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.a_offset, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.T, (mac_inst->UE_list_spec+i)->NPDCCH_config_dedicated.ss_start_uss);
}
//UL initial
//Setting nprach configuration
setting_nprach();
//Initialize uplink resource from nprach configuration
Initialize_Resource();
//add_UL_Resource(mac_inst);
extend_available_resource_DL(mac_inst, mac_inst->current_subframe + 1 + 160);
}
void mac_top_init_eNB_NB_IoT(void)
{
// can be an input of this function, but now fix to 0
module_id_t i = 0;
//UE_list_t *UE_list;
//eNB_MAC_INST_NB_IoT *mac;
int nb_inst_NB_IOT_MAC= 1;
LOG_I(MAC,"[NB-IoT MAIN] Init function start:nb_nbiot_macrlc_inst=%d\n",nb_inst_NB_IOT_MAC);
if (nb_inst_NB_IOT_MAC>0) {
// only one inst exit in legacy OAI
mac_inst->Mod_id = i;
// IF Module Initialization linking
mac_inst->if_inst_NB_IoT = IF_Module_init_NB_IoT(i);
mac_inst->if_inst_NB_IoT->PHY_config_req = PHY_config_req_NB_IoT;
mac_inst->if_inst_NB_IoT->schedule_response = schedule_response_NB_IoT;
//reserve for fapi structure initializati
} else {
mac_inst = NULL;
}
// for NB-IoT UE list initialization will be in init_mac_NB_IoT
}
int l2_init_eNB_NB_IoT(void)
{
LOG_I(MAC,"[MAIN] MAC_INIT_GLOBAL_PARAM NB-IoT IN...\n");
mac_inst = (eNB_MAC_INST_NB_IoT *) malloc (sizeof(eNB_MAC_INST_NB_IoT));
memset(mac_inst,0,sizeof(eNB_MAC_INST_NB_IoT));
Is_rrc_registered_NB_IoT=0;
mac_init_global_param_NB_IoT();
Is_rrc_registered_NB_IoT=1;
//init_mac_NB_IoT(mac_inst);
return(1);
}
/*! \file schedule_tool_NB_IoT.c
* \brief scheduler helper function
* \author NTUST BMW Lab./
* \date 2017
* \email:
* \version 1.0
*
*/
#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"
void print_available_UL_resource(void){
int sixtone_num=0;
int threetone_num=0;
int singletone1_num=0;
int singletone2_num=0;
int singletone3_num=0;
available_resource_UL_t *available_resource;
///sixtone
available_resource = available_resource_UL->sixtone_Head;
while(available_resource!=NULL)
{
sixtone_num++;
LOG_D(MAC,"[sixtone][Node %d] start %d , end %d\n",sixtone_num,available_resource->start_subframe,available_resource->end_subframe);
available_resource = available_resource->next;
}
///threetone
available_resource = available_resource_UL->threetone_Head;
while(available_resource!=NULL)
{
threetone_num++;
LOG_D(MAC,"[threetone][Node %d] start %d, end %d\n",threetone_num,available_resource->start_subframe,available_resource->end_subframe);
available_resource = available_resource->next;
}
///singletone1
available_resource = available_resource_UL->singletone1_Head;
while(available_resource!=NULL)
{
singletone1_num++;
LOG_D(MAC,"[singletone1][Node %d] start %d, end %d\n",singletone1_num,available_resource->start_subframe,available_resource->end_subframe);
available_resource = available_resource->next;
}
///singletone1
available_resource = available_resource_UL->singletone2_Head;
while(available_resource!=NULL)
{
singletone2_num++;
LOG_D(MAC,"[singletone2][Node %d] start %d, end %d\n",singletone2_num,available_resource->start_subframe,available_resource->end_subframe);
available_resource = available_resource->next;
}
///singletone1
available_resource = available_resource_UL->singletone3_Head;
while(available_resource!=NULL)
{
singletone3_num++;
LOG_D(MAC,"[singletone3][Node %d] start %d, end %d\n",singletone3_num,available_resource->start_subframe,available_resource->end_subframe);
available_resource = available_resource->next;
}
}
void print_scheduling_result_UL(void)
{
schedule_result_t *scheduling_result_tmp;
scheduling_result_tmp = schedule_result_list_DL;
while(scheduling_result_tmp!=NULL)
{
LOG_D(MAC,"[UE:%05d][%s] output subframe : %d\n", scheduling_result_tmp->rnti, ((scheduling_result_tmp->channel==NPDCCH)? "NPDCCH":"NPDSCH"), scheduling_result_tmp->output_subframe);
scheduling_result_tmp = scheduling_result_tmp->next;
}
scheduling_result_tmp = schedule_result_list_UL;
while(scheduling_result_tmp!=NULL)
{
LOG_D(MAC,"[UE:%05d][NPUSCH] output subframe : %d\n", scheduling_result_tmp->rnti, scheduling_result_tmp->output_subframe);
scheduling_result_tmp = scheduling_result_tmp->next;
}
}
void setting_nprach(){
nprach_list[0].nprach_Periodicity = rachperiod[3];
nprach_list[0].nprach_StartTime = rachstart[0];
nprach_list[0].nprach_SubcarrierOffset = rachscofst[0];
nprach_list[0].nprach_NumSubcarriers = rachnumsc[0];
nprach_list[0].numRepetitionsPerPreambleAttempt = rachrepeat[0];
nprach_list[1].nprach_Periodicity = rachperiod[3];
nprach_list[1].nprach_StartTime = rachstart[0];
nprach_list[1].nprach_SubcarrierOffset = rachscofst[1];
nprach_list[1].nprach_NumSubcarriers = rachnumsc[0];
nprach_list[1].numRepetitionsPerPreambleAttempt = rachrepeat[0];
nprach_list[2].nprach_Periodicity = rachperiod[3];
nprach_list[2].nprach_StartTime = rachstart[0];
nprach_list[2].nprach_SubcarrierOffset = rachscofst[2];
nprach_list[2].nprach_NumSubcarriers = rachnumsc[1];
nprach_list[2].numRepetitionsPerPreambleAttempt = rachrepeat[0];
// fixed nprach configuration
}
void Initialize_Resource_node(available_resource_UL_t *tone_head, available_resource_UL_t *npusch_frame, int tone)
{
int i=0;
available_resource_UL_t *second_node;
second_node = (available_resource_UL_t*)malloc(sizeof(available_resource_UL_t));
if(tone == sixtone)
i=2;
else if(tone == threetone)
i=1;
else
i=0;
tone_head->start_subframe = ceil ( (nprach_list+i)->nprach_StartTime + 1.4*4*((nprach_list+i)->numRepetitionsPerPreambleAttempt) ) ;
tone_head->end_subframe = (nprach_list+i)->nprach_StartTime-1 + (nprach_list+i)->nprach_Periodicity;
second_node->start_subframe = tone_head->start_subframe + (nprach_list+i)->nprach_Periodicity;
second_node->end_subframe = tone_head->end_subframe + (nprach_list+i)->nprach_Periodicity;
second_node->next =NULL;
tone_head->next = second_node;
*npusch_frame = *tone_head->next;
////////////////////////CALVIN TIMING DIAGRAM GENERATOR///////////////////////////
#ifdef TIMING_GENERATOR
uint32_t ii, jj;
for(ii=(nprach_list+i)->nprach_StartTime; ii<tone_head->start_subframe; ++ii){
if(ii == sim_end_time) break;
for(jj=0; jj<(nprach_list+i)->nprach_NumSubcarriers; ++jj){
ul_scheduled(ii, 0, (nprach_list+i)->nprach_SubcarrierOffset + jj, _NPRACH, 0, (char *)0);
}
}
for(ii=tone_head->end_subframe+1; ii<second_node->start_subframe; ++ii){
if(ii == sim_end_time) break;
for(jj=0; jj<(nprach_list+i)->nprach_NumSubcarriers; ++jj){
ul_scheduled(ii, 0, (nprach_list+i)->nprach_SubcarrierOffset + jj, _NPRACH, 0, (char *)0);
}
}
#endif
////////////////////////CALVIN TIMING DIAGRAM GENERATOR///////////////////////////
}
/*when there is SIB-2 configuration coming to MAC, filled the uplink resource grid*/
void Initialize_Resource(void){
int i;
available_resource_UL_t *new_node;
///memory allocate to Head
available_resource_UL = (available_resource_tones_UL_t*)malloc(sizeof(available_resource_tones_UL_t));
available_resource_UL->sixtone_Head = (available_resource_UL_t *)0;
available_resource_UL->threetone_Head = (available_resource_UL_t *)0;
available_resource_UL->singletone1_Head = (available_resource_UL_t *)0;
available_resource_UL->singletone2_Head = (available_resource_UL_t *)0;
available_resource_UL->singletone3_Head = (available_resource_UL_t *)0;
available_resource_UL->sixtone_end_subframe = 0;
available_resource_UL->threetone_end_subframe = 0;
available_resource_UL->singletone1_end_subframe = 0;
available_resource_UL->singletone2_end_subframe = 0;
available_resource_UL->singletone3_end_subframe = 0;
//initialize first node
if((nprach_list+2)->nprach_StartTime!=0)
{
new_node = (available_resource_UL_t *)malloc(sizeof(available_resource_UL_t));
new_node->next = (available_resource_UL_t *)0;
new_node->prev = (available_resource_UL_t *)0;
new_node->start_subframe = 0;
new_node->end_subframe = (nprach_list+2)->nprach_StartTime-1;
if( (available_resource_UL_t *)0 == available_resource_UL->sixtone_Head){
available_resource_UL->sixtone_Head = new_node;
new_node->prev = (available_resource_UL_t *)0;
}
}
if((nprach_list+1)->nprach_StartTime!=0)
{
new_node = (available_resource_UL_t *)malloc(sizeof(available_resource_UL_t));
new_node->next = (available_resource_UL_t *)0;
new_node->prev = (available_resource_UL_t *)0;
new_node->start_subframe = 0;
new_node->end_subframe = (nprach_list+1)->nprach_StartTime-1;
if( (available_resource_UL_t *)0 == available_resource_UL->threetone_Head){
available_resource_UL->threetone_Head = new_node;
new_node->prev = (available_resource_UL_t *)0;
}
}
for(i=0;i<3;++i)
{
if(nprach_list->nprach_StartTime!=0)
{
new_node = (available_resource_UL_t *)malloc(sizeof(available_resource_UL_t));
new_node->next = (available_resource_UL_t *)0;
new_node->prev = (available_resource_UL_t *)0;
new_node->start_subframe = 0;
new_node->end_subframe = nprach_list->nprach_StartTime-1;
if( (available_resource_UL_t *)0 == available_resource_UL->threetone_Head){
if(i==0)
available_resource_UL->singletone1_Head = new_node;
else if(i==1)
available_resource_UL->singletone2_Head = new_node;
else
available_resource_UL->singletone3_Head = new_node;
new_node->prev = (available_resource_UL_t *)0;
}
}
}
add_UL_Resource();
add_UL_Resource();
LOG_D(MAC,"Initialization of the UL Resource grid has been done\n");
}
void add_UL_Resource_node(available_resource_UL_t **head, uint32_t *end_subframe, uint32_t ce_level){
available_resource_UL_t *new_node, *iterator;
new_node = (available_resource_UL_t *)malloc(sizeof(available_resource_UL_t));
new_node->next = (available_resource_UL_t *)0;
new_node->prev = (available_resource_UL_t *)0;
new_node->start_subframe = *end_subframe + ceil( (nprach_list+ce_level)->nprach_StartTime + 1.4*4*((nprach_list+ce_level)->numRepetitionsPerPreambleAttempt) ) ;
new_node->end_subframe = *end_subframe + (nprach_list+ce_level)->nprach_Periodicity - 1;
if( (available_resource_UL_t *)0 == *head){
*head = new_node;
new_node->prev = (available_resource_UL_t *)0;
}else{
iterator = *head;
while( (available_resource_UL_t *)0 != iterator->next){
iterator = iterator->next;
}
iterator->next = new_node;
new_node->prev = iterator;
}
////////////////////////CALVIN TIMING DIAGRAM GENERATOR///////////////////////////
#ifdef TIMING_GENERATOR
uint32_t ii, jj;
for(ii=*end_subframe+(nprach_list+ce_level)->nprach_StartTime; ii<new_node->start_subframe; ++ii){
if(ii >= sim_end_time) break;
for(jj=0; jj<(nprach_list+ce_level)->nprach_NumSubcarriers; ++jj){
ul_scheduled(ii, 0, (nprach_list+ce_level)->nprach_SubcarrierOffset + jj, _NPRACH, 0, (char *)0);
}
}
#endif
////////////////////////CALVIN TIMING DIAGRAM GENERATOR///////////////////////////
*end_subframe += (nprach_list+ce_level)->nprach_Periodicity;
}
/// Use to extend the UL resource grid (5 list) at the end of nprach peroid time
void add_UL_Resource(void)
{
add_UL_Resource_node(&available_resource_UL->sixtone_Head, &available_resource_UL->sixtone_end_subframe, 2);
add_UL_Resource_node(&available_resource_UL->threetone_Head, &available_resource_UL->threetone_end_subframe, 1);
add_UL_Resource_node(&available_resource_UL->singletone1_Head, &available_resource_UL->singletone1_end_subframe, 0);
add_UL_Resource_node(&available_resource_UL->singletone2_Head, &available_resource_UL->singletone2_end_subframe, 0);
add_UL_Resource_node(&available_resource_UL->singletone3_Head, &available_resource_UL->singletone3_end_subframe, 0);
}
int get_I_TBS_NB_IoT(int x,int y)
{
int I_TBS = 0;
if(y==1) I_TBS=x;
else
{
if(x==1) I_TBS=2;
else if(x==2) I_TBS=1;
else
{
I_TBS=x;
}
}
return I_TBS;
}
int get_TBS_UL_NB_IoT(uint32_t mcs,uint32_t multi_tone,int Iru)
{
int TBS;
uint32_t I_TBS=get_I_TBS_NB_IoT(mcs,multi_tone);
TBS=UL_TBS_Table[I_TBS][Iru];
return TBS>>3;
}
int get_N_REP(int CE_level)
{
int N_rep= 0;
if(CE_level == 0)
{
N_rep = (nprach_list)->numRepetitionsPerPreambleAttempt;
}else if (CE_level == 1)
{
N_rep = (nprach_list+1)->numRepetitionsPerPreambleAttempt;
}else if (CE_level == 2)
{
//N_rep = (nprach_list+2)->numRepetitionsPerPreambleAttempt;
N_rep = 1;
}else
{
LOG_D(MAC,"unknown CE level!\n");
return -1;
}
return N_rep;
}
int get_I_REP(int N_rep)
{
int i;
for(i = 0; i < 8;i++)
{
if(N_rep == rachrepeat[i])
return i;
}
LOG_D(MAC,"unknown repetition value!\n");
return -1;
}
int get_DCI_REP(uint32_t R,uint32_t R_max)
{
int value = -1;
if (R_max == 1)
{
if(R == 1)
{
value =0;
}
}else if (R_max == 2)
{
if(R == 1)
value = 0;
if(R == 2)
value = 1;
}else if (R_max == 4)
{
if(R == 1)
value = 0;
if(R == 2)
value = 1;
if(R == 4)
value = 2;
}else if (R_max >= 8)
{
if(R == R_max/8)
value = 0;
if(R == R_max/4)
value = 1;
if(R == R_max/2)
value = 2;
if(R == R_max)
value = 3;
}
return value;
}
int single_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int fmt2_flag)
{
available_resource_UL_t *single_node_tmp;
uint32_t uplink_time_end;
if(fmt2_flag == 0)
// 16 * 0.5 (slot) = 8 subframe
uplink_time_end = uplink_time + total_ru*8 -1;
else
// 4 * 0.5 (slot) = 2 subframe
uplink_time_end = uplink_time + total_ru*2 -1;
//check first list of single tone
single_node_tmp = available_resource_UL->singletone1_Head;
while(single_node_tmp!=NULL)
{
if (uplink_time >= single_node_tmp->start_subframe)
{
if ( uplink_time_end <= single_node_tmp->end_subframe)
{
NPUSCH_info->sf_end = uplink_time_end;
NPUSCH_info->sf_start = uplink_time;
NPUSCH_info->tone = singletone1;
NPUSCH_info->subcarrier_indication = 0 ; // Isc when single tone : 0-2
NPUSCH_info->node = single_node_tmp;
LOG_D(MAC,"[UL scheduler] Use uplink resource single tone 1, sf_start: %d, sf_end: %d\n",NPUSCH_info->sf_start,NPUSCH_info->sf_end);
return 0;
}
}
single_node_tmp = single_node_tmp->next;
}
//check second list of single tone
single_node_tmp = available_resource_UL->singletone2_Head;
while(single_node_tmp!=NULL)
{
if (uplink_time >= single_node_tmp->start_subframe)
{
if ( uplink_time_end <= single_node_tmp->end_subframe)
{
NPUSCH_info->sf_end = uplink_time_end;
NPUSCH_info->sf_start = uplink_time;
NPUSCH_info->tone = singletone2;
NPUSCH_info->subcarrier_indication = 1 ; // Isc when single tone : 0-2
NPUSCH_info->node = single_node_tmp;
LOG_D(MAC,"[UL scheduler] Use uplink resource single tone 2, sf_start: %d, sf_end: %d\n",NPUSCH_info->sf_start,NPUSCH_info->sf_end);
return 0;
}
}
single_node_tmp = single_node_tmp->next;
}
//check third list of single tone
single_node_tmp = available_resource_UL->singletone3_Head;
while(single_node_tmp!=NULL)
{
if (uplink_time >= single_node_tmp->start_subframe)
{
if ( uplink_time_end <= single_node_tmp->end_subframe)
{
NPUSCH_info->sf_end = uplink_time_end;
NPUSCH_info->sf_start = uplink_time;
NPUSCH_info->tone = singletone3;
NPUSCH_info->subcarrier_indication = 2 ; // Isc when single tone : 0-2
NPUSCH_info->node = single_node_tmp;
LOG_D(MAC,"[UL scheduler]Use uplink resource single tone 3, sf_start: %d, sf_end: %d\n",NPUSCH_info->sf_start,NPUSCH_info->sf_end);
return 0;
}
}
single_node_tmp = single_node_tmp->next;
}
return -1;
}
int multi_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info)
{
available_resource_UL_t *Next_Node;
int single_tone_result = -1;
uint32_t uplink_time_end;
/*This checking order may result in the different of the resource optimization*/
/*check 6 tones first*/
Next_Node = available_resource_UL->sixtone_Head;
// 4 * 0.5 (slot) = 2 subframe
uplink_time_end = uplink_time + total_ru*2 -1;
while(Next_Node!=NULL)
{
if (uplink_time >= Next_Node->start_subframe)
{
if ( uplink_time_end <= Next_Node->end_subframe)
{
NPUSCH_info->sf_end = uplink_time_end;
NPUSCH_info->sf_start = uplink_time;
NPUSCH_info->tone = sixtone;
NPUSCH_info->subcarrier_indication = 17 ; // Isc when 6 tone : 6 - 12
NPUSCH_info->node = Next_Node;
LOG_D(MAC,"[UL scheduler] Use uplink resource six tone, sf_start: %d, sf_end: %d\n",NPUSCH_info->sf_start,NPUSCH_info->sf_end);
return 0;
}
}
Next_Node = Next_Node->next;
}
/*check 3 tones*/
Next_Node = available_resource_UL->threetone_Head;
// 8 * 0.5 (slot) = 4 subframe
uplink_time_end = uplink_time + total_ru * 4 -1;
while(Next_Node!=NULL)
{
if (uplink_time >= Next_Node->start_subframe)
{
if ( uplink_time_end <= Next_Node->end_subframe)
{
NPUSCH_info->sf_end = uplink_time_end;
NPUSCH_info->sf_start = uplink_time;
NPUSCH_info->tone = threetone;
NPUSCH_info->subcarrier_indication = 13 ; // Isc when 3 tone : 3-5
NPUSCH_info->node = Next_Node;
LOG_D(MAC,"[UL scheduler] Use uplink resource three tone, sf_start: %d, sf_end: %d\n",NPUSCH_info->sf_start,NPUSCH_info->sf_end);
return 0;
}
}
Next_Node = Next_Node->next;
}
/*if there is no multi-tone resource, try to allocate the single tone resource*/
single_tone_result = single_tone_ru_allocation(uplink_time,total_ru,NPUSCH_info,0);
if(single_tone_result == 0)
return 0;
return -1;
}
int get_resource_field_value(int subcarrier, int k0)
{
int value = 0;
if (k0 == 13)
value = subcarrier;
else if (k0 == 15)
value = subcarrier + 4;
else if (k0 == 17)
value = subcarrier + 8;
else if (k0 == 18)
value = subcarrier + 12;
return value;
}
int Check_UL_resource(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int multi_tone, int fmt2_flag)
{
int result =-1;
if(fmt2_flag ==0)
{
if(multi_tone == 1)
result = multi_tone_ru_allocation(uplink_time, total_ru, NPUSCH_info);
else if(multi_tone == 0)
result = single_tone_ru_allocation(uplink_time, total_ru, NPUSCH_info,0);
}else if (fmt2_flag == 1)
{
result = single_tone_ru_allocation(uplink_time, total_ru, NPUSCH_info, 1);
LOG_D(MAC,"harq result %d, time:%d total ru:%d\n", result, uplink_time, total_ru);
}
if(result == 0)
{
return 0;
}
return -1;
}
void insert_schedule_result(schedule_result_t **list, int subframe, schedule_result_t *node){
schedule_result_t *tmp, *tmp1;
if((schedule_result_t *)0 == *list){
*list = node;
}else{
tmp = *list;
tmp1 = (schedule_result_t *)0;
while((schedule_result_t *)0 != tmp){
if(subframe < tmp->output_subframe){
break;
}
tmp1 = tmp;
tmp = tmp->next;
}
if((schedule_result_t *)0 == tmp){
tmp1->next = node;
}else{
node->next = tmp;
if(tmp1){
tmp1->next = node;
}else{
*list = node;
}
}
}
}
void generate_scheduling_result_UL(int32_t DCI_subframe, int32_t DCI_end_subframe, uint32_t UL_subframe, uint32_t UL_end_subframe, DCIFormatN0_t *DCI_inst, rnti_t rnti, uint8_t *ul_printf_str, uint8_t *dl_printf_str, uint8_t msg3_flag){
// create the schedule result node for this time transmission
schedule_result_t *UL_result = (schedule_result_t*)malloc(sizeof(schedule_result_t));
schedule_result_t *DL_result;
schedule_result_t *tmp1, *tmp;
UL_result->direction = UL;
UL_result->output_subframe = UL_subframe;
UL_result->end_subframe = UL_end_subframe;
UL_result->DCI_pdu = DCI_inst;
UL_result->npusch_format = 0;
UL_result->DCI_release = 1;
UL_result->channel = NPUSCH;
UL_result->rnti = rnti;
UL_result->msg3_flag = msg3_flag;
UL_result->next = NULL;
//UL_result->printf_str = ul_printf_str;
if(-1 == DCI_subframe){
LOG_D(MAC,"[UL scheduler][UE:%05d] UL_result = output subframe : %d\n", rnti, UL_result->output_subframe);
}else{
DL_result = (schedule_result_t*)malloc(sizeof(schedule_result_t));
DL_result->output_subframe = DCI_subframe;
DL_result->end_subframe = DCI_end_subframe;
DL_result->DCI_pdu = DCI_inst;
DL_result->DCI_release = 0;
DL_result->direction = UL;
DL_result->channel = NPDCCH;
DL_result->rnti = rnti;
DL_result->next = NULL;
//DL_result->printf_str = dl_printf_str;
insert_schedule_result(&schedule_result_list_DL, DCI_subframe, DL_result);
LOG_D(MAC,"[UL scheduler][UE:%05d] DL_result = output subframe : %d UL_result = output subframe : %d\n", rnti, DL_result->output_subframe,UL_result->output_subframe);
}
tmp1 = NULL;
// be the first node of UL
if(schedule_result_list_UL == NULL)
{
schedule_result_list_UL = UL_result;
}else
{
tmp = schedule_result_list_UL;
while(tmp!=NULL)
{
if(UL_subframe < tmp->output_subframe)
{
break;
}
tmp1 = tmp;
tmp = tmp->next;
}
if(tmp==NULL)
{
tmp1->next = UL_result;
}
else
{
UL_result->next = tmp;
if(tmp1){
tmp1->next = UL_result;
}else{
schedule_result_list_UL = UL_result;
}
}
}
}
void adjust_UL_resource_list(sched_temp_UL_NB_IoT_t *NPUSCH_info)
{
available_resource_UL_t *temp;
available_resource_UL_t *node = NPUSCH_info->node;
// divided into two node
// keep one node(align left or right)
// delete node
int align_left = (node->start_subframe==NPUSCH_info->sf_start);
int align_right = (node->end_subframe==NPUSCH_info->sf_end);
switch(align_left+align_right){
case 0:
// divided into two node
temp = (available_resource_UL_t *)malloc(sizeof(available_resource_UL_t));
temp->next = node->next;
node->next = temp;
temp->prev = node;
temp->start_subframe = NPUSCH_info->sf_end +1;
temp->end_subframe = node->end_subframe;
node->end_subframe = NPUSCH_info->sf_start - 1;
break;
case 1:
// keep one node
if(align_left){
node->start_subframe = NPUSCH_info->sf_end +1;
}else{
node->end_subframe = NPUSCH_info->sf_start - 1 ;
}
break;
case 2:
if(node!=NULL)
{
// delete
if(node->prev==(available_resource_UL_t *)0)
{
if(NPUSCH_info->tone==sixtone)
available_resource_UL->sixtone_Head = node->next;
else if(NPUSCH_info->tone==threetone)
available_resource_UL->threetone_Head = node->next;
else if(NPUSCH_info->tone==singletone1)
available_resource_UL->singletone1_Head = node->next;
else if(NPUSCH_info->tone==singletone2)
available_resource_UL->singletone2_Head = node->next;
else if(NPUSCH_info->tone==singletone3)
available_resource_UL->singletone3_Head = node->next;
}else{
node->prev->next = node->next;
}
if(node->next!=(available_resource_UL_t *)0)
{
node->next->prev = node->prev;
}else{
node->prev->next = (available_resource_UL_t *)0;
}
free(node);
break;
}
default:
//error
break;
}
}
void add_ue_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce, uint32_t PHR, uint32_t ul_total_buffer){
int32_t i;
UE_list_NB_IoT_t *UE_list = (mac_inst->UE_list_spec + (uint32_t)ce);
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if(UE_list->UE_template_NB_IoT[i].active == 0){
UE_list->UE_template_NB_IoT[i].active = 1;
UE_list->UE_template_NB_IoT[i].rnti = rnti;
UE_list->UE_template_NB_IoT[i].PHR = PHR;
UE_list->UE_template_NB_IoT[i].ul_total_buffer = ul_total_buffer;
//New UE setting start
UE_list->UE_template_NB_IoT[i].R_dl = dl_rep[(uint32_t)ce];;
UE_list->UE_template_NB_IoT[i].I_mcs_dl = 0;
UE_list->UE_template_NB_IoT[i].CE_level = (uint32_t)ce;
//assume random select direction
UE_list->UE_template_NB_IoT[i].R_dci = dci_rep[(uint32_t)ce];
UE_list->UE_template_NB_IoT[i].R_max = UE_list->NPDCCH_config_dedicated.R_max;
//UE_list->UE_template_NB_IoT[i].R_max = 16;
UE_list->UE_template_NB_IoT[i].R_harq = harq_rep[(uint32_t)ce];
UE_list->UE_template_NB_IoT[i].HARQ_round = 0;
UE_list->UE_template_NB_IoT[i].oldNDI_UL = 0;
UE_list->UE_template_NB_IoT[i].oldNDI_DL = 0;
UE_list->UE_template_NB_IoT[i].multi_tone = 0;
//New UE setting ending
UE_list->UE_template_NB_IoT[i].prev = -1;
if(-1 == UE_list->head){
UE_list->UE_template_NB_IoT[i].next = -1;
}else{
UE_list->UE_template_NB_IoT[i].next = UE_list->head;
}
UE_list->head = i;
return ;
}
}
}
void remove_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce){
int32_t i;
UE_list_NB_IoT_t *UE_list = (mac_inst->UE_list_spec + (uint32_t)ce);
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if(UE_list->UE_template_NB_IoT[i].active == 1 && UE_list->UE_template_NB_IoT[i].rnti == rnti){
UE_list->UE_template_NB_IoT[i].active = 0;
return ;
}
}
}
//Transfrom source into hyperSF, Frame, Subframe format
void convert_system_number(uint32_t source_sf,uint32_t *hyperSF, uint32_t *frame, uint32_t *subframe)
{
if(source_sf>=1024*1024*10)
{
source_sf=source_sf%(1024*1024*10);
}
*hyperSF = (source_sf/10)/1024;
*frame = (source_sf/10)%1024;
*subframe = (source_sf%10240)%10;
}
//Trnasform hyperSF, Frame, Subframe format into subframe unit
uint32_t convert_system_number_sf(uint32_t hyperSF, uint32_t frame, uint32_t subframe)
{
return hyperSF*1024*10+frame*10+subframe;
}
/*input start position amd num_dlsf DL subframe, caculate the last subframe number*/
uint32_t cal_num_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF, uint32_t frame, uint32_t subframe, uint32_t* hyperSF_result, uint32_t* frame_result, uint32_t* subframe_result, uint32_t num_dlsf_require)
{
uint16_t sf_dlsf_index;
uint16_t dlsf_num_temp;
uint32_t abs_sf_start = 0;
uint32_t abs_sf_end = 0;
uint8_t period_count=0;
uint8_t shift_flag=0;
uint8_t scale_flag=0;
//uint8_t flag_printf=0;
abs_sf_start=convert_system_number_sf(hyperSF, frame, subframe);
sf_dlsf_index = abs_sf_start%2560%(mac_inst->sib1_period*10);
dlsf_num_temp = DLSF_information.sf_to_dlsf_table[sf_dlsf_index];
while(num_dlsf_require>DLSF_information.num_dlsf_per_period)
{
//flag_printf=1;
period_count++;
num_dlsf_require-=DLSF_information.num_dlsf_per_period;
}
abs_sf_end = abs_sf_start+period_count*mac_inst->sib1_period*10;
//LOG_D(MAC,"[cal_num_dlsf]abs_sf_end %d after loop\n", abs_sf_end);
if(num_dlsf_require>DLSF_information.num_dlsf_per_period-dlsf_num_temp+1)
{
if(is_dlsf(mac_inst, sf_dlsf_index)==1)
{
num_dlsf_require-=DLSF_information.num_dlsf_per_period-dlsf_num_temp+1;
}
else
{
num_dlsf_require-=DLSF_information.num_dlsf_per_period-dlsf_num_temp;
}
abs_sf_end+=mac_inst->sib1_period*10-abs_sf_end%(mac_inst->sib1_period*10);
dlsf_num_temp = 0;
scale_flag = 1;
}
if(num_dlsf_require!=0)
{
if(scale_flag!=1)
{
if(is_dlsf(mac_inst, abs_sf_end)==1)
{
shift_flag = 1;
}
}
if(abs_sf_end%(mac_inst->sib1_period*10)!=0)
{
abs_sf_end-=abs_sf_end%(mac_inst->sib1_period*10);
//LOG_D(MAC,"[cal_num_dlsf] abs_sf_end is %d mod period = %d\n", abs_sf_end, abs_sf_end%(mac_inst->sib1_NB_IoT_sched_config.sib1_period*10));
}
if(shift_flag==1)
{
abs_sf_end +=DLSF_information.dlsf_to_sf_table[dlsf_num_temp+num_dlsf_require-2];
}
else
{
abs_sf_end +=DLSF_information.dlsf_to_sf_table[dlsf_num_temp+num_dlsf_require-1];
}
}
convert_system_number(abs_sf_end, hyperSF_result, frame_result, subframe_result);
return abs_sf_end;
}
void init_dlsf_info(eNB_MAC_INST_NB_IoT *mac_inst, DLSF_INFO_t *DLSF_info)
{
uint16_t dlsf_num_temp=0;
uint16_t i;
uint16_t j=0;
DLSF_info->sf_to_dlsf_table=(uint16_t*)malloc(mac_inst->sib1_period*10*sizeof(uint16_t));
for(i=0;i<mac_inst->sib1_period*10;++i)
{
if(is_dlsf(mac_inst, i)==1)
{
dlsf_num_temp++;
DLSF_info->sf_to_dlsf_table[i]=dlsf_num_temp;
}
else
{
DLSF_info->sf_to_dlsf_table[i]=dlsf_num_temp;
}
}
DLSF_info->num_dlsf_per_period = dlsf_num_temp;
DLSF_info->dlsf_to_sf_table = (uint16_t*)malloc(dlsf_num_temp*sizeof(uint16_t));
for(i=0;i<mac_inst->sib1_period*10;++i)
{
if(is_dlsf(mac_inst, i)==1)
{
DLSF_info->dlsf_to_sf_table[j]= i;
j++;
}
}
}
void init_tool_sib1(eNB_MAC_INST_NB_IoT *mac_inst){
int i, j;
//int repetition_pattern = 1;// 1:every2frame, 2:every4frame, 3:every8frame, 4:every16frame
for(i=0;i<8;++i){
mac_inst->sib1_flag[(i<<1)+mac_inst->rrc_config.sib1_NB_IoT_sched_config.starting_rf] = 1;
}
for(i=0, j=0;i<64;++i){
if(mac_inst->sib1_flag[i]==1){
++j;
}
mac_inst->sib1_count[i]=j;
}
mac_inst->sib1_period = 256 / mac_inst->rrc_config.sib1_NB_IoT_sched_config.repetitions;
return ;
}
uint32_t calculate_DLSF(eNB_MAC_INST_NB_IoT *mac_inst, int abs_start_subframe, int abs_end_subframe){ //LOG_D(MAC,"calcu %p %d %d\n", mac_inst, abs_start_subframe, abs_end_subframe);
int i;
int num_dlsf=0;
//int diff_subframe = abs_end_subframe - abs_start_subframe;
int start_frame = abs_start_subframe / 10;
int end_frame = abs_end_subframe / 10;
int start_subframe = abs_start_subframe % 10;
int end_subframe = abs_end_subframe % 10;
int start_frame_mod_64 = start_frame & 0x0000003f;
int end_frame_mod_64 = end_frame & 0x0000003f;
int start_frame_div_64 = (start_frame & 0xffffffc0)>>6;
int end_frame_div_64 = (end_frame & 0xffffffc0)>>6;
if(abs_start_subframe > abs_end_subframe){
return calculate_DLSF(mac_inst, abs_start_subframe, (MAX_FRAME*10)+9) + calculate_DLSF(mac_inst, 0, abs_end_subframe);
}
if(start_frame_div_64==end_frame_div_64 && start_frame==end_frame){
for(i=abs_start_subframe;i<=abs_end_subframe;++i){
num_dlsf += is_dlsf(mac_inst, i);
}
}else{
num_dlsf = mac_inst->dlsf_table[end_frame_mod_64];
num_dlsf -= (start_frame_mod_64==0)?0:mac_inst->dlsf_table[start_frame_mod_64-1];
for(i=0;i<start_subframe;++i, --abs_start_subframe){
num_dlsf -= is_dlsf(mac_inst, abs_start_subframe-1);
}
for(i=end_subframe;i<9;++i, ++abs_end_subframe){
num_dlsf -= is_dlsf(mac_inst, abs_end_subframe+1);
}
if(start_frame_div_64!=end_frame_div_64){
num_dlsf+= (472+(end_frame_div_64-start_frame_div_64-1)*472);
}
}
return num_dlsf;
}
int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
int frame = abs_subframe/10;
int subframe = abs_subframe%10;
return !(subframe==0||subframe==5||((frame&0x1)==0&&subframe==9)||(mac_inst->sib1_flag[frame%mac_inst->sib1_period]==1&&subframe==4));
}
void init_dl_list(eNB_MAC_INST_NB_IoT *mac_inst){
available_resource_DL_t *node;
node = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
node->next = (available_resource_DL_t *)0;
node->prev = (available_resource_DL_t *)0;
available_resource_DL = node;
available_resource_DL_last = node;
node->start_subframe = 0;
node->end_subframe = 0;
mac_inst->schedule_subframe_DL = 0;
//node->end_subframe = mac_inst->rrc_config.si_window_length;
//mac_inst->schedule_subframe_DL = mac_inst->rrc_config.si_window_length;
// init sibs for first si-window
//schedule_sibs(mac_inst, 0, 0); // TODO, check init
}
#if 1
// extend subframe align to si-period
void extend_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int max_subframe){
available_resource_DL_t *new_node;
uint32_t i, i_div_si_window;
LOG_D(MAC,"[extend DL] max_subframe: %d, current schedule subframe: %d\n", max_subframe, mac_inst->schedule_subframe_DL);
print_available_resource_DL(mac_inst);
if(max_subframe > mac_inst->schedule_subframe_DL){
// align to si-period
max_subframe = ((max_subframe%mac_inst->rrc_config.si_window_length)==0)? max_subframe : (((max_subframe/mac_inst->rrc_config.si_window_length)+1)*mac_inst->rrc_config.si_window_length);
if(mac_inst->schedule_subframe_DL == available_resource_DL_last->end_subframe){
LOG_D(MAC,"[extend DL] last node is align to schedule_sf_dl\n");
available_resource_DL_last->end_subframe = max_subframe;
}else{
LOG_D(MAC,"[extend DL] add new node !\n");
new_node = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
new_node->prev= available_resource_DL_last;
available_resource_DL_last->next = new_node;
new_node->start_subframe = mac_inst->schedule_subframe_DL+1;
new_node->end_subframe = max_subframe;
new_node->next = (available_resource_DL_t *)0;
available_resource_DL_last = new_node;
}
// do schedule sibs after extend.
for(i=mac_inst->schedule_subframe_DL; i<max_subframe; i+=mac_inst->rrc_config.si_window_length){
i_div_si_window = (i / mac_inst->rrc_config.si_window_length)%256;
if(-1 != mac_inst->sibs_table[i_div_si_window]){
LOG_D(MAC,"[sibs%d] %d\n", mac_inst->sibs_table[i_div_si_window], i + (mac_inst->rrc_config.si_radio_frame_offset*10));
schedule_sibs(mac_inst, mac_inst->sibs_table[i_div_si_window], i + (mac_inst->rrc_config.si_radio_frame_offset*10)); // add si-radio-frame-offset carried in SIB1
}
}
mac_inst->schedule_subframe_DL = max_subframe;
}
}
#endif
#if 0
// extend subframe align to si-period
void extend_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int max_subframe){ // assume max_subframe is found.
available_resource_DL_t *new_node;
//int temp;
uint32_t i, i_div_si_window;
//uint32_t si_period_div_window;
//pt = available_resource_DL;
LOG_D(MAC,"[extend DL] max_subframe: %d, current schedule subframe: %d\n", max_subframe, mac_inst->schedule_subframe_DL);
print_available_resource_DL(mac_inst);
if(max_subframe > mac_inst->schedule_subframe_DL){
// align to si-period
max_subframe = ((max_subframe%mac_inst->rrc_config.si_window_length)==0)? max_subframe : (((max_subframe/mac_inst->rrc_config.si_window_length)+1)*mac_inst->rrc_config.si_window_length);
if(mac_inst->schedule_subframe_DL == available_resource_DL_last->end_subframe){
LOG_D(MAC,"[extend DL] last node is align to schedule_sf_dl\n");
available_resource_DL_last->end_subframe = max_subframe;
}else{
LOG_D(MAC,"[extend DL] add new node !\n");
new_node = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
available_resource_DL_last->next = new_node;
new_node->start_subframe = mac_inst->schedule_subframe_DL+1;
new_node->end_subframe = max_subframe;
new_node->next = (available_resource_DL_t *)0;
available_resource_DL_last = new_node;
}
LOG_D(MAC,"sf_dl:%d max:%d siw:%d\n",mac_inst->schedule_subframe_DL,max_subframe,mac_inst->rrc_config.si_window_length);
// do schedule sibs after extend.
for(i=mac_inst->schedule_subframe_DL;i<max_subframe;i+=mac_inst->rrc_config.si_window_length){
i_div_si_window = (i / mac_inst->rrc_config.si_window_length)%256;
LOG_D(MAC,"[sibs out:%d] schedule_DL:%d i_div_si_window:%d\n", mac_inst->sibs_table[i_div_si_window], i, i_div_si_window);
if(-1 != mac_inst->sibs_table[i_div_si_window]){
LOG_D(MAC,"[sibs%d] %d\n", mac_inst->sibs_table[i_div_si_window], i);
schedule_sibs(mac_inst, mac_inst->sibs_table[i_div_si_window], i);
}
}
mac_inst->schedule_subframe_DL = max_subframe;
}
return ;
}
#endif
void maintain_available_resource(eNB_MAC_INST_NB_IoT *mac_inst){
available_resource_DL_t *pfree, *iterator;
available_resource_UL_t *pfree2, *iterator2;
schedule_result_t *iterator1;
if(available_resource_DL != (available_resource_DL_t *)0){
LOG_D(MAC,"[maintain]current:%d, end:%d\n",mac_inst->current_subframe,available_resource_DL->end_subframe);
if(mac_inst->current_subframe >= available_resource_DL->end_subframe){
pfree = available_resource_DL;
if(available_resource_DL->next == (available_resource_DL_t *)0){
LOG_D(MAC,"[maintain_available_resource]=====t:%d=====dl resource list next is NULL %d\n", mac_inst->current_subframe, available_resource_DL->end_subframe);
available_resource_DL = (available_resource_DL_t *)0;
}else{
LOG_D(MAC,"[maintain_available_resource]=====t:%d=====dl resource list remove next:%d-%d\n", mac_inst->current_subframe, available_resource_DL->next->start_subframe, available_resource_DL->next->end_subframe);
available_resource_DL = available_resource_DL->next;
available_resource_DL->prev = (available_resource_DL_t *)0;
}
free((available_resource_DL_t *)pfree);
}else{
// only update when current subframe bigger than to start subframe
if(mac_inst->current_subframe > available_resource_DL->start_subframe)
{
LOG_D(MAC,"[maintain] update from %d to current %d, ori end %d\n",available_resource_DL->start_subframe,mac_inst->current_subframe,available_resource_DL->end_subframe);
available_resource_DL->start_subframe = mac_inst->current_subframe;
}else
LOG_D(MAC,"[maintain] do nothing\n");
}
}
// UL
iterator2 = available_resource_UL->singletone1_Head;
if(iterator2 != (available_resource_UL_t *)0){
if(mac_inst->current_subframe > iterator2->end_subframe){
pfree2 = iterator2;
available_resource_UL->singletone1_Head = iterator2->next;
available_resource_UL->singletone1_Head->prev = (available_resource_UL_t *)0;
free((available_resource_UL_t *)pfree2);
}else{
if(iterator2->start_subframe<mac_inst->current_subframe)
iterator2->start_subframe = mac_inst->current_subframe;
}
}
iterator2 = available_resource_UL->singletone2_Head;
if(iterator2 != (available_resource_UL_t *)0){
if(mac_inst->current_subframe > iterator2->end_subframe){
pfree2 = iterator2;
available_resource_UL->singletone2_Head = iterator2->next;
available_resource_UL->singletone2_Head->prev = (available_resource_UL_t *)0;
free((available_resource_UL_t *)pfree2);
}else{
if(iterator2->start_subframe<mac_inst->current_subframe)
iterator2->start_subframe = mac_inst->current_subframe;
}
}
iterator2 = available_resource_UL->singletone3_Head;
if(iterator2 != (available_resource_UL_t *)0){
if(mac_inst->current_subframe > iterator2->end_subframe){
pfree2 = iterator2;
available_resource_UL->singletone3_Head = iterator2->next;
available_resource_UL->singletone3_Head->prev = (available_resource_UL_t *)0;
free((available_resource_UL_t *)pfree2);
}else{
if(iterator2->start_subframe<mac_inst->current_subframe)
iterator2->start_subframe = mac_inst->current_subframe;
}
}
iterator2 = available_resource_UL->sixtone_Head;
if(iterator2 != (available_resource_UL_t *)0){
if(mac_inst->current_subframe > iterator2->end_subframe){
pfree2 = iterator2;
available_resource_UL->sixtone_Head = iterator2->next;
available_resource_UL->sixtone_Head->prev = (available_resource_UL_t *)0;
free((available_resource_UL_t *)pfree2);
}
else{
if(iterator2->start_subframe<mac_inst->current_subframe)
iterator2->start_subframe = mac_inst->current_subframe;
}
}
iterator2 = available_resource_UL->threetone_Head;
if(iterator2 != (available_resource_UL_t *)0){
if(mac_inst->current_subframe > iterator2->end_subframe){
pfree2 = iterator2;
available_resource_UL->threetone_Head = iterator2->next;
available_resource_UL->threetone_Head->prev = (available_resource_UL_t *)0;
free((available_resource_UL_t *)pfree2);
}else{
if(iterator2->start_subframe<mac_inst->current_subframe)
iterator2->start_subframe = mac_inst->current_subframe;
}
}
if(mac_inst->current_subframe == 0){
// DL available cross zero
iterator = available_resource_DL;
while(iterator != (available_resource_DL_t *)0){
if(iterator->start_subframe >= MAX_SUBFRAME)
iterator->start_subframe -= MAX_SUBFRAME;
if(iterator->end_subframe >= MAX_SUBFRAME)
iterator->end_subframe -= MAX_SUBFRAME;
iterator = iterator->next;
}
if(mac_inst->schedule_subframe_DL >= MAX_SUBFRAME)
mac_inst->schedule_subframe_DL -= MAX_SUBFRAME;
// UL available cross zero
iterator2 = available_resource_UL->sixtone_Head;
while(iterator2 != (available_resource_UL_t *)0){
if(iterator2->start_subframe >= MAX_SUBFRAME)
iterator2->start_subframe -= MAX_SUBFRAME;
if(iterator2->end_subframe >= MAX_SUBFRAME)
iterator2->end_subframe -= MAX_SUBFRAME;
iterator2 = iterator2->next;
}
iterator2 = available_resource_UL->threetone_Head;
while(iterator2 != (available_resource_UL_t *)0){
if(iterator2->start_subframe >= MAX_SUBFRAME)
iterator2->start_subframe -= MAX_SUBFRAME;
if(iterator2->end_subframe >= MAX_SUBFRAME)
iterator2->end_subframe -= MAX_SUBFRAME;
iterator2 = iterator2->next;
}
iterator2 = available_resource_UL->singletone3_Head;
while(iterator2 != (available_resource_UL_t *)0){
if(iterator2->start_subframe >= MAX_SUBFRAME)
iterator2->start_subframe -= MAX_SUBFRAME;
if(iterator2->end_subframe >= MAX_SUBFRAME)
iterator2->end_subframe -= MAX_SUBFRAME;
iterator2 = iterator2->next;
}
iterator2 = available_resource_UL->singletone1_Head;
while(iterator2 != (available_resource_UL_t *)0){
if(iterator2->start_subframe >= MAX_SUBFRAME)
iterator2->start_subframe -= MAX_SUBFRAME;
if(iterator2->end_subframe >= MAX_SUBFRAME)
iterator2->end_subframe -= MAX_SUBFRAME;
iterator2 = iterator2->next;
}
iterator2 = available_resource_UL->singletone2_Head;
while(iterator2 != (available_resource_UL_t *)0){
if(iterator2->start_subframe >= MAX_SUBFRAME)
iterator2->start_subframe -= MAX_SUBFRAME;
if(iterator2->end_subframe >= MAX_SUBFRAME)
iterator2->end_subframe -= MAX_SUBFRAME;
iterator2 = iterator2->next;
}
if(available_resource_UL->singletone1_end_subframe >= MAX_SUBFRAME)
available_resource_UL->singletone1_end_subframe -= MAX_SUBFRAME;
if(available_resource_UL->singletone2_end_subframe >= MAX_SUBFRAME)
available_resource_UL->singletone2_end_subframe -= MAX_SUBFRAME;
if(available_resource_UL->singletone3_end_subframe >= MAX_SUBFRAME)
available_resource_UL->singletone3_end_subframe -= MAX_SUBFRAME;
if(available_resource_UL->sixtone_end_subframe >= MAX_SUBFRAME)
available_resource_UL->sixtone_end_subframe -= MAX_SUBFRAME;
if(available_resource_UL->threetone_end_subframe >= MAX_SUBFRAME)
available_resource_UL->threetone_end_subframe -= MAX_SUBFRAME;
// DL result cross zero
iterator1 = schedule_result_list_DL;
while(iterator1 != (schedule_result_t *)0){
if(iterator1->output_subframe >= MAX_SUBFRAME)
iterator1->output_subframe -= MAX_SUBFRAME;
if(iterator1->end_subframe >= MAX_SUBFRAME)
iterator1->end_subframe -= MAX_SUBFRAME;
iterator1 = iterator1->next;
}
// UL result cross zero
iterator1 = schedule_result_list_UL;
while(iterator1 != (schedule_result_t *)0){
if(iterator1->output_subframe >= MAX_SUBFRAME)
iterator1->output_subframe -= MAX_SUBFRAME;
if(iterator1->end_subframe >= MAX_SUBFRAME)
iterator1->end_subframe -= MAX_SUBFRAME;
iterator1 = iterator1->next;
}
}
return ;
}
void fill_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, available_resource_DL_t *node, int start_subframe, int end_subframe, schedule_result_t *new_node){
//printf_FUNCTION_IN("[FILL DL]");
available_resource_DL_t *temp;
schedule_result_t *iterator, *temp1;
// divided into two node
// keep one node(align left or right)
// delete node
//LOG_D(MAC,"fill dl test1\n");
int align_left = (node->start_subframe==start_subframe)||(calculate_DLSF(mac_inst, node->start_subframe, start_subframe-1) == 0);
int align_right = (end_subframe==node->end_subframe)||(calculate_DLSF(mac_inst, end_subframe+1, node->end_subframe) == 0);
//LOG_D(MAC,"fill dl test2\n");
switch(align_left+align_right){
case 0:
// divided into two node, always insert before original node, so won't happen that temp is the last node of the list.
// A | node | B
// A | temp | node | B
LOG_D(MAC,"Case 0 [b], node : %p node_prev : %p\n",node,node->prev);
temp = (available_resource_DL_t *)malloc(sizeof(available_resource_DL_t));
if(node->prev){
//LOG_I(MAC,"start_subframe : %d\n",node->prev->start_subframe);
node->prev->next = temp;
}else{
available_resource_DL = temp;
}
temp->prev = node->prev;
temp->next = node;
node->prev = temp;
temp->start_subframe = node->start_subframe;
temp->end_subframe = start_subframe - 1;
node->start_subframe = end_subframe + 1;
LOG_D(MAC,"Case 0 [a], node : %p node_prev : %p\n",node,node->prev);
break;
case 1:
LOG_D(MAC,"Case 1, node : %p node_prev : %p\n",node,node->prev);
// keep one node
if(align_left){
node->start_subframe = end_subframe + 1 ;
}else{
node->end_subframe = start_subframe - 1 ;
}
break;
case 2:
LOG_D(MAC,"Case 2 [b], node : %p node_prev : %p\n",node,node->prev);
// delete
if(node->next){
node->next->prev = node->prev;
}else{
available_resource_DL_last = node->prev;
}
if(node->prev){
node->prev->next = node->next;
}else{
available_resource_DL = node->next;
}
LOG_D(MAC,"Case 2 [a], node : %p node_prev : %p\n",node,node->prev);
free(node);
break;
default:
//error
break;
}
// new node allocate from up-layer calling function.
iterator = schedule_result_list_DL;
temp1 = (schedule_result_t *)0;
if((schedule_result_t *)0 == schedule_result_list_DL){
schedule_result_list_DL = new_node;
}else{
while((schedule_result_t *)0 != iterator){
if(start_subframe < iterator->output_subframe){
break;
}
temp1 = iterator;
iterator = iterator->next;
}
if((schedule_result_t *)0 == iterator){
temp1->next = new_node;
}else{
new_node->next = iterator;
if(temp1){
temp1->next = new_node;
}else{
schedule_result_list_DL = new_node;
}
}
}
//printf_FUNCTION_OUT("[FILL DL]");
}
// check_subframe must be DLSF, you can use is_dlsf() to check before call function
available_resource_DL_t *check_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int check_subframe, int num_subframes, int *out_last_subframe, int *out_first_subframe){
available_resource_DL_t *pt;
pt = available_resource_DL;
int end_subframe = check_subframe + num_subframes - 1;
int diff_gap;
while((available_resource_DL_t *)0 != pt){
if(pt->start_subframe <= check_subframe && pt->end_subframe >= check_subframe){
break;
}
pt = pt->next;
}
if((available_resource_DL_t *)0 == pt){
return (available_resource_DL_t *)0;
}else{
if(num_subframes <= calculate_DLSF(mac_inst, check_subframe, pt->end_subframe)){
diff_gap = num_subframes - calculate_DLSF(mac_inst, check_subframe, end_subframe);
LOG_D(MAC,"Diff_gap : %d num_subframes : %d \n",diff_gap,num_subframes);
while(diff_gap){
++end_subframe;
if(is_dlsf(mac_inst, end_subframe)){
--diff_gap;
}
}
*out_last_subframe = end_subframe;
while(!is_dlsf(mac_inst, check_subframe)){
++check_subframe;
}
*out_first_subframe = check_subframe;
return pt;
}else{
return (available_resource_DL_t *)0;
}
}
}
available_resource_DL_t *check_sibs_resource(eNB_MAC_INST_NB_IoT *mac_inst, int check_start_subframe, int check_end_subframe, int num_subframe, int *residual_subframe, int *out_last_subframe, int *out_first_subframe){
available_resource_DL_t *pt;
uint32_t num_dlsf;
uint8_t output = 0x0;
pt = available_resource_DL;
// TODO find the pt which can cover part of check_start_subframe, e.g. 1280-> 1281-1440
while((available_resource_DL_t *)0 != pt){
if(pt->start_subframe <= check_start_subframe && pt->end_subframe >= check_start_subframe){
break;
}
pt = pt->next;
}
if((available_resource_DL_t *)0 == pt){
return (available_resource_DL_t *)0;
}
num_dlsf = calculate_DLSF(mac_inst, check_start_subframe, pt->end_subframe);
if((available_resource_DL_t *)0 == pt){
return (available_resource_DL_t *)0;
}else{
if(num_subframe <= num_dlsf){
while(num_subframe>0){
if(is_dlsf(mac_inst, check_start_subframe)){
--num_subframe;
if(output == 0x0){
*out_first_subframe = check_start_subframe;
output = 0x1;
}
}
if(num_subframe==0||check_start_subframe>=check_end_subframe){
break;
}else{
++check_start_subframe;
}
}
*residual_subframe = num_subframe;
*out_last_subframe = check_start_subframe;
}else{
if(num_dlsf == 0){
return (available_resource_DL_t *)0;
}else{
while(!is_dlsf(mac_inst, check_start_subframe)){
++check_start_subframe;
}
*out_first_subframe = check_start_subframe;
}
*residual_subframe = num_subframe - num_dlsf;
*out_last_subframe = pt->end_subframe;
}
return pt;
}
}
void print_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst){
available_resource_DL_t *pt;
pt = available_resource_DL;
int i=0;
LOG_D(MAC,"=== print available resource === t=%d\nsched subframe: %d, list end: %d-%d\n", mac_inst->current_subframe, mac_inst->schedule_subframe_DL, available_resource_DL_last->start_subframe, available_resource_DL_last->end_subframe);
while(pt){
LOG_D(MAC,"[%2d] %p %3d-%3d prev:%p\n", i, pt, pt->start_subframe, pt->end_subframe, pt->prev);
pt = pt->next;
}
LOG_D(MAC,"\n");
}
void print_schedule_result(void){
schedule_result_t *iterator_dl = schedule_result_list_DL;
schedule_result_t *iterator_ul = schedule_result_list_UL;
schedule_result_t *iterator;
int i = 0;
char str[20];
char str1[20];
char str2[20];
LOG_D(MAC,"=== print schedule result ===\n");
while((schedule_result_t *)0 != iterator_dl || (schedule_result_t *)0 != iterator_ul){
if((schedule_result_t *)0 == iterator_dl){
iterator = iterator_ul;
iterator_ul = iterator_ul->next;
}
else if((schedule_result_t *)0 == iterator_ul){
iterator = iterator_dl;
iterator_dl = iterator_dl->next;
}else{
if(iterator_ul->output_subframe < iterator_dl->output_subframe){
iterator = iterator_ul;
iterator_ul = iterator_ul->next;
}else{
iterator = iterator_dl;
iterator_dl = iterator_dl->next;
}
}
if(iterator->rnti == P_RNTI){
sprintf(str, " PAGING");
}
else if(iterator->rnti == SI_RNTI){
sprintf(str, "SI-RNTI");
}
else if(iterator->rnti <= RA_RNTI_HIGH && iterator->rnti >= RA_RNTI_LOW){
sprintf(str, "RA-RNTI");
}else{
sprintf(str, "UE%05d", iterator->rnti-C_RNTI_LOW);
}
if(iterator->direction == DL){
sprintf(str1, "DL");
}else{
sprintf(str1, "UL");
}
switch(iterator->channel){
case NPDCCH:
sprintf(str2, "NPDCCH");
break;
case NPDSCH:
sprintf(str2, "NPDSCH");
break;
case NPUSCH:
sprintf(str2, "NPUSCH");
break;
default:
break;
}
LOG_D(MAC,"[%2d][%s][%s][%s] output(%4d)\n", i++, str, str1, str2, iterator->output_subframe);
/* if((uint8_t *)0 != iterator->printf_str){
LOG_D(MAC," printf: %s\n", iterator->printf_str);
}else{
LOG_D(MAC,"\n");
}*/
}
}
void print_schedule_result_DL(void){
schedule_result_t *iterator = schedule_result_list_DL;
int i=0;
char str[20];
LOG_D(MAC,"=== print schedule result DL ===\n");
while((schedule_result_t *)0 != iterator){
if(iterator->rnti == P_RNTI){
sprintf(str, " PAGE");
}
else if(iterator->rnti == SI_RNTI){
sprintf(str, " SI");
}
else if(iterator->rnti <= RA_RNTI_HIGH && iterator->rnti >= RA_RNTI_LOW){
sprintf(str, " RA");
}else{
sprintf(str, "UE%03d", iterator->rnti-C_RNTI_LOW);
}
LOG_D(MAC,"[%2d][%s][""DL""] output(%4d)\n", i++, str, iterator->output_subframe);
/*if((uint8_t *)0 != iterator->printf_str){
LOG_D(MAC," printf: %s\n", iterator->printf_str);
}else{
LOG_D(MAC,"\n");
}*/
iterator = iterator->next;
}
}
void print_schedule_result_UL(void){
schedule_result_t *iterator = schedule_result_list_UL;
int i=0;
char str[20];
LOG_D(MAC,"=== print schedule result UL ===\n");
while((schedule_result_t *)0 != iterator){
sprintf(str, "UE%03d", iterator->rnti-C_RNTI_LOW);
LOG_D(MAC,"[%2d][%s][""UL""] output(%4d)\n", i++, str, iterator->output_subframe);
/*if((uint8_t *)0 != iterator->printf_str){
LOG_D(MAC," printf: %s\tnext %p\n", iterator->printf_str, iterator->next);
}else{
LOG_D(MAC,"\n");
}*/
iterator = iterator->next;
}
}
uint32_t get_scheduling_delay(uint32_t I_delay, uint32_t R_max)
{
if(I_delay==0)
{
return 0;
}
else
{
if(R_max<128)
{
if(I_delay<=4)
return 4*I_delay;
else
return (uint32_t)(2<<I_delay);
}
else
{
return (uint32_t)(16<<(I_delay-1));
}
}
}
/*
uint8_t *parse_ulsch_header( uint8_t *mac_header,
uint8_t *num_ce,
uint8_t *num_sdu,
uint8_t *rx_ces,
uint8_t *rx_lcids,
uint16_t *rx_lengths,
uint16_t tb_length ){
uint8_t not_done=1, num_ces=0, num_sdus=0, lcid,num_sdu_cnt;
uint8_t *mac_header_ptr = mac_header;
uint16_t length, ce_len=0;
while(not_done==1){
if(((SCH_SUBHEADER_FIXED_NB_IoT*)mac_header_ptr)->E == 0){
not_done = 0;
}
lcid = ((SCH_SUBHEADER_FIXED_NB_IoT *)mac_header_ptr)->LCID;
if(lcid < EXTENDED_POWER_HEADROOM){
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_SHORT_NB_IoT *)mac_header_ptr)->F == 0){
length = ((SCH_SUBHEADER_SHORT_NB_IoT *)mac_header_ptr)->L;
mac_header_ptr += 2;//sizeof(SCH_SUBHEADER_SHORT_NB_IoT);
}else{ // F = 1
length = ((((SCH_SUBHEADER_LONG_NB_IoT *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG_NB_IoT *)mac_header_ptr)->L_LSB & 0xff);
mac_header_ptr += 3;//sizeof(SCH_SUBHEADER_LONG);
}
}
rx_lcids[num_sdus] = lcid;
rx_lengths[num_sdus] = length;
num_sdus++;
}else{ // This is a control element subheader POWER_HEADROOM, BSR and CRNTI
if(lcid == SHORT_PADDING){
mac_header_ptr++;
}else{
rx_ces[num_ces] = lcid;
num_ces++;
mac_header_ptr++;
if(lcid==LONG_BSR){
ce_len+=3;
}else if(lcid==CRNTI){
ce_len+=2;
}else if((lcid==POWER_HEADROOM) || (lcid==TRUNCATED_BSR)|| (lcid== SHORT_BSR)) {
ce_len++;
}else{
// wrong lcid
}
}
}
}
*num_ce = num_ces;
*num_sdu = num_sdus;
return(mac_header_ptr);
}
*/
// calvin
// maybe we can try to use hash table to enhance searching time.
UE_TEMPLATE_NB_IoT *get_ue_from_rnti(eNB_MAC_INST_NB_IoT *inst, rnti_t rnti){
uint32_t i;
for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
if((inst->UE_list_spec+ (uint32_t)2)->UE_template_NB_IoT[i].active == 1){
if((inst->UE_list_spec+ (uint32_t)2)->UE_template_NB_IoT[i].rnti == rnti){
return &(inst->UE_list_spec+ (uint32_t)2)->UE_template_NB_IoT[i];
}
}
}
return (UE_TEMPLATE_NB_IoT *)0;
}
......@@ -44,7 +44,7 @@
#include "COMMON/platform_constants.h"
#include "COMMON/platform_types.h"
#include "COMMON/mac_rrc_primitives.h"
//#include "COMMON/mac_rrc_primitives.h"
//#include "LAYER2/MAC/defs.h"
//#include "COMMON/openair_defs.h"
......@@ -476,7 +476,7 @@ typedef struct OAI_UECapability_NB_IoT_s {
#define RRC_BUFFER_SIZE_MAX_NB_IoT 1024
#if 0
typedef struct UE_RRC_INST_NB_IoT_s {
Rrc_State_NB_IoT_t RrcState;
......@@ -571,7 +571,7 @@ typedef struct UE_RRC_INST_NB_IoT_s {
*/
} UE_RRC_INST_NB_IoT;
#endif
#include "proto_NB_IoT.h" //should be put here otherwise compilation error
#endif
......
......@@ -44,7 +44,7 @@ extern eNB_MAC_INST_NB_IoT *mac_inst;
//MP: NOTE:XXX some of the parameters defined in vars_nb_iot are called by the extern.h file so not replicated here
extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT;
//extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT;
extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT;
......
......@@ -42,7 +42,7 @@
//------------------------------------------------------------------------
UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT; //MP: may not used for the moment
//UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT; //MP: may not used for the moment
#ifndef USER_MODE
#ifndef NO_RRM
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment