At this point we are successfully able to build. Additionally, we can run the scenario, however, it does not pass. It seems that the gNB is not connecting to the proxy correctly. Just wanted to push the progress so far. FYI, the items that had to be changed to correct the linking issues were the following: - mac_rrc_data_ind_ue vs. nr_mac_rrc_data_ind_ue - rrc_data_req vs. nr_rrc_data_req - mac_rrc_data_req_ue vs. nr_mac_rrc_data_req_ue - rrc_data_req_ue vs. rrc_data_req_nr_ue - rrc_data_req vs. nr_rrc_data_req The listed functions should be declard in the LTE/NR UE directory depending on the functionality. Several were mixed. i.e.: LTE functions being called in NR UE. Also, removing siWindowLength, siWindowLength_int, SIBType, SIBPeriod, and siPeriod_int from the NR UE RRC. These variable were not used in the NR UE and are defined for LTE only. Lastly, in the NR_IF_Module.c of the NR UE, the global variable def_dci_pdu_rel15 is not accessible. Need to revisit this. For not it is commented out.
2249 lines
95 KiB
C
2249 lines
95 KiB
C
/*
|
|
* 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 phy_procedures_lte_eNB.c
|
|
* \brief Implementation of eNB procedures from 36.213 LTE specifications / FeMBMS 36.231 LTE procedures v14.2
|
|
* \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas, J. Morgade
|
|
* \date 2011
|
|
* \version 0.1
|
|
* \company Eurecom
|
|
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk, javier.morgade@ieee.org
|
|
* \note
|
|
* \warning
|
|
*/
|
|
|
|
#include "PHY/defs_eNB.h"
|
|
#include "PHY/phy_extern.h"
|
|
#include "SCHED/sched_eNB.h"
|
|
#include "SCHED/sched_common_extern.h"
|
|
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
#include "fapi_l1.h"
|
|
#include "common/utils/LOG/log.h"
|
|
#include <common/utils/system.h>
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include <nfapi/oai_integration/nfapi_pnf.h>
|
|
|
|
#include "assertions.h"
|
|
#include "msc.h"
|
|
|
|
#include <time.h>
|
|
|
|
#include "intertask_interface.h"
|
|
#include <executables/split_headers.h>
|
|
|
|
#define MBMS_NFAPI_SCHEDULER
|
|
|
|
#include "common/ran_context.h"
|
|
extern RAN_CONTEXT_t RC;
|
|
|
|
|
|
int16_t get_hundred_times_delta_IF_eNB(PHY_VARS_eNB *eNB,uint16_t ULSCH_id,uint8_t harq_pid, uint8_t bw_factor) {
|
|
uint32_t Nre,sumKr,MPR_x100,Kr,r;
|
|
uint16_t beta_offset_pusch;
|
|
DevAssert( ULSCH_id < NUMBER_OF_ULSCH_MAX+1 );
|
|
DevAssert( harq_pid < 8 );
|
|
Nre = eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->Nsymb_initial *
|
|
eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->nb_rb*12;
|
|
sumKr = 0;
|
|
|
|
for (r=0; r<eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->C; r++) {
|
|
if (r<eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->Cminus)
|
|
Kr = eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->Kminus;
|
|
else
|
|
Kr = eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->Kplus;
|
|
|
|
sumKr += Kr;
|
|
}
|
|
|
|
if (Nre==0)
|
|
return(0);
|
|
|
|
MPR_x100 = 100*sumKr/Nre;
|
|
// Note: MPR=is the effective spectral efficiency of the PUSCH
|
|
// FK 20140908 sumKr is only set after the ulsch_encoding
|
|
beta_offset_pusch = 8;
|
|
//(eNB->ulsch[UE_id]->harq_processes[harq_pid]->control_only == 1) ? eNB->ulsch[UE_id]->beta_offset_cqi_times8:8;
|
|
DevAssert( ULSCH_id < NUMBER_OF_ULSCH_MAX );
|
|
//#warning "This condition happens sometimes. Need more investigation" // navid
|
|
//DevAssert( MPR_x100/6 < 100 );
|
|
|
|
if (1==1) { //eNB->ul_power_control_dedicated[UE_id].deltaMCS_Enabled == 1) {
|
|
// This is the formula from Section 5.1.1.1 in 36.213 10*log10(deltaIF_PUSCH = (2^(MPR*Ks)-1)*beta_offset_pusch)
|
|
if (bw_factor == 1) {
|
|
uint8_t nb_rb = eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->nb_rb;
|
|
return(hundred_times_delta_TF[MPR_x100/6]+10*dB_fixed_x10((beta_offset_pusch)>>3)) + hundred_times_log10_NPRB[nb_rb-1];
|
|
} else
|
|
return(hundred_times_delta_TF[MPR_x100/6]+10*dB_fixed_x10((beta_offset_pusch)>>3));
|
|
} else {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
int16_t get_hundred_times_delta_IF_mac(module_id_t module_idP, uint8_t CC_id, rnti_t rnti, uint8_t harq_pid) {
|
|
int8_t ULSCH_id;
|
|
|
|
if ((RC.eNB == NULL) || (module_idP > RC.nb_inst) || (CC_id > RC.nb_CC[module_idP])) {
|
|
LOG_E(PHY,"get_UE_stats: No eNB found (or not allocated) for Mod_id %d,CC_id %d\n",module_idP,CC_id);
|
|
return -1;
|
|
}
|
|
|
|
ULSCH_id = find_ulsch( rnti, RC.eNB[module_idP][CC_id],SEARCH_EXIST);
|
|
|
|
if (ULSCH_id == -1) {
|
|
// not found
|
|
return 0;
|
|
}
|
|
|
|
return get_hundred_times_delta_IF_eNB( RC.eNB[module_idP][CC_id], ULSCH_id, harq_pid, 0 );
|
|
}
|
|
|
|
int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind);
|
|
|
|
|
|
lte_subframe_t get_subframe_direction(uint8_t Mod_id,uint8_t CC_id,uint8_t subframe) {
|
|
return(subframe_select(&RC.eNB[Mod_id][CC_id]->frame_parms,subframe));
|
|
}
|
|
|
|
#ifdef MBMS_NFAPI_SCHEDULER
|
|
void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, int fembms_flag) {
|
|
int subframe = proc->subframe_tx;
|
|
// This is DL-Cell spec pilots in Control region
|
|
if(!fembms_flag){
|
|
generate_pilots_slot (eNB, eNB->common_vars.txdataF, AMP, subframe << 1, 1);
|
|
generate_mbsfn_pilot(eNB,proc,
|
|
eNB->common_vars.txdataF,
|
|
AMP);
|
|
}else
|
|
generate_mbsfn_pilot_khz_1dot25(eNB,proc,
|
|
eNB->common_vars.txdataF,
|
|
AMP);
|
|
|
|
if(eNB->dlsch_MCH->active==1){
|
|
if(!fembms_flag){
|
|
generate_mch (eNB, proc,NULL/*, eNB->dlsch_MCH->harq_processes[0]->pdu*/);
|
|
}
|
|
else{
|
|
generate_mch_khz_1dot25 (eNB, proc,NULL/*, eNB->dlsch_MCH->harq_processes[0]->pdu*/);
|
|
}
|
|
|
|
LOG_D(PHY,"[eNB%"PRIu8"] Frame %d subframe %d : Got MCH pdu for MBSFN (TBS %d) fembms %d \n",
|
|
eNB->Mod_id,proc->frame_tx,subframe,
|
|
eNB->dlsch_MCH->harq_processes[0]->TBS>>3,fembms_flag);
|
|
|
|
}
|
|
eNB->dlsch_MCH->active = 0;
|
|
}
|
|
#else
|
|
void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
|
|
MCH_PDU *mch_pduP=NULL;
|
|
// uint8_t sync_area=255;
|
|
int subframe = proc->subframe_tx;
|
|
AssertFatal (1 == 1, "pmch not tested for the moment, exiting\n");
|
|
// This is DL-Cell spec pilots in Control region
|
|
generate_pilots_slot (eNB, eNB->common_vars.txdataF, AMP, subframe << 1, 1);
|
|
|
|
// if mcch is active, send regardless of the node type: eNB or RN
|
|
// when mcch is active, MAC sched does not allow MCCH and MTCH multiplexing
|
|
/*
|
|
mch_pduP = mac_xface->get_mch_sdu(eNB->Mod_id,
|
|
eNB->CC_id,
|
|
proc->frame_tx,
|
|
subframe);
|
|
*/
|
|
mch_pduP= &RC.mac[eNB->Mod_id]->common_channels[eNB->CC_id].MCH_pdu;
|
|
if ((mch_pduP->Pdu_size > 0) && (mch_pduP->sync_area == 0)) // TEST: only transmit mcch for sync area 0
|
|
LOG_D(PHY,"[eNB%"PRIu8"] Frame %d subframe %d : Got MCH pdu for MBSFN (MCS %"PRIu8", TBS %d) \n",
|
|
eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->mcs,
|
|
eNB->dlsch_MCH->harq_processes[0]->TBS>>3);
|
|
else {
|
|
LOG_D(PHY,"[DeNB %"PRIu8"] Frame %d subframe %d : Do not transmit MCH pdu for MBSFN sync area %"PRIu8" (%s)\n",
|
|
eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->sync_area,
|
|
(mch_pduP->Pdu_size == 0)? "Empty MCH PDU":"Let RN transmit for the moment");
|
|
mch_pduP = NULL;
|
|
}
|
|
|
|
if (mch_pduP) {
|
|
fill_eNB_dlsch_MCH (eNB, mch_pduP->mcs, 1, 0);
|
|
eNB->dlsch_MCH->harq_ids[proc->frame_tx%2][subframe] = 0;
|
|
eNB->dlsch_MCH->harq_processes[0]->pdu=(uint8_t *) mch_pduP->payload;
|
|
// Generate PMCH
|
|
generate_mch (eNB, proc, NULL/*(uint8_t *) mch_pduP->payload*/);
|
|
} else {
|
|
LOG_D (PHY, "[eNB/RN] Frame %d subframe %d: MCH not generated \n", proc->frame_tx, subframe);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void common_signal_procedures_fembms (PHY_VARS_eNB *eNB,int frame, int subframe) {
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
int **txdataF = eNB->common_vars.txdataF;
|
|
uint8_t *pbch_pdu=&eNB->pbch_pdu[0];
|
|
|
|
if((frame&3)!=0 /*&& subframe != 0*/)
|
|
return;
|
|
|
|
LOG_I(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s index:%d\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?",(frame&15)/4);
|
|
// generate Cell-Specific Reference Signals for both slots
|
|
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1);
|
|
|
|
|
|
if(subframe_select(fp,subframe) == SF_S)
|
|
generate_pilots_slot(eNB,
|
|
txdataF,
|
|
AMP,
|
|
subframe<<1,1);
|
|
else
|
|
generate_pilots_slot(eNB,
|
|
txdataF,
|
|
AMP,
|
|
subframe<<1,0);
|
|
|
|
// check that 2nd slot is for DL
|
|
if (subframe_select (fp, subframe) == SF_DL)
|
|
generate_pilots_slot (eNB, txdataF, AMP, (subframe << 1) + 1, 0);
|
|
|
|
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX, 0);
|
|
|
|
// First half of PSS/SSS (FDD, slot 0)
|
|
if (subframe == 0) {
|
|
//if (fp->frame_type == FDD) {
|
|
generate_pss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 0);
|
|
generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 5 : 4, 0);
|
|
//}
|
|
|
|
/// First half of SSS (TDD, slot 1)
|
|
|
|
//if (fp->frame_type == TDD) {
|
|
generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 1);
|
|
//}
|
|
|
|
// generate PBCH (Physical Broadcast CHannel) info
|
|
|
|
/// generate PBCH
|
|
if ((frame&15)==0) {
|
|
//AssertFatal(eNB->pbch_configured==1,"PBCH was not configured by MAC\n");
|
|
if (eNB->pbch_configured!=1) return;
|
|
|
|
eNB->pbch_configured=0;
|
|
}
|
|
|
|
if (T_ACTIVE(T_ENB_PHY_MIB)) {
|
|
/* MIB is stored in reverse in pbch_pdu, reverse it for properly logging */
|
|
uint8_t mib[3];
|
|
mib[0] = pbch_pdu[2];
|
|
mib[1] = pbch_pdu[1];
|
|
mib[2] = pbch_pdu[0];
|
|
T(T_ENB_PHY_MIB, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe),
|
|
T_BUFFER(mib, 3));
|
|
}
|
|
generate_pbch_fembms (&eNB->pbch, txdataF, AMP, fp, pbch_pdu, (frame & 15)/4);
|
|
} //else if ((subframe == 1) && (fp->frame_type == TDD)) {
|
|
//generate_pss (txdataF, AMP, fp, 2, 2);
|
|
// }
|
|
// Second half of PSS/SSS (FDD, slot 10)
|
|
else if ((subframe == 5) && (fp->frame_type == FDD) && is_fembms_nonMBSFN_subframe(frame,subframe,fp)) {
|
|
generate_pss (txdataF, AMP, &eNB->frame_parms, (fp->Ncp == NORMAL) ? 6 : 5, 10);
|
|
generate_sss (txdataF, AMP, &eNB->frame_parms, (fp->Ncp == NORMAL) ? 5 : 4, 10);
|
|
}
|
|
// Second-half of SSS (TDD, slot 11)
|
|
// else if ((subframe == 5) && (fp->frame_type == TDD)) {
|
|
// generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 11);
|
|
// }
|
|
// Second half of PSS (TDD, slot 12)
|
|
// else if ((subframe == 6) && (fp->frame_type == TDD)) {
|
|
// generate_pss (txdataF, AMP, fp, 2, 12);
|
|
// }
|
|
}
|
|
|
|
void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) {
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
int **txdataF = eNB->common_vars.txdataF;
|
|
uint8_t *pbch_pdu=&eNB->pbch_pdu[0];
|
|
//LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?");
|
|
// generate Cell-Specific Reference Signals for both slots
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1);
|
|
|
|
if(subframe_select(fp,subframe) == SF_S)
|
|
generate_pilots_slot(eNB,
|
|
txdataF,
|
|
AMP,
|
|
subframe<<1,1);
|
|
else
|
|
generate_pilots_slot(eNB,
|
|
txdataF,
|
|
AMP,
|
|
subframe<<1,0);
|
|
|
|
// check that 2nd slot is for DL
|
|
if (subframe_select (fp, subframe) == SF_DL)
|
|
generate_pilots_slot (eNB, txdataF, AMP, (subframe << 1) + 1, 0);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX, 0);
|
|
|
|
// First half of PSS/SSS (FDD, slot 0)
|
|
if (subframe == 0) {
|
|
if (fp->frame_type == FDD) {
|
|
generate_pss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 0);
|
|
generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 5 : 4, 0);
|
|
}
|
|
|
|
/// First half of SSS (TDD, slot 1)
|
|
|
|
if (fp->frame_type == TDD) {
|
|
generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 1);
|
|
}
|
|
|
|
// generate PBCH (Physical Broadcast CHannel) info
|
|
|
|
/// generate PBCH
|
|
if ((frame&3)==0) {
|
|
//AssertFatal(eNB->pbch_configured==1,"PBCH was not configured by MAC\n");
|
|
if (eNB->pbch_configured!=1) return;
|
|
|
|
eNB->pbch_configured=0;
|
|
}
|
|
|
|
if (T_ACTIVE(T_ENB_PHY_MIB)) {
|
|
/* MIB is stored in reverse in pbch_pdu, reverse it for properly logging */
|
|
uint8_t mib[3];
|
|
mib[0] = pbch_pdu[2];
|
|
mib[1] = pbch_pdu[1];
|
|
mib[2] = pbch_pdu[0];
|
|
T(T_ENB_PHY_MIB, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe),
|
|
T_BUFFER(mib, 3));
|
|
}
|
|
generate_pbch (&eNB->pbch, txdataF, AMP, fp, pbch_pdu, frame & 3);
|
|
} else if ((subframe == 1) && (fp->frame_type == TDD)) {
|
|
generate_pss (txdataF, AMP, fp, 2, 2);
|
|
}
|
|
// Second half of PSS/SSS (FDD, slot 10)
|
|
else if ((subframe == 5) && (fp->frame_type == FDD)) {
|
|
generate_pss (txdataF, AMP, &eNB->frame_parms, (fp->Ncp == NORMAL) ? 6 : 5, 10);
|
|
generate_sss (txdataF, AMP, &eNB->frame_parms, (fp->Ncp == NORMAL) ? 5 : 4, 10);
|
|
}
|
|
// Second-half of SSS (TDD, slot 11)
|
|
else if ((subframe == 5) && (fp->frame_type == TDD)) {
|
|
generate_sss (txdataF, AMP, fp, (fp->Ncp == NORMAL) ? 6 : 5, 11);
|
|
}
|
|
// Second half of PSS (TDD, slot 12)
|
|
else if ((subframe == 6) && (fp->frame_type == TDD)) {
|
|
generate_pss (txdataF, AMP, fp, 2, 12);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool dlsch_procedures(PHY_VARS_eNB *eNB,
|
|
L1_rxtx_proc_t *proc,
|
|
int harq_pid,
|
|
LTE_eNB_DLSCH_t *dlsch,
|
|
LTE_eNB_UE_stats *ue_stats) {
|
|
int frame=proc->frame_tx;
|
|
int subframe=proc->subframe_tx;
|
|
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid];
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
|
|
if (dlsch->rnti != 0xffff) {//frame < 200) {
|
|
LOG_D(PHY,
|
|
"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH (type %d) with input size = %"PRIu16", pdsch_start %d, G %d, nb_rb %"PRIu16", rb0 %x, rb1 %x, TBS %"PRIu16", pmi_alloc %"PRIx64", rv %"PRIu8" (round %"PRIu8")\n",
|
|
eNB->Mod_id, dlsch->rnti,harq_pid,
|
|
frame, subframe, dlsch->ue_type,dlsch_harq->TBS/8, dlsch_harq->pdsch_start,
|
|
get_G(fp,
|
|
dlsch_harq->nb_rb,
|
|
dlsch_harq->rb_alloc,
|
|
dlsch_harq->Qm,
|
|
dlsch_harq->Nl,
|
|
dlsch_harq->pdsch_start,
|
|
frame,
|
|
subframe,
|
|
dlsch_harq->mimo_mode==TM7?7:0),
|
|
dlsch_harq->nb_rb,
|
|
dlsch_harq->rb_alloc[0],
|
|
dlsch_harq->rb_alloc[1],
|
|
dlsch_harq->TBS,
|
|
pmi2hex_2Ar1(dlsch_harq->pmi_alloc),
|
|
dlsch_harq->rvidx,
|
|
dlsch_harq->round);
|
|
}
|
|
|
|
if (ue_stats) ue_stats->dlsch_sliding_cnt++;
|
|
|
|
if (dlsch_harq->round == 0) {
|
|
if (ue_stats)
|
|
ue_stats->dlsch_trials[harq_pid][0]++;
|
|
} else {
|
|
ue_stats->dlsch_trials[harq_pid][dlsch_harq->round]++;
|
|
#ifdef DEBUG_PHY_PROC
|
|
#ifdef DEBUG_DLSCH
|
|
LOG_D (PHY, "[eNB] This DLSCH is a retransmission\n");
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
if (dlsch->rnti!=0xffff)
|
|
LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n",
|
|
dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0],
|
|
dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round);
|
|
|
|
// 36-212
|
|
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF
|
|
if (dlsch_harq->pdu==NULL) {
|
|
LOG_E(PHY,"dlsch_harq->pdu == NULL SFN/SF:%04d%d dlsch[rnti:%x] dlsch_harq[pdu:%p pdsch_start:%d Qm:%d Nl:%d round:%d nb_rb:%d rb_alloc[0]:%d]\n", frame,subframe,dlsch->rnti, dlsch_harq->pdu,
|
|
dlsch_harq->pdsch_start,dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0]);
|
|
return false;
|
|
}
|
|
|
|
start_meas(&eNB->dlsch_encoding_stats);
|
|
dlsch_encoding_all(eNB,
|
|
proc,
|
|
dlsch_harq->pdu,
|
|
dlsch_harq->pdsch_start,
|
|
dlsch,
|
|
frame,
|
|
subframe,
|
|
&eNB->dlsch_rate_matching_stats,
|
|
&eNB->dlsch_turbo_encoding_stats,
|
|
&eNB->dlsch_turbo_encoding_waiting_stats,
|
|
&eNB->dlsch_turbo_encoding_main_stats,
|
|
&eNB->dlsch_turbo_encoding_wakeup_stats0,
|
|
&eNB->dlsch_turbo_encoding_wakeup_stats1,
|
|
&eNB->dlsch_interleaving_stats);
|
|
stop_meas(&eNB->dlsch_encoding_stats);
|
|
|
|
if ( proc->threadPool->activated ) {
|
|
// Wait all other threads finish to process
|
|
while (proc->nbEncode) {
|
|
delNotifiedFIFO_elt(pullTpool(proc->respEncode, proc->threadPool));
|
|
proc->nbEncode--;
|
|
}
|
|
}
|
|
|
|
if(eNB->dlsch_encoding_stats.p_time>500*3000 && opp_enabled == 1) {
|
|
print_meas_now(&eNB->dlsch_encoding_stats,"total coding",stderr);
|
|
}
|
|
|
|
#ifdef PHY_TX_THREAD
|
|
dlsch->active[subframe] = 0;
|
|
#else
|
|
dlsch->active = 0;
|
|
#endif
|
|
dlsch_harq->round++;
|
|
LOG_D(PHY,"Generated DLSCH dlsch_harq[round:%d]\n",dlsch_harq->round);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void pdsch_procedures(PHY_VARS_eNB *eNB,
|
|
L1_rxtx_proc_t *proc,
|
|
int harq_pid,
|
|
LTE_eNB_DLSCH_t *dlsch,
|
|
LTE_eNB_DLSCH_t *dlsch1) {
|
|
int frame=proc->frame_tx;
|
|
int subframe=proc->subframe_tx;
|
|
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid];
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
// 36-211
|
|
start_meas(&eNB->dlsch_scrambling_stats);
|
|
dlsch_scrambling(fp,
|
|
0,
|
|
dlsch,
|
|
harq_pid,
|
|
get_G(fp,
|
|
dlsch_harq->nb_rb,
|
|
dlsch_harq->rb_alloc,
|
|
dlsch_harq->Qm,
|
|
dlsch_harq->Nl,
|
|
dlsch_harq->pdsch_start,
|
|
frame,subframe,
|
|
0),
|
|
0,
|
|
frame,
|
|
subframe<<1);
|
|
stop_meas(&eNB->dlsch_scrambling_stats);
|
|
start_meas(&eNB->dlsch_modulation_stats);
|
|
dlsch_modulation(eNB,
|
|
eNB->common_vars.txdataF,
|
|
AMP,
|
|
frame,
|
|
subframe,
|
|
dlsch_harq->pdsch_start,
|
|
dlsch,
|
|
dlsch->ue_type==0 ? dlsch1 : (LTE_eNB_DLSCH_t *)NULL);
|
|
stop_meas(&eNB->dlsch_modulation_stats);
|
|
LOG_D(PHY,"Generated PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round);
|
|
}
|
|
|
|
|
|
|
|
void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
|
|
L1_rxtx_proc_t *proc,
|
|
int do_meas) {
|
|
int frame=proc->frame_tx;
|
|
int subframe=proc->subframe_tx;
|
|
uint8_t harq_pid;
|
|
uint8_t num_pdcch_symbols=0;
|
|
uint8_t num_dci=0;
|
|
uint8_t num_mdci = 0;
|
|
uint8_t ul_subframe;
|
|
uint32_t ul_frame;
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
LTE_UL_eNB_HARQ_t *ulsch_harq;
|
|
|
|
if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL))
|
|
return;
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+(eNB->CC_id),1);
|
|
|
|
if (do_meas==1) start_meas(&eNB->phy_proc_tx);
|
|
if (do_meas==1) start_meas(&eNB->dlsch_common_and_dci);
|
|
|
|
// clear the transmit data array for the current subframe
|
|
for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) {
|
|
if (eNB->use_DTX==0)
|
|
memcpy(&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti)],
|
|
&eNB->subframe_mask[aa][subframe*fp->ofdm_symbol_size*fp->symbols_per_tti],
|
|
fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t));
|
|
else memset(&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti)], 0, fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t));
|
|
}
|
|
|
|
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
|
|
if (is_fembms_pmch_subframe(frame,subframe,fp)) {
|
|
#ifdef MBMS_NFAPI_SCHEDULER
|
|
pmch_procedures(eNB,proc,1);
|
|
LOG_D(MAC,"frame %d, subframe %d -> PMCH\n",frame,subframe);
|
|
return;
|
|
#endif
|
|
}else if(is_fembms_cas_subframe(frame,subframe,fp) || is_fembms_nonMBSFN_subframe(frame,subframe,fp)){
|
|
LOG_D(MAC,"frame %d, subframe %d -> CAS\n",frame,subframe);
|
|
common_signal_procedures_fembms(eNB,proc->frame_tx, proc->subframe_tx);
|
|
//return;
|
|
}
|
|
|
|
if((!is_fembms_cas_subframe(frame,subframe,fp)) && (!is_fembms_nonMBSFN_subframe(frame,subframe,fp))){
|
|
if (is_pmch_subframe(frame,subframe,fp)) {
|
|
#ifdef MBMS_NFAPI_SCHEDULER
|
|
pmch_procedures(eNB,proc,0);
|
|
#else
|
|
pmch_procedures(eNB,proc);
|
|
#endif
|
|
} else {
|
|
// this is not a pmch subframe, so generate PSS/SSS/PBCH
|
|
common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear existing ulsch dci allocations before applying info from MAC (this is table
|
|
ul_subframe = pdcch_alloc2ul_subframe (fp, subframe);
|
|
ul_frame = pdcch_alloc2ul_frame (fp, frame, subframe);
|
|
|
|
// clear previous allocation information for all UEs
|
|
for (volatile int i = 0; i < NUMBER_OF_DLSCH_MAX; i++) {
|
|
if (eNB->dlsch[i][0])
|
|
eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
|
|
}
|
|
|
|
/* TODO: check the following test - in the meantime it is put back as it was before */
|
|
//if ((ul_subframe < 10)&&
|
|
// (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here
|
|
if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here
|
|
for (volatile int i=0; i<NUMBER_OF_DLSCH_MAX; i++) {
|
|
if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0;
|
|
|
|
else
|
|
harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe);
|
|
|
|
if (eNB->ulsch[i]) {
|
|
ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
|
|
/* Store first_rb and n_DMRS for correct PHICH generation below.
|
|
* For PHICH generation we need "old" values of last scheduling
|
|
* for this HARQ process. 'generate_eNB_dlsch_params' below will
|
|
* overwrite first_rb and n_DMRS and 'generate_phich_top', done
|
|
* after 'generate_eNB_dlsch_params', would use the "new" values
|
|
* instead of the "old" ones.
|
|
*
|
|
* This has been tested for FDD only, may be wrong for TDD.
|
|
*
|
|
* TODO: maybe we should restructure the code to be sure it
|
|
* is done correctly. The main concern is if the code
|
|
* changes and first_rb and n_DMRS are modified before
|
|
* we reach here, then the PHICH processing will be wrong,
|
|
* using wrong first_rb and n_DMRS values to compute
|
|
* ngroup_PHICH and nseq_PHICH.
|
|
*
|
|
* TODO: check if that works with TDD.
|
|
*/
|
|
ulsch_harq->previous_first_rb = ulsch_harq->first_rb;
|
|
ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS;
|
|
}
|
|
}
|
|
}
|
|
|
|
num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols;
|
|
num_dci = eNB->pdcch_vars[subframe&1].num_dci;
|
|
LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,num_pdcch_symbols);
|
|
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME (VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO, (frame * 10) + subframe);
|
|
|
|
if (num_pdcch_symbols == 0) {
|
|
LOG_E(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols);
|
|
return;
|
|
}
|
|
|
|
if (num_dci > 0)
|
|
LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1);
|
|
|
|
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
|
|
generate_dci_top(num_pdcch_symbols,
|
|
num_dci,
|
|
&eNB->pdcch_vars[subframe&1].dci_alloc[0],
|
|
0,
|
|
AMP,
|
|
fp,
|
|
eNB->common_vars.txdataF,
|
|
subframe);
|
|
num_mdci = eNB->mpdcch_vars[subframe &1].num_dci;
|
|
|
|
if (num_mdci > 0) {
|
|
LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci);
|
|
generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF);
|
|
}
|
|
}
|
|
|
|
if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci);
|
|
|
|
if (do_meas==1) start_meas(&eNB->dlsch_ue_specific);
|
|
|
|
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
|
|
if (is_fembms_pmch_subframe(frame,subframe,fp)) {
|
|
#ifdef MBMS_NFAPI_SCHEDULER
|
|
pmch_procedures(eNB,proc,1);
|
|
return;
|
|
#endif
|
|
}else if(is_fembms_cas_subframe(frame,subframe,fp)){
|
|
common_signal_procedures_fembms(eNB,proc->frame_tx, proc->subframe_tx);
|
|
}
|
|
}
|
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1);
|
|
// Now scan UE specific DLSCH
|
|
LTE_eNB_DLSCH_t *dlsch0,*dlsch1;
|
|
|
|
for (int DLSCH_id=0; DLSCH_id<NUMBER_OF_DLSCH_MAX; DLSCH_id++) {
|
|
dlsch0 = eNB->dlsch[(uint8_t)DLSCH_id][0];
|
|
dlsch1 = eNB->dlsch[(uint8_t)DLSCH_id][1];
|
|
|
|
if ((dlsch0)&&(dlsch0->rnti>0)&&
|
|
#ifdef PHY_TX_THREAD
|
|
(dlsch0->active[subframe] == 1)
|
|
#else
|
|
(dlsch0->active == 1)
|
|
#endif
|
|
) {
|
|
// get harq_pid
|
|
harq_pid = dlsch0->harq_ids[frame%2][subframe];
|
|
//AssertFatal(harq_pid>=0,"harq_pid is negative\n");
|
|
|
|
if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
|
|
|
|
if (dlsch0->ue_type==0)
|
|
LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 DLSCH_id:%d frame:%d subframe:%d rnti:%x [ %1d.%1d.%1d.%1d.%1d.%1d.%1d.%1d\n", harq_pid,DLSCH_id,frame,subframe,dlsch0->rnti,
|
|
dlsch0->harq_ids[frame%2][0],
|
|
dlsch0->harq_ids[frame%2][1],
|
|
dlsch0->harq_ids[frame%2][2],
|
|
dlsch0->harq_ids[frame%2][3],
|
|
dlsch0->harq_ids[frame%2][4],
|
|
dlsch0->harq_ids[frame%2][5],
|
|
dlsch0->harq_ids[frame%2][6],
|
|
dlsch0->harq_ids[frame%2][7]);
|
|
} else {
|
|
if (dlsch_procedures(eNB,
|
|
proc,
|
|
harq_pid,
|
|
dlsch0,
|
|
&eNB->UE_stats[(uint32_t)DLSCH_id])) {
|
|
// if we generate dlsch, we must generate pdsch
|
|
pdsch_procedures(eNB,
|
|
proc,
|
|
harq_pid,
|
|
dlsch0,
|
|
dlsch1);
|
|
}
|
|
}
|
|
} else if ((dlsch0)&&(dlsch0->rnti>0)&&
|
|
#ifdef PHY_TX_THREAD
|
|
(dlsch0->active[subframe] == 0)
|
|
#else
|
|
(dlsch0->active == 0)
|
|
#endif
|
|
) {
|
|
// clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later)
|
|
dlsch0->subframe_tx[subframe]=0;
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0);
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH,1);
|
|
generate_phich_top(eNB,
|
|
proc,
|
|
AMP);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH,0);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+(eNB->CC_id),0);
|
|
|
|
if (do_meas==1) stop_meas(&eNB->dlsch_ue_specific);
|
|
|
|
if (do_meas==1) stop_meas(&eNB->phy_proc_tx);
|
|
}
|
|
|
|
/* This has to be updated with FAPI structures*/
|
|
|
|
void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
|
|
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
|
|
const int subframe = proc->subframe_rx;
|
|
const int frame = proc->frame_rx;
|
|
int i;
|
|
|
|
if (is_srs_occasion_common (fp, frame, subframe)) {
|
|
// Do SRS processing
|
|
// check if there is SRS and we have to use shortened format
|
|
// TODO: check for exceptions in transmission of SRS together with ACK/NACK
|
|
for (i = 0; i < NUMBER_OF_SRS_MAX; i++) {
|
|
if (eNB->soundingrs_ul_config_dedicated[i].active == 1) {
|
|
if (lte_srs_channel_estimation (fp, &eNB->common_vars, &eNB->srs_vars[i], &eNB->soundingrs_ul_config_dedicated[i], subframe, 0 /*eNB_id */ )) {
|
|
LOG_E (PHY, "problem processing SRS\n");
|
|
}
|
|
|
|
eNB->soundingrs_ul_config_dedicated[i].active = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) {
|
|
if ( split73 == SPLIT73_DU ) {
|
|
sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, NULL, frame, subframe, NULL,0,0, rnti, stat);
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&eNB->UL_INFO_mutex);
|
|
nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind;
|
|
nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body;
|
|
assert(sr_ind_body->number_of_srs <= NFAPI_SR_IND_MAX_PDU);
|
|
nfapi_sr_indication_pdu_t *pdu = &sr_ind_body->sr_pdu_list[sr_ind_body->number_of_srs];
|
|
sr_ind->sfn_sf = frame<<4|subframe;
|
|
sr_ind->header.message_id = NFAPI_RX_SR_INDICATION;
|
|
sr_ind_body->tl.tag = NFAPI_SR_INDICATION_BODY_TAG;
|
|
pdu->instance_length = 0; // don't know what to do with this
|
|
// pdu->rx_ue_information.handle = handle;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = rnti;
|
|
int SNRtimes10 = dB_fixed_x10(stat) - 10 * eNB->measurements.n0_pucch_dB;
|
|
LOG_D(PHY,"stat %d n0 %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_dB[0][0], SNRtimes10);
|
|
pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
|
|
|
|
if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0;
|
|
else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255;
|
|
else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5;
|
|
|
|
pdu->ul_cqi_information.channel = 0;
|
|
sr_ind_body->number_of_srs++;
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*
|
|
* Main handler of PUCCH received
|
|
*/
|
|
void
|
|
uci_procedures(PHY_VARS_eNB *eNB,
|
|
L1_rxtx_proc_t *proc)
|
|
//-----------------------------------------------------------------------------
|
|
{
|
|
uint8_t SR_payload = 0;
|
|
uint8_t pucch_b0b1[4][2] = {{0,0},{0,0},{0,0},{0,0}};
|
|
uint8_t harq_ack[4] = {0,0,0,0};
|
|
uint16_t tdd_multiplexing_mask = 0;
|
|
int32_t metric[4] = {0,0,0,0};
|
|
int32_t metric_SR = 0;
|
|
int32_t max_metric = 0;
|
|
const int subframe = proc->subframe_rx;
|
|
const int frame = proc->frame_rx;
|
|
LTE_eNB_UCI *uci = NULL;
|
|
LTE_DL_FRAME_PARMS *fp = &(eNB->frame_parms);
|
|
|
|
calc_pucch_1x_interference(eNB, frame, subframe, 0);
|
|
|
|
for (int i = 0; i < NUMBER_OF_UCI_MAX; i++) {
|
|
uci = &(eNB->uci_vars[i]);
|
|
|
|
if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) {
|
|
if (uci->ue_id > MAX_MOBILES_PER_ENB) {
|
|
LOG_W(PHY, "UCI for UE %d and/or but is not active in MAC\n", uci->ue_id);
|
|
continue;
|
|
}
|
|
LOG_D(PHY,"Frame %d, subframe %d: Running uci procedures (type %d) for %d \n",
|
|
frame,
|
|
subframe,
|
|
uci->type,
|
|
i);
|
|
uci->active = 0;
|
|
|
|
// Null out PUCCH PRBs for noise measurement
|
|
switch (fp->N_RB_UL) {
|
|
case 6:
|
|
eNB->rb_mask_ul[0] |= (0x1 | (1 << 5)); // position 5
|
|
break;
|
|
|
|
case 15:
|
|
eNB->rb_mask_ul[0] |= (0x1 | (1 << 14)); // position 14
|
|
break;
|
|
|
|
case 25:
|
|
eNB->rb_mask_ul[0] |= (0x1 | (1 << 24)); // position 24
|
|
break;
|
|
|
|
case 50:
|
|
eNB->rb_mask_ul[0] |= 0x1;
|
|
eNB->rb_mask_ul[1] |= (1 << 17); // position 49 (49-32)
|
|
break;
|
|
|
|
case 75:
|
|
eNB->rb_mask_ul[0] |= 0x1;
|
|
eNB->rb_mask_ul[2] |= (1 << 10); // position 74 (74-64)
|
|
break;
|
|
|
|
case 100:
|
|
eNB->rb_mask_ul[0] |= 0x1;
|
|
eNB->rb_mask_ul[3] |= (1 << 3); // position 99 (99-96)
|
|
break;
|
|
|
|
default:
|
|
LOG_E(PHY,"Unknown number for N_RB_UL %d\n", fp->N_RB_UL);
|
|
break;
|
|
}
|
|
|
|
SR_payload = 0;
|
|
|
|
switch (uci->type) {
|
|
case SR:
|
|
case HARQ_SR: {
|
|
int pucch1_thres = (uci->ue_type == 0) ? eNB->pucch1_DTX_threshold : eNB->pucch1_DTX_threshold_emtc[0];
|
|
metric_SR = rx_pucch(eNB,
|
|
uci->pucch_fmt,
|
|
i,//uci->ue_id,
|
|
uci->n_pucch_1_0_sr[0],
|
|
0, // n2_pucch
|
|
uci->srs_active, // shortened format
|
|
&SR_payload,
|
|
frame,
|
|
subframe,
|
|
pucch1_thres,
|
|
uci->ue_type
|
|
);
|
|
LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR is %d (uci.type %d SR n1pucch is %d)\n",
|
|
eNB->Mod_id,
|
|
uci->rnti,
|
|
frame,
|
|
subframe,
|
|
SR_payload,
|
|
uci->type,
|
|
uci->n_pucch_1_0_sr[0]);
|
|
|
|
if (uci->type == SR) {
|
|
if (SR_payload == 1) {
|
|
fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR);
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
case HARQ: {
|
|
int pucch1ab_thres = (uci->ue_type == 0) ? eNB->pucch1ab_DTX_threshold : eNB->pucch1ab_DTX_threshold_emtc[0];
|
|
|
|
if (fp->frame_type == FDD) {
|
|
LOG_D(PHY,"Frame %d Subframe %d Demodulating PUCCH (UCI %d) for ACK/NAK (uci->pucch_fmt %d,uci->type %d.uci->frame %d, uci->subframe %d): n1_pucch0 %d SR_payload %d\n",
|
|
frame,subframe,i,
|
|
uci->pucch_fmt,uci->type,
|
|
uci->frame,uci->subframe,uci->n_pucch_1[0][0],
|
|
SR_payload);
|
|
metric[0] = rx_pucch(eNB,
|
|
uci->pucch_fmt,
|
|
uci->ue_id,
|
|
uci->n_pucch_1[0][0],
|
|
0, //n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[0],
|
|
frame,
|
|
subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
|
|
//dump_ulsch(eNB,frame,subframe,0,0); exit(-1);
|
|
|
|
/* cancel SR detection if reception on n1_pucch0 is better than on SR PUCCH resource index, otherwise send it up to MAC */
|
|
if (uci->type==HARQ_SR && metric[0] > metric_SR) SR_payload = 0;
|
|
else if (SR_payload == 1) fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR);
|
|
|
|
if (uci->type==HARQ_SR && metric[0] <= metric_SR) {
|
|
/* when transmitting ACK/NACK on SR PUCCH resource index, SR payload is always 1 */
|
|
SR_payload = 1;
|
|
metric[0]=rx_pucch(eNB,
|
|
uci->pucch_fmt,
|
|
uci->ue_id,
|
|
uci->n_pucch_1_0_sr[0],
|
|
0, //n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[0],
|
|
frame,
|
|
subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
}
|
|
|
|
LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n",
|
|
eNB->Mod_id,
|
|
uci->rnti,
|
|
frame,subframe,
|
|
pucch_b0b1[0][0],metric[0]);
|
|
uci->stat = metric[0];
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,pucch_b0b1[0],0,0xffff);
|
|
} else { // frame_type == TDD
|
|
LOG_D(PHY,"Frame %d Subframe %d Demodulating PUCCH (UCI %d) for ACK/NAK (uci->pucch_fmt %d,uci->type %d.uci->frame %d, uci->subframe %d): n1_pucch0 %d SR_payload %d\n",
|
|
frame,subframe,i,
|
|
uci->pucch_fmt,uci->type,
|
|
uci->frame,uci->subframe,uci->n_pucch_1[0][0],
|
|
SR_payload);
|
|
#if 1
|
|
metric[0] = rx_pucch(eNB,
|
|
uci->pucch_fmt,
|
|
uci->ue_id,
|
|
uci->n_pucch_1[0][0],
|
|
0, //n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[0],
|
|
frame,
|
|
subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
|
|
if (uci->type==HARQ_SR && metric[0] > metric_SR) SR_payload = 0;
|
|
else if (SR_payload == 1) fill_sr_indication(i, eNB,uci->rnti,frame,subframe,metric_SR);
|
|
|
|
if (uci->type==HARQ_SR && metric[0] <= metric_SR) {
|
|
SR_payload = 1;
|
|
metric[0] = rx_pucch(eNB,
|
|
pucch_format1b,
|
|
uci->ue_id,
|
|
uci->n_pucch_1_0_sr[0],
|
|
0, //n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[0],
|
|
frame,
|
|
subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
}
|
|
|
|
#else
|
|
|
|
// if SR was detected, use the n1_pucch from SR
|
|
if (SR_payload==1) {
|
|
#ifdef DEBUG_PHY_PROC
|
|
LOG_D (PHY, "[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d with SR\n", eNB->Mod_id,
|
|
eNB->dlsch[UE_id][0]->rnti, frame, subframe, n1_pucch0, n1_pucch1, n1_pucch2, n1_pucch3, format);
|
|
#endif
|
|
metric[0] = rx_pucch (eNB, pucch_format1b, i, uci->n_pucch_1_0_sr[0], 0, //n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[0], frame, subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
} else { //using assigned pucch resources
|
|
#ifdef DEBUG_PHY_PROC
|
|
LOG_D (PHY, "[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK M=%d (%d,%d,%d,%d) format %d\n", eNB->Mod_id,
|
|
eNB->dlsch[UE_id][0]->rnti,
|
|
frame, subframe, uci->num_pucch_resources, uci->n_pucch_1[res][0], uci->n_pucch_1[res][1], uci->n_pucch_1[res][2], uci->n_pucch_1[res][3], uci->pucch_fmt);
|
|
#endif
|
|
|
|
for (res = 0; res < uci->num_pucch_resources; res++)
|
|
metric[res] = rx_pucch (eNB, uci->pucch_fmt, i, uci->n_pucch_1[res][0], 0, // n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[res], frame, subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
|
|
for (res=0; res<uci->num_pucch_resources; res++)
|
|
metric[res] = rx_pucch(eNB,
|
|
uci->pucch_fmt,
|
|
i,
|
|
uci->n_pucch_1[res][0],
|
|
0, // n2_pucch
|
|
uci->srs_active, // shortened format
|
|
pucch_b0b1[res],
|
|
frame,
|
|
subframe,
|
|
pucch1ab_thres,
|
|
uci->ue_type
|
|
);
|
|
}
|
|
|
|
#ifdef DEBUG_PHY_PROC
|
|
LOG_D(PHY,"RNTI %x type %d SR_payload %d Frame %d Subframe %d pucch_b0b1[0][0] %d pucch_b0b1[0][1] %d pucch_b0b1[1][0] %d pucch_b0b1[1][1] %d \n",
|
|
uci->rnti,uci->type,SR_payload,frame,subframe,pucch_b0b1[0][0],pucch_b0b1[0][1],pucch_b0b1[1][0],pucch_b0b1[1][1]);
|
|
#endif
|
|
#endif
|
|
|
|
if (SR_payload == 1) { // this implements Table 7.3.1 from 36.213
|
|
if (pucch_b0b1[0][0] == 4) { // there isn't a likely transmission
|
|
harq_ack[0] = 4; // DTX
|
|
} else if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1) { // 1/4/7 ACKs
|
|
harq_ack[0] = 1;
|
|
} else if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] != 1) { // 2/5/8 ACKs
|
|
harq_ack[0] = 2;
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] == 1) { // 3/6/9 ACKs
|
|
harq_ack[0] = 3;
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1) { // 0 ACKs, or at least one DL assignment missed
|
|
harq_ack[0] = 0;
|
|
}
|
|
|
|
uci->stat = metric[0];
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,2,0xffff); // special_bundling mode
|
|
} else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==2)) { // multiplexing + no SR, implement Table 10.1.3-5 (Rel14) for multiplexing with M=2
|
|
if (pucch_b0b1[0][0] == 4 ||
|
|
pucch_b0b1[1][0] == 4) { // there isn't a likely transmission
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
} else {
|
|
if (metric[1]>metric[0]) {
|
|
if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x3;
|
|
} else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x2;
|
|
} else {
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 4; // DTX
|
|
}
|
|
} else {
|
|
if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x1;
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1) {
|
|
harq_ack[0] = 2; // NACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
} else {
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 4; // DTX
|
|
}
|
|
}
|
|
}
|
|
|
|
uci->stat = max(metric[0],metric[1]);
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode
|
|
} //else if ((uci->tdd_bundling == 0) && (res==2))
|
|
else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==3)) { // multiplexing + no SR, implement Table 10.1.3-6 (Rel14) for multiplexing with M=3
|
|
if (harq_ack[0] == 4 ||
|
|
harq_ack[1] == 4 ||
|
|
harq_ack[2] == 4) { // there isn't a likely transmission
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
max_metric = 0;
|
|
} else {
|
|
max_metric = max(metric[0],max(metric[1],metric[2]));
|
|
|
|
if (metric[0]==max_metric) {
|
|
if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x1;
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1) {
|
|
harq_ack[0] = 2; // NACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
} else {
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 4; // DTX
|
|
harq_ack[2] = 4; // DTX
|
|
}
|
|
} // if (metric[0]==max_metric) {
|
|
else if (metric[1]==max_metric) {
|
|
if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x3;
|
|
} else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x2;
|
|
} else {
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 4; // DTX
|
|
harq_ack[2] = 4; // DTX
|
|
}
|
|
} // if (metric[1]==max_metric) {
|
|
else {
|
|
if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x7;
|
|
} else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x5;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x6;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x4;
|
|
}
|
|
}
|
|
|
|
uci->stat = max_metric;
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode
|
|
}
|
|
} //else if ((uci->tdd_bundling == 0) && (res==3))
|
|
else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==4)) { // multiplexing + no SR, implement Table 10.1.3-7 (Rel14) for multiplexing with M=4
|
|
if (pucch_b0b1[0][0] == 4 ||
|
|
pucch_b0b1[1][0] == 4 ||
|
|
pucch_b0b1[2][0] == 4 ||
|
|
pucch_b0b1[3][0] == 4) { // there isn't a likely transmission
|
|
harq_ack[0] = 4; // DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
max_metric = 0;
|
|
} else {
|
|
max_metric = max(metric[0],max(metric[1],max(metric[2],metric[3])));
|
|
|
|
if (metric[0]==max_metric) {
|
|
if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] != 1) {
|
|
harq_ack[0] = 2; // NACK
|
|
harq_ack[1] = 4; // DTX
|
|
harq_ack[2] = 4; // DTX
|
|
harq_ack[3] = 4; // DTX
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x9;
|
|
} else if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x1;
|
|
} else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1) {
|
|
harq_ack[0] = 2; // NACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
}
|
|
} else if (metric[1]==max_metric) {
|
|
if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0xF;
|
|
} else if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1 ) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x3;
|
|
} else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] != 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0xE;
|
|
} else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x2;
|
|
}
|
|
} else if (metric[2]==max_metric) {
|
|
if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x7;
|
|
} else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 6; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x5;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) {
|
|
harq_ack[0] = 4; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 4; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x6;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 4; // NACK/DTX
|
|
harq_ack[1] = 4; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 4; // NACK/DTX
|
|
tdd_multiplexing_mask = 0x4;
|
|
}
|
|
} else { // max_metric[3]=max_metric
|
|
if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1) {
|
|
harq_ack[0] = 1; // ACK
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0xD;
|
|
} else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 1; // ACK
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0xA;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 1; // ACK
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0xC;
|
|
} else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) {
|
|
harq_ack[0] = 6; // NACK/DTX
|
|
harq_ack[1] = 6; // NACK/DTX
|
|
harq_ack[2] = 6; // NACK/DTX
|
|
harq_ack[3] = 1; // ACK
|
|
tdd_multiplexing_mask = 0x8;
|
|
}
|
|
}
|
|
}
|
|
|
|
uci->stat = max_metric;
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode
|
|
} // else if ((uci->tdd_bundling == 0) && (res==4))
|
|
else { // bundling
|
|
harq_ack[0] = pucch_b0b1[0][0];
|
|
harq_ack[1] = pucch_b0b1[0][1];
|
|
uci->stat = metric[0];
|
|
LOG_D(PHY,"bundling: (%d,%d), metric %d\n",harq_ack[0],harq_ack[1],uci->stat);
|
|
fill_uci_harq_indication(i, eNB,uci,frame,subframe,harq_ack,0,0xffff); // special_bundling mode
|
|
}
|
|
|
|
#ifdef DEBUG_PHY_PROC
|
|
LOG_D (PHY, "[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, (%d,%d)\n", eNB->Mod_id,
|
|
eNB->dlsch[DLSCH_id][0]->rnti, frame, subframe, metric0, metric1, pucch_b0b1[0], pucch_b0b1[1]);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
AssertFatal (1 == 0, "Unsupported UCI type %d\n", uci->type);
|
|
break;
|
|
}
|
|
|
|
if (SR_payload == 1) {
|
|
LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n", eNB->Mod_id, uci->rnti, frame, subframe);
|
|
|
|
if (eNB->first_sr[uci->ue_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4
|
|
eNB->first_sr[uci->ue_id] = 0;
|
|
eNB->dlsch[uci->ue_id][0]->harq_processes[0]->round = 0;
|
|
eNB->dlsch[uci->ue_id][0]->harq_processes[0]->status = SCH_IDLE;
|
|
LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[uci->ue_id]->rnti, frame, subframe);
|
|
}
|
|
}
|
|
}
|
|
} // end if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) {
|
|
} // end loop for (int i = 0; i < NUMBER_OF_UCI_MAX; i++) {
|
|
}
|
|
|
|
void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req) {
|
|
turboDecode_t * rdata=(turboDecode_t *) NotifiedFifoData(req);
|
|
|
|
LTE_eNB_ULSCH_t *ulsch = rdata->eNB->ulsch[rdata->UEid];
|
|
LTE_UL_eNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
|
|
PHY_VARS_eNB *eNB=rdata->eNB;
|
|
|
|
bool decodeSucess=rdata->decodeIterations <= rdata->maxIterations;
|
|
ulsch_harq->processedSegments++;
|
|
LOG_D(PHY, "processing result of segment: %d, ue %d, processed %d/%d\n",
|
|
rdata->segment_r, rdata->UEid, ulsch_harq->processedSegments, rdata->nbSegments);
|
|
proc->nbDecode--;
|
|
LOG_D(PHY,"remain to decoded in subframe: %d\n", proc->nbDecode);
|
|
if (decodeSucess) {
|
|
int Fbytes=(rdata->segment_r==0) ? rdata->Fbits>>3 : 0;
|
|
int sz=(rdata->Kr>>3) - Fbytes - ((ulsch_harq->C>1)?3:0);
|
|
memcpy(ulsch_harq->decodedBytes+rdata->offset,
|
|
rdata->decoded_bytes+Fbytes,
|
|
sz);
|
|
} else {
|
|
if ( rdata->nbSegments != ulsch_harq->processedSegments ) {
|
|
int nb=abortTpool(proc->threadPool, req->key);
|
|
nb+=abortNotifiedFIFO(proc->respDecode, req->key);
|
|
proc->nbDecode-=nb;
|
|
LOG_D(PHY,"uplink segment error %d/%d, aborted %d segments\n",rdata->segment_r,rdata->nbSegments, nb);
|
|
AssertFatal(ulsch_harq->processedSegments+nb == rdata->nbSegments,"processed: %d, aborted: %d, total %d\n",
|
|
ulsch_harq->processedSegments, nb, rdata->nbSegments);
|
|
ulsch_harq->processedSegments=rdata->nbSegments;
|
|
}
|
|
}
|
|
|
|
// if this UE segments are all done
|
|
if ( rdata->nbSegments == ulsch_harq->processedSegments) {
|
|
//compute the expected ULSCH RX power (for the stats)
|
|
int i=rdata->UEid;
|
|
ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,rdata->harq_pid, 0); // 0 means bw_factor is not considered
|
|
if (RC.mac != NULL) { /* ulsim does not use RC.mac context. */
|
|
if (ulsch_harq->cqi_crc_status == 1) {
|
|
fill_ulsch_cqi_indication(eNB,rdata->frame,rdata->subframe,ulsch_harq,ulsch->rnti);
|
|
RC.mac[eNB->Mod_id]->UE_info.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << rdata->subframe));
|
|
} else {
|
|
if(RC.mac[eNB->Mod_id]->UE_info.UE_sched_ctrl[i].cqi_req_flag & (1 << rdata->subframe) ) {
|
|
RC.mac[eNB->Mod_id]->UE_info.UE_sched_ctrl[i].cqi_req_flag &= (~(1 << rdata->subframe));
|
|
RC.mac[eNB->Mod_id]->UE_info.UE_sched_ctrl[i].cqi_req_timer=30;
|
|
LOG_D(PHY,"Frame %d,Subframe %d, We're supposed to get a cqi here. Set cqi_req_timer to 30.\n",rdata->frame,rdata->subframe);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!decodeSucess) {
|
|
T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(rdata->frame), T_INT(rdata->subframe), T_INT(ulsch->rnti),
|
|
T_INT(rdata->harq_pid));
|
|
fill_crc_indication(eNB,i,rdata->frame,rdata->subframe,1); // indicate NAK to MAC
|
|
fill_rx_indication(eNB,i,rdata->frame,rdata->subframe); // indicate SDU to MAC
|
|
LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n",
|
|
eNB->Mod_id,rdata->harq_pid,
|
|
rdata->frame,rdata->subframe, i,
|
|
ulsch_harq->round,
|
|
ulsch->Mlimit,
|
|
ulsch_harq->o_ACK[0],
|
|
ulsch_harq->o_ACK[1]);
|
|
|
|
if (ulsch_harq->round >= 3) {
|
|
ulsch_harq->status = SCH_IDLE;
|
|
ulsch_harq->handled = 0;
|
|
ulsch->harq_mask &= ~(1 << rdata->harq_pid);
|
|
ulsch_harq->round = 0;
|
|
}
|
|
/* Mark the HARQ process to release it later if max transmission reached
|
|
* (see below).
|
|
* MAC does not send the max transmission count, we have to deal with it
|
|
* locally in PHY.
|
|
*/
|
|
ulsch_harq->handled = 1;
|
|
} // ulsch in error
|
|
else if(ulsch_harq->repetition_number == ulsch_harq->total_number_of_repetitions){
|
|
fill_crc_indication(eNB,i,rdata->frame,rdata->subframe,0); // indicate ACK to MAC
|
|
fill_rx_indication(eNB,i,rdata->frame,rdata->subframe); // indicate SDU to MAC
|
|
ulsch_harq->status = SCH_IDLE;
|
|
ulsch->harq_mask &= ~(1 << rdata->harq_pid);
|
|
for (int j=0;j<NUMBER_OF_ULSCH_MAX;j++)
|
|
if (eNB->ulsch_stats[j].rnti == ulsch->rnti) {
|
|
eNB->ulsch_stats[j].total_bytes_rx+=ulsch_harq->TBS;
|
|
for (int aa=0;aa<eNB->frame_parms.nb_antennas_rx;aa++) {
|
|
eNB->ulsch_stats[j].ulsch_power[aa] = dB_fixed_x10(eNB->pusch_vars[rdata->UEid]->ulsch_power[aa]);
|
|
eNB->ulsch_stats[j].ulsch_noise_power[aa] = dB_fixed_x10(eNB->pusch_vars[rdata->UEid]->ulsch_noise_power[aa]);
|
|
}
|
|
break;
|
|
}
|
|
T (T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(rdata->frame), T_INT(rdata->subframe), T_INT(ulsch->rnti),
|
|
T_INT(rdata->harq_pid));
|
|
} // ulsch not in error
|
|
|
|
if (ulsch_harq->O_ACK>0)
|
|
fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,rdata->frame,rdata->subframe,ulsch->bundling);
|
|
}
|
|
}
|
|
|
|
void pusch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
|
|
uint32_t i;
|
|
uint32_t harq_pid;
|
|
uint8_t nPRS;
|
|
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
|
|
LTE_eNB_ULSCH_t *ulsch;
|
|
LTE_UL_eNB_HARQ_t *ulsch_harq;
|
|
const int subframe = proc->subframe_rx;
|
|
const int frame = proc->frame_rx;
|
|
uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe);
|
|
|
|
for (i = 0; i < NUMBER_OF_ULSCH_MAX; i++) {
|
|
ulsch = eNB->ulsch[i];
|
|
if (!ulsch) continue;
|
|
|
|
if (ulsch->ue_type > 0) harq_pid = 0;
|
|
else harq_pid=harq_pid0;
|
|
|
|
ulsch_harq = ulsch->harq_processes[harq_pid];
|
|
|
|
if (ulsch->rnti>0) LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n",
|
|
i, harq_pid, frame,subframe,i,ulsch->rnti,
|
|
ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled);
|
|
|
|
if ((ulsch->rnti>0) &&
|
|
(ulsch_harq->status == ACTIVE) &&
|
|
((ulsch_harq->frame == frame) || (ulsch_harq->repetition_number >1) ) &&
|
|
((ulsch_harq->subframe == subframe) || (ulsch_harq->repetition_number >1) ) &&
|
|
(ulsch_harq->handled == 0)) {
|
|
// UE has ULSCH scheduling
|
|
for (int rb=0;
|
|
rb<=ulsch_harq->nb_rb;
|
|
rb++) {
|
|
int rb2 = rb+ulsch_harq->first_rb;
|
|
eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
|
|
}
|
|
|
|
LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i);
|
|
nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1];
|
|
ulsch->cyclicShift = (ulsch_harq->n_DMRS2 +
|
|
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift +
|
|
nPRS)%12;
|
|
AssertFatal(ulsch_harq->TBS>0,"illegal TBS %d\n",ulsch_harq->TBS);
|
|
LOG_D(PHY,
|
|
"[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n",
|
|
eNB->Mod_id,harq_pid,frame,subframe,
|
|
ulsch_harq->dci_alloc,
|
|
ulsch_harq->rar_alloc,
|
|
ulsch_harq->round,
|
|
ulsch_harq->first_rb,
|
|
ulsch_harq->nb_rb,
|
|
ulsch_harq->Qm,
|
|
ulsch_harq->TBS,
|
|
ulsch_harq->rvidx,
|
|
ulsch->cyclicShift,
|
|
ulsch_harq->n_DMRS2,
|
|
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift,
|
|
ulsch_harq->O_ACK,
|
|
ulsch->beta_offset_cqi_times8);
|
|
start_meas(&eNB->ulsch_demodulation_stats);
|
|
rx_ulsch(eNB,proc, i);
|
|
stop_meas(&eNB->ulsch_demodulation_stats);
|
|
start_meas(&eNB->ulsch_decoding_stats);
|
|
ulsch_decoding(eNB,proc,
|
|
i,
|
|
0, // control_only_flag
|
|
ulsch_harq->V_UL_DAI,
|
|
ulsch_harq->nb_rb>20 ? 1 : 0);
|
|
stop_meas(&eNB->ulsch_decoding_stats);
|
|
/*
|
|
int ulsch_id=-1;
|
|
for (ulsch_id=0;ulsch_id<NUMBER_OF_ULSCH_MAX;ulsch_id++)
|
|
if (ulsch->rnti == eNB->ulsch_stats[ulsch_id].rnti) break;
|
|
AssertFatal(ulsch_id>=0,"no ulsch_id found\n");
|
|
|
|
if (eNB->ulsch_stats[ulsch_id].round_trials[0]>100) {
|
|
dump_ulsch(eNB,frame,subframe,i,ulsch_harq->round);
|
|
AssertFatal(1==0,"exiting\n");
|
|
}
|
|
*/
|
|
}
|
|
else if ((ulsch) &&
|
|
(ulsch->rnti>0) &&
|
|
(ulsch_harq->status == ACTIVE) &&
|
|
(ulsch_harq->frame == frame) &&
|
|
(ulsch_harq->subframe == subframe) &&
|
|
(ulsch_harq->handled == 1)) {
|
|
// this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that
|
|
ulsch_harq->status = SCH_IDLE;
|
|
ulsch_harq->handled = 0;
|
|
ulsch->harq_mask &= ~(1 << harq_pid);
|
|
LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask);
|
|
}
|
|
} // for (i=0; i<NUMBER_OF_ULSCH_MAX; i++)
|
|
|
|
while (proc->nbDecode > 0) {
|
|
notifiedFIFO_elt_t *req=pullTpool(proc->respDecode, proc->threadPool);
|
|
postDecode(proc, req);
|
|
delNotifiedFIFO_elt(req);
|
|
}
|
|
}
|
|
|
|
extern int oai_exit;
|
|
|
|
extern void *td_thread (void *);
|
|
|
|
void init_td_thread(PHY_VARS_eNB *eNB) {
|
|
/*
|
|
L1_proc_t *proc = &eNB->proc;
|
|
proc->tdp.eNB = eNB;
|
|
proc->instance_cnt_td = -1;
|
|
threadCreate(&proc->pthread_td, td_thread, (void *)&proc->tdp, "TD", -1, OAI_PRIORITY_RT);
|
|
*/
|
|
}
|
|
|
|
void kill_td_thread(PHY_VARS_eNB *eNB) {
|
|
/*
|
|
L1_proc_t *proc = &eNB->proc;
|
|
proc->instance_cnt_td = 0;
|
|
pthread_cond_signal(&proc->cond_td);
|
|
pthread_join(proc->pthread_td, NULL);
|
|
pthread_mutex_destroy( &proc->mutex_td );
|
|
pthread_cond_destroy( &proc->cond_td );
|
|
*/
|
|
}
|
|
|
|
extern void *te_thread (void *);
|
|
|
|
void init_te_thread(PHY_VARS_eNB *eNB) {
|
|
/*
|
|
L1_proc_t *proc = &eNB->proc;
|
|
|
|
for(int i=0; i<3 ; i++) {
|
|
proc->tep[i].eNB = eNB;
|
|
proc->tep[i].instance_cnt_te = -1;
|
|
LOG_I(PHY,"Creating te_thread %d\n",i);
|
|
char txt[128];
|
|
sprintf(txt,"TE_%d", i);
|
|
threadCreate(&proc->tep[i].pthread_te, te_thread, (void *)&proc->tep[i], txt, -1, OAI_PRIORITY_RT);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void kill_te_thread(PHY_VARS_eNB *eNB) {
|
|
/*
|
|
L1_proc_t *proc = &eNB->proc;
|
|
|
|
for(int i=0; i<3 ; i++) {
|
|
proc->tep[i].instance_cnt_te = 0;
|
|
pthread_cond_signal(&proc->tep[i].cond_te);
|
|
pthread_join(proc->tep[i].pthread_te, NULL);
|
|
pthread_mutex_destroy( &proc->tep[i].mutex_te);
|
|
pthread_cond_destroy( &proc->tep[i].cond_te);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void fill_rx_indication(PHY_VARS_eNB *eNB,
|
|
int ULSCH_id,
|
|
int frame,
|
|
int subframe) {
|
|
nfapi_rx_indication_pdu_t *pdu;
|
|
int timing_advance_update;
|
|
int sync_pos;
|
|
uint32_t harq_pid;
|
|
|
|
if (eNB->ulsch[ULSCH_id]->ue_type > 0) harq_pid = 0;
|
|
else {
|
|
harq_pid = subframe2harq_pid (&eNB->frame_parms,
|
|
frame, subframe);
|
|
}
|
|
|
|
pthread_mutex_lock(&eNB->UL_INFO_mutex);
|
|
eNB->UL_INFO.rx_ind.sfn_sf = frame<<4| subframe;
|
|
eNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG;
|
|
assert(eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus <= NFAPI_RX_IND_MAX_PDU);
|
|
pdu = &eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus];
|
|
// pdu->rx_ue_information.handle = eNB->ulsch[ULSCH_id]->handle;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = eNB->ulsch[ULSCH_id]->rnti;
|
|
pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG;
|
|
pdu->rx_indication_rel8.length = eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->TBS>>3;
|
|
pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation
|
|
assert(pdu->rx_indication_rel8.length <= NFAPI_RX_IND_DATA_MAX);
|
|
memcpy(pdu->rx_ind_data,
|
|
eNB->ulsch[ULSCH_id]->harq_processes[harq_pid]->decodedBytes,
|
|
pdu->rx_indication_rel8.length);
|
|
|
|
// estimate timing advance for MAC
|
|
sync_pos = lte_est_timing_advance_pusch(&eNB->frame_parms, eNB->pusch_vars[ULSCH_id]->drs_ch_estimates_time);
|
|
timing_advance_update = sync_pos;
|
|
|
|
for (int i=0;i<NUMBER_OF_SCH_STATS_MAX;i++)
|
|
if (eNB->ulsch_stats[i].rnti == eNB->ulsch[ULSCH_id]->rnti)
|
|
eNB->ulsch_stats[i].timing_offset = sync_pos;
|
|
// if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,ULSCH_id); exit(-1);}
|
|
// if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,ULSCH_id); exit(-1);}
|
|
switch (eNB->frame_parms.N_RB_DL) {
|
|
case 6: /* nothing to do */
|
|
break;
|
|
|
|
case 15:
|
|
timing_advance_update /= 2;
|
|
break;
|
|
|
|
case 25:
|
|
timing_advance_update /= 4;
|
|
break;
|
|
|
|
case 50:
|
|
timing_advance_update /= 8;
|
|
break;
|
|
|
|
case 75:
|
|
timing_advance_update /= 12;
|
|
break;
|
|
|
|
case 100:
|
|
timing_advance_update /= 16;
|
|
break;
|
|
|
|
default:
|
|
abort ();
|
|
}
|
|
|
|
// put timing advance command in 0..63 range
|
|
timing_advance_update += 31;
|
|
|
|
if (timing_advance_update < 0)
|
|
timing_advance_update = 0;
|
|
|
|
if (timing_advance_update > 63)
|
|
timing_advance_update = 63;
|
|
|
|
pdu->rx_indication_rel8.timing_advance = timing_advance_update;
|
|
// estimate UL_CQI for MAC
|
|
int total_power=0, avg_noise_power=0;
|
|
for (int i=0;i<eNB->frame_parms.nb_antennas_rx;i++) {
|
|
total_power+=(eNB->pusch_vars[ULSCH_id]->ulsch_power[i]);
|
|
avg_noise_power+=(eNB->pusch_vars[ULSCH_id]->ulsch_noise_power[i])/eNB->frame_parms.nb_antennas_rx;
|
|
}
|
|
int SNRtimes10 = dB_fixed_x10(total_power) -
|
|
dB_fixed_x10(avg_noise_power);
|
|
|
|
if (SNRtimes10 < -640)
|
|
pdu->rx_indication_rel8.ul_cqi = 0;
|
|
else if (SNRtimes10 > 635)
|
|
pdu->rx_indication_rel8.ul_cqi = 255;
|
|
else
|
|
pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5;
|
|
|
|
LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d,%d,%d), timing_advance %d (update %d,sync_pos %d)\n",
|
|
harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,dB_fixed_x10(total_power),dB_fixed_x10(avg_noise_power),pdu->rx_indication_rel8.timing_advance,timing_advance_update,sync_pos);
|
|
for (int i=0;i<eNB->frame_parms.nb_antennas_rx;i++)
|
|
LOG_D(PHY,"antenna %d: ulsch_power %d, noise_power %d\n",i,dB_fixed_x10(eNB->pusch_vars[ULSCH_id]->ulsch_power[i]),dB_fixed_x10(eNB->pusch_vars[ULSCH_id]->ulsch_noise_power[i]));
|
|
|
|
eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++;
|
|
eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe;
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*
|
|
* Release the harq process if its round is >= 'after_rounds'
|
|
*/
|
|
static void do_release_harq(PHY_VARS_eNB *eNB,
|
|
int DLSCH_id,
|
|
int tb,
|
|
uint16_t frame,
|
|
uint8_t subframe,
|
|
uint16_t mask,
|
|
int after_rounds)
|
|
//-----------------------------------------------------------------------------
|
|
{
|
|
LTE_eNB_DLSCH_t *dlsch0 = NULL;
|
|
LTE_eNB_DLSCH_t *dlsch1 = NULL;
|
|
LTE_DL_eNB_HARQ_t *dlsch0_harq = NULL;
|
|
LTE_DL_eNB_HARQ_t *dlsch1_harq = NULL;
|
|
int harq_pid;
|
|
int subframe_tx;
|
|
int frame_tx;
|
|
AssertFatal(DLSCH_id != -1, "No existing dlsch context\n");
|
|
AssertFatal(DLSCH_id < NUMBER_OF_DLSCH_MAX, "Returned DLSCH_id %d >= %d (NUMBER_OF_DLSCH_MAX)\n", DLSCH_id, NUMBER_OF_DLSCH_MAX);
|
|
dlsch0 = eNB->dlsch[DLSCH_id][0];
|
|
dlsch1 = eNB->dlsch[DLSCH_id][1];
|
|
|
|
if (eNB->frame_parms.frame_type == FDD) {
|
|
subframe_tx = (subframe + 6) % 10;
|
|
frame_tx = ul_ACK_subframe2_dl_frame(&eNB->frame_parms,
|
|
frame,
|
|
subframe,
|
|
subframe_tx);
|
|
harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
|
|
|
|
if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
|
|
LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
|
|
dlsch0_harq = dlsch0->harq_processes[harq_pid];
|
|
dlsch1_harq = dlsch1->harq_processes[harq_pid];
|
|
AssertFatal(dlsch0_harq != NULL, "dlsch0_harq is null\n");
|
|
#if T_TRACER
|
|
|
|
if (after_rounds != -1) {
|
|
T(T_ENB_PHY_DLSCH_UE_NACK,
|
|
T_INT(0),
|
|
T_INT(frame),
|
|
T_INT(subframe),
|
|
T_INT(dlsch0->rnti),
|
|
T_INT(harq_pid));
|
|
} else {
|
|
T(T_ENB_PHY_DLSCH_UE_ACK,
|
|
T_INT(0),
|
|
T_INT(frame),
|
|
T_INT(subframe),
|
|
T_INT(dlsch0->rnti),
|
|
T_INT(harq_pid));
|
|
}
|
|
|
|
#endif
|
|
|
|
if (dlsch0_harq->round >= after_rounds) {
|
|
dlsch0_harq->status = SCH_IDLE;
|
|
dlsch0->harq_mask &= ~(1 << harq_pid);
|
|
}
|
|
} else {
|
|
/* Release all processes in the bundle that was acked, based on mask */
|
|
/* This is at most 4 for multiplexing and 9 for bundling/special bundling */
|
|
int M = ul_ACK_subframe2_M(&eNB->frame_parms, subframe);
|
|
|
|
for (int m=0; m < M; m++) {
|
|
subframe_tx = ul_ACK_subframe2_dl_subframe(&eNB->frame_parms,
|
|
subframe,
|
|
m);
|
|
frame_tx = ul_ACK_subframe2_dl_frame(&eNB->frame_parms,
|
|
frame,
|
|
subframe,
|
|
subframe_tx);
|
|
|
|
if (((1 << m) & mask) > 0) {
|
|
harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
|
|
|
|
if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
|
|
LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
|
|
dlsch0_harq = dlsch0->harq_processes[harq_pid];
|
|
dlsch1_harq = dlsch1->harq_processes[harq_pid];
|
|
AssertFatal(dlsch0_harq != NULL, "Dlsch0_harq is null\n");
|
|
#if T_TRACER
|
|
|
|
if (after_rounds != -1) {
|
|
T(T_ENB_PHY_DLSCH_UE_NACK,
|
|
T_INT(0),
|
|
T_INT(frame),
|
|
T_INT(subframe),
|
|
T_INT(dlsch0->rnti),
|
|
T_INT(harq_pid));
|
|
} else {
|
|
T(T_ENB_PHY_DLSCH_UE_ACK,
|
|
T_INT(0),
|
|
T_INT(frame),
|
|
T_INT(subframe),
|
|
T_INT(dlsch0->rnti),
|
|
T_INT(harq_pid));
|
|
}
|
|
|
|
#endif
|
|
|
|
if (dlsch0_harq->round >= after_rounds) {
|
|
dlsch0_harq->status = SCH_IDLE;
|
|
|
|
if ((dlsch1_harq == NULL) || ((dlsch1_harq != NULL) && (dlsch1_harq->status == SCH_IDLE))) {
|
|
dlsch0->harq_mask &= ~(1 << harq_pid);
|
|
}
|
|
}
|
|
} // end if (((1 << m) & mask) > 0)
|
|
} // end for (int m=0; m < M; m++)
|
|
} // end if TDD
|
|
}
|
|
|
|
static void release_harq(PHY_VARS_eNB *eNB,int DLSCH_id,int tb,uint16_t frame,uint8_t subframe,uint16_t mask, int is_ack) {
|
|
/*
|
|
* Maximum number of DL transmissions = 4.
|
|
* TODO: get the value from configuration.
|
|
* If is_ack is true then we release immediately. The value -1 can be used for that.
|
|
*/
|
|
do_release_harq(eNB, DLSCH_id, tb, frame, subframe, mask, is_ack ? -1 : 4);
|
|
}
|
|
|
|
int getM(PHY_VARS_eNB *eNB,int frame,int subframe) {
|
|
int M,Mtx=0;
|
|
LTE_eNB_DLSCH_t *dlsch0=NULL,*dlsch1=NULL;
|
|
LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL;
|
|
int harq_pid;
|
|
int subframe_tx,frame_tx;
|
|
int m;
|
|
M=ul_ACK_subframe2_M(&eNB->frame_parms,
|
|
subframe);
|
|
|
|
for (m=0; m<M; m++) {
|
|
subframe_tx = ul_ACK_subframe2_dl_subframe(&eNB->frame_parms,
|
|
subframe,
|
|
m);
|
|
frame_tx = ul_ACK_subframe2_dl_frame(&eNB->frame_parms,frame,
|
|
subframe,subframe_tx);
|
|
|
|
if (dlsch0 == NULL || dlsch1 == NULL) {
|
|
LOG_E(PHY, "dlsch0 and/or dlsch1 NULL, getM frame %i, subframe %i\n",frame,subframe);
|
|
return Mtx;
|
|
}
|
|
|
|
harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
|
|
|
|
if (harq_pid>=0 && harq_pid<dlsch0->Mdlharq) {
|
|
dlsch0_harq = dlsch0->harq_processes[harq_pid];
|
|
dlsch1_harq = dlsch1->harq_processes[harq_pid];
|
|
AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n");
|
|
|
|
if (dlsch0_harq->status == ACTIVE||
|
|
(dlsch1_harq!=NULL && dlsch1_harq->status == ACTIVE)) Mtx ++;
|
|
}
|
|
}
|
|
|
|
return (Mtx);
|
|
}
|
|
|
|
|
|
void fill_ulsch_cqi_indication (PHY_VARS_eNB *eNB, uint16_t frame, uint8_t subframe, LTE_UL_eNB_HARQ_t *ulsch_harq, uint16_t rnti) {
|
|
pthread_mutex_lock (&eNB->UL_INFO_mutex);
|
|
assert(eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis <= NFAPI_CQI_IND_MAX_PDU);
|
|
nfapi_cqi_indication_pdu_t *pdu = &eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list[eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis];
|
|
nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis];
|
|
pdu->instance_length = 0;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = rnti;
|
|
|
|
if (ulsch_harq->cqi_crc_status != 1)
|
|
pdu->cqi_indication_rel9.data_offset = 0;
|
|
else
|
|
pdu->cqi_indication_rel9.data_offset = 1; // fill in after all cqi_indications have been generated when non-zero
|
|
|
|
// by default set O to rank 1 value
|
|
pdu->cqi_indication_rel9.tl.tag = NFAPI_CQI_INDICATION_REL9_TAG;
|
|
pdu->cqi_indication_rel9.length = (ulsch_harq->Or1>>3) + ((ulsch_harq->Or1&7) > 0 ? 1 : 0);
|
|
pdu->cqi_indication_rel9.ri[0] = 0;
|
|
|
|
// if we have RI bits, set them and if rank2 overwrite O
|
|
if (ulsch_harq->O_RI > 0) {
|
|
pdu->cqi_indication_rel9.ri[0] = ulsch_harq->o_RI[0];
|
|
|
|
if (ulsch_harq->o_RI[0] == 2)
|
|
pdu->cqi_indication_rel9.length = (ulsch_harq->Or2 >> 3) + ((ulsch_harq->Or2 & 7) > 0 ? 1 : 0);
|
|
|
|
pdu->cqi_indication_rel9.timing_advance = 0;
|
|
}
|
|
|
|
pdu->cqi_indication_rel9.number_of_cc_reported = 1;
|
|
pdu->ul_cqi_information.channel = 1; // PUSCH
|
|
pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
|
|
memcpy ((void *) raw_pdu->pdu, ulsch_harq->o, pdu->cqi_indication_rel9.length);
|
|
eNB->UL_INFO.cqi_ind.cqi_indication_body.tl.tag = NFAPI_CQI_INDICATION_BODY_TAG;
|
|
eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis++;
|
|
LOG_D(PHY,"eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis:%d\n", eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis);
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_harq, uint16_t rnti, int frame, int subframe, int bundling) {
|
|
int DLSCH_id = find_dlsch(rnti,eNB,SEARCH_EXIST);
|
|
|
|
if( (DLSCH_id<0) || (DLSCH_id>=NUMBER_OF_DLSCH_MAX) ) {
|
|
LOG_E(PHY,"illegal DLSCH_id found!!! rnti %04x DLSCH_id %d\n",rnti,DLSCH_id);
|
|
return;
|
|
}
|
|
|
|
//AssertFatal(DLSCH_id>=0,"DLSCH_id doesn't exist\n");
|
|
pthread_mutex_lock(&eNB->UL_INFO_mutex);
|
|
assert(eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs <= NFAPI_HARQ_IND_MAX_PDU);
|
|
nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs];
|
|
int M;
|
|
int i;
|
|
eNB->UL_INFO.harq_ind.header.message_id = NFAPI_HARQ_INDICATION;
|
|
eNB->UL_INFO.harq_ind.sfn_sf = frame<<4|subframe;
|
|
eNB->UL_INFO.harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG;
|
|
pdu->instance_length = 0; // don't know what to do with this
|
|
// pdu->rx_ue_information.handle = handle;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = rnti;
|
|
|
|
if (eNB->frame_parms.frame_type == FDD) {
|
|
pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG;
|
|
pdu->harq_indication_fdd_rel13.mode = 0;
|
|
pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK;
|
|
|
|
for (i = 0; i < ulsch_harq->O_ACK; i++) {
|
|
AssertFatal (ulsch_harq->o_ACK[i] == 0 || ulsch_harq->o_ACK[i] == 1, "harq_ack[%d] is %d, should be 1,2 or 4\n", i, ulsch_harq->o_ACK[i]);
|
|
pdu->harq_indication_fdd_rel13.harq_tb_n[i] = 2 - ulsch_harq->o_ACK[i];
|
|
// release DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,i,frame,subframe,0xffff, ulsch_harq->o_ACK[i] == 1);
|
|
}
|
|
} else { // TDD
|
|
M = ul_ACK_subframe2_M (&eNB->frame_parms, subframe);
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.mode = 1-bundling;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK;
|
|
|
|
for (i = 0; i < ulsch_harq->O_ACK; i++) {
|
|
AssertFatal (ulsch_harq->o_ACK[i] == 0 || ulsch_harq->o_ACK[i] == 1, "harq_ack[%d] is %d, should be 1,2 or 4\n", i, ulsch_harq->o_ACK[i]);
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 2-ulsch_harq->o_ACK[i];
|
|
// release DLSCH if needed
|
|
/* TODO: review this code, it's most certainly wrong.
|
|
* We have to release the proper HARQ in case of ACK or NACK if max retransmission reached.
|
|
* Basically, call release_harq with 1 as last argument when ACK and 0 when NACK.
|
|
*/
|
|
release_harq(eNB,DLSCH_id,i,frame,subframe,0xffff, ulsch_harq->o_ACK[i] == 1);
|
|
|
|
if (M==1 && ulsch_harq->O_ACK==1 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, ulsch_harq->o_ACK[i] == 1);
|
|
else if (M==1 && ulsch_harq->O_ACK==2 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,DLSCH_id,i,frame,subframe,0xffff, ulsch_harq->o_ACK[i] == 1);
|
|
else if (M>1 && ulsch_harq->o_ACK[i] == 1) {
|
|
// spatial bundling
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,1<<i, ulsch_harq->o_ACK[i] == 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,1<<i, ulsch_harq->o_ACK[i] == 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//LOG_E(PHY,"eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs:%d\n", eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs);
|
|
eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs++;
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) {
|
|
if ( split73 == SPLIT73_DU ) {
|
|
sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, uci, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0);
|
|
return;
|
|
}
|
|
|
|
int DLSCH_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST);
|
|
|
|
//AssertFatal(DLSCH_id>=0,"DLSCH_id doesn't exist rnti:%x\n", uci->rnti);
|
|
if (DLSCH_id < 0) {
|
|
LOG_E(PHY,"SFN/SF:%04d%d Unable to find rnti:%x do not send HARQ\n", frame, subframe, uci->rnti);
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&eNB->UL_INFO_mutex);
|
|
nfapi_harq_indication_t *ind = &eNB->UL_INFO.harq_ind;
|
|
nfapi_harq_indication_body_t *body = &ind->harq_indication_body;
|
|
assert(eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs <= NFAPI_HARQ_IND_MAX_PDU);
|
|
nfapi_harq_indication_pdu_t *pdu = &body->harq_pdu_list[eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs];
|
|
ind->sfn_sf = frame<<4|subframe;
|
|
ind->header.message_id = NFAPI_HARQ_INDICATION;
|
|
body->tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG;
|
|
pdu->instance_length = 0; // don't know what to do with this
|
|
// pdu->rx_ue_information.handle = handle;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = uci->rnti;
|
|
// estimate UL_CQI for MAC (from antenna port 0 only)
|
|
pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
|
|
int SNRtimes10 = dB_fixed_x10(uci->stat) - 10 * eNB->measurements.n0_pucch_dB;
|
|
|
|
if (SNRtimes10 < -100)
|
|
LOG_I (PHY, "uci->stat %d \n", uci->stat);
|
|
|
|
if (SNRtimes10 < -640)
|
|
pdu->ul_cqi_information.ul_cqi = 0;
|
|
else if (SNRtimes10 > 635)
|
|
pdu->ul_cqi_information.ul_cqi = 255;
|
|
else
|
|
pdu->ul_cqi_information.ul_cqi = (640 + SNRtimes10) / 5;
|
|
|
|
pdu->ul_cqi_information.channel = 0;
|
|
|
|
if (eNB->frame_parms.frame_type == FDD) {
|
|
if (uci->pucch_fmt == pucch_format1a) {
|
|
pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG;
|
|
pdu->harq_indication_fdd_rel13.mode = 0;
|
|
pdu->harq_indication_fdd_rel13.number_of_ack_nack = 1;
|
|
AssertFatal (harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n", harq_ack[0]);
|
|
pdu->harq_indication_fdd_rel13.harq_tb_n[0] = harq_ack[0];
|
|
// release DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
} else if (uci->pucch_fmt == pucch_format1b) {
|
|
pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG;
|
|
pdu->harq_indication_fdd_rel13.mode = 0;
|
|
pdu->harq_indication_fdd_rel13.number_of_ack_nack = 2;
|
|
AssertFatal (harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n", harq_ack[0]);
|
|
AssertFatal (harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n", harq_ack[1]);
|
|
pdu->harq_indication_fdd_rel13.harq_tb_n[0] = harq_ack[0];
|
|
pdu->harq_indication_fdd_rel13.harq_tb_n[1] = harq_ack[1];
|
|
// release DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, harq_ack[1] == 1);
|
|
} else AssertFatal(1==0,"only format 1a/b for now, received %d\n",uci->pucch_fmt);
|
|
} else { // TDD
|
|
AssertFatal (tdd_mapping_mode == 0 || tdd_mapping_mode == 1 || tdd_mapping_mode == 2, "Illegal tdd_mapping_mode %d\n", tdd_mapping_mode);
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.mode = tdd_mapping_mode;
|
|
LOG_D(PHY,"%s(eNB, uci_harq format %d, rnti:%04x, frame:%d, subframe:%d, tdd_mapping_mode:%d) harq_ack[0]:%d harq_ack[1]:%d\n", __FUNCTION__, uci->pucch_fmt,uci->rnti, frame, subframe,
|
|
tdd_mapping_mode,harq_ack[0],harq_ack[1]);
|
|
|
|
switch (tdd_mapping_mode) {
|
|
case 0: // bundling
|
|
if (uci->pucch_fmt == pucch_format1a) {
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1;
|
|
LOG_D(PHY,"bundling, pucch1a, number of ack nack %d\n",pdu->harq_indication_tdd_rel13.number_of_ack_nack);
|
|
AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]);
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0];
|
|
// release all bundled DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
} else if (uci->pucch_fmt == pucch_format1b) {
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2;
|
|
AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]);
|
|
AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]);
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0];
|
|
pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = harq_ack[1];
|
|
// release all DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, harq_ack[1] == 1);
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // multiplexing
|
|
AssertFatal (uci->pucch_fmt == pucch_format1b, "uci->pucch_format %d is not format1b\n", uci->pucch_fmt);
|
|
|
|
if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1a) {
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1;
|
|
AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]);
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0];
|
|
// release all DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
} else if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1b) {
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2;
|
|
AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]);
|
|
AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]);
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0];
|
|
pdu->harq_indication_tdd_rel13.harq_data[1].multiplex.value_0 = harq_ack[1];
|
|
// release all DLSCH if needed
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, harq_ack[0] == 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, harq_ack[1] == 1);
|
|
} else { // num_pucch_resources (M) > 1
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = uci->num_pucch_resources;
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0];
|
|
pdu->harq_indication_tdd_rel13.harq_data[1].multiplex.value_0 = harq_ack[1];
|
|
|
|
if (uci->num_pucch_resources == 3) pdu->harq_indication_tdd_rel13.harq_data[2].multiplex.value_0 = harq_ack[2];
|
|
|
|
if (uci->num_pucch_resources == 4) pdu->harq_indication_tdd_rel13.harq_data[3].multiplex.value_0 = harq_ack[3];
|
|
|
|
// spatial-bundling in this case so release both HARQ if necessary
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,tdd_multiplexing_mask, 1 /* force release? previous code was unconditional */);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,tdd_multiplexing_mask, 1 /* force release? previous code was unconditional */);
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // special bundling (SR collision)
|
|
pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
|
|
pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1;
|
|
pdu->harq_indication_tdd_rel13.mode = 0;
|
|
int tdd_config5_sf2scheds=0;
|
|
|
|
if (eNB->frame_parms.tdd_config==5) tdd_config5_sf2scheds = getM(eNB,frame,subframe);
|
|
|
|
switch (harq_ack[0]) {
|
|
case 0:
|
|
case 4:
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 0;
|
|
/* TODO: release_harq here? this whole code looks suspicious */
|
|
break;
|
|
|
|
case 1: // check if M=1,4,7
|
|
if (uci->num_pucch_resources == 1 || uci->num_pucch_resources == 4 ||
|
|
tdd_config5_sf2scheds == 1 || tdd_config5_sf2scheds == 4 || tdd_config5_sf2scheds == 7) {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1;
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, 1);
|
|
} else {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // check if M=2,5,8
|
|
if (uci->num_pucch_resources == 2 || tdd_config5_sf2scheds == 2 ||
|
|
tdd_config5_sf2scheds == 5 || tdd_config5_sf2scheds == 8) {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1;
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, 1);
|
|
} else {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: // check if M=3,6,9
|
|
if (uci->num_pucch_resources == 3 || tdd_config5_sf2scheds == 3 ||
|
|
tdd_config5_sf2scheds == 6 || tdd_config5_sf2scheds == 9) {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1;
|
|
release_harq(eNB,DLSCH_id,0,frame,subframe,0xffff, 1);
|
|
release_harq(eNB,DLSCH_id,1,frame,subframe,0xffff, 1);
|
|
} else {
|
|
pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
} //TDD
|
|
|
|
eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs++;
|
|
LOG_D(PHY,"Incremented eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs:%d\n", eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs);
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
void fill_crc_indication (PHY_VARS_eNB *eNB, int ULSCH_id, int frame, int subframe, uint8_t crc_flag) {
|
|
pthread_mutex_lock(&eNB->UL_INFO_mutex);
|
|
assert(eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs <= NFAPI_CRC_IND_MAX_PDU);
|
|
nfapi_crc_indication_pdu_t *pdu = &eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list[eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs];
|
|
eNB->UL_INFO.crc_ind.sfn_sf = frame<<4 | subframe;
|
|
eNB->UL_INFO.crc_ind.header.message_id = NFAPI_CRC_INDICATION;
|
|
eNB->UL_INFO.crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG;
|
|
pdu->instance_length = 0; // don't know what to do with this
|
|
// pdu->rx_ue_information.handle = handle;
|
|
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
|
|
pdu->rx_ue_information.rnti = eNB->ulsch[ULSCH_id]->rnti;
|
|
pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG;
|
|
pdu->crc_indication_rel8.crc_flag = crc_flag;
|
|
eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs++;
|
|
//LOG_D(PHY, "%s() rnti:%04x crcs:%d crc_flag:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, crc_flag);
|
|
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
|
|
}
|
|
|
|
void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
|
|
//RX processing for ue-specific resources (i
|
|
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
|
|
const int subframe = proc->subframe_rx;
|
|
const int frame = proc->frame_rx;
|
|
/* TODO: use correct rxdata */
|
|
T (T_ENB_PHY_INPUT_SIGNAL, T_INT (eNB->Mod_id), T_INT (frame), T_INT (subframe), T_INT (0),
|
|
T_BUFFER (&eNB->RU_list[0]->common.rxdata[0][subframe * eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti * 4));
|
|
|
|
if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return;
|
|
|
|
T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe));
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 );
|
|
LOG_D (PHY, "[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n", eNB->Mod_id, frame, subframe);
|
|
eNB->rb_mask_ul[0] = 0;
|
|
eNB->rb_mask_ul[1] = 0;
|
|
eNB->rb_mask_ul[2] = 0;
|
|
eNB->rb_mask_ul[3] = 0;
|
|
// Fix me here, these should be locked
|
|
eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0;
|
|
eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0;
|
|
// Call SRS first since all others depend on presence of SRS or lack thereof
|
|
srs_procedures (eNB, proc);
|
|
eNB->first_run_I0_measurements = 0;
|
|
uci_procedures (eNB, proc);
|
|
|
|
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // If PNF or monolithic
|
|
pusch_procedures(eNB,proc);
|
|
}
|
|
|
|
lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements);
|
|
|
|
// clear unused statistics after 2 seconds
|
|
for (int i=0;i<NUMBER_OF_SCH_STATS_MAX;i++) {
|
|
if (eNB->ulsch_stats[i].frame <= frame) {
|
|
if ((eNB->ulsch_stats[i].frame + 200) < frame) memset(&eNB->ulsch_stats[i],0,sizeof(eNB->ulsch_stats[i]));
|
|
}
|
|
else {
|
|
if (eNB->ulsch_stats[i].frame + 200 < (frame+1024)) memset(&eNB->ulsch_stats[i],0,sizeof(eNB->ulsch_stats[i]));
|
|
}
|
|
if (eNB->uci_stats[i].frame <= frame) {
|
|
if ((eNB->uci_stats[i].frame + 200) < frame) memset(&eNB->uci_stats[i],0,sizeof(eNB->uci_stats[i]));
|
|
}
|
|
else {
|
|
if (eNB->uci_stats[i].frame + 200 < (frame+1024)) memset(&eNB->uci_stats[i],0,sizeof(eNB->uci_stats[i]));
|
|
}
|
|
}
|
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
|
|
}
|
|
|
|
void release_rnti_of_phy(module_id_t mod_id) {
|
|
int i,j;
|
|
int CC_id;
|
|
rnti_t rnti;
|
|
PHY_VARS_eNB *eNB_PHY = NULL;
|
|
LTE_eNB_ULSCH_t *ulsch = NULL;
|
|
LTE_eNB_DLSCH_t *dlsch = NULL;
|
|
|
|
for(i = 0; i< release_rntis.number_of_TLVs; i++) {
|
|
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
|
eNB_PHY = RC.eNB[mod_id][CC_id];
|
|
rnti = release_rntis.ue_release_request_TLVs_list[i].rnti;
|
|
|
|
for (j=0; j<NUMBER_OF_DLSCH_MAX; j++) {
|
|
|
|
dlsch = eNB_PHY->dlsch[j][0];
|
|
|
|
if((dlsch != NULL) && (dlsch->rnti == rnti)) {
|
|
LOG_I(PHY, "clean_eNb_dlsch dlsch[%d] UE %x \n", j, rnti);
|
|
clean_eNb_dlsch(dlsch);
|
|
}
|
|
}
|
|
|
|
for (j=0;j<NUMBER_OF_ULSCH_MAX; j++) {
|
|
ulsch = eNB_PHY->ulsch[j];
|
|
|
|
if((ulsch != NULL) && (ulsch->rnti == rnti)) {
|
|
LOG_I(PHY, "clean_eNb_ulsch ulsch[%d] UE %x\n", j, rnti);
|
|
clean_eNb_ulsch(ulsch);
|
|
for (j=0;j<NUMBER_OF_ULSCH_MAX;j++)
|
|
if (eNB_PHY->ulsch_stats[j].rnti == rnti) {eNB_PHY->ulsch_stats[j].rnti=0; break;}
|
|
}
|
|
}
|
|
|
|
for(j=0; j<NUMBER_OF_UCI_MAX; j++) {
|
|
if(eNB_PHY->uci_vars[j].rnti == rnti) {
|
|
LOG_I(PHY, "clean eNb uci_vars[%d] UE %x \n",j, rnti);
|
|
memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(&release_rntis, 0, sizeof(nfapi_ue_release_request_body_t));
|
|
}
|