Files
openairinterface5g/openair1/SCHED/phy_procedures_lte_eNb.c
T
Cedric Roux 91332d3906 fixup previous bad merge (UE disconnection did not work properly anymore)
Doing airplane mode off to connect a cots UE followed by airplane mode on
to disconnect it gives very bad results (bad disconnection with lots of
UL failures followed by lots of logs in the eNB). It used to work properly
after the work done by Xu Bo.

It turns out that in 2018.w04 things were still working okay. But
in 2018.w05 no.

So I ran:

    git diff 2018.w04 2018.w05

And I checked all the modifications that I thought were relevant
(everything related to the UE, oaisim, if4 and fapi has not been checked).

This commits takes back the version of 2018.w04.

The modifications in openair2/RRC/LITE/rrc_eNB.c are necessary, I think.

The other modifications may not be necessary or even wrong. To be checked
at some point.
2018-02-14 17:59:04 +01:00

1921 lines
67 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
* \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas
* \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
* \note
* \warning
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "nfapi_interface.h"
#include "fapi_l1.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "T.h"
#include "assertions.h"
#include "msc.h"
#include <time.h>
#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif
extern uint8_t nfapi_mode;
int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind);
void pmch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,PHY_VARS_RN *rn,relaying_type_t r_type) {
#if defined(Rel10) || defined(Rel14)
MCH_PDU *mch_pduP=NULL;
MCH_PDU mch_pdu;
// uint8_t sync_area=255;
#endif
int subframe = proc->subframe_tx;
AssertFatal(1==0,"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 defined(Rel10) || defined(Rel14)
// 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);
*/
switch (r_type) {
case no_relay:
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;
}
break;
case multicast_relay:
if ((mch_pduP->Pdu_size > 0) && ((mch_pduP->mcch_active == 1) || mch_pduP->msi_active==1)) {
LOG_D(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Got the MCH PDU for MBSFN sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n",
rn->Mod_id,rn->frame, subframe,
mch_pduP->sync_area,mch_pduP->mcs,mch_pduP->Pdu_size);
} else if (rn->mch_avtive[subframe%5] == 1) { // SF2 -> SF7, SF3 -> SF8
mch_pduP= &mch_pdu;
memcpy(&mch_pduP->payload, // could be a simple copy
rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->b,
rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3);
mch_pduP->Pdu_size = (uint16_t) (rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3);
mch_pduP->mcs = rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->mcs;
LOG_D(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Forward the MCH PDU for MBSFN received on SF %d sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n",
rn->Mod_id,rn->frame, subframe,subframe%5,
rn->sync_area[subframe%5],mch_pduP->mcs,mch_pduP->Pdu_size);
} else {
mch_pduP=NULL;
}
rn->mch_avtive[subframe]=0;
break;
default:
LOG_W(PHY,"[eNB %"PRIu8"] Frame %d subframe %d: unknown relaying type %d \n",
eNB->Mod_id,proc->frame_tx,subframe,r_type);
mch_pduP=NULL;
break;
}// switch
if (mch_pduP) {
fill_eNB_dlsch_MCH(eNB,mch_pduP->mcs,1,0);
// Generate PMCH
generate_mch(eNB,proc,(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 (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);
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;
}
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);
}
}
void pdsch_procedures(PHY_VARS_eNB *eNB,
eNB_rxtx_proc_t *proc,
int harq_pid,
LTE_eNB_DLSCH_t *dlsch,
LTE_eNB_DLSCH_t *dlsch1,
LTE_eNB_UE_stats *ue_stats,
int ra_flag) {
int frame=proc->frame_tx;
int subframe=proc->subframe_tx;
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid];
int input_buffer_length = dlsch_harq->TBS/8;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
if (dlsch->rnti == 0x02) {//frame < 200) {
LOG_D(PHY,
"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH 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, input_buffer_length, 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 defined(MESSAGE_CHART_GENERATOR_PHY)
MSC_LOG_TX_MESSAGE(
MSC_PHY_ENB,MSC_PHY_UE,
NULL,0,
"%05u:%02u PDSCH/DLSCH input size = %"PRIu16", G %d, nb_rb %"PRIu16", TBS %"PRIu16", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")",
frame, subframe,
input_buffer_length,
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->TBS,
pmi2hex_2Ar1(dlsch_harq->pmi_alloc),
dlsch_harq->rvidx,
dlsch_harq->round);
#endif
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
}
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 == 0 || nfapi_mode == 1) { // 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;
}
start_meas(&eNB->dlsch_encoding_stats);
eNB->te(eNB,
dlsch_harq->pdu,
dlsch_harq->pdsch_start,
dlsch,
frame,subframe,
&eNB->dlsch_rate_matching_stats,
&eNB->dlsch_turbo_encoding_stats,
&eNB->dlsch_interleaving_stats);
stop_meas(&eNB->dlsch_encoding_stats);
// 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,
subframe,
dlsch_harq->pdsch_start,
dlsch,
dlsch1);
stop_meas(&eNB->dlsch_modulation_stats);
}
dlsch->active = 0;
dlsch_harq->round++;
LOG_D(PHY,"Generating DLSCH/PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round);
}
void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
eNB_rxtx_proc_t *proc,
relaying_type_t r_type,
PHY_VARS_RN *rn,
int do_meas)
{
UNUSED(rn);
int frame=proc->frame_tx;
int subframe=proc->subframe_tx;
uint32_t i,aa;
uint8_t harq_pid;
int8_t UE_id=0;
uint8_t num_pdcch_symbols=0;
uint8_t num_dci=0;
uint8_t ul_subframe;
uint32_t ul_frame;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
LTE_UL_eNB_HARQ_t *ulsch_harq;
int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1;
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+offset,1);
if (do_meas==1) start_meas(&eNB->phy_proc_tx);
// clear the transmit data array for the current subframe
for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) {
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 == 0 || nfapi_mode == 1) {
if (is_pmch_subframe(frame,subframe,fp)) {
pmch_procedures(eNB,proc,rn,r_type);
}
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 (i=0; i<NUMBER_OF_UE_MAX; i++) {
if (eNB->dlsch[i][0])
eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
}
/* save old HARQ information needed for PHICH generation */
/* 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 (i=0; i<NUMBER_OF_UE_MAX; i++) {
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 = DCI_pdu->num_pdcch_symbols;
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",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols,
// DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_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_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);
//LOG_D(PHY,"Before generate_dci_top num_pdcch_symbols:%d num_dci:%d dci_alloc:dci_length:%d\n", num_pdcch_symbols, num_dci, eNB->pdcch_vars[subframe&1].dci_alloc[0].dci_length);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1);
if (nfapi_mode == 0 || nfapi_mode == 1) {
generate_dci_top(num_pdcch_symbols,
num_dci,
&eNB->pdcch_vars[subframe&1].dci_alloc[0],
0,
AMP,
fp,
eNB->common_vars.txdataF,
subframe);
}
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 (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++)
{
dlsch0 = eNB->dlsch[(uint8_t)UE_id][0];
dlsch1 = eNB->dlsch[(uint8_t)UE_id][1];
if ((dlsch0)&&
(dlsch0->rnti>0)&&
(dlsch0->active == 1)) {
// get harq_pid
harq_pid = dlsch0->harq_ids[subframe];
AssertFatal(harq_pid>=0,"harq_pid is negative\n");
if (harq_pid>=8)
{
LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x\n", harq_pid,UE_id,frame,subframe,dlsch0->rnti);
}
else
{
// generate pdsch
pdsch_procedures(eNB,
proc,
harq_pid,
dlsch0,
dlsch1,
&eNB->UE_stats[(uint32_t)UE_id],
0);
}
}
else if ((dlsch0)&&
(dlsch0->rnti>0)&&
(dlsch0->active == 0)) {
// 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+offset,0);
if (do_meas==1) stop_meas(&eNB->phy_proc_tx);
}
void srs_procedures(PHY_VARS_eNB *eNB,eNB_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_UE_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(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) {
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;
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_times10(stat) - 200;//(10*eNB->measurements.n0_power_dB[0]);
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);
}
void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
{
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
uint8_t SR_payload = 0,pucch_b0b1[4][2]= {{0,0},{0,0},{0,0},{0,0}},harq_ack[4]={0,0,0,0};
int32_t metric[4]={0,0,0,0},metric_SR=0,max_metric;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
int i;
LTE_eNB_UCI *uci;
uint16_t tdd_multiplexing_mask=0;
int res;
for (i=0;i<NUMBER_OF_UE_MAX;i++) {
uci = &eNB->uci_vars[i];
if ((uci->active == 1) &&
(uci->frame == frame) &&
(uci->subframe == subframe)) {
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;
}
switch (uci->type) {
case SR:
case HARQ_SR:
metric_SR = rx_pucch(eNB,
uci->pucch_fmt,
i,
uci->n_pucch_1_0_sr[0],
0, // n2_pucch
uci->srs_active, // shortened format
&SR_payload,
frame,
subframe,
PUCCH1_THRES);
LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR is %d (SR n1pucch is %d)\n",
eNB->Mod_id,
uci->rnti,
frame,
subframe,
SR_payload,
uci->n_pucch_1_0_sr[0]);
if (uci->type == SR) {
if (SR_payload == 1) {
fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR);
continue;
}
else {
continue;
}
}
case HARQ:
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,
i,
uci->n_pucch_1[0][0],
0, //n2_pucch
uci->srs_active, // shortened format
pucch_b0b1[0],
frame,
subframe,
PUCCH1a_THRES);
/* 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(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,
i,
uci->n_pucch_1_0_sr[0],
0, //n2_pucch
uci->srs_active, // shortened format
pucch_b0b1[0],
frame,
subframe,
PUCCH1a_THRES);
}
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(eNB,uci,frame,subframe,pucch_b0b1[0],0,0xffff);
}
else { // frame_type == TDD
// 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,
PUCCH1a_THRES);
} 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,
PUCCH1a_THRES);
}
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[1][0] == 1 && pucch_b0b1[1][1] == 1) { // 1/4/7 ACKs
harq_ack[0] = 1;
}
else if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1) { // 2/5/8 ACKs
harq_ack[0] = 2;
}
else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1) { // 3/6/9 ACKs
harq_ack[0] = 3;
}
else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] != 1) { // 0 ACKs, or at least one DL assignment missed
harq_ack[0] = 0;
}
uci->stat = metric[0];
fill_uci_harq_indication(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(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
}
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(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
} 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(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];
fill_uci_harq_indication(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[UE_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[i] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4
eNB->first_sr[i] = 0;
eNB->dlsch[i][0]->harq_processes[0]->round=0;
eNB->dlsch[i][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[i]->rnti,frame,subframe);
}
}
}
}
}
void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
{
uint32_t ret=0,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;
if (fp->frame_type == FDD) harq_pid = ((10*frame) + subframe)&7;
else harq_pid = subframe%10;
for (i=0; i<NUMBER_OF_UE_MAX; i++) {
ulsch = eNB->ulsch[i];
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) &&
(ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
(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;
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);
ret = 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);
LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n",
eNB->Mod_id,harq_pid,
frame,subframe,
ulsch->rnti,
dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]),
dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]),
20,//eNB->measurements.n0_power_dB[0],
20,//eNB->measurements.n0_power_dB[1],
ulsch_harq->o_ACK[0],
ulsch_harq->o_ACK[1],
ret,
ulsch_harq->cqi_crc_status,
ulsch_harq->O_ACK,
eNB->ulsch_decoding_stats.diff_now, eNB->ulsch_decoding_stats.max);
//compute the expected ULSCH RX power (for the stats)
ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered
if (ulsch_harq->cqi_crc_status == 1) {
#ifdef DEBUG_PHY_PROC
//if (((frame%10) == 0) || (frame < 50))
print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL);
#endif
fill_ulsch_cqi_indication(eNB,frame,subframe,
ulsch_harq,
ulsch->rnti);
}
if (ret == (1+MAX_TURBO_ITERATIONS)) {
T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti),
T_INT(harq_pid));
fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC
fill_rx_indication(eNB,i,frame,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,harq_pid,
frame,subframe, i,
ulsch_harq->round-1,
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 << harq_pid);
ulsch_harq->round = 0;
}
#if defined(MESSAGE_CHART_GENERATOR_PHY)
MSC_LOG_RX_DISCARDED_MESSAGE(
MSC_PHY_ENB,MSC_PHY_UE,
NULL,0,
"%05u:%02u ULSCH received rnti %x harq id %u round %d",
frame,subframe,
ulsch->rnti,harq_pid,
ulsch_harq->round-1
);
#endif
/* 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 {
fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC
fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC
ulsch_harq->status = SCH_IDLE;
ulsch->harq_mask &= ~(1 << harq_pid);
T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti),
T_INT(harq_pid));
#if defined(MESSAGE_CHART_GENERATOR_PHY)
MSC_LOG_RX_MESSAGE(
MSC_PHY_ENB,MSC_PHY_UE,
NULL,0,
"%05u:%02u ULSCH received rnti %x harq id %u",
frame,subframe,
ulsch->rnti,harq_pid
);
#endif
#ifdef DEBUG_PHY_PROC
#ifdef DEBUG_ULSCH
LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe,
harq_pid,ulsch_harq->TBS>>3);
for (j=0; j<ulsch_harq->TBS>>3; j++)
LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]);
LOG_T(PHY,"\n");
#endif
#endif
} // ulsch not in error
if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling);
LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n",
eNB->Mod_id,frame,subframe,
harq_pid,
i,
ret,
ulsch_harq->cqi_crc_status,
ulsch_harq->o_ACK[0],
ulsch_harq->o_ACK[1],
eNB->UE_stats[i].ulsch_errors[harq_pid],
eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]);
} // if ((ulsch) &&
// (ulsch->rnti>0) &&
// (ulsch_harq->status == ACTIVE))
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_UE_MAX; i++)
}
extern int oai_exit;
extern void *td_thread(void*);
void init_td_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_td) {
eNB_proc_t *proc = &eNB->proc;
proc->tdp.eNB = eNB;
proc->instance_cnt_td = -1;
pthread_mutex_init( &proc->mutex_td, NULL);
pthread_cond_init( &proc->cond_td, NULL);
pthread_create(&proc->pthread_td, attr_td, td_thread, (void*)&proc->tdp);
}
extern void *te_thread(void*);
void init_te_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_te) {
eNB_proc_t *proc = &eNB->proc;
proc->tep.eNB = eNB;
proc->instance_cnt_te = -1;
pthread_mutex_init( &proc->mutex_te, NULL);
pthread_cond_init( &proc->cond_te, NULL);
printf("Creating te_thread\n");
pthread_create(&proc->pthread_te, attr_te, te_thread, (void*)&proc->tep);
}
void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe)
{
nfapi_rx_indication_pdu_t *pdu;
int timing_advance_update;
int sync_pos;
uint32_t 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;
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[UE_id]->handle;
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti;
pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG;
pdu->rx_indication_rel8.length = eNB->ulsch[UE_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
pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b;
// estimate timing advance for MAC
sync_pos = lte_est_timing_advance_pusch(eNB,UE_id);
timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check
// if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);}
// if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_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 (from antenna port 0 only)
int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 200;//(10*eNB->measurements.n0_power_dB[0]);
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), timing_advance %d (update %d)\n",
harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance,
timing_advance_update);
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);
}
void release_harq(PHY_VARS_eNB *eNB,int UE_id,int tb,uint16_t frame,uint8_t subframe,uint16_t mask) {
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;
int M,m;
AssertFatal(UE_id!=-1,"no existing dlsch context\n");
AssertFatal(UE_id<NUMBER_OF_UE_MAX,"returned UE_id %d >= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX);
dlsch0 = eNB->dlsch[UE_id][0];
dlsch1 = eNB->dlsch[UE_id][1];
if (eNB->frame_parms.frame_type == FDD) {
subframe_tx = (subframe+6)%10;
harq_pid = dlsch0->harq_ids[subframe_tx];
AssertFatal((harq_pid>=0) && (harq_pid<10),"harq_pid %d not in 0...9\n",harq_pid);
dlsch0_harq = dlsch0->harq_processes[harq_pid];
dlsch1_harq = dlsch1->harq_processes[harq_pid];
AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n");
dlsch0_harq->status = SCH_IDLE;
/*if ((dlsch1_harq == NULL)||
((dlsch1_harq!=NULL)&&
(dlsch1_harq->status == SCH_IDLE)))*/
dlsch0->harq_mask &= ~(1<<harq_pid);
LOG_D(PHY,"Frame %d, subframe %d: Releasing harq %d for UE %x\n",frame,subframe,harq_pid,dlsch0->rnti);
}
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
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);
if (((1<<m)&mask) > 0) {
harq_pid = dlsch0->harq_ids[subframe_tx];
if ((harq_pid>=0) && (harq_pid<10)) {
dlsch0_harq = dlsch0->harq_processes[harq_pid];
dlsch1_harq = dlsch1->harq_processes[harq_pid];
AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n");
dlsch0_harq->status = SCH_IDLE;
if ((dlsch1_harq == NULL)||
((dlsch1_harq!=NULL)&&
(dlsch1_harq->status == SCH_IDLE)))
dlsch0->harq_mask &= ~(1<<harq_pid);
}
}
}
}
}
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;
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);
harq_pid = dlsch0->harq_ids[subframe_tx];
if (harq_pid>=0 && harq_pid<10) {
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);
nfapi_cqi_indication_pdu_t *pdu = &eNB->UL_INFO.cqi_ind.cqi_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis];
nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis];
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
memcpy((void*)raw_pdu->pdu,ulsch_harq->o,pdu->cqi_indication_rel9.length);
eNB->UL_INFO.cqi_ind.number_of_cqis++;
LOG_D(PHY,"eNB->UL_INFO.cqi_ind.number_of_cqis:%d\n", eNB->UL_INFO.cqi_ind.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 UE_id = find_dlsch(rnti,eNB,SEARCH_EXIST);
//AssertFatal(UE_id>=0,"UE_id doesn't exist\n");
if (UE_id < 0)
{
LOG_E(PHY,"%s(eNB, ulsch_harq, rnti:%04x, frame:%d, subframe:%d, bundling:%d) harq_pdus:%d - Could not find rnti - abort fill of ulsch harq ind\n", __FUNCTION__, rnti, frame, subframe, bundling,eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs);
return;
}
LOG_D(PHY,"%s(eNB, ulsch_harq, rnti:%04x, frame:%d, subframe:%d, bundling:%d) harq_pdus:%d O_ACK:%d\n", __FUNCTION__, rnti, frame, subframe, bundling,eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,ulsch_harq->O_ACK);
pthread_mutex_lock(&eNB->UL_INFO_mutex);
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
if (ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff);
#if T_TRACER
/* TODO: get correct harq pid */
if (ulsch_harq->o_ACK[i] != 1)
T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(0), T_INT(frame), T_INT(subframe),
T_INT(rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10]));
else
T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(0), T_INT(frame), T_INT(subframe),
T_INT(rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10]));
#endif
}
}
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].multiplex.value_0 = 2-ulsch_harq->o_ACK[i];
// release DLSCH if needed
if (ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff);
if (M==1 && ulsch_harq->O_ACK==1 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
else if (M==1 && ulsch_harq->O_ACK==2 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff);
else if (M>1 && ulsch_harq->o_ACK[i] == 1) {
// spatial bundling
release_harq(eNB,UE_id,0,frame,subframe,1<<i);
release_harq(eNB,UE_id,1,frame,subframe,1<<i);
}
}
}
//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(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) {
int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST);
//AssertFatal(UE_id>=0,"UE_id doesn't exist rnti:%x\n", uci->rnti);
if (UE_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;
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_times10(uci->stat) - 200;//(10*eNB->measurements.n0_power_dB[0]);
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
#if T_TRACER
if (harq_ack[0] != 1)
T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(0), T_INT(frame), T_INT(subframe),
T_INT(uci->rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10]));
else
T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(0), T_INT(frame), T_INT(subframe),
T_INT(uci->rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10]));
#endif
}
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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;
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;
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
}
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
}
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
if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff);
if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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,UE_id,0,frame,subframe,tdd_multiplexing_mask);
release_harq(eNB,UE_id,1,frame,subframe,tdd_multiplexing_mask);
}
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;
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:
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) {
release_harq(eNB,UE_id,0,frame,subframe,0xffff);
release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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) {
release_harq(eNB,UE_id,0,frame,subframe,0xffff);
release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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) {
release_harq(eNB,UE_id,0,frame,subframe,0xffff);
release_harq(eNB,UE_id,1,frame,subframe,0xffff);
}
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 UE_id,int frame,int subframe,uint8_t crc_flag) {
pthread_mutex_lock(&eNB->UL_INFO_mutex);
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[UE_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,eNB_rxtx_proc_t *proc,const relaying_type_t r_type)
{
//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;
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));
/* 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));
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 == 0 || nfapi_mode == 1) { // If PNF or monolithic
pusch_procedures(eNB,proc);
}
lte_eNB_I0_measurements(eNB,
subframe,
0,
eNB->first_run_I0_measurements);
int min_I0=1000,max_I0=0;
if ((frame==0) && (subframe==4)) {
for (int i=0;i<eNB->frame_parms.N_RB_UL;i++) {
if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2;
if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0) min_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) max_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
}
LOG_I(PHY,"max_I0 %d, min_I0 %d\n",max_I0,min_I0);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
stop_meas(&eNB->phy_proc_rx);
}