/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see <http://www.gnu.org/licenses/>. Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ /*! \file phy_procedures_lte_eNB.c * \brief Implementation of common utilities for eNB/UE procedures from 36.213 LTE specifications * \author R. Knopp, F. Kaltenberger * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr * \note * \warning */ #include "PHY/defs.h" #include "PHY/extern.h" #include "MAC_INTERFACE/defs.h" #include "MAC_INTERFACE/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #ifdef LOCALIZATION #include <sys/time.h> #endif void get_Msg3_alloc(LTE_DL_FRAME_PARMS *frame_parms, unsigned char current_subframe, unsigned int current_frame, unsigned int *frame, unsigned char *subframe) { // Fill in other TDD Configuration!!!! if (frame_parms->frame_type == FDD) { *subframe = current_subframe+6; if (*subframe>9) { *subframe = *subframe-10; *frame = current_frame+1; } else { *frame=current_frame; } } else { // TDD if (frame_parms->tdd_config == 1) { switch (current_subframe) { case 0: *subframe = 7; *frame = current_frame; break; case 4: *subframe = 2; *frame = current_frame+1; break; case 5: *subframe = 2; *frame = current_frame+1; break; case 9: *subframe = 7; *frame = current_frame+1; break; } } else if (frame_parms->tdd_config == 3) { switch (current_subframe) { case 0: case 5: case 6: *subframe = 2; *frame = current_frame+1; break; case 7: *subframe = 3; *frame = current_frame+1; break; case 8: *subframe = 4; *frame = current_frame+1; break; case 9: *subframe = 2; *frame = current_frame+2; break; } } } } void get_Msg3_alloc_ret(LTE_DL_FRAME_PARMS *frame_parms, unsigned char current_subframe, unsigned int current_frame, unsigned int *frame, unsigned char *subframe) { if (frame_parms->frame_type == FDD) { // always retransmit in n+8 *subframe = current_subframe+8; if (*subframe>9) { *subframe = *subframe-10; *frame = current_frame+1; } else { *frame=current_frame; } } else { if (frame_parms->tdd_config == 1) { // original PUSCH in 2, PHICH in 6 (S), ret in 2 // original PUSCH in 3, PHICH in 9, ret in 3 // original PUSCH in 7, PHICH in 1 (S), ret in 7 // original PUSCH in 8, PHICH in 4, ret in 8 *frame = current_frame+1; } else if (frame_parms->tdd_config == 3) { // original PUSCH in 2, PHICH in 8, ret in 2 next frame // original PUSCH in 3, PHICH in 9, ret in 3 next frame // original PUSCH in 4, PHICH in 0, ret in 4 next frame *frame=current_frame+1; } } } uint8_t get_Msg3_harq_pid(LTE_DL_FRAME_PARMS *frame_parms, uint32_t frame, unsigned char current_subframe) { uint8_t ul_subframe=0; uint32_t ul_frame; if (frame_parms->frame_type ==FDD) { ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6); ul_frame = (current_subframe>3) ? (frame+1) : frame; } else { switch (frame_parms->tdd_config) { case 1: switch (current_subframe) { case 9: case 0: ul_subframe = 7; break; case 5: case 7: ul_subframe = 2; break; } break; case 3: switch (current_subframe) { case 0: case 5: case 6: ul_subframe = 2; break; case 7: ul_subframe = 3; break; case 8: ul_subframe = 4; break; case 9: ul_subframe = 2; break; } break; case 4: switch (current_subframe) { case 0: case 5: case 6: case 8: case 9: ul_subframe = 2; break; case 7: ul_subframe = 3; break; } break; case 5: ul_subframe =2; break; default: LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",frame_parms->tdd_config); mac_xface->macphy_exit("get_Msg3_harq_pid: Unsupported TDD configuration"); break; } } return(subframe2harq_pid(frame_parms,ul_frame,ul_subframe)); } unsigned char ul_ACK_subframe2_dl_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe,unsigned char ACK_index) { if (frame_parms->frame_type == FDD) { return((subframe<4) ? subframe+6 : subframe-4); } else { switch (frame_parms->tdd_config) { case 3: if (subframe == 2) { // ACK subframes 5 and 6 if (ACK_index==2) return(1); return(5+ACK_index); } else if (subframe == 3) { // ACK subframes 7 and 8 return(7+ACK_index); // To be updated } else if (subframe == 4) { // ACK subframes 9 and 0 return((9+ACK_index)%10); } else { LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; case 1: if (subframe == 2) { // ACK subframes 5 and 6 return(5+ACK_index); } else if (subframe == 3) { // ACK subframe 9 return(9); // To be updated } else if (subframe == 7) { // ACK subframes 0 and 1 return(ACK_index); // To be updated } else if (subframe == 8) { // ACK subframe 4 return(4); // To be updated } else { LOG_E(PHY,"phy_procedures_lte_common.c/ul_ACK_subframe2_dl_subframe: illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; } } return(0); } unsigned char ul_ACK_subframe2_M(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) { if (frame_parms->frame_type == FDD) { return(1); } else { switch (frame_parms->tdd_config) { case 3: if (subframe == 2) { // ACK subframes 5 and 6 return(2); // should be 3 } else if (subframe == 3) { // ACK subframes 7 and 8 return(2); // To be updated } else if (subframe == 4) { // ACK subframes 9 and 0 return(2); } else { LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; case 1: if (subframe == 2) { // ACK subframes 5 and 6 return(2); } else if (subframe == 3) { // ACK subframe 9 return(1); // To be updated } else if (subframe == 7) { // ACK subframes 0 and 1 return(2); // To be updated } else if (subframe == 8) { // ACK subframe 4 return(1); // To be updated } else { LOG_E(PHY,"phy_procedures_lte_common.c/subframe2_dl_harq_pid: illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; } } return(0); } // This function implements table 10.1-1 of 36-213, p. 69 uint8_t get_ack(LTE_DL_FRAME_PARMS *frame_parms, harq_status_t *harq_ack, unsigned char subframe, unsigned char *o_ACK) { uint8_t status=0; uint8_t subframe_dl; // printf("get_ack: SF %d\n",subframe); if (frame_parms->frame_type == FDD) { if (subframe < 4) subframe_dl = subframe + 6; else subframe_dl = subframe - 4; o_ACK[0] = harq_ack[subframe_dl].ack; status = harq_ack[subframe_dl].send_harq_status; //printf("get_ack: Getting ACK/NAK for PDSCH (subframe %d) => %d\n",subframe_dl,o_ACK[0]); } else { switch (frame_parms->tdd_config) { case 1: if (subframe == 2) { // ACK subframes 5 (forget 6) o_ACK[0] = harq_ack[5].ack; status = harq_ack[5].send_harq_status; } else if (subframe == 3) { // ACK subframe 9 o_ACK[0] = harq_ack[9].ack; status = harq_ack[9].send_harq_status; } else if (subframe == 4) { // nothing status = 0; } else if (subframe == 7) { // ACK subframes 0 (forget 1) o_ACK[0] = harq_ack[0].ack; status = harq_ack[0].send_harq_status; } else if (subframe == 8) { // ACK subframes 4 o_ACK[0] = harq_ack[4].ack; status = harq_ack[4].send_harq_status; } else { LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; case 3: if (subframe == 2) { // ACK subframes 5 and 6 if (harq_ack[5].send_harq_status == 1) { o_ACK[0] = harq_ack[5].ack; if (harq_ack[6].send_harq_status == 1) o_ACK[1] = harq_ack[6].ack; } else if (harq_ack[6].send_harq_status == 1) o_ACK[0] = harq_ack[6].ack; status = harq_ack[5].send_harq_status + (harq_ack[6].send_harq_status<<1); //printf("Subframe 2, TDD config 3: harq_ack[5] = %d (%d),harq_ack[6] = %d (%d)\n",harq_ack[5].ack,harq_ack[5].send_harq_status,harq_ack[6].ack,harq_ack[6].send_harq_status); } else if (subframe == 3) { // ACK subframes 7 and 8 if (harq_ack[7].send_harq_status == 1) { o_ACK[0] = harq_ack[7].ack; if (harq_ack[8].send_harq_status == 1) o_ACK[1] = harq_ack[8].ack; } else if (harq_ack[8].send_harq_status == 1) o_ACK[0] = harq_ack[8].ack; status = harq_ack[7].send_harq_status + (harq_ack[8].send_harq_status<<1); //printf("Subframe 3, TDD config 3: harq_ack[7] = %d,harq_ack[8] = %d\n",harq_ack[7].ack,harq_ack[8].ack); //printf("status %d : o_ACK (%d,%d)\n", status,o_ACK[0],o_ACK[1]); } else if (subframe == 4) { // ACK subframes 9 and 0 if (harq_ack[9].send_harq_status == 1) { o_ACK[0] = harq_ack[9].ack; if (harq_ack[0].send_harq_status == 1) o_ACK[1] = harq_ack[0].ack; } else if (harq_ack[8].send_harq_status == 1) o_ACK[0] = harq_ack[8].ack; status = harq_ack[9].send_harq_status + (harq_ack[0].send_harq_status<<1); //printf("Subframe 4, TDD config 3: harq_ack[9] = %d,harq_ack[0] = %d\n",harq_ack[9].ack,harq_ack[0].ack); } else { LOG_E(PHY,"phy_procedures_lte.c: get_ack, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); return(0); } break; } } //printf("status %d\n",status); return(status); } uint8_t Np6[4]={0,1,3,5}; uint8_t Np15[4]={0,3,8,13}; uint8_t Np25[4]={0,5,13,22}; uint8_t Np50[4]={0,11,27,44}; uint8_t Np75[4]={0,16,41,66}; uint8_t Np100[4]={0,22,55,88}; // This is part of the PUCCH allocation procedure (see Section 10.1 36.213) uint16_t get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1) { uint8_t *Np; switch (N_RB_DL) { case 6: Np=Np6; break; case 15: Np=Np15; break; case 25: Np=Np25; break; case 50: Np=Np50; break; case 75: Np=Np75; break; case 100: Np=Np100; break; default: LOG_E(PHY,"get_Np() FATAL: unsupported N_RB_DL %d\n",N_RB_DL); return(0); break; } if (nCCE>=Np[2]) return(Np[2+plus1]); else if (nCCE>=Np[1]) return(Np[1+plus1]); else return(Np[0+plus1]); } lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) { // if FDD return dummy value if (frame_parms->frame_type == FDD) return(SF_DL); switch (frame_parms->tdd_config) { case 1: switch (subframe) { case 0: case 4: case 5: case 9: return(SF_DL); break; case 2: case 3: case 7: case 8: return(SF_UL); break; default: return(SF_S); break; } case 3: if ((subframe<1) || (subframe>=5)) return(SF_DL); else if ((subframe>1) && (subframe < 5)) return(SF_UL); else if (subframe==1) return (SF_S); else { LOG_E(PHY,"[PHY_PROCEDURES_LTE] Unknown subframe number\n"); return(255); } break; default: LOG_E(PHY,"subframe %d Unsupported TDD configuration %d\n",subframe,frame_parms->tdd_config); mac_xface->macphy_exit("subframe x Unsupported TDD configuration"); return(255); } } lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subframe) { return(subframe_select(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms,subframe)); } uint8_t phich_subframe_to_harq_pid(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t subframe) { //LOG_D(PHY,"phich_subframe_to_harq_pid.c: frame %d, subframe %d\n",frame,subframe); return(subframe2harq_pid(frame_parms, phich_frame2_pusch_frame(frame_parms,frame,subframe), phich_subframe2_pusch_subframe(frame_parms,subframe))); } unsigned int is_phich_subframe(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) { if (frame_parms->frame_type == FDD) { return(1); } else { switch (frame_parms->tdd_config) { case 1: if ((subframe == 1) || (subframe == 4) || (subframe == 6) || (subframe == 9)) return(1); break; case 3: if ((subframe == 0) || (subframe == 8) || (subframe == 9)) return(1); break; case 4: if ((subframe == 0) || (subframe == 8) ) return(1); break; case 5: if (subframe == 0) return(1); break; default: return(0); break; } } return(0); } #ifdef LOCALIZATION double aggregate_eNB_UE_localization_stats(PHY_VARS_eNB *phy_vars_eNB, int8_t UE_id, frame_t frame, sub_frame_t subframe, int32_t UE_tx_power_dB){ // parameters declaration int8_t Mod_id, CC_id; int32_t harq_pid, avg_power, avg_rssi, median_power, median_rssi, median_subcarrier_rss, median_TA, median_TA_update, ref_timestamp_ms, current_timestamp_ms; char cqis[100], sub_powers[2048]; int len = 0, i; struct timeval ts; double sys_bw = 0; uint8_t N_RB_DL; LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; Mod_id = phy_vars_eNB->Mod_id; CC_id = phy_vars_eNB->CC_id; ref_timestamp_ms = phy_vars_eNB->ulsch_eNB[UE_id+1]->reference_timestamp_ms; for (i=0;i<13;i++) { len += sprintf(&cqis[len]," %d ", phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_subband_cqi[0][i]); } len = 0; for (i=0;i<phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier;i++) { len += sprintf(&sub_powers[len]," %d ", phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->subcarrier_power[i]); } gettimeofday(&ts, NULL); current_timestamp_ms = ts.tv_sec * 1000 + ts.tv_usec / 1000; LOG_F(LOCALIZE, "PHY: [UE %x/%d -> eNB %d], timestamp %d, " "frame %d, subframe %d" "UE Tx power %d dBm, " "RSSI ant1 %d dBm, " "RSSI ant2 %d dBm, " "pwr ant1 %d dBm, " "pwr ant2 %d dBm, " "Rx gain %d dBm, " "TA %d, " "TA update %d, " "DL_CQI (%d,%d), " "Wideband CQI (%d,%d), " "DL Subband CQI[13] %s \n" "timestamp %d, (%d active subcarrier) %s \n" ,phy_vars_eNB->dlsch_eNB[(uint32_t)UE_id][0]->rnti, UE_id, Mod_id, current_timestamp_ms, frame,subframe, UE_tx_power_dB, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[0], phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[1], dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[0]), dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[1]), phy_vars_eNB->rx_total_gain_eNB_dB, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset, // raw timing advance 1/sampling rate phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].timing_advance_update, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_cqi[0],phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].DL_cqi[1], phy_vars_eNB->PHY_measurements_eNB[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][0], phy_vars_eNB->PHY_measurements_eNB[Mod_id].wideband_cqi_dB[(uint32_t)UE_id][1], cqis, current_timestamp_ms, phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier, sub_powers); N_RB_DL = frame_parms->N_RB_DL; switch (N_RB_DL) { case 6: sys_bw = 1.92; break; case 25: sys_bw = 7.68; break; case 50: sys_bw = 15.36; break; case 100: sys_bw = 30.72; break; } if ((current_timestamp_ms - ref_timestamp_ms > phy_vars_eNB->ulsch_eNB[UE_id+1]->aggregation_period_ms) && (phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list.size != 0)) { // check the size of one list to be sure there was a message transmitted during the defined aggregation period median_power = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list); del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list); median_rssi = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list); del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list); median_subcarrier_rss = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list); del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list); median_TA = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list); del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list); median_TA_update = calculate_median(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list); del(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list); double alpha = 2, power_distance, time_distance; power_distance = pow(10, ((UE_tx_power_dB - (median_subcarrier_rss - phy_vars_eNB->rx_total_gain_eNB_dB))/(20.0*alpha))); time_distance = (double) 299792458*(phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset)/(sys_bw*1000000); phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].distance.time_based = time_distance; phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].distance.power_based = power_distance; LOG_D(LOCALIZE, " PHY [UE %x/%d -> eNB %d], timestamp %d, " "frame %d, subframe %d " "UE Tx power %d dBm, " "median RSSI %d dBm, " "median Power %d dBm, " "Rx gain %d dBm, " "power estimated r = %0.3f, " " TA %d, update %d " "TA estimated r = %0.3f\n" ,phy_vars_eNB->dlsch_eNB[(uint32_t)UE_id][0]->rnti, UE_id, Mod_id, current_timestamp_ms, frame, subframe, UE_tx_power_dB, median_rssi, median_power, phy_vars_eNB->rx_total_gain_eNB_dB, power_distance, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset, median_TA_update, time_distance); initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list); initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list); initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list); initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list); initialize(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list); // make the reference timestamp == current timestamp phy_vars_eNB->ulsch_eNB[UE_id+1]->reference_timestamp_ms = current_timestamp_ms; return 0; } else { avg_power = (dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[0]) + dB_fixed(phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->ulsch_power[1]))/2; avg_rssi = (phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[0] + phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UL_rssi[1])/2; push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rss_list,avg_power); push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_rssi_list,avg_rssi); for (i=0;i<phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->active_subcarrier;i++) { push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_subcarrier_rss_list, phy_vars_eNB->lte_eNB_pusch_vars[(uint32_t)UE_id]->subcarrier_power[i]); } push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_advance_list, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].UE_timing_offset); push_front(&phy_vars_eNB->ulsch_eNB[UE_id+1]->loc_timing_update_list, phy_vars_eNB->eNB_UE_stats[(uint32_t)UE_id].timing_advance_update); return -1; } } #endif LTE_eNB_UE_stats* get_eNB_UE_stats(uint8_t Mod_id, uint8_t CC_id,uint16_t rnti) { int8_t UE_id; if ((PHY_vars_eNB_g == NULL) || (PHY_vars_eNB_g[Mod_id] == NULL) || (PHY_vars_eNB_g[Mod_id][CC_id]==NULL)) { LOG_E(PHY,"get_eNB_UE_stats: No phy_vars_eNB found (or not allocated) for Mod_id %d,CC_id %d\n",Mod_id,CC_id); return NULL; } UE_id = find_ue(rnti, PHY_vars_eNB_g[Mod_id][CC_id]); if (UE_id == -1) { // LOG_E(PHY,"get_eNB_UE_stats: UE with rnti %x not found\n",rnti); return NULL; } return(&PHY_vars_eNB_g[Mod_id][CC_id]->eNB_UE_stats[(uint32_t)UE_id]); } int8_t find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB) { uint8_t i; for (i=0;i<NUMBER_OF_UE_MAX;i++) { if ((phy_vars_eNB->dlsch_eNB[i]) && (phy_vars_eNB->dlsch_eNB[i][0]) && (phy_vars_eNB->dlsch_eNB[i][0]->rnti==rnti)) { return(i); } } #ifdef CBA for (i=0; i<NUM_MAX_CBA_GROUP; i++){ if ((phy_vars_eNB->ulsch_eNB[i]) && // ue J is the representative of group j (phy_vars_eNB->ulsch_eNB[i]->num_active_cba_groups) && (phy_vars_eNB->ulsch_eNB[i]->cba_rnti[i]== rnti)) return(i); } #endif return(-1); } LTE_DL_FRAME_PARMS* get_lte_frame_parms(module_id_t Mod_id, uint8_t CC_id){ return(&PHY_vars_eNB_g[Mod_id][CC_id]->lte_frame_parms); } MU_MIMO_mode *get_mu_mimo_mode (module_id_t Mod_id, uint8_t CC_id, rnti_t rnti){ return(&PHY_vars_eNB_g[Mod_id][CC_id]->mu_mimo_mode[find_ue(rnti,PHY_vars_eNB_g[Mod_id][CC_id])]); }