Fix data race in NR UE MSG3 scheduling Fixed a data race between DL processing of RAR and UL scheduler, which might result in dropping MSG3. It was possible that the UL scheduler for the UL slot which RAR indicates as MSG3 slot was already run by the time the RAR was decoded. Therefore when DCI for RAR is decoded, assume worst case and halt UL scheduler for next slot until RAR is decoded solving the data race. This also in turn halts all later scheduling due to sequential nature of the UL scheduler calls. Closes #962
1280 lines
53 KiB
C
1280 lines
53 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_nr_ue.c
|
|
* \brief Implementation of UE procedures from 36.213 LTE specifications
|
|
* \author R. Knopp, F. Kaltenberger, N. Nikaein, A. Mico Pereperez, G. Casati
|
|
* \date 2018
|
|
* \version 0.1
|
|
* \company Eurecom
|
|
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr, guido.casati@iis.fraunhofer.de
|
|
* \note
|
|
* \warning
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include "nr/nr_common.h"
|
|
#include "assertions.h"
|
|
#include "defs.h"
|
|
#include "PHY/defs_nr_UE.h"
|
|
#include "PHY/NR_REFSIG/dmrs_nr.h"
|
|
#include "PHY/phy_extern_nr_ue.h"
|
|
#include "PHY/MODULATION/modulation_UE.h"
|
|
#include "PHY/INIT/nr_phy_init.h"
|
|
#include "PHY/NR_REFSIG/ptrs_nr.h"
|
|
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
|
|
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
|
#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h"
|
|
#include "SCHED_NR_UE/phy_sch_processing_time.h"
|
|
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
|
#ifdef EMOS
|
|
#include "SCHED/phy_procedures_emos.h"
|
|
#endif
|
|
#include "executables/softmodem-common.h"
|
|
#include "executables/nr-uesoftmodem.h"
|
|
#include "SCHED_NR_UE/pucch_uci_ue_nr.h"
|
|
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
|
|
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
|
|
|
|
//#define DEBUG_PHY_PROC
|
|
//#define NR_PDCCH_SCHED_DEBUG
|
|
//#define NR_PUCCH_SCHED
|
|
//#define NR_PUCCH_SCHED_DEBUG
|
|
//#define NR_PDSCH_DEBUG
|
|
|
|
#ifndef PUCCH
|
|
#define PUCCH
|
|
#endif
|
|
|
|
#include "common/utils/LOG/log.h"
|
|
|
|
#ifdef EMOS
|
|
fifo_dump_emos_UE emos_dump_UE;
|
|
#endif
|
|
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include "UTIL/OPT/opt.h"
|
|
#include "intertask_interface.h"
|
|
#include "T.h"
|
|
#include "instrumentation.h"
|
|
|
|
static const unsigned int gain_table[31] = {100, 112, 126, 141, 158, 178, 200, 224, 251, 282, 316,
|
|
359, 398, 447, 501, 562, 631, 708, 794, 891, 1000, 1122,
|
|
1258, 1412, 1585, 1778, 1995, 2239, 2512, 2818, 3162};
|
|
|
|
static void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txData);
|
|
|
|
void nr_fill_dl_indication(nr_downlink_indication_t *dl_ind,
|
|
fapi_nr_dci_indication_t *dci_ind,
|
|
fapi_nr_rx_indication_t *rx_ind,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
PHY_VARS_NR_UE *ue,
|
|
void *phy_data)
|
|
{
|
|
memset((void*)dl_ind, 0, sizeof(nr_downlink_indication_t));
|
|
|
|
dl_ind->gNB_index = proc->gNB_id;
|
|
dl_ind->module_id = ue->Mod_id;
|
|
dl_ind->cc_id = ue->CC_id;
|
|
dl_ind->frame = proc->frame_rx;
|
|
dl_ind->slot = proc->nr_slot_rx;
|
|
dl_ind->phy_data = phy_data;
|
|
|
|
if (dci_ind) {
|
|
|
|
dl_ind->rx_ind = NULL; //no data, only dci for now
|
|
dl_ind->dci_ind = dci_ind;
|
|
|
|
} else if (rx_ind) {
|
|
|
|
dl_ind->rx_ind = rx_ind; // hang on rx_ind instance
|
|
dl_ind->dci_ind = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
static uint32_t get_ssb_arfcn(NR_DL_FRAME_PARMS *frame_parms)
|
|
{
|
|
uint32_t band_size_hz = frame_parms->N_RB_DL * 12 * frame_parms->subcarrier_spacing;
|
|
int ssb_center_sc = frame_parms->ssb_start_subcarrier + 120; // ssb is 20 PRBs -> 240 sub-carriers
|
|
uint64_t ssb_freq = frame_parms->dl_CarrierFreq - (band_size_hz / 2) + frame_parms->subcarrier_spacing * ssb_center_sc;
|
|
return to_nrarfcn(frame_parms->nr_band, ssb_freq, frame_parms->numerology_index, band_size_hz);
|
|
}
|
|
void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
|
|
uint8_t pdu_type,
|
|
PHY_VARS_NR_UE *ue,
|
|
NR_UE_DLSCH_t *dlsch0,
|
|
NR_UE_DLSCH_t *dlsch1,
|
|
uint16_t n_pdus,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
void *typeSpecific,
|
|
uint8_t *b)
|
|
{
|
|
if (n_pdus > 1){
|
|
LOG_E(PHY, "In %s: multiple number of DL PDUs not supported yet...\n", __FUNCTION__);
|
|
}
|
|
fapi_nr_rx_indication_body_t *rx = rx_ind->rx_indication_body + n_pdus - 1;
|
|
switch (pdu_type){
|
|
case FAPI_NR_RX_PDU_TYPE_SIB:
|
|
case FAPI_NR_RX_PDU_TYPE_RAR:
|
|
case FAPI_NR_RX_PDU_TYPE_DLSCH:
|
|
if(dlsch0) {
|
|
NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][dlsch0->dlsch_config.harq_process_nbr];
|
|
rx->pdsch_pdu.harq_pid = dlsch0->dlsch_config.harq_process_nbr;
|
|
rx->pdsch_pdu.ack_nack = dl_harq0->decodeResult;
|
|
rx->pdsch_pdu.pdu = b;
|
|
rx->pdsch_pdu.pdu_length = dlsch0->dlsch_config.TBS / 8;
|
|
if (dl_harq0->decodeResult) {
|
|
int t = WS_C_RNTI;
|
|
if (pdu_type == FAPI_NR_RX_PDU_TYPE_RAR)
|
|
t = WS_RA_RNTI;
|
|
if (pdu_type == FAPI_NR_RX_PDU_TYPE_SIB)
|
|
t = WS_SI_RNTI;
|
|
ws_trace_t tmp = {.nr = true,
|
|
.direction = DIRECTION_DOWNLINK,
|
|
.pdu_buffer = b,
|
|
.pdu_buffer_size = rx->pdsch_pdu.pdu_length,
|
|
.ueid = 0,
|
|
.rntiType = t,
|
|
.rnti = dlsch0->rnti,
|
|
.sysFrame = proc->frame_rx,
|
|
.subframe = proc->nr_slot_rx,
|
|
.harq_pid = dlsch0->dlsch_config.harq_process_nbr};
|
|
trace_pdu(&tmp);
|
|
}
|
|
}
|
|
if(dlsch1) {
|
|
AssertFatal(1==0,"Second codeword currently not supported\n");
|
|
}
|
|
break;
|
|
case FAPI_NR_RX_PDU_TYPE_SSB: {
|
|
if (typeSpecific) {
|
|
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
|
|
fapiPbch_t *pbch = (fapiPbch_t *)typeSpecific;
|
|
memcpy(rx->ssb_pdu.pdu, pbch->decoded_output, sizeof(pbch->decoded_output));
|
|
rx->ssb_pdu.additional_bits = pbch->xtra_byte;
|
|
rx->ssb_pdu.ssb_index = (frame_parms->ssb_index) & 0x7;
|
|
rx->ssb_pdu.ssb_length = frame_parms->Lmax;
|
|
rx->ssb_pdu.cell_id = frame_parms->Nid_cell;
|
|
rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier;
|
|
rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index];
|
|
rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index];
|
|
rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms);
|
|
rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here
|
|
rx->ssb_pdu.decoded_pdu = true;
|
|
} else {
|
|
rx->ssb_pdu.radiolink_monitoring = RLM_out_of_sync; // TODO to be removed from here
|
|
rx->ssb_pdu.decoded_pdu = false;
|
|
}
|
|
} break;
|
|
case FAPI_NR_CSIRS_IND:
|
|
memcpy(&rx->csirs_measurements, typeSpecific, sizeof(fapi_nr_csirs_measurements_t));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
rx->pdu_type = pdu_type;
|
|
rx_ind->number_pdus = n_pdus;
|
|
|
|
}
|
|
|
|
int get_tx_amp_prach(int power_dBm, int power_max_dBm, int N_RB_UL){
|
|
|
|
int gain_dB = power_dBm - power_max_dBm, amp_x_100 = -1;
|
|
|
|
switch (N_RB_UL) {
|
|
case 6:
|
|
amp_x_100 = AMP; // PRACH is 6 PRBS so no scale
|
|
break;
|
|
case 15:
|
|
amp_x_100 = 158*AMP; // 158 = 100*sqrt(15/6)
|
|
break;
|
|
case 25:
|
|
amp_x_100 = 204*AMP; // 204 = 100*sqrt(25/6)
|
|
break;
|
|
case 50:
|
|
amp_x_100 = 286*AMP; // 286 = 100*sqrt(50/6)
|
|
break;
|
|
case 75:
|
|
amp_x_100 = 354*AMP; // 354 = 100*sqrt(75/6)
|
|
break;
|
|
case 100:
|
|
amp_x_100 = 408*AMP; // 408 = 100*sqrt(100/6)
|
|
break;
|
|
default:
|
|
LOG_E(PHY, "Unknown PRB size %d\n", N_RB_UL);
|
|
return (amp_x_100);
|
|
break;
|
|
}
|
|
if (gain_dB < -30) {
|
|
return (amp_x_100/3162);
|
|
} else if (gain_dB > 0)
|
|
return (amp_x_100);
|
|
else
|
|
return (amp_x_100/gain_table[-gain_dB]); // 245 corresponds to the factor sqrt(25/6)
|
|
|
|
return (amp_x_100);
|
|
}
|
|
|
|
// UL time alignment procedures:
|
|
// - If the current tx frame and slot match the TA configuration
|
|
// then timing advance is processed and set to be applied in the next UL transmission
|
|
// - Application of timing adjustment according to TS 38.213 p4.2
|
|
// - handle RAR TA application as per ch 4.2 TS 38.213
|
|
void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx)
|
|
{
|
|
if (frame_tx == ue->ta_frame && slot_tx == ue->ta_slot) {
|
|
uint16_t ofdm_symbol_size = ue->frame_parms.ofdm_symbol_size;
|
|
|
|
// convert time factor "16 * 64 * T_c / (2^mu)" in N_TA calculation in TS38.213 section 4.2 to samples by multiplying with
|
|
// samples per second
|
|
// 16 * 64 * T_c / (2^mu) * samples_per_second
|
|
// = 16 * T_s / (2^mu) * samples_per_second
|
|
// = 16 * 1 / (15 kHz * 2048) / (2^mu) * (15 kHz * 2^mu * ofdm_symbol_size)
|
|
// = 16 * 1 / 2048 * ofdm_symbol_size
|
|
// = 16 * ofdm_symbol_size / 2048
|
|
uint16_t bw_scaling = 16 * ofdm_symbol_size / 2048;
|
|
|
|
ue->timing_advance += (ue->ta_command - 31) * bw_scaling;
|
|
|
|
LOG_D(PHY,
|
|
"[UE %d] [%d.%d] Got timing advance command %u from MAC, new value is %d\n",
|
|
ue->Mod_id,
|
|
frame_tx,
|
|
slot_tx,
|
|
ue->ta_command,
|
|
ue->timing_advance);
|
|
|
|
ue->ta_frame = -1;
|
|
ue->ta_slot = -1;
|
|
}
|
|
}
|
|
|
|
void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txp)
|
|
{
|
|
const int slot_tx = proc->nr_slot_tx;
|
|
const int frame_tx = proc->frame_tx;
|
|
|
|
AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n");
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN);
|
|
|
|
const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * ue->frame_parms.ofdm_symbol_size;
|
|
c16_t txdataF_buf[ue->frame_parms.nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32)));
|
|
memset(txdataF_buf, 0, sizeof(txdataF_buf));
|
|
c16_t *txdataF[ue->frame_parms.nb_antennas_tx]; /* workaround to be compatible with current txdataF usage in all tx procedures. */
|
|
for(int i=0; i< ue->frame_parms.nb_antennas_tx; ++i)
|
|
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
|
|
|
|
LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
|
|
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0};
|
|
|
|
start_meas_nr_ue_phy(ue, PHY_PROC_TX);
|
|
|
|
nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF, was_symbol_used);
|
|
|
|
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, phy_data, was_symbol_used);
|
|
|
|
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF, was_symbol_used);
|
|
|
|
LOG_D(PHY, "Sending Uplink data \n");
|
|
|
|
// Don't do OFDM Mod if txdata contains prach
|
|
const NR_UE_PRACH *prach_var = ue->prach_vars[proc->gNB_id];
|
|
if (!prach_var->active) {
|
|
start_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
|
|
nr_ue_pusch_common_procedures(ue,
|
|
proc->nr_slot_tx,
|
|
&ue->frame_parms,
|
|
ue->frame_parms.nb_antennas_tx,
|
|
(c16_t **)txdataF,
|
|
txp,
|
|
link_type_ul,
|
|
was_symbol_used);
|
|
stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
|
|
}
|
|
|
|
nr_ue_prach_procedures(ue, proc, txp);
|
|
|
|
LOG_D(PHY, "****** end TX-Chain for AbsSubframe %d.%d ******\n", proc->frame_tx, proc->nr_slot_tx);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
|
|
stop_meas_nr_ue_phy(ue, PHY_PROC_TX);
|
|
}
|
|
|
|
void nr_ue_measurement_procedures(uint16_t l,
|
|
PHY_VARS_NR_UE *ue,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
NR_UE_DLSCH_t *dlsch,
|
|
uint32_t pdsch_est_size,
|
|
int32_t dl_ch_estimates[][pdsch_est_size])
|
|
{
|
|
NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
int gNB_id = proc->gNB_id;
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_IN);
|
|
|
|
if (l==2) {
|
|
|
|
LOG_D(PHY,"Doing UE measurement procedures in symbol l %u Ncp %d nr_slot_rx %d, rxdata %p\n",
|
|
l,
|
|
ue->frame_parms.Ncp,
|
|
nr_slot_rx,
|
|
ue->common_vars.rxdata);
|
|
|
|
nr_ue_measurements(ue, proc, dlsch, pdsch_est_size, dl_ch_estimates);
|
|
|
|
#if T_TRACER
|
|
if(nr_slot_rx == 0)
|
|
T(T_UE_PHY_MEAS,
|
|
T_INT(gNB_id),
|
|
T_INT(ue->Mod_id),
|
|
T_INT(proc->frame_rx % 1024),
|
|
T_INT(nr_slot_rx),
|
|
T_INT((int)(10 * log10(ue->measurements.rsrp[0]) - ue->rx_total_gain_dB)),
|
|
T_INT((int)ue->measurements.rx_rssi_dBm[0]),
|
|
T_INT((int)(ue->measurements.rx_power_avg_dB[0] - ue->measurements.n0_power_avg_dB)),
|
|
T_INT((int)ue->measurements.rx_power_avg_dB[0]),
|
|
T_INT((int)ue->measurements.n0_power_avg_dB),
|
|
T_INT((int)ue->measurements.wideband_cqi_avg[0]));
|
|
#endif
|
|
}
|
|
|
|
// accumulate and filter timing offset estimation every subframe (instead of every frame)
|
|
if (( nr_slot_rx == 2) && (l==(2-frame_parms->Ncp))) {
|
|
|
|
// AGC
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_IN);
|
|
|
|
|
|
//printf("start adjust gain power avg db %d\n", ue->measurements.rx_power_avg_dB[gNB_id]);
|
|
phy_adjust_gain_nr (ue,ue->measurements.rx_power_avg_dB[gNB_id],gNB_id);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT);
|
|
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_OUT);
|
|
}
|
|
|
|
static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
int estimateSz,
|
|
struct complex16 dl_ch_estimates[][estimateSz],
|
|
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
|
|
{
|
|
TracyCZone(ctx, true);
|
|
int ret = 0;
|
|
DevAssert(ue);
|
|
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
int gNB_id = proc->gNB_id;
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);
|
|
|
|
LOG_D(PHY,"[UE %d] Frame %d Slot %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,nr_slot_rx,ue->frame_parms.Nid_cell,gNB_id);
|
|
fapiPbch_t result;
|
|
int hf_frame_bit, ssb_index, symb_offset;
|
|
ret = nr_rx_pbch(ue,
|
|
proc,
|
|
ue->is_synchronized,
|
|
estimateSz,
|
|
dl_ch_estimates,
|
|
&ue->frame_parms,
|
|
(ue->frame_parms.ssb_index) & 7,
|
|
ue->frame_parms.ssb_start_subcarrier,
|
|
ue->frame_parms.Nid_cell,
|
|
&result,
|
|
&hf_frame_bit,
|
|
&ssb_index,
|
|
&symb_offset,
|
|
ue->frame_parms.samples_per_frame_wCP,
|
|
rxdataF);
|
|
|
|
if (ret==0) {
|
|
T(T_NRUE_PHY_MIB, T_INT(frame_rx), T_INT(nr_slot_rx),
|
|
T_INT(ssb_index), T_BUFFER(result.decoded_output, 3));
|
|
|
|
#ifdef DEBUG_PHY_PROC
|
|
LOG_D(PHY,
|
|
"[UE %d] frame %d, nr_slot_rx %d, Received PBCH (MIB): ssb idx: %d, N_RB_DL %d\n",
|
|
ue->Mod_id,
|
|
frame_rx,
|
|
nr_slot_rx,
|
|
ssb_index,
|
|
ue->frame_parms.N_RB_DL);
|
|
#endif
|
|
|
|
} else {
|
|
LOG_E(PHY, "[UE %d] frame %d, nr_slot_rx %d, Error decoding PBCH!\n", ue->Mod_id, frame_rx, nr_slot_rx);
|
|
}
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_OUT);
|
|
TracyCZoneEnd(ctx);
|
|
return ret;
|
|
}
|
|
|
|
int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
int32_t pdcch_est_size,
|
|
c16_t pdcch_dl_ch_estimates[][pdcch_est_size],
|
|
nr_phy_data_t *phy_data,
|
|
int n_ss,
|
|
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
|
|
{
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config;
|
|
|
|
fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &phy_pdcch_config->pdcch_config[n_ss];
|
|
|
|
start_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS);
|
|
|
|
/// PDCCH/DCI e-sequence (input to rate matching).
|
|
int32_t pdcch_e_rx_size = NR_MAX_PDCCH_SIZE;
|
|
c16_t pdcch_e_rx[pdcch_e_rx_size];
|
|
|
|
nr_rx_pdcch(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, pdcch_e_rx, rel15, rxdataF);
|
|
|
|
fapi_nr_dci_indication_t dci_ind;
|
|
nr_dci_decoding_procedure(ue, proc, pdcch_e_rx, &dci_ind, rel15);
|
|
|
|
for (int i = 0; i < dci_ind.number_of_dcis; i++) {
|
|
LOG_D(PHY,
|
|
"[UE %d] AbsSubFrame %d.%d: DCI %i of %d total DCIs found --> rnti %x : format %d\n",
|
|
ue->Mod_id,
|
|
frame_rx % 1024,
|
|
nr_slot_rx,
|
|
i + 1,
|
|
dci_ind.number_of_dcis,
|
|
dci_ind.dci_list[i].rnti,
|
|
dci_ind.dci_list[i].dci_format);
|
|
}
|
|
|
|
nr_downlink_indication_t dl_indication;
|
|
// fill dl_indication message
|
|
nr_fill_dl_indication(&dl_indication, &dci_ind, NULL, proc, ue, phy_data);
|
|
// send to mac
|
|
ue->if_inst->dl_indication(&dl_indication);
|
|
stop_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT);
|
|
return (dci_ind.number_of_dcis);
|
|
}
|
|
|
|
static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
NR_UE_DLSCH_t dlsch[2],
|
|
int16_t *llr[2],
|
|
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
|
|
int G)
|
|
{
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
|
|
// We handle only one CW now
|
|
if (!(NR_MAX_NB_LAYERS>4)) {
|
|
NR_UE_DLSCH_t *dlsch0 = &dlsch[0];
|
|
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlschCfg = &dlsch0->dlsch_config;
|
|
int harq_pid = dlschCfg->harq_process_nbr;
|
|
// dlsch0_harq contains the previous transmissions data for this harq pid
|
|
NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid];
|
|
|
|
LOG_D(PHY,
|
|
"[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask "
|
|
"%x, Nl %d\n",
|
|
ue->Mod_id,
|
|
frame_rx,
|
|
nr_slot_rx,
|
|
harq_pid,
|
|
dlsch0_harq->status,
|
|
dlschCfg->BWPStart,
|
|
dlschCfg->start_rb,
|
|
dlschCfg->number_rbs,
|
|
dlschCfg->start_symbol,
|
|
dlschCfg->number_symbols,
|
|
dlschCfg->dlDmrsSymbPos,
|
|
dlsch0->Nl);
|
|
|
|
const uint32_t pdsch_est_size = ((ue->frame_parms.symbols_per_slot * ue->frame_parms.ofdm_symbol_size + 15) / 16) * 16;
|
|
fourDimArray_t *toFree = NULL;
|
|
allocCast2D(pdsch_dl_ch_estimates, int32_t, toFree, ue->frame_parms.nb_antennas_rx * dlsch0->Nl, pdsch_est_size, false);
|
|
|
|
c16_t ptrs_phase_per_slot[ue->frame_parms.nb_antennas_rx][NR_SYMBOLS_PER_SLOT];
|
|
memset(ptrs_phase_per_slot, 0, sizeof(ptrs_phase_per_slot));
|
|
|
|
int32_t ptrs_re_per_slot[ue->frame_parms.nb_antennas_rx][NR_SYMBOLS_PER_SLOT];
|
|
memset(ptrs_re_per_slot, 0, sizeof(ptrs_re_per_slot));
|
|
|
|
const uint32_t rx_size_symbol = (dlsch[0].dlsch_config.number_rbs * NR_NB_SC_PER_RB + 15) & ~15;
|
|
fourDimArray_t *toFree2 = NULL;
|
|
allocCast3D(rxdataF_comp,
|
|
int32_t,
|
|
toFree2,
|
|
dlsch[0].Nl,
|
|
ue->frame_parms.nb_antennas_rx,
|
|
rx_size_symbol * NR_SYMBOLS_PER_SLOT,
|
|
false);
|
|
|
|
uint32_t nvar = 0;
|
|
|
|
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS);
|
|
for (int m = dlschCfg->start_symbol; m < (dlschCfg->start_symbol + dlschCfg->number_symbols); m++) {
|
|
if (dlschCfg->dlDmrsSymbPos & (1 << m)) {
|
|
for (int nl = 0; nl < dlsch0->Nl; nl++) { //for MIMO Config: it shall loop over no_layers
|
|
LOG_D(PHY,"PDSCH Channel estimation layer %d, slot %d, symbol %d\n", nl, nr_slot_rx, m);
|
|
uint32_t nvar_tmp = 0;
|
|
nr_pdsch_channel_estimation(ue,
|
|
proc,
|
|
nl,
|
|
get_dmrs_port(nl, dlschCfg->dmrs_ports),
|
|
m,
|
|
dlschCfg->nscid,
|
|
dlschCfg->dlDmrsScramblingId,
|
|
dlschCfg->BWPStart,
|
|
dlschCfg->dmrsConfigType,
|
|
dlschCfg->rb_offset,
|
|
ue->frame_parms.first_carrier_offset + (dlschCfg->BWPStart + dlschCfg->start_rb) * 12,
|
|
dlschCfg->number_rbs,
|
|
pdsch_est_size,
|
|
pdsch_dl_ch_estimates,
|
|
ue->frame_parms.samples_per_slot_wCP,
|
|
rxdataF,
|
|
&nvar_tmp);
|
|
nvar += nvar_tmp;
|
|
#if 0
|
|
///LOG_M: the channel estimation
|
|
char filename[100];
|
|
for (uint8_t aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
|
|
sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", frame_rx, nr_slot_rx, m, nl, aarx);
|
|
int **dl_ch_estimates = ue->pdsch_vars[gNB_id]->dl_ch_estimates;
|
|
LOG_M(filename,"channel_F",&dl_ch_estimates[nl*ue->frame_parms.nb_antennas_rx+aarx][ue->frame_parms.ofdm_symbol_size*m],ue->frame_parms.ofdm_symbol_size, 1, 1);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS);
|
|
|
|
nvar /= (dlschCfg->number_symbols * dlsch0->Nl * ue->frame_parms.nb_antennas_rx);
|
|
|
|
nr_ue_measurement_procedures(2, ue, proc, &dlsch[0], pdsch_est_size, pdsch_dl_ch_estimates);
|
|
|
|
if (ue->chest_time == 1) { // averaging time domain channel estimates
|
|
nr_chest_time_domain_avg(&ue->frame_parms,
|
|
(int32_t **)pdsch_dl_ch_estimates,
|
|
dlschCfg->number_symbols,
|
|
dlschCfg->start_symbol,
|
|
dlschCfg->dlDmrsSymbPos,
|
|
dlschCfg->number_rbs);
|
|
}
|
|
|
|
uint16_t first_symbol_with_data = dlschCfg->start_symbol;
|
|
uint32_t dmrs_data_re;
|
|
|
|
if (dlschCfg->dmrsConfigType == NFAPI_NR_DMRS_TYPE1)
|
|
dmrs_data_re = 12 - 6 * dlschCfg->n_dmrs_cdm_groups;
|
|
else
|
|
dmrs_data_re = 12 - 4 * dlschCfg->n_dmrs_cdm_groups;
|
|
|
|
while ((dmrs_data_re == 0) && (dlschCfg->dlDmrsSymbPos & (1 << first_symbol_with_data))) {
|
|
first_symbol_with_data++;
|
|
}
|
|
|
|
uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT] = {0};
|
|
uint32_t llr_offset[NR_SYMBOLS_PER_SLOT] = {0};
|
|
|
|
int32_t log2_maxh = 0;
|
|
start_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
|
pdsch_scope_req_t scope_req = { .copy_chanest_to_scope = false,
|
|
.copy_rxdataF_to_scope = false,
|
|
.scope_rxdataF_offset = 0 };
|
|
if (UEScopeHasTryLock(ue)) {
|
|
metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx};
|
|
scope_req.copy_chanest_to_scope = UETryLockScopeData(ue,
|
|
pdschChanEstimates,
|
|
sizeof(c16_t),
|
|
1,
|
|
dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols,
|
|
&mt);
|
|
scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue,
|
|
pdschRxdataF,
|
|
sizeof(c16_t),
|
|
1,
|
|
dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols,
|
|
&mt);
|
|
}
|
|
for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
|
|
bool first_symbol_flag = false;
|
|
if (m == first_symbol_with_data)
|
|
first_symbol_flag = true;
|
|
|
|
// process DLSCH received symbols in the slot
|
|
// symbol by symbol processing (if data/DMRS are multiplexed is checked inside the function)
|
|
if (nr_rx_pdsch(ue,
|
|
proc,
|
|
dlsch,
|
|
m,
|
|
first_symbol_flag,
|
|
harq_pid,
|
|
pdsch_est_size,
|
|
pdsch_dl_ch_estimates,
|
|
llr,
|
|
dl_valid_re,
|
|
rxdataF,
|
|
llr_offset,
|
|
&log2_maxh,
|
|
rx_size_symbol,
|
|
ue->frame_parms.nb_antennas_rx,
|
|
rxdataF_comp,
|
|
ptrs_phase_per_slot,
|
|
ptrs_re_per_slot,
|
|
G,
|
|
nvar,
|
|
&scope_req)
|
|
< 0) {
|
|
if (scope_req.copy_chanest_to_scope) {
|
|
UEunlockScopeData(ue, pdschChanEstimates);
|
|
}
|
|
if (scope_req.copy_rxdataF_to_scope) {
|
|
UEunlockScopeData(ue, pdschRxdataF);
|
|
}
|
|
return -1;
|
|
}
|
|
} // CRNTI active
|
|
stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
|
if (scope_req.copy_chanest_to_scope) {
|
|
UEunlockScopeData(ue, pdschChanEstimates);
|
|
}
|
|
if (scope_req.copy_rxdataF_to_scope) {
|
|
UEunlockScopeData(ue, pdschRxdataF);
|
|
}
|
|
free(toFree);
|
|
free(toFree2);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config)
|
|
{
|
|
uint32_t unav_res = 0;
|
|
for (int i = 0; i < dlsch_config->numCsiRsForRateMatching; i++) {
|
|
fapi_nr_dl_config_csirs_pdu_rel15_t *csi_pdu = &dlsch_config->csiRsForRateMatching[i];
|
|
// check overlapping symbols
|
|
int num_overlap_symb = 0;
|
|
// num of consecutive csi symbols from l0 included
|
|
int num_l0 [18] = {1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 4, 2, 2, 4};
|
|
int num_symb = num_l0[csi_pdu->row - 1];
|
|
for (int s = 0; s < num_symb; s++) {
|
|
int l0_symb = csi_pdu->symb_l0 + s;
|
|
if (l0_symb >= dlsch_config->start_symbol && l0_symb <= dlsch_config->start_symbol + dlsch_config->number_symbols)
|
|
num_overlap_symb++;
|
|
}
|
|
// check also l1 if relevant
|
|
if (csi_pdu->row == 13 || csi_pdu->row == 14 || csi_pdu->row == 16 || csi_pdu->row == 17) {
|
|
num_symb += 2;
|
|
for (int s = 0; s < 2; s++) { // two consecutive symbols including l1
|
|
int l1_symb = csi_pdu->symb_l1 + s;
|
|
if (l1_symb >= dlsch_config->start_symbol && l1_symb <= dlsch_config->start_symbol + dlsch_config->number_symbols)
|
|
num_overlap_symb++;
|
|
}
|
|
}
|
|
if (num_overlap_symb == 0)
|
|
continue;
|
|
// check number overlapping prbs
|
|
// assuming CSI is spanning the whole BW
|
|
AssertFatal(dlsch_config->BWPSize <= csi_pdu->nr_of_rbs, "Assuming CSI-RS is spanning the whold BWP this shouldn't happen\n");
|
|
int dlsch_start = dlsch_config->start_rb + dlsch_config->BWPStart;
|
|
int num_overlapping_prbs = dlsch_config->number_rbs;
|
|
if (num_overlapping_prbs < 1)
|
|
continue; // no overlapping prbs
|
|
if (csi_pdu->freq_density < 2) { // 0.5 density
|
|
num_overlapping_prbs /= 2;
|
|
// odd number of prbs and the start PRB is even/odd when CSI is in even/odd PRBs
|
|
if ((num_overlapping_prbs % 2) && ((dlsch_start % 2) == csi_pdu->freq_density))
|
|
num_overlapping_prbs += 1;
|
|
}
|
|
// density is number or res per port per rb (over all symbols)
|
|
int ports [18] = {1, 1, 2, 4, 4, 8, 8, 8, 12, 12, 16, 16, 24, 24, 24, 32, 32, 32};
|
|
int num_csi_res_per_prb = csi_pdu->freq_density == 3 ? 3 : 1;
|
|
num_csi_res_per_prb *= ports[csi_pdu->row - 1];
|
|
unav_res += num_overlapping_prbs * num_csi_res_per_prb * num_overlap_symb / num_symb;
|
|
}
|
|
return unav_res;
|
|
}
|
|
|
|
/*! \brief Process the whole DLSCH slot
|
|
*/
|
|
static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
|
|
const UE_nr_rxtx_proc_t *proc,
|
|
NR_UE_DLSCH_t dlsch[2],
|
|
int16_t *llr[2]) {
|
|
if (dlsch[0].active == false) {
|
|
LOG_E(PHY, "DLSCH should be active when calling this function\n");
|
|
return;
|
|
}
|
|
|
|
int harq_pid = dlsch[0].dlsch_config.harq_process_nbr;
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid];
|
|
NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid];
|
|
uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos);
|
|
nr_downlink_indication_t dl_indication;
|
|
fapi_nr_rx_indication_t rx_ind = {0};
|
|
uint16_t number_pdus = 1;
|
|
|
|
uint8_t is_cw0_active = dl_harq0->status;
|
|
uint8_t is_cw1_active = dl_harq1->status;
|
|
int nb_dlsch = 0;
|
|
nb_dlsch += (is_cw0_active == ACTIVE) ? 1 : 0;
|
|
nb_dlsch += (is_cw1_active == ACTIVE) ? 1 : 0;
|
|
uint16_t nb_symb_sch = dlsch[0].dlsch_config.number_symbols;
|
|
uint8_t dmrs_type = dlsch[0].dlsch_config.dmrsConfigType;
|
|
|
|
uint8_t nb_re_dmrs;
|
|
if (dmrs_type == NFAPI_NR_DMRS_TYPE1) {
|
|
nb_re_dmrs = 6 * dlsch[0].dlsch_config.n_dmrs_cdm_groups;
|
|
} else {
|
|
nb_re_dmrs = 4 * dlsch[0].dlsch_config.n_dmrs_cdm_groups;
|
|
}
|
|
|
|
LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw0_active);
|
|
LOG_D(PHY, "AbsSubframe %d.%d Start LDPC Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx % 1024, nr_slot_rx, harq_pid, is_cw1_active);
|
|
|
|
// exit dlsch procedures as there are no active dlsch
|
|
if (is_cw0_active != ACTIVE && is_cw1_active != ACTIVE) {
|
|
// don't wait anymore
|
|
LOG_E(NR_PHY, "Internal error nr_ue_dlsch_procedure() called but no active cw on slot %d, harq %d\n", nr_slot_rx, harq_pid);
|
|
if (dlsch[0].dlsch_config.k1_feedback) {
|
|
const int ack_nack_slot_and_frame =
|
|
(proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
|
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int G[2];
|
|
uint8_t DLSCH_ids[nb_dlsch];
|
|
int pdsch_id = 0;
|
|
uint8_t *p_b[2] = {NULL};
|
|
for (uint8_t DLSCH_id = 0; DLSCH_id < 2; DLSCH_id++) {
|
|
NR_DL_UE_HARQ_t *dl_harq = &ue->dl_harq_processes[DLSCH_id][harq_pid];
|
|
if (dl_harq->status != ACTIVE) continue;
|
|
|
|
DLSCH_ids[pdsch_id++] = DLSCH_id;
|
|
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[DLSCH_id].dlsch_config;
|
|
uint32_t unav_res = 0;
|
|
if (dlsch_config->pduBitmap & 0x1) {
|
|
uint16_t ptrsSymbPos = 0;
|
|
set_ptrs_symb_idx(&ptrsSymbPos, dlsch_config->number_symbols, dlsch_config->start_symbol, 1 << dlsch_config->PTRSTimeDensity,
|
|
dlsch_config->dlDmrsSymbPos);
|
|
int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity;
|
|
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols);
|
|
unav_res = n_ptrs * ptrsSymbPerSlot;
|
|
}
|
|
unav_res += compute_csi_rm_unav_res(dlsch_config);
|
|
G[DLSCH_id] = nr_get_G(dlsch_config->number_rbs, nb_symb_sch, nb_re_dmrs, dmrs_len, unav_res, dlsch_config->qamModOrder, dlsch[DLSCH_id].Nl);
|
|
|
|
start_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
|
|
nr_dlsch_unscrambling(llr[DLSCH_id], G[DLSCH_id], 0, dlsch[DLSCH_id].dlsch_config.dlDataScramblingId, dlsch[DLSCH_id].rnti);
|
|
stop_meas_nr_ue_phy(ue, DLSCH_UNSCRAMBLING_STATS);
|
|
|
|
p_b[DLSCH_id] = dl_harq->b;
|
|
}
|
|
|
|
start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
|
|
nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
|
|
stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
|
|
|
|
int ind_type = -1;
|
|
switch (dlsch[0].rnti_type) {
|
|
case TYPE_RA_RNTI_:
|
|
ind_type = FAPI_NR_RX_PDU_TYPE_RAR;
|
|
break;
|
|
|
|
case TYPE_SI_RNTI_:
|
|
ind_type = FAPI_NR_RX_PDU_TYPE_SIB;
|
|
break;
|
|
|
|
case TYPE_C_RNTI_:
|
|
ind_type = FAPI_NR_RX_PDU_TYPE_DLSCH;
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(true, "Invalid DLSCH type %d\n", dlsch[0].rnti_type);
|
|
break;
|
|
}
|
|
|
|
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
|
|
nr_fill_rx_indication(&rx_ind, ind_type, ue, &dlsch[0], NULL, number_pdus, proc, NULL, p_b[0]);
|
|
|
|
LOG_D(PHY, "DL PDU length in bits: %d, in bytes: %d \n", dlsch[0].dlsch_config.TBS, dlsch[0].dlsch_config.TBS / 8);
|
|
if (cpumeas(CPUMEAS_GETSTATE)) {
|
|
LOG_D(PHY,
|
|
" --> Unscrambling %5.3f\n",
|
|
ue->phy_cpu_stats.cpu_time_stats[DLSCH_UNSCRAMBLING_STATS].p_time / (cpuf * 1000.0));
|
|
LOG_D(PHY,
|
|
"AbsSubframe %d.%d --> LDPC Decoding %5.3f\n",
|
|
frame_rx % 1024,
|
|
nr_slot_rx,
|
|
ue->phy_cpu_stats.cpu_time_stats[DLSCH_DECODING_STATS].p_time / (cpuf * 1000.0));
|
|
}
|
|
|
|
// send to mac
|
|
if (ue->if_inst && ue->if_inst->dl_indication) {
|
|
ue->if_inst->dl_indication(&dl_indication);
|
|
}
|
|
|
|
// DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH
|
|
if ((dlsch[0].rnti_type == TYPE_C_RNTI_ || dlsch[0].rnti_type == TYPE_RA_RNTI_) && dlsch[0].dlsch_config.k1_feedback) {
|
|
const int ack_nack_slot_and_frame =
|
|
(proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
|
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
|
}
|
|
|
|
int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * NR_MAX_NB_LAYERS; // number of segments to be allocated
|
|
int num_rb = dlsch[0].dlsch_config.number_rbs;
|
|
if (num_rb != 273) {
|
|
a_segments = a_segments * num_rb;
|
|
a_segments = (a_segments / 273) + 1;
|
|
}
|
|
uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment
|
|
|
|
if (ue->phy_sim_dlsch_b && is_cw0_active == ACTIVE)
|
|
memcpy(ue->phy_sim_dlsch_b, p_b[0], dlsch_bytes);
|
|
else if (ue->phy_sim_dlsch_b && is_cw1_active == ACTIVE)
|
|
memcpy(ue->phy_sim_dlsch_b, p_b[1], dlsch_bytes);
|
|
|
|
}
|
|
|
|
static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index)
|
|
{
|
|
if (ue->received_config_request) {
|
|
const fapi_nr_config_request_t *cfg = &ue->nrUE_config;
|
|
const uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[index / 32].ssb_mask;
|
|
return ((curr_mask >> (31 - (index % 32))) & 0x01);
|
|
} else
|
|
return ue->frame_parms.ssb_index == index;
|
|
}
|
|
|
|
int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data)
|
|
{
|
|
TracyCZone(ctx, true);
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
int gNB_id = proc->gNB_id;
|
|
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
|
NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config;
|
|
int sampleShift = INT_MAX;
|
|
nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);
|
|
|
|
LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d ****** \n",
|
|
frame_rx%1024, nr_slot_rx);
|
|
|
|
const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP;
|
|
__attribute__ ((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz];
|
|
// checking if current frame is compatible with SSB periodicity
|
|
|
|
const int default_ssb_period = 2;
|
|
const int ssb_period = ue->received_config_request ? ue->nrUE_config.ssb_table.ssb_period : default_ssb_period;
|
|
if (ssb_period == 0 || !(frame_rx % (1 << (ssb_period - 1)))) {
|
|
const int estimateSz = fp->symbols_per_slot * fp->ofdm_symbol_size;
|
|
// loop over SSB blocks
|
|
for (int ssb_index = 0; ssb_index < fp->Lmax; ssb_index++) {
|
|
// check if current SSB is transmitted
|
|
if (is_ssb_index_transmitted(ue, ssb_index)) {
|
|
int ssb_start_symbol = nr_get_ssb_start_symbol(fp, ssb_index);
|
|
int ssb_slot = ssb_start_symbol/fp->symbols_per_slot;
|
|
int ssb_slot_2 = (ssb_period == 0) ? ssb_slot + (fp->slots_per_frame >> 1) : -1;
|
|
|
|
if (ssb_slot == nr_slot_rx || ssb_slot_2 == nr_slot_rx) {
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PBCH, VCD_FUNCTION_IN);
|
|
LOG_D(PHY," ------ PBCH ChannelComp/LLR: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx);
|
|
|
|
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[fp->nb_antennas_rx][estimateSz];
|
|
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[fp->nb_antennas_rx][fp->ofdm_symbol_size];
|
|
|
|
for (int i=1; i<4; i++) {
|
|
nr_slot_fep(ue,
|
|
fp,
|
|
proc->nr_slot_rx,
|
|
(ssb_start_symbol + i) % (fp->symbols_per_slot),
|
|
rxdataF,
|
|
link_type_dl,
|
|
0,
|
|
ue->common_vars.rxdata);
|
|
|
|
nr_pbch_channel_estimation(&ue->frame_parms,
|
|
NULL,
|
|
estimateSz,
|
|
dl_ch_estimates,
|
|
dl_ch_estimates_time,
|
|
proc,
|
|
(ssb_start_symbol + i) % (fp->symbols_per_slot),
|
|
i - 1,
|
|
ssb_index & 7,
|
|
ssb_slot_2 == nr_slot_rx,
|
|
fp->ssb_start_subcarrier,
|
|
rxdataF,
|
|
false,
|
|
fp->Nid_cell);
|
|
|
|
if (i - 1 == 2)
|
|
UEscopeCopy(ue,
|
|
pbchDlChEstimateTime,
|
|
(void *)dl_ch_estimates_time,
|
|
sizeof(c16_t),
|
|
fp->nb_antennas_rx,
|
|
fp->ofdm_symbol_size,
|
|
0);
|
|
}
|
|
|
|
nr_ue_ssb_rsrp_measurements(ue, ssb_index, proc, rxdataF);
|
|
|
|
// resetting ssb index for PBCH detection if there is a stronger SSB index
|
|
if(ue->measurements.ssb_rsrp_dBm[ssb_index] > ue->measurements.ssb_rsrp_dBm[fp->ssb_index])
|
|
fp->ssb_index = ssb_index;
|
|
|
|
if(ssb_index == fp->ssb_index) {
|
|
|
|
LOG_D(PHY," ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx);
|
|
const int pbchSuccess = nr_ue_pbch_procedures(ue, proc, estimateSz, dl_ch_estimates, rxdataF);
|
|
|
|
if (ue->no_timing_correction==0 && pbchSuccess == 0) {
|
|
LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction);
|
|
sampleShift =
|
|
nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384);
|
|
}
|
|
|
|
if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) {
|
|
double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates);
|
|
LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz, accumulated frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset, ue->freq_off_acc);
|
|
|
|
// PI controller
|
|
const double PID_P = get_nrUE_params()->freq_sync_P;
|
|
const double PID_I = get_nrUE_params()->freq_sync_I;
|
|
ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I;
|
|
ue->freq_off_acc += freq_offset;
|
|
}
|
|
}
|
|
LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
|
|
nr_ue_rrc_measurements(ue, proc, rxdataF);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PBCH, VCD_FUNCTION_OUT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for PRS slot - section 7.4.1.7.4 in 3GPP rel16 38.211
|
|
for(int gNB_id = 0; gNB_id < ue->prs_active_gNBs; gNB_id++)
|
|
{
|
|
for(int rsc_id = 0; rsc_id < ue->prs_vars[gNB_id]->NumPRSResources; rsc_id++)
|
|
{
|
|
prs_config_t *prs_config = &ue->prs_vars[gNB_id]->prs_resource[rsc_id].prs_cfg;
|
|
for (int i = 0; i < prs_config->PRSResourceRepetition; i++)
|
|
{
|
|
if( (((frame_rx*fp->slots_per_frame + nr_slot_rx) - (prs_config->PRSResourceSetPeriod[1] + prs_config->PRSResourceOffset) + prs_config->PRSResourceSetPeriod[0])%prs_config->PRSResourceSetPeriod[0]) == i*prs_config->PRSResourceTimeGap)
|
|
{
|
|
for(int j = prs_config->SymbolStart; j < (prs_config->SymbolStart+prs_config->NumPRSSymbols); j++)
|
|
{
|
|
nr_slot_fep(ue, fp, proc->nr_slot_rx, (j % fp->symbols_per_slot), rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
|
|
}
|
|
nr_prs_channel_estimation(gNB_id, rsc_id, i, ue, proc, fp, rxdataF);
|
|
}
|
|
} // for i
|
|
} // for rsc_id
|
|
} // for gNB_id
|
|
|
|
LOG_D(PHY," ------ --> PDCCH ChannelComp/LLR Frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_IN);
|
|
|
|
uint8_t nb_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.duration : 0;
|
|
int first_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.StartSymbolIndex : 0;
|
|
int last_symb_pdcch = first_symb_pdcch + nb_symb_pdcch;
|
|
for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) {
|
|
nr_slot_fep(ue, fp, proc->nr_slot_rx, l, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
|
|
}
|
|
|
|
// Hold the channel estimates in frequency domain.
|
|
int32_t pdcch_est_size = ((((fp->symbols_per_slot*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH))+15)/16)*16);
|
|
__attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[4 * fp->nb_antennas_rx][pdcch_est_size];
|
|
|
|
uint8_t dci_cnt = 0;
|
|
for(int n_ss = 0; n_ss<phy_pdcch_config->nb_search_space; n_ss++) {
|
|
for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) {
|
|
// note: this only works if RBs for PDCCH are contigous!
|
|
nr_pdcch_channel_estimation(ue,
|
|
proc,
|
|
l,
|
|
&phy_pdcch_config->pdcch_config[n_ss].coreset,
|
|
fp->first_carrier_offset,
|
|
phy_pdcch_config->pdcch_config[n_ss].BWPStart,
|
|
pdcch_est_size,
|
|
pdcch_dl_ch_estimates,
|
|
rxdataF);
|
|
}
|
|
dci_cnt = dci_cnt + nr_ue_pdcch_procedures(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, phy_data, n_ss, rxdataF);
|
|
}
|
|
LOG_D(PHY, "[UE %d] Frame %d, nr_slot_rx %d: found %d DCIs\n", ue->Mod_id, frame_rx, nr_slot_rx, dci_cnt);
|
|
phy_pdcch_config->nb_search_space = 0;
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_OUT);
|
|
TracyCZoneEnd(ctx);
|
|
return sampleShift;
|
|
}
|
|
|
|
void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data)
|
|
{
|
|
int frame_rx = proc->frame_rx;
|
|
int nr_slot_rx = proc->nr_slot_rx;
|
|
int gNB_id = proc->gNB_id;
|
|
|
|
NR_UE_DLSCH_t *dlsch = &phy_data->dlsch[0];
|
|
// do procedures for C-RNTI
|
|
|
|
bool slot_fep_map[14] = {0};
|
|
const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP;
|
|
__attribute__ ((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz];
|
|
|
|
// do procedures for CSI-IM
|
|
if (phy_data->csiim_vars.active == 1) {
|
|
for(int symb_idx = 0; symb_idx < 4; symb_idx++) {
|
|
int symb = phy_data->csiim_vars.csiim_config_pdu.l_csiim[symb_idx];
|
|
if (!slot_fep_map[symb]) {
|
|
nr_slot_fep(ue, &ue->frame_parms, proc->nr_slot_rx, symb, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
|
|
slot_fep_map[symb] = true;
|
|
}
|
|
}
|
|
nr_ue_csi_im_procedures(ue, proc, rxdataF, &phy_data->csiim_vars.csiim_config_pdu);
|
|
}
|
|
|
|
// do procedures for CSI-RS
|
|
if (phy_data->csirs_vars.active == 1) {
|
|
for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
|
|
if(is_csi_rs_in_symbol(phy_data->csirs_vars.csirs_config_pdu, symb)) {
|
|
if (!slot_fep_map[symb]) {
|
|
nr_slot_fep(ue, &ue->frame_parms, proc->nr_slot_rx, symb, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
|
|
slot_fep_map[symb] = true;
|
|
}
|
|
}
|
|
}
|
|
nr_ue_csi_rs_procedures(ue, proc, rxdataF, &phy_data->csirs_vars.csirs_config_pdu);
|
|
}
|
|
|
|
if (dlsch[0].active) {
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDSCH, VCD_FUNCTION_IN);
|
|
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[0].dlsch_config;
|
|
uint16_t nb_symb_sch = dlsch_config->number_symbols;
|
|
uint16_t start_symb_sch = dlsch_config->start_symbol;
|
|
|
|
LOG_D(PHY," ------ --> PDSCH ChannelComp/LLR Frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx);
|
|
|
|
for (int m = start_symb_sch; m < (nb_symb_sch + start_symb_sch) ; m++) {
|
|
if (!slot_fep_map[m]) {
|
|
nr_slot_fep(ue, &ue->frame_parms, proc->nr_slot_rx, m, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
|
|
slot_fep_map[m] = true;
|
|
}
|
|
}
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDSCH, VCD_FUNCTION_OUT);
|
|
|
|
uint8_t nb_re_dmrs;
|
|
if (dlsch_config->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) {
|
|
nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups;
|
|
}
|
|
else {
|
|
nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups;
|
|
}
|
|
uint16_t dmrs_len = get_num_dmrs(dlsch_config->dlDmrsSymbPos);
|
|
uint32_t unav_res = 0;
|
|
if(dlsch_config->pduBitmap & 0x1) {
|
|
uint16_t ptrsSymbPos = 0;
|
|
set_ptrs_symb_idx(&ptrsSymbPos,
|
|
dlsch_config->number_symbols,
|
|
dlsch_config->start_symbol,
|
|
1 << dlsch_config->PTRSTimeDensity,
|
|
dlsch_config->dlDmrsSymbPos);
|
|
int n_ptrs = (dlsch_config->number_rbs + dlsch_config->PTRSFreqDensity - 1) / dlsch_config->PTRSFreqDensity;
|
|
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ptrsSymbPos, dlsch_config->start_symbol, dlsch_config->number_symbols);
|
|
unav_res = n_ptrs * ptrsSymbPerSlot;
|
|
}
|
|
unav_res += compute_csi_rm_unav_res(dlsch_config);
|
|
int G = nr_get_G(dlsch_config->number_rbs,
|
|
dlsch_config->number_symbols,
|
|
nb_re_dmrs,
|
|
dmrs_len,
|
|
unav_res,
|
|
dlsch_config->qamModOrder,
|
|
dlsch[0].Nl);
|
|
const uint32_t rx_llr_buf_sz = ((G + 15) / 16) * 16;
|
|
const uint32_t nb_codewords = NR_MAX_NB_LAYERS > 4 ? 2 : 1;
|
|
int16_t* llr[2];
|
|
for (int i = 0; i < nb_codewords; i++)
|
|
llr[i] = (int16_t *)malloc16_clear(rx_llr_buf_sz * sizeof(int16_t));
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_C, VCD_FUNCTION_IN);
|
|
// it returns -1 in case of internal failure, or 0 in case of normal result
|
|
int ret_pdsch = nr_ue_pdsch_procedures(ue, proc, dlsch, llr, rxdataF, G);
|
|
TracyCPlot("pdsch mcs", dlsch->dlsch_config.mcs);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_C, VCD_FUNCTION_OUT);
|
|
|
|
UEscopeCopy(ue, pdschLlr, llr[0], sizeof(int16_t), 1, G, 0);
|
|
|
|
LOG_D(PHY, "DLSCH data reception at nr_slot_rx: %d\n", nr_slot_rx);
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
|
|
|
|
start_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS);
|
|
|
|
if (ret_pdsch >= 0) {
|
|
nr_ue_dlsch_procedures(ue, proc, dlsch, llr);
|
|
}
|
|
else {
|
|
LOG_E(NR_PHY, "Demodulation impossible, internal error\n");
|
|
if (dlsch_config->k1_feedback) {
|
|
const int ack_nack_slot_and_frame =
|
|
proc->nr_slot_rx + dlsch_config->k1_feedback + proc->frame_rx * ue->frame_parms.slots_per_frame;
|
|
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
|
|
}
|
|
LOG_W(NR_PHY, "nr_ue_pdsch_procedures failed in slot %d\n", proc->nr_slot_rx);
|
|
}
|
|
|
|
stop_meas_nr_ue_phy(ue, DLSCH_PROCEDURES_STATS);
|
|
if (cpumeas(CPUMEAS_GETSTATE)) {
|
|
LOG_D(PHY, "[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",nr_slot_rx,ue->phy_cpu_stats.cpu_time_stats[DLSCH_PROCEDURES_STATS].p_time/(cpuf*1000.0));
|
|
}
|
|
|
|
if (ue->phy_sim_rxdataF)
|
|
memcpy(ue->phy_sim_rxdataF, rxdataF, sizeof(int32_t)*rxdataF_sz*ue->frame_parms.nb_antennas_rx);
|
|
if (ue->phy_sim_pdsch_llr)
|
|
memcpy(ue->phy_sim_pdsch_llr, llr[0], sizeof(int16_t)*rx_llr_buf_sz);
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
|
|
for (int i=0; i<nb_codewords; i++)
|
|
free(llr[i]);
|
|
}
|
|
|
|
if (nr_slot_rx==9) {
|
|
if (frame_rx % 10 == 0) {
|
|
if ((ue->dlsch_received[gNB_id] - ue->dlsch_received_last[gNB_id]) != 0)
|
|
ue->dlsch_fer[gNB_id] = (100*(ue->dlsch_errors[gNB_id] - ue->dlsch_errors_last[gNB_id]))/(ue->dlsch_received[gNB_id] - ue->dlsch_received_last[gNB_id]);
|
|
|
|
ue->dlsch_errors_last[gNB_id] = ue->dlsch_errors[gNB_id];
|
|
ue->dlsch_received_last[gNB_id] = ue->dlsch_received[gNB_id];
|
|
}
|
|
|
|
|
|
ue->bitrate[gNB_id] = (ue->total_TBS[gNB_id] - ue->total_TBS_last[gNB_id])*100;
|
|
ue->total_TBS_last[gNB_id] = ue->total_TBS[gNB_id];
|
|
LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n",
|
|
ue->Mod_id,frame_rx,ue->total_TBS[gNB_id],
|
|
ue->total_TBS_last[gNB_id],(float) ue->bitrate[gNB_id]/1000.0);
|
|
|
|
#if UE_AUTOTEST_TRACE
|
|
if ((frame_rx % 100 == 0)) {
|
|
LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[gNB_id]/1000.0, frame_rx);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef EMOS
|
|
phy_procedures_emos_UE_RX(ue,slot,gNB_id);
|
|
#endif
|
|
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);
|
|
|
|
LOG_D(PHY," ****** end RX-Chain for AbsSubframe %d.%d ****** \n", frame_rx%1024, nr_slot_rx);
|
|
UEscopeCopy(ue, commonRxdataF, rxdataF, sizeof(int32_t), ue->frame_parms.nb_antennas_rx, rxdataF_sz, 0);
|
|
}
|
|
|
|
|
|
// todo:
|
|
// - power control as per 38.213 ch 7.4
|
|
static void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txData)
|
|
{
|
|
int gNB_id = proc->gNB_id;
|
|
int frame_tx = proc->frame_tx, nr_slot_tx = proc->nr_slot_tx, prach_power; // tx_amp
|
|
uint8_t mod_id = ue->Mod_id;
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN);
|
|
|
|
NR_UE_PRACH *prach_var = ue->prach_vars[gNB_id];
|
|
if (prach_var->active) {
|
|
fapi_nr_ul_config_prach_pdu *prach_pdu = &prach_var->prach_pdu;
|
|
// Generate PRACH in first slot. For L839, the following slots are also filled in this slot.
|
|
if (prach_pdu->prach_slot == nr_slot_tx) {
|
|
ue->tx_power_dBm[nr_slot_tx] = prach_pdu->prach_tx_power;
|
|
|
|
LOG_D(PHY,
|
|
"In %s: [UE %d][RAPROC][%d.%d]: Generating PRACH Msg1 (preamble %d, P0_PRACH %d)\n",
|
|
__FUNCTION__,
|
|
mod_id,
|
|
frame_tx,
|
|
nr_slot_tx,
|
|
prach_pdu->ra_PreambleIndex,
|
|
ue->tx_power_dBm[nr_slot_tx]);
|
|
|
|
prach_var->amp = AMP;
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_IN);
|
|
|
|
start_meas_nr_ue_phy(ue, PRACH_GEN_STATS);
|
|
prach_power = generate_nr_prach(ue, gNB_id, frame_tx, nr_slot_tx, txData);
|
|
stop_meas_nr_ue_phy(ue, PRACH_GEN_STATS);
|
|
if (cpumeas(CPUMEAS_GETSTATE)) {
|
|
LOG_D(PHY,
|
|
"[SFN %d.%d] PRACH Proc %5.2f\n",
|
|
proc->frame_tx,
|
|
proc->nr_slot_tx,
|
|
ue->phy_cpu_stats.cpu_time_stats[PRACH_GEN_STATS].p_time / (cpuf * 1000.0));
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT);
|
|
|
|
LOG_D(PHY,
|
|
"In %s: [UE %d][RAPROC][%d.%d]: Generated PRACH Msg1 (TX power PRACH %d dBm, digital power %d dBW (amp %d)\n",
|
|
__FUNCTION__,
|
|
mod_id,
|
|
frame_tx,
|
|
nr_slot_tx,
|
|
ue->tx_power_dBm[nr_slot_tx],
|
|
dB_fixed(prach_power),
|
|
ue->prach_vars[gNB_id]->amp);
|
|
|
|
// set duration of prach slots so we know when to skip OFDM modulation
|
|
const int prach_format = ue->prach_vars[gNB_id]->prach_pdu.prach_format;
|
|
const int prach_slots = (prach_format < 4) ? get_long_prach_dur(prach_format, ue->frame_parms.numerology_index) : 1;
|
|
prach_var->num_prach_slots = prach_slots;
|
|
}
|
|
|
|
// set as inactive in the last slot
|
|
prach_var->active = !(nr_slot_tx == (prach_pdu->prach_slot + prach_var->num_prach_slots - 1));
|
|
}
|
|
|
|
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT);
|
|
|
|
}
|