/* * 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.1 (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_bch.c * \brief procedures related to eNB for the BCH transport channel * \author Navid Nikaein and Raymond Knopp * \date 2010 - 2014 * \email: navid.nikaein@eurecom.fr * \version 1.0 * @ingroup _mac */ #include "assertions.h" #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" #include "OCG.h" #include "OCG_extern.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" #if defined(ENABLE_ITTI) #include "intertask_interface.h" #endif #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 // NEED TO ADD schedule_SI_BR for SIB1_BR and SIB23_BR // CCE_allocation_infeasible to be done for EPDCCH/MPDCCH #ifdef Rel14 #define size_Sj25 2 int Sj25[size_Sj25] = { 0, 3 }; #define size_Sj50 6 int Sj50[size_Sj50] = { 0, 1, 2, 5, 6, 7 }; #define size_Sj75 10 int Sj75[size_Sj75] = { 0, 1, 2, 3, 4, 7, 8, 9, 10, 11 }; #define size_Sj100 14 int Sj100[size_Sj100] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15 }; int SIB1_BR_TBS_table[6] = { 208, 256, 328, 504, 712, 936 }; //------------------------------------------------------------------------------ void schedule_SIB1_BR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) //------------------------------------------------------------------------------ { int8_t bcch_sdu_length; int CC_id; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc; uint8_t *vrb_map; int first_rb = -1; int N_RB_DL; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; nfapi_dl_config_request_body_t *dl_req; int m, i, N_S_NB; int *Sj; int n_NB = 0; int TBS; int k = 0, rvidx; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { cc = &eNB->common_channels[CC_id]; vrb_map = (void *) &cc->vrb_map; N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; int foffset = cc->physCellId & 1; int sfoffset = (cc->tdd_Config == NULL) ? 0 : 1; // Time-domain scheduling if (cc->mib->message.schedulingInfoSIB1_BR_r13 == 0) continue; else switch ((cc->mib->message.schedulingInfoSIB1_BR_r13 - 1) % 3) { case 0: // repetition 4 k = (frameP >> 1) & 3; if ((subframeP != (4 + sfoffset)) || ((frameP & 1) != foffset)) continue; break; case 1: // repetition 8 k = frameP & 3; AssertFatal(N_RB_DL > 15, "SIB1-BR repetition 8 not allowed for N_RB_DL= %d\n", N_RB_DL); if ((foffset == 0) && (subframeP != (4 + sfoffset))) continue; else if ((foffset == 1) && (subframeP != ((9 + sfoffset) % 10))) continue; break; case 2: // repetition 16 k = ((10 * frameP) + subframeP) & 3; AssertFatal(N_RB_DL > 15, "SIB1-BR repetition 16 not allowed for N_RB_DL= %d\n", N_RB_DL); if ((sfoffset == 1) && ((subframeP != 0) || (subframeP != 5))) continue; else if ((sfoffset == 0) && (foffset == 0) && (subframeP != 4) && (subframeP != 9)) continue; else if ((sfoffset == 0) && (foffset == 1) && (subframeP != 0) && (subframeP != 9)) continue; break; } // if we get here we have to schedule SIB1_BR in this frame/subframe // keep counter of SIB1_BR repetitions in 8 frame period to choose narrowband on which to transmit if ((frameP & 7) == 0) cc->SIB1_BR_cnt = 0; else cc->SIB1_BR_cnt++; // Frequency-domain scheduling switch (N_RB_DL) { case 6: case 15: default: m = 1; n_NB = 0; N_S_NB = 0; Sj = NULL; break; case 25: m = 2; N_S_NB = 2; Sj = Sj25; break; case 50: m = 2; N_S_NB = 6; Sj = Sj50; break; case 75: m = 4; N_S_NB = 10; Sj = Sj75; break; case 100: m = 4; N_S_NB = 14; Sj = Sj100; break; } // Note: definition of k above and rvidx from 36.321 section 5.3.1 rvidx = (((3 * k) >> 1) + (k & 1)) & 3; i = cc->SIB1_BR_cnt & (m - 1); n_NB = Sj[((cc->physCellId % N_S_NB) + (i * N_S_NB / m)) % N_S_NB]; bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SIB1_BR, 1, &cc->BCCH_BR_pdu[0].payload[0], 1, module_idP, 0); // not used in this case AssertFatal(cc->mib->message.schedulingInfoSIB1_BR_r13 < 19, "schedulingInfoSIB1_BR_r13 %d > 18\n", (int) cc->mib->message.schedulingInfoSIB1_BR_r13); AssertFatal(bcch_sdu_length > 0, "RRC returned 0 bytes for SIB1-BR\n"); TBS = SIB1_BR_TBS_table[(cc->mib->message.schedulingInfoSIB1_BR_r13 - 1) / 3] >> 3; AssertFatal(bcch_sdu_length <= TBS, "length returned by RRC %d is not compatible with the TBS %d from MIB\n", bcch_sdu_length, TBS); if ((frameP & 1023) < 200) LOG_D(MAC, "[eNB %d] Frame %d Subframe %d: SIB1_BR->DLSCH CC_id %d, Received %d bytes, scheduling on NB %d (i %d,m %d,N_S_NB %d) rvidx %d\n", module_idP, frameP, subframeP, CC_id, bcch_sdu_length, n_NB, i, m, N_S_NB, rvidx); // allocate all 6 PRBs in narrowband for SIB1_BR first_rb = narrowband_to_first_rb(cc, n_NB); vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; vrb_map[first_rb + 2] = 1; vrb_map[first_rb + 3] = 1; vrb_map[first_rb + 4] = 1; vrb_map[first_rb + 5] = 1; dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = TBS; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // Rel10 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; // Rel13 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 0; // SIB1-BR dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SFx // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; // Program TX Request TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB-> TX_req [CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = bcch_sdu_length; TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[0].payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; if (opt_enabled == 1) { trace_pdu(1, &cc->BCCH_BR_pdu[0].payload[0], bcch_sdu_length, 0xffff, 4, 0xffff, eNB->frame, eNB->subframe, 0, 0); LOG_D(OPT, "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); } if (cc->tdd_Config != NULL) { //TDD LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (TDD) for CC_id %d SIB1-BR %d bytes\n", frameP, CC_id, bcch_sdu_length); } else { LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (FDD) for CC_id %d SIB1-BR %d bytes\n", frameP, CC_id, bcch_sdu_length); } } return; } int si_WindowLength_BR_r13tab [SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_spare] = { 20, 40, 60, 80, 120, 160, 200 }; int si_TBS_r13tab[SchedulingInfo_BR_r13__si_TBS_r13_b936 + 1] = { 152, 208, 256, 328, 408, 504, 600, 712, 808, 936 }; //------------------------------------------------------------------------------ void schedule_SI_BR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) //------------------------------------------------------------------------------ { int8_t bcch_sdu_length; int CC_id; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc; uint8_t *vrb_map; int first_rb = -1; int N_RB_DL; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; nfapi_dl_config_request_body_t *dl_req; int i; int rvidx; int absSF = (frameP * 10) + subframeP; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { cc = &eNB->common_channels[CC_id]; vrb_map = (void *) &cc->vrb_map; N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; // Time-domain scheduling if (cc->mib->message.schedulingInfoSIB1_BR_r13 == 0) continue; else { AssertFatal(cc-> sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL, "sib_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); SchedulingInfoList_BR_r13_t *schedulingInfoList_BR_r13 = cc->sib1_v13ext-> bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13; AssertFatal(schedulingInfoList_BR_r13 != NULL, "sib_v13ext->schedulingInfoList_BR_r13 is null\n"); SchedulingInfoList_t *schedulingInfoList = cc->schedulingInfoList; AssertFatal(schedulingInfoList_BR_r13->list.count == schedulingInfoList->list.count, "schedulingInfolist_BR.r13->list.count %d != schedulingInfoList.list.count %d\n", schedulingInfoList_BR_r13->list.count, schedulingInfoList->list.count); AssertFatal(cc-> sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13 <= SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200, "si_WindowLength_BR_r13 %d > %d\n", (int) cc-> sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13, SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200); // check that SI frequency-hopping is disabled AssertFatal(cc-> sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13 == SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_off, "Deactivate SI_HoppingConfigCommon_r13 in configuration file, not supported for now\n"); long si_WindowLength_BR_r13 = si_WindowLength_BR_r13tab[cc-> sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13]; long si_RepetitionPattern_r13 = cc->sib1_v13ext-> bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13; AssertFatal(si_RepetitionPattern_r13 <= SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF, "si_RepetitionPattern_r13 %d > %d\n", (int) si_RepetitionPattern_r13, SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF); // cycle through SIB list for (i = 0; i < schedulingInfoList_BR_r13->list.count; i++) { long si_Periodicity = schedulingInfoList->list.array[i]->si_Periodicity; long si_Narrowband_r13 = schedulingInfoList_BR_r13->list.array[i]-> si_Narrowband_r13; long si_TBS_r13 = si_TBS_r13tab[schedulingInfoList_BR_r13-> list.array[i]->si_TBS_r13]; // check if the SI is to be scheduled now int period_in_sf = 80 << si_Periodicity; // 2^i * 80 subframes, note: si_Periodicity is 2^i * 80ms int sf_mod_period = absSF % period_in_sf; int k = sf_mod_period & 3; // Note: definition of k and rvidx from 36.321 section 5.3.1 rvidx = (((3 * k) >> 1) + (k & 1)) & 3; if ((sf_mod_period < si_WindowLength_BR_r13) && ((frameP & (((1 << si_RepetitionPattern_r13) - 1))) == 0)) { // this SIB is to be scheduled bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SI_BR + i, 1, &cc->BCCH_BR_pdu[i + 1].payload[0], 1, module_idP, 0); // not used in this case AssertFatal(bcch_sdu_length > 0, "RRC returned 0 bytes for SI-BR %d\n", i); if (bcch_sdu_length > 0) { AssertFatal(bcch_sdu_length <= (si_TBS_r13 >> 3), "RRC provided bcch with length %d > %d (si_TBS_r13 %d)\n", bcch_sdu_length, (int) (si_TBS_r13 >> 3), (int) schedulingInfoList_BR_r13-> list.array[i]->si_TBS_r13); // allocate all 6 PRBs in narrowband for SIB1_BR // check that SIB1 didn't take this narrowband if (vrb_map[first_rb] > 0) continue; first_rb = narrowband_to_first_rb(cc, si_Narrowband_r13 - 1); vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; vrb_map[first_rb + 2] = 1; vrb_map[first_rb + 4] = 1; vrb_map[first_rb + 5] = 1; if ((frameP & 1023) < 200) LOG_D(MAC, "[eNB %d] Frame %d Subframe %d: SI_BR->DLSCH CC_id %d, Narrowband %d rvidx %d (sf_mod_period %d : si_WindowLength_BR_r13 %d : si_RepetitionPattern_r13 %d) bcch_sdu_length %d\n", module_idP, frameP, subframeP, CC_id, (int) si_Narrowband_r13 - 1, rvidx, sf_mod_period, (int) si_WindowLength_BR_r13, (int) si_RepetitionPattern_r13, bcch_sdu_length); dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req-> number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = si_TBS_r13 >> 3; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.redundancy_version = rvidx; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.number_of_layers = 1; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. num_bf_vector = 1; // Rel10 fields (for PDSCH starting symbol) dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10. pdsch_start = cc[CC_id]. sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; // Rel13 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 1; // SI-BR dl_config_pdu->dlsch_pdu. dlsch_pdu_rel13.initial_transmission_sf_io = absSF - sf_mod_period; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; // Program TX Request TX_req = &eNB->TX_req[CC_id]. tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = bcch_sdu_length; TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[i + 1].payload; eNB->TX_req[CC_id].tx_request_body. number_of_pdus++; if (opt_enabled == 1) { trace_pdu(1, &cc->BCCH_BR_pdu[i + 1].payload[0], bcch_sdu_length, 0xffff, 4, 0xffff, eNB->frame, eNB->subframe, 0, 0); LOG_D(OPT, "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); } if (cc->tdd_Config != NULL) { //TDD LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (TDD) for CC_id %d SI-BR %d bytes\n", frameP, i, CC_id, bcch_sdu_length); } else { LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (FDD) for CC_id %d SI-BR %d bytes\n", frameP, i, CC_id, bcch_sdu_length); } } } // scheduling in current frame/subframe } //for SI List } // eMTC is activated } // CC_id return; } #endif void schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; int mib_sdu_length; int CC_id; nfapi_dl_config_request_body_t *dl_req; AssertFatal(subframeP == 0, "Subframe must be 0\n"); AssertFatal((frameP & 3) == 0, "Frame must be a multiple of 4\n"); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { dl_req = &eNB->DL_req[CC_id].dl_config_request_body; cc = &eNB->common_channels[CC_id]; mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 1, module_idP, 0); // not used in this case LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", frameP, subframeP, mib_sdu_length); if (mib_sdu_length > 0) { LOG_D(MAC, "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", frameP, subframeP, dl_req->number_pdu, mib_sdu_length); if ((frameP & 1023) < 40) LOG_D(MAC, "[eNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes (cc->mib->message.schedulingInfoSIB1_BR_r13 %d)\n", module_idP, frameP, CC_id, mib_sdu_length, (int) cc->mib->message.schedulingInfoSIB1_BR_r13); dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_BCH_PDU_TYPE, dl_config_pdu->pdu_size = 2 + sizeof(nfapi_dl_config_bch_pdu); dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->bch_pdu.bch_pdu_rel8.transmission_power = 6000; dl_req->number_pdu++; LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", dl_req->number_pdu, &dl_req->number_pdu); // DL request TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req [CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = 3; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = 0; TX_req->segments[0].segment_data = cc[CC_id].MIB_pdu.payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; } } } //------------------------------------------------------------------------------ void schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) //------------------------------------------------------------------------------ { int8_t bcch_sdu_length; int mcs = -1; int CC_id; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc; uint8_t *vrb_map; int first_rb = -1; int N_RB_DL; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; nfapi_dl_config_request_body_t *dl_req; start_meas(&eNB->schedule_si); // Only schedule LTE System Information in subframe 5 if (subframeP == 5) { for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { cc = &eNB->common_channels[CC_id]; vrb_map = (void *) &cc->vrb_map; N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 1, module_idP, 0); // not used in this case if (bcch_sdu_length > 0) { LOG_D(MAC, "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", module_idP, frameP, CC_id, bcch_sdu_length); // Allocate 4 PRBs in a random location /* while (1) { first_rb = (unsigned char)(taus()%(PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL-4)); if ((vrb_map[first_rb] != 1) && (vrb_map[first_rb+1] != 1) && (vrb_map[first_rb+2] != 1) && (vrb_map[first_rb+3] != 1)) break; } */ switch (N_RB_DL) { case 6: first_rb = 0; break; case 15: first_rb = 6; break; case 25: first_rb = 11; break; case 50: first_rb = 23; break; case 100: first_rb = 48; break; } vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; vrb_map[first_rb + 2] = 1; vrb_map[first_rb + 3] = 1; // Get MCS for length of SI, 3 PRBs if (bcch_sdu_length <= 7) { mcs = 0; } else if (bcch_sdu_length <= 11) { mcs = 1; } else if (bcch_sdu_length <= 18) { mcs = 2; } else if (bcch_sdu_length <= 22) { mcs = 3; } else if (bcch_sdu_length <= 26) { mcs = 4; } else if (bcch_sdu_length <= 28) { mcs = 5; } else if (bcch_sdu_length <= 32) { mcs = 6; } else if (bcch_sdu_length <= 41) { mcs = 7; } else if (bcch_sdu_length <= 49) { mcs = 8; } dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level = 4; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // S-RNTI : see Table 4-10 from SCF082 - nFAPI specifications dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. new_data_indicator_1 = 0; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. redundancy_version_1 = 0; dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); // Rel10 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; // Rel13 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF if (!CCE_allocation_infeasible (module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP); dl_req->number_dci++; dl_req->number_pdu++; dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. redundancy_version = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. number_of_layers = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. transmission_mode = (cc->p_eNB == 1) ? 1 : 2; dl_config_pdu->dlsch_pdu. dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; // Program TX Request TX_req = &eNB->TX_req[CC_id]. tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = bcch_sdu_length; TX_req->segments[0].segment_data = cc->BCCH_pdu.payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; } else { LOG_E(MAC, "[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A for SI\n", module_idP, CC_id, frameP, subframeP); } if (opt_enabled == 1) { trace_pdu(1, &cc->BCCH_pdu.payload[0], bcch_sdu_length, 0xffff, 4, 0xffff, eNB->frame, eNB->subframe, 0, 0); LOG_D(OPT, "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); } if (cc->tdd_Config != NULL) { //TDD LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH->DLSCH (TDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } else { LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } eNB->eNB_stats[CC_id].total_num_bcch_pdu += 1; eNB->eNB_stats[CC_id].bcch_buffer = bcch_sdu_length; eNB->eNB_stats[CC_id].total_bcch_buffer += bcch_sdu_length; eNB->eNB_stats[CC_id].bcch_mcs = mcs; } else { //LOG_D(MAC,"[eNB %d] Frame %d : BCCH not active \n",Mod_id,frame); } } } #ifdef Rel14 schedule_SIB1_BR(module_idP, frameP, subframeP); schedule_SI_BR(module_idP, frameP, subframeP); #endif stop_meas(&eNB->schedule_si); return; }