diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 70c2d88e82e57f101dfe863bb0247474968cc4f8..0dc849d2d643abacdba863b3114777dc353c2823 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1243,6 +1243,12 @@ set(PHY_SRC_UE # actual source ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c ${OPENAIR1_DIR}/PHY/INIT/nr_parms.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/pss_nr.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/sss_nr.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dmrs_nr.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/ul_ref_seq_nr.c ${OPENAIR1_DIR}/PHY/TOOLS/file_output.c ${OPENAIR1_DIR}/PHY/TOOLS/cadd_vv.c ${OPENAIR1_DIR}/PHY/TOOLS/lte_dfts.c @@ -2160,6 +2166,76 @@ target_link_libraries (nr-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRY target_link_libraries (nr-softmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (nr-softmodem ${T_LIB}) +# nr-uesoftmodem is UE implementation +####################################### + +add_executable(nr-uesoftmodem + ${rrc_h} + ${s1ap_h} + ${OPENAIR_BIN_DIR}/messages_xml.h + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_TARGETS}/RT/USER/nr-ue.c + ${OPENAIR_TARGETS}/RT/USER/nr-uesoftmodem.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c + ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c + ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c + ${XFORMS_SOURCE} + ${XFORMS_SOURCE_SOFTMODEM} + ${T_SOURCE} + ${CONFIG_SOURCES} + ${SHLIB_LOADER_SOURCES} + ) + +target_link_libraries (nr-uesoftmodem + -Wl,--start-group + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_NR_UE PHY_COMMON PHY_UE PHY_RU LFDS L2_UE + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 + -Wl,--end-group z dl) + +target_link_libraries (nr-uesoftmodem ${LIBXML2_LIBRARIES}) +target_link_libraries (nr-uesoftmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (nr-uesoftmodem ${LIB_LMS_LIBRARIES}) +target_link_libraries (nr-uesoftmodem ${T_LIB}) + +# nr-uesoftmodem is UE implementation +####################################### + +add_executable(nr-uesoftmodem-nos1 + ${rrc_h} + ${s1ap_h} +# ${OPENAIR_BIN_DIR}/messages_xml.h + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_TARGETS}/RT/USER/nr-ue.c + ${OPENAIR_TARGETS}/RT/USER/nr-uesoftmodem.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c + ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c + ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c + ${XFORMS_SOURCE} + ${XFORMS_SOURCE_SOFTMODEM} + ${T_SOURCE} + ${CONFIG_SOURCES} + ${SHLIB_LOADER_SOURCES} + ) + +target_link_libraries (nr-uesoftmodem-nos1 + -Wl,--start-group + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB PHY_NR_UE PHY_COMMON PHY_UE PHY_RU LFDS L2_UE + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 + -Wl,--end-group z dl) + +target_link_libraries (nr-uesoftmodem-nos1 ${LIBXML2_LIBRARIES}) +target_link_libraries (nr-uesoftmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (nr-uesoftmodem-nos1 ${LIB_LMS_LIBRARIES}) +target_link_libraries (nr-uesoftmodem-nos1 ${T_LIB}) + # USIM process ################# #add_executable(usim diff --git a/openair1/PHY/MODULATION/modulation_UE.h b/openair1/PHY/MODULATION/modulation_UE.h index 7e2a3c8a27778f75b59866ea60392916baf9c684..92afcea7246f6f8e097cf1ba25b11a5427fd6009 100644 --- a/openair1/PHY/MODULATION/modulation_UE.h +++ b/openair1/PHY/MODULATION/modulation_UE.h @@ -23,6 +23,8 @@ #define __MODULATION_DEFS__H__ #include "PHY/defs_common.h" #include "modulation_common.h" +#include "PHY/defs_UE.h" +#include "PHY/defs_nr_UE.h" /** @addtogroup _PHY_MODULATION_ * @{ */ @@ -46,6 +48,13 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, int no_prefix, int reset_freq_est); +int slot_fep_pbch(PHY_VARS_NR_UE *phy_vars_ue, + unsigned char l, + unsigned char Ns, + int sample_offset, + int no_prefix, + int reset_freq_est); + int slot_fep_mbsfn(PHY_VARS_UE *phy_vars_ue, unsigned char l, int subframe, diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index b01979431dcf88212604aa71cf0d0470eb177d06..3b5a2f1840f6e9c240464b35d3bc3c3e26e565f9 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -20,6 +20,7 @@ */ #include "PHY/defs_UE.h" +#include "PHY/defs_nr_UE.h" #include "modulation_UE.h" #include "PHY/LTE_ESTIMATION/lte_estimation.h" @@ -27,6 +28,207 @@ #define SOFFSET 0 +int slot_fep_pbch(PHY_VARS_NR_UE *ue, + unsigned char l, + unsigned char Ns, + int sample_offset, + int no_prefix, + int reset_freq_est) +{ + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + NR_UE_COMMON *common_vars = &ue->common_vars; + uint8_t eNB_id = 0;//ue_common_vars->eNb_id; + unsigned char aa; + unsigned char symbol = l+((7-frame_parms->Ncp)*(Ns&1)); ///symbol within sub-frame + unsigned int nb_prefix_samples = (no_prefix ? 0 : frame_parms->nb_prefix_samples); + unsigned int nb_prefix_samples0 = (no_prefix ? 0 : frame_parms->nb_prefix_samples0); + unsigned int subframe_offset;//,subframe_offset_F; + unsigned int slot_offset; + int i; + unsigned int frame_length_samples = frame_parms->samples_per_subframe * 10; + unsigned int rx_offset; + + /*LTE_UE_DLSCH_t **dlsch_ue = phy_vars_ue->dlsch_ue[eNB_id]; + unsigned char harq_pid = dlsch_ue[0]->current_harq_pid; + LTE_DL_UE_HARQ_t *dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; + int uespec_pilot[9][1200];*/ + + void (*dft)(int16_t *,int16_t *, int); + int tmp_dft_in[2048] __attribute__ ((aligned (32))); // This is for misalignment issues for 6 and 15 PRBs + + switch (frame_parms->ofdm_symbol_size) { + case 128: + dft = dft128; + break; + + case 256: + dft = dft256; + break; + + case 512: + dft = dft512; + break; + + case 1024: + dft = dft1024; + break; + + case 1536: + dft = dft1536; + break; + + case 2048: + dft = dft2048; + break; + + default: + dft = dft512; + break; + } + + if (no_prefix) { + subframe_offset = frame_parms->ofdm_symbol_size * frame_parms->symbols_per_tti * (Ns>>1); + slot_offset = frame_parms->ofdm_symbol_size * (frame_parms->symbols_per_tti>>1) * (Ns%2); + } else { + subframe_offset = frame_parms->samples_per_tti * (Ns>>1); + slot_offset = (frame_parms->samples_per_tti>>1) * (Ns%2); + } + + if (l<0 || l>=7-frame_parms->Ncp) { + printf("slot_fep: l must be between 0 and %d\n",7-frame_parms->Ncp); + return(-1); + } + + if (Ns<0 || Ns>=20) { + printf("slot_fep: Ns must be between 0 and 19\n"); + return(-1); + } + + + + for (aa=0; aa<frame_parms->nb_antennas_rx; aa++) { + memset(&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],0,frame_parms->ofdm_symbol_size*sizeof(int)); + + rx_offset = sample_offset + slot_offset + nb_prefix_samples0 + subframe_offset - SOFFSET; + // Align with 256 bit + // rx_offset = rx_offset&0xfffffff8; + + if (l==0) { + + if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) + memcpy((short *)&common_vars->rxdata[aa][frame_length_samples], + (short *)&common_vars->rxdata[aa][0], + frame_parms->ofdm_symbol_size*sizeof(int)); + + if ((rx_offset&7)!=0) { // if input to dft is not 256-bit aligned, issue for size 6,15 and 25 PRBs + memcpy((void *)tmp_dft_in, + (void *)&common_vars->rxdata[aa][rx_offset % frame_length_samples], + frame_parms->ofdm_symbol_size*sizeof(int)); + dft((int16_t *)tmp_dft_in, + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } else { // use dft input from RX buffer directly +#if UE_TIMING_TRACE + start_meas(&ue->rx_dft_stats); +#endif + + dft((int16_t *)&common_vars->rxdata[aa][(rx_offset) % frame_length_samples], + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); +#if UE_TIMING_TRACE + stop_meas(&ue->rx_dft_stats); +#endif + + } + } else { + rx_offset += (frame_parms->ofdm_symbol_size+nb_prefix_samples)*l;// + + // (frame_parms->ofdm_symbol_size+nb_prefix_samples)*(l-1); + +#ifdef DEBUG_FEP + // if (ue->frame <100) + LOG_I(PHY,"slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %d, nb_prefix_samples0 %d, slot_offset %d, subframe_offset %d, sample_offset %d,rx_offset %d, frame_length_samples %d\n", ue->proc.proc_rxtx[(Ns>>1)&1].frame_rx,Ns, symbol, + nb_prefix_samples,nb_prefix_samples0,slot_offset,subframe_offset,sample_offset,rx_offset,frame_length_samples); +#endif + + if (rx_offset > (frame_length_samples - frame_parms->ofdm_symbol_size)) + memcpy((void *)&common_vars->rxdata[aa][frame_length_samples], + (void *)&common_vars->rxdata[aa][0], + frame_parms->ofdm_symbol_size*sizeof(int)); +#if UE_TIMING_TRACE + start_meas(&ue->rx_dft_stats); +#endif + + if ((rx_offset&7)!=0) { // if input to dft is not 128-bit aligned, issue for size 6 and 15 PRBs + memcpy((void *)tmp_dft_in, + (void *)&common_vars->rxdata[aa][(rx_offset) % frame_length_samples], + frame_parms->ofdm_symbol_size*sizeof(int)); + dft((int16_t *)tmp_dft_in, + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } else { // use dft input from RX buffer directly + + dft((int16_t *)&common_vars->rxdata[aa][(rx_offset) % frame_length_samples], + (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],1); + } +#if UE_TIMING_TRACE + stop_meas(&ue->rx_dft_stats); +#endif + + + } + + #ifdef DEBUG_FEP + // if (ue->frame <100) + printf("slot_fep: frame %d: symbol %d rx_offset %d\n", ue->proc.proc_rxtx[(Ns>>1)&1].frame_rx, symbol,rx_offset); + #endif + } + + if (ue->perfect_ce == 0) { + if ((l==0) || (l==(4-frame_parms->Ncp))) { + for (aa=0; aa<frame_parms->nb_antenna_ports_eNB; aa++) { + +#ifdef DEBUG_FEP + printf("Channel estimation eNB %d, aatx %d, slot %d, symbol %d\n",eNB_id,aa,Ns,l); +#endif +#if UE_TIMING_TRACE + start_meas(&ue->dlsch_channel_estimation_stats); +#endif + /* nr_pbch_channel_estimation(ue,eNB_id,0, + Ns, + aa, + l, + symbol);*/ + } + + + // do frequency offset estimation here! + // use channel estimates from current symbol (=ch_t) and last symbol (ch_{t-1}) +#ifdef DEBUG_FEP + printf("Frequency offset estimation\n"); +#endif + + if (l==(4-frame_parms->Ncp)) { + +#if UE_TIMING_TRACE + start_meas(&ue->dlsch_freq_offset_estimation_stats); +#endif + + /*lte_est_freq_offset(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns>>1]].dl_ch_estimates[0], + frame_parms, + l, + &common_vars->freq_offset, + reset_freq_est);*/ +#if UE_TIMING_TRACE + stop_meas(&ue->dlsch_freq_offset_estimation_stats); +#endif + + } + } + + } + +#ifdef DEBUG_FEP + printf("slot_fep: done\n"); +#endif + return(0); +} int slot_fep(PHY_VARS_UE *ue, unsigned char l, diff --git a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..1a64c8902c9ad89038a9a73e0b92bdf1cdd81e73 --- /dev/null +++ b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.c @@ -0,0 +1,234 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : ul_ref_seq_nr.c +* +* MODULE : generation of uplink reference sequence for nr +* +* DESCRIPTION : function to generate uplink reference sequences +* see 3GPP TS 38.211 5.2.2 Low-PAPR sequence generation +* +************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "defs.h" + +#define DEFINE_VARIABLES_LOWPAPR_SEQUENCES_NR_H +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" +#undef DEFINE_VARIABLES_LOWPAPR_SEQUENCES_NR_H + +/******************************************************************* +* +* NAME : base_sequence_less_3_RB +* +* PARAMETERS : M_ZC length of Zadoff Chu sequence +* u sequence group number +* scaling to apply +* +* RETURN : pointer to generated sequence +* +* DESCRIPTION : base sequence generation of less than 36 elements +* see TS 38.211 5.2.2.2 Base sequences of length less than 36 +* +*********************************************************************/ + +int16_t *base_sequence_less_than_36(unsigned int M_ZC, unsigned int u, unsigned int scaling) +{ + char *phi_table; + int16_t *rv_overbar; + double x; + unsigned int n; + + switch(M_ZC) { + case 6: + phi_table = (char *)phi_M_ZC_6; + break; + case 12: + phi_table = (char *)phi_M_ZC_12; + break; + case 18: + phi_table = (char *)phi_M_ZC_18; + break; + case 24: + phi_table = (char *)phi_M_ZC_24; + break; + case 30: + break; + default: + printf("function base_sequence_less_than 36_: unsupported base sequence size : %d \n", M_ZC); + assert(0); + break; + } + + rv_overbar = malloc16(IQ_SIZE*M_ZC); + + if (rv_overbar == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + if (M_ZC == 30) { + for (n=0; n<M_ZC; n++) { + x = -(M_PI * (u + 1) * (n + 1) * (n + 2))/(double)31; + rv_overbar[2*n] =(int16_t)(floor(scaling*cos(x))); + rv_overbar[2*n+1] =(int16_t)(floor(scaling*sin(x))); + } + } + else { + for (n=0; n<M_ZC; n++) { + x = (double)phi_table[n + u*M_ZC] * (M_PI/4); + rv_overbar[2*n] = (int16_t)(floor(scaling*cos(x))); + rv_overbar[2*n+1] = (int16_t)(floor(scaling*sin(x))); + } + } + return rv_overbar; +} + +/******************************************************************* +* +* NAME : base_sequence_36_or_larger +* +* PARAMETERS : M_ZC length of Zadoff chu sequence +* u sequence group number +* scaling to apply +* +* RETURN : pointer to generated sequence +* +* DESCRIPTION : base sequence generation of less than 36 elements +* 5.2.2.1 Base sequences of length 36 or larger +* +*********************************************************************/ + +int16_t *base_sequence_36_or_larger(unsigned int Msc_RS, unsigned int u, unsigned int v, unsigned int scaling) +{ + int16_t *rv_overbar; + unsigned int N_ZC; + double q_overbar, x; + unsigned int q,m,n; + unsigned int M_ZC = ul_allocated_re[Msc_RS]; + + rv_overbar = malloc16(IQ_SIZE*M_ZC); + if (rv_overbar == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + N_ZC = ref_ul_primes[Msc_RS]; /* The length N_ZC is given by the largest prime number such that N_ZC < M_ZC */ + + q_overbar = N_ZC * (u+1)/(double)31; + + /* q = (q_overbar + 1/2) + v.(-1)^(2q_overbar) */ + if ((((int)floor(2*q_overbar))&1) == 0) + q = (int)(floor(q_overbar+.5)) - v; + else + q = (int)(floor(q_overbar+.5)) + v; + + for (n = 0; n < M_ZC; n++) { + m=n%N_ZC; + x = (double)q * m * (m+1)/N_ZC; + rv_overbar[2*n] = (int16_t)(floor(scaling*cos(M_PI*x))); /* cos(-x) = cos(x) */ + rv_overbar[2*n+1] = -(int16_t)(floor(scaling*sin(M_PI*x))); /* sin(-x) = -sin(x) */ + } + return rv_overbar; +} + +/******************************************************************* +* +* NAME : generate_ul_srs_sequences +* +* PARAMETERS : scaling to apply +* +* RETURN : none +* +* DESCRIPTION : uplink reference signal sequences generation +* which are Low-PAPR base sequences +* see TS 38.211 5.2.2 Low-PAPR sequence generation +* +*********************************************************************/ + +void generate_ul_reference_signal_sequences(unsigned int scaling) +{ + unsigned int u,v,Msc_RS; + +#if 0 + + char output_file[255]; + char sequence_name[255]; + +#endif + + for (Msc_RS=0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) { + v = 0; + for (u=0; u < U_GROUP_NUMBER; u++) { + rv_ul_ref_sig[u][v][Msc_RS] = base_sequence_less_than_36(ul_allocated_re[Msc_RS], u, scaling); +#if 0 + sprintf(output_file, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); + sprintf(sequence_name, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); + printf("u %d Msc_RS %d allocate memory %x of size %d \n", u, Msc_RS, rv_ul_ref_sig[u][v][Msc_RS], (IQ_SIZE* ul_allocated_re[Msc_RS])); + write_output(output_file, sequence_name, rv_ul_ref_sig[u][v][Msc_RS], ul_allocated_re[Msc_RS], 1, 1); + +#endif + } + } + + for (Msc_RS=INDEX_SB_LESS_32+1; Msc_RS < SRS_SB_CONF; Msc_RS++) { + for (u=0; u < U_GROUP_NUMBER; u++) { + for (v=0; v < V_BASE_SEQUENCE_NUMBER; v++) { + rv_ul_ref_sig[u][v][Msc_RS] = base_sequence_36_or_larger(Msc_RS, u, v, scaling); +#if 0 + sprintf(output_file, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); + sprintf(sequence_name, "rv_seq_%d_%d_%d.m", u, v, ul_allocated_re[Msc_RS]); + printf("u %d Msc_RS %d allocate memory %x of size %d \n", u, Msc_RS, rv_ul_ref_sig[u][v][Msc_RS], (IQ_SIZE* ul_allocated_re[Msc_RS])); + write_output(output_file, sequence_name, rv_ul_ref_sig[u][v][Msc_RS], ul_allocated_re[Msc_RS], 1, 1); + +#endif + } + } + } +} + +/******************************************************************* +* +* NAME : free_ul_reference_signal_sequences +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : free of uplink reference signal sequences +* +*********************************************************************/ +void free_ul_reference_signal_sequences(void) +{ + unsigned int u,v,Msc_RS; + for (Msc_RS=0; Msc_RS < SRS_SB_CONF; Msc_RS++) { + for (u=0; u < U_GROUP_NUMBER; u++) { + for (v=0; v < V_BASE_SEQUENCE_NUMBER; v++) { + if (rv_ul_ref_sig[u][v][Msc_RS]) + free16(rv_ul_ref_sig[u][v][Msc_RS],2*sizeof(int16_t)*ul_allocated_re[Msc_RS]); + } + } + } +} diff --git a/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..dd967e8e5e6339478c9287bd1b352c2654042e36 --- /dev/null +++ b/openair1/PHY/NR_REFSIG/ul_ref_seq_nr.h @@ -0,0 +1,271 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : ul_ref_seq_nr.hh +* +* MODULE : generation of uplink reference sequence for nr +* +* DESCRIPTION : variables to generate sequences with low peak to average power +* see 3GPP TS 38.211 5.2.2 Low-PAPR sequence generation +* +************************************************************************/ + +#ifndef LOWPAPR_SEQUENCES_NR_H +#define LOWPAPR_SEQUENCES_NR_H + +#include "PHY/defs_nr_UE.h" +#include "PHY/types.h" + +#include "PHY/NR_REFSIG/ss_pbch_nr.h" + +#ifdef DEFINE_VARIABLES_LOWPAPR_SEQUENCES_NR_H +#define EXTERN +#define INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H +#else +#define EXTERN extern +#endif + +/************** DEFINE ********************************************/ +#define U_GROUP_NUMBER (30) /* maximum number of sequence-group */ +#define V_BASE_SEQUENCE_NUMBER (2) /* maximum number of base sequences */ +#define SRS_SB_CONF (71) /* maximum number of configuration for srs subcarrier allocation */ + +/************** VARIABLES *****************************************/ + +#define INDEX_SB_LESS_32 (4) /* index of dftsizes array for which subcarrier number is less than 36 */ + +const uint16_t ul_allocated_re[SRS_SB_CONF] /* number of uplink allocated resource elements */ +/* this table is derivated from TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration which gives m_SRS_b then all possible values of sequence length is */ +/* M_sc_b_SRS = m_SRS_b * N_SC_RB/K_TC with K_TC = 2 or K_TC = 4 as specified in TS 38.211 6.4.1.4.3 */ +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { /* +K_TC 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +m_SRS_b 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 */ + 6, 12, 18, 24, 30, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, +/* +K_TC 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 6 3 3 +m_SRS_b 84 88 92 96 100 104 108 112 116 120 128 132 136 144 152 160 168 176 184 192 100 208 216 */ + 252, 264, 276, 288, 300, 312, 324, 336, 348, 360, 384, 396, 408, 432, 456, 480, 504, 528, 552, 576, 600, 624, 648, +/* +K_TC 3 6 3 3 3 3 6 6 6 6 6 6 6 6 6 6 6 6 6 6 +m_SRS_b 224 116, 240 256 264 272 144 152 160 168 176 184 192 208 216 224 240 256 264 272 */ + 672, 696, 720, 768, 792, 816, 864, 912, 960, 1008, 1056, 1104, 1152, 1248, 1296, 1344, 1440, 1536, 1584, 1632, + +/* below numbers have been added just to include all possible lengths already used for lte */ + 540, 900, 972, 1080, 1200, +} +#endif +; + +/* table of largest prime number lower than uplink allocated resource elements "ul_allocated_re" */ +const uint16_t ref_ul_primes[SRS_SB_CONF] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/* 6, 12, 18, 24, 30, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, */ + 5, 11, 17, 23, 29, 31, 47, 59, 71, 83, 89, 107, 113, 127, 139, 151, 167, 179, 191, 199, 211, 227, 239, + +/* 252, 264, 276, 288, 300, 312, 324, 336, 348, 360, 384, 396, 408, 432, 456, 480, 504, 528, 552, 576, 600, 624, 648, */ + 251, 263, 271, 283, 293, 311, 317, 331, 347, 359, 383, 389, 401, 431, 449, 479, 503, 523, 547, 571, 599, 619, 647, + +/* 672, 696, 720, 768, 792, 816, 864, 912, 960, 1008, 1056, 1104, 1152, 1248, 1296, 1344, 1440, 1536, 1584, 1632, */ + 661, 691, 719, 761, 787, 811, 863, 911, 953, 997, 1051, 1103, 1151, 1237, 1291, 1327, 1439, 1531, 1583, 1627, + +/* 540, 900, 972, 1080, 1200, */ + 523, 887, 971, 1069, 1193, +} +#endif +; + +/* Low-PAPR base sequence; see TS 38.211 clause 5.2.2 */ +int16_t *rv_ul_ref_sig[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][SRS_SB_CONF]; + +/* 38.211 table Table 5.2.2.2-1: Definition of phi(n) for M_ZC = 6 */ +const char phi_M_ZC_6[6*U_GROUP_NUMBER] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/* 0 1 2 3 4 5 */ +/* 0 */ -3, -1, 3, 3, -1, -3, +/* 1 */ -3, 3, -1, -1, 3, -3, +/* 2 */ -3, -3, -3, 3, 1, -3, +/* 3 */ 1, 1, 1, 3, -1, -3, +/* 4 */ 1, 1, 1, -3, -1, 3, +/* 5 */ -3, 1, -1, -3, -3, -3, +/* 6 */ -3, 1, 3, -3, -3, -3, +/* 7 */ -3, -1, 1, -3, 1, -1, +/* 8 */ -3, -1, -3, 1, -3, -3, +/* 9 */ -3, -3, 1, -3, 3, -3, +/* 10 */ -3, 1, 3, 1, -3, -3, +/* 11 */ -3, -1, -3, 1, 1, -3, +/* 12 */ 1, 1, 3, -1, -3, 3, +/* 13 */ 1, 1, 3, 3, -1, 3, +/* 14 */ 1, 1, 1, -3, 3, -1, +/* 15 */ -1, 1, 1, -1, 3, -3, +/* 16 */ -3, -1, -1, -1, 3, -1, +/* 17 */ -3, -3, -1, 1, -1, -3, +/* 18 */ -3, -3, -3, 1, -3, -1, +/* 19 */ -3, 1, 1, -3, -1, -3, +/* 20 */ -3, 3, -3, 1, 1, -3, +/* 21 */ -3, 1, -3, -3, -3, -1, +/* 22 */ 1, 1, -3, 3, 1, 3, +/* 23 */ 1, 1, -3, -3, 1, -3, +/* 24 */ 1, 1, 3, -1, 3, 3, +/* 25 */ 1, 1, -3, 1, 3, 3, +/* 26 */ 1, 1, -1, -1, 3, -1, +/* 27 */ 1, 1, -1, 3, -1, -1, +/* 28 */ 1, 1, -1, 3, -3, -1, +/* 29 */ 1, 1, -3, 1, -1, -1, +} +#endif +; +/* Table 5.2.2.2-2: Definition of phi ( n ) for M ZC = 12 */ +const char phi_M_ZC_12[12*U_GROUP_NUMBER] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/* 0 1 2 3 4 5 6 7 8 9 10 11 */ +/* 0 */ 1, -1, 3, 1, 1, -1, -1, -1, 1, 3, -3, 1, +/* 1 */ -1, -1, -1, -1, 1, -3, -1, 3, 3, -1, -3, 1, +/* 2 */ -3, 1, -3, -3, -3, 3, -3, -1, 1, 1, 1, -3, +/* 3 */ -3, 3, 1, 3, -3, 1, 1, 1, 1, 3, -3, 3, +/* 4 */ -3, 1, 3, -1, -1, -3, -3, -1, -1, 3, 1, -3, +/* 5 */ -1, 1, 1, -1, 1, 3, 3, -1, -1, -3, 1, -3, +/* 6 */ -3, -3, -1, 3, 3, 3, -3, 3, -3, 1, -1, -3, +/* 7 */ -3, 3, -3, 3, 3, -3, -1, -1, 3, 3, 1, -3, +/* 8 */ -3, -1, -3, -1, -1, -3, 3, 3, -1, -1, 1, -3, +/* 9 */ -3, 3, 3, 3, -1, -3, -3, -1, -3, 1, 3, -3, +/* 10 */ 1, 3, -3, 1, 3, 3, 3, 1, -1, 1, -1, 3, +/* 11 */ -1, -3, 3, -1, -3, -3, -3, -1, 1, -1, 1, -3, +/* 12 */ 3, 1, 3, 1, 3, -3, -1, 1, 3, 1, -1, -3, +/* 13 */ -3, -3, 3, 3, 3, -3, -1, 1, -3, 3, 1, -3, +/* 14 */ -3, -1, 1, -3, 1, 3, 3, 3, -1, -3, 3, 3, +/* 15 */ -3, -3, 3, 1, -3, -3, -3, -1, 3, -1, 1, 3, +/* 16 */ -1, 1, 3, -3, 1, -1, 1, -1, -1, -3, 1, -1, +/* 17 */ -3, -1, -1, 1, 3, 1, 1, -1, 1, -1, -3, 1, +/* 18 */ -3, -1, 3, -3, -3, -1, -3, 1, -1, -3, 3, 3, +/* 19 */ -3, -3, 3, -3, -1, 3, 3, 3, -1, -3, 1, -3, +/* 20 */ -3, 1, -1, -1, 3, 3, -3, -1, -1, -3, -1, -3, +/* 21 */ -3, 1, 3, 3, -1, -1, -3, 3, 3, -3, 3, -3, +/* 22 */ -3, -1, -1, -3, -3, -1, -3, 3, 1, 3, -1, -3, +/* 23 */ -3, -1, 3, 1, -3, -1, -3, 3, 1, 3, 3, 1, +/* 24 */ -3, 3, 3, 1, -3, 3, -1, 1, 3, -3, 3, -3, +/* 25 */ 3, -1, -3, 3, -3, -1, 3, 3, 3, -3, -1, -3, +/* 26 */ 1, -1, 3, -1, -1, -1, -3, -1, 1, 1, 1, -3, +/* 27 */ -3, 3, 1, -3, 1, 3, -1, -1, 1, 3, 3, 3, +/* 28 */ -3, 3, -3, 3, -3, -3, 3, -1, -1, 1, 3, -3, +/* 29 */ -3, 3, 1, -1, 3, 3, -3, 1, -1, 1, -1, 1, +} +#endif +; + +/* Table 5.2.2.2-3: Definition of phi (n ) for M_ZC = 18 */ +const char phi_M_ZC_18[18*U_GROUP_NUMBER] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */ +/* 0 */ 3, -3, 3, -1, 1, 3, -3, -1, -3, -3, -1, -3, 3, 1, -1, 3, -3, 3, +/* 1 */ 3, -3, 1, 1, 3, -1, 1, -1, -1, -3, 1, 1, -1, 3, 3, -3, 3, -1, +/* 2 */ -3, 3, -1, -3, -1, -3, 1, 1, -3, -3, -1, -1, 3, -3, 1, 3, 1, 1, +/* 3 */ 1, 1, -1, -1, -3, -1, 1, -3, -3, -3, 1, -3, -1, -1, 1, -1, 3, 1, +/* 4 */ 1, 1, -3, 3, 3, 1, 3, -3, 3, -1, 1, 1, -1, 1, -3, -3, -1, 3, +/* 5 */ -3, -3, 1, -3, 3, 3, 3, -1, 3, 1, 1, -3, -3, -3, 3, -3, -1, -1, +/* 6 */ -1, 3, -1, -3, 3, 1, -3, -1, 3, -3, -1, -1, 1, 1, 1, -1, -1, -1, +/* 7 */ -3, 1, -3, -3, 1, -3, -3, 3, 1, -3, -1, -3, -3, -3, -1, 1, 1, 3, +/* 8 */ 1, -3, -1, -3, 3, 3, -1, -3, 1, -3, -3, -1, -3, -1, 1, 3, 3, 3, +/* 9 */ -3, 3, 1, -1, -1, -1, -1, 1, -1, 3, 3, -3, -1, 1, 3, -1, 3, -1, +/* 10 */ -3, -3, 1, -1, -1, 1, 1, -3, -1, 3, 3, 3, 3, -1, 3, 1, 3, 1, +/* 11 */ -3, -3, 3, 3, -3, 1, 3, -1, -3, 1, -1, -3, 3, -3, -1, -1, -1, 3, +/* 12 */ -3, -3, 3, 3, 3, 1, -3, 1, 3, 3, 1, -3, -3, 3, -1, -3, -1, 1, +/* 13 */ -3, 3, -1, 1, 3, 1, -3, -1, 1, 1, -3, 1, 3, 3, -1, -3, -3, -3, +/* 14 */ -3, 1, -3, -1, -1, 3, 1, -3, -3, -3, -1, -3, -3, 1, 1, 1, -1, -1, +/* 15 */ -3, -3, 3, 3, 3, -1, -1, -3, -1, -1, -1, 3, 1, -3, -3, -1, 3, -1, +/* 16 */ -3, -1, 3, 3, -1, 3, -1, -3, -1, 1, -1, -3, -1, -1, -1, 3, 3, 1, +/* 17 */ -3, -1, -3, -1, -3, 1, 3, -3, -1, 3, 3, 3, 1, -1, -3, 3, -1, -3, +/* 18 */ -3, 3, 1, -1, -1, 3, -3, -1, 1, 1, 1, 1, 1, -1, 3, -1, -3, -1, +/* 19 */ 3, -1, -3, 1, -3, -3, -3, 3, 3, -1, 1, -3, -1, 3, 1, 1, 3, 3, +/* 20 */ 3, 3, 3, -3, -1, -3, -1, 3, -1, 1, -1, -3, 1, -3, -3, -1, 3, 3, +/* 21 */ 3, -1, 3, 1, -3, -3, -1, 1, -3, -3, 3, 3, 3, 1, 3, -3, 3, -3, +/* 22 */ -3, 1, 1, -3, 1, 1, 3, -3, -1, -3, -1, 3, -3, 3, -1, -1, -1, -3, +/* 23 */ -3, -1, -1, -3, 1, -3, 3, -1, -1, -3, 3, 3, -3, -1, 3, -1, -1, -1, +/* 24 */ -3, -3, -3, 1, -3, 3, 1, 1, 3, -3, -3, 1, 3, -1, 3, -3, -3, 3, +/* 25 */ 1, 1, -3, -3, -3, -3, 1, 3, -3, 3, 3, 1, -3, -1, 3, -1, -3, 1, +/* 26 */ 3, -1, -1, 1, -3, -1, -3, -1, -3, -3, -1, -3, 1, 1, 1, -3, -3, 3, +/* 27 */ 3, 1, -3, 1, -3, 3, 3, -1, -3, -3, -1, -3, -3, 3, -3, -1, 1, 3, +/* 28 */ -1, -3, 1, -3, -3, -3, 1, 1, 3, 3, -3, 3, 3, -3, -1, 3, -3, 1, +/* 29 */ -3, -1, -3, -3, 1, 1, -1, -3, -1, -3, -1, -1, 3, 3, -1, 3, 1, 3, +} +#endif +; + +/* Table 5.2.2.2-4: Definition of phi (n ) for M_ZC = 24 */ +const char phi_M_ZC_24[24*U_GROUP_NUMBER] +#ifdef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H += { +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 */ +/* 0 */ -1, -3, 3, 1, 1, -3, 1, -3, -3, 1, -3, -1, -1, 3, -3, 3, 3, 3, -3, 1, 3, 3, -3, -3, +/* 1 */ -1, -3, 3, -1, 3, 1, 3, -1, 1, -3, -1, -3, -1, 1, 3, -3, -1, -3, 3, 3, 3, -3, -3, -3, +/* 2 */ -3, 3, 1, 3, -1, 1, -3, 1, -3, 1, -1, -3, -1, -3, -3, -3, -3, -1, -1, -1, 1, 1, -3, -3, +/* 3 */ 3, -1, 3, -1, 1, -3, 1, 1, -3, -3, 3, -3, -1, -1, -1, -1, -1, -3, -3, -1, 1, 1, -3, -3, +/* 4 */ 1, -3, 3, -1, -3, -1, 3, 3, 1, -1, 1, 1, 3, -3, -1, -3, -3, -3, -1, 3, -3, -1, -3, -3, +/* 5 */ 3, -1, 1, -1, 3, -3, 1, 1, 3, -1, -3, 3, 1, -3, 3, -1, -1, -1, -1, 1, -3, -3, -3, -3, +/* 6 */ -3, 3, -1, 3, 1, -1, -1, -1, 3, 3, 1, 1, 1, 3, 3, 1, -3, -3, -1, 1, -3, 1, 3, -3, +/* 7 */ -3, -1, 1, -3, -3, 1, 1, -3, 3, -1, -1, -3, 1, 3, 1, -1, -3, -1, -3, 1, -3, -3, -3, -3, +/* 8 */ -3, 1, -3, 1, -3, -3, 1, -3, 1, -3, -3, -3, -3, -3, 1, -3, -3, 1, 1, -3, 1, 1, -3, -3, +/* 9 */ 3, -3, -3, -1, 3, 3, -3, -1, 3, 1, 1, 1, 3, -1, 3, -3, -1, 3, -1, 3, 1, -1, -3, -3, +/* 10 */ -3, -3, -1, -1, -1, -3, 1, -1, -3, -1, 3, -3, 1, -3, 3, -3, 3, 3, 1, -1, -1, 1, -3, -3, +/* 11 */ -3, -3, 3, 3, 1, -1, -1, -1, 1, -3, -1, 1, -1, 3, -3, -1, -3, -1, -1, 1, -3, 3, -1, -3, +/* 12 */ -3, -3, 1, -1, 3, 3, -3, -1, 1, -1, -1, 1, 1, -1, -1, 3, -3, 1, -3, 1, -1, -1, -1, -3, +/* 13 */ -3, 1, -3, 3, -1, -1, -1, -3, 3, 1, -1, -3, -1, 1, 3, -1, 1, -1, 1, -3, -3, -3, -3, -3, +/* 14 */ -3, -3, -3, -1, 3, -3, 3, 1, 3, 1, -3, -1, -1, -3, 1, 1, 3, 1, -1, -3, 3, 1, 3, -3, +/* 15 */ 1, 1, -1, -3, -1, 1, 1, -3, 1, -1, 1, -3, 3, -3, -3, 3, -1, -3, 1, 3, -3, 1, -3, -3, +/* 16 */ -3, 3, -1, 3, -1, 3, 3, 1, 1, -3, 1, 3, -3, 3, -3, -3, -1, 1, 3, -3, -1, -1, -3, -3, +/* 17 */ -1, -3, -3, 1, -1, -1, -3, 1, 3, -1, -3, -1, -1, -3, 1, 1, 3, 1, -3, -1, -1, 3, -3, -3, +/* 18 */ -3, 1, -3, 1, -3, 1, 1, 3, 1, -3, -3, -1, 1, 3, -1, -3, 3, 1, -1, -3, -3, -3, -3, -3, +/* 19 */ 3, -3, 3, -1, -3, 1, 3, 1, -1, -1, -3, -1, 3, -3, 3, -1, -1, 3, 3, -3, -3, 3, -3, -3, +/* 20 */ -1, 3, -3, -3, -1, 3, -1, -1, 1, 3, 1, 3, -1, -1, -3, 1, 3, 1, -1, -3, 1, -1, -3, -3, +/* 21 */ -3, 1, -3, -1, -1, 3, 1, 3, -3, 1, -1, 3, 3, -1, -3, 3, -3, -1, -1, -3, -3, -3, 3, -3, +/* 22 */ -3, -1, -1, -3, 1, -3, -3, -1, -1, 3, -1, 1, -1, 3, 1, -3, -1, 3, 1, 1, -1, -1, -3, -3, +/* 23 */ -3, 1, -3, 3, -3, 1, -3, 3, 1, -1, -3, -1, -3, -3, -3, -3, 1, 3, -1, 1, 3, 3, 3, -3, +/* 24 */ -3, -1, 1, -3, -1, -1, 1, 1, 1, 3, 3, -1, 1, -1, 1, -1, -1, -3, -3, -3, 3, 1, -1, -3, +/* 25 */ 3, -3, -1, 1, 3, -1, -1, -3, -1, 3, -1, -3, -1, -3, 3, -1, 3, 1, 1, -3, 3, -3, -3, -3, +/* 26 */ -3, 1, 3, -1, 1, -1, 3, -3, 3, -1, -3, -1, -3, 3, -1, -1, -1, -3, -1, -1, -3, 3, 3, -3, +/* 27 */ -3, 3, -1, -3, -1, -1, -1, 3, -1, -1, 3, -3, -1, 3, -3, 3, -3, -1, 3, 1, 1, -1, -3, -3, +/* 28 */ -3, 1, -1, -3, -3, -1, 1, -3, -1, -3, 1, 1, -1, 1, 1, 3, 3, 3, -1, 1, -1, 1, -1, -3, +/* 29 */ -1, 3, -1, -1, 3, 3, -1, -1, -1, 3, -1, -3, 1, 3, 1, 1, -3, -3, -3, -1, -3, -1, -3, -3, +} +#endif +; +/************** FUNCTION ******************************************/ + +int16_t *base_sequence_36_or_larger(unsigned int M_ZC, unsigned int u, unsigned int v, unsigned int scaling); +int16_t *base_sequence_less_than_36(unsigned int M_ZC, unsigned int u, unsigned int scaling); +/*! +\brief This function generate the sounding reference symbol (SRS) for the uplink. +@param tables of srs +@param scaling amplitude of the reference signal +*/ +void generate_ul_reference_signal_sequences(unsigned int scaling); +void free_ul_reference_signal_sequences(void); + +#undef INIT_VARIABLES_LOWPAPR_SEQUENCES_NR_H +#undef EXTERN + +#endif /* SSS_NR_H */ diff --git a/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.c b/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..98248d02dd523267629419a48d87a9f73d605b3c --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.c @@ -0,0 +1,578 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : cic_filter_nr.c +* +* MODULE : generic functions for cic filters +* +* DESCRIPTION : generic functions useful for decimation based on cascaded integrator comb filter +* +************************************************************************/ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <math.h> + +#include "PHY/defs_nr_UE.h" + +#define DEFINE_VARIABLES_CIC_FILTER_NR_H +#include "PHY/NR_UE_TRANSPORT/cic_filter_nr.h" +#undef DEFINE_VARIABLES_CIC_FILTER_NR_H + +/******************************************************************* +* +* NAME : integrator_stage +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* +* RETURN : +* +* DESCRIPTION : single stage of an integrator +* +* It is a single-pole IIR filter with a unity feedback coefficient +* +* y(n) = y(n-1) +x(n)* +* +*********************************************************************/ + +void integrator_stage(int32_t *input, int32_t *output, int length) +{ + /* first sample is just copied */ + for (int i = 0; i < 1; i++) { + output[2*i] = input[2*i]; + output[2*i+1] = input[2*i+1]; + } + + /* then process all other samples */ + for (int i = 1; i < length; i++) { + output[2*i] = output[2*(i-1)] + input[2*i]; + output[2*i+1] = output[2*(i-1)+1] + input[2*i+1]; + +#ifdef DBG_CIC_FILTER_NR + if (i < 20) { + printf("output[%d] = output[%d] + input[%d] \n", (2*i), 2*(i-1), 2*i); + printf("%d = %d + %d \n", output[2*i], output[2*(i-1)], input[2*i]); + } +#endif + } +} + +/******************************************************************* +* +* NAME : comb_stage +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* +* RETURN : +* +* DESCRIPTION : single stage of a comb filter which is an odd-symetric FIR filter +* +* y(n) = x(n) - x(n - M) +* +* M is called the differential delay. It can take any positive +* integer but it is usually limited to 1 or 2. +* +*********************************************************************/ + +void comb_stage(int32_t *input, int32_t *output, int length, int differential_delay) +{ + /* first sample is just copied */ + for (int i = 0; i < differential_delay; i++) { + output[2*i] = input[2*i]; + output[2*i+1] = input[2*i+1]; + } + + /* then process all other samples */ + for (int i = differential_delay; i < length; i++) { + output[2*i] = input[2*i] - input[2*(i-differential_delay)]; + output[2*i+1] = input[2*i+1] - input[2*(i-differential_delay)+1]; + +#ifdef DBG_CIC_FILTER_NR + if (i < 20) { + printf("output[%d] = input[%d] - input[%d] \n", (2*i), (2*i), 2*(i-differential_delay)); + printf("%d = %d - %d \n", output[2*i], input[2*i], input[2*(i-differential_delay)]); + } +#endif + } +} + +/******************************************************************* +* +* NAME : rate_change_stage +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* +* RETURN : none +* +* DESCRIPTION : change sampling rate by a factor of R +* just copy one samples over R from input to output buffer +* +*********************************************************************/ + +void rate_change_stage(int32_t *input, int32_t *output, int length, int rate_change) +{ + for (int i = 0; (i*rate_change) < length; i++) { + output[2*i] = input[2*i*rate_change]; + output[2*i+1] = input[(2*i*rate_change)+1]; + +#ifdef DBG_CIC_FILTER_NR + if (i < 20) { + printf("input[%d] : %d \n", 2*i*rate_change, input[2*i*rate_change]); + printf("output[%d] : %d \n", 2*i, output[2*i]); + } +#endif + } +} + +/******************************************************************* +* +* NAME : fir_filter +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* +* RETURN : none +* +* DESCRIPTION : implement a fir filter with taps from an array +* +*********************************************************************/ + +void fir_filter_init(fir_filter_t* f, int taps_fir_number, int32_t *filter_taps) { + int i; + for(i = 0; i < taps_fir_number; ++i) + f->history[i] = 0; + f->last_index = 0; + if (taps_fir_number > MAX_SAMPLEFILTER_TAP_NUM) { + printf("Number of taps of this FIR filter %d exceeds maximum value %d \n", taps_fir_number, MAX_SAMPLEFILTER_TAP_NUM); + assert(0); + } + f->filter_tap_number = taps_fir_number; + f->filter_taps = filter_taps; +} + +void fir_filter_put(fir_filter_t* f, int32_t input) { + f->history[f->last_index++] = input; + if(f->last_index == f->filter_tap_number) + f->last_index = 0; +} + +int32_t fir_filter_get(fir_filter_t* f, int scaling_shift) { + long long acc = 0; + int index = f->last_index, i; + for(i = 0; i < f->filter_tap_number; ++i) { + index = index != 0 ? index-1 : f->filter_tap_number-1; + acc += (long long)f->history[index] * f->filter_taps[i]; + }; + return acc >> scaling_shift; +} + +void fir_filter_basic(int32_t *input, int32_t *output, int length, int taps_fir_number, int32_t *filter_taps, int scaling_shift) +{ + fir_filter_t filter; + + for (int j = 0; j < 2; j++) { + + fir_filter_init(&filter, taps_fir_number, filter_taps); + + for (int i = 0; i < length; i++) { + fir_filter_put(&filter, input[2*i+j]); + output[2*i+j] = fir_filter_get(&filter, scaling_shift); + //printf("i %d input %d output %d ", 2*i+j, input[2*i+j], output[2*i + j]); + } + } +} + +/******************************************************************* +* +* NAME : fir_filter +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* +* RETURN : +* +* DESCRIPTION : single stage of a fir filter which is an odd-symetric FIR filter +* +* y(n) = SUM ( bi * x(n - i) ) +* +* bi are tags of FIR filter +* +*********************************************************************/ + +void fir_filter(int32_t *input, int32_t *output, int length, int taps_fir_number, int *taps_fir, int scaling_shift) +{ + int32_t current; + + /* taps start from 1 to taps_fir_number */ + for (int i = 0; i < taps_fir_number; i++) { + for (int j=0; j<2 ; j++) { + current = 0; + for (int taps_number = 0; taps_number < taps_fir_number; taps_number++) { + if (i >= taps_number) { + current += taps_fir[taps_number]*input[2*(i-taps_number)+j]; +#ifdef DBG_CIC_FILTER_NR + printf("current[%d] %d = taps[%d] : %d x input[%d] : %d \n", (2*i+j), current, taps_number, taps_fir[taps_number], (2*(i-taps_number)+j), input[2*(i-taps_number)+j]); +#endif + } + } + output[2*i+j] = current >> scaling_shift; + } + } + + for (int i = taps_fir_number; i < length; i++) { + for (int j=0; j<2 ; j++) { + current = 0; + for (int taps_number = 0; taps_number < taps_fir_number; taps_number++) { + current += taps_fir[taps_number]*input[2*(i-taps_number)+j]; +#ifdef DBG_CIC_FILTER_NR + if (i < taps_fir_number + 16) { + printf("current[%d] %d = taps[%d] : %d x input[%d] : %d \n", (2*i+j), current, taps_number, taps_fir[taps_number], (2*(i-taps_number)+j), input[2*(i-taps_number)+j]); + } +#endif + } + output[2*i+j] = current >> scaling_shift; // SHARPENED_FIR_SCALING_ACC; + } + } +} + +/******************************************************************* +* +* NAME : cic_decimator +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* length size of input buffer +* decimation by a factor of R +* +* RETURN : result of decimator is the output buffer +* +* DESCRIPTION : Cascaded integrator-comb filter +* rate change by a factor of R +* +* CIC filter with N stages is composed of: +* - N cascaded integrator filters clocked at high sampling rate fs +* - N cascaded comb stage running at fs/R +* +* +-----------+ +----------+ +----------+ +----+ +----------+ +----------+ +----------+ +--------------+ +* | Integrator| |Integrator| |Integrator| | R | | Comb | | Comb | | Comb | | Compensation | +* input --->| stage |->| stage |->| stage |->| |->| stage |->| stage |->| stage |-------->| FIR Filter |---> output +* +-----------+ +----------+ +----------+ +----+ +----------+ +----------+ +----------+ +--------------+ +* <----------------------------------------> | <--------------------------------------> +* N cascaded integrator filters | N cascaded comb stage running at fs/R +* clocked at high sampling rate fs V +* downsampling +* from fs to fs/R +* +* In order that cic filter works properly, some caution should be taken for getting good accuracy. +* Firstly data should be in fixed point in order to balance integrator and comb stages. If does not work with data in floating point. +* +* k1 is the number of significant bits for input +* k2 is the number of significant bits for output +* m = k2 - k2 > N * log2(RM - 1) N number of stage, M differential delay and R rate change factor +* for example with R=16 N=4 and M=1 with input data on 16 bits +* output data should be on k2 = m + k1 > 31 +* +* Additionally there is a bit growth so processing has a gain of +* G = (RM)power(N) +* For example with R=16 N=4 M=1 G=(16*1)power(4)=65536 +* +* It gives size of output data with number of significant bit Bout = (N x log2(R x M)) + Bin +* With R=16 N=4 M=1 Bin=16 => Bout = (4 x log2(16 x 1)) + 16 = (4 x 4) + 16 = 32 so output significant bits should be 32. +* As a consequence, all computations are done with 32 bits up to the last stage (no rounding or truncation). +* Except for the final result which can be casted from 32 bits to 16 bits. +* +*********************************************************************/ + +void cic_decimator(int16_t *input_buffer, int16_t *output_buffer, int length, int rate_change, int number_cic_stage, int set_scaling_factor, int fir_rate_change) +{ + int32_t *buffer_one; + int32_t *buffer_two; + int32_t *input; + int32_t *output; + int32_t *tmp; + int new_length; + int current_rate_change; + + /* for cic decimator, gain g of the output depends on rate change R, differential delay M and number of stage N */ + /* g = power(R x M, N) / power(2 , log2 (R x M) */ + /* so a scale factor should be applied to output in order to get a unity DC gain */ + + int scaling_factor = 0; // pow(2, log2(rate_change * M_DIFFERENTIAL_DELAY))/pow((rate_change * M_DIFFERENTIAL_DELAY), number_cic_stage); + + if (set_scaling_factor != 0) { + scaling_factor = set_scaling_factor; + printf("Decimation with rate change of %d with set gain of %d \n", rate_change, scaling_factor); + } + + /* get working buffers */ + buffer_one = malloc(length*sizeof(int32_t) * 2); /* for i&q samples */ + if (buffer_one == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + buffer_two = malloc(length*sizeof(int32_t) * 2); /* for i&q samples */ + if (buffer_two == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + /* copy of input buffer from int16 to int32 */ + for (int i = 0; i < length; i++) { + buffer_one[2*i] = input_buffer[2*i]; + buffer_one[2*i + 1] = input_buffer[2*i + 1]; + +#ifdef DBG_CIC_FILTER_NR + if (i < 10) { + printf("buffer_one[%d] : %d %d \n", i, buffer_one[2*i], buffer_one[2*i + 1]); + } +#endif + } + + input = buffer_one; + output = buffer_two; + + /* call of integrator stages running at Fs */ + for (int stage = 0; stage < number_cic_stage; stage++) + { + integrator_stage(input, output, length); + + /* swap between output and input */ + tmp = input; + input = output; + output = tmp; + +#if 0 + char output_file[255]; + char sequence_name[255]; + sprintf(output_file, "int_seq_%d.m", stage); + sprintf(sequence_name, "int_seq_%d", stage); + + printf("file %s signal %s\n", output_file, sequence_name); + write_output(output_file, sequence_name, input, length, 1, 3); /* format = 3 is for int32_t */ +#endif + } + + /* a sharpened Fir filter can be added which can provide also a rate change */ + current_rate_change = rate_change/fir_rate_change; + + /* rate change from sampling frequency Fs to Fs/R */ + rate_change_stage(input, output, length, current_rate_change); + + /* new length of samples should be computed based on the rate change factor R */ + new_length = length/current_rate_change; + + /* swap between output and input */ + tmp = input; + input = output; + output = tmp; + + /* call of comb stages running at Fs/R */ + for (int stage = 0; stage < number_cic_stage; stage++) + { + comb_stage(input, output, new_length, M_DIFFERENTIAL_DELAY); + + /* swap between output and input */ + tmp = input; + input = output; + output = tmp; + +#if 0 + char output_file[255]; + char sequence_name[255]; + sprintf(output_file, "comb_seq_%d.m", stage); + sprintf(sequence_name, "comb_seq_%d", stage); + printf("file %s signal %s\n", output_file, sequence_name); + write_output(output_file, sequence_name, input, new_length, 1, 3); /* format = 3 for int32_t */ +#endif + } + +#if 1 + + if (fir_rate_change > 1) + { +#define FIR_TAPS_SCALING (10000) + + /* convert float taps of fir filter to int32 taps */ + int32_t *filter_taps_fixed_point = malloc(FIR_TAPS_NUMBER*sizeof(int32_t)); + if (filter_taps_fixed_point == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + for (int i = 0; i < FIR_TAPS_NUMBER; i++) { + filter_taps_fixed_point[i] = (int32_t)(sharpened_fir_taps[i] * FIR_TAPS_SCALING); + } + +#if 1 + + /* compensation filter for equalizing the passband drop and perform a low rate change */ + fir_filter(input, output, new_length, FIR_TAPS_NUMBER, filter_taps_fixed_point, FIR_FITER_SCALING_ACC); + +#else + + fir_filter_basic(input, output, new_length, FIR_TAPS_NUMBER, filter_taps, SHARPENED_FIR_SCALING_ACC); + +#endif + } + else + { + output = input; + } + + /* new length of samples should be computed based on the rate change */ + current_rate_change = fir_rate_change; + new_length = new_length/current_rate_change; + + /* filter has created a delay on the signal which can be compensated */ + //int delay = FIR_TAPS_NUMBER; + int delay = 0; + + for (int i = 0; (i*fir_rate_change) < new_length; i++) { + output_buffer[2*i] = output[(2*i+delay)*current_rate_change]>> scaling_factor; + output_buffer[2*i+1] = output[((2*i+delay)*current_rate_change)+1]>> scaling_factor; + +#ifdef DBG_CIC_FILTER_NR + if (i < 10) { + printf("output_buffer[%d] = output[%d] >> scaling_factor \n", (2*i), ((2*i+delay)*current_rate_change)); + printf(" %d = %d >> %d \n", output_buffer[2*i], output[((2*i+delay)*current_rate_change)], scaling_factor); + } +#endif + } + +#else + + scaling_factor = 0; + + /* copy of final result from int32 to int16 with a scaling factor and a rate change */ + for (int i = 0; i < new_length; i++) { + output_buffer[2*i] = input[2*i] >> scaling_factor; + output_buffer[2*i + 1] = input[2*i + 1] >> scaling_factor; + +#ifdef DBG_CIC_FILTER_NR + if (i < 10) { + printf("output_buffer[%d] : %d \n", (2*i), output_buffer[2*i]); + printf("input[%d] : %d \n", 2*i, input[2*i] >> scaling_factor); + } +#endif + } + +#endif + +#if 1 + /* clear till end of the buffer */ + for (int i = new_length; i < length; i++) { + output_buffer[2*i] = 0; + output_buffer[2*i + 1] = 0; + } +#endif +} + +/******************************************************************* +* +* NAME : fir_decimator +* +* PARAMETERS : pointer to input complex data +* pointer to output complex data +* length size of input buffer +* decimation by a factor of R +* +* RETURN : result of decimator is the output buffer +* +* DESCRIPTION : fir filter +* rate change by a factor of R +* +* +*********************************************************************/ + +void fir_decimator(int16_t *input_buffer, int16_t *output_buffer, int length, int rate_change, int scaling_factor) +{ + int32_t *buffer_one; + int32_t *buffer_two; + int32_t *input; + int32_t *output; + int new_length; + + /* get working buffers */ + buffer_one = malloc(length*sizeof(int32_t) * 2); /* for i&q samples */ + if (buffer_one == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + buffer_two = malloc(length*sizeof(int32_t) * 2); /* for i&q samples */ + if (buffer_two == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + /* copy of input buffer from int16 to int32 */ + for (int i = 0; i < length; i++) { + buffer_one[2*i] = input_buffer[2*i]; + buffer_one[2*i + 1] = input_buffer[2*i + 1]; + } + + input = buffer_one; + output = buffer_two; + +#if 1 + + fir_filter(input, output, length, SAMPLEFILTER_TAP_NUM, filter_taps, FIR_SCALING_ACC); + +#else + + fir_filter_basic(input, output, length, SAMPLEFILTER_TAP_NUM, filter_taps, FIR_SCALING_ACC); + +#endif + + /* rate change from sampling frequency Fs to Fs/R */ + rate_change_stage(output, input, length, rate_change); + + new_length = length/rate_change; + + /* copy of final result from int32 to int16 with a scaling factor and a rate change */ + for (int i = 0; i < new_length; i++) { + output_buffer[2*i] = input[2*i] >> scaling_factor; + output_buffer[2*i + 1] = input[2*i + 1] >> scaling_factor; + } + +#if 1 + /* clear till end of the buffer */ + for (int i = new_length; i < length; i++) { + output_buffer[2*i] = 0; + output_buffer[2*i + 1] = 0; + } +#endif + +} + + + + + + + diff --git a/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.h b/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..74e02731ff2a16dd634761af4afb3e1b9ad1c398 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/cic_filter_nr.h @@ -0,0 +1,207 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : cic_filter_nr.h +* +* MODULE : synchronisation signal +* +* DESCRIPTION : function related to nr synchronisation +* It provides filters for sampling decimation +* +************************************************************************/ + +#ifndef CIC_FILTER_NR_H +#define CIC_FILTER_NR_H + +#include "PHY/defs_nr_UE.h" +#include "PHY/types.h" + +#ifdef DEFINE_VARIABLES_CIC_FILTER_NR_H +#define EXTERN +#define INIT_VARIABLES_CIC_FILTER_NR_H +#else +#define EXTERN extern +#endif + +/************** DEFINE ********************************************/ + +#define M_DIFFERENTIAL_DELAY (1) +#define FIR_RATE_CHANGE (2) + +/************** VARIABLES *****************************************/ + +#define FIR_TAPS_NUMBER (20) +#define FIR_FITER_SCALING_ACC (14) + +EXTERN double sharpened_fir_taps[FIR_TAPS_NUMBER] +#ifdef INIT_VARIABLES_CIC_FILTER_NR_H += { +/* +cic filter and compensation FIR have been designed based on cic design tools provided at +http://www.tsdconseil.fr/tutos/index.html +-->cfir = cic_comp_design(4,4,1,30720000,2,1650000,20); +R = 4.00, Fin = 30720000.00 Hz, Fout = 7680000.00 Hz. +Attenuation for f > fout/2 : -14.82 dB. +Attenuation at 1650000.00 Hz: -0.15 dB. +Attenuation max. between 0 et 1650000.00 Hz: -0.15 dB. +E.g. in linear scale : * 0.983 +Number of additionnal bits needed for implementation: 7. +Fout = 7680000.00 Hz. +index = 1026 / 4096. +Correction Fint ? +Filtre global : + +-->cfir + cfir = +*/ + - 0.0059900, + - 0.0056191, + 0.0107582, + 0.0266043, + 0.0130358, + - 0.0331228, + - 0.0680440, + - 0.0278570, + 0.1106335, + 0.2897060, + 0.3607857, + 0.2607354, + 0.0983409, + - 0.0243749, + - 0.0583235, + - 0.0276023, + 0.0104286, + 0.0199533, + 0.0071721, + - 0.0028096, +} +#endif +; + +#define MAX_SAMPLEFILTER_TAP_NUM (100) +#define FIR_SCALING_ACC (15) + +typedef struct { + int32_t history[MAX_SAMPLEFILTER_TAP_NUM]; + int last_index; + int filter_tap_number; + int32_t *filter_taps; +} fir_filter_t; + +#define SAMPLEFILTER_TAP_NUM (59) + +/* + * This low pass filter was designed based on the tool at http://t-filter.engineerjs.com/ + * with below parameters + * sampling frequency 30.72 MHz + * from to gain ripple/att. + * 0 Hz 1.9 MHz 1 0.5 dB + * 2 MHz 15 MHz 0 -20 dB + */ + +EXTERN int filter_taps[SAMPLEFILTER_TAP_NUM] +#ifdef INIT_VARIABLES_CIC_FILTER_NR_H += { + -1572, + 65, + -132, + 197, + 26, + 393, + 194, + 536, + 250, + 514, + 105, + 279, + -234, + -105, + -646, + -466, + -924, + -583, + -856, + -279, + -321, + 492, + 639, + 1601, + 1812, + 2766, + 2872, + 3650, + 3503, + 3976, + 3503, + 3650, + 2872, + 2766, + 1812, + 1601, + 639, + 492, + -321, + -279, + -856, + -583, + -924, + -466, + -646, + -105, + -234, + 279, + 105, + 514, + 250, + 536, + 194, + 393, + 26, + 197, + -132, + 65, + -1572 +} +#endif +; + +/************** FUNCTION ******************************************/ + +void integrator_stage(int32_t *input, int32_t *output, int length); + +void comb_stage(int32_t *input, int32_t *output, int length, int differential_delay); + +void rate_change_stage(int32_t *input, int32_t *output, int length, int rate_change); + +void fir_filter(int32_t *input, int32_t *output, int length, int taps_fir_number, int32_t *taps_fir, int scaling_shift); + +void cic_decimator(int16_t *input_buffer, int16_t *output_buffer, int length, int rate_change, int number_cic_stage, int set_scaling_factor, int fir_rate_change); + +void fir_decimator(int16_t *input_buffer, int16_t *output_buffer, int length, int rate_change, int scaling_factor); + +#undef EXTERN +#undef INIT_VARIABLES_CIC_FILTER_NR_H + +#endif /* CIC_FILTER_NR_H */ + + diff --git a/openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..06ccd9459f699be59ae45b12167710c64cbef0d2 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/dmrs_nr.c @@ -0,0 +1,311 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : dmrs_nr.c +* +* MODULE : demodulation reference signals +* +* DESCRIPTION : generation of dmrs sequences +* 3GPP TS 38.211 +* +************************************************************************/ + +//#include "PHY/LTE_REFSIG/defs.h" +#include "PHY/NR_REFSIG/ss_pbch_nr.h" +#include "PHY/NR_REFSIG/dmrs_nr.h" + +/******************************************************************* +* +* NAME : pseudo_random_gold_sequence +* +* PARAMETERS : +* +* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence +* +* DESCRIPTION : 3GPP TS 38.211 5.2.1 Pseudo-random sequence generation +* Sequence generation is a length-31 Gold sequence +* +*********************************************************************/ + +#define NC (1600) +#define GOLD_SEQUENCE_LENGTH (31) + +int pseudo_random_sequence(int M_PN, uint32_t *c, uint32_t cinit) +{ + int n; + int size_x = NC + GOLD_SEQUENCE_LENGTH + M_PN; + uint32_t *x1; + uint32_t *x2; + + x1 = calloc(size_x, sizeof(uint32_t)); + + if (x1 == NULL) { + msg("Fatal error: memory allocation problem \n"); + assert(0); + } + + x2 = calloc(size_x, sizeof(uint32_t)); + + if (x2 == NULL) { + free(x1); + msg("Fatal error: memory allocation problem \n"); + assert(0); + } + + x1[0] = 1; /* init first m sequence */ + + /* cinit allows to initialise second m-sequence x2 */ + for (n = 0; n < GOLD_SEQUENCE_LENGTH; n++) { + x2[n] = (cinit >> n) & 0x1; + } + + for (n = 0; n < (NC + M_PN); n++) { + x1[n+31] = (x1[n+3] + x1[n])%2; + x2[n+31] = (x2[n+3] + x2[n+2] + x2[n+1] + x2[n])%2; + } + + for (int n = 0; n < M_PN; n++) { + c[n] = (x1[n+NC] + x2[n+NC])%2; + } + + free(x1); + free(x2); + + return 0; +} + +/******************************************************************* +* +* NAME : pseudo_random_sequence_optimised +* +* PARAMETERS : +* +* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence +* +* DESCRIPTION : 3GPP TS 38.211 5.2.1 Pseudo-random sequence generation +* Sequence generation is a length-31 Gold sequence +* This is an optimized function based on bitmap variables +* +* x1(0)=1,x1(1)=0,...x1(30)=0,x1(31)=1 +* x2 <=> cinit, x2(31) = x2(3)+x2(2)+x2(1)+x2(0) +* x2 <=> cinit = sum_{i=0}^{30} x2(i)2^i +* c(n) = x1(n+Nc) + x2(n+Nc) mod 2 +* +* equivalent to +* x1(n+31) = (x1(n+3)+x1(n))mod 2 <=> x1(n) = x1(n-28) + x1(n-31) +* x2(n+31) = (x2(n+3)+x2(n+2)+x2(n+1)+x2(n))mod 2 <=> x2(n) = x2(n-28) + x2(n-29) + x2(n-30) + x2(n-31) +* +*********************************************************************/ + +void pseudo_random_sequence_optimised(unsigned int size, uint32_t *c, uint32_t cinit) +{ + unsigned int n,x1,x2; + + /* init of m-sequences */ + x1 = 1+ (1<<31); + x2 = cinit; + x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31); + + /* skip first 50 double words of uint32_t (1600 bits) */ + for (n=1; n<50; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + } + + for (n=0; n<size; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + c[n] = x1^x2; + } +} + +/******************************************************************* +* +* NAME : lte_gold_new +* +* PARAMETERS : +* +* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence +* +* DESCRIPTION : This function is the same as "lte_gold" function in file lte_gold.c +* It allows checking that optimization works fine. +* generated sequence is given in an array as a bit map. +* +*********************************************************************/ + +#define CELL_DMRS_LENGTH (224*2) +#define CHECK_GOLD_SEQUENCE + +void lte_gold_new(LTE_DL_FRAME_PARMS *frame_parms, uint32_t lte_gold_table[20][2][14], uint16_t Nid_cell) +{ + unsigned char ns,l,Ncp=1-frame_parms->Ncp; + uint32_t cinit; + +#ifdef CHECK_GOLD_SEQUENCE + + uint32_t dmrs_bitmap[20][2][14]; + uint32_t *dmrs_sequence = calloc(CELL_DMRS_LENGTH, sizeof(uint32_t)); + if (dmrs_sequence == NULL) { + msg("Fatal error: memory allocation problem \n"); + assert(0); + } + else + { + printf("Check of demodulation reference signal of pbch sequence \n"); + } + +#endif + + /* for each slot number */ + for (ns=0; ns<20; ns++) { + + /* for each ofdm position */ + for (l=0; l<2; l++) { + + cinit = Ncp + + (Nid_cell<<1) + + (((1+(Nid_cell<<1))*(1 + (((frame_parms->Ncp==0)?4:3)*l) + (7*(1+ns))))<<10); + + pseudo_random_sequence_optimised(14, &(lte_gold_table[ns][l][0]), cinit); + +#ifdef CHECK_GOLD_SEQUENCE + + pseudo_random_sequence(CELL_DMRS_LENGTH, dmrs_sequence, cinit); + + int j = 0; + int k = 0; + + /* format for getting bitmap from uint32_t */ + for (int i=0; i<14; i++) { + dmrs_bitmap[ns][l][i] = 0; + for (; j < k + 32; j++) { + dmrs_bitmap[ns][l][i] |= (dmrs_sequence[j]<<j); + } + k = j; + } + + for (int i=0; i<14; i++) { + if (lte_gold_table[ns][l][i] != dmrs_bitmap[ns][l][i]) { + printf("Error in gold sequence computation for ns %d l %d and index %i : 0x%x 0x%x \n", ns, l, i, lte_gold_table[ns][l][i], dmrs_bitmap[ns][l][i]); + assert(0); + } + } + +#endif + + } + } + +#ifdef CHECK_GOLD_SEQUENCE + free(dmrs_sequence); +#endif +} + +/******************************************************************* +* +* NAME : get_dmrs_pbch +* +* PARAMETERS : i_ssb : index of ssb/pbch beam +* n_hf : number of the half frame in which PBCH is transmitted in frame +* +* RETURN : demodulation reference signal for PBCH +* +* DESCRIPTION : see TS 38.211 7.4.1.4 Demodulation reference signals for PBCH +* +*********************************************************************/ + +#define CHECK_DMRS_PBCH_SEQUENCE + +void generate_dmrs_pbch(uint32_t dmrs_pbch_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_HF][DMRS_BITMAP_SIZE], uint16_t Nid_cell) +{ + uint32_t cinit; + int i_ssb; + int n_hf; + int _i_ssb; + +#ifdef CHECK_DMRS_PBCH_SEQUENCE + + uint32_t dmrs_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_HF][DMRS_BITMAP_SIZE]; + uint32_t *dmrs_sequence = calloc(CELL_DMRS_LENGTH, sizeof(uint32_t)); + if (dmrs_sequence == NULL) { + msg("Fatal error: memory allocation problem \n"); + assert(0); + } + else + { + printf("Check of demodulation reference signal of pbch sequence \n"); + } + +#endif + + /* for each slot number */ + for (i_ssb = 0; i_ssb<DMRS_PBCH_I_SSB; i_ssb++) { + + /* for each ofdm position */ + for (n_hf=0; n_hf<DMRS_PBCH_N_HF; n_hf++) { + + _i_ssb = i_ssb + 4*n_hf; + + cinit = (((_i_ssb + 1)*((Nid_cell>>4) + 1))<<11) + ((_i_ssb + 1)<<6) + (Nid_cell%4); + + pseudo_random_sequence_optimised(DMRS_BITMAP_SIZE, &(dmrs_pbch_bitmap[i_ssb][n_hf][0]), cinit); + +#ifdef CHECK_DMRS_PBCH_SEQUENCE + + /* it allows checking generated with standard generation code */ + pseudo_random_sequence(DMRS_BITMAP_SIZE*sizeof(uint32_t), dmrs_sequence, cinit); + + int j = 0; + int k = 0; + + /* format for getting bitmap from uint32_t */ + for (int i=0; i<DMRS_BITMAP_SIZE; i++) { + dmrs_bitmap[i_ssb][n_hf][i] = 0; + /* convert to bitmap */ + for (; j < k + 32; j++) { + dmrs_bitmap[i_ssb][n_hf][i] |= (dmrs_sequence[j]<<j); + } + k = j; + } + + for (int i=0; i<DMRS_BITMAP_SIZE; i++) { + if (dmrs_pbch_bitmap[i_ssb][n_hf][i] != dmrs_bitmap[i_ssb][n_hf][i]) { + printf("Error in gold sequence computation for ns %d l %d and index %i : 0x%x 0x%x \n", i_ssb, n_hf, i, dmrs_pbch_bitmap[i_ssb][n_hf][i], dmrs_bitmap[i_ssb][n_hf][i]); + assert(0); + } + } + +#endif + + } + } + +#ifdef CHECK_DMRS_PBCH_SEQUENCE + free(dmrs_sequence); +#endif +} + diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h new file mode 100644 index 0000000000000000000000000000000000000000..24134358c5b23c5d0575101f170b3a879a8fe999 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -0,0 +1,1662 @@ +/* + * 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/NR_UE_TRANSPORT/transport_proto_ue.h + * \brief Function prototypes for PHY physical/transport channel processing and generation V8.6 2009-03 + * \author R. Knopp, F. Kaltenberger + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr + * \note + * \warning + */ +#ifndef __NR_TRANSPORT_PROTO_UE__H__ +#define __NR_TRANSPORT_PROTO_UE__H__ +#include "PHY/defs_nr_UE.h" +//#include "PHY/LTE_TRANSPORT/transport_common_proto.h" +#include <math.h> +#include "nfapi_interface.h" + +// Functions below implement 36-211 and 36-212 + +/** @addtogroup _PHY_TRANSPORT_ + * @{ + */ + +/** \fn free_ue_dlsch(NR_UE_DLSCH_t *dlsch) + \brief This function frees memory allocated for a particular DLSCH at UE + @param dlsch Pointer to DLSCH to be removed +*/ +void free_ue_dlsch(NR_UE_DLSCH_t *dlsch); + +/** \fn new_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t abstraction_flag) + \brief This function allocates structures for a particular DLSCH at UE + @returns Pointer to DLSCH to be removed + @param Kmimo Kmimo factor from 36-212/36-213 + @param Mdlharq Maximum number of HARQ rounds (36-212/36-213) + @param Nsoft Soft-LLR buffer size from UE-Category + @params N_RB_DL total number of resource blocks (determine the operating BW) + @param abstraction_flag Flag to indicate abstracted interface +*/ +NR_UE_DLSCH_t *new_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t max_turbo_iterations,uint8_t N_RB_DL, uint8_t abstraction_flag); + + +void free_ue_ulsch(NR_UE_ULSCH_t *ulsch); + + +NR_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag); + +void fill_UE_dlsch_MCH(PHY_VARS_NR_UE *ue,int mcs,int ndi,int rvidx,int eNB_id); + +int rx_pmch(PHY_VARS_NR_UE *phy_vars_ue, + unsigned char eNB_id, + uint8_t subframe, + unsigned char symbol); + +/** \brief Dump OCTAVE/MATLAB files for PMCH debugging + @param phy_vars_ue Pointer to UE variables + @param eNB_id index of eNB in ue variables + @param coded_bits_per_codeword G from 36.211 + @param subframe Index of subframe + @returns 0 on success +*/ +void dump_mch(PHY_VARS_NR_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,int subframe); + + + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/QPSK reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qpsk_qpsk(int16_t *stream0_in, + int16_t *stream1_in, + int16_t *stream0_out, + int16_t *rho01, + int32_t length); + +/** \brief This function perform LLR computation for dual-stream (QPSK/QPSK) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr128p pointer to pointer to symbol in dlsch_llr*/ +int32_t dlsch_qpsk_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + int32_t **rho_i, + int16_t *dlsch_llr, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adj, + int16_t **llr128p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/16QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qpsk_qam16(int16_t *stream0_in, + int16_t *stream1_in, + short *ch_mag_i, + int16_t *stream0_out, + int16_t *rho01, + int32_t length); + +/** \brief This function perform LLR computation for dual-stream (QPSK/16QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr128p pointer to pointer to symbol in dlsch_llr*/ +int32_t dlsch_qpsk_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + int **dl_ch_mag_i, //|h_1|^2*(2/sqrt{10}) + int32_t **rho_i, + int16_t *dlsch_llr, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adj, + int16_t **llr128p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/64QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qpsk_qam64(int16_t *stream0_in, + int16_t *stream1_in, + short *ch_mag_i, + int16_t *stream0_out, + int16_t *rho01, + int32_t length); + +/** \brief This function perform LLR computation for dual-stream (QPSK/64QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr128p pointer to pointer to symbol in dlsch_llr*/ +int32_t dlsch_qpsk_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + int **dl_ch_mag_i, //|h_1|^2*(2/sqrt{10}) + int32_t **rho_i, + int16_t *dlsch_llr, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adj, + int16_t **llr128p); + + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 16QAM/QPSK reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam16_qpsk(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *stream0_out, + short *rho01, + int length); +/** \brief This function perform LLR computation for dual-stream (16QAM/QPSK) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_16qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, //|h_0|^2*(2/sqrt{10}) + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + short **llr16p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 16QAM/16QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam16_qam16(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *ch_mag_i, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function perform LLR computation for dual-stream (16QAM/16QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_16qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, //|h_0|^2*(2/sqrt{10}) + int **dl_ch_mag_i, //|h_1|^2*(2/sqrt{10}) + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + short **llr16p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 16QAM/64QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam16_qam64(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *ch_mag_i, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function perform LLR computation for dual-stream (16QAM/64QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_16qam_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, //|h_0|^2*(2/sqrt{10}) + int **dl_ch_mag_i, //|h_1|^2*(2/sqrt{10}) + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + short **llr16p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 64QAM/64QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam64_qpsk(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function perform LLR computation for dual-stream (64QAM/64QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_64qam_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + short **llr16p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 64QAM/16QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam64_qam16(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *ch_mag_i, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 64QAM/16QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam64_qam16_avx2(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *ch_mag_i, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function perform LLR computation for dual-stream (64QAM/16QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_64qam_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, + int **dl_ch_mag_i, + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + short **llr16p); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 64QAM/64QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam64_qam64(short *stream0_in, + short *stream1_in, + short *ch_mag, + short *ch_mag_i, + short *stream0_out, + short *rho01, + int length); + +/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream 64QAM/64QAM reception. + @param stream0_in Input from channel compensated (MR combined) stream 0 + @param stream1_in Input from channel compensated (MR combined) stream 1 + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param stream0_out Output from LLR unit for stream0 + @param rho01 Cross-correlation between channels (MR combined) + @param length in complex channel outputs*/ +void qam64_qam64_avx2(int32_t *stream0_in, + int32_t *stream1_in, + int32_t *ch_mag, + int32_t *ch_mag_i, + int16_t *stream0_out, + int32_t *rho01, + int length); + +/** \brief This function perform LLR computation for dual-stream (64QAM/64QAM) transmission. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param ch_mag Input from scaled channel magnitude square of h0'*g0 + @param ch_mag_i Input from scaled channel magnitude square of h0'*g1 + @param rho_i Correlation between channel of signal and inteference + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag flag to indicate this is the first symbol of the dlsch + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr16p pointer to pointer to symbol in dlsch_llr*/ +int dlsch_64qam_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int **rxdataF_comp_i, + int **dl_ch_mag, + int **dl_ch_mag_i, + int **rho_i, + short *dlsch_llr, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned short nb_rb, + uint16_t pbch_pss_sss_adjust, + //short **llr16p, + uint32_t llr_offset); + + +/** \brief This function generates log-likelihood ratios (decoder input) for single-stream QPSK received waveforms. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param dlsch_llr llr output + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS + @param llr128p pointer to pointer to symbol in dlsch_llr + @param beamforming_mode beamforming mode +*/ +int32_t dlsch_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *dlsch_llr, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adj, + //int16_t **llr128p, + uint8_t beamforming_mode); + +/** + \brief This function generates log-likelihood ratios (decoder input) for single-stream 16QAM received waveforms + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param dlsch_llr llr output + @param dl_ch_mag Squared-magnitude of channel in each resource element position corresponding to allocation and weighted for mid-point in 16QAM constellation + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adjust Adjustment factor in RE for PBCH/PSS/SSS allocations + @param llr128p pointer to pointer to symbol in dlsch_llr + @param beamforming_mode beamforming mode +*/ + +int32_t dlsch_qpsk_llr_SIC(NR_DL_FRAME_PARMS *frame_parms, + int **rxdataF_comp, + int32_t **sic_buffer, + int **rho_i, + short *dlsch_llr, + uint8_t num_pdcch_symbols, + uint16_t nb_rb, + uint8_t subframe, + uint16_t mod_order_0, + uint32_t rb_alloc); + +void dlsch_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *dlsch_llr, + int32_t **dl_ch_mag, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adjust, + int16_t **llr128p, + uint8_t beamforming_mode); +/** + \brief This function generates log-likelihood ratios (decoder input) for single-stream 16QAM received waveforms + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param dlsch_llr llr output + @param dl_ch_mag Squared-magnitude of channel in each resource element position corresponding to allocation, weighted by first mid-point of 64-QAM constellation + @param dl_ch_magb Squared-magnitude of channel in each resource element position corresponding to allocation, weighted by second mid-point of 64-QAM constellation + @param symbol OFDM symbol index in sub-frame + @param first_symbol_flag + @param nb_rb number of RBs for this allocation + @param pbch_pss_sss_adjust PBCH/PSS/SSS RE adjustment (in REs) + @param beamforming_mode beamforming mode +*/ +void dlsch_16qam_llr_SIC (NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **sic_buffer, //Q15 + int32_t **rho_i, + int16_t *dlsch_llr, + uint8_t num_pdcch_symbols, + int32_t **dl_ch_mag, + uint16_t nb_rb, + uint8_t subframe, + uint16_t mod_order_0, + uint32_t rb_alloc); + +void dlsch_64qam_llr_SIC(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **sic_buffer, //Q15 + int32_t **rho_i, + int16_t *dlsch_llr, + uint8_t num_pdcch_symbols, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint16_t nb_rb, + uint8_t subframe, + uint16_t mod_order_0, + uint32_t rb_alloc); + + +void dlsch_64qam_llr(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *dlsch_llr, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + uint16_t pbch_pss_sss_adjust, + //int16_t **llr_save, + uint32_t llr_offset, + uint8_t beamforming_mode); + + +/** \fn dlsch_siso(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + uint8_t l, + uint16_t nb_rb) + \brief This function does the first stage of llr computation for SISO, by just extracting the pilots, PBCH and primary/secondary synchronization sequences. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param l symbol in sub-frame + @param nb_rb Number of RBs in this allocation +*/ + +void dlsch_siso(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + uint8_t l, + uint16_t nb_rb); + +/** \fn dlsch_alamouti(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint16_t nb_rb) + \brief This function does Alamouti combining on RX and prepares LLR inputs by skipping pilots, PBCH and primary/secondary synchronization signals. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param dl_ch_mag First squared-magnitude of channel (16QAM and 64QAM) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param dl_ch_magb Second squared-magnitude of channel (64QAM only) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param symbol Symbol in sub-frame + @param nb_rb Number of RBs in this allocation +*/ +void dlsch_alamouti(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint16_t nb_rb); + +/** \fn dlsch_antcyc(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint16_t nb_rb) + \brief This function does antenna selection (based on antenna cycling pattern) on RX and prepares LLR inputs by skipping pilots, PBCH and primary/secondary synchronization signals. Note that this is not LTE, it is just included for comparison purposes. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param dl_ch_mag First squared-magnitude of channel (16QAM and 64QAM) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param dl_ch_magb Second squared-magnitude of channel (64QAM only) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param symbol Symbol in sub-frame + @param nb_rb Number of RBs in this allocation +*/ +void dlsch_antcyc(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint16_t nb_rb); + +/** \fn dlsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + int32_t **rho, + int32_t **rho_i, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + uint8_t symbol, + uint16_t nb_rb, + uint8_t dual_stream_UE) + + \brief This function does maximal-ratio combining for dual-antenna receivers. + @param frame_parms Frame descriptor structure + @param rxdataF_comp Compensated channel output + @param rxdataF_comp_i Compensated channel output for interference + @param rho Cross correlation between spatial channels + @param rho_i Cross correlation between signal and inteference channels + @param dl_ch_mag First squared-magnitude of channel (16QAM and 64QAM) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param dl_ch_magb Second squared-magnitude of channel (64QAM only) for LLR computation. Alamouti combining should be performed on this as well. Result is stored in first antenna position + @param symbol Symbol in sub-frame + @param nb_rb Number of RBs in this allocation + @param dual_stream_UE Flag to indicate dual-stream detection +*/ +void dlsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int32_t **rxdataF_comp_i, + int32_t **rho, + int32_t **rho_i, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + int32_t **dl_ch_mag_i, + int32_t **dl_ch_magb_i, + uint8_t symbol, + uint16_t nb_rb, + uint8_t dual_stream_UE); + +void dlsch_detection_mrc_TM34(NR_DL_FRAME_PARMS *frame_parms, + NR_UE_PDSCH *lte_ue_pdsch_vars, + int harq_pid, + int round, + unsigned char symbol, + unsigned short nb_rb, + unsigned char dual_stream_UE); + +/** \fn dlsch_extract_rbs_single(int32_t **rxdataF, + int32_t **dl_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_ch_estimates_ext, + uint16_t pmi, + uint8_t *pmi_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + NR_DL_FRAME_PARMS *frame_parms) + \brief This function extracts the received resource blocks, both channel estimates and data symbols, + for the current allocation and for single antenna eNB transmission. + @param rxdataF Raw FFT output of received signal + @param dl_ch_estimates Channel estimates of current slot + @param rxdataF_ext FFT output for RBs in this allocation + @param dl_ch_estimates_ext Channel estimates for RBs in this allocation + @param pmi subband Precoding matrix indicator + @param pmi_ext Extracted PMI for chosen RBs + @param rb_alloc RB allocation vector + @param symbol Symbol to extract + @param subframe Subframe number + @param vrb_type Flag to indicate distributed VRB type + @param high_speed_flag + @param frame_parms Pointer to frame descriptor +*/ +uint16_t dlsch_extract_rbs_single(int32_t **rxdataF, + int32_t **dl_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_ch_estimates_ext, + uint16_t pmi, + uint8_t *pmi_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + NR_DL_FRAME_PARMS *frame_parms); + +/** \fn dlsch_extract_rbs_dual(int32_t **rxdataF, + int32_t **dl_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_ch_estimates_ext, + uint16_t pmi, + uint8_t *pmi_ext, + uint32_t *rb_alloc, + uint8_t symbol, + NR_DL_FRAME_PARMS *frame_parms) + \brief This function extracts the received resource blocks, both channel estimates and data symbols, + for the current allocation and for dual antenna eNB transmission. + @param rxdataF Raw FFT output of received signal + @param dl_ch_estimates Channel estimates of current slot + @param rxdataF_ext FFT output for RBs in this allocation + @param dl_ch_estimates_ext Channel estimates for RBs in this allocation + @param pmi subband Precoding matrix indicator + @param pmi_ext Extracted PMI for chosen RBs + @param rb_alloc RB allocation vector + @param symbol Symbol to extract + @param subframe Subframe index + @param high_speed_flag + @param frame_parms Pointer to frame descriptor +*/ +uint16_t dlsch_extract_rbs_dual(int32_t **rxdataF, + int32_t **dl_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_ch_estimates_ext, + uint16_t pmi, + uint8_t *pmi_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + NR_DL_FRAME_PARMS *frame_parms, + MIMO_mode_t mimo_mode); + +/** \fn dlsch_extract_rbs_TM7(int32_t **rxdataF, + int32_t **dl_bf_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_bf_ch_estimates_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + NR_DL_FRAME_PARMS *frame_parms) + \brief This function extracts the received resource blocks, both channel estimates and data symbols, + for the current allocation and for single antenna eNB transmission. + @param rxdataF Raw FFT output of received signal + @param dl_bf_ch_estimates Beamforming channel estimates of current slot + @param rxdataF_ext FFT output for RBs in this allocation + @param dl_bf_ch_estimates_ext Beamforming channel estimates for RBs in this allocation + @param rb_alloc RB allocation vector + @param symbol Symbol to extract + @param subframe Subframe number + @param high_speed_flag + @param frame_parms Pointer to frame descriptor +*/ +uint16_t dlsch_extract_rbs_TM7(int32_t **rxdataF, + int32_t **dl_bf_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_bf_ch_estimates_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + NR_DL_FRAME_PARMS *frame_parms); + +/** \brief This function performs channel compensation (matched filtering) on the received RBs for this allocation. In addition, it computes the squared-magnitude of the channel with weightings for 16QAM/64QAM detection as well as dual-stream detection (cross-correlation) + @param rxdataF_ext Frequency-domain received signal in RBs to be demodulated + @param dl_ch_estimates_ext Frequency-domain channel estimates in RBs to be demodulated + @param dl_ch_mag First Channel magnitudes (16QAM/64QAM) + @param dl_ch_magb Second weighted Channel magnitudes (64QAM) + @param rxdataF_comp Compensated received waveform + @param rho Cross-correlation between two spatial channels on each RX antenna + @param frame_parms Pointer to frame descriptor + @param symbol Symbol on which to operate + @param first_symbol_flag set to 1 on first DLSCH symbol + @param mod_order Modulation order of allocation + @param nb_rb Number of RBs in allocation + @param output_shift Rescaling for compensated output (should be energy-normalizing) + @param phy_measurements Pointer to UE PHY measurements +*/ +void dlsch_channel_compensation(int32_t **rxdataF_ext, + int32_t **dl_ch_estimates_ext, + int32_t **dl_ch_mag, + int32_t **dl_ch_magb, + int32_t **rxdataF_comp, + int32_t **rho, + NR_DL_FRAME_PARMS *frame_parms, + uint8_t symbol, + uint8_t first_symbol_flag, + uint8_t mod_order, + uint16_t nb_rb, + uint8_t output_shift, + PHY_NR_MEASUREMENTS *phy_measurements); + +void dlsch_dual_stream_correlation(NR_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, + unsigned short nb_rb, + int **dl_ch_estimates_ext, + int **dl_ch_estimates_ext_i, + int **dl_ch_rho_ext, + unsigned char output_shift); + +void dlsch_dual_stream_correlationTM34(NR_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, + unsigned short nb_rb, + int **dl_ch_estimates_ext, + int **dl_ch_estimates_ext_i, + int **dl_ch_rho_ext, + unsigned char output_shift0, + unsigned char output_shift1); +//This function is used to compute multiplications in Hhermitian * H matrix +void conjch0_mult_ch1(int *ch0, + int *ch1, + int32_t *ch0conj_ch1, + unsigned short nb_rb, + unsigned char output_shift0); + +void construct_HhH_elements(int *ch0conj_ch0, + int *ch1conj_ch1, + int *ch2conj_ch2, + int *ch3conj_ch3, + int *ch0conj_ch1, + int *ch1conj_ch0, + int *ch2conj_ch3, + int *ch3conj_ch2, + int32_t *after_mf_00, + int32_t *after_mf_01, + int32_t *after_mf_10, + int32_t *after_mf_11, + unsigned short nb_rb); + +void squared_matrix_element(int32_t *Hh_h_00, + int32_t *Hh_h_00_sq, + unsigned short nb_rb); + +void dlsch_channel_level_TM34_meas(int *ch00, + int *ch01, + int *ch10, + int *ch11, + int *avg_0, + int *avg_1, + unsigned short nb_rb); + +void det_HhH(int32_t *after_mf_00, + int32_t *after_mf_01, + int32_t *after_mf_10, + int32_t *after_mf_11, + int32_t *det_fin_128, + unsigned short nb_rb); + +void numer(int32_t *Hh_h_00_sq, + int32_t *Hh_h_01_sq, + int32_t *Hh_h_10_sq, + int32_t *Hh_h_11_sq, + int32_t *num_fin, + unsigned short nb_rb); + +uint8_t rank_estimation_tm3_tm4(int *dl_ch_estimates_00, + int *dl_ch_estimates_01, + int *dl_ch_estimates_10, + int *dl_ch_estimates_11, + unsigned short nb_rb); + +void dlsch_channel_compensation_TM56(int **rxdataF_ext, + int **dl_ch_estimates_ext, + int **dl_ch_mag, + int **dl_ch_magb, + int **rxdataF_comp, + unsigned char *pmi_ext, + NR_DL_FRAME_PARMS *frame_parms, + PHY_NR_MEASUREMENTS *phy_measurements, + int eNB_id, + unsigned char symbol, + unsigned char mod_order, + unsigned short nb_rb, + unsigned char output_shift, + unsigned char dl_power_off); + + +void dlsch_channel_compensation_TM34(NR_DL_FRAME_PARMS *frame_parms, + NR_UE_PDSCH *lte_ue_pdsch_vars, + PHY_NR_MEASUREMENTS *phy_measurements, + int eNB_id, + unsigned char symbol, + unsigned char mod_order0, + unsigned char mod_order1, + int harq_pid, + int round, + MIMO_mode_t mimo_mode, + unsigned short nb_rb, + unsigned char output_shift0, + unsigned char output_shift1); + + +/** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal + @param dl_ch_estimates_ext Channel estimates in allocated RBs + @param frame_parms Pointer to frame descriptor + @param avg Pointer to average signal strength + @param pilots_flag Flag to indicate pilots in symbol + @param nb_rb Number of allocated RBs +*/ +void dlsch_channel_level(int32_t **dl_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + int32_t *avg, + uint8_t pilots_flag, + uint16_t nb_rb); + + +void dlsch_channel_level_TM34(int **dl_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char *pmi_ext, + int *avg_0, + int *avg_1, + uint8_t symbol, + unsigned short nb_rb, + MIMO_mode_t mimo_mode); + + +void dlsch_channel_level_TM56(int32_t **dl_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + unsigned char *pmi_ext, + int32_t *avg, + uint8_t symbol_mod, + uint16_t nb_rb); + +void dlsch_channel_level_TM7(int32_t **dl_bf_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + int32_t *avg, + uint8_t pilots_flag, + uint16_t nb_rb); + +void dlsch_scale_channel(int32_t **dl_ch_estimates_ext, + NR_DL_FRAME_PARMS *frame_parms, + NR_UE_DLSCH_t **dlsch_ue, + uint8_t symbol_mod, + uint16_t nb_rb); + +/** \brief This is the top-level entry point for DLSCH decoding in UE. It should be replicated on several + threads (on multi-core machines) corresponding to different HARQ processes. The routine first + computes the segmentation information, followed by rate dematching and sub-block deinterleaving the of the + received LLRs computed by dlsch_demodulation for each transport block segment. It then calls the + turbo-decoding algorithm for each segment and stops after either after unsuccesful decoding of at least + one segment or correct decoding of all segments. Only the segment CRCs are check for the moment, the + overall CRC is ignored. Finally transport block reassembly is performed. + @param phy_vars_ue Pointer to ue variables + @param dlsch_llr Pointer to LLR values computed by dlsch_demodulation + @param lte_frame_parms Pointer to frame descriptor + @param dlsch Pointer to DLSCH descriptor + @param frame Frame number + @param subframe Subframe number + @param num_pdcch_symbols Number of PDCCH symbols + @param is_crnti indicates if PDSCH belongs to a CRNTI (necessary for parallelizing decoding threads) + @param llr8_flag If 1, indicate that the 8-bit turbo decoder should be used + @returns 0 on success, 1 on unsuccessful decoding +*/ +uint32_t dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, + int16_t *dlsch_llr, + NR_DL_FRAME_PARMS *lte_frame_parms, + NR_UE_DLSCH_t *dlsch, + NR_DL_UE_HARQ_t *harq_process, + uint32_t frame, + uint8_t subframe, + uint8_t harq_pid, + uint8_t is_crnti, + uint8_t llr8_flag); + + +uint32_t dlsch_decoding_emul(PHY_VARS_NR_UE *phy_vars_ue, + uint8_t subframe, + PDSCH_t dlsch_id, + uint8_t eNB_id); + +/** \brief This function is the top-level entry point to PDSCH demodulation, after frequency-domain transformation and channel estimation. It performs + - RB extraction (signal and channel estimates) + - channel compensation (matched filtering) + - RE extraction (pilot, PBCH, synch. signals) + - antenna combining (MRC, Alamouti, cycling) + - LLR computation + This function supports TM1, 2, 3, 5, and 6. + @param PHY_VARS_NR_UE Pointer to PHY variables + @param type Type of PDSCH (SI_PDSCH,RA_PDSCH,PDSCH,PMCH) + @param eNB_id eNb index (Nid1) 0,1,2 + @param eNB_id_i Interfering eNB index (Nid1) 0,1,2, or 3 in case of MU-MIMO IC receiver + @param subframe Subframe number + @param symbol Symbol on which to act (within sub-frame) + @param first_symbol_flag set to 1 on first DLSCH symbol + @param rx_type. rx_type=RX_IC_single_stream will enable interference cancellation of a second stream when decoding the first stream. In case of TM1, 2, 5, and this can cancel interference from a neighbouring cell given by eNB_id_i. In case of TM5, eNB_id_i should be set to n_connected_eNB to perform multi-user interference cancellation. In case of TM3, eNB_id_i should be set to eNB_id to perform co-channel interference cancellation; this option should be used together with an interference cancellation step [...]. In case of TM3, if rx_type=RX_IC_dual_stream, both streams will be decoded by applying the IC single stream receiver twice. + @param i_mod Modulation order of the interfering stream +*/ +int32_t rx_pdsch(PHY_VARS_NR_UE *phy_vars_ue, + PDSCH_t type, + uint8_t eNB_id, + uint8_t eNB_id_i, + uint32_t frame, + uint8_t subframe, + uint8_t symbol, + uint8_t first_symbol_flag, + RX_type_t rx_type, + uint8_t i_mod, + uint8_t harq_pid); + +int32_t rx_pdcch(PHY_VARS_NR_UE *ue, + uint32_t frame, + uint8_t subframe, + uint8_t eNB_id, + MIMO_mode_t mimo_mode, + uint32_t high_speed_flag); + +/*! \brief Extract PSS and SSS resource elements + @param phy_vars_ue Pointer to UE variables + @param[out] pss_ext contain the PSS signals after the extraction + @param[out] sss_ext contain the SSS signals after the extraction + @returns 0 on success +*/ +int pss_sss_extract(PHY_VARS_NR_UE *phy_vars_ue, + int32_t pss_ext[4][72], + int32_t sss_ext[4][72], + uint8_t subframe); + +/*! \brief Extract only PSS resource elements + @param phy_vars_ue Pointer to UE variables + @param[out] pss_ext contain the PSS signals after the extraction + @returns 0 on success +*/ +int pss_only_extract(PHY_VARS_NR_UE *phy_vars_ue, + int32_t pss_ext[4][72], + uint8_t subframe); + +/*! \brief Extract only SSS resource elements + @param phy_vars_ue Pointer to UE variables + @param[out] sss_ext contain the SSS signals after the extraction + @returns 0 on success +*/ +int sss_only_extract(PHY_VARS_NR_UE *phy_vars_ue, + int32_t sss_ext[4][72], + uint8_t subframe); + +/*! \brief Performs detection of SSS to find cell ID and other framing parameters (FDD/TDD, normal/extended prefix) + @param phy_vars_ue Pointer to UE variables + @param tot_metric Pointer to variable containing maximum metric under framing hypothesis (to be compared to other hypotheses + @param flip_max Pointer to variable indicating if start of frame is in second have of RX buffer (i.e. PSS/SSS is flipped) + @param phase_max Pointer to variable (0 ... 6) containing rought phase offset between PSS and SSS (can be used for carrier + frequency adjustment. 0 means -pi/3, 6 means pi/3. + @returns 0 on success +*/ +int rx_sss(PHY_VARS_NR_UE *phy_vars_ue,int32_t *tot_metric,uint8_t *flip_max,uint8_t *phase_max); + +/*! \brief receiver for the PBCH + \returns number of tx antennas or -1 if error +*/ +uint16_t rx_pbch(NR_UE_COMMON *lte_ue_common_vars, + NR_UE_PBCH *lte_ue_pbch_vars, + NR_DL_FRAME_PARMS *frame_parms, + uint8_t eNB_id, + MIMO_mode_t mimo_mode, + uint32_t high_speed_flag, + uint8_t frame_mod4); + +uint16_t rx_pbch_emul(PHY_VARS_NR_UE *phy_vars_ue, + uint8_t eNB_id, + uint8_t pbch_phase); + + +/*! \brief PBCH unscrambling + This is similar to pbch_scrabling with the difference that inputs are signed s16s (llr values) and instead of flipping bits we change signs. + \param frame_parms Pointer to frame descriptor + \param llr Output of the demodulator + \param length Length of the sequence + \param frame_mod4 Frame number modulo 4*/ +void pbch_unscrambling(NR_DL_FRAME_PARMS *frame_parms, + int8_t* llr, + uint32_t length, + uint8_t frame_mod4); + + +void generate_64qam_table(void); +void generate_16qam_table(void); +void generate_qpsk_table(void); + +uint16_t extract_crc(uint8_t *dci,uint8_t DCI_LENGTH); + +/*! \brief LLR from two streams. This function takes two streams (qpsk modulated) and calculates the LLR, considering one stream as interference. + \param stream0_in pointer to first stream0 + \param stream1_in pointer to first stream1 + \param stream0_out pointer to output stream + \param rho01 pointer to correlation matrix + \param length*/ +void qpsk_qpsk_TM3456(short *stream0_in, + short *stream1_in, + short *stream0_out, + short *rho01, + int length + ); + +/** \brief Attempt decoding of a particular DCI with given length and format. + @param DCI_LENGTH length of DCI in bits + @param DCI_FMT Format of DCI + @param e e-sequence (soft bits) + @param decoded_output Output of Viterbi decoder +*/ +void dci_decoding(uint8_t DCI_LENGTH, + uint8_t DCI_FMT, + int8_t *e, + uint8_t *decoded_output); + +/** \brief Do 36.213 DCI decoding procedure by searching different RNTI options and aggregation levels. Currently does + not employ the complexity reducing procedure based on RNTI. + @param phy_vars_ue UE variables + @param dci_alloc Pointer to DCI_ALLOC_t array to store results for DLSCH/ULSCH programming + @param do_common If 1 perform search in common search-space else ue-specific search-space + @param eNB_id eNB Index on which to act + @param subframe Index of subframe + @returns bitmap of occupied CCE positions (i.e. those detected) +*/ +uint16_t dci_decoding_procedure(PHY_VARS_NR_UE *phy_vars_ue, + DCI_ALLOC_t *dci_alloc, + int do_common, + int16_t eNB_id, + uint8_t subframe); + +uint16_t dci_CRNTI_decoding_procedure(PHY_VARS_NR_UE *ue, + DCI_ALLOC_t *dci_alloc, + uint8_t DCIFormat, + uint8_t agregationLevel, + int16_t eNB_id, + uint8_t subframe); + +uint16_t dci_decoding_procedure_emul(NR_UE_PDCCH **lte_ue_pdcch_vars, + uint8_t num_ue_spec_dci, + uint8_t num_common_dci, + DCI_ALLOC_t *dci_alloc_tx, + DCI_ALLOC_t *dci_alloc_rx, + int16_t eNB_id); + +/** \brief Compute Q (modulation order) based on I_MCS PDSCH. Implements table 7.1.7.1-1 from 36.213. + @param I_MCS */ +uint8_t get_Qm(uint8_t I_MCS); + +/** \brief Compute Q (modulation order) based on I_MCS for PUSCH. Implements table 8.6.1-1 from 36.213. + @param I_MCS */ +uint8_t get_Qm_ul(uint8_t I_MCS); + +/** \brief Compute I_TBS (transport-block size) based on I_MCS for PDSCH. Implements table 7.1.7.1-1 from 36.213. + @param I_MCS */ +uint8_t get_I_TBS(uint8_t I_MCS); + +/** \brief Compute I_TBS (transport-block size) based on I_MCS for PUSCH. Implements table 8.6.1-1 from 36.213. + @param I_MCS */ +unsigned char get_I_TBS_UL(unsigned char I_MCS); + +/** \brief Compute Q (modulation order) based on downlink I_MCS. Implements table 7.1.7.1-1 from 36.213. + @param I_MCS + @param nb_rb + @return Transport block size */ +uint32_t get_TBS_DL(uint8_t mcs, uint16_t nb_rb); + +/** \brief Compute Q (modulation order) based on uplink I_MCS. Implements table 7.1.7.1-1 from 36.213. + @param I_MCS + @param nb_rb + @return Transport block size */ +uint32_t get_TBS_UL(uint8_t mcs, uint16_t nb_rb); + +/* \brief Return bit-map of resource allocation for a given DCI rballoc (RIV format) and vrb type + @param N_RB_DL number of PRB on DL + @param indicator for even/odd slot + @param vrb vrb index + @param Ngap Gap indicator +*/ +uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap); + +/* \brief Return prb for a given vrb index + @param vrb_type VRB type (0=localized,1=distributed) + @param rb_alloc_dci rballoc field from DCI +*/ +uint32_t get_rballoc(vrb_t vrb_type,uint16_t rb_alloc_dci); + + +/* \brief Return bit-map of resource allocation for a given DCI rballoc (RIV format) and vrb type + @returns Transmission mode (1-7) +*/ +uint8_t get_transmission_mode(module_id_t Mod_id, uint8_t CC_id, rnti_t rnti); + + +/* \brief + @param ra_header Header of resource allocation (0,1) (See sections 7.1.6.1/7.1.6.2 of 36.213 Rel8.6) + @param rb_alloc Bitmap allocation from DCI (format 1,2) + @returns number of physical resource blocks +*/ +uint32_t conv_nprb(uint8_t ra_header,uint32_t rb_alloc,int N_RB_DL); + +int get_G(NR_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe, uint8_t beamforming_mode); + +int adjust_G(NR_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe); +int adjust_G2(NR_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe,uint8_t symbol); + + +#ifndef modOrder +#define modOrder(I_MCS,I_TBS) ((I_MCS-I_TBS)*2+2) // Find modulation order from I_TBS and I_MCS +#endif + +/** \fn uint8_t I_TBS2I_MCS(uint8_t I_TBS); + \brief This function maps I_tbs to I_mcs according to Table 7.1.7.1-1 in 3GPP TS 36.213 V8.6.0. Where there is two supported modulation orders for the same I_TBS then either high or low modulation is chosen by changing the equality of the two first comparisons in the if-else statement. + \param I_TBS Index of Transport Block Size + \return I_MCS given I_TBS +*/ +uint8_t I_TBS2I_MCS(uint8_t I_TBS); + +/** \fn uint8_t SE2I_TBS(float SE, + uint8_t N_PRB, + uint8_t symbPerRB); + \brief This function maps a requested throughput in number of bits to I_tbs. The throughput is calculated as a function of modulation order, RB allocation and number of symbols per RB. The mapping orginates in the "Transport block size table" (Table 7.1.7.2.1-1 in 3GPP TS 36.213 V8.6.0) + \param SE Spectral Efficiency (before casting to integer, multiply by 1024, remember to divide result by 1024!) + \param N_PRB Number of PhysicalResourceBlocks allocated \sa lte_frame_parms->N_RB_DL + \param symbPerRB Number of symbols per resource block allocated to this channel + \return I_TBS given an SE and an N_PRB +*/ +uint8_t SE2I_TBS(float SE, + uint8_t N_PRB, + uint8_t symbPerRB); +/** \brief This function generates the sounding reference symbol (SRS) for the uplink according to 36.211 v8.6.0. If IFFT_FPGA is defined, the SRS is quantized to a QPSK sequence. + @param frame_parms LTE DL Frame Parameters + @param soundingrs_ul_config_dedicated Dynamic configuration from RRC during Connection Establishment + @param txdataF pointer to the frequency domain TX signal + @returns 0 on success*/ +int generate_srs(NR_DL_FRAME_PARMS *frame_parms, + SOUNDINGRS_UL_CONFIG_DEDICATED *soundingrs_ul_config_dedicated, + int *txdataF, + int16_t amp, + uint32_t subframe); + + +/*! + \brief This function is similar to generate_srs_tx but generates a conjugate sequence for channel estimation. If IFFT_FPGA is defined, the SRS is quantized to a QPSK sequence. + @param phy_vars_ue Pointer to PHY_VARS structure + @param eNB_id Index of destination eNB for this SRS + @param amp Linear amplitude of SRS + @param subframe Index of subframe on which to act + @returns 0 on success, -1 on error with message +*/ + +int32_t generate_srs_tx(PHY_VARS_NR_UE *phy_vars_ue, + uint8_t eNB_id, + int16_t amp, + uint32_t subframe); + +/*! + \brief This function generates the downlink reference signal for the PUSCH according to 36.211 v8.6.0. The DRS occuies the RS defined by rb_alloc and the symbols 2 and 8 for extended CP and 3 and 10 for normal CP. +*/ + +int32_t generate_drs_pusch(PHY_VARS_NR_UE *phy_vars_ue, + UE_nr_rxtx_proc_t *proc, + uint8_t eNB_id, + int16_t amp, + uint32_t subframe, + uint32_t first_rb, + uint32_t nb_rb, + uint8_t ant); + +/*! + \brief This function initializes the Group Hopping, Sequence Hopping and nPRS sequences for PUCCH/PUSCH according to 36.211 v8.6.0. It should be called after configuration of UE (reception of SIB2/3) and initial configuration of eNB (or after reconfiguration of cell-specific parameters). + @param frame_parms Pointer to a NR_DL_FRAME_PARMS structure (eNB or UE)*/ +void init_ul_hopping(NR_DL_FRAME_PARMS *frame_parms); + + +/*! + \brief This function implements the initialization of paging parameters for UE (See Section 7, 36.304).It must be called after setting IMSImod1024 during UE startup and after receiving SIB2 + @param ue Pointer to UE context + @param defaultPagingCycle T from 36.304 (0=32,1=64,2=128,3=256) + @param nB nB from 36.304 (0=4T,1=2T,2=T,3=T/2,4=T/4,5=T/8,6=T/16,7=T/32*/ +int init_ue_paging_info(PHY_VARS_NR_UE *ue, long defaultPagingCycle, long nB); + +int32_t compareints (const void * a, const void * b); + + +void ulsch_modulation(int32_t **txdataF, + int16_t amp, + frame_t frame, + uint32_t subframe, + NR_DL_FRAME_PARMS *frame_parms, + NR_UE_ULSCH_t *ulsch); + + + + + + +int generate_ue_dlsch_params_from_dci(int frame, + uint8_t subframe, + void *dci_pdu, + rnti_t rnti, + DCI_format_t dci_format, + NR_UE_PDCCH *pdcch_vars, + NR_UE_PDSCH *pdsch_vars, + NR_UE_DLSCH_t **dlsch, + NR_DL_FRAME_PARMS *frame_parms, + PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, + uint16_t si_rnti, + uint16_t ra_rnti, + uint16_t p_rnti, + uint8_t beamforming_mode, + uint16_t tc_rnti); + + +int generate_ue_ulsch_params_from_dci(void *dci_pdu, + rnti_t rnti, + uint8_t subframe, + DCI_format_t dci_format, + PHY_VARS_NR_UE *phy_vars_ue, + UE_nr_rxtx_proc_t *proc, + uint16_t si_rnti, + uint16_t ra_rnti, + uint16_t p_rnti, + uint16_t cba_rnti, + uint8_t eNB_id, + uint8_t use_srs); + +int32_t generate_ue_ulsch_params_from_rar(PHY_VARS_NR_UE *phy_vars_ue, + UE_nr_rxtx_proc_t *proc, + uint8_t eNB_id); +double sinr_eff_cqi_calc(PHY_VARS_NR_UE *phy_vars_ue, + uint8_t eNB_id, + uint8_t subframe); + +uint8_t sinr2cqi(double sinr,uint8_t trans_mode); + + +int dump_dci(NR_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci); + +int dump_ue_stats(PHY_VARS_NR_UE *phy_vars_ue, UE_nr_rxtx_proc_t *proc, char* buffer, int length, runmode_t mode, int input_level_dBm); + + + +void generate_pcfich_reg_mapping(NR_DL_FRAME_PARMS *frame_parms); + + +void pcfich_unscrambling(NR_DL_FRAME_PARMS *frame_parms, + uint8_t subframe, + int16_t *d); + + +uint8_t rx_pcfich(NR_DL_FRAME_PARMS *frame_parms, + uint8_t subframe, + NR_UE_PDCCH *lte_ue_pdcch_vars, + MIMO_mode_t mimo_mode); + +void generate_phich_reg_mapping(NR_DL_FRAME_PARMS *frame_parms); + + +void init_transport_channels(uint8_t); + +void generate_RIV_tables(void); + +/*! + \brief This function performs the initial cell search procedure - PSS detection, SSS detection and PBCH detection. At the + end, the basic frame parameters are known (Frame configuration - TDD/FDD and cyclic prefix length, + N_RB_DL, PHICH_CONFIG and Nid_cell) and the UE can begin decoding PDCCH and DLSCH SI to retrieve the rest. Once these + parameters are know, the routine calls some basic initialization routines (cell-specific reference signals, etc.) + @param phy_vars_ue Pointer to UE variables +*/ +int initial_sync(PHY_VARS_NR_UE *phy_vars_ue, runmode_t mode); + + +/*! + \brief Encoding of PUSCH/ACK/RI/ACK from 36-212. + @param a Pointer to ulsch SDU + @param frame_parms Pointer to Frame parameters + @param ulsch Pointer to ulsch descriptor + @param harq_pid HARQ process ID + @param tmode Transmission mode (1-7) + @param control_only_flag Generate PUSCH with control information only + @param Nbundled Parameter for ACK/NAK bundling (36.213 Section 7.3) +*/ +uint32_t ulsch_encoding(uint8_t *a, + PHY_VARS_NR_UE *phy_vars_ue, + uint8_t harq_pid, + uint8_t eNB_id, + uint8_t subframe_rx, + uint8_t tmode, + uint8_t control_only_flag, + uint8_t Nbundled); + + + + +/* \brief This routine demodulates the PHICH and updates PUSCH/ULSCH parameters. + @param phy_vars_ue Pointer to UE variables + @param proc Pointer to RXN_TXNp4 proc + @param subframe Subframe of received PDCCH/PHICH + @param eNB_id Index of eNB +*/ + +void rx_phich(PHY_VARS_NR_UE *phy_vars_ue, + UE_nr_rxtx_proc_t *proc, + uint8_t subframe, + uint8_t eNB_id); + + +/** \brief This routine provides the relationship between a PHICH TXOp and its corresponding PUSCH subframe (Table 8.3.-1 from 36.213). + @param frame_parms Pointer to DL frame configuration parameters + @param subframe Subframe of received/transmitted PHICH + @returns subframe of PUSCH transmission +*/ +uint8_t phich_subframe2_pusch_subframe(NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe); + +/** \brief This routine provides the relationship between a PHICH TXOp and its corresponding PUSCH frame (Table 8.3.-1 from 36.213). + @param frame_parms Pointer to DL frame configuration parameters + @param frame Frame of received/transmitted PHICH + @param subframe Subframe of received/transmitted PHICH + @returns frame of PUSCH transmission +*/ +int phich_frame2_pusch_frame(NR_DL_FRAME_PARMS *frame_parms, int frame, int subframe); + +void print_CQI(void *o,UCI_format_t uci_format,uint8_t eNB_id,int N_RB_DL); + +void fill_CQI(NR_UE_ULSCH_t *ulsch,PHY_NR_MEASUREMENTS *meas,uint8_t eNB_id, uint8_t harq_pid,int N_RB_DL, rnti_t rnti, uint8_t trans_mode,double sinr_eff); + +void reset_cba_uci(void *o); + +/** \brief This routine computes the subband PMI bitmap based on measurements (0,1,2,3 for rank 0 and 0,1 for rank 1) in the format needed for UCI + @param meas pointer to measurements + @param eNB_id eNB_id + @param nb_subbands number of subbands + @returns subband PMI bitmap +*/ +uint16_t quantize_subband_pmi(PHY_NR_MEASUREMENTS *meas,uint8_t eNB_id,int nb_subbands); + +int32_t pmi_convert_rank1_from_rank2(uint16_t pmi_alloc, int tpmi, int nb_rb); + +uint16_t quantize_subband_pmi2(PHY_NR_MEASUREMENTS *meas,uint8_t eNB_id,uint8_t a_id,int nb_subbands); + + + +uint64_t cqi2hex(uint32_t cqi); + +uint16_t computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); + + +/** \brief This routine extracts a single subband PMI from a bitmap coming from UCI or the pmi_extend function + @param N_RB_DL number of resource blocks + @param mimo_mode + @param pmi_alloc subband PMI bitmap + @param rb resource block for which to extract PMI + @returns subband PMI +*/ +uint8_t get_pmi(uint8_t N_RB_DL,MIMO_mode_t mode, uint32_t pmi_alloc,uint16_t rb); + +int get_nCCE_offset_l1(int *CCE_table, + const unsigned char L, + const int nCCE, + const int common_dci, + const unsigned short rnti, + const unsigned char subframe); + +uint16_t get_nCCE(uint8_t num_pdcch_symbols,NR_DL_FRAME_PARMS *frame_parms,uint8_t mi); + +uint16_t get_nquad(uint8_t num_pdcch_symbols,NR_DL_FRAME_PARMS *frame_parms,uint8_t mi); + +uint8_t get_mi(NR_DL_FRAME_PARMS *frame,uint8_t subframe); + +uint16_t get_nCCE_mac(uint8_t Mod_id,uint8_t CC_id,int num_pdcch_symbols,int subframe); + +uint8_t get_num_pdcch_symbols(uint8_t num_dci,DCI_ALLOC_t *dci_alloc,NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe); + +void pdcch_interleaving(NR_DL_FRAME_PARMS *frame_parms,int32_t **z, int32_t **wbar,uint8_t n_symbols_pdcch,uint8_t mi); + +void pdcch_unscrambling(NR_DL_FRAME_PARMS *frame_parms, + uint8_t subframe, + int8_t* llr, + uint32_t length); + + + +void dlsch_unscrambling(NR_DL_FRAME_PARMS *frame_parms, + int mbsfn_flag, + NR_UE_DLSCH_t *dlsch, + int G, + int16_t* llr, + uint8_t q, + uint8_t Ns); + +void init_ncs_cell(NR_DL_FRAME_PARMS *frame_parms,uint8_t ncs_cell[20][7]); + +void generate_pucch1x(int32_t **txdataF, + NR_DL_FRAME_PARMS *frame_parms, + uint8_t ncs_cell[20][7], + PUCCH_FMT_t fmt, + PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, + uint16_t n1_pucch, + uint8_t shortened_format, + uint8_t *payload, + int16_t amp, + uint8_t subframe); + +void generate_pucch2x(int32_t **txdataF, + NR_DL_FRAME_PARMS *fp, + uint8_t ncs_cell[20][7], + PUCCH_FMT_t fmt, + PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, + uint16_t n2_pucch, + uint8_t *payload, + int A, + int B2, + int16_t amp, + uint8_t subframe, + uint16_t rnti); + +void generate_pucch3x(int32_t **txdataF, + NR_DL_FRAME_PARMS *frame_parms, + uint8_t ncs_cell[20][7], + PUCCH_FMT_t fmt, + PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, + uint16_t n3_pucch, + uint8_t shortened_format, + uint8_t *payload, + int16_t amp, + uint8_t subframe, + uint16_t rnti); + + +void init_ulsch_power_LUT(void); + +/*! + \brief Check for PRACH TXop in subframe + @param frame_parms Pointer to NR_DL_FRAME_PARMS + @param frame frame index to check + @param subframe subframe index to check + @returns 0 on success +*/ +int is_prach_subframe(NR_DL_FRAME_PARMS *frame_parms,frame_t frame, uint8_t subframe); + +/*! + \brief Generate PRACH waveform + @param phy_vars_ue Pointer to ue top-level descriptor + @param eNB_id Index of destination eNB + @param subframe subframe index to operate on + @param index of preamble (0-63) + @param Nf System frame number + @returns 0 on success + +*/ +int32_t generate_prach(PHY_VARS_NR_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe,uint16_t Nf); + + +/*! + \brief Helper for MAC, returns number of available PRACH in TDD for a particular configuration index + @param frame_parms Pointer to NR_DL_FRAME_PARMS structure + @returns 0-5 depending on number of available prach +*/ +uint8_t get_num_prach_tdd(module_id_t Mod_id); + +/*! + \brief Return the PRACH format as a function of the Configuration Index and Frame type. + @param prach_ConfigIndex PRACH Configuration Index + @param frame_type 0-FDD, 1-TDD + @returns 0-1 accordingly +*/ +uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type); + +/*! + \brief Helper for MAC, returns frequency index of PRACH resource in TDD for a particular configuration index + @param frame_parms Pointer to NR_DL_FRAME_PARMS structure + @returns 0-5 depending on number of available prach +*/ +uint8_t get_fid_prach_tdd(module_id_t Mod_id,uint8_t tdd_map_index); + +/*! + \brief Comp ute DFT of PRACH ZC sequences. Used for generation of prach in UE and reception of PRACH in eNB. + @param rootSequenceIndex PRACH root sequence + #param prach_ConfigIndex PRACH Configuration Index + @param zeroCorrelationZoneConfig PRACH ncs_config + @param highSpeedFlat PRACH High-Speed Flag + @param frame_type TDD/FDD flag + @param Xu DFT output +*/ +void compute_prach_seq(uint16_t rootSequenceIndex, + uint8_t prach_ConfigIndex, + uint8_t zeroCorrelationZoneConfig, + uint8_t highSpeedFlag, + lte_frame_type_t frame_type, + uint32_t X_u[64][839]); + + +void init_prach_tables(int N_ZC); + +void init_unscrambling_lut(void); +void init_scrambling_lut(void); + +/*! + \brief Return the status of MBSFN in this frame/subframe + @param frame Frame index + @param subframe Subframe index + @param frame_parms Pointer to frame parameters + @returns 1 if subframe is for MBSFN +*/ +int is_pmch_subframe(frame_t frame, int subframe, NR_DL_FRAME_PARMS *frame_parms); + +uint8_t is_not_pilot(uint8_t pilots, uint8_t re, uint8_t nushift, uint8_t use2ndpilots); + +uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode); + +uint32_t dlsch_decoding_abstraction(double *dlsch_MIPB, + NR_DL_FRAME_PARMS *lte_frame_parms, + NR_UE_DLSCH_t *dlsch, + uint8_t subframe, + uint8_t num_pdcch_symbols); + +// DL power control functions +double get_pa_dB(uint8_t pa); + + +double computeRhoA_UE(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, + NR_UE_DLSCH_t *dlsch_ue, + uint8_t dl_power_off, + uint8_t n_antenna_port); + +double computeRhoB_UE(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, + PDSCH_CONFIG_COMMON *pdsch_config_common, + uint8_t n_antenna_port, + NR_UE_DLSCH_t *dlsch_ue, + uint8_t dl_power_off); + +/*void compute_sqrt_RhoAoRhoB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, + PDSCH_CONFIG_COMMON *pdsch_config_common, + uint8_t n_antenna_port, + NR_UE_DLSCH_t *dlsch_ue); +*/ + +uint8_t get_prach_prb_offset(NR_DL_FRAME_PARMS *frame_parms, + uint8_t prach_ConfigIndex, + uint8_t n_ra_prboffset, + uint8_t tdd_mapindex, uint16_t Nf); + + + + + +/**@}*/ +#endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h new file mode 100644 index 0000000000000000000000000000000000000000..3ff99c12d6f7a8d64dddba1884cf7fd1ff87853e --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -0,0 +1,335 @@ +/* + * 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/NR_TRANSPORT/defs.h +* \brief data structures for PDSCH/DLSCH/PUSCH/ULSCH physical and transport channel descriptors (TX/RX) +* \author R. Knopp +* \date 2011 +* \version 0.1 +* \company Eurecom +* \email: raymond.knopp@eurecom.fr, florian.kaltenberger@eurecom.fr, oscar.tonelli@yahoo.it +* \note +* \warning +*/ +#ifndef __NR_TRANSPORT_UE__H__ +#define __NR_TRANSPORT_UE__H__ +#include "PHY/defs_nr_UE.h" +//#include "../LTE_TRANSPORT/dci.h" +//#include "../LTE_TRANSPORT/mdci.h" +//#include "../LTE_TRANSPORT/uci_common.h" +//#include "../LTE_TRANSPORT/transport_common.h" +#ifndef STANDALONE_COMPILE +#include "UTIL/LISTS/list.h" +#endif + +//#include "../LTE_TRANSPORT/transport_common.h" + +// structures below implement 36-211 and 36-212 + +/** @addtogroup _PHY_TRANSPORT_ + * @{ + */ + +#define SHRT_MAX 32767 + +typedef struct { + /// Indicator of first transmission + uint8_t first_tx; + /// Last Ndi received for this process on DCI (used for C-RNTI only) + uint8_t DCINdi; + /// Flag indicating that this ULSCH has a new packet (start of new round) + // uint8_t Ndi; + /// Status Flag indicating for this ULSCH (idle,active,disabled) + SCH_status_t status; + /// Subframe scheduling indicator (i.e. Transmission opportunity indicator) + uint8_t subframe_scheduling_flag; + /// Subframe cba scheduling indicator (i.e. Transmission opportunity indicator) + uint8_t subframe_cba_scheduling_flag; + /// First Allocated RB + uint16_t first_rb; + /// Current Number of RBs + uint16_t nb_rb; + /// Last TPC command + uint8_t TPC; + /// Transport block size + uint32_t TBS; + /// The payload + CRC size in bits, "B" from 36-212 + uint32_t B; + /// Length of ACK information (bits) + uint8_t O_ACK; + /// Pointer to the payload + uint8_t *b; + /// Pointers to transport block segments + uint8_t *c[MAX_NUM_ULSCH_SEGMENTS]; + /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) + uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS]; + /// Index of current HARQ round for this ULSCH + uint8_t round; + /// MCS format of this ULSCH + uint8_t mcs; + /// Redundancy-version of the current sub-frame + uint8_t rvidx; + /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 + uint8_t d[MAX_NUM_ULSCH_SEGMENTS][(96+3+(3*6144))]; + /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) + uint8_t w[MAX_NUM_ULSCH_SEGMENTS][3*6144]; + /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) + uint32_t C; + /// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cminus; + /// Number of "large" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cplus; + /// Number of bits in "small" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kminus; + /// Number of bits in "large" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kplus; + /// Total number of bits across all segments + uint32_t sumKr; + /// Number of "Filler" bits (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t F; + /// Msc_initial, Initial number of subcarriers for ULSCH (36-212, v8.6 2009-03, p.26-27) + uint16_t Msc_initial; + /// Nsymb_initial, Initial number of symbols for ULSCH (36-212, v8.6 2009-03, p.26-27) + uint8_t Nsymb_initial; + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) + uint8_t n_DMRS; + /// n_DMRS2 for cyclic shift of DMRS (36.211 Table 5.5.1.1.-1) + uint8_t n_DMRS2; + /// Flag to indicate that this is a control only ULSCH (i.e. no MAC SDU) + uint8_t control_only; + /// Flag to indicate that this is a calibration ULSCH (i.e. no MAC SDU and filled with TDD calibration information) + // int calibration_flag; + /// Number of soft channel bits + uint32_t G; + + // decode phich + uint8_t decode_phich; +} NR_UL_UE_HARQ_t; + +typedef struct { + /// Current Number of Symbols + uint8_t Nsymb_pusch; + /// SRS active flag + uint8_t srs_active; + /// Pointers to 8 HARQ processes for the ULSCH + NR_UL_UE_HARQ_t *harq_processes[8]; + /// Pointer to CQI data (+1 for 8 bits crc) + uint8_t o[1+MAX_CQI_BYTES]; + /// Length of CQI data (bits) + uint8_t O; + /// Format of CQI data + UCI_format_t uci_format; + /// Rank information + uint8_t o_RI[2]; + /// Length of rank information (bits) + uint8_t O_RI; + /// Pointer to ACK + uint8_t o_ACK[4]; + /// Minimum number of CQI bits for PUSCH (36-212 r8.6, Sec 5.2.4.1 p. 37) + uint8_t O_CQI_MIN; + /// ACK/NAK Bundling flag + uint8_t bundling; + /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) + uint8_t e[MAX_NUM_CHANNEL_BITS]; + /// Interleaved "h"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) + uint8_t h[MAX_NUM_CHANNEL_BITS]; + /// Scrambled "b"-sequences (for definition see 36-211 V8.6 2009-03, p.14) + uint8_t b_tilde[MAX_NUM_CHANNEL_BITS]; + /// Modulated "d"-sequences (for definition see 36-211 V8.6 2009-03, p.14) + int32_t d[MAX_NUM_RE]; + /// Transform-coded "z"-sequences (for definition see 36-211 V8.6 2009-03, p.14-15) + int32_t z[MAX_NUM_RE]; + /// "q" sequences for CQI/PMI (for definition see 36-212 V8.6 2009-03, p.27) + uint8_t q[MAX_CQI_PAYLOAD]; + /// coded and interleaved CQI bits + uint8_t o_w[(MAX_CQI_BITS+8)*3]; + /// coded CQI bits + uint8_t o_d[96+((MAX_CQI_BITS+8)*3)]; + /// coded ACK bits + uint8_t q_ACK[MAX_ACK_PAYLOAD]; + /// coded RI bits + uint8_t q_RI[MAX_RI_PAYLOAD]; + /// beta_offset_cqi times 8 + uint16_t beta_offset_cqi_times8; + /// beta_offset_ri times 8 + uint16_t beta_offset_ri_times8; + /// beta_offset_harqack times 8 + uint16_t beta_offset_harqack_times8; + /// power_offset + uint8_t power_offset; + // for cooperative communication + uint8_t cooperation_flag; + /// RNTI attributed to this ULSCH + uint16_t rnti; + /// f_PUSCH parameter for PUSCH power control + int16_t f_pusch; + /// Po_PUSCH - target output power for PUSCH + int16_t Po_PUSCH; + /// PHR - current power headroom (based on last PUSCH transmission) + int16_t PHR; + /// Po_SRS - target output power for SRS + int16_t Po_SRS; + /// num active cba group + uint8_t num_active_cba_groups; + /// num dci found for cba + uint8_t num_cba_dci[10]; + /// allocated CBA RNTI + uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; + /// UL max-harq-retransmission + uint8_t Mlimit; +} NR_UE_ULSCH_t; + + + + +typedef struct { + /// Indicator of first transmission + uint8_t first_tx; + /// Last Ndi received for this process on DCI (used for C-RNTI only) + uint8_t DCINdi; + /// DLSCH status flag indicating + SCH_status_t status; + /// Transport block size + uint32_t TBS; + /// The payload + CRC size in bits + uint32_t B; + /// Pointer to the payload + uint8_t *b; + /// Pointers to transport block segments + uint8_t *c[MAX_NUM_DLSCH_SEGMENTS]; + /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) + uint32_t RTC[MAX_NUM_DLSCH_SEGMENTS]; + /// Index of current HARQ round for this DLSCH + uint8_t round; + /// MCS format for this DLSCH + uint8_t mcs; + /// Qm (modulation order) for this DLSCH + uint8_t Qm; + /// Redundancy-version of the current sub-frame + uint8_t rvidx; + /// MIMO mode for this DLSCH + MIMO_mode_t mimo_mode; + /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + int16_t w[MAX_NUM_DLSCH_SEGMENTS][3*(6144+64)]; + /// for abstraction soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + double w_abs[MAX_NUM_DLSCH_SEGMENTS][3*(6144+64)]; + /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + int16_t *d[MAX_NUM_DLSCH_SEGMENTS]; + /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) + uint32_t C; + /// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cminus; + /// Number of "large" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cplus; + /// Number of bits in "small" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kminus; + /// Number of bits in "large" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kplus; + /// Number of "Filler" bits (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t F; + /// Number of MIMO layers (streams) (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Nl; + /// current delta_pucch + int8_t delta_PUCCH; + /// Number of soft channel bits + uint32_t G; + /// Current Number of RBs + uint16_t nb_rb; + /// Current subband PMI allocation + uint16_t pmi_alloc; + /// Current RB allocation (even slots) + uint32_t rb_alloc_even[4]; + /// Current RB allocation (odd slots) + uint32_t rb_alloc_odd[4]; + /// distributed/localized flag + vrb_t vrb_type; + /// downlink power offset field + uint8_t dl_power_off; + /// trials per round statistics + uint32_t trials[8]; + /// error statistics per round + uint32_t errors[8]; + /// codeword this transport block is mapped to + uint8_t codeword; +} NR_DL_UE_HARQ_t; + + +typedef struct { + /// HARQ process id + uint8_t harq_id; + /// ACK bits (after decoding) 0:NACK / 1:ACK / 2:DTX + uint8_t ack; + /// send status (for PUCCH) + uint8_t send_harq_status; + /// nCCE (for PUCCH) + uint8_t nCCE; + /// DAI value detected from DCI1/1a/1b/1d/2/2a/2b/2c. 0xff indicates not touched + uint8_t vDAI_DL; + /// DAI value detected from DCI0/4. 0xff indicates not touched + uint8_t vDAI_UL; +} nr_harq_status_t; + +typedef struct { + /// RNTI + uint16_t rnti; + /// Active flag for DLSCH demodulation + uint8_t active; + /// Transmission mode + uint8_t mode1_flag; + /// amplitude of PDSCH (compared to RS) in symbols without pilots + int16_t sqrt_rho_a; + /// amplitude of PDSCH (compared to RS) in symbols containing pilots + int16_t sqrt_rho_b; + /// Current HARQ process id threadRx Odd and threadRx Even + uint8_t current_harq_pid; + /// Current subband antenna selection + uint32_t antenna_alloc; + /// Current subband RI allocation + uint32_t ri_alloc; + /// Current subband CQI1 allocation + uint32_t cqi_alloc1; + /// Current subband CQI2 allocation + uint32_t cqi_alloc2; + /// saved subband PMI allocation from last PUSCH/PUCCH report + uint16_t pmi_alloc; + /// HARQ-ACKs + nr_harq_status_t harq_ack[10]; + /// Pointers to up to 8 HARQ processes + NR_DL_UE_HARQ_t *harq_processes[8]; + /// Maximum number of HARQ processes(for definition see 36-212 V8.6 2009-03, p.17 + uint8_t Mdlharq; + /// MIMO transmission mode indicator for this sub-frame (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Kmimo; + /// Nsoft parameter related to UE Category + uint32_t Nsoft; + /// Maximum number of Turbo iterations + uint8_t max_turbo_iterations; + /// number of iterations used in last turbo decoding + uint8_t last_iteration_cnt; + /// accumulated tx power adjustment for PUCCH + int8_t g_pucch; +} NR_UE_DLSCH_t; + + + + +/**@}*/ +#endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/pbch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pbch_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..334faafecd4f0593d2d2b623bb29064468b68a10 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/pbch_nr.c @@ -0,0 +1,100 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : pbch_nr.c +* +* MODULE : broacast channel +* +* DESCRIPTION : generation of pbch +* 3GPP TS 38.211 7.3.3 Physical broadcast channel +* +************************************************************************/ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#include "PHY/defs.h" + +#define DEFINE_VARIABLES_PBCH_NR_H +#include "PHY/NR_REFSIG/pbch_nr.h" +#undef DEFINE_VARIABLES_PBCH_NR_H + +/******************************************************************* +* +* NAME : pseudo_random_gold_sequence +* +* PARAMETERS : +* +* RETURN : generate pseudo-random sequence which is a length-31 Gold sequence +* +* DESCRIPTION : 3GPP TS 38.211 5.2.1 Pseudo-random sequence generation +* Sequence generation +* +*********************************************************************/ + +#define NC (1600) +#define GOLD_LENGTH (31) + +uint32_t *pseudo_random_gold_sequence(length M_PN, uint32_t cinit) +{ + int size = M_PN * sizeof(uint32_t); + int size_x = (sizeof(int)*M_PN + size; + int *x1 = malloc(size_x); + int *x2 = malloc(size_x); + + if ((x1 == NULL) || (x2 == NULL)) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + else { + bzero(x1, size_x); + bzero(x2, size_x); + } + + x1[0] = 1; + + for (n = 0; n < 31; n++) { + x2[n] = (cinit >> n) & 0x1; + } + + for (int n = 0; n < (NC+M_PN); n++) { + x1(n+31) = (x1(n+3) + x1(n))%2; + x2(n+31) = (x2(n+3) + x2(n+2) + x2(n+1) + x2(n))%2; + } + + int *c = calloc(size); + if (c != NULL) { + bzero(c, size); + } + else { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + for (int n = 0; n < M_PN; n++) { + c(i) = (x1(n+NC) + x2(n+NC))%2; + } + + return c; +} diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..8a93271d90bc05defebbbd3f334c7c6c5b5ab72d --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c @@ -0,0 +1,873 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : pss_nr.c +* +* MODULE : synchronisation signal +* +* DESCRIPTION : generation of pss +* 3GPP TS 38.211 7.4.2.2 Primary synchronisation signal +* +************************************************************************/ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#include "PHY/defs_nr_UE.h" + +#include "PHY/NR_REFSIG/ss_pbch_nr.h" + +#define DEFINE_VARIABLES_PSS_NR_H +#include "PHY/NR_REFSIG/pss_nr.h" +#undef DEFINE_VARIABLES_PSS_NR_H + +#include "PHY/NR_REFSIG/sss_nr.h" +#include "PHY/NR_UE_TRANSPORT/cic_filter_nr.h" + +/******************************************************************* +* +* NAME : get_idft +* +* PARAMETERS : size of ofdm symbol +* +* RETURN : function idft +* +* DESCRIPTION : get idft function depending of ofdm size +* +*********************************************************************/ + +void *get_idft(int ofdm_symbol_size) +{ + void (*idft)(int16_t *,int16_t *, int); + + switch (ofdm_symbol_size) { + case 128: + idft = idft128; + break; + + case 256: + idft = idft256; + break; + + case 512: + idft = idft512; + break; + + case 1024: + idft = idft1024; + break; + + case 1536: + idft = idft1536; + break; + + case 2048: + idft = idft2048; + break; + + default: + printf("function get_idft : unsupported ofdm symbol size \n"); + assert(0); + break; + } + return idft; +} + +/******************************************************************* +* +* NAME : get_dft +* +* PARAMETERS : size of ofdm symbol +* +* RETURN : function for discrete fourier transform +* +* DESCRIPTION : get dft function depending of ofdm size +* +*********************************************************************/ + +void *get_dft(int ofdm_symbol_size) +{ + void (*dft)(int16_t *,int16_t *, int); + + switch (ofdm_symbol_size) { + case 128: + dft = dft128; + break; + + case 256: + dft = dft256; + break; + + case 512: + dft = dft512; + break; + + case 1024: + dft = dft1024; + break; + + case 1536: + dft = dft1536; + break; + + case 2048: + dft = dft2048; + break; + + default: + printf("function get_dft : unsupported ofdm symbol size \n"); + assert(0); + break; + } + return dft; +} + +/******************************************************************* +* +* NAME : generate_pss_nr +* +* PARAMETERS : N_ID_2 : element 2 of physical layer cell identity +* value : { 0, 1, 2} +* +* RETURN : generate binary pss sequence (this is a m-sequence) +* +* DESCRIPTION : 3GPP TS 38.211 7.4.2.2 Primary synchronisation signal +* Sequence generation +* +*********************************************************************/ + +void generate_pss_nr(int N_ID_2, int ofdm_symbol_size) +{ + int16_t d_pss[LENGTH_PSS_NR]; + int16_t x[LENGTH_PSS_NR]; + int16_t *primary_synchro_time = primary_synchro_time_nr[N_ID_2]; + unsigned int length = ofdm_symbol_size; + unsigned int size = length * IQ_SIZE; /* i & q */ + int16_t *primary_synchro = primary_synchro_nr[N_ID_2]; /* pss in complex with alternatively i then q */ + void (*idft)(int16_t *,int16_t *, int); + + #define INITIAL_PSS_NR (7) + const int x_initial[INITIAL_PSS_NR] = {0, 1, 1 , 0, 1, 1, 1}; + + assert(N_ID_2 < NUMBER_PSS_SEQUENCE); + assert(size <= SYNCF_TMP_SIZE); + assert(size <= SYNC_TMP_SIZE); + + bzero(synchroF_tmp, size); + bzero(synchro_tmp, size); + + for (int i=0; i < INITIAL_PSS_NR; i++) { + x[i] = x_initial[i]; + } + + for (int i=0; i < (LENGTH_PSS_NR - INITIAL_PSS_NR); i++) { + x[i+INITIAL_PSS_NR] = (x[i + 4] + x[i])%(2); + } + + for (int n=0; n < LENGTH_PSS_NR; n++) { + int m = (n + 43*N_ID_2)%(LENGTH_PSS_NR); + d_pss[n] = 1 - 2*x[m]; + } + + /* PSS is directly mapped to subcarrier without modulation 38.211 */ + for (int i=0; i < LENGTH_PSS_NR; i++) { +#if 1 + primary_synchro[2*i] = (d_pss[i] * SHRT_MAX)>>SCALING_PSS_NR; /* Maximum value for type short int ie int16_t */ + primary_synchro[2*i+1] = 0; +#else + primary_synchro[2*i] = d_pss[i] * AMP; + primary_synchro[2*i+1] = 0; +#endif + } + +#ifdef DBG_PSS_NR + + if (N_ID_2 == 0) { + char output_file[255]; + char sequence_name[255]; + sprintf(output_file, "pss_seq_%d_%d.m", N_ID_2, length); + sprintf(sequence_name, "pss_seq_%d_%d", N_ID_2, length); + printf("file %s sequence %s\n", output_file, sequence_name); + + write_output(output_file, sequence_name, primary_synchro, LENGTH_PSS_NR, 1, 1); + } + +#endif + + /* call of IDFT should be done with ordered input as below + * + * n input samples + * <------------------------------------------------> + * 0 n + * are written into input buffer for IFFT + * ------------------------------------------------- + * |xxxxxxx N/2 xxxxxxxx| + * -------------------------------------------------- + * ^ ^ ^ ^ ^ + * | | | | | + * n/2 end of n=0 start of n/2-1 + * pss pss + * + * Frequencies + * positives negatives + * 0 (+N/2)(-N/2) + * |-----------------------><-------------------------| + * + * sample 0 is for continuous frequency which is used here + */ + + unsigned int k = length - (LENGTH_PSS_NR/2+1); + + for (int i=0; i < LENGTH_PSS_NR; i++) { + synchroF_tmp[2*k] = primary_synchro[2*i]; + synchroF_tmp[2*k+1] = primary_synchro[2*i+1]; + + k++; + + if (k >= length) { + k++; + k-=length; + } + } + + /* IFFT will give temporal signal of Pss */ + + idft = get_idft(length); + + idft(synchroF_tmp, /* complex input */ + synchro_tmp, /* complex output */ + 1); /* scaling factor */ + + /* then get final pss in time */ + for (unsigned int i=0; i<length; i++) { + ((int32_t *)primary_synchro_time)[i] = ((int32_t *)synchro_tmp)[i]; + } + +#ifdef DBG_PSS_NR + + if (N_ID_2 == 0) { + char output_file[255]; + char sequence_name[255]; + sprintf(output_file, "%s%d_%d%s","pss_seq_t_", N_ID_2, length, ".m"); + sprintf(sequence_name, "%s%d_%d","pss_seq_t_", N_ID_2, length); + + printf("file %s sequence %s\n", output_file, sequence_name); + + write_output(output_file, sequence_name, primary_synchro_time, length, 1, 1); + } + +#endif + + +#if 0 + +/* it allows checking that process of idft on a signal and then dft gives same signal with limited errors */ + + if ((N_ID_2 == 0) && (length == 256)) { + + write_output("pss_f00.m","pss_f00",synchro_tmp,length,1,1); + + + bzero(synchroF_tmp, size); + + void (*dft)(int16_t *,int16_t *, int) = get_dft(length); + + /* get pss in the time domain by applying an inverse FFT */ + dft(synchro_tmp, /* complex input */ + synchroF_tmp, /* complex output */ + 1); /* scaling factor */ + + if ((N_ID_2 == 0) && (length == 256)) { + write_output("pss_f_0.m","pss_f_0",synchroF_tmp,length,1,1); + } + + /* check Pss */ + k = length - (LENGTH_PSS_NR/2); + +#define LIMIT_ERROR_FFT (10) + + for (int i=0; i < LENGTH_PSS_NR; i++) { + if (abs(synchroF_tmp[2*k] - primary_synchro[2*i]) > LIMIT_ERROR_FFT) { + printf("Pss Error[%d] Compute %d Reference %d \n", k, synchroF_tmp[2*k], primary_synchro[2*i]); + } + + if (abs(synchroF_tmp[2*k+1] - primary_synchro[2*i+1]) > LIMIT_ERROR_FFT) { + printf("Pss Error[%d] Compute %d Reference %d\n", (2*k+1), synchroF_tmp[2*k+1], primary_synchro[2*i+1]); + } + + k++; + + if (k >= length) { + k-=length; + } + } + } +#endif +} + +/******************************************************************* +* +* NAME : init_context_pss_nr +* +* PARAMETERS : structure NR_DL_FRAME_PARMS give frame parameters +* +* RETURN : generate binary pss sequences (this is a m-sequence) +* +* DESCRIPTION : 3GPP TS 38.211 7.4.2.2 Primary synchronisation signal +* Sequence generation +* +*********************************************************************/ + +void init_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue) +{ + int ofdm_symbol_size = frame_parms_ue->ofdm_symbol_size; + int sizePss = LENGTH_PSS_NR * IQ_SIZE; /* complex value i & q signed 16 bits */ + int size = ofdm_symbol_size * IQ_SIZE; /* i and q samples signed 16 bits */ + int16_t *p = NULL; + int *q = NULL; + + for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) { + + p = malloc16(sizePss); /* pss in complex with alternatively i then q */ + if (p != NULL) { + primary_synchro_nr[i] = p; + bzero( primary_synchro_nr[i], sizePss); + } + else { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + p = malloc16(size); + if (p != NULL) { + primary_synchro_time_nr[i] = p; + bzero( primary_synchro_time_nr[i], size); + } + else { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + size = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(int)*frame_parms_ue->samples_per_subframe; + q = malloc16(size); + if (q != NULL) { + pss_corr_ue[i] = q; + bzero( pss_corr_ue[i], size); + } + else { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + generate_pss_nr(i, ofdm_symbol_size); + } +} + +/******************************************************************* +* +* NAME : free_context_pss_nr +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : free context related to pss +* +*********************************************************************/ + +void free_context_pss_nr(void) +{ + for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) { + + if (primary_synchro_time_nr[i] != NULL) { + free(primary_synchro_time_nr[i]); + primary_synchro_time_nr[i] = NULL; + } + else { + msg("Fatal memory deallocation problem \n"); + assert(0); + } + + if (primary_synchro_nr[i] != NULL) { + free(primary_synchro_nr[i]); + primary_synchro_nr[i] = NULL; + } + else { + msg("Fatal memory deallocation problem \n"); + assert(0); + } + + if (pss_corr_ue[i] != NULL) { + free(pss_corr_ue[i]); + pss_corr_ue[i] = NULL; + } + else { + msg("Fatal memory deallocation problem \n"); + assert(0); + } + } +} + +/******************************************************************* +* +* NAME : init_context_synchro_nr +* +* PARAMETERS : none +* +* RETURN : generate context for pss and sss +* +* DESCRIPTION : initialise contexts and buffers for synchronisation +* +*********************************************************************/ + +void init_context_synchro_nr(NR_DL_FRAME_PARMS *frame_parms_ue) +{ +#ifndef STATIC_SYNC_BUFFER + + /* initialise global buffers for synchronisation */ + synchroF_tmp = malloc16(SYNCF_TMP_SIZE); + if (synchroF_tmp == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + + synchro_tmp = malloc16(SYNC_TMP_SIZE); + if (synchro_tmp == NULL) { + msg("Fatal memory allocation problem \n"); + assert(0); + } + +#endif + + init_context_pss_nr(frame_parms_ue); + + init_context_sss_nr(AMP); +} + +/******************************************************************* +* +* NAME : free_context_synchro_nr +* +* PARAMETERS : none +* +* RETURN : free context for pss and sss +* +* DESCRIPTION : deallocate memory of synchronisation +* +*********************************************************************/ + +void free_context_synchro_nr(void) +{ +#ifndef STATIC_SYNC_BUFFER + + if (synchroF_tmp != NULL) { + free(synchroF_tmp); + synchroF_tmp = NULL; + } + else { + msg("Fatal memory deallocation problem \n"); + assert(0); + } + + if (synchro_tmp != NULL) { + free(synchro_tmp); + synchro_tmp = NULL; + } + else { + msg("Fatal memory deallocation problem \n"); + assert(0); + } + +#endif + + free_context_pss_nr(); +} + +/******************************************************************* +* +* NAME : set_frame_context_pss_nr +* +* PARAMETERS : configuration for UE with new FFT size +* +* RETURN : 0 if OK else error +* +* DESCRIPTION : initialisation of UE contexts +* +*********************************************************************/ + +void set_frame_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue, int rate_change) +{ + /* set new value according to rate_change */ + frame_parms_ue->ofdm_symbol_size = (frame_parms_ue->ofdm_symbol_size / rate_change); + frame_parms_ue->samples_per_tti = (frame_parms_ue->samples_per_tti / rate_change); + frame_parms_ue->samples_per_subframe = (frame_parms_ue->samples_per_subframe / rate_change); + + free_context_pss_nr(); + + /* pss reference have to be rebuild with new parameters ie ofdm symbol size */ + init_context_synchro_nr(frame_parms_ue); + +#ifdef SYNCHRO_DECIMAT + set_pss_nr(frame_parms_ue->ofdm_symbol_size); +#endif +} + +/******************************************************************* +* +* NAME : restore_frame_context_pss_nr +* +* PARAMETERS : configuration for UE and eNB with new FFT size +* +* RETURN : 0 if OK else error +* +* DESCRIPTION : initialisation of UE and eNode contexts +* +*********************************************************************/ + +void restore_frame_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue, int rate_change) +{ + frame_parms_ue->ofdm_symbol_size = frame_parms_ue->ofdm_symbol_size * rate_change; + frame_parms_ue->samples_per_tti = frame_parms_ue->samples_per_tti * rate_change; + frame_parms_ue->samples_per_subframe = frame_parms_ue->samples_per_subframe * rate_change; + + free_context_pss_nr(); + + /* pss reference have to be rebuild with new parameters ie ofdm symbol size */ + init_context_synchro_nr(frame_parms_ue); +#ifdef SYNCHRO_DECIMAT + set_pss_nr(frame_parms_ue->ofdm_symbol_size); +#endif +} + +/******************************************************************** +* +* NAME : decimation_synchro_nr +* +* INPUT : UE context +* for first and second pss sequence +* - position of pss in the received UE buffer +* - number of pss sequence +* +* RETURN : 0 if OK else error +* +* DESCRIPTION : detect pss sequences in the received UE buffer +* +********************************************************************/ + +void decimation_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change, int **rxdata) +{ + NR_DL_FRAME_PARMS *frame_parms = &(PHY_vars_UE->frame_parms); + int samples_for_frame = LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti; + +#if TEST_SYNCHRO_TIMING_PSS + + opp_enabled = 1; + + start_meas(&generic_time[TIME_RATE_CHANGE]); + +#endif + +/* build with cic filter does not work properly. Performances are significantly deteriorated */ +#ifdef CIC_DECIMATOR + + cic_decimator((int16_t *)&(PHY_vars_UE->common_vars.rxdata[0][0]), (int16_t *)&(rxdata[0][0]), + samples_for_frame, rate_change, CIC_FILTER_STAGE_NUMBER, 0, FIR_RATE_CHANGE); +#else + + fir_decimator((int16_t *)&(PHY_vars_UE->common_vars.rxdata[0][0]), (int16_t *)&(rxdata[0][0]), + samples_for_frame, rate_change, 0); + +#endif + + set_frame_context_pss_nr(frame_parms, rate_change); + +#if TEST_SYNCHRO_TIMING_PSS + + stop_meas(&generic_time[TIME_RATE_CHANGE]); + + printf("Rate change execution duration %5.2f \n", generic_time[TIME_RATE_CHANGE].p_time/(cpuf*1000.0)); + +#endif +} + +/******************************************************************* +* +* NAME : pss_synchro_nr +* +* PARAMETERS : int rate_change +* +* RETURN : position of detected pss +* +* DESCRIPTION : pss search can be done with sampling decimation.* +* +*********************************************************************/ + +int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change) +{ + NR_DL_FRAME_PARMS *frame_parms = &(PHY_vars_UE->frame_parms); + int synchro_position; + int **rxdata = NULL; + +#ifdef DBG_PSS_NR + + int samples_for_frame = frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME; + + write_output("rxdata0_rand.m","rxd0_rand", &PHY_vars_UE->common_vars.rxdata[0][0], samples_for_frame, 1, 1); + +#endif + + if (rate_change != 1) { + + rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*)); + + for (int aa=0; aa < frame_parms->nb_antennas_rx; aa++) { + rxdata[aa] = (int32_t*) malloc16_clear( (frame_parms->samples_per_subframe*10+2048)*sizeof(int32_t)); + } +#ifdef SYNCHRO_DECIMAT + + decimation_synchro_nr(PHY_vars_UE, rate_change, rxdata); + +#endif + } + else { + + rxdata = PHY_vars_UE->common_vars.rxdata; + } + +#ifdef DBG_PSS_NR + + write_output("rxdata0_des.m","rxd0_des", &rxdata[0][0], samples_for_frame,1,1); + +#endif + +#if TEST_SYNCHRO_TIMING_PSS + + opp_enabled = 1; + + start_meas(&generic_time[TIME_PSS]); + +#endif + +#if 1 + + synchro_position = pss_search_time_nr(rxdata, + frame_parms, + (int *)&PHY_vars_UE->common_vars.eNb_id); + +#else + + synchro_position = lte_sync_time(rxdata, + frame_parms, + (int *)&PHY_vars_UE->common_vars.eNb_id); +#endif + +#if TEST_SYNCHRO_TIMING_PSS + + stop_meas(&generic_time[TIME_PSS]); + + printf("PSS execution duration %5.2f \n", generic_time[TIME_PSS].p_time/(cpuf*1000.0)); + +#endif + +#ifdef SYNCHRO_DECIMAT + + if (rate_change != 1) { + + if (rxdata[0] != NULL) { + + for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) { + free(rxdata[aa]); + } + + free(rxdata); + } + + restore_frame_context_pss_nr(frame_parms, rate_change); + } +#endif + + return synchro_position; +} + +static inline int abs32(int x) +{ + return (((int)((short*)&x)[0])*((int)((short*)&x)[0]) + ((int)((short*)&x)[1])*((int)((short*)&x)[1])); +} + +/******************************************************************* +* +* NAME : pss_search_time_nr +* +* PARAMETERS : received buffer +* frame parameters +* +* RETURN : position of detected pss +* +* DESCRIPTION : Synchronisation on pss sequence is based on a time domain correlation between received samples and pss sequence +* A maximum likelihood detector finds the timing offset (position) that corresponds to the maximum correlation +* Length of received buffer should be a minimum of 2 frames (see TS 38.213 4.1 Cell search) +* Search pss in the received buffer is done each 4 samples which ensures a memory alignment to 128 bits (32 bits x 4). +* This is required by SIMD (single instruction Multiple Data) Extensions of Intel processors +* Correlation computation is based on a a dot product which is realized thank to SIMS extensions +* +* (x frames) +* <---------------------------------------------------------------------------> +* +* +* ----------------------------------------------------------------------------- +* | Received UE data buffer | +* ---------------------------------------------------------------------------- +* ------------- +* <--------->| pss | +* position ------------- +* ^ +* | +* peak position +* given by maximum of correlation result +* position matches beginning of first ofdm symbol of pss sequence +* +* Remark: memory position should be aligned on a multiple of 4 due to I & Q samples of int16 +* An OFDM symbol is composed of x number of received samples depending of Rf front end sample rate. +* +* I & Q storage in memory +* +* First samples Second samples +* ------------------------- ------------------------- ... +* | I1 | Q1 | I2 | Q2 | +* --------------------------------------------------- ... +* ^ 16 bits 16 bits ^ +* | | +* --------------------------------------------------- ... +* | sample 1 | sample 2 | +* ---------------------------------------------------- ... +* ^ +* +*********************************************************************/ + +#define DOT_PRODUCT_SCALING_SHIFT (17) + +int pss_search_time_nr(int **rxdata, ///rx data in time domain + NR_DL_FRAME_PARMS *frame_parms, + int *eNB_id) +{ + unsigned int n, ar, peak_position, peak_value, pss_source; + int result; + int synchro_out; + unsigned int tmp[NUMBER_PSS_SEQUENCE]; + unsigned int length = (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->ttis_per_subframe*frame_parms->samples_per_tti); /* 1 frame for now, it should be 2 TODO_NR */ + + for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) { + tmp[i] = 0; + if (pss_corr_ue[i] == NULL) { + msg("[SYNC TIME] pss_corr_ue[%d] not yet allocated! Exiting.\n", i); + return(-1); + } + } + + peak_value = 0; + peak_position = 0; + pss_source = 0; + + /* Search pss in the received buffer each 4 samples which ensures a memory alignment on 128 bits (32 bits x 4 ) */ + /* This is required by SIMD (single instruction Multiple Data) Extensions of Intel processors. */ + /* Correlation computation is based on a a dot product which is realized thank to SIMS extensions */ + for (n=0; n < length; n+=4) { + +#ifdef RTAI_ENABLED + + // This is necessary since the sync takes a long time and it seems to block all other threads thus screwing up RTAI. If we pause it for a little while during its execution we give RTAI a chance to catch up with its other tasks. + if ((n%frame_parms->samples_per_subframe == 0) && (n>0) && (openair_daq_vars.sync_state==0)) { +#ifdef DEBUG_PHY + msg("[SYNC TIME] pausing for 1000ns, n=%d\n",n); +#endif + rt_sleep(nano2count(1000)); + } + +#endif + + for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) { + + pss_corr_ue[pss_index][n] = 0; /* clean correlation for position n */ + + synchro_out = 0; + + if ( n < (length - frame_parms->ofdm_symbol_size)) { + + /* calculate dot product of primary_synchro_time_nr and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n]; */ + for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) { + + /* perform correlation of rx data and pss sequence ie it is a dot product */ + result = dot_product((short*)primary_synchro_time_nr[pss_index], (short*) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, DOT_PRODUCT_SCALING_SHIFT); + + ((short*)pss_corr_ue[pss_index])[2*n] += ((short*) &result)[0]; /* real part */ + ((short*)pss_corr_ue[pss_index])[2*n+1] += ((short*) &result)[1]; /* imaginary part */ + ((short*)&synchro_out)[0] += ((short*) &result)[0]; /* real part */ + ((short*)&synchro_out)[1] += ((short*) &result)[1]; /* imaginary part */ + } + } + + pss_corr_ue[pss_index][n] = abs32(pss_corr_ue[pss_index][n]); + + /* calculate the absolute value of sync_corr[n] */ + tmp[pss_index] = (abs32(synchro_out)) ; + + if (tmp[pss_index] > peak_value) { + peak_value = tmp[pss_index]; + peak_position = n; + pss_source = pss_index; + + //printf("pss_index %d: n %6d peak_value %10d, synchro_out (% 6d,% 6d) \n", pss_index, n, abs32(synchro_out),((int16_t*)&synchro_out)[0],((int16_t*)&synchro_out)[1]); + } + } + } + + *eNB_id = pss_source; + + LOG_I(PHY,"[UE] nr_synchro_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n", pss_source, peak_position, peak_value, dB_fixed(peak_value)/2); + +#ifdef DEBUG_PSS_NR + +#define PSS_DETECTION_FLOOR_NR (31) + if ((dB_fixed(peak_value)/2) > PSS_DETECTION_FLOOR_NR) { + + printf("[UE] nr_synchro_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n", pss_source, peak_position, peak_value,dB_fixed(peak_value)/2); + } +#endif + +#ifdef DEBUG_PHY + + if (debug_cnt == 0) { + write_output("pss_corr_ue0.m","pss_corr_ue0",pss_corr_ue[0],length,1,2); + write_output("pss_corr_ue1.m","pss_corr_ue1",pss_corr_ue[1],length,1,2); + write_output("pss_corr_ue2.m","pss_corr_ue2",pss_corr_ue[2],length,1,2); + write_output("rxdata0.m","rxd0",rxdata[0],length,1,1); + } else { + debug_cnt++; + } + +#endif + + return(peak_position); +} + diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..aba3c12636e3a675aa0c4b9ed4bcf2e9b09bba9a --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c @@ -0,0 +1,488 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : srs_modulation_nr_nr.c +* +* MODULE : +* +* DESCRIPTION : function to set uplink reference symbols +* see TS 38211 6.4.1.4 Sounding reference signal +* +************************************************************************/ + +#include <stdio.h> +#include <math.h> + +#define DEFINE_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H +#include "PHY/impl_defs_nr.h" +#undef DEFINE_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H + +#include "PHY/defs_nr_UE.h" +//#include "extern.h" +#include "PHY/NR_REFSIG/ss_pbch_nr.h" +#include "PHY/NR_REFSIG/dmrs_nr.h" +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + +#define DEFINE_VARIABLES_SRS_MODULATION_NR_H +#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" +#undef DEFINE_VARIABLES_SRS_MODULATION_NR_H + +/******************************************************************* +* +* NAME : generate_srs +* +* PARAMETERS : pointer to resource set +* pointer to transmit buffer +* amplitude scaling for this physical signal +* slot number of transmission +* RETURN : 0 if srs sequence has been successfully generated +* -1 if sequence can not be properly generated +* +* DESCRIPTION : generate/map srs symbol into transmit buffer +* see TS 38211 6.4.1.4 Sounding reference signal +* +* FFS_TODO_NR +* Current supported configuration: +* - single resource per resource set +* - single port antenna +* - 1 symbol for SRS +* - no symbol offset +* - periodic mode +* - no hopping +* - no carrier switching +* - no antenna switching* +* +*********************************************************************/ +int32_t generate_srs_nr(SRS_ResourceSet_t *p_srs_resource_set, + NR_DL_FRAME_PARMS *frame_parms, + int32_t *txptr, + int16_t amp, + UE_nr_rxtx_proc_t *proc) +{ + uint8_t n_SRS_cs_max; + uint8_t u, v_nu; + uint32_t f_gh = 0; + SRS_Resource_t *p_SRS_Resource; + int frame_number = proc->frame_tx; + int slot_number = proc->nr_tti_tx; + uint16_t n_SRS, n_SRS_cs_i; + double alpha_i; + uint8_t K_TC_p; + uint16_t n_b[B_SRS_NUMBER], F_b, subcarrier; + uint8_t N_b, k_0_overbar_p; + + if (p_srs_resource_set->p_srs_ResourceList[0] == NULL) { + LOG_E(PHY,"generate_srs: No resource associated with the SRS resource set!\n"); + return (-1); + } + else { + if (p_srs_resource_set->number_srs_Resource <= MAX_NR_OF_SRS_RESOURCES_PER_SET) { + p_SRS_Resource = p_srs_resource_set->p_srs_ResourceList[0]; + } + else { + LOG_E(PHY,"generate_srs: resource number of this resource set %d exceeds maximum supported value %d!\n", p_srs_resource_set->number_srs_Resource, MAX_NR_OF_SRS_RESOURCES_PER_SET); + return (-1); + } + } + + if (p_srs_resource_set->resourceType != periodic) { + LOG_E(PHY,"generate_srs: only SRS periodic is supported up to now!\n"); + return (-1); + } + /* get parameters from SRS resource configuration */ + uint8_t B_SRS = p_SRS_Resource->freqHopping_b_SRS; + uint8_t C_SRS = p_SRS_Resource->freqHopping_c_SRS; + uint8_t b_hop = p_SRS_Resource->freqHopping_b_hop; + uint8_t K_TC = p_SRS_Resource->transmissionComb; + uint8_t K_TC_overbar = p_SRS_Resource->combOffset; /* FFS_TODO_NR is this parameter for K_TC_overbar ?? */ + uint8_t n_SRS_cs = p_SRS_Resource->cyclicShift; + uint8_t n_ID_SRS = p_SRS_Resource->sequenceId; + uint8_t n_shift = p_SRS_Resource->freqDomainPosition; /* it adjusts the SRS allocation to align with the common resource block grid in multiples of four */ + uint8_t n_RRC = p_SRS_Resource->freqDomainShift; + uint8_t groupOrSequenceHopping = p_SRS_Resource->groupOrSequenceHopping; + + uint8_t l_offset = p_SRS_Resource->resourceMapping_startPosition; + + uint16_t T_SRS = srs_period[p_SRS_Resource->SRS_Periodicity]; + uint16_t T_offset = p_SRS_Resource->SRS_Offset;; /* FFS_TODO_NR to check interface with RRC */ + uint8_t R = p_SRS_Resource->resourceMapping_repetitionFactor; + + /* TS 38.211 6.4.1.4.1 SRS resource */ + uint8_t N_ap = (uint8_t)p_SRS_Resource->nrof_SrsPorts; /* antenna port for transmission */ + uint8_t N_symb_SRS = p_SRS_Resource->resourceMapping_nrofSymbols; /* consecutive OFDM symbols */ + uint8_t l0 = N_SYMB_SLOT - 1 - l_offset; /* starting position in the time domain */ + uint8_t k_0_p; /* frequency domain starting position */ + + if (N_ap != port1) { + LOG_E(PHY, "generate_srs: this number of antenna ports %d is not yet supported!\n", N_ap); + return (-1); + } + if (N_symb_SRS != 1) { + LOG_E(PHY, "generate_srs: this number of srs symbol %d is not yet supported!\n", N_symb_SRS); + return (-1); + } + if (groupOrSequenceHopping != neitherHopping) { + LOG_E(PHY, "generate_srs: sequence hopping is not yet supported!\n"); + return (-1); + } + if (R == 0) { + LOG_E(PHY, "generate_srs: this parameter repetition factor %d is not consistent !\n", R); + return (-1); + } + else if (R > N_symb_SRS) { + LOG_E(PHY, "generate_srs: R %d can not be greater than N_symb_SRS %d !\n", R, N_symb_SRS); + return (-1); + } + /* see 38211 6.4.1.4.2 Sequence generation */ + if (K_TC == 4) { + n_SRS_cs_max = 12; + // delta = 2; /* delta = log2(K_TC) */ + } + else if (K_TC == 2) { + n_SRS_cs_max = 8; + // delta = 1; /* delta = log2(K_TC) */ + } + else { + LOG_E(PHY, "generate_srs: SRS unknown value for K_TC %d !\n", K_TC); + return (-1); + } + if (n_SRS_cs >= n_SRS_cs_max) { + LOG_E(PHY, "generate_srs: inconsistent parameter n_SRS_cs %d >= n_SRS_cs_max %d !\n", n_SRS_cs, n_SRS_cs_max); + return (-1); + } + if (T_SRS == 0) { + LOG_E(PHY, "generate_srs: inconsistent parameter T_SRS %d can not be equal to zero !\n", T_SRS); + return (-1); + } + else + { + int index = 0; + while (srs_periodicity[index] != T_SRS) { + index++; + if (index == SRS_PERIODICITY) { + LOG_E(PHY, "generate_srs: inconsistent parameter T_SRS %d not specified !\n", T_SRS); + return (-1); + } + } + } + + uint16_t m_SRS_b = srs_bandwidth_config[C_SRS][B_SRS][0]; /* m_SRS_b is given by TS 38211 clause 6.4.1.4.3 */ + uint16_t M_sc_b_SRS = m_SRS_b * N_SC_RB/K_TC; /* length of the sounding reference signal sequence */ + + /* for each antenna ports for transmission */ + for (int p_index = 0; p_index < N_ap; p_index++) { + + /* see TS 38.211 6.4.1.4.2 Sequence generation */ + + n_SRS_cs_i = (n_SRS_cs + (n_SRS_cs_max * (SRS_antenna_port[p_index] - 1000)/N_ap))%n_SRS_cs_max; + alpha_i = 2 * M_PI * ((double)n_SRS_cs_i / (double)n_SRS_cs_max); + + /* for each SRS symbol which should be managed by SRS configuration */ + /* from TS 38.214 6.2.1.1 UE SRS frequency hopping procedure */ + /* A UE may be configured to transmit an SRS resource on adjacent symbols within the last six symbols of a slot, */ + /* where all antenna ports of the SRS resource are mapped to each symbol of the resource */ + + + uint8_t l = p_index; + if (l >= N_symb_SRS) { + LOG_E(PHY, "generate_srs: number of antenna ports %d and number of srs symbols %d are different !\n", N_ap, N_symb_SRS); + } + + switch(groupOrSequenceHopping) { + case neitherHopping: + { + f_gh = 0; + v_nu = 0; + break; + } + case groupHopping: + { + uint8_t c_last_index = 8 * (slot_number * N_SYMB_SLOT + l0 + l) + 7; /* compute maximum value of the random sequence */ + uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t)); + uint32_t cinit = n_ID_SRS/30; + pseudo_random_sequence(c_last_index+1, c_sequence, cinit); + for (int m = 0; m < 8; m++) { + f_gh += c_sequence[8 * (slot_number * N_SYMB_SLOT + l0 + l) + m]<<m; + } + free(c_sequence); + f_gh = f_gh%30; + v_nu = 0; + break; + } + case sequenceHopping: + { + f_gh = 0; + if (M_sc_b_SRS > 6 * N_SC_RB) { + uint8_t c_last_index = (slot_number * N_SYMB_SLOT + l0 + l); /* compute maximum value of the random sequence */ + uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t)); + uint32_t cinit = n_ID_SRS; + pseudo_random_sequence(c_last_index+1, c_sequence, cinit); + v_nu = c_sequence[c_last_index]; + free(c_sequence); + } + else { + v_nu = 0; + } + break; + } + default: + { + LOG_E(PHY, "generate_srs: unknown hopping setting %d !\n", groupOrSequenceHopping); + return (-1); + } + } + + /* u is the sequence-group number defined in section 6.4.1.4.1 */ + u = (f_gh + n_ID_SRS)%U_GROUP_NUMBER; /* 30 */ + + /* TS 38.211 6.4.1.4.3 Mapping to physical resources */ + + if((n_SRS_cs >= n_SRS_cs_max/2)&&(n_SRS_cs < n_SRS_cs_max)&&(N_ap == 4) && ((SRS_antenna_port[p_index] == 1001) || (SRS_antenna_port[p_index] == 1003))) { + K_TC_p = (K_TC_overbar + K_TC/2)%K_TC; + } + else { + K_TC_p = K_TC_overbar; + } + + for (int b = 0; b <= B_SRS; b++) { + N_b = srs_bandwidth_config[C_SRS][b][1]; + if (b_hop >= B_SRS) { + n_b[b] = (4 * n_RRC/m_SRS_b)%N_b; /* frequency hopping is disabled and the frequency position index n_b remains constant */ + } + else { + if (b == b_hop) { + N_b = 1; + } + /* periodicity and offset */ + if (p_srs_resource_set->resourceType == aperiodic) { + n_SRS = l/R; + } + else { + int8_t N_slot_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * frame_parms->ttis_per_subframe; + n_SRS = ((N_slot_frame*frame_number + slot_number - T_offset)/T_SRS)*(N_symb_SRS/R)+(l/R); + } + + uint16_t product_N_b = 1; /* for b_hop to b-1 */ + for (unsigned int b_prime = b_hop; b_prime < B_SRS; b_prime++) { /* product for b_hop to b-1 */ + if (b_prime != b_hop) { + product_N_b *= srs_bandwidth_config[C_SRS][b_prime][1]; + } + } + + if (N_b & 1) { /* Nb odd */ + F_b = (N_b/2)*(n_SRS/product_N_b); + } + else { /* Nb even */ + uint16_t product_N_b_B_SRS = product_N_b; + product_N_b_B_SRS *= srs_bandwidth_config[C_SRS][B_SRS][1]; /* product for b_hop to b */ + F_b = (N_b/2)*((n_SRS%product_N_b_B_SRS)/product_N_b) + ((n_SRS%product_N_b_B_SRS)/2*product_N_b); + } + + if (b <= b_hop) { + n_b[b] = (4 * n_RRC/m_SRS_b)%N_b; + } + else { + n_b[b] = (F_b + (4 * n_RRC/m_SRS_b))%N_b; + } + } + } + + k_0_overbar_p = n_shift * N_SC_RB + K_TC_p; + + k_0_p = k_0_overbar_p; /* it is the frequency-domain starting position */ + + for (int b = 0; b <= B_SRS; b++) { + k_0_p += K_TC * M_sc_b_SRS * n_b[b]; + } + + subcarrier = (frame_parms->first_carrier_offset) + k_0_p; + if (subcarrier>frame_parms->ofdm_symbol_size) { + subcarrier -= frame_parms->ofdm_symbol_size; + } + + /* find index of table which is for this srs length */ + unsigned int M_sc_b_SRS_index = 0; + while((ul_allocated_re[M_sc_b_SRS_index] != M_sc_b_SRS) && (M_sc_b_SRS_index < SRS_SB_CONF)){ + M_sc_b_SRS_index++; + } + + if (ul_allocated_re[M_sc_b_SRS_index] != M_sc_b_SRS) { + LOG_E(PHY, "generate_srs: srs uplink allocation %d can not be found! \n", M_sc_b_SRS); + return (-1); + } + +#if 0 + + char output_file[255]; + char sequence_name[255]; + sprintf(output_file, "rv_seq_%d_%d_%d.m", u, v_nu, ul_allocated_re[M_sc_b_SRS_index]); + sprintf(sequence_name, "rv_seq_%d_%d_%d", u, v_nu, ul_allocated_re[M_sc_b_SRS_index]); + write_output(output_file, sequence_name, rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index], ul_allocated_re[M_sc_b_SRS_index], 1, 1); + +#endif + + for (int k=0; k < M_sc_b_SRS; k++) { + + double real_shift = cos(alpha_i*k); + double imag_shift = sin(alpha_i*k); + + /* cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */ + double real = ((real_shift*rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k]) - (imag_shift*rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k+1]))/sqrt(N_ap); + /* sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */ + double imag = ((imag_shift*rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k]) + (real_shift*rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k+1]))/sqrt(N_ap); + + int32_t real_amp = ((int32_t)round((double) amp * real)) >> 15; + int32_t imag_amp = ((int32_t)round((double) amp * imag)) >> 15; + +#if 0 + printf("subcarrier %5d srs[%3d] r: %4d i: %4d reference[%d][%d][%d] r: %6d i: %6d\n", subcarrier, k, real_amp, imag_amp, + u, v_nu, M_sc_b_SRS_index, + rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k], + rv_ul_ref_sig[u][v_nu][M_sc_b_SRS_index][2*k+1]); +#endif + + txptr[subcarrier] = (real_amp & 0xFFFF) + ((imag_amp<<16)&0xFFFF0000); + + subcarrier += (K_TC); /* subcarrier increment */ + + if (subcarrier >= frame_parms->ofdm_symbol_size) + subcarrier=subcarrier-frame_parms->ofdm_symbol_size; + } + /* process next symbol */ + txptr = txptr + frame_parms->ofdm_symbol_size; + } + + return (0); +} + +/******************************************************************* +* +* NAME : is_srs_period_nr +* +* PARAMETERS : pointer to resource set +* pointer to transmit buffer +* amplitude scaling for this physical signal +* slot number of transmission +* RETURN : 0 if it is a valid slot for transmitting srs +* -1 if srs should not be transmitted +* +* DESCRIPTION : for periodic, +* +*********************************************************************/ +int is_srs_period_nr(SRS_Resource_t *p_SRS_Resource, NR_DL_FRAME_PARMS *frame_parms, int frame_tx, int slot_tx) +{ + uint16_t T_SRS = srs_period[p_SRS_Resource->SRS_Periodicity]; + uint16_t T_offset = p_SRS_Resource->SRS_Offset; /* FFS_TODO_NR to check interface */ + + if (T_offset > T_SRS) { + LOG_E(PHY,"is_srs_occasion_nr: T_offset %d is greater than T_SRS %d!\n", T_offset, T_SRS); + return (-1); + } + + int16_t N_slot_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * frame_parms->ttis_per_subframe; + if ((N_slot_frame*frame_tx + slot_tx - T_offset)%T_SRS == 0) { + return (0); + } + else { + return (-1); + } +} + +/******************************************************************* +* +* NAME : ue_srs_procedure_nr +* +* PARAMETERS : pointer to ue context +* pointer to rxtx context* +* +* RETURN : 0 if it is a valid slot for transmitting srs +* -1 if srs should not be transmitted +* +* DESCRIPTION : ue srs procedure +* send srs according to current configuration +* +*********************************************************************/ +int ue_srs_procedure_nr(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t eNB_id) +{ + NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); + SRS_NR *p_srs_nr = &(ue->frame_parms.srs_nr); + SRS_ResourceSet_t *p_srs_resource_set = frame_parms->srs_nr.p_SRS_ResourceSetList[p_srs_nr->active_srs_Resource_Set]; + int generate_srs = 0; + + /* is there any resource set which has been configurated ? */ + if (p_srs_nr->number_srs_Resource_Set != 0) { + + /* what is the current active resource set ? */ + if (p_srs_nr->active_srs_Resource_Set > MAX_NR_OF_SRS_RESOURCE_SET) { + LOG_W(PHY,"phy_procedures_UE_TX: srs active %d greater than maximum %d!\n", p_srs_nr->active_srs_Resource_Set, MAX_NR_OF_SRS_RESOURCE_SET); + } + else { + /* SRS resource set configurated ? */ + if (p_srs_resource_set != NULL) { + + SRS_Resource_t *p_srs_resource = frame_parms->srs_nr.p_SRS_ResourceSetList[p_srs_nr->active_srs_Resource_Set]->p_srs_ResourceList[0]; + + /* SRS resource configurated ? */ + if (p_srs_resource != NULL) { + if (p_srs_resource_set->resourceType == periodic) { + if (is_srs_period_nr(p_srs_resource, frame_parms, proc->frame_tx, proc->nr_tti_tx) == 0) { + generate_srs = 1; + } + } + } + else { + LOG_W(PHY,"phy_procedures_UE_TX: no configurated srs resource!\n"); + } + } + } + } + if (generate_srs == 1) { + int16_t txptr = AMP; + uint16_t nsymb = (ue->frame_parms.Ncp==0) ? 14:12; + uint16_t symbol_offset = (int)ue->frame_parms.ofdm_symbol_size*((proc->nr_tti_tx*nsymb)+(nsymb-1)); + if (generate_srs_nr(p_srs_resource_set, frame_parms, &ue->common_vars.txdataF[eNB_id][symbol_offset], txptr, proc) == 0) { + return 0; + } + else + { + return (-1); + } + } + else { + return (-1); + } +} + + + + + + + + + + + + + + diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..86fd7fcc917f5ada3eaff86d814198576d6ece62 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h @@ -0,0 +1,169 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : srs_modulation_nr.h +* +* MODULE : +* +* DESCRIPTION : function to generate uplink reference sequences +* see 3GPP TS 38.211 6.4.1.4 Sounding reference signal +* +************************************************************************/ + +#ifndef SRS_MODULATION_NR_H +#define SRS_MODULATION_NR_H + +#ifdef DEFINE_VARIABLES_SRS_MODULATION_NR_H +#define EXTERN +#define INIT_VARIABLES_SRS_MODULATION_NR_H +#else +#define EXTERN extern +#undef INIT_VARIABLES_SRS_MODULATION_NR_H +#endif + + +/************** DEFINE ********************************************/ + +#define C_SRS_NUMBER (64) +#define B_SRS_NUMBER (4) + +/************** VARIABLES *****************************************/ + +/* TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration */ +EXTERN const unsigned short srs_bandwidth_config[C_SRS_NUMBER][B_SRS_NUMBER][2] +#ifdef INIT_VARIABLES_SRS_MODULATION_NR_H += { +/* B_SRS = 0 B_SRS = 1 B_SRS = 2 B_SRS = 3 */ +/* C SRS m_srs0 N_0 m_srs1 N_1 m_srs2 N_2 m_srs3 N_3 */ +/* 0 */ { { 4, 1 },{ 4, 1 },{ 4, 1 },{ 4, 1 } }, +/* 1 */ { { 8, 1 },{ 4, 2 },{ 4, 1 },{ 4, 1 } }, +/* 2 */ { { 12, 1 },{ 4, 3 },{ 4, 1 },{ 4, 1 } }, +/* 3 */ { { 16, 1 },{ 4, 4 },{ 4, 1 },{ 4, 1 } }, +/* 4 */ { { 16, 1 },{ 8, 2 },{ 4, 2 },{ 4, 1 } }, +/* 5 */ { { 20, 1 },{ 4, 5 },{ 4, 1 },{ 4, 1 } }, +/* 6 */ { { 24, 1 },{ 4, 6 },{ 4, 1 },{ 4, 1 } }, +/* 7 */ { { 24, 1 },{ 12, 2 },{ 4, 3 },{ 4, 1 } }, +/* 8 */ { { 28, 1 },{ 4, 7 },{ 4, 1 },{ 4, 1 } }, +/* 9 */ { { 32, 1 },{ 16, 2 },{ 8, 2 },{ 4, 2 } }, +/* 10 */ { { 36, 1 },{ 12, 3 },{ 4, 3 },{ 4, 1 } }, +/* 11 */ { { 40, 1 },{ 20, 2 },{ 4, 5 },{ 4, 1 } }, +/* 12 */ { { 48, 1 },{ 16, 3 },{ 8, 2 },{ 4, 2 } }, +/* 13 */ { { 48, 1 },{ 24, 2 },{ 12, 2 },{ 4, 3 } }, +/* 14 */ { { 52, 1 },{ 4, 13 },{ 4, 1 },{ 4, 1 } }, +/* 15 */ { { 56, 1 },{ 28, 2 },{ 4, 7 },{ 4, 1 } }, +/* 16 */ { { 60, 1 },{ 20, 3 },{ 4, 5 },{ 4, 1 } }, +/* 17 */ { { 64, 1 },{ 32, 2 },{ 16, 2 },{ 4, 4 } }, +/* 18 */ { { 72, 1 },{ 24, 3 },{ 12, 2 },{ 4, 3 } }, +/* 19 */ { { 72, 1 },{ 36, 2 },{ 12, 3 },{ 4, 3 } }, +/* 20 */ { { 76, 1 },{ 4, 19 },{ 4, 1 },{ 4, 1 } }, +/* 21 */ { { 80, 1 },{ 40, 2 },{ 20, 2 },{ 4, 5 } }, +/* 22 */ { { 88, 1 },{ 44, 2 },{ 4, 11 },{ 4, 1 } }, +/* 23 */ { { 96, 1 },{ 32, 3 },{ 16, 2 },{ 4, 4 } }, +/* 24 */ { { 96, 1 },{ 48, 2 },{ 24, 2 },{ 4, 6 } }, +/* 25 */ { { 104, 1 },{ 52, 2 },{ 4, 13 },{ 4, 1 } }, +/* 26 */ { { 112, 1 },{ 56, 2 },{ 28, 2 },{ 4, 7 } }, +/* 27 */ { { 120, 1 },{ 60, 2 },{ 20, 3 },{ 4, 5 } }, +/* 28 */ { { 120, 1 },{ 40, 3 },{ 8, 5 },{ 4, 2 } }, +/* 29 */ { { 120, 1 },{ 24, 5 },{ 12, 2 },{ 4, 3 } }, +/* 30 */ { { 128, 1 },{ 64, 2 },{ 32, 2 },{ 4, 8 } }, +/* 31 */ { { 128, 1 },{ 64, 2 },{ 16, 4 },{ 4, 4 } }, +/* 32 */ { { 128, 1 },{ 16, 8 },{ 8, 2 },{ 4, 2 } }, +/* 33 */ { { 132, 1 },{ 44, 3 },{ 4, 11 },{ 4, 1 } }, +/* 34 */ { { 136, 1 },{ 68, 2 },{ 4, 17 },{ 4, 1 } }, +/* 35 */ { { 144, 1 },{ 72, 2 },{ 36, 2 },{ 4, 9 } }, +/* 36 */ { { 144, 1 },{ 48, 3 },{ 24, 2 },{ 12, 2 } }, +/* 37 */ { { 144, 1 },{ 48, 3 },{ 16, 3 },{ 4, 4 } }, +/* 38 */ { { 144, 1 },{ 16, 9 },{ 8, 2 },{ 4, 2 } }, +/* 39 */ { { 152, 1 },{ 76, 2 },{ 4, 19 },{ 4, 1 } }, +/* 40 */ { { 160, 1 },{ 80, 2 },{ 40, 2 },{ 4, 10 } }, +/* 41 */ { { 160, 1 },{ 80, 2 },{ 20, 4 },{ 4, 5 } }, +/* 42 */ { { 160, 1 },{ 32, 5 },{ 16, 2 },{ 4, 4 } }, +/* 43 */ { { 168, 1 },{ 84, 2 },{ 28, 3 },{ 4, 7 } }, +/* 44 */ { { 176, 1 },{ 88, 2 },{ 44, 2 },{ 4, 11 } }, +/* 45 */ { { 184, 1 },{ 92, 2 },{ 4, 23 },{ 4, 1 } }, +/* 46 */ { { 192, 1 },{ 96, 2 },{ 48, 2 },{ 4, 12 } }, +/* 47 */ { { 192, 1 },{ 96, 2 },{ 24, 4 },{ 4, 6 } }, +/* 48 */ { { 192, 1 },{ 64, 3 },{ 16, 4 },{ 4, 4 } }, +/* 49 */ { { 192, 1 },{ 24, 8 },{ 8, 3 },{ 4, 2 } }, +/* 50 */ { { 208, 1 },{ 104, 2 },{ 52, 2 },{ 4, 13 } }, +/* 51 */ { { 216, 1 },{ 108, 2 },{ 36, 3 },{ 4, 9 } }, +/* 52 */ { { 224, 1 },{ 112, 2 },{ 56, 2 },{ 4, 14 } }, +/* 53 */ { { 240, 1 },{ 120, 2 },{ 60, 2 },{ 4, 15 } }, +/* 54 */ { { 240, 1 },{ 80, 3 },{ 20, 4 },{ 4, 5 } }, +/* 55 */ { { 240, 1 },{ 48, 5 },{ 16, 3 },{ 8, 2 } }, +/* 56 */ { { 240, 1 },{ 24, 10 },{ 12, 2 },{ 4, 3 } }, +/* 57 */ { { 256, 1 },{ 128, 2 },{ 64, 2 },{ 4, 16 } }, +/* 58 */ { { 256, 1 },{ 128, 2 },{ 32, 4 },{ 4, 8 } }, +/* 59 */ { { 256, 1 },{ 16, 16 },{ 8, 2 },{ 4, 2 } }, +/* 60 */ { { 264, 1 },{ 132, 2 },{ 44, 3 },{ 4, 11 } }, +/* 61 */ { { 272, 1 },{ 136, 2 },{ 68, 2 },{ 4, 17 } }, +/* 62 */ { { 272, 1 },{ 68, 4 },{ 4, 17 },{ 4, 1 } }, +/* 63 */ { { 272, 1 },{ 16, 17 },{ 8, 2 },{ 4, 2 } }, +} +#endif +; + +#define SRS_PERIODICITY (17) + +EXTERN const uint16_t srs_periodicity[SRS_PERIODICITY] +#ifdef INIT_VARIABLES_SRS_MODULATION_NR_H += { 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560} +#endif +; + +/*************** FUNCTIONS *****************************************/ + +/** \brief This function generates the sounding reference symbol (SRS) for the uplink according to 38.211 6.4.1.4 Sounding reference signal + @param frame_parms NR DL Frame parameters + @param txdataF pointer to the frequency domain TX signal + @param amp amplitude of generated signal + @param proc pointer to the transmit parameters + @returns 0 on success -1 on error with message */ + +int32_t generate_srs_nr(SRS_ResourceSet_t *p_srs_resource_set, + NR_DL_FRAME_PARMS *frame_parms, + int32_t *txptr, + int16_t amp, + UE_nr_rxtx_proc_t *proc); + +/** \brief This function checks for periodic srs if srs should be transmitted in this slot + * @param p_SRS_Resource pointer to active resource + @param frame_parms NR DL Frame parameters + @param txdataF pointer to the frequency domain TX signal + @returns 0 if srs should be transmitted -1 on error with message */ + +int is_srs_period_nr(SRS_Resource_t *p_SRS_Resource, + NR_DL_FRAME_PARMS *frame_parms, + int frame_tx, int slot_tx); +/** \brief This function processes srs configuration + * @param ue context + @param rxtx context + @param current eNB identifier + @returns 0 if srs is transmitted -1 otherwise */ + +int ue_srs_procedure_nr(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t eNB_id); + +#undef EXTERN +#undef INIT_VARIABLES_SRS_MODULATION_NR_H + +#endif /* SRS_MODULATION_NR_H */ diff --git a/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c new file mode 100644 index 0000000000000000000000000000000000000000..904afb653cd0a77c3e264861a66a62fe5043d4f5 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c @@ -0,0 +1,603 @@ +/* + * 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 + */ + +/********************************************************************** +* +* FILENAME : sss_nr.c +* +* MODULE : Functions for secundary synchronisation signal +* +* DESCRIPTION : generation of sss +* 3GPP TS 38.211 7.4.2.3 Secondary synchronisation signal +* +************************************************************************/ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#include "PHY/defs_nr_UE.h" +#include "PHY/MODULATION/modulation_UE.h" + +#include "PHY/NR_REFSIG/ss_pbch_nr.h" + +#define DEFINE_VARIABLES_SSS_NR_H +#include "PHY/NR_REFSIG/sss_nr.h" +#undef DEFINE_VARIABLES_SSS_NR_H + +/******************************************************************* +* +* NAME : init_context_sss_nr +* +* PARAMETERS : N_ID_2 : element 2 of physical layer cell identity +* value : { 0, 1, 2 } +* +* RETURN : generate binary sss sequence (this is a m-sequence) +* d_sss is a third dimension array depending on +* Cell identity elements: +* - N_ID_1 : value from 0 to 335 +* - N_ID_2 : value from 0 to 2 +* +* DESCRIPTION : 3GPP TS 38.211 7.4.2.3 Secundary synchronisation signal +* Sequence generation +* +*********************************************************************/ + +#define INITIAL_SSS_NR (7) + +void init_context_sss_nr(int amp) +{ + int16_t x0[LENGTH_SSS_NR]; + int16_t x1[LENGTH_SSS_NR]; + int16_t dss_current; + int m0, m1; + + const int x0_initial[INITIAL_SSS_NR] = { 1, 0, 0, 0, 0, 0, 0 }; + const int x1_initial[INITIAL_SSS_NR] = { 1, 0, 0, 0, 0, 0, 0 }; + + for (int i=0; i < INITIAL_SSS_NR; i++) { + x0[i] = x0_initial[i]; + x1[i] = x1_initial[i]; + } + + for (int i=0; i < (LENGTH_SSS_NR - INITIAL_SSS_NR); i++) { + x0[i+7] = (x0[i + 4] + x0[i])%(2); + x1[i+7] = (x1[i + 1] + x1[i])%(2); + } + + for (int N_ID_2 = 0; N_ID_2 < N_ID_2_NUMBER; N_ID_2++) { + + for (int N_ID_1 = 0; N_ID_1 < N_ID_1_NUMBER; N_ID_1++) { + + m0 = 15*(N_ID_1/112) + (5*N_ID_2); + m1 = N_ID_1%112; + + for (int n = 0; n < LENGTH_SSS_NR; n++) { + + dss_current = (1 - 2*x0[(n + m0)%(LENGTH_SSS_NR)])*(1 - 2*x1[(n + m1)%(LENGTH_SSS_NR)]); + + /* Modulation of SSS is a BPSK TS 36.211 chapter 5.1.2 BPSK */ +#if 1 + d_sss[N_ID_2][N_ID_1][n] = dss_current * amp; +#else + (void) amp; + d_sss[N_ID_2][N_ID_1][n] = (dss_current * SHRT_MAX)>>SCALING_PSS_NR; +#endif + } + } + } + +#if 0 + for (int i = 0; i < LENGTH_SSS_NR; i++) { + printf("sss ref[%i] : %d %d \n", i, d_sss[0][0][i], d_sss[0][0][i]); + } +#endif +} + +/******************************************************************* +* +* NAME : insert_sss_nr +* +* PARAMETERS : pointer to input buffer for which sss in inserted +* amp amplitude applied to input +* frame parameters for cell identity +* +* RETURN : none +* +* DESCRIPTION : Allow to generate a reference sss sequence according to cell identity +* +*********************************************************************/ + +void insert_sss_nr(int16_t *sss_time, + NR_DL_FRAME_PARMS *frame_parms) +{ + unsigned int ofdm_symbol_size = frame_parms->ofdm_symbol_size; + unsigned int size = ofdm_symbol_size * IQ_SIZE; /* i & q */ + + assert(size <= SYNCF_TMP_SIZE); + assert(size <= SYNC_TMP_SIZE); + + bzero(synchroF_tmp, size); + bzero(synchro_tmp, size); + + int Nid2 = GET_NID2(frame_parms->Nid_cell); + int Nid1 = GET_NID1(frame_parms->Nid_cell); + + /* call of IDFT should be done with ordered input as below + * + * n input samples + * <------------------------------------------------> + * 0 n + * are written into input buffer for IFFT in this order + * ------------------------------------------------- + * |xxxxxxx N/2 xxxxxxxx| + * -------------------------------------------------- + * ^ ^ ^ ^ ^ + * | | | | | + * n/2 end of n=0 start of n/2-1 + * sss sss + * + * Frequencies + * positives negatives + * 0 (+N/2)(-N/2) + * |-----------------------><-------------------------| + * + * sample 0 is for continuous frequency which is not used here + */ + + unsigned int k = ofdm_symbol_size - ((LENGTH_SSS_NR/2)+1); + + /* SSS is directly mapped to subcarrier */ + for (int i=0; i<LENGTH_SSS_NR; i++) { + synchroF_tmp[2*k] = d_sss[Nid2][Nid1][i]; + synchroF_tmp[2*k+1] = 0; + + k++; + + if (k >= ofdm_symbol_size) { + k++; + k-=ofdm_symbol_size; + } + } + + /* get sss in the frequency domain by applying an inverse FFT */ + idft2048(synchroF_tmp, /* complex input */ + synchro_tmp, /* complex output */ + 1); /* scaling factor */ + + /* then get final sss in time */ + for (unsigned int i=0; i<ofdm_symbol_size; i++) { + ((int32_t *)sss_time)[i] = ((int32_t *)synchro_tmp)[i]; + } +} + +/******************************************************************* +* +* NAME : pss_ch_est +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : pss channel estimation +* +*********************************************************************/ + +int pss_ch_est_nr(PHY_VARS_NR_UE *ue, + int32_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR], + int32_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR]) +{ + int16_t *pss; + int16_t *pss_ext2,*sss_ext2,*sss_ext3,tmp_re,tmp_im,tmp_re2,tmp_im2; + uint8_t aarx,i; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + + pss = primary_synchro_nr[ue->common_vars.eNb_id]; + + sss_ext3 = (int16_t*)&sss_ext[0][0]; + + for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) { + + sss_ext2 = (int16_t*)&sss_ext[aarx][0]; + pss_ext2 = (int16_t*)&pss_ext[aarx][0]; + + +#if 0 + + int16_t *p = pss; + + for (int i = 0; i < LENGTH_PSS_NR; i++) { + printf(" pss ref [%d] %d %d at address %p\n", i, p[2*i], p[2*i+1], &p[2*i]); + printf(" pss ext [%d] %d %d at address %p\n", i, pss_ext2[2*i], pss_ext2[2*i+1], &pss_ext2[2*i]); + } + +#endif + +#if 0 + + for (int i = 0; i < LENGTH_PSS_NR; i++) { + printf(" sss ext 2 [%d] %d %d at address %p\n", i, sss_ext2[2*i], sss_ext2[2*i+1], &sss_ext2[2*i]); + printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i], &d_sss[0][0][i]); + } + +#endif + + for (i = 0; i < LENGTH_PSS_NR; i++) { + + // This is H*(PSS) = R* \cdot PSS + tmp_re = (int16_t)(((pss_ext2[i*2] * (int32_t)pss[i*2])>>SCALING_CE_PSS_NR) + ((pss_ext2[i*2+1] * (int32_t)pss[i*2+1])>>SCALING_CE_PSS_NR)); + tmp_im = (int16_t)(((pss_ext2[i*2] * (int32_t)pss[i*2+1])>>SCALING_CE_PSS_NR) - ((pss_ext2[i*2+1] * (int32_t)pss[i*2])>>SCALING_CE_PSS_NR)); + //printf("H*(%d,%d) : (%d,%d)\n",aarx,i,tmp_re,tmp_im); + //printf("pss(%d,%d) : (%d,%d)\n",aarx,i,pss[2*i],pss[2*i+1]); + //printf("pss_ext(%d,%d) : (%d,%d)\n",aarx,i,pss_ext2[2*i],pss_ext2[2*i+1]); + + // This is R(SSS) \cdot H*(PSS) + tmp_re2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2])>>SCALING_CE_PSS_NR) - ((tmp_im * (int32_t)sss_ext2[i*2+1]>>SCALING_CE_PSS_NR))); + tmp_im2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2+1])>>SCALING_CE_PSS_NR) + ((tmp_im * (int32_t)sss_ext2[i*2]>>SCALING_CE_PSS_NR))); + + // printf("SSSi(%d,%d) : (%d,%d)\n",aarx,i,sss_ext2[i<<1],sss_ext2[1+(i<<1)]); + // printf("SSSo(%d,%d) : (%d,%d)\n",aarx,i,tmp_re2,tmp_im2); + // MRC on RX antennas + if (aarx==0) { + sss_ext3[i<<1] = tmp_re2; + sss_ext3[1+(i<<1)] = tmp_im2; + } else { + sss_ext3[i<<1] += tmp_re2; + sss_ext3[1+(i<<1)] += tmp_im2; + } + } + } + +#if 0 + + for (int i = 0; i < LENGTH_PSS_NR; i++) { + printf(" sss ext 2 [%d] %d %d at address %p\n", i, sss_ext2[2*i], sss_ext2[2*i+1]); + printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i]); + printf(" sss ext 3 [%d] %d %d at address %p\n", i, sss_ext3[2*i], sss_ext3[2*i+1]); + } + +#endif + + // sss_ext now contains the compensated SSS + return(0); +} + +/******************************************************************* +* +* NAME : do_pss_sss_extract +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : it allows extracting sss from samples buffer +* +*********************************************************************/ + +int do_pss_sss_extract_nr(PHY_VARS_NR_UE *ue, + int32_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR], + int32_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR], + uint8_t doPss, uint8_t doSss, + uint8_t subframe) // add flag to indicate extracting only PSS, only SSS, or both +{ + uint8_t aarx; + int32_t *pss_rxF,*pss_rxF_ext; + int32_t *sss_rxF,*sss_rxF_ext; + uint8_t pss_symbol, sss_symbol; + int32_t **rxdataF; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + +#if 1 + + for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) { + + pss_symbol = PSS_SYMBOL_NB; /* symbol position */ + sss_symbol = SSS_SYMBOL_NB; + + rxdataF = ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF; + + unsigned int ofdm_symbol_size = frame_parms->ofdm_symbol_size; + + pss_rxF = &rxdataF[aarx][pss_symbol*ofdm_symbol_size]; + sss_rxF = &rxdataF[aarx][sss_symbol*ofdm_symbol_size]; + + pss_rxF_ext = &pss_ext[aarx][0]; + sss_rxF_ext = &sss_ext[aarx][0]; + + unsigned int k = ofdm_symbol_size - ((LENGTH_PSS_NR/2)+1); + + for (int i=0; i < LENGTH_PSS_NR; i++) { + if (doPss) { + pss_rxF_ext[i] = pss_rxF[k]; + } + + if (doSss) { + sss_rxF_ext[i] = sss_rxF[k]; + } + + k++; + + if (k >= ofdm_symbol_size) { + k++; + k-=ofdm_symbol_size; + } + } + } + +#if 0 + + int16_t *p = (int16_t *)sss_rxF_ext; + + for (int i = 0; i < LENGTH_PSS_NR; i++) { + printf(" sss ext 2 [%d] %d %d at address %p\n", i, p[2*i], p[2*i+1], &p[2*i]); + printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i], &d_sss[0][0][i]); + } + +#endif + +#if 0 + + int16_t *p2 = (int16_t *)pss_rxF_ext; + + for (int i = 0; i < LENGTH_PSS_NR; i++) { + printf(" pss_rxF_ext [%d] %d %d at address %p\n", i, p2[2*i], p2[2*i+1], &p2[2*i]); + } + +#endif + +#else + + /* same method as LTE implementation */ + + uint16_t rb,nb_rb = N_RB_SS_PBCH_BLOCK; + + int rx_offset = frame_parms->ofdm_symbol_size - (LENGTH_SSS_NR/2); + + for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) { + + pss_symbol = PSS_SYMBOL_NB; + sss_symbol = SSS_SYMBOL_NB; + + rxdataF = ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF; + pss_rxF = &rxdataF[aarx][(rx_offset + (pss_symbol*(frame_parms->ofdm_symbol_size)))]; + sss_rxF = &rxdataF[aarx][(rx_offset + (sss_symbol*(frame_parms->ofdm_symbol_size)))]; + + //printf("extract_rbs: symbol_mod=%d, rx_offset=%d, ch_offset=%d\n",symbol_mod, + // (rx_offset + (symbol*(frame_parms->ofdm_symbol_size)))*2, + // LTE_CE_OFFSET+ch_offset+(symbol_mod*(frame_parms->ofdm_symbol_size))); + + pss_rxF_ext = &pss_ext[aarx][0]; + sss_rxF_ext = &sss_ext[aarx][0]; + + for (rb=0; rb<nb_rb; rb++) { + + for (int i=0; i<N_SC_RB; i++) { + if (doPss) {pss_rxF_ext[i] = pss_rxF[i];} + if (doSss) {sss_rxF_ext[i] = sss_rxF[i];} + } + + pss_rxF += N_SC_RB; + sss_rxF += N_SC_RB; + pss_rxF_ext += N_SC_RB; + sss_rxF_ext += N_SC_RB; + } + } + +#endif + + return(0); +} + +/******************************************************************* +* +* NAME : rx_sss_nr +* +* PARAMETERS : none +* +* RETURN : none +* +* DESCRIPTION : +* +*********************************************************************/ + +int pss_sss_extract_nr(PHY_VARS_NR_UE *phy_vars_ue, + int32_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR], + int32_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR], + uint8_t subframe) +{ + return do_pss_sss_extract_nr(phy_vars_ue, pss_ext, sss_ext, 1 /* doPss */, 1 /* doSss */, subframe); +} + +/******************************************************************* +* +* NAME : rx_sss_nr +* +* PARAMETERS : none +* +* RETURN : Set Nid_cell in ue context +* +* DESCRIPTION : Determine element Nid1 of cell identity +* so Nid_cell in ue context is set according to Nid1 & Nid2 +* +*********************************************************************/ + +int rx_sss_nr(PHY_VARS_NR_UE *ue, int32_t *tot_metric,uint8_t *phase_max) +{ + uint8_t i; + int32_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR]; + int32_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR]; + uint8_t Nid2 = GET_NID2(ue->common_vars.eNb_id); + uint16_t Nid1; + uint8_t phase; + int16_t *sss; + NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms; + int32_t metric, metric_re; + int16_t *d; + + /* slop_fep function works for lte and takes into account begining of frame with prefix for subframe 0 */ + /* for NR this is not the case but slot_fep is still used for computing FFT of samples */ + /* in order to achieve correct processing for NR prefix samples is forced to 0 and then restored after function call */ + /* symbol number are from beginning of SS/PBCH blocks as below: */ + /* Signal PSS PBCH SSS PBCH */ + /* symbol number 0 1 2 3 */ + /* time samples in buffer rxdata are used as input of FFT -> FFT results are stored in the frequency buffer rxdataF */ + /* rxdataF stores SS/PBCH from beginning of buffers in the same symbol order as in time domain */ + + int nb_prefix_samples0 = frame_parms->nb_prefix_samples0; + frame_parms->nb_prefix_samples0 = 0; + + // Do FFTs for SSS/PSS + // SSS + slot_fep_pbch(ue, + SSS_SYMBOL_NB, // symbol number + 0, // Ns slot number + ue->rx_offset, // sample_offset of int16_t + 0, // no_prefix + 1); // reset frequency estimation + + // PSS + slot_fep_pbch(ue, + PSS_SYMBOL_NB, + 0, + ue->rx_offset, + 0, + 1); + + frame_parms->nb_prefix_samples0 = nb_prefix_samples0; + + // pss sss extraction + pss_sss_extract_nr(ue, + pss_ext, + sss_ext, + 0); /* subframe */ + +#ifdef DEBUG_PLOT_SSS + + write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_tti,1,1); + write_output("rxdataF0.m","rxF0",&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[0]].rxdataF[0],frame_parms->ofdm_symbol_size,2,1); + write_output("pss_ext.m","pss_ext",pss_ext,LENGTH_PSS_NR,1,1); + +#endif + +#if 0 + + write_output("sss_ext.m","sss_ext",sss_ext,LENGTH_SSS_NR,1,1); + write_output("sss_ref.m","sss_ref", d_sss,LENGTH_SSS_NR,1,1); + +#endif + +#if 0 + int16_t *p = (int16_t *)sss_ext[0]; + int16_t *p2 = (int16_t *)pss_ext[0]; + + for (int i = 0; i < LENGTH_SSS_NR; i++) { + printf("sss ref [%i] : %d %d \n", i, d_sss[0][0][i], d_sss[0][0][i]); + printf("sss ext [%i] : %d %d \n", i, p[2*i], p[2*i+1]); + + printf("pss ref [%i] : %d %d \n", i, primary_synchro_nr[0][2*i], primary_synchro_nr[0][2*i+1]); + printf("pss ext [%i] : %d %d \n", i, p2[2*i], p2[2*i+1]); + } +#endif + + // get conjugated channel estimate from PSS, H* = R* \cdot PSS + // and do channel estimation and compensation based on PSS + + pss_ch_est_nr(ue, + pss_ext, + sss_ext); + + // now do the SSS detection based on the precomputed sequences in PHY/LTE_TRANSPORT/sss.h + *tot_metric = INT_MIN; + + sss = (int16_t*)&sss_ext[0][0]; + +#if 0 + + /* simulate of a phase shift on the signal */ + + int phase_shift_index = 0; + + phase_shift_samples(sss, LENGTH_SSS_NR, phase_re_nr[phase_shift_index], phase_im_nr[phase_shift_index]); + +#endif + +#if 0 + int16_t *ps = (int16_t *)pss_ext; + + for (int i = 0; i < LENGTH_SSS_NR; i++) { + printf("sss ref [%i] : %d %d \n", i, d_sss[0][0][i], d_sss[0][0][i]); + printf("sss ext [%i] : %d %d \n", i, sss[2*i], sss[2*i+1]); + + printf("pss ref [%i] : %d %d \n", i, primary_synchro_nr[0][2*i], primary_synchro_nr[0][2*i+1]); + printf("pss ext [%i] : %d %d \n", i, ps[2*i], ps[2*i+1]); + } +#endif + + /* for phase evaluation, one uses an array of possible phase shifts */ + /* then a correlation is done between received signal with a shift pÄ¥ase and the reference signal */ + /* Computation of signal with shift phase is based on below formula */ + /* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */ + /* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */ + + for (phase=0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS + for (Nid1 = 0 ; Nid1 < N_ID_1_NUMBER; Nid1++) { // all possible Nid1 values + + metric = 0; + metric_re = 0; + + d = (int16_t *)&d_sss[Nid2][Nid1]; + + // This is the inner product using one particular value of each unknown parameter + for (i=0; i < LENGTH_SSS_NR; i++) { + + metric_re += d[i]*(((phase_re_nr[phase]*sss[2*i])>>SCALING_METRIC_SSS_NR) - ((phase_im_nr[phase]*sss[2*i+1])>>SCALING_METRIC_SSS_NR)) + + d[i]*(((phase_im_nr[phase]*sss[2*i])>>SCALING_METRIC_SSS_NR) + ((phase_re_nr[phase]*sss[2*i+1])>>SCALING_METRIC_SSS_NR)); + } + + metric = metric_re; + + // if the current metric is better than the last save it + if (metric > *tot_metric) { + *tot_metric = metric; + ue->frame_parms.Nid_cell = Nid2+(3*Nid1); + *phase_max = phase; + +#ifdef DEBUG_SSS_NR + + printf("(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max); + +#endif + } + } + } + +#ifdef DEBUG_SSS_NR + +#define SSS_METRIC_FLOOR_NR (30000) +if (*tot_metric > SSS_METRIC_FLOOR_NR) { + Nid2 = GET_NID2(frame_parms->Nid_cell); + Nid1 = GET_NID1(frame_parms->Nid_cell); + printf("Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max); +} +#endif + + return(0); +} diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index c4e83cc6a4243fe8350d192dbe28afcf196e8af3..4c41852bad9953392d983a0720f46ad02b7f6bf6 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -19,9 +19,9 @@ * contact@openairinterface.org */ -/*! \file PHY/defs_gNB.h - \brief Top-level defines and structure definitions for gNB - \author Guy De Souza +/*! \file PHY/defs_nr_UE.h + \brief Top-level defines and structure definitions for nr ue + \author Guy De Souza, H. WANG \date 2018 \version 0.1 \company Eurecom @@ -29,15 +29,1026 @@ \note \warning */ -#ifndef __PHY_DEFS_GNB__H__ -#define __PHY_DEFS_GNB__H__ +#ifndef __PHY_DEFS_NR_UE__H__ +#define __PHY_DEFS_NR_UE__H__ #include "defs_nr_common.h" +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <malloc.h> +#include <string.h> +#include <math.h> +#include "common_lib.h" +#include "msc.h" +//#include <complex.h> +#include "assertions.h" +#ifdef MEX +# define msg mexPrintf +#else +# ifdef OPENAIR2 +# if ENABLE_RAL +# include "collection/hashtable/hashtable.h" +# include "COMMON/ral_messages_types.h" +# include "UTIL/queue.h" +# endif +# include "log.h" +# define msg(aRGS...) LOG_D(PHY, ##aRGS) +# else +# define msg printf +# endif +#endif +//use msg in the real-time thread context +#define msg_nrt printf +//use msg_nrt in the non real-time context (for initialization, ...) +#ifndef malloc16 +# ifdef __AVX2__ +# define malloc16(x) memalign(32,x) +# else +# define malloc16(x) memalign(16,x) +# endif +#endif +#define free16(y,x) free(y) +#define bigmalloc malloc +#define bigmalloc16 malloc16 +#define openair_free(y,x) free((y)) +#define PAGE_SIZE 4096 + +//#define RX_NB_TH_MAX 3 +//#define RX_NB_TH 3 + + +//#ifdef SHRLIBDEV +//extern int rxrescale; +//#define RX_IQRESCALELEN rxrescale +//#else +//#define RX_IQRESCALELEN 15 +//#endif + +//! \brief Allocate \c size bytes of memory on the heap with alignment 16 and zero it afterwards. +//! If no more memory is available, this function will terminate the program with an assertion error. +/*static inline void* malloc16_clear( size_t size ) +{ +#ifdef __AVX2__ + void* ptr = memalign(32, size); +#else + void* ptr = memalign(16, size); +#endif + DevAssert(ptr); + memset( ptr, 0, size ); + return ptr; +}*/ + + + +#define PAGE_MASK 0xfffff000 +#define virt_to_phys(x) (x) + +#define openair_sched_exit() exit(-1) + + +#define max(a,b) ((a)>(b) ? (a) : (b)) +#define min(a,b) ((a)<(b) ? (a) : (b)) + + +#define bzero(s,n) (memset((s),0,(n))) + +#define cmax(a,b) ((a>b) ? (a) : (b)) +#define cmin(a,b) ((a<b) ? (a) : (b)) + +#define cmax3(a,b,c) ((cmax(a,b)>c) ? (cmax(a,b)) : (c)) + +/// suppress compiler warning for unused arguments +#define UNUSED(x) (void)x; + + +#include "impl_defs_top.h" +#include "impl_defs_nr.h" + +#include "PHY/TOOLS/time_meas.h" +#include "PHY/CODING/coding_defs.h" +#include "PHY/TOOLS/tools_defs.h" +#include "platform_types.h" +#include "NR_UE_TRANSPORT/nr_transport_ue.h" + +#if defined(UPGRADE_RAT_NR) + +#include "PHY/NR_REFSIG/ss_pbch_nr.h" + +#endif + +//#include "PHY/LTE_TRANSPORT/defs.h" +#include <pthread.h> + +#include "targets/ARCH/COMMON/common_lib.h" + + + +/// Context data structure for RX/TX portion of subframe processing +typedef struct { + /// index of the current UE RX/TX proc + int proc_id; + /// Component Carrier index + uint8_t CC_id; + /// timestamp transmitted to HW + openair0_timestamp timestamp_tx; +//#ifdef UE_NR_PHY_DEMO + /// NR TTI index within subframe_tx [0 .. ttis_per_subframe - 1] to act upon for transmission + int nr_tti_tx; + /// NR TTI index within subframe_rx [0 .. ttis_per_subframe - 1] to act upon for reception + int nr_tti_rx; +//#endif + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception + int subframe_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for reception + int frame_rx; + /// \brief Instance count for RXn-TXnp4 processing thread. + /// \internal This variable is protected by \ref mutex_rxtx. + int instance_cnt_rxtx; + /// pthread structure for RXn-TXnp4 processing thread + pthread_t pthread_rxtx; + /// pthread attributes for RXn-TXnp4 processing thread + pthread_attr_t attr_rxtx; + /// condition variable for tx processing thread + pthread_cond_t cond_rxtx; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex_rxtx; + /// scheduling parameters for RXn-TXnp4 thread + struct sched_param sched_param_rxtx; + + /// internal This variable is protected by ref mutex_fep_slot1. + //int instance_cnt_slot0_dl_processing; + int instance_cnt_slot1_dl_processing; + /// pthread descriptor fep_slot1 thread + //pthread_t pthread_slot0_dl_processing; + pthread_t pthread_slot1_dl_processing; + /// pthread attributes for fep_slot1 processing thread + // pthread_attr_t attr_slot0_dl_processing; + pthread_attr_t attr_slot1_dl_processing; + /// condition variable for UE fep_slot1 thread; + //pthread_cond_t cond_slot0_dl_processing; + pthread_cond_t cond_slot1_dl_processing; + /// mutex for UE synch thread + //pthread_mutex_t mutex_slot0_dl_processing; + pthread_mutex_t mutex_slot1_dl_processing; + //int instance_cnt_slot0_dl_processing; + int instance_cnt_dlsch_td; + /// pthread descriptor fep_slot1 thread + //pthread_t pthread_slot0_dl_processing; + pthread_t pthread_dlsch_td; + /// pthread attributes for fep_slot1 processing thread + // pthread_attr_t attr_slot0_dl_processing; + pthread_attr_t attr_dlsch_td; + /// condition variable for UE fep_slot1 thread; + //pthread_cond_t cond_slot0_dl_processing; + pthread_cond_t cond_dlsch_td; + /// mutex for UE synch thread + //pthread_mutex_t mutex_slot0_dl_processing; + pthread_mutex_t mutex_dlsch_td; + // + uint8_t chan_est_pilot0_slot1_available; + uint8_t chan_est_slot1_available; + uint8_t llr_slot1_available; + uint8_t dci_slot0_available; + uint8_t first_symbol_available; + uint8_t decoder_thread_available; + uint8_t decoder_main_available; + uint8_t decoder_switch; + int counter_decoder; + uint8_t channel_level; + int eNB_id; + int harq_pid; + int llr8_flag; + /// scheduling parameters for fep_slot1 thread + struct sched_param sched_param_fep_slot1; + + int sub_frame_start; + int sub_frame_step; + unsigned long long gotIQs; + uint8_t decoder_thread_available1; + int instance_cnt_dlsch_td1; + /// pthread descriptor fep_slot1 thread + //pthread_t pthread_slot0_dl_processing; + pthread_t pthread_dlsch_td1; + /// pthread attributes for fep_slot1 processing thread + // pthread_attr_t attr_slot0_dl_processing; + pthread_attr_t attr_dlsch_td1; + /// condition variable for UE fep_slot1 thread; + //pthread_cond_t cond_slot0_dl_processing; + pthread_cond_t cond_dlsch_td1; + /// mutex for UE synch thread + //pthread_mutex_t mutex_slot0_dl_processing; + pthread_mutex_t mutex_dlsch_td1; + int dci_err_cnt; +} UE_nr_rxtx_proc_t; + +/// Context data structure for eNB subframe processing +typedef struct { + /// Component Carrier index + uint8_t CC_id; + /// Last RX timestamp + openair0_timestamp timestamp_rx; + /// pthread attributes for main UE thread + pthread_attr_t attr_ue; + /// scheduling parameters for main UE thread + struct sched_param sched_param_ue; + /// pthread descriptor main UE thread + pthread_t pthread_ue; + /// \brief Instance count for synch thread. + /// \internal This variable is protected by \ref mutex_synch. + int instance_cnt_synch; + /// pthread attributes for synch processing thread + pthread_attr_t attr_synch; + /// scheduling parameters for synch thread + struct sched_param sched_param_synch; + /// pthread descriptor synch thread + pthread_t pthread_synch; + /// condition variable for UE synch thread; + pthread_cond_t cond_synch; + /// mutex for UE synch thread + pthread_mutex_t mutex_synch; + /// set of scheduling variables RXn-TXnp4 threads + UE_nr_rxtx_proc_t proc_rxtx[RX_NB_TH]; +} UE_nr_proc_t; + +#define debug_msg if (((mac_xface->frame%100) == 0) || (mac_xface->frame < 50)) msg + +typedef struct { + //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) + //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) + //unsigned short rx_avg_power_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //! estimated avg received signal power (dB) + + // RRC measurements + uint32_t rssi; + int n_adj_cells; + unsigned int adj_cell_id[6]; + uint32_t rsrq[7]; + uint32_t rsrp[7]; + float rsrp_filtered[7]; // after layer 3 filtering + float rsrq_filtered[7]; + // common measurements + //! estimated noise power (linear) + unsigned int n0_power[NB_ANTENNAS_RX]; + //! estimated noise power (dB) + unsigned short n0_power_dB[NB_ANTENNAS_RX]; + //! total estimated noise power (linear) + unsigned int n0_power_tot; + //! total estimated noise power (dB) + unsigned short n0_power_tot_dB; + //! average estimated noise power (linear) + unsigned int n0_power_avg; + //! average estimated noise power (dB) + unsigned short n0_power_avg_dB; + //! total estimated noise power (dBm) + short n0_power_tot_dBm; + + // UE measurements + //! estimated received spatial signal power (linear) + int rx_spatial_power[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + //! estimated received spatial signal power (dB) + unsigned short rx_spatial_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + + /// estimated received signal power (sum over all TX/RX antennas) + int rx_power_tot[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + /// estimated received signal power (sum over all TX/RX antennas) + unsigned short rx_power_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + + //! estimated received signal power (sum of all TX/RX antennas, time average) + int rx_power_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated received signal power (sum of all TX/RX antennas, time average, in dB) + unsigned short rx_power_avg_dB[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// SINR (sum of all TX/RX antennas, in dB) + int wideband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX]; + /// SINR (sum of all TX/RX antennas, time average, in dB) + int wideband_cqi_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + + //! estimated rssi (dBm) + short rx_rssi_dBm[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) + int rx_correlation[NUMBER_OF_CONNECTED_eNB_MAX][2]; + //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) + int rx_correlation_dB[NUMBER_OF_CONNECTED_eNB_MAX][2]; + + /// Wideband CQI (sum of all RX antennas, in dB, for precoded transmission modes (3,4,5,6), up to 4 spatial streams) + int precoded_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX+1][4]; + /// Subband CQI per RX antenna (= SINR) + int subband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX]; + /// Total Subband CQI (= SINR) + int subband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Subband CQI in dB (= SINR dB) + int subband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX]; + /// Total Subband CQI + int subband_cqi_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Wideband PMI for each RX antenna + int wideband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// Wideband PMI for each RX antenna + int wideband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX][NB_ANTENNAS_RX]; + /// chosen RX antennas (1=Rx antenna 1, 2=Rx antenna 2, 3=both Rx antennas) + unsigned char selected_rx_antennas[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Wideband Rank indication + unsigned char rank[NUMBER_OF_CONNECTED_eNB_MAX]; + /// Number of RX Antennas + unsigned char nb_antennas_rx; + /// DLSCH error counter + // short dlsch_errors; + +} PHY_NR_MEASUREMENTS; + +typedef struct { + + /// \brief Holds the received data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: symbol [0..28*ofdm_symbol_size[ + int32_t **rxdataF; + + /// \brief Hold the channel estimates in frequency domain. + /// - first index: eNB id [0..6] (hard coded) + /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - third index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[ + int32_t **dl_ch_estimates[7]; + + /// \brief Hold the channel estimates in time domain (used for tracking). + /// - first index: eNB id [0..6] (hard coded) + /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - third index: samples? [0..2*ofdm_symbol_size[ + int32_t **dl_ch_estimates_time[7]; +}NR_UE_COMMON_PER_THREAD; + +typedef struct { + /// \brief Holds the transmit data in time domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->tx_vars[a].TX_DMA_BUFFER. + /// - first index: tx antenna [0..nb_antennas_tx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES[ + int32_t **txdata; + /// \brief Holds the transmit data in the frequency domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. + /// - first index: tx antenna [0..nb_antennas_tx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX[ + int32_t **txdataF; + + /// \brief Holds the received data in time domain. + /// Should point to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES+2048[ + int32_t **rxdata; + + NR_UE_COMMON_PER_THREAD common_vars_rx_data_per_thread[RX_NB_TH_MAX]; + + /// holds output of the sync correlator + int32_t *sync_corr; + /// estimated frequency offset (in radians) for all subcarriers + int32_t freq_offset; + /// eNb_id user is synched to + int32_t eNb_id; +} NR_UE_COMMON; + +typedef struct { + /// \brief Received frequency-domain signal after extraction. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_ext; + /// \brief Received frequency-domain ue specific pilots. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..12*N_RB_DL[ + int32_t **rxdataF_uespec_pilots; + /// \brief Received frequency-domain signal after extraction and channel compensation. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_comp0; + /// \brief Received frequency-domain signal after extraction and channel compensation for the second stream. For the SIC receiver we need to store the history of this for each harq process and round + /// - first index: ? [0..7] (hard coded) accessed via \c harq_pid + /// - second index: ? [0..7] (hard coded) accessed via \c round + /// - third index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - fourth index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_comp1[8][8]; + /// \brief Downlink channel estimates extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_estimates_ext; + /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. For the SIC receiver we need to store the history of this for each harq process and round + /// - first index: ? [0..7] (hard coded) accessed via \c harq_pid + /// - second index: ? [0..7] (hard coded) accessed via \c round + /// - third index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - fourth index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_rho_ext[8][8]; + /// \brief Downlink beamforming channel estimates in frequency domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[ + int32_t **dl_bf_ch_estimates; + /// \brief Downlink beamforming channel estimates. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_bf_ch_estimates_ext; + /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_rho2_ext; + /// \brief Downlink PMIs extracted in PRBS and grouped in subbands. + /// - first index: ressource block [0..N_RB_DL[ + uint8_t *pmi_ext; + /// \brief Magnitude of Downlink Channel first layer (16QAM level/First 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_mag0; + /// \brief Magnitude of Downlink Channel second layer (16QAM level/First 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_mag1[8][8]; + /// \brief Magnitude of Downlink Channel, first layer (2nd 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_magb0; + /// \brief Magnitude of Downlink Channel second layer (2nd 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_magb1[8][8]; + /// \brief Cross-correlation of two eNB signals. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: symbol [0..] + int32_t **rho; + /// never used... always send dl_ch_rho_ext instead... + int32_t **rho_i; + /// \brief Pointers to llr vectors (2 TBs). + /// - first index: ? [0..1] (hard coded) + /// - second index: ? [0..1179743] (hard coded) + int16_t *llr[2]; + /// \f$\log_2(\max|H_i|^2)\f$ + int16_t log2_maxh; + /// \f$\log_2(\max|H_i|^2)\f$ //this is for TM3-4 layer1 channel compensation + int16_t log2_maxh0; + /// \f$\log_2(\max|H_i|^2)\f$ //this is for TM3-4 layer2 channel commpensation + int16_t log2_maxh1; + /// \brief LLR shifts for subband scaling. + /// - first index: ? [0..168*N_RB_DL[ + uint8_t *llr_shifts; + /// \brief Pointer to LLR shifts. + /// - first index: ? [0..168*N_RB_DL[ + uint8_t *llr_shifts_p; + /// \brief Pointers to llr vectors (128-bit alignment). + /// - first index: ? [0..0] (hard coded) + /// - second index: ? [0..] + int16_t **llr128; + /// \brief Pointers to llr vectors (128-bit alignment). + /// - first index: ? [0..0] (hard coded) + /// - second index: ? [0..] + int16_t **llr128_2ndstream; + //uint32_t *rb_alloc; + //uint8_t Qm[2]; + //MIMO_mode_t mimo_mode; + // llr offset per ofdm symbol + uint32_t llr_offset[14]; + // llr length per ofdm symbol + uint32_t llr_length[14]; +} NR_UE_PDSCH; + +typedef struct { + /// \brief Received frequency-domain signal after extraction. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + int32_t **rxdataF_ext; + /// \brief Received frequency-domain signal after extraction and channel compensation. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + double **rxdataF_comp; + /// \brief Downlink channel estimates extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + int32_t **dl_ch_estimates_ext; + /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + double **dl_ch_rho_ext; + /// \brief Downlink PMIs extracted in PRBS and grouped in subbands. + /// - first index: ressource block [0..N_RB_DL[ + uint8_t *pmi_ext; + /// \brief Magnitude of Downlink Channel (16QAM level/First 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + double **dl_ch_mag; + /// \brief Magnitude of Downlink Channel (2nd 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..] + double **dl_ch_magb; + /// \brief Cross-correlation of two eNB signals. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..] + double **rho; + /// never used... always send dl_ch_rho_ext instead... + double **rho_i; + /// \brief Pointers to llr vectors (2 TBs). + /// - first index: ? [0..1] (hard coded) + /// - second index: ? [0..1179743] (hard coded) + int16_t *llr[2]; + /// \f$\log_2(\max|H_i|^2)\f$ + uint8_t log2_maxh; + /// \brief Pointers to llr vectors (128-bit alignment). + /// - first index: ? [0..0] (hard coded) + /// - second index: ? [0..] + int16_t **llr128; + //uint32_t *rb_alloc; + //uint8_t Qm[2]; + //MIMO_mode_t mimo_mode; +} NR_UE_PDSCH_FLP; + +typedef struct { + /// \brief Pointers to extracted PDCCH symbols in frequency-domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_ext; + /// \brief Pointers to extracted and compensated PDCCH symbols in frequency-domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_comp; + /// \brief Pointers to extracted channel estimates of PDCCH symbols. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_estimates_ext; + /// \brief Pointers to channel cross-correlation vectors for multi-eNB detection. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_rho_ext; + /// \brief Pointers to channel cross-correlation vectors for multi-eNB detection. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..] + int32_t **rho; + /// \brief Pointer to llrs, 4-bit resolution. + /// - first index: ? [0..48*N_RB_DL[ + uint16_t *llr; + /// \brief Pointer to llrs, 16-bit resolution. + /// - first index: ? [0..96*N_RB_DL[ + uint16_t *llr16; + /// \brief \f$\overline{w}\f$ from 36-211. + /// - first index: ? [0..48*N_RB_DL[ + uint16_t *wbar; + /// \brief PDCCH/DCI e-sequence (input to rate matching). + /// - first index: ? [0..96*N_RB_DL[ + int8_t *e_rx; + /// number of PDCCH symbols in current subframe + uint8_t num_pdcch_symbols; + /// Allocated CRNTI for UE + uint16_t crnti; + /// 1: the allocated crnti is Temporary C-RNTI / 0: otherwise + uint8_t crnti_is_temporary; + /// Total number of PDU errors (diagnostic mode) + uint32_t dci_errors; + /// Total number of PDU received + uint32_t dci_received; + /// Total number of DCI False detection (diagnostic mode) + uint32_t dci_false; + /// Total number of DCI missed (diagnostic mode) + uint32_t dci_missed; + /// nCCE for PUCCH per subframe + uint8_t nCCE[10]; + //Check for specific DCIFormat and AgregationLevel + uint8_t dciFormat; + uint8_t agregationLevel; +} NR_UE_PDCCH; + +#define PBCH_A 24 + +typedef struct { + /// \brief Pointers to extracted PBCH symbols in frequency-domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..287] (hard coded) + int32_t **rxdataF_ext; + /// \brief Pointers to extracted and compensated PBCH symbols in frequency-domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..287] (hard coded) + int32_t **rxdataF_comp; + /// \brief Pointers to downlink channel estimates in frequency-domain extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..287] (hard coded) + int32_t **dl_ch_estimates_ext; + /// \brief Pointer to PBCH llrs. + /// - first index: ? [0..1919] (hard coded) + int8_t *llr; + /// \brief Pointer to PBCH decoded output. + /// - first index: ? [0..63] (hard coded) + uint8_t *decoded_output; + /// \brief Total number of PDU errors. + uint32_t pdu_errors; + /// \brief Total number of PDU errors 128 frames ago. + uint32_t pdu_errors_last; + /// \brief Total number of consecutive PDU errors. + uint32_t pdu_errors_conseq; + /// \brief FER (in percent) . + uint32_t pdu_fer; +} NR_UE_PBCH; + +typedef struct { + int16_t amp; + int16_t *prachF; + int16_t *prach; +} NR_UE_PRACH; + +/*typedef enum { + /// do not detect any DCIs in the current subframe + NO_DCI = 0x0, + /// detect only downlink DCIs in the current subframe + UL_DCI = 0x1, + /// detect only uplink DCIs in the current subframe + DL_DCI = 0x2, + /// detect both uplink and downlink DCIs in the current subframe + UL_DL_DCI = 0x3} nr_dci_detect_mode_t;*/ + +typedef struct UE_NR_SCAN_INFO_s { + /// 10 best amplitudes (linear) for each pss signals + int32_t amp[3][10]; + /// 10 frequency offsets (kHz) corresponding to best amplitudes, with respect do minimum DL frequency in the band + int32_t freq_offset_Hz[3][10]; +} UE_NR_SCAN_INFO_t; + +/// Top-level PHY Data Structure for UE +typedef struct { + /// \brief Module ID indicator for this instance + uint8_t Mod_id; + /// \brief Component carrier ID for this PHY instance + uint8_t CC_id; + /// \brief Mapping of CC_id antennas to cards + openair0_rf_map rf_map; + //uint8_t local_flag; + /// \brief Indicator of current run mode of UE (normal_txrx, rx_calib_ue, no_L2_connect, debug_prach) + runmode_t mode; + /// \brief Indicator that UE should perform band scanning + int UE_scan; + /// \brief Indicator that UE should perform coarse scanning around carrier + int UE_scan_carrier; + /// \brief Indicator that UE is synchronized to an eNB + int is_synchronized; + /// Data structure for UE process scheduling + UE_nr_proc_t proc; + /// Flag to indicate the UE shouldn't do timing correction at all + int no_timing_correction; + /// \brief Total gain of the TX chain (16-bit baseband I/Q to antenna) + uint32_t tx_total_gain_dB; + /// \brief Total gain of the RX chain (antenna to baseband I/Q) This is a function of rx_gain_mode (and the corresponding gain) and the rx_gain of the card. + uint32_t rx_total_gain_dB; + /// \brief Total gains with maximum RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_max[4]; + /// \brief Total gains with medium RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_med[4]; + /// \brief Total gains with bypassed RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_byp[4]; + /// \brief Current transmit power + int16_t tx_power_dBm[10]; + /// \brief Total number of REs in current transmission + int tx_total_RE[10]; + /// \brief Maximum transmit power + int8_t tx_power_max_dBm; + /// \brief Number of eNB seen by UE + uint8_t n_connected_eNB; + /// \brief indicator that Handover procedure has been initiated + uint8_t ho_initiated; + /// \brief indicator that Handover procedure has been triggered + uint8_t ho_triggered; + /// \brief Measurement variables. + PHY_NR_MEASUREMENTS measurements; + NR_DL_FRAME_PARMS frame_parms; + /// \brief Frame parame before ho used to recover if ho fails. + NR_DL_FRAME_PARMS frame_parms_before_ho; + NR_UE_COMMON common_vars; + + // point to the current rxTx thread index + uint8_t current_thread_id[10]; + NR_UE_PDSCH *pdsch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX+1]; // two RxTx Threads + NR_UE_PDSCH_FLP *pdsch_vars_flp[NUMBER_OF_CONNECTED_eNB_MAX+1]; + NR_UE_PDSCH *pdsch_vars_SI[NUMBER_OF_CONNECTED_eNB_MAX+1]; + NR_UE_PDSCH *pdsch_vars_ra[NUMBER_OF_CONNECTED_eNB_MAX+1]; + NR_UE_PDSCH *pdsch_vars_p[NUMBER_OF_CONNECTED_eNB_MAX+1]; + NR_UE_PDSCH *pdsch_vars_MCH[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_PBCH *pbch_vars[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_PDCCH *pdcch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_PRACH *prach_vars[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_DLSCH_t *dlsch[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX][2]; // two RxTx Threads + NR_UE_ULSCH_t *ulsch[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_DLSCH_t *dlsch_SI[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_DLSCH_t *dlsch_ra[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_DLSCH_t *dlsch_p[NUMBER_OF_CONNECTED_eNB_MAX]; + NR_UE_DLSCH_t *dlsch_MCH[NUMBER_OF_CONNECTED_eNB_MAX]; + // This is for SIC in the UE, to store the reencoded data + LTE_eNB_DLSCH_t *dlsch_eNB[NUMBER_OF_CONNECTED_eNB_MAX]; + //Paging parameters + uint32_t IMSImod1024; + uint32_t PF; + uint32_t PO; + // For abstraction-purposes only + uint8_t sr[10]; + uint8_t pucch_sel[10]; + uint8_t pucch_payload[22]; + UE_MODE_t UE_mode[NUMBER_OF_CONNECTED_eNB_MAX]; + /// cell-specific reference symbols + uint32_t lte_gold_table[7][20][2][14]; + +#if defined(UPGRADE_RAT_NR) + + /// demodulation reference signal for NR PBCH + uint32_t dmrs_pbch_bitmap_nr[DMRS_PBCH_I_SSB][DMRS_PBCH_N_HF][DMRS_BITMAP_SIZE]; + +#endif + + /// UE-specific reference symbols (p=5), TM 7 + uint32_t lte_gold_uespec_port5_table[20][38]; + + /// ue-specific reference symbols + uint32_t lte_gold_uespec_table[2][20][2][21]; + + /// mbsfn reference symbols + uint32_t lte_gold_mbsfn_table[10][3][42]; + + uint32_t X_u[64][839]; + + uint32_t high_speed_flag; + uint32_t perfect_ce; + int16_t ch_est_alpha; + int generate_ul_signal[NUMBER_OF_CONNECTED_eNB_MAX]; + + UE_NR_SCAN_INFO_t scan_info[NB_BANDS_MAX]; + + char ulsch_no_allocation_counter[NUMBER_OF_CONNECTED_eNB_MAX]; + + + + unsigned char ulsch_Msg3_active[NUMBER_OF_CONNECTED_eNB_MAX]; + uint32_t ulsch_Msg3_frame[NUMBER_OF_CONNECTED_eNB_MAX]; + unsigned char ulsch_Msg3_subframe[NUMBER_OF_CONNECTED_eNB_MAX]; + PRACH_RESOURCES_t *prach_resources[NUMBER_OF_CONNECTED_eNB_MAX]; + int turbo_iterations, turbo_cntl_iterations; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_TBS[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_TBS_last[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t bitrate[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_received_bits[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_errors_last[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_received_last[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_fer[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_SI_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_SI_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_ra_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_ra_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_p_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_p_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mch_received_sf[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mch_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_received[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_received[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_errors[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_errors[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_trials[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_trials[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int current_dlsch_cqi[NUMBER_OF_CONNECTED_eNB_MAX]; + unsigned char first_run_timing_advance[NUMBER_OF_CONNECTED_eNB_MAX]; + uint8_t generate_prach; + uint8_t prach_cnt; + uint8_t prach_PreambleIndex; + // uint8_t prach_timer; + uint8_t decode_SIB; + uint8_t decode_MIB; + int rx_offset; /// Timing offset + int rx_offset_diff; /// Timing adjustment for ofdm symbol0 on HW USRP + int time_sync_cell; + int timing_advance; ///timing advance signalled from eNB + int hw_timing_advance; + int N_TA_offset; ///timing offset used in TDD + /// Flag to tell if UE is secondary user (cognitive mode) + unsigned char is_secondary_ue; + /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from. + unsigned char has_valid_precoder; + /// hold the precoder for NULL beam to the primary eNB + int **ul_precoder_S_UE; + /// holds the maximum channel/precoder coefficient + char log2_maxp; + + /// if ==0 enables phy only test mode + int mac_enabled; + + /// Flag to initialize averaging of PHY measurements + int init_averaging; + + /// \brief sinr for all subcarriers of the current link (used only for abstraction). + /// - first index: ? [0..12*N_RB_DL[ + double *sinr_dB; + + /// \brief sinr for all subcarriers of first symbol for the CQI Calculation. + /// - first index: ? [0..12*N_RB_DL[ + double *sinr_CQI_dB; + + /// sinr_effective used for CQI calulcation + double sinr_eff; + + /// N0 (used for abstraction) + double N0; + + /// PDSCH Varaibles + PDSCH_CONFIG_DEDICATED pdsch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// PUSCH Varaibles + PUSCH_CONFIG_DEDICATED pusch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// PUSCH contention-based access vars + PUSCH_CA_CONFIG_DEDICATED pusch_ca_config_dedicated[NUMBER_OF_eNB_MAX]; // lola + + /// PUCCH variables + + PUCCH_CONFIG_DEDICATED pucch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + uint8_t ncs_cell[20][7]; + + /// UL-POWER-Control + UL_POWER_CONTROL_DEDICATED ul_power_control_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// TPC + TPC_PDCCH_CONFIG tpc_pdcch_config_pucch[NUMBER_OF_CONNECTED_eNB_MAX]; + TPC_PDCCH_CONFIG tpc_pdcch_config_pusch[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// CQI reporting + CQI_REPORT_CONFIG cqi_report_config[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// SRS Variables + SOUNDINGRS_UL_CONFIG_DEDICATED soundingrs_ul_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// Scheduling Request Config + SCHEDULING_REQUEST_CONFIG scheduling_request_config[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// Transmission mode per eNB + uint8_t transmission_mode[NUMBER_OF_CONNECTED_eNB_MAX]; + + time_stats_t phy_proc[RX_NB_TH]; + time_stats_t phy_proc_tx; + time_stats_t phy_proc_rx[RX_NB_TH]; + + uint32_t use_ia_receiver; + + time_stats_t ofdm_mod_stats; + time_stats_t ulsch_encoding_stats; + time_stats_t ulsch_modulation_stats; + time_stats_t ulsch_segmentation_stats; + time_stats_t ulsch_rate_matching_stats; + time_stats_t ulsch_turbo_encoding_stats; + time_stats_t ulsch_interleaving_stats; + time_stats_t ulsch_multiplexing_stats; + + time_stats_t generic_stat; + time_stats_t generic_stat_bis[RX_NB_TH][LTE_SLOTS_PER_SUBFRAME]; + time_stats_t ue_front_end_stat[RX_NB_TH]; + time_stats_t ue_front_end_per_slot_stat[RX_NB_TH][LTE_SLOTS_PER_SUBFRAME]; + time_stats_t pdcch_procedures_stat[RX_NB_TH]; + time_stats_t pdsch_procedures_stat[RX_NB_TH]; + time_stats_t pdsch_procedures_per_slot_stat[RX_NB_TH][LTE_SLOTS_PER_SUBFRAME]; + time_stats_t dlsch_procedures_stat[RX_NB_TH]; + + time_stats_t ofdm_demod_stats; + time_stats_t dlsch_rx_pdcch_stats; + time_stats_t rx_dft_stats; + time_stats_t dlsch_channel_estimation_stats; + time_stats_t dlsch_freq_offset_estimation_stats; + time_stats_t dlsch_decoding_stats[2]; + time_stats_t dlsch_demodulation_stats; + time_stats_t dlsch_rate_unmatching_stats; + time_stats_t dlsch_turbo_decoding_stats; + time_stats_t dlsch_deinterleaving_stats; + time_stats_t dlsch_llr_stats; + time_stats_t dlsch_llr_stats_parallelization[RX_NB_TH][LTE_SLOTS_PER_SUBFRAME]; + time_stats_t dlsch_unscrambling_stats; + time_stats_t dlsch_rate_matching_stats; + time_stats_t dlsch_turbo_encoding_stats; + time_stats_t dlsch_interleaving_stats; + time_stats_t dlsch_tc_init_stats; + time_stats_t dlsch_tc_alpha_stats; + time_stats_t dlsch_tc_beta_stats; + time_stats_t dlsch_tc_gamma_stats; + time_stats_t dlsch_tc_ext_stats; + time_stats_t dlsch_tc_intl1_stats; + time_stats_t dlsch_tc_intl2_stats; + time_stats_t tx_prach; + + /// RF and Interface devices per CC + openair0_device rfdevice; + time_stats_t dlsch_encoding_SIC_stats; + time_stats_t dlsch_scrambling_SIC_stats; + time_stats_t dlsch_modulation_SIC_stats; + time_stats_t dlsch_llr_stripping_unit_SIC_stats; + time_stats_t dlsch_unscrambling_SIC_stats; + +#if ENABLE_RAL + hash_table_t *ral_thresholds_timed; + SLIST_HEAD(ral_thresholds_gen_poll_s, ral_threshold_phy_t) ral_thresholds_gen_polled[RAL_LINK_PARAM_GEN_MAX]; + SLIST_HEAD(ral_thresholds_lte_poll_s, ral_threshold_phy_t) ral_thresholds_lte_polled[RAL_LINK_PARAM_LTE_MAX]; +#endif + +} PHY_VARS_NR_UE; + +/* this structure is used to pass both UE phy vars and + * proc to the function UE_thread_rxn_txnp4 + */ +struct nr_rxtx_thread_data { + PHY_VARS_NR_UE *UE; + UE_nr_rxtx_proc_t *proc; +}; + +void exit_fun(const char* s); + +/*static inline int wait_on_condition(pthread_mutex_t *mutex,pthread_cond_t *cond,int *instance_cnt,char *name) { + + if (pthread_mutex_lock(mutex) != 0) { + LOG_E( PHY, "[SCHED][eNB] error locking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + + while (*instance_cnt < 0) { + // most of the time the thread is waiting here + // proc->instance_cnt_rxtx is -1 + pthread_cond_wait(cond,mutex); // this unlocks mutex_rxtx while waiting and then locks it again + } + + if (pthread_mutex_unlock(mutex) != 0) { + LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + return(0); +} + +static inline int wait_on_busy_condition(pthread_mutex_t *mutex,pthread_cond_t *cond,int *instance_cnt,char *name) { + + if (pthread_mutex_lock(mutex) != 0) { + LOG_E( PHY, "[SCHED][eNB] error locking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + + while (*instance_cnt == 0) { + // most of the time the thread will skip this + // waits only if proc->instance_cnt_rxtx is 0 + pthread_cond_wait(cond,mutex); // this unlocks mutex_rxtx while waiting and then locks it again + } + + if (pthread_mutex_unlock(mutex) != 0) { + LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + return(0); +} + +static inline int release_thread(pthread_mutex_t *mutex,int *instance_cnt,char *name) { + + if (pthread_mutex_lock(mutex) != 0) { + LOG_E( PHY, "[SCHED][eNB] error locking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + + *instance_cnt=*instance_cnt-1; + + if (pthread_mutex_unlock(mutex) != 0) { + LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for %s\n",name); + exit_fun("nothing to add"); + return(-1); + } + return(0); +} +*/ + + +/* +#include "PHY/INIT/defs.h" +#include "PHY/LTE_REFSIG/defs.h" +#include "PHY/MODULATION/defs.h" +#include "PHY/LTE_TRANSPORT/proto.h" +#include "PHY/LTE_ESTIMATION/defs.h" +*/ +#include "SIMULATION/ETH_TRANSPORT/defs.h" #endif diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 65168dfb8c368cf4bbf98f4616e24290661b1965..996797a7adfb5ecb316337f3f6bd4b763edf947a 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -34,6 +34,7 @@ #define __PHY_DEFS_NR_COMMON__H__ #include "defs_common.h" +#include "impl_defs_nr.h" #include "PHY/CODING/nrPolar_tools/nr_polar_defs.h" #define nr_subframe_t lte_subframe_t @@ -73,6 +74,14 @@ typedef enum{ } nr_ssb_type_e; typedef struct NR_DL_FRAME_PARMS { + /// Number of resource blocks (RB) in DL + uint8_t N_RB_DL; + /// Number of resource blocks (RB) in UL + uint8_t N_RB_UL; + /// total Number of Resource Block Groups: this is ceil(N_PRB/P) + uint8_t N_RBG; + /// Total Number of Resource Block Groups SubSets: this is P + uint8_t N_RBGS; /// EUTRA Band uint8_t eutra_band; /// DL carrier frequency @@ -84,6 +93,13 @@ typedef struct NR_DL_FRAME_PARMS { /// RX attenuation uint32_t att_rx; /// total Number of Resource Block Groups: this is ceil(N_PRB/P) + /// Frame type (0 FDD, 1 TDD) + lte_frame_type_t frame_type; + /// TDD subframe assignment (0-7) (default = 3) (254=RX only, 255=TX only) + uint8_t tdd_config; + /// TDD S-subframe configuration (0-9) + /// Cell ID + uint16_t Nid_cell; uint32_t subcarrier_spacing; /// 3/4 sampling uint8_t threequarter_fs; @@ -101,14 +117,45 @@ typedef struct NR_DL_FRAME_PARMS { uint16_t slots_per_subframe; /// Number of samples in a subframe uint32_t samples_per_subframe; + /// Number of OFDM/SC-FDMA symbols in one subframe (to be modified to account for potential different in UL/DL) + uint16_t symbols_per_tti; /// Number of samples in a radio frame uint32_t samples_per_frame; /// Number of samples in a subframe without CP uint32_t samples_per_subframe_wCP; /// Number of samples in a radio frame without CP uint32_t samples_per_frame_wCP; - - //SSB related params + /// Number of samples in a tti (same as subrame in LTE, depending on numerology in NR) + uint32_t samples_per_tti; + /// NR numerology index [0..5] as specified in 38.211 Section 4 (mu). 0=15khZ SCS, 1=30khZ, 2=60kHz, etc + uint8_t numerology_index; + /// NR number of ttis per subframe deduced from numerology (cf 38.211): 1, 2, 4, 8(not supported),16(not supported),32(not supported) + uint8_t ttis_per_subframe; + /// NR number of slots per tti . Assumption only 2 Slot per TTI is supported (Slot Config 1 in 38.211) + uint8_t slots_per_tti; +//#endif + /// Number of Physical transmit antennas in node + uint8_t nb_antennas_tx; + /// Number of Receive antennas in node + uint8_t nb_antennas_rx; + /// Number of common transmit antenna ports in eNodeB (1 or 2) + uint8_t nb_antenna_ports_eNB; + /// Cyclic Prefix for DL (0=Normal CP, 1=Extended CP) + lte_prefix_type_t Ncp; + /// SRS configuration from TS 38.331 RRC + SRS_NR srs_nr; + + /// for NR TDD management + TDD_UL_DL_configCommon_t *p_tdd_UL_DL_Configuration; + + TDD_UL_DL_configCommon_t *p_tdd_UL_DL_ConfigurationCommon2; + + TDD_UL_DL_SlotConfig_t *p_TDD_UL_DL_ConfigDedicated; + + /// TDD configuration + uint16_t tdd_uplink_nr[MAX_NR_OF_SLOTS]; /* this is a bitmap of symbol of each slot given for 2 frames */ + + //SSB related params /// Start in Subcarrier index of the SSB block uint16_t ssb_start_subcarrier; /// SSB type diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..390949072ae720c79541a063fea7a8a485f5c92f --- /dev/null +++ b/openair1/PHY/impl_defs_nr.h @@ -0,0 +1,345 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : impl_defs_nr.h +* +* MODULE : +* +* DESCRIPTION : NR Physical channel configuration and variable structure definitions +* This is an interface between ue physical layer and RRC message from network +* see TS 38.336 Radio Resource Control (RRC) protocol specification +* +************************************************************************/ + +#ifndef PHY_IMPL_DEFS_NR_H +#define PHY_IMPL_DEFS_NR_H + +#include "types.h" + +#ifdef DEFINE_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H +#define EXTERN +#define INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H +#else +#define EXTERN extern +#undef INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H +#endif + +#ifdef PHY_DBG_DEV_TST + #define PHY_DBG_DEV_TST_PRINTF(...) printf(__VA_ARGS__) +#else + #define PHY_DBG_DEV_TST_PRINTF(...) +#endif + +/* to set for UE capabilities */ +#define MAX_NR_OF_SRS_RESOURCE_SET (1) +#define MAX_NR_OF_SRS_RESOURCES_PER_SET (1) + +#define NR_NUMBER_OF_SUBFRAMES_PER_FRAME (10) +#define MAX_NROFSRS_PORTS (4) + +/* TS 38.211 Table 4.3.2-1: Number of OFDM symbols per slot, slots per frame, and slots per subframe for normal cyclic prefix */ +#define MU_NUMBER (5) +EXTERN const uint8_t N_slot_subframe[MU_NUMBER] +#ifdef INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H += { 1, 2, 4, 8, 16} +#endif +; + +/*********************************************************************** +* +* FUNCTIONALITY : Time Division Duplex +* +* DESCRIPTION : interface for FDD/TDD configuration +* +************************************************************************/ + +#define MAX_NR_OF_SLOTS (320) /* maximum number of slots for tdd configuration which is periodic */ + +#define NR_TDD_DOWNLINK_SLOT (0x0000) +#define NR_TDD_UPLINK_SLOT (0x3FFF) /* uplink bitmap for each symbol, there are 14 symbols per slots */ +#define NR_TDD_SET_ALL_SYMBOLS (0x3FFF) + +#define FRAME_DURATION_MICRO_SEC (10000) /* frame duration in microsecond */ + +typedef enum { + SLOT_DL = 0, + SLOT_UL = 1, +} nr_slot_t; + +typedef enum { + ms0p5 = 500, /* duration is given in microsecond */ + ms0p625 = 625, + ms1 = 1000, + ms1p25 = 1250, + ms2 = 2000, + ms2p5 = 2500, + ms5 = 5000, + ms10 = 10000, +} dl_UL_TransmissionPeriodicity_t; + +typedef struct { + /// Reference SCS used to determine the time domain boundaries in the UL-DL pattern which must be common across all subcarrier specific + /// virtual carriers, i.e., independent of the actual subcarrier spacing using for data transmission. + /// Only the values 15 or 30 kHz (<6GHz), 60 or 120 kHz (>6GHz) are applicable. + /// Corresponds to L1 parameter 'reference-SCS' (see 38.211, section FFS_Section) + /// \ subcarrier spacing + uint8_t referenceSubcarrierSpacing; + /// \ Periodicity of the DL-UL pattern. Corresponds to L1 parameter 'DL-UL-transmission-periodicity' (see 38.211, section FFS_Section) + dl_UL_TransmissionPeriodicity_t dl_UL_TransmissionPeriodicity; + /// \ Number of consecutive full DL slots at the beginning of each DL-UL pattern. + /// Corresponds to L1 parameter 'number-of-DL-slots' (see 38.211, Table 4.3.2-1) + uint8_t nrofDownlinkSlots; + /// \ Number of consecutive DL symbols in the beginning of the slot following the last full DL slot (as derived from nrofDownlinkSlots). + /// If the field is absent or released, there is no partial-downlink slot. + /// Corresponds to L1 parameter 'number-of-DL-symbols-common' (see 38.211, section FFS_Section). + uint8_t nrofDownlinkSymbols; + /// \ Number of consecutive full UL slots at the end of each DL-UL pattern. + /// Corresponds to L1 parameter 'number-of-UL-slots' (see 38.211, Table 4.3.2-1) + uint8_t nrofUplinkSlots; + /// \ Number of consecutive UL symbols in the end of the slot preceding the first full UL slot (as derived from nrofUplinkSlots). + /// If the field is absent or released, there is no partial-uplink slot. + /// Corresponds to L1 parameter 'number-of-UL-symbols-common' (see 38.211, section FFS_Section) + uint8_t nrofUplinkSymbols; + /// \ for setting a sequence + struct TDD_UL_DL_configCommon_t *p_next_TDD_UL_DL_configCommon_t; +} TDD_UL_DL_configCommon_t; + +typedef struct { + /// \ Identifies a slot within a dl-UL-TransmissionPeriodicity (given in tdd-UL-DL-configurationCommon) + uint16_t slotIndex; + /// \ The direction (downlink or uplink) for the symbols in this slot. "allDownlink" indicates that all symbols in this slot are used + /// for downlink; "allUplink" indicates that all symbols in this slot are used for uplink; "explicit" indicates explicitly how many symbols + /// in the beginning and end of this slot are allocated to downlink and uplink, respectively. + /// Number of consecutive DL symbols in the beginning of the slot identified by slotIndex. + /// If the field is absent the UE assumes that there are no leading DL symbols. + /// Corresponds to L1 parameter 'number-of-DL-symbols-dedicated' (see 38.211, section FFS_Section) + uint16_t nrofDownlinkSymbols; + /// Number of consecutive UL symbols in the end of the slot identified by slotIndex. + /// If the field is absent the UE assumes that there are no trailing UL symbols. + /// Corresponds to L1 parameter 'number-of-UL-symbols-dedicated' (see 38.211, section FFS_Section) + uint16_t nrofUplinkSymbols; + /// \ for setting a sequence + struct TDD_UL_DL_SlotConfig_t *p_next_TDD_UL_DL_SlotConfig; +} TDD_UL_DL_SlotConfig_t; + +/*********************************************************************** +* +* FUNCTIONALITY : Sounding Reference Signal +* +* DESCRIPTION : interface description for managing uplink SRS signals from UE +* SRS are generated by UE and transmit to network +* depending on configuration +* +************************************************************************/ + +EXTERN const int16_t SRS_antenna_port[MAX_NROFSRS_PORTS] +#ifdef INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H += { 1000, 1001, 1002, 1003 } +#endif +; + +typedef enum { + port1 = 1, + port2 = 2, + port4 = 4 +} nrof_Srs_Ports_t; + +typedef enum { + neitherHopping = 0, + groupHopping = 1, + sequenceHopping = 2 +} groupOrSequenceHopping_t; + +typedef enum { + aperiodic = 0, + semi_persistent = 1, + periodic = 2 +} resourceType_t; + +typedef enum { + sl1 = 0, + sl2 = 1, + sl4 = 2, + sl5 = 3, + sl8 = 4, + sl10 = 5, + sl16 = 6, + sl20 = 7, + sl32 = 8, + sl40 = 9, + sl64 = 10, + sl80 = 11, + sl160 = 12, + sl320 = 13, + sl640 = 14, + sl1280 = 15, + sl2560 = 16 +} SRS_Periodicity_t; + +#define NB_SRS_PERIOD (17) + +const uint16_t srs_period[NB_SRS_PERIOD] +#ifdef INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H += { 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560} +#endif +; + +/// SRS_Resource of SRS_Config information element from 38.331 RRC specifications +typedef struct { + /// \brief srs resource identity. + uint8_t srs_ResourceId; + /// \brief number of srs ports. + nrof_Srs_Ports_t nrof_SrsPorts; + /// \brief index of prts port index. + uint8_t ptrs_PortIndex; + /// \brief srs transmission comb see parameter SRS-TransmissionComb 38.214 section &6.2.1. + uint8_t transmissionComb; + /// \brief comb offset. + uint8_t combOffset; + /// \brief cyclic shift configuration - see parameter SRS-CyclicShiftConfig 38.214 &6.2.1. + uint8_t cyclicShift; + /// \brief OFDM symbol location of the SRS resource within a slot. + // Corresponds to L1 parameter 'SRS-ResourceMapping' (see 38.214, section 6.2.1 and 38.211, section 6.4.1.4). + // startPosition (SRSSymbolStartPosition = 0..5; "0" refers to the last symbol, "1" refers to the second last symbol. + uint8_t resourceMapping_startPosition; + /// \brief number of OFDM symbols (N = 1, 2 or 4 per SRS resource). + uint8_t resourceMapping_nrofSymbols; + /// \brief RepetitionFactor (r = 1, 2 or 4). + uint8_t resourceMapping_repetitionFactor; + /// \brief Parameter(s) defining frequency domain position and configurable shift to align SRS allocation to 4 PRB grid. + // Corresponds to L1 parameter 'SRS-FreqDomainPosition' (see 38.214, section 6.2.1) + uint8_t freqDomainPosition; // INTEGER (0..67), + uint16_t freqDomainShift; // INTEGER (0..268), + /// \brief Includes parameters capturing SRS frequency hopping + // Corresponds to L1 parameter 'SRS-FreqHopping' (see 38.214, section 6.2.1) + uint8_t freqHopping_c_SRS; // INTEGER (0..63), + uint8_t freqHopping_b_SRS; // INTEGER (0..3), + uint8_t freqHopping_b_hop; // INTEGER (0..3) + // Parameter(s) for configuring group or sequence hopping + // Corresponds to L1 parameter 'SRS-GroupSequenceHopping' see 38.211 + groupOrSequenceHopping_t groupOrSequenceHopping; + /// \brief Time domain behavior of SRS resource configuration. + // Corresponds to L1 parameter 'SRS-ResourceConfigType' (see 38.214, section 6.2.1). + // For codebook based uplink transmission, the network configures SRS resources in the same resource set with the same + // time domain behavior on periodic, aperiodic and semi-persistent SRS + SRS_Periodicity_t SRS_Periodicity; + uint16_t SRS_Offset; + /// \brief Sequence ID used to initialize psedo random group and sequence hopping. + // Corresponds to L1 parameter 'SRS-SequenceId' (see 38.214, section 6.2.1). + uint16_t sequenceId; // BIT STRING (SIZE (10)) + /// \brief Configuration of the spatial relation between a reference RS and the target SRS. Reference RS can be SSB/CSI-RS/SRS. + // Corresponds to L1 parameter 'SRS-SpatialRelationInfo' (see 38.214, section 6.2.1) + uint8_t spatialRelationInfo_ssb_Index; // SSB-Index, + uint8_t spatialRelationInfo_csi_RS_Index; // NZP-CSI-RS-ResourceId, + uint8_t spatialRelationInfo_srs_Id; // SRS-ResourceId +} SRS_Resource_t; + +typedef enum { + beamManagement = 0, + codebook = 1, + nonCodebook = 2, + antennaSwitching = 3, +} SRS_resourceSet_usage_t; + +typedef enum { + sameAsFci2 = 0, + separateClosedLoop = 1 +} srs_PowerControlAdjustmentStates_t; + +typedef enum { + ssb_Index = 0, + csi_RS_Index = 1, +} pathlossReferenceRS_t; + +// SRS_Config information element from 38.331 RRC specifications from 38.331 RRC specifications. +typedef struct { + /// \brief The ID of this resource set. It is unique in the context of the BWP in which the parent SRS-Config is defined. + uint8_t srs_ResourceSetId; + /// \brief number of resources in the resource set + uint8_t number_srs_Resource; + /// \brief The IDs of the SRS-Resources used in this SRS-ResourceSet. + /// in fact this is an array of pointers to resource structures + SRS_Resource_t *p_srs_ResourceList[MAX_NR_OF_SRS_RESOURCES_PER_SET]; + resourceType_t resourceType; + /// \brief The DCI "code point" upon which the UE shall transmit SRS according to this SRS resource set configuration. + // Corresponds to L1 parameter 'AperiodicSRS-ResourceTrigger' (see 38.214, section 6.1.1.2) + uint8_t aperiodicSRS_ResourceTrigger; // INTEGER (0..maxNrofSRS-TriggerStates-1) : [0:3] + /// \brief ID of CSI-RS resource associated with this SRS resource set. (see 38.214, section 6.1.1.2). + uint8_t NZP_CSI_RS_ResourceId; + /// \brief An offset in number of slots between the triggering DCI and the actual transmission of this SRS-ResourceSet. + // If the field is absent the UE applies no offset (value 0) + uint8_t aperiodic_slotOffset; // INTEGER (1..8) + /// \brief Indicates if the SRS resource set is used for beam management vs. used for either codebook based or non-codebook based transmission. + // Corresponds to L1 parameter 'SRS-SetUse' (see 38.214, section 6.2.1) + // FFS_CHECK: Isn't codebook/noncodebook already known from the ulTxConfig in the SRS-Config? If so, isn't the only distinction + // in the set between BeamManagement, AtennaSwitching and "Otherâ€? Or what happens if SRS-Config=Codebook but a Set=NonCodebook? + SRS_resourceSet_usage_t usage; + /// \brief alpha value for SRS power control. Corresponds to L1 parameter 'alpha-srs' (see 38.213, section 7.3). + // When the field is absent the UE applies the value 1 + uint8_t alpha; + /// \brief P0 value for SRS power control. The value is in dBm. Only even values (step size 2) are allowed. + // Corresponds to L1 parameter 'p0-srs' (see 38.213, section 7.3) + int8_t p0; // INTEGER (-202..24) + /// \brief A reference signal (e.g. a CSI-RS config or a SSblock) to be used for SRS path loss estimation. + /// Corresponds to L1 parameter 'srs-pathlossReference-rs-config' (see 38.213, section 7.3) + pathlossReferenceRS_t pathlossReferenceRS_t; + uint8_t path_loss_SSB_Index; + uint8_t path_loss_NZP_CSI_RS_ResourceId; + /// \brief Indicates whether hsrs,c(i) = fc(i,1) or hsrs,c(i) = fc(i,2) (if twoPUSCH-PC-AdjustmentStates are configured) + /// or separate close loop is configured for SRS. This parameter is applicable only for Uls on which UE also transmits PUSCH. + /// If absent or release, the UE applies the value sameAs-Fci1 + /// Corresponds to L1 parameter 'srs-pcadjustment-state-config' (see 38.213, section 7.3) + srs_PowerControlAdjustmentStates_t srs_PowerControlAdjustmentStates; +} SRS_ResourceSet_t; + +typedef struct { + uint8_t active_srs_Resource_Set; /* ue implementation specific */ + uint8_t number_srs_Resource_Set; /* ue implementation specific */ + SRS_ResourceSet_t *p_SRS_ResourceSetList[MAX_NR_OF_SRS_RESOURCE_SET]; /* ue implementation specific */ +} SRS_NR; + +//#define RX_NB_TH_MAX 3 +//#define RX_NB_TH 3 + +#define LTE_SLOTS_PER_SUBFRAME 2 + +#define LTE_NUMBER_OF_SUBFRAMES_PER_FRAME 10 +#define LTE_SLOTS_PER_FRAME 20 +#define LTE_CE_FILTER_LENGTH 5 +#define LTE_CE_OFFSET LTE_CE_FILTER_LENGTH +#define TX_RX_SWITCH_SYMBOL (NUMBER_OF_SYMBOLS_PER_FRAME>>1) +#define PBCH_PDU_SIZE 3 //bytes + +#define PRACH_SYMBOL 3 //position of the UL PSS wrt 2nd slot of special subframe + +#define NUMBER_OF_FREQUENCY_GROUPS (lte_frame_parms->N_RB_DL) + +#define SSS_AMP 1148 + +#define MAX_NUM_PHICH_GROUPS 56 //110 RBs Ng=2, p.60 36-212, Sec. 6.9 + +#define MAX_MBSFN_AREA 8 + +#undef EXTERN +#undef INIT_VARIABLES_PHY_IMPLEMENTATION_DEFS_NR_H +#endif /* PHY_IMPL_DEFS_NR_H */ diff --git a/openair1/PHY/phy_extern_nr_ue.h b/openair1/PHY/phy_extern_nr_ue.h new file mode 100644 index 0000000000000000000000000000000000000000..a9694ea058d6278fb7b2564d5bc294ee958f5dd2 --- /dev/null +++ b/openair1/PHY/phy_extern_nr_ue.h @@ -0,0 +1,124 @@ +/* + * 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 + */ + +#ifndef __PHY_EXTERN_UE__H__ +#define __PHY_EXTERN_UE__H__ + +#include "PHY/defs_nr_UE.h" +#include "common/ran_context.h" + +extern char* namepointer_chMag ; +extern char* namepointer_log2; +extern char fmageren_name2[512]; + +extern unsigned int RX_DMA_BUFFER[4][NB_ANTENNAS_RX]; +extern unsigned int TX_DMA_BUFFER[4][NB_ANTENNAS_TX]; + +#include "PHY/LTE_TRANSPORT/transport_extern.h" + +extern int number_of_cards; + + +#ifndef OCP_FRAMEWORK +extern PHY_VARS_NR_UE ***PHY_vars_UE_g; +extern NR_DL_FRAME_PARMS *lte_frame_parms_g; +#else +#define MAX_UE 10 +#define MAX_eNB 20 + +extern PHY_VARS_NR_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]; +#endif + +extern short primary_synch0[144]; +extern short primary_synch1[144]; +extern short primary_synch2[144]; +extern unsigned char primary_synch0_tab[72]; +extern unsigned char primary_synch1_tab[72]; +extern unsigned char primary_synch2_tab[72]; +extern int16_t *primary_synch0_time; //!< index: [0..ofdm_symbol_size*2[ +extern int16_t *primary_synch1_time; //!< index: [0..ofdm_symbol_size*2[ +extern int16_t *primary_synch2_time; //!< index: [0..ofdm_symbol_size*2[ +extern int *sync_corr_ue0; //!< index [0..10*samples_per_tti[ +extern int *sync_corr_ue1; //!< index [0..10*samples_per_tti[ +extern int *sync_corr_ue2; //!< index [0..10*samples_per_tti[ + +extern int flagMag; +//extern short **txdataF_rep_tmp; + +extern char mode_string[4][20]; + +extern unsigned char NB_RU; + +#ifndef OPENAIR2 +extern unsigned char NB_eNB_INST; +extern unsigned char NB_UE_INST; +extern unsigned char NB_RN_INST; +#endif + +extern unsigned int ULSCH_max_consecutive_errors; +extern int flag_LA; +extern double sinr_bler_map[MCS_COUNT][2][MCS_TABLE_LENGTH_MAX]; +extern double sinr_bler_map_up[MCS_COUNT][2][16]; +extern int table_length[MCS_COUNT]; +extern double sinr_to_cqi[4][16]; +extern int cqi_to_mcs[16]; + +//for MU-MIMO abstraction using MIESM +//this 2D arrarays contains SINR, MI and RBIR in rows 1, 2, and 3 respectively +extern double MI_map_4qam[3][162]; +extern double MI_map_16qam[3][197]; +extern double MI_map_64qam[3][227]; + +extern double beta1_dlsch_MI[6][MCS_COUNT]; +extern double beta2_dlsch_MI[6][MCS_COUNT]; + +extern double q_qpsk[8]; +extern double q_qam16[8]; +extern double q_qam64[8]; + +extern double p_qpsk[8]; +extern double p_qam16[8]; +extern double p_qam64[8]; + +extern double beta1_dlsch[6][MCS_COUNT]; +extern double beta2_dlsch[6][MCS_COUNT]; + +extern char eNB_functions[6][20]; +extern char eNB_timing[2][20]; +extern char ru_if_types[MAX_RU_IF_TYPES][20]; + +extern int16_t unscrambling_lut[65536*16]; +extern uint8_t scrambling_lut[65536*16]; + +extern unsigned short msrsb_6_40[8][4]; +extern unsigned short msrsb_41_60[8][4]; +extern unsigned short msrsb_61_80[8][4]; +extern unsigned short msrsb_81_110[8][4]; +extern unsigned short Nb_6_40[8][4]; +extern unsigned short Nb_41_60[8][4]; +extern unsigned short Nb_61_80[8][4]; +extern unsigned short Nb_81_110[8][4]; + +extern uint16_t hundred_times_log10_NPRB[100]; +extern uint8_t alpha_lut[8]; +extern uint8_t max_turbo_iterations; +#endif /*__PHY_EXTERN_H__ */ + diff --git a/openair1/PHY/phy_vars_nr_ue.h b/openair1/PHY/phy_vars_nr_ue.h new file mode 100644 index 0000000000000000000000000000000000000000..a179f509c61ad2169f1173b5fc862eb968585d19 --- /dev/null +++ b/openair1/PHY/phy_vars_nr_ue.h @@ -0,0 +1,150 @@ +/* + * 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 + */ + +#ifndef __PHY_VARS_NR_H__ +#define __PHY_VARS_NR_H__ + +#include "PHY/types.h" +#include "PHY/defs_nr_UE.h" +#include "PHY/phy_vars_nr_ue.h" + +#include "common/ran_context.h" + +char* namepointer_chMag ; +char fmageren_name2[512]; +char* namepointer_log2; + + +#include "PHY/LTE_REFSIG/primary_synch.h" +int16_t *primary_synch0_time; +int16_t *primary_synch1_time; +int16_t *primary_synch2_time; + + +#include "PHY/CODING/coding_vars.h" + +//PHY_VARS *PHY_vars; +#ifndef OCP_FRAMEWORK +PHY_VARS_NR_UE ***PHY_vars_UE_g; +LTE_DL_FRAME_PARMS *lte_frame_parms_g; +#else +PHY_VARS_NR_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]={NULL}; + +#endif + + +unsigned short rev[2048],rev_times4[8192],rev_half[1024]; +unsigned short rev256[256],rev512[512],rev1024[1024],rev4096[4096],rev2048[2048],rev8192[8192]; + + +char mode_string[4][20] = {"NOT SYNCHED","PRACH","RAR","PUSCH"}; + + + +#include "SIMULATION/ETH_TRANSPORT/vars.h" + +unsigned char NB_RU=0; + +#ifndef OPENAIR2 +unsigned char NB_eNB_INST=0; +unsigned char NB_UE_INST=0; +unsigned char NB_RN_INST=0; +unsigned char NB_INST=0; +#endif + +unsigned int ULSCH_max_consecutive_errors = 20; + +int number_of_cards; + + +int flag_LA=0; +int flagMag; +//extern channel_desc_t *eNB2UE[NUMBER_OF_eNB_MAX][NUMBER_OF_UE_MAX]; +//extern double ABS_SINR_eff_BLER_table[MCS_COUNT][9][9]; +//extern double ABS_beta[MCS_COUNT];odi +double sinr_bler_map[MCS_COUNT][2][MCS_TABLE_LENGTH_MAX]; +int table_length[MCS_COUNT]; +//double sinr_bler_map_up[MCS_COUNT][2][16]; + +//for MU-MIMO abstraction using MIESM +//this 2D arrarays contains SINR, MI and RBIR in rows 1, 2, and 3 respectively +double MI_map_4qam[3][162]; +double MI_map_16qam[3][197]; +double MI_map_64qam[3][227]; + +// here the first index is for transmission mode 1, 2, 5 and 6 whereas the second index is for the 16 sinr vaues corresponding to 16 CQIs +double sinr_to_cqi[4][16]= { {-2.5051, -2.5051, -1.7451, -0.3655, 1.0812, 2.4012, 3.6849, 6.6754, 8.3885, 8.7970, 12.0437, 14.4709, 15.7281, 17.2424, 17.2424, 17.2424}, + {-2.2360, -2.2360, -1.3919, -0.0218, 1.5319, 2.9574, 4.3234, 6.3387, 8.9879, 9.5096, 12.6609, 14.0116, 16.4984, 18.1572, 18.1572, 18.1572}, + {-1, -1.0000, -0.4198, -0.0140, 1.0362, 2.3520, 3.5793, 6.1136, 8.4836, 9.0858, 12.4723, 13.9128, 16.2054, 17.7392, 17.7392, 17.7392}, + { -4.1057, -4.1057, -3.3768, -2.2916, -1.1392, 0.1236, 1.2849, 3.1933, 5.9298, 6.4052, 9.6245, 10.9414, 13.5166, 14.9545, 14.9545, 14.9545} +}; + +//int cqi_to_mcs[16]={0, 0, 1, 3, 5, 7, 9, 13, 15, 16, 20, 23, 25, 27, 27, 27}; +int cqi_to_mcs[16]= {0, 0, 1, 2, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 27, 28}; + +//for SNR to MI conversion 7 th order Polynomial coeff +double q_qam16[8]= {3.21151853033897e-10,5.55435952230651e-09,-2.30760065362117e-07,-6.25587743817859e-06,4.62251036452795e-06,0.00224150813158937,0.0393723140344367,0.245486379182639}; +double q_qpsk[8]= {1.94491167814437e-09,8.40494123817774e-08,4.75527131198034e-07,-2.48946285301621e-05,-0.000347614016158364,0.00209252225437100,0.0742986115462510,0.488297879889425}; +double q_qam64[8]= {2.25934026232206e-11,-1.45992206328306e-10,-3.70861183071900e-08,-1.22206071019319e-06,6.49115500399637e-06,0.00129828997837433,0.0259669554914859,0.166602901214898}; + +//for MI to SNR conversion 7 th order Polynomial coeff +double p_qpsk[8]= {5982.42405670359,-21568.1135917693,31293.9987036905,-23394.6795043871,9608.34750585489,-2158.15802349899,267.731968719036,-20.6145324295965}; +double p_qam16[8]= {7862.12690694170,-28510.3207048338,41542.2150287122,-31088.3036957379,12690.1982361016,-2785.66604739984,326.595462489375,-18.9911849872089}; +double p_qam64[8]= {8832.57933013696,-32119.1802555952,46914.2578990397,-35163.8150557183,14343.7419388853,-3126.61025510092,360.954930562237,-18.0358548533343}; + +// ideal CE MIESM + +double beta1_dlsch_MI[6][MCS_COUNT] = { {1.1188, 0.3720, 0.3755, 0.9453, 0.5799, 0.5256, 0.5485, 0.5340, 0.5165, 0.5300, 0.6594, 0.5962, 0.4884, 0.4927, 0.3687, 0.4614, 0.4081, 0.2639,0.2935,0.2520,0.3709,0.2906,0.2612,0.2390}, {0.7138, 0.5533, 0.5533, 0.4828, 0.4998, 0.4843, 0.4942, 0.5323, 0.5142, 0.4756, 0.5792, 0.4167, 0.4445, 0.3942, 0.3789, 0.2756, 0.4456, 0.1650, 0.2254, 0.2353, 0.2097,0.2517,0.3242,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1},{1.808065416202085, 1.754544945430673,1.902272019362616, 1.790054645392961, 1.563204092967629, 1.585258289348813, 1.579349443720310, 1.570650121437345, 1.545055626608596, 1.362229442426877, 1.85, 1.79, 1.65, 1.54, 1.46, 1.39, 1.33, 1,1,1,1,1,1,1},{0.7146, 0.4789, 0.5392, 0.5556, 0.4975, 0.4847, 0.4691, 0.5261, 0.5278, 0.4962, 0.4468, 0.4113, 0.4622, 0.4609, 0.3946, 0.3991, 0.3532, 0.2439, 0.1898, 0.2929, 0.2712, 0.3367, 0.3591, 0.2571}}; +double beta2_dlsch_MI[6][MCS_COUNT] = { {1.1293, 0.3707, 0.3722, 0.9310, 0.5808, 0.5265, 0.5404, 0.5279, 0.5210, 0.5226, 0.6438, 0.5827, 0.4804, 0.4830, 0.3638, 0.4506, 0.4107, 0.2547, 0.2797, 0.2413, 0.3351, 0.2750, 0.2568, 0.2273}, {0.7028, 0.5503, 0.5503, 0.4815, 0.5006, 0.4764, 0.4810, 0.5124, 0.4964, 0.4485, 0.5497, 0.3971, 0.4239, 0.3701, 0.3494, 0.2630, 0.4053, 0.1505, 0.2001,0.2024,0.1788,0.2124,0.2668,1}, {1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1},{1.079518113138858, 1.105622953570353, 1.031337449900606, 1.073342032668810, 1.242636589110353, 1.255054927783647, 1.291463834317768, 1.317048698347491, 1.354485054187984, 0.338534029291017, 1.85, 1.79, 1.65, 1.54, 1.46, 1.39, 1.33,1, 1,1,1,1,1,1},{0.6980, 0.4694, 0.5379, 0.5483, 0.4982, 0.4737, 0.4611, 0.5051, 0.5020, 0.4672, 0.4357, 0.3957, 0.4389, 0.4344, 0.3645, 0.3661, 0.3301, 0.2179, 0.1730, 0.2536, 0.2389,0.2884,0.2936,0.2226}}; + +//real CE MIESM +/* +double beta1_dlsch_MI[6][MCS_COUNT] = { {1.32955, 0.59522, 0.54024, 0.98698, 0.81305, 0.76976, 0.69258, 0.69713, 0.70546, 0.69111, 0.81904, 0.72664, 0.79491, 0.72562, 0.53980, 0.33134, 0.50550, 0.40602,0.40281,0.47012,0.50510,0.23540,0.32045,1}, {0.59632, 1.08475, 1.02431, 1.07020, 0.90170, 0.97719, 0.95464, 0.92764, 0.86721, 0.85986, 0.64558, 0.80631, 0.82673, 0.82888, 0.87122, 0.77245, 0.29771, 0.43477, 0.55321, 0.61027, 0.56111, 0.57292, 0.39737,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1},{1.808065416202085, 1.754544945430673,1.902272019362616, 1.790054645392961, 1.563204092967629, 1.585258289348813, 1.579349443720310, 1.570650121437345, 1.545055626608596, 1.362229442426877, 1.85, 1.79, 1.65, 1.54, 1.46, 1.39, 1.33, 1,1,1,1,1,1,1},{0.77532, 1.07544, 1.10571, 1.04099, 0.91638, 0.88644, 0.96405, 0.86709, 0.94066, 0.84430, 1.24478, 1.09665, 1.42604, 0.79541, 0.71847, 0.71604, 0.74561, 0.36431, 0.41536, 0.52175, 0.47096, 0.49977, 0.59728,1}}; +double beta2_dlsch_MI[6][MCS_COUNT] = { {1.36875, 0.59304, 0.53870, 0.98239, 0.81637, 0.76847, 0.69842, 0.69885, 0.69967, 0.69826, 0.82660, 0.70559, 0.78404, 0.70670, 0.55393, 0.36893, 0.52225, 0.39752, 0.40494, 0.46239, 0.49247,0.26900,0.34504,1}, {0.43775, 0.78208, 0.72875, 0.77458, 0.64485, 0.69174, 0.66097, 0.63289, 0.59652, 0.61175, 0.44551, 0.56047, 0.57314, 0.57553, 0.58849, 0.52159, 0.21241, 0.30139, 0.37373, 0.32029, 0.37067, 0.36706, 0.27118,1}, {1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1},{1.079518113138858, 1.105622953570353, 1.031337449900606, 1.073342032668810, 1.242636589110353, 1.255054927783647, 1.291463834317768, 1.317048698347491, 1.354485054187984, 0.338534029291017, 1.85, 1.79, 1.65, 1.54, 1.46, 1.39, 1.33,1, 1,1,1,1,1,1},{0.54448, 0.73731, 0.79165, 0.74407, 0.68042, 0.64906, 0.71349, 0.62109, 0.65815, 0.60940, 0.90549, 0.78708, 1.03176, 0.58431, 0.53379, 0.51224, 0.52767, 0.26848, 0.29642, 0.36879, 0.34148, 0.35279,0.40633,1}}; +*/ +//ideal channel estimation values +//double beta1_dlsch[6][MCS_COUNT] = { {2.3814, 0.4956, 0.5273, 1.1708, 0.8014, 0.7889, 0.8111, 0.8139, 0.8124, 0.8479, 1.9280, 1.9664, 2.3857, 2.5147, 2.4511, 3.0158, 2.8643, 5.3013, 5.8594, 6.5372, 7.8073, 7.8030, 7.5295, 7.1320}, {0.5146, 0.5549, 0.7405, 0.6913, 0.7349, 0.7000, 0.7539, 0.7955, 0.8074, 0.7760, 1.8150, 1.6561, 1.9280, 2.3563, 2.6699, 2.3086, 3.1601, 4.5316, 5.2870, 6.0983, 6.5635, 7.7024, 9.9592, 6.6173}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {1.79358, 1.17908, 2.02600, 1.72040, 1.58618, 1.59039, 1.68111, 1.67062, 1.64911, 1.33274, 4.87800, 3.58797, 3.72338, 5.35700, 2.81752, 1.93472, 2.23259, 1,1,1,1,1,1,1}, {0.4445, 0.5918, 0.7118, 0.7115, 0.7284, 0.7202, 0.7117, 0.8111, 0.8239, 0.7907, 1.8456, 1.8144, 2.3830, 2.6634, 2.6129, 2.8127, 2.7372, 4.9424, 4.8763, 6.8413, 7.1493, 9.4180, 10.1230, 8.9613}}; +//double beta2_dlsch[6][MCS_COUNT] = { {2.3639, 0.4952, 0.5207, 1.1572, 0.8026, 0.7864, 0.7996, 0.8034, 0.8200, 0.8367, 1.8701, 1.9212, 2.2947, 2.4472, 2.4091, 2.9479, 2.8973, 5.0591, 5.5134, 6.1483, 7.2166, 7.5177, 7.5704, 7.2248}, {0.5113, 0.5600, 0.7359, 0.6860, 0.7344, 0.6902, 0.7315, 0.7660, 0.7817, 0.7315, 1.7268, 1.5912, 1.8519, 2.2115, 2.4580, 2.1879, 2.9015, 4.1543, 4.6986, 5.3193, 5.6319, 6.5640, 8.2421, 5.6393}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {0.79479, 0.52872, 0.90005, 0.77170, 0.73220, 0.72060, 0.75433, 0.75451, 0.75989, 0.67655, 1.68525, 1.31100, 1.46573, 1.99843, 1.57293, 1.62852, 2.10636, 1,1,1,1,1,1,1}, {0.4398, 0.5823, 0.7094, 0.7043, 0.7282, 0.7041, 0.6979, 0.7762, 0.7871, 0.7469, 1.7752, 1.7443, 2.2266, 2.4767, 2.4146, 2.6040, 2.5708, 4.4488, 4.4944, 5.9630, 6.3740, 8.1097, 8.4210, 7.8027}}; +double beta1_dlsch[6][MCS_COUNT] = { {1.199175, 1.085656, 0.983872, 0.843789, 0.816093, 0.853078, 0.899236, 0.919665, 0.888673, 0.924181, 0.814176, 0.794108, 0.770653, 0.826266, 0.982043, 0.979621, 0.985176, 0.901741, 0.870311, 0.911303, 0.898923, 1.003359, 0.988535, 1.030639, 1.151038, 1.116939, 1.214118, 1.219148}, {0.5146, 0.5549, 0.7405, 0.6913, 0.7349, 0.7000, 0.7539, 0.7955, 0.8074, 0.7760, 1.8150, 1.6561, 1.9280, 2.3563, 2.6699, 2.3086, 3.1601, 4.5316, 5.2870, 6.0983, 6.5635, 7.7024, 9.9592, 6.6173}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {1.79358, 1.17908, 2.02600, 1.72040, 1.58618, 1.59039, 1.68111, 1.67062, 1.64911, 1.33274, 4.87800, 3.58797, 3.72338, 5.35700, 2.81752, 1.93472, 2.23259, 1,1,1,1,1,1,1}, {0.4445, 0.5918, 0.7118, 0.7115, 0.7284, 0.7202, 0.7117, 0.8111, 0.8239, 0.7907, 1.8456, 1.8144, 2.3830, 2.6634, 2.6129, 2.8127, 2.7372, 4.9424, 4.8763, 6.8413, 7.1493, 9.4180, 10.1230, 8.9613}}; +double beta2_dlsch[6][MCS_COUNT] = { {0.534622, 0.596561, 0.500838, 0.471721, 0.548218, 0.547974, 0.924245, 0.836484, 0.776917, 0.879691, 0.875722, 0.666933, 0.666393, 0.755377, 1.074985, 1.080290, 1.010914, 0.790892, 0.793435, 0.860249, 0.901508, 0.967060, 0.951372, 1.011493, 1.106151, 1.117076, 1.209397, 1.227790}, {0.5113, 0.5600, 0.7359, 0.6860, 0.7344, 0.6902, 0.7315, 0.7660, 0.7817, 0.7315, 1.7268, 1.5912, 1.8519, 2.2115, 2.4580, 2.1879, 2.9015, 4.1543, 4.6986, 5.3193, 5.6319, 6.5640, 8.2421, 5.6393}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {0.79479, 0.52872, 0.90005, 0.77170, 0.73220, 0.72060, 0.75433, 0.75451, 0.75989, 0.67655, 1.68525, 1.31100, 1.46573, 1.99843, 1.57293, 1.62852, 2.10636, 1,1,1,1,1,1,1}, {0.4398, 0.5823, 0.7094, 0.7043, 0.7282, 0.7041, 0.6979, 0.7762, 0.7871, 0.7469, 1.7752, 1.7443, 2.2266, 2.4767, 2.4146, 2.6040, 2.5708, 4.4488, 4.4944, 5.9630, 6.3740, 8.1097, 8.4210, 7.8027}}; + +//real channel estimation valus +/* +double beta1_dlsch[6][MCS_COUNT] = { {2.50200, 0.84047, 0.78195, 1.37929, 1.16871, 1.11906, 1.06303, 1.07447, 1.11403, 1.09223, 2.82502, 2.87556, 3.51254, 3.62920, 3.53638, 2.35980, 3.74126, 8.66532, 7.31772, 9.86882, 10.64939, 6.75208, 9.50664, 13.63057}, {0.92257, 1, 1.80445, 1.43175, 1.42093, 1.37381, 1.45392, 1.47255, 1.47451, 1.41235, 3.9079, 3.38557, 4.13059, 4.93355, 4.97277, 6.04951, 5.88896, 8.68076, 10.23746, 12.37069, 5.50538, 17.29612, 17.95050, 13.27095}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {1.79255, 1.88213, 4.44226, 2.25150, 1.93710, 2.18504, 2.57389, 1.94322, 1.78515, 2.09265, 2.37459, 1.74442, 1.74346, 1.19705, 1.56149, 1.59604, 1.6, 1,1,1,1,1,1,1}, {0.93374, 1.40389, 1.36670, 1.38679, 1.35707, 1.26353, 1.32360, 1.40164, 1.51843, 1.34863, 3.45839, 3.13726, 3.94768, 4.21966, 4.60750, 4.97894, 5.40755, 8.12814, 10.59221, 12.96427, 13.37323, 14.27206, 16.61779, 17.19656}}; +double beta2_dlsch[6][MCS_COUNT] = { {2.52163, 0.83231, 0.77472, 1.36536, 1.16829, 1.11186, 1.06287, 1.07292, 1.09946, 1.10650, 2.79174, 2.75655, 3.36651, 3.49011, 3.60903, 2.73517, 3.84009, 8.20312, 7.41739, 9.64081, 10.40911, 8.11765, 10.41923, 9.34300}, {0.67252, 0.8600, 1.28633, 1.01624, 1.03066, 0.97590, 1.02560, 1.01840, 1.00547, 0.97093, 2.72573, 2.33283, 2.86181, 3.40452, 3.47957, 4.08916, 3.97628, 6.14541, 7.11017, 8.42369, 4.04812, 11.42082, 11.57171, 9.28462}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1,1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1,1,1,1,1}, {0.85784, 0.90361, 2.09766, 1.08385, 0.96300, 1.04432, 1.22763, 0.99249, 0.95544, 1.12333, 1.37924, 1.12913, 1.30644, 1.19253, 1.75488, 2.13813, 2.10636, 1,1,1,1,1,1,1}, {0.66288, 0.96402, 0.98545, 0.99386, 0.99981, 0.92678, 0.98978, 0.99600, 1.05538, 0.97777, 2.52504, 2.29338, 2.89631, 3.10812, 3.41916, 3.58671, 3.84166, 6.05254, 7.45821, 9.15812, 9.66330, 10.17852, 11.50519, 11.16299}}; + +*/ + +#ifdef OCP_FRAMEWORK +#include <enums.h> +#else +char eNB_functions[6][20]={"eNodeB_3GPP","eNodeB_3GPP_BBU","NGFI_RAU_IF4p5","NGFI_RRU_IF5","NGFI_RRU_IF4p5",}; +char eNB_timing[2][20]={"synch_to_ext_device","synch_to_other"}; +char ru_if_types[MAX_RU_IF_TYPES][20]={"local RF","IF5 RRU","IF5 Mobipass","IF4p5 RRU","IF1pp RRU"}; +#endif + +/// lookup table for unscrambling in RX +int16_t unscrambling_lut[65536*16] __attribute__((aligned(32))); +/// lookup table for scrambling in TX +uint8_t scrambling_lut[65536*16] __attribute__((aligned(32))); + +uint8_t max_turbo_iterations=4; +#endif /*__PHY_VARS_H__ */ diff --git a/openair1/SCHED_NR/phy_frame_config_nr.h b/openair1/SCHED_NR/phy_frame_config_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..80cf23b02672e0800edc78d4e29d11045b62bb40 --- /dev/null +++ b/openair1/SCHED_NR/phy_frame_config_nr.h @@ -0,0 +1,96 @@ +/* + * 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 + */ + +/*********************************************************************** +* +* FILENAME : phy_frame_configuration_nr.h +* +* DESCRIPTION : functions related to FDD/TDD configuration for NR +* see TS 38.213 11.1 Slot configuration +* and TS 38.331 for RRC configuration +* +************************************************************************/ + +#ifndef PHY_FRAME_CONFIG_NR_H +#define PHY_FRAME_CONFIG_NR_H + +/************** DEFINE ********************************************/ + +#define TDD_CONFIG_NB_FRAMES (2) + +/*************** FUNCTIONS *****************************************/ + +/** \brief This function processes tdd dedicated configuration for nr + * @param frame_parms NR DL Frame parameters + * @param dl_UL_TransmissionPeriodicity periodicity + * @param nrofDownlinkSlots number of downlink slots + * @param nrofDownlinkSymbols number of downlink symbols + * @param nrofUplinkSlots number of uplink slots + * @param nrofUplinkSymbols number of uplink symbols + @returns 0 if tdd dedicated configuration has been properly set or -1 on error with message */ + +int set_tdd_config_nr(NR_DL_FRAME_PARMS *frame_parms, int dl_UL_TransmissionPeriodicity, + int nrofDownlinkSlots, int nrofDownlinkSymbols, + int nrofUplinkSlots, int nrofUplinkSymbols); + +/** \brief This function adds a slot configuration to current dedicated configuration for nr + * @param frame_parms NR DL Frame parameters + * @param slotIndex + * @param nrofDownlinkSymbols + * @param nrofUplinkSymbols + @returns none */ + +void add_tdd_dedicated_configuration_nr(NR_DL_FRAME_PARMS *frame_parms, int slotIndex, + int nrofDownlinkSymbols, int nrofUplinkSymbols); + +/** \brief This function processes tdd dedicated configuration for nr + * @param frame_parms nr frame parameters + * @param dl_UL_TransmissionPeriodicity periodicity + * @param nrofDownlinkSlots number of downlink slots + * @param nrofDownlinkSymbols number of downlink symbols + * @param nrofUplinkSlots number of uplink slots + * @param nrofUplinkSymbols number of uplink symbols + @returns 0 if tdd dedicated configuration has been properly set or -1 on error with message */ + +int set_tdd_configuration_dedicated_nr(NR_DL_FRAME_PARMS *frame_parms); + +/** \brief This function checks nr slot direction : downlink or uplink + * @param frame_parms NR DL Frame parameters + * @param nr_frame : frame number + * @param nr_tti : slot number + @returns nr_slot_t : downlink or uplink */ + +nr_slot_t slot_select_nr(NR_DL_FRAME_PARMS *frame_parms, int nr_frame, int nr_tti); + +/** \brief This function frees tdd configuration for nr + * @param frame_parms NR DL Frame parameters + @returns none */ + +void free_tdd_configuration_nr(NR_DL_FRAME_PARMS *frame_parms); + +/** \brief This function frees tdd dedicated configuration for nr + * @param frame_parms NR DL Frame parameters + @returns none */ + +void free_tdd_configuration_dedicated_nr(NR_DL_FRAME_PARMS *frame_parms); + +#endif /* PHY_FRAME_CONFIG_NR_H */ + diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 7460c4849bfa383048a100ef4184b562d5856f0e..e6f0d5d0f13e6d41b8ada32d42a69392259af807 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -211,6 +211,14 @@ typedef struct { int iq_rxrescale; //! Configuration file for LMS7002M char *configFilename; + //! remote IP/MAC addr for Ethernet interface + char *remote_addr; + //! remote port number for Ethernet interface + unsigned int remote_port; + //! local IP/MAC addr for Ethernet interface (eNB/BBU, UE) + char *my_addr; + //! local port number for Ethernet interface (eNB/BBU, UE) + unsigned int my_port; #if defined(USRP_REC_PLAY) unsigned short sf_mode; // 1=record, 2=replay char sf_filename[1024]; // subframes file path diff --git a/targets/COMMON/threads_t.h b/targets/COMMON/threads_t.h index ddc060e8c331328b9b8a3a564940df4fba896e80..99fb0d8cf449d225c0d771bbde630fb460cfe508 100644 --- a/targets/COMMON/threads_t.h +++ b/targets/COMMON/threads_t.h @@ -9,6 +9,12 @@ typedef struct threads_s { int slot1_proc_one; int slot1_proc_two; int slot1_proc_three; + int dlsch_td_one; + int dlsch_td_two; + int dlsch_td_three; + int dlsch_td1_one; + int dlsch_td1_two; + int dlsch_td1_three; } threads_t; #endif /* _THREADS_T_H_ */ diff --git a/targets/RT/USER/nr-ue.c b/targets/RT/USER/nr-ue.c index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..38b80f28480cb1a3027b261a7b07d4e838169084 100644 --- a/targets/RT/USER/nr-ue.c +++ b/targets/RT/USER/nr-ue.c @@ -0,0 +1,1077 @@ +/* + * 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.0 (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 lte-ue.c + * \brief threads and support functions for real-time LTE UE target + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2015 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ +#include "nr-uesoftmodem.h" + +#include "rt_wrapper.h" + +#include "LAYER2/MAC/mac.h" +#include "RRC/LTE/rrc_extern.h" +#include "PHY_INTERFACE/phy_interface_extern.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/phy_extern_nr_ue.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" + +#include "SCHED_NR/extern.h" +//#ifndef NO_RAT_NR +#include "SCHED_NR/phy_frame_config_nr.h" +//#endif + +#include "../../../openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" + +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" + +#include "T.h" + +extern double cpuf; + +#define FRAME_PERIOD 100000000ULL +#define DAQ_PERIOD 66667ULL +#define FIFO_PRIORITY 40 + +typedef enum { + pss=0, + pbch=1, + si=2 +} sync_mode_t; + +void init_UE_threads(PHY_VARS_NR_UE *UE); +void *UE_thread(void *arg); +void init_UE(int nb_inst); + +int32_t **rxdata; +int32_t **txdata; + +#define KHz (1000UL) +#define MHz (1000*KHz) +#define SAIF_ENABLED + +#ifdef SAIF_ENABLED +uint64_t g_ue_rx_thread_busy = 0; +#endif + +typedef struct eutra_band_s { + int16_t band; + uint32_t ul_min; + uint32_t ul_max; + uint32_t dl_min; + uint32_t dl_max; + lte_frame_type_t frame_type; +} eutra_band_t; + +typedef struct band_info_s { + int nbands; + eutra_band_t band_info[100]; +} band_info_t; + +band_info_t bands_to_scan; + +static const eutra_band_t eutra_bands[] = { + { 1, 1920 * MHz, 1980 * MHz, 2110 * MHz, 2170 * MHz, FDD}, + { 2, 1850 * MHz, 1910 * MHz, 1930 * MHz, 1990 * MHz, FDD}, + { 3, 1710 * MHz, 1785 * MHz, 1805 * MHz, 1880 * MHz, FDD}, + { 4, 1710 * MHz, 1755 * MHz, 2110 * MHz, 2155 * MHz, FDD}, + { 5, 824 * MHz, 849 * MHz, 869 * MHz, 894 * MHz, FDD}, + { 6, 830 * MHz, 840 * MHz, 875 * MHz, 885 * MHz, FDD}, + { 7, 2500 * MHz, 2570 * MHz, 2620 * MHz, 2690 * MHz, FDD}, + { 8, 880 * MHz, 915 * MHz, 925 * MHz, 960 * MHz, FDD}, + { 9, 1749900 * KHz, 1784900 * KHz, 1844900 * KHz, 1879900 * KHz, FDD}, + {10, 1710 * MHz, 1770 * MHz, 2110 * MHz, 2170 * MHz, FDD}, + {11, 1427900 * KHz, 1452900 * KHz, 1475900 * KHz, 1500900 * KHz, FDD}, + {12, 698 * MHz, 716 * MHz, 728 * MHz, 746 * MHz, FDD}, + {13, 777 * MHz, 787 * MHz, 746 * MHz, 756 * MHz, FDD}, + {14, 788 * MHz, 798 * MHz, 758 * MHz, 768 * MHz, FDD}, + {17, 704 * MHz, 716 * MHz, 734 * MHz, 746 * MHz, FDD}, + {20, 832 * MHz, 862 * MHz, 791 * MHz, 821 * MHz, FDD}, + {22, 3510 * MHz, 3590 * MHz, 3410 * MHz, 3490 * MHz, FDD}, + {33, 1900 * MHz, 1920 * MHz, 1900 * MHz, 1920 * MHz, TDD}, + {34, 2010 * MHz, 2025 * MHz, 2010 * MHz, 2025 * MHz, TDD}, + {35, 1850 * MHz, 1910 * MHz, 1850 * MHz, 1910 * MHz, TDD}, + {36, 1930 * MHz, 1990 * MHz, 1930 * MHz, 1990 * MHz, TDD}, + {37, 1910 * MHz, 1930 * MHz, 1910 * MHz, 1930 * MHz, TDD}, + {38, 2570 * MHz, 2620 * MHz, 2570 * MHz, 2630 * MHz, TDD}, + {39, 1880 * MHz, 1920 * MHz, 1880 * MHz, 1920 * MHz, TDD}, + {40, 2300 * MHz, 2400 * MHz, 2300 * MHz, 2400 * MHz, TDD}, + {41, 2496 * MHz, 2690 * MHz, 2496 * MHz, 2690 * MHz, TDD}, + {42, 3400 * MHz, 3600 * MHz, 3400 * MHz, 3600 * MHz, TDD}, + {43, 3600 * MHz, 3800 * MHz, 3600 * MHz, 3800 * MHz, TDD}, + {44, 703 * MHz, 803 * MHz, 703 * MHz, 803 * MHz, TDD}, +}; + +void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char * name) { + +#ifdef DEADLINE_SCHEDULER + if (sched_runtime!=0) { + struct sched_attr attr= {0}; + attr.size = sizeof(attr); + attr.sched_policy = SCHED_DEADLINE; + attr.sched_runtime = sched_runtime; + attr.sched_deadline = sched_deadline; + attr.sched_period = 0; + AssertFatal(sched_setattr(0, &attr, 0) == 0, + "[SCHED] %s thread: sched_setattr failed %s \n", name, strerror(errno)); + LOG_I(HW,"[SCHED][eNB] %s deadline thread %lu started on CPU %d\n", + name, (unsigned long)gettid(), sched_getcpu()); + } + +#else + if (CPU_COUNT(cpuset) > 0) + AssertFatal( 0 == pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), cpuset), ""); + struct sched_param sp; + sp.sched_priority = sched_fifo; + AssertFatal(pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp)==0, + "Can't set thread priority, Are you root?\n"); + /* Check the actual affinity mask assigned to the thread */ + cpu_set_t *cset=CPU_ALLOC(CPU_SETSIZE); + if (0 == pthread_getaffinity_np(pthread_self(), CPU_ALLOC_SIZE(CPU_SETSIZE), cset)) { + char txt[512]={0}; + for (int j = 0; j < CPU_SETSIZE; j++) + if (CPU_ISSET(j, cset)) + sprintf(txt+strlen(txt), " %d ", j); + printf("CPU Affinity of thread %s is %s\n", name, txt); + } + CPU_FREE(cset); +#endif + + // Lock memory from swapping. This is a process wide call (not constraint to this thread). + mlockall(MCL_CURRENT | MCL_FUTURE); + pthread_setname_np( pthread_self(), name ); + + // LTS: this sync stuff should be wrong + printf("waiting for sync (%s)\n",name); + pthread_mutex_lock(&sync_mutex); + printf("Locked sync_mutex, waiting (%s)\n",name); + while (sync_var<0) + pthread_cond_wait(&sync_cond, &sync_mutex); + pthread_mutex_unlock(&sync_mutex); + printf("started %s as PID: %ld\n",name, gettid()); +} + +void init_UE(int nb_inst) +{ + int inst; + for (inst=0; inst < nb_inst; inst++) { + // UE->rfdevice.type = NONE_DEV; + PHY_VARS_NR_UE *UE = PHY_vars_UE_g[inst][0]; + AssertFatal(0 == pthread_create(&UE->proc.pthread_ue, + &UE->proc.attr_ue, + UE_thread, + (void*)UE), ""); + } + + printf("UE threads created by %ld\n", gettid()); +#if 0 +#if defined(ENABLE_USE_MME) + extern volatile int start_UE; + while (start_UE == 0) { + sleep(1); + } +#endif +#endif +} + +/*! + * \brief This is the UE synchronize thread. + * It performs band scanning and synchonization. + * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void *UE_thread_synch(void *arg) { + static int __thread UE_thread_synch_retval; + int i, hw_slot_offset; + PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE*) arg; + int current_band = 0; + int current_offset = 0; + sync_mode_t sync_mode = pbch; + int CC_id = UE->CC_id; + int freq_offset=0; + char threadname[128]; + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + if ( threads.iq != -1 ) + CPU_SET(threads.iq, &cpuset); + // this thread priority must be lower that the main acquisition thread + sprintf(threadname, "sync UE %d\n", UE->Mod_id); + init_thread(100000, 500000, FIFO_PRIORITY-1, &cpuset, threadname); + + UE->is_synchronized = 0; + + if (UE->UE_scan == 0) { + int ind; + for ( ind=0; + ind < sizeof(eutra_bands) / sizeof(eutra_bands[0]); + ind++) { + current_band = eutra_bands[ind].band; + LOG_D(PHY, "Scanning band %d, dl_min %"PRIu32", ul_min %"PRIu32"\n", current_band, eutra_bands[ind].dl_min,eutra_bands[ind].ul_min); + if ( eutra_bands[ind].dl_min <= downlink_frequency[0][0] && eutra_bands[ind].dl_max >= downlink_frequency[0][0] ) { + for (i=0; i<4; i++) + uplink_frequency_offset[CC_id][i] = eutra_bands[ind].ul_min - eutra_bands[ind].dl_min; + break; + } + } + AssertFatal( ind < sizeof(eutra_bands) / sizeof(eutra_bands[0]), "Can't find EUTRA band for frequency"); + + LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %"PRIu32", UL %"PRIu32" (oai_exit %d, rx_num_channels %d)\n", + downlink_frequency[0][0], downlink_frequency[0][0]+uplink_frequency_offset[0][0], + oai_exit, openair0_cfg[0].rx_num_channels); + + for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) { + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]; + openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = + downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]; + openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1; + if (uplink_frequency_offset[CC_id][i] != 0) // + openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_FDD; + else //FDD + openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_TDD; + } + sync_mode = pbch; + + } else { + current_band=0; + for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) { + downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[CC_id].dl_min; + uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] = + bands_to_scan.band_info[CC_id].ul_min-bands_to_scan.band_info[CC_id].dl_min; + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]; + openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = + downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]; + openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB; + } + } + + // AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n"); + + while (oai_exit==0) { + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + while (UE->proc.instance_cnt_synch < 0) + // the thread waits here most of the time + pthread_cond_wait( &UE->proc.cond_synch, &UE->proc.mutex_synch ); + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + + switch (sync_mode) { + case pss: + LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset); + lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset); + current_offset += 20000000; // increase by 20 MHz + + if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) { + current_band++; + current_offset=0; + } + + if (current_band==bands_to_scan.nbands) { + current_band=0; + oai_exit=1; + } + + for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) { + downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].dl_min+current_offset; + uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].ul_min-bands_to_scan.band_info[0].dl_min + current_offset; + + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]; + openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]; + openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB; + if (UE->UE_scan_carrier) { + openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1; + } + + } + + break; + + case pbch: + +#if DISABLE_LOG_X + printf("[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode); +#else + LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode); +#endif + if (initial_sync( UE, UE->mode ) == 0) { + + hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_tti; + printf("Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n", + hw_slot_offset, + freq_offset, + UE->rx_total_gain_dB, + downlink_frequency[0][0]+freq_offset, + downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset, + UE->UE_scan_carrier ); + + + // rerun with new cell parameters and frequency-offset + for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) { + openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; + if (UE->UE_scan_carrier == 1) { + if (freq_offset >= 0) + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] += abs(UE->common_vars.freq_offset); + else + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= abs(UE->common_vars.freq_offset); + openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i]; + downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i]; + freq_offset=0; + } + } + + // reconfigure for potentially different bandwidth + switch(UE->frame_parms.N_RB_DL) { + case 6: + openair0_cfg[UE->rf_map.card].sample_rate =1.92e6; + openair0_cfg[UE->rf_map.card].rx_bw =.96e6; + openair0_cfg[UE->rf_map.card].tx_bw =.96e6; + // openair0_cfg[0].rx_gain[0] -= 12; + break; + case 25: + openair0_cfg[UE->rf_map.card].sample_rate =7.68e6; + openair0_cfg[UE->rf_map.card].rx_bw =2.5e6; + openair0_cfg[UE->rf_map.card].tx_bw =2.5e6; + // openair0_cfg[0].rx_gain[0] -= 6; + break; + case 50: + openair0_cfg[UE->rf_map.card].sample_rate =15.36e6; + openair0_cfg[UE->rf_map.card].rx_bw =5.0e6; + openair0_cfg[UE->rf_map.card].tx_bw =5.0e6; + // openair0_cfg[0].rx_gain[0] -= 3; + break; + case 100: + openair0_cfg[UE->rf_map.card].sample_rate=30.72e6; + openair0_cfg[UE->rf_map.card].rx_bw=10.0e6; + openair0_cfg[UE->rf_map.card].tx_bw=10.0e6; + // openair0_cfg[0].rx_gain[0] -= 0; + break; + } + + UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); + //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]); + //UE->rfdevice.trx_stop_func(&UE->rfdevice); + // sleep(1); + //init_frame_parms(&UE->frame_parms,1); + /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { + LOG_E(HW,"Could not start the device\n"); + oai_exit=1; + }*/ + + if (UE->UE_scan_carrier == 1) { + + UE->UE_scan_carrier = 0; + } else { + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + UE->is_synchronized = 1; + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + + if( UE->mode == rx_dump_frame ) { + FILE *fd; + if ((UE->proc.proc_rxtx[0].frame_rx&1) == 0) { // this guarantees SIB1 is present + if ((fd = fopen("rxsig_frame0.dat","w")) != NULL) { + fwrite((void*)&UE->common_vars.rxdata[0][0], + sizeof(int32_t), + 10*UE->frame_parms.samples_per_subframe, + fd); + LOG_I(PHY,"Dummping Frame ... bye bye \n"); + fclose(fd); + exit(0); + } else { + LOG_E(PHY,"Cannot open file for writing\n"); + exit(0); + } + } else { + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + UE->is_synchronized = 0; + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + + } + } + } + } else { + // initial sync failed + // calculate new offset and try again + if (UE->UE_scan_carrier == 1) { + if (freq_offset >= 0) + freq_offset += 100; + freq_offset *= -1; + + if (abs(freq_offset) > 7500) { + LOG_I( PHY, "[initial_sync] No cell synchronization found, abandoning\n" ); + FILE *fd; + if ((fd = fopen("rxsig_frame0.dat","w"))!=NULL) { + fwrite((void*)&UE->common_vars.rxdata[0][0], + sizeof(int32_t), + 10*UE->frame_parms.samples_per_subframe, + fd); + LOG_I(PHY,"Dummping Frame ... bye bye \n"); + fclose(fd); + exit(0); + } + //mac_xface->macphy_exit("No cell synchronization found, abandoning"); new mac + return &UE_thread_synch_retval; // not reached + } + } +#if DISABLE_LOG_X + printf("[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n", + freq_offset, + UE->rx_total_gain_dB, + downlink_frequency[0][0]+freq_offset, + downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset ); +#else + LOG_I(PHY, "[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n", + freq_offset, + UE->rx_total_gain_dB, + downlink_frequency[0][0]+freq_offset, + downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset ); +#endif + + for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) { + openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+freq_offset; + openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]+freq_offset; + openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; + if (UE->UE_scan_carrier==1) + openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1; + } + UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0); + }// initial_sync=0 + break; + case si: + default: + break; + } + + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + // indicate readiness + UE->proc.instance_cnt_synch--; + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH, 0 ); + } // while !oai_exit + + return &UE_thread_synch_retval; +} + +/*! + * \brief This is the UE thread for RX subframe n and TX subframe n+4. + * This thread performs the phy_procedures_UE_RX() on every received slot. + * then, if TX is enabled it performs TX for n+4. + * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + +static void *UE_thread_rxn_txnp4(void *arg) { + static __thread int UE_thread_rxtx_retval; + struct nr_rxtx_thread_data *rtd = arg; + UE_nr_rxtx_proc_t *proc = rtd->proc; + PHY_VARS_NR_UE *UE = rtd->UE; + int ret; + + //proc->counter_decoder = 0; + proc->instance_cnt_rxtx=-1; + proc->subframe_rx=proc->sub_frame_start; + + proc->dci_err_cnt=0; + char threadname[256]; + sprintf(threadname,"UE_%d_proc_%d", UE->Mod_id, proc->sub_frame_start); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + char timing_proc_name[256]; + sprintf(timing_proc_name,"Delay to process sub-frame proc %d",proc->sub_frame_start); + + if ( (proc->sub_frame_start+1)%RX_NB_TH == 0 && threads.one != -1 ) + CPU_SET(threads.one, &cpuset); + if ( (proc->sub_frame_start+1)%RX_NB_TH == 1 && threads.two != -1 ) + CPU_SET(threads.two, &cpuset); + if ( (proc->sub_frame_start+1)%RX_NB_TH == 2 && threads.three != -1 ) + CPU_SET(threads.three, &cpuset); + //CPU_SET(threads.three, &cpuset); + init_thread(900000,1000000 , FIFO_PRIORITY-1, &cpuset, + threadname); + + while (!oai_exit) { + if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { + LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" ); + exit_fun("nothing to add"); + } + while (proc->instance_cnt_rxtx < 0) { + // most of the time, the thread is waiting here + pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx ); + } + if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { + LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" ); + exit_fun("nothing to add"); + } + +// initRefTimes(t2); + initRefTimes(t3); + pickTime(current); +// updateTimes(proc->gotIQs, &t2, 10000, "Delay to wake up UE_Thread_Rx (case 2)"); + +#ifndef NO_RAT_NR + // Process Rx data for one sub-frame + nr_slot_t nr_slot ; //= slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx); + + if (nr_slot == NR_TDD_DOWNLINK_SLOT) { +#else + // Process Rx data for one sub-frame + lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx); + if ((sf_type == SF_DL) || + (UE->frame_parms.frame_type == FDD) || + (sf_type == SF_S)) { + + if (UE->frame_parms.frame_type == TDD) { + LOG_D(PHY, "%s,TDD%d,%s: calling UE_RX\n", + threadname, + UE->frame_parms.tdd_config, + (sf_type==SF_DL? "SF_DL" : + (sf_type==SF_UL? "SF_UL" : + (sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE")))); + } else { + LOG_D(PHY, "%s,%s,%s: calling UE_RX\n", + threadname, + (UE->frame_parms.frame_type==FDD? "FDD": + (UE->frame_parms.frame_type==TDD? "TDD":"UNKNOWN_DUPLEX_MODE")), + (sf_type==SF_DL? "SF_DL" : + (sf_type==SF_UL? "SF_UL" : + (sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE")))); + } +#endif +#ifdef UE_SLOT_PARALLELISATION + phy_procedures_slot_parallelization_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL ); +#else + phy_procedures_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL ); +#endif + } + +#if UE_TIMING_TRACE + start_meas(&UE->generic_stat); +#endif + if (UE->mac_enabled==1) { + +#ifdef NEW_MAC + ret = mac_xface->ue_scheduler(UE->Mod_id, + proc->frame_rx, + proc->subframe_rx, + proc->nr_tti_rx, + proc->frame_tx, + proc->subframe_tx, + proc->nr_tti_tx%(UE->frame_parms.ttis_per_subframe), +#ifndef NO_RAT_NR + slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx), +#else + subframe_select(&UE->frame_parms,proc->subframe_tx), +#endif + 0, + 0/*FIXME CC_id*/); +#endif + +/*#else + ret = mac_xface->ue_scheduler(UE->Mod_id, + proc->frame_rx, + proc->subframe_rx, + proc->frame_tx, + proc->subframe_tx, + subframe_select(&UE->frame_parms,proc->subframe_tx), + 0, */ +// 0/*FIXME CC_id*/); +//#endif + if ( ret != CONNECTION_OK) { + char *txt; + switch (ret) { + case CONNECTION_LOST: + txt="RRC Connection lost, returning to PRACH"; + break; + case PHY_RESYNCH: + txt="RRC Connection lost, trying to resynch"; + break; + case RESYNCH: + txt="return to PRACH and perform a contention-free access"; + break; + default: + txt="UNKNOWN RETURN CODE"; + }; + LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u %s\n", + UE->Mod_id, proc->frame_rx, proc->subframe_tx,txt ); + } + } +#if UE_TIMING_TRACE + stop_meas(&UE->generic_stat); +#endif + + // Prepare the future Tx data +#if 1 + if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || + (UE->frame_parms.frame_type == FDD) ) + if (UE->mode != loop_through_memory) + phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay); +#endif + + if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) && + (UE->frame_parms.frame_type == TDD)) + if (UE->mode != loop_through_memory) + phy_procedures_UE_S_TX(UE,0,0,no_relay); + updateTimes(current, &t3, 10000, timing_proc_name); + + if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { + LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" ); + exit_fun("noting to add"); + } + proc->instance_cnt_rxtx--; + if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { + LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXTX\n" ); + exit_fun("noting to add"); + } + } + +// thread finished + free(arg); + return &UE_thread_rxtx_retval; +} + +/*! + * \brief This is the main UE thread. + * This thread controls the other three UE threads: + * - UE_thread_rxn_txnp4 (even subframes) + * - UE_thread_rxn_txnp4 (odd subframes) + * - UE_thread_synch + * \param arg unused + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + +void *UE_thread(void *arg) { + + PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg; + // int tx_enabled = 0; + int dummy_rx[UE->frame_parms.nb_antennas_rx][UE->frame_parms.samples_per_tti] __attribute__((aligned(32))); + openair0_timestamp timestamp,timestamp1; + void* rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX]; + int start_rx_stream = 0; + int i; + char threadname[128]; + int th_id; + UE->proc.proc_rxtx[0].counter_decoder = 0; + UE->proc.proc_rxtx[1].counter_decoder = 0; + UE->proc.proc_rxtx[2].counter_decoder = 0; + + static uint8_t thread_idx = 0; + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + if ( threads.iq != -1 ) + CPU_SET(threads.iq, &cpuset); + init_thread(100000, 500000, FIFO_PRIORITY, &cpuset, + "UHD Threads"); + if (oaisim_flag == 0) + AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), ""); + UE->rfdevice.host_type = RAU_HOST; + sprintf(threadname, "Main UE %d", UE->Mod_id); + pthread_setname_np(pthread_self(), threadname); + init_UE_threads(UE); + +#ifdef NAS_UE + MessageDef *message_p; + message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE); + itti_send_msg_to_task (TASK_NAS_UE, UE->Mod_id + NB_eNB_INST, message_p); +#endif + + int tti_nr=-1; + //int cumulated_shift=0; + AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n"); + while (!oai_exit) { + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + int instance_cnt_synch = UE->proc.instance_cnt_synch; + int is_synchronized = UE->is_synchronized; + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + + if (is_synchronized == 0) { + if (instance_cnt_synch < 0) { // we can invoke the synch + // grab 10 ms of signal and wakeup synch thread + for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) + rxp[i] = (void*)&UE->common_vars.rxdata[i][0]; + + if (UE->mode != loop_through_memory) + AssertFatal( UE->frame_parms.samples_per_subframe*10 == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_subframe*10, + UE->frame_parms.nb_antennas_rx), ""); + AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); + instance_cnt_synch = ++UE->proc.instance_cnt_synch; + if (instance_cnt_synch == 0) { + AssertFatal( 0 == pthread_cond_signal(&UE->proc.cond_synch), ""); + } else { + LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" ); + exit_fun("nothing to add"); + } + AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), ""); + } else { +#if OAISIM + (void)dummy_rx; /* avoid gcc warnings */ + usleep(500); +#else + // grab 10 ms of signal into dummy buffer + if (UE->mode != loop_through_memory) { + for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) + rxp[i] = (void*)&dummy_rx[i][0]; + for (int sf=0; sf<10; sf++) + // printf("Reading dummy sf %d\n",sf); + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + UE->frame_parms.samples_per_subframe, + UE->frame_parms.nb_antennas_rx); + } +#endif + } + + } // UE->is_synchronized==0 + else { + if (start_rx_stream==0) { + start_rx_stream=1; + if (UE->mode != loop_through_memory) { + if (UE->no_timing_correction==0) { + LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); + AssertFatal(UE->rx_offset == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void**)UE->common_vars.rxdata, + UE->rx_offset, + UE->frame_parms.nb_antennas_rx),""); + } + UE->rx_offset=0; + UE->time_sync_cell=0; + //UE->proc.proc_rxtx[0].frame_rx++; + //UE->proc.proc_rxtx[1].frame_rx++; + for (th_id=0; th_id < RX_NB_TH; th_id++) { + UE->proc.proc_rxtx[th_id].frame_rx++; + } + + // read in first symbol + AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + (void**)UE->common_vars.rxdata, + UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, + UE->frame_parms.nb_antennas_rx),""); + slot_fep_pbch(UE,0, 0, 0, 0, 0); + } //UE->mode != loop_through_memory + else + rt_sleep_ns(1000*1000); + + } else { + tti_nr++; + tti_nr%=10*UE->frame_parms.ttis_per_subframe; + UE_nr_rxtx_proc_t *proc = &UE->proc.proc_rxtx[thread_idx]; + // update thread index for received subframe + UE->current_thread_id[tti_nr] = thread_idx; + + LOG_D(PHY,"Process TTI %d thread Idx %d \n", tti_nr, UE->current_thread_id[tti_nr]); + + thread_idx++; + if(thread_idx>=RX_NB_TH) + thread_idx = 0; + + + if (UE->mode != loop_through_memory) { + for (i=0; i<UE->frame_parms.nb_antennas_rx; i++) + rxp[i] = (void*)&UE->common_vars.rxdata[i][UE->frame_parms.ofdm_symbol_size+ + UE->frame_parms.nb_prefix_samples0+ + tti_nr*UE->frame_parms.samples_per_tti]; + for (i=0; i<UE->frame_parms.nb_antennas_tx; i++) + txp[i] = (void*)&UE->common_vars.txdata[i][((tti_nr+2)%10*UE->frame_parms.ttis_per_subframe)*UE->frame_parms.samples_per_tti]; + + int readBlockSize, writeBlockSize; + if (tti_nr<(10*UE->frame_parms.ttis_per_subframe-1)) { + readBlockSize=UE->frame_parms.samples_per_tti; + writeBlockSize=UE->frame_parms.samples_per_tti; + } else { + // set TO compensation to zero + UE->rx_offset_diff = 0; + // compute TO compensation that should be applied for this frame + if ( UE->rx_offset < 5*UE->frame_parms.samples_per_subframe && + UE->rx_offset > 0 ) + UE->rx_offset_diff = -1 ; + if ( UE->rx_offset > 5*UE->frame_parms.samples_per_subframe && + UE->rx_offset < 10*UE->frame_parms.samples_per_tti ) + UE->rx_offset_diff = 1; + + LOG_D(PHY,"AbsSubframe %d.%d TTI SET rx_off_diff to %d rx_offset %d \n",proc->frame_rx,tti_nr,UE->rx_offset_diff,UE->rx_offset); + readBlockSize=UE->frame_parms.samples_per_tti - + UE->frame_parms.ofdm_symbol_size - + UE->frame_parms.nb_prefix_samples0 - + UE->rx_offset_diff; + writeBlockSize=UE->frame_parms.samples_per_tti - + UE->rx_offset_diff; + } + + AssertFatal(readBlockSize == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp, + rxp, + readBlockSize, + UE->frame_parms.nb_antennas_rx),""); + AssertFatal( writeBlockSize == + UE->rfdevice.trx_write_func(&UE->rfdevice, + timestamp+ + (2*UE->frame_parms.samples_per_tti) - + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - + openair0_cfg[0].tx_sample_advance, + txp, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + 1),""); + if( tti_nr==(10*UE->frame_parms.ttis_per_subframe-1)) { + // read in first symbol of next frame and adjust for timing drift + int first_symbols=writeBlockSize-readBlockSize; + if ( first_symbols > 0 ) + AssertFatal(first_symbols == + UE->rfdevice.trx_read_func(&UE->rfdevice, + ×tamp1, + (void**)UE->common_vars.rxdata, + first_symbols, + UE->frame_parms.nb_antennas_rx),""); + if ( first_symbols <0 ) + LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols); + } + pickTime(gotIQs); + // operate on thread sf mod 2 + AssertFatal(pthread_mutex_lock(&proc->mutex_rxtx) ==0,""); + if(tti_nr == 0) { + //UE->proc.proc_rxtx[0].frame_rx++; + //UE->proc.proc_rxtx[1].frame_rx++; + for (th_id=0; th_id < RX_NB_TH; th_id++) { + UE->proc.proc_rxtx[th_id].frame_rx++; + } +#ifdef SAIF_ENABLED + if (!(proc->frame_rx%4000)) + { + printf("frame_rx=%d rx_thread_busy=%ld - rate %8.3f\n", + proc->frame_rx, g_ue_rx_thread_busy, + (float)g_ue_rx_thread_busy/(proc->frame_rx*10+1)*100.0); + fflush(stdout); + } +#endif + } + //UE->proc.proc_rxtx[0].gotIQs=readTime(gotIQs); + //UE->proc.proc_rxtx[1].gotIQs=readTime(gotIQs); + for (th_id=0; th_id < RX_NB_TH; th_id++) { + UE->proc.proc_rxtx[th_id].gotIQs=readTime(gotIQs); + } + proc->nr_tti_rx=tti_nr; + proc->nr_tti_tx=(tti_nr+4)%(10*UE->frame_parms.ttis_per_subframe); + proc->subframe_rx=tti_nr>>((uint8_t)(log2 (UE->frame_parms.ttis_per_subframe))); + proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0); + proc->subframe_tx=(proc->nr_tti_tx)>>((uint8_t)(log2 (UE->frame_parms.ttis_per_subframe))); + proc->timestamp_tx = timestamp+ + (4*UE->frame_parms.samples_per_tti)- + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; + + proc->instance_cnt_rxtx++; + LOG_D( PHY, "[SCHED][UE %d] UE RX instance_cnt_rxtx %d subframe %d !!\n", UE->Mod_id, proc->instance_cnt_rxtx,proc->subframe_rx); + if (proc->instance_cnt_rxtx == 0) { + if (pthread_cond_signal(&proc->cond_rxtx) != 0) { + LOG_E( PHY, "[SCHED][UE %d] ERROR pthread_cond_signal for UE RX thread\n", UE->Mod_id); + exit_fun("nothing to add"); + } + } else { +#ifdef SAIF_ENABLED + g_ue_rx_thread_busy++; +#endif + LOG_E( PHY, "[SCHED][UE %d] !! UE RX thread busy (IC %d)!!\n", UE->Mod_id, proc->instance_cnt_rxtx); + if (proc->instance_cnt_rxtx > 4) + { + char exit_fun_string[256]; + sprintf(exit_fun_string,"[SCHED][UE %d] !!! UE instance_cnt_rxtx > 2 (IC %d) (Proc %d)!!", + UE->Mod_id, proc->instance_cnt_rxtx, + UE->current_thread_id[tti_nr]); + printf("%s\n",exit_fun_string); + fflush(stdout); + sleep(1); + exit_fun(exit_fun_string); + } + } + + AssertFatal (pthread_cond_signal(&proc->cond_rxtx) ==0 ,""); + AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,""); +// initRefTimes(t1); +// initStaticTime(lastTime); +// updateTimes(lastTime, &t1, 20000, "Delay between two IQ acquisitions (case 1)"); +// pickStaticTime(lastTime); + + } else { + printf("Processing subframe %d",proc->subframe_rx); + getchar(); + } + } // start_rx_stream==1 + } // UE->is_synchronized==1 + + } // while !oai_exit + return NULL; +} + +/*! + * \brief Initialize the UE theads. + * Creates the UE threads: + * - UE_thread_rxtx0 + * - UE_thread_rxtx1 + * - UE_thread_synch + * - UE_thread_fep_slot0 + * - UE_thread_fep_slot1 + * - UE_thread_dlsch_proc_slot0 + * - UE_thread_dlsch_proc_slot1 + * and the locking between them. + */ +void init_UE_threads(PHY_VARS_NR_UE *UE) { + struct nr_rxtx_thread_data *rtd; + + pthread_attr_init (&UE->proc.attr_ue); + pthread_attr_setstacksize(&UE->proc.attr_ue,8192);//5*PTHREAD_STACK_MIN); + + pthread_mutex_init(&UE->proc.mutex_synch,NULL); + pthread_cond_init(&UE->proc.cond_synch,NULL); + + // the threads are not yet active, therefore access is allowed without locking + int nb_threads=RX_NB_TH; + for (int i=0; i<nb_threads; i++) { + rtd = calloc(1, sizeof(struct nr_rxtx_thread_data)); + if (rtd == NULL) abort(); + rtd->UE = UE; + rtd->proc = &UE->proc.proc_rxtx[i]; + + pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_rxtx,NULL); + pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL); + UE->proc.proc_rxtx[i].sub_frame_start=i; + UE->proc.proc_rxtx[i].sub_frame_step=nb_threads; + printf("Init_UE_threads rtd %d proc %d nb_threads %d i %d\n",rtd->proc->sub_frame_start, UE->proc.proc_rxtx[i].sub_frame_start,nb_threads, i); + pthread_create(&UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_thread_rxn_txnp4, rtd); + +#ifdef UE_DLSCH_PARALLELISATION + pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_dlsch_td,NULL); + pthread_cond_init(&UE->proc.proc_rxtx[i].cond_dlsch_td,NULL); + pthread_create(&UE->proc.proc_rxtx[i].pthread_dlsch_td,NULL,dlsch_decoding_2thread0, rtd); + //thread 2 + pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_dlsch_td1,NULL); + pthread_cond_init(&UE->proc.proc_rxtx[i].cond_dlsch_td1,NULL); + pthread_create(&UE->proc.proc_rxtx[i].pthread_dlsch_td1,NULL,dlsch_decoding_2thread1, rtd); +#endif + +#ifdef UE_SLOT_PARALLELISATION + //pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_slot0_dl_processing,NULL); + //pthread_cond_init(&UE->proc.proc_rxtx[i].cond_slot0_dl_processing,NULL); + //pthread_create(&UE->proc.proc_rxtx[i].pthread_slot0_dl_processing,NULL,UE_thread_slot0_dl_processing, rtd); + + pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_slot1_dl_processing,NULL); + pthread_cond_init(&UE->proc.proc_rxtx[i].cond_slot1_dl_processing,NULL); + pthread_create(&UE->proc.proc_rxtx[i].pthread_slot1_dl_processing,NULL,UE_thread_slot1_dl_processing, rtd); +#endif + + } + pthread_create(&UE->proc.pthread_synch,NULL,UE_thread_synch,(void*)UE); +} + + +#ifdef OPENAIR2 +void fill_ue_band_info(void) { + + UE_EUTRA_Capability_t *UE_EUTRA_Capability = UE_rrc_inst[0].UECap->UE_EUTRA_Capability; + int i,j; + + bands_to_scan.nbands = UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; + + for (i=0; i<bands_to_scan.nbands; i++) { + + for (j=0; j<sizeof (eutra_bands) / sizeof (eutra_bands[0]); j++) + if (eutra_bands[j].band == UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->bandEUTRA) { + memcpy(&bands_to_scan.band_info[i], + &eutra_bands[j], + sizeof(eutra_band_t)); + + printf("Band %d (%lu) : DL %u..%u Hz, UL %u..%u Hz, Duplex %s \n", + bands_to_scan.band_info[i].band, + UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->bandEUTRA, + bands_to_scan.band_info[i].dl_min, + bands_to_scan.band_info[i].dl_max, + bands_to_scan.band_info[i].ul_min, + bands_to_scan.band_info[i].ul_max, + (bands_to_scan.band_info[i].frame_type==FDD) ? "FDD" : "TDD"); + break; + } + } +} +#endif + +int setup_ue_buffers(PHY_VARS_NR_UE **phy_vars_ue, openair0_config_t *openair0_cfg) { + + int i, CC_id; + LTE_DL_FRAME_PARMS *frame_parms; + openair0_rf_map *rf_map; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + rf_map = &phy_vars_ue[CC_id]->rf_map; + + AssertFatal( phy_vars_ue[CC_id] !=0, ""); + frame_parms = &(phy_vars_ue[CC_id]->frame_parms); + + // replace RX signal buffers with mmaped HW versions + rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); + txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) ); + + for (i=0; i<frame_parms->nb_antennas_rx; i++) { + LOG_I(PHY, "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", + CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); + free( phy_vars_ue[CC_id]->common_vars.rxdata[i] ); + rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); + phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD + } + + for (i=0; i<frame_parms->nb_antennas_tx; i++) { + LOG_I(PHY, "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", + CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); + free( phy_vars_ue[CC_id]->common_vars.txdata[i] ); + txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); + phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i]; + } + + // rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x] + // txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x] + // be careful when releasing memory! + // because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes) + } + return 0; +} + diff --git a/targets/RT/USER/nr-uesoftmodem.c b/targets/RT/USER/nr-uesoftmodem.c new file mode 100644 index 0000000000000000000000000000000000000000..eebc2b2ca2397567c4d577c8195eeae71df51201 --- /dev/null +++ b/targets/RT/USER/nr-uesoftmodem.c @@ -0,0 +1,1741 @@ +/* + * 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 + */ + + +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <sched.h> + +#include "T.h" +#include "rt_wrapper.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "PHY/types.h" +#include "PHY/defs_nr_UE.h" +#include "common/ran_context.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/phy_vars_nr_ue.h" +#include "PHY/LTE_TRANSPORT/transport_vars.h" +#include "SCHED/sched_common_vars.h" +#include "PHY/MODULATION/modulation_vars.h" +//#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_vars.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_vars.h" +#include "PHY_INTERFACE/phy_interface_vars.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_vars.h" +#endif + +#if defined(ENABLE_ITTI) +#include "intertask_interface_init.h" +#include "create_tasks.h" +#endif + +#include "PHY/INIT/phy_init.h" +#include "system.h" +#include "stats.h" +#ifdef XFORMS +#include "PHY/TOOLS/lte_phy_scope.h" +//#include "stats.h" +// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) +// at eNB 0, an UL scope for every UE +FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; +FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; +char title[255]; +unsigned char scope_enb_num_ue = 2; +static pthread_t forms_thread; //xforms +#endif //XFORMS +#include "nr-uesoftmodem.h" + +RAN_CONTEXT_t RC; + +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. + +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + +#if defined(ENABLE_ITTI) +volatile int start_eNB = 0; +volatile int start_UE = 0; +#endif +volatile int oai_exit = 0; + +static clock_source_t clock_source = internal; +static int wait_for_sync = 0; + +static char UE_flag=0; +unsigned int mmapped_dma=0; +int single_thread_flag=1; + +static char threequarter_fs=0; + +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + + +static char *conf_config_file_name = NULL; +#if defined(ENABLE_ITTI) +static char *itti_dump_file = NULL; +#endif + +int UE_scan = 1; +int UE_scan_carrier = 0; +runmode_t mode = normal_txrx; + +FILE *input_fd=NULL; + + +#if MAX_NUM_CCs == 1 +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; +#else +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; +#endif + +double rx_gain_off = 0.0; + +double sample_rate=30.72e6; +double bw = 10.0e6; + +static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; + +char rf_config_file[1024]; + +int chain_offset=0; +int phy_test = 0; +uint8_t usim_test = 0; + +uint8_t dci_Format = 0; +uint8_t agregation_Level =0xFF; + +uint8_t nb_antenna_tx = 1; +uint8_t nb_antenna_rx = 1; + +char ref[128] = "internal"; +char channels[128] = "0"; + +int rx_input_level_dBm; +static int online_log_messages=0; +#ifdef XFORMS +extern int otg_enabled; +static char do_forms=0; +#else +int otg_enabled; +#endif +//int number_of_cards = 1; + +static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; +static nfapi_config_request_t *config[MAX_NUM_CCs]; +int16_t node_synch_ref[MAX_NUM_CCs]; + +uint32_t target_dl_mcs = 28; //maximum allowed mcs +uint32_t target_ul_mcs = 20; +uint32_t timing_advance = 0; +uint8_t exit_missed_slots=1; +uint64_t num_missed_slots=0; // counter for the number of missed slots + +int transmission_mode=1; +int numerology = 0; + +int16_t glog_level = LOG_INFO; +int16_t glog_verbosity = LOG_MED; +int16_t hw_log_level = LOG_INFO; +int16_t hw_log_verbosity = LOG_MED; +int16_t phy_log_level = LOG_INFO; +int16_t phy_log_verbosity = LOG_MED; +int16_t mac_log_level = LOG_INFO; +int16_t mac_log_verbosity = LOG_MED; +int16_t rlc_log_level = LOG_INFO; +int16_t rlc_log_verbosity = LOG_MED; +int16_t pdcp_log_level = LOG_INFO; +int16_t pdcp_log_verbosity = LOG_MED; +int16_t rrc_log_level = LOG_INFO; +int16_t rrc_log_verbosity = LOG_MED; +int16_t opt_log_level = LOG_INFO; +int16_t opt_log_verbosity = LOG_MED; + +# if defined(ENABLE_USE_MME) +int16_t gtpu_log_level = LOG_DEBUG; +int16_t gtpu_log_verbosity = LOG_MED; +int16_t udp_log_level = LOG_DEBUG; +int16_t udp_log_verbosity = LOG_MED; +#endif +#if defined (ENABLE_SECURITY) +int16_t osa_log_level = LOG_INFO; +int16_t osa_log_verbosity = LOG_MED; +#endif + +char *rrh_UE_ip = "127.0.0.1"; +int rrh_UE_port = 51000; + +/* flag set by eNB conf file to specify if the radio head is local or remote (default option is local) */ +//uint8_t local_remote_radio = BBU_LOCAL_RADIO_HEAD; +/* struct for ethernet specific parameters given in eNB conf file */ +//eth_params_t *eth_params; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +double cpuf; + +char uecap_xer[1024],uecap_xer_in=0; + +int oaisim_flag=0; +int emulate_rf = 0; + +threads_t threads= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; + +/* forward declarations */ +void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + + +/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed + * this is very hackish - find a proper solution + */ +uint8_t abstraction_flag=0; + +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } +#if 1 + if (changed) print_difftimes(); +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + +#if !defined(ENABLE_ITTI) +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + printf("trying to exit gracefully...\n"); + oai_exit = 1; + } +} +#endif +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KBLU "\x1B[34m" +#define RESET "\033[0m" + +void help (void) { + printf (KGRN "Usage:\n"); + printf(" sudo -E lte-softmodem [options]\n"); + printf(" sudo -E ./lte-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.openEPC.conf -S -V -m 26 -t 16 -x 1 --ulsch-max-errors 100 -W\n\n"); + printf("Options:\n"); + printf(" --rf-config-file Configuration file for front-end (e.g. LMS7002M)\n"); + printf(" --ulsch-max-errors set the max ULSCH erros\n"); + printf(" --calib-ue-rx set UE RX calibration\n"); + printf(" --calib-ue-rx-med \n"); + printf(" --calib-ue-rxbyp\n"); + printf(" --debug-ue-prach run normal prach power ramping, but don't continue random-access\n"); + printf(" --calib-prach-tx run normal prach with maximum power, but don't continue random-access\n"); + printf(" --no-L2-connect bypass L2 and upper layers\n"); + printf(" --ue-rxgain set UE RX gain\n"); + printf(" --ue-rxgain-off external UE amplifier offset\n"); + printf(" --ue-txgain set UE TX gain\n"); + printf(" --ue-nb-ant-rx set UE number of rx antennas\n"); + printf(" --ue-scan-carrier set UE to scan around carrier\n"); + printf(" --dlsch-demod-shift dynamic shift for LLR compuation for TM3/4 (default 0)\n"); + printf(" --loop-memory get softmodem (UE) to loop through memory instead of acquiring from HW\n"); + printf(" --mmapped-dma sets flag for improved EXMIMO UE performance\n"); + printf(" --external-clock tells hardware to use an external clock reference\n"); + printf(" --usim-test use XOR autentication algo in case of test usim mode\n"); + printf(" --single-thread-disable. Disables single-thread mode in lte-softmodem\n"); + printf(" --AgregationLevel Choose the agregation level used by tghe eNB for the OAI use 1, it will save some time of processing the pdcch\n"); + printf(" --DCIformat choose the DCI format, be careful when using this option(for the moment only valid for SISO DCI format 1)\n"); + printf(" -A Set timing_advance\n"); + printf(" -C Set the downlink frequency for all component carriers\n"); + printf(" -d Enable soft scope and L1 and L2 stats (Xforms)\n"); + printf(" -F Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n"); + printf(" -g Set the global log level, valide options: (9:trace, 8/7:debug, 6:info, 4:warn, 3:error)\n"); + printf(" -G Set the global log verbosity \n"); + printf(" -h provides this help message!\n"); + printf(" -K Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n"); + printf(" -m Set the maximum downlink MCS\n"); + printf(" -O eNB configuration file (located in targets/PROJECTS/GENERIC-LTE-EPC/CONF\n"); + printf(" -q Enable processing timing measurement of lte softmodem on per subframe basis \n"); + printf(" -r Set the PRB, valid values: 6, 25, 50, 100 \n"); + printf(" -S Skip the missed slots/subframes \n"); + printf(" -t Set the maximum uplink MCS\n"); + printf(" -T Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n"); + printf(" -U Set the lte softmodem as a UE\n"); + printf(" -W Enable L2 wireshark messages on localhost \n"); + printf(" -V Enable VCD (generated file will be located atopenair_dump_eNB.vcd, read it with target/RT/USER/eNB.gtkw\n"); + printf(" -x Set the transmission mode, valid options: 1 \n"); + printf(" -E Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n"); +#if T_TRACER + printf(" --T_port [port] use given port\n"); + printf(" --T_nowait don't wait for tracer, start immediately\n"); + printf(" --T_dont_fork to ease debugging with gdb\n"); +#endif + printf(RESET); + fflush(stdout); +} + +void exit_fun(const char* s) { + int CC_id; + + if (s != NULL) { + printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); + } + + oai_exit = 1; + + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + if (PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func) + PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); + } + +#if defined(ENABLE_ITTI) + sleep(1); //allow lte-softmodem threads to exit first + itti_terminate_tasks (TASK_UNKNOWN); +#endif + +} + + +#ifdef XFORMS + + +void reset_stats(FL_OBJECT *button, long arg) { + int i,j,k; + /*PHY_VARS_eNB *phy_vars_eNB = PHY_vars_eNB_g[0][0]; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + for (k=0; k<8; k++) { //harq_processes + for (j=0; j<phy_vars_eNB->dlsch[i][0]->Mlimit; j++) { + phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0; + } + + phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0; + + for (j=0; j<phy_vars_eNB->ulsch[i]->Mlimit; j++) { + phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_round_errors[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_round_fer[k][j]=0; + } + } + + phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0; + }*/ +} + +static void *scope_thread(void *arg) { + char stats_buffer[16384]; +# ifdef ENABLE_XFORMS_WRITE_STATS + FILE *UE_stats, *eNB_stats; +# endif + int len = 0; + struct sched_param sched_param; + int UE_id, CC_id; + int ue_cnt=0; + + sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; + sched_setscheduler(0, SCHED_FIFO,&sched_param); + + printf("Scope thread has priority %d\n",sched_param.sched_priority); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (UE_flag==1) + UE_stats = fopen("UE_stats.txt", "w"); + else + eNB_stats = fopen("eNB_stats.txt", "w"); + +#endif + + while (!oai_exit) { + if (UE_flag==1) { + //len = dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm); + //fl_set_object_label(form_stats->stats_text, stats_buffer); + fl_clear_browser(form_stats->stats_text); + fl_add_browser_line(form_stats->stats_text, stats_buffer); + + /*phy_scope_UE(form_ue[0], + PHY_vars_UE_g[0][0], + 0, + 0,7);*/ + + } + + //printf("doing forms\n"); + //usleep(100000); // 100 ms + sleep(1); + } + + // printf("%s",stats_buffer); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (UE_flag==1) { + if (UE_stats) { + rewind (UE_stats); + fwrite (stats_buffer, 1, len, UE_stats); + fclose (UE_stats); + } + } + +# endif + + pthread_exit((void*)arg); +} +#endif + + + + +#if defined(ENABLE_ITTI) +void *l2l1_task(void *arg) { + MessageDef *message_p = NULL; + int result; + + itti_set_task_real_time(TASK_L2L1); + itti_mark_task_ready(TASK_L2L1); + + if (UE_flag == 0) { + /* Wait for the initialize message */ + printf("Wait for the ITTI initialize message\n"); + do { + if (message_p != NULL) { + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case INITIALIZE_MESSAGE: + /* Start eNB thread */ + LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p)); + start_eNB = 1; + break; + + case TERMINATE_MESSAGE: + printf("received terminate message\n"); + oai_exit=1; + itti_exit_task (); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + do { + // Wait for a message + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case TERMINATE_MESSAGE: + oai_exit=1; + itti_exit_task (); + break; + + case ACTIVATE_MESSAGE: + start_UE = 1; + break; + + case DEACTIVATE_MESSAGE: + start_UE = 0; + break; + + case MESSAGE_TEST: + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while(!oai_exit); + + return NULL; +} +#endif + + + + +static void get_options (int argc, char **argv) { + int c; + // char line[1000]; + // int l; + int k,i;//,j,k; +#if defined(OAI_USRP) || defined(CPRIGW) || defined(OAI_ADRV9371_ZC706) + int clock_src; +#endif + int CC_id; + + enum long_option_e { + LONG_OPTION_START = 0x100, /* Start after regular single char options */ + LONG_OPTION_RF_CONFIG_FILE, + LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS, + LONG_OPTION_CALIB_UE_RX, + LONG_OPTION_CALIB_UE_RX_MED, + LONG_OPTION_CALIB_UE_RX_BYP, + LONG_OPTION_DEBUG_UE_PRACH, + LONG_OPTION_NO_L2_CONNECT, + LONG_OPTION_CALIB_PRACH_TX, + LONG_OPTION_RXGAIN, + LONG_OPTION_RXGAINOFF, + LONG_OPTION_TXGAIN, + LONG_OPTION_NBRXANT, + LONG_OPTION_NBTXANT, + LONG_OPTION_SCANCARRIER, + LONG_OPTION_MAXPOWER, + LONG_OPTION_DUMP_FRAME, + LONG_OPTION_LOOPMEMORY, + LONG_OPTION_PHYTEST, + LONG_OPTION_USIMTEST, + LONG_OPTION_MMAPPED_DMA, + LONG_OPTION_EXTERNAL_CLOCK, + LONG_OPTION_WAIT_FOR_SYNC, + LONG_OPTION_SINGLE_THREAD_DISABLE, + LONG_OPTION_THREADIQ, + LONG_OPTION_THREADONESUBFRAME, + LONG_OPTION_THREADTWOSUBFRAME, + LONG_OPTION_THREADTHREESUBFRAME, + LONG_OPTION_THREADSLOT1PROCONE, + LONG_OPTION_THREADSLOT1PROCTWO, + LONG_OPTION_THREADSLOT1PROCTHREE, + LONG_OPTION_THREADDLSCHTDONE, + LONG_OPTION_THREADDLSCHTDTWO, + LONG_OPTION_THREADDLSCHTDTHREE, + LONG_OPTION_THREADDLSCHTD1ONE, + LONG_OPTION_THREADDLSCHTD1TWO, + LONG_OPTION_THREADDLSCHTD1THREE, + LONG_OPTION_DCIFORMAT, + LONG_OPTION_AGREGATIONLEVEL, + LONG_OPTION_DEMOD_SHIFT, +#if T_TRACER + LONG_OPTION_T_PORT, + LONG_OPTION_T_NOWAIT, + LONG_OPTION_T_DONT_FORK, +#endif + + }; + + static const struct option long_options[] = { + {"rf-config-file",required_argument, NULL, LONG_OPTION_RF_CONFIG_FILE}, + {"ulsch-max-errors",required_argument, NULL, LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS}, + {"calib-ue-rx", required_argument, NULL, LONG_OPTION_CALIB_UE_RX}, + {"calib-ue-rx-med", required_argument, NULL, LONG_OPTION_CALIB_UE_RX_MED}, + {"calib-ue-rx-byp", required_argument, NULL, LONG_OPTION_CALIB_UE_RX_BYP}, + {"debug-ue-prach", no_argument, NULL, LONG_OPTION_DEBUG_UE_PRACH}, + {"no-L2-connect", no_argument, NULL, LONG_OPTION_NO_L2_CONNECT}, + {"calib-prach-tx", no_argument, NULL, LONG_OPTION_CALIB_PRACH_TX}, + {"ue-rxgain", required_argument, NULL, LONG_OPTION_RXGAIN}, + {"ue-rxgain-off", required_argument, NULL, LONG_OPTION_RXGAINOFF}, + {"ue-txgain", required_argument, NULL, LONG_OPTION_TXGAIN}, + {"ue-nb-ant-rx", required_argument, NULL, LONG_OPTION_NBRXANT}, + {"ue-nb-ant-tx", required_argument, NULL, LONG_OPTION_NBTXANT}, + {"ue-scan-carrier", no_argument, NULL, LONG_OPTION_SCANCARRIER}, + {"ue-max-power", required_argument, NULL, LONG_OPTION_MAXPOWER}, + {"ue-dump-frame", no_argument, NULL, LONG_OPTION_DUMP_FRAME}, + {"loop-memory", required_argument, NULL, LONG_OPTION_LOOPMEMORY}, + {"phy-test", no_argument, NULL, LONG_OPTION_PHYTEST}, + {"usim-test", no_argument, NULL, LONG_OPTION_USIMTEST}, + {"mmapped-dma", no_argument, NULL, LONG_OPTION_MMAPPED_DMA}, + {"external-clock", no_argument, NULL, LONG_OPTION_EXTERNAL_CLOCK}, + {"wait-for-sync", no_argument, NULL, LONG_OPTION_WAIT_FOR_SYNC}, + {"single-thread-disable", no_argument, NULL, LONG_OPTION_SINGLE_THREAD_DISABLE}, + {"threadIQ", required_argument, NULL, LONG_OPTION_THREADIQ}, + {"threadOneSubframe", required_argument, NULL, LONG_OPTION_THREADONESUBFRAME}, + {"threadTwoSubframe", required_argument, NULL, LONG_OPTION_THREADTWOSUBFRAME}, + {"threadThreeSubframe", required_argument, NULL, LONG_OPTION_THREADTHREESUBFRAME}, + {"threadSlot1ProcOne", required_argument, NULL, LONG_OPTION_THREADSLOT1PROCONE}, + {"threadSlot1ProcTwo", required_argument, NULL, LONG_OPTION_THREADSLOT1PROCTWO}, + {"threadSlot1ProcThree", required_argument, NULL, LONG_OPTION_THREADSLOT1PROCTHREE}, + {"threadDlschTdOne", required_argument, NULL, LONG_OPTION_THREADDLSCHTDONE}, + {"threadDlschTdTwo", required_argument, NULL, LONG_OPTION_THREADDLSCHTDTWO}, + {"threadDlschTdThree", required_argument, NULL, LONG_OPTION_THREADDLSCHTDTHREE}, + {"threadDlschTd1One", required_argument, NULL, LONG_OPTION_THREADDLSCHTD1ONE}, + {"threadDlschTd1Two", required_argument, NULL, LONG_OPTION_THREADDLSCHTD1TWO}, + {"threadDlschTd1Three", required_argument, NULL, LONG_OPTION_THREADDLSCHTD1THREE}, + {"DCIformat", required_argument, NULL, LONG_OPTION_DCIFORMAT}, + {"AgregationLevel", required_argument, NULL, LONG_OPTION_AGREGATIONLEVEL}, + {"dlsch-demod-shift", required_argument, NULL, LONG_OPTION_DEMOD_SHIFT}, +#if T_TRACER + {"T_port", required_argument, 0, LONG_OPTION_T_PORT}, + {"T_nowait", no_argument, 0, LONG_OPTION_T_NOWAIT}, + {"T_dont_fork", no_argument, 0, LONG_OPTION_T_DONT_FORK}, +#endif + {NULL, 0, NULL, 0} + }; + + while ((c = getopt_long (argc, argv, "A:a:C:dEK:g:F:G:hqO:m:n:SUVRM:r:P:Ws:t:Tx:",long_options,NULL)) != -1) { + switch (c) { + case LONG_OPTION_RF_CONFIG_FILE: + if ((strcmp("null", optarg) == 0) || (strcmp("NULL", optarg) == 0)) { + printf("no configuration filename is provided\n"); + } + else if (strlen(optarg)<=1024){ + strcpy(rf_config_file,optarg); + }else { + printf("Configuration filename is too long\n"); + exit(-1); + } + break; + case LONG_OPTION_MAXPOWER: + tx_max_power[0]=atoi(optarg); + for (CC_id=1;CC_id<MAX_NUM_CCs;CC_id++) + tx_max_power[CC_id]=tx_max_power[0]; + break; + case LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS: + ULSCH_max_consecutive_errors = atoi(optarg); + printf("Set ULSCH_max_consecutive_errors = %d\n",ULSCH_max_consecutive_errors); + break; + + case LONG_OPTION_CALIB_UE_RX: + mode = rx_calib_ue; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA max), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_CALIB_UE_RX_MED: + mode = rx_calib_ue_med; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA med), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_CALIB_UE_RX_BYP: + mode = rx_calib_ue_byp; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA byp), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_DEBUG_UE_PRACH: + mode = debug_prach; + break; + + case LONG_OPTION_NO_L2_CONNECT: + mode = no_L2_connect; + break; + + case LONG_OPTION_CALIB_PRACH_TX: + mode = calib_prach_tx; + printf("Setting mode to calib_prach_tx (%d)\n",mode); + break; + + case LONG_OPTION_RXGAIN: + for (i=0; i<4; i++) + rx_gain[0][i] = atof(optarg); + + break; + + case LONG_OPTION_RXGAINOFF: + rx_gain_off = atof(optarg); + break; + + case LONG_OPTION_TXGAIN: + for (i=0; i<4; i++) + tx_gain[0][i] = atof(optarg); + + break; + case LONG_OPTION_NBRXANT: + nb_antenna_rx = atof(optarg); + break; + case LONG_OPTION_NBTXANT: + nb_antenna_tx = atof(optarg); + break; + case LONG_OPTION_SCANCARRIER: + UE_scan_carrier=1; + + break; + + case LONG_OPTION_LOOPMEMORY: + mode=loop_through_memory; + input_fd = fopen(optarg,"r"); + AssertFatal(input_fd != NULL,"Please provide an input file\n"); + break; + + case LONG_OPTION_DUMP_FRAME: + mode = rx_dump_frame; + break; + + case LONG_OPTION_PHYTEST: + phy_test = 1; + break; + + case LONG_OPTION_USIMTEST: + usim_test = 1; + break; + case LONG_OPTION_MMAPPED_DMA: + mmapped_dma = 1; + break; + + case LONG_OPTION_SINGLE_THREAD_DISABLE: + single_thread_flag = 0; + break; + + case LONG_OPTION_EXTERNAL_CLOCK: + clock_source = external; + break; + + case LONG_OPTION_WAIT_FOR_SYNC: + wait_for_sync = 1; + break; + + case LONG_OPTION_THREADIQ: + threads.iq=atoi(optarg); + break; + case LONG_OPTION_THREADONESUBFRAME: + threads.one=atoi(optarg); + break; + case LONG_OPTION_THREADTWOSUBFRAME: + threads.two=atoi(optarg); + break; + case LONG_OPTION_THREADTHREESUBFRAME: + threads.three=atoi(optarg); + break; + case LONG_OPTION_THREADSLOT1PROCONE: + threads.slot1_proc_one=atoi(optarg); + break; + case LONG_OPTION_THREADSLOT1PROCTWO: + threads.slot1_proc_two=atoi(optarg); + break; + case LONG_OPTION_THREADSLOT1PROCTHREE: + threads.slot1_proc_three=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTDONE: + threads.dlsch_td_one=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTDTWO: + threads.dlsch_td_two=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTDTHREE: + threads.dlsch_td_three=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTD1ONE: + threads.dlsch_td1_one=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTD1TWO: + threads.dlsch_td1_two=atoi(optarg); + break; + case LONG_OPTION_THREADDLSCHTD1THREE: + threads.dlsch_td1_three=atoi(optarg); + break; + case LONG_OPTION_DCIFORMAT: + dci_Format = atoi(optarg); + break; + case LONG_OPTION_AGREGATIONLEVEL: + agregation_Level = atoi(optarg); + break; + case LONG_OPTION_DEMOD_SHIFT: { + extern int16_t dlsch_demod_shift; + dlsch_demod_shift = atof(optarg); + break; + } +#if T_TRACER + case LONG_OPTION_T_PORT: { + extern int T_port; + if (optarg == NULL) abort(); /* should not happen */ + T_port = atoi(optarg); + break; + } + + case LONG_OPTION_T_NOWAIT: { + extern int T_wait; + T_wait = 0; + break; + } + + case LONG_OPTION_T_DONT_FORK: { + extern int T_dont_fork; + T_dont_fork = 1; + break; + } +#endif + + case 'A': + timing_advance = atoi (optarg); + break; + + case 'C': + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + downlink_frequency[CC_id][0] = atof(optarg); // Use float to avoid issue with frequency over 2^31. + downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); + } + + UE_scan=0; + + break; + + case 'a': + chain_offset = atoi(optarg); + break; + + case 'd': +#ifdef XFORMS + do_forms=1; + printf("Running with XFORMS!\n"); +#endif + break; + + case 'E': + threequarter_fs=1; + break; + + case 'K': +#if defined(ENABLE_ITTI) + itti_dump_file = strdup(optarg); +#else + printf("-K option is disabled when ENABLE_ITTI is not defined\n"); +#endif + break; + + case 'O': + conf_config_file_name = optarg; + break; + + case 'U': + UE_flag = 1; + break; + + case 'm': + target_dl_mcs = atoi (optarg); + break; + + case 't': + target_ul_mcs = atoi (optarg); + break; + + case 'W': + opt_enabled=1; + opt_type = OPT_WIRESHARK; + strncpy(in_ip, "127.0.0.1", sizeof(in_ip)); + in_ip[sizeof(in_ip) - 1] = 0; // terminate string + printf("Enabling OPT for wireshark for local interface"); + /* + if (optarg == NULL){ + in_ip[0] =NULL; + printf("Enabling OPT for wireshark for local interface"); + } else { + strncpy(in_ip, optarg, sizeof(in_ip)); + in_ip[sizeof(in_ip) - 1] = 0; // terminate string + printf("Enabling OPT for wireshark with %s \n",in_ip); + } + */ + break; + + case 'P': + opt_type = OPT_PCAP; + opt_enabled=1; + + if (optarg == NULL) { + strncpy(in_path, "/tmp/oai_opt.pcap", sizeof(in_path)); + in_path[sizeof(in_path) - 1] = 0; // terminate string + printf("Enabling OPT for PCAP with the following path /tmp/oai_opt.pcap"); + } else { + strncpy(in_path, optarg, sizeof(in_path)); + in_path[sizeof(in_path) - 1] = 0; // terminate string + printf("Enabling OPT for PCAP with the following file %s \n",in_path); + } + + break; + + case 'V': + ouput_vcd = 1; + break; + + case 'q': + opp_enabled = 1; + break; + + case 'R' : + online_log_messages =1; + break; + + /*case 'r': + UE_scan = 0; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + switch(atoi(optarg)) { + case 6: + frame_parms[CC_id]->N_RB_DL=6; + frame_parms[CC_id]->N_RB_UL=6; + break; + + case 25: + frame_parms[CC_id]->N_RB_DL=25; + frame_parms[CC_id]->N_RB_UL=25; + break; + + case 50: + frame_parms[CC_id]->N_RB_DL=50; + frame_parms[CC_id]->N_RB_UL=50; + break; + + case 100: + frame_parms[CC_id]->N_RB_DL=100; + frame_parms[CC_id]->N_RB_UL=100; + break; + + default: + printf("Unknown N_RB_DL %d, switching to 25\n",atoi(optarg)); + break; + } + } + + break;*/ + + case 's': +#if defined(OAI_USRP) || defined(CPRIGW) || defined(OAI_ADRV9371_ZC706) + + clock_src = atoi(optarg); + + if (clock_src == 0) { + // char ref[128] = "internal"; + //strncpy(uhd_ref, ref, strlen(ref)+1); + } else if (clock_src == 1) { + //char ref[128] = "external"; + //strncpy(uhd_ref, ref, strlen(ref)+1); + } + +#else + printf("Note: -s not defined for ExpressMIMO2\n"); +#endif + break; + + case 'S': + exit_missed_slots=0; + printf("Skip exit for missed slots\n"); + break; + + case 'g': + glog_level=atoi(optarg); // value between 1 - 9 + break; + + case 'F': + break; + + case 'G': + glog_verbosity=atoi(optarg);// value from 0, 0x5, 0x15, 0x35, 0x75 + break; + + case 'x': + printf("Transmission mode should be set in config file now\n"); + exit(-1); + /* + transmission_mode = atoi(optarg); + + if (transmission_mode > 7) { + printf("Transmission mode %d not supported for the moment\n",transmission_mode); + exit(-1); + } + */ + break; + + case 'T': + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) + frame_parms[CC_id]->frame_type = TDD; + break; + + case 'n': + numerology=atoi(optarg); + break; + + case 'h': + help (); + exit (-1); + + default: + help (); + exit (-1); + break; + } + } + + if (UE_flag == 0) + AssertFatal(conf_config_file_name != NULL,"Please provide a configuration file\n"); + + if (UE_flag == 1) { + if (conf_config_file_name != NULL) { + + // Here the configuration file is the XER encoded UE capabilities + // Read it in and store in asn1c data structures + strcpy(uecap_xer,conf_config_file_name); + uecap_xer_in=1; + } + } +} + +#if T_TRACER +int T_wait = 1; /* by default we wait for the tracer */ +int T_port = 2021; /* default port to listen to to wait for the tracer */ +int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ +#endif + +void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { + + int CC_id; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + frame_parms[CC_id] = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS)); + /* Set some default values that may be overwritten while reading options */ + frame_parms[CC_id] = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS)); + config[CC_id] = (nfapi_config_request_t*) malloc(sizeof(nfapi_config_request_t)); + config[CC_id]->subframe_config.numerology_index_mu.value =1; + config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD + config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL + config[CC_id]->rf_config.dl_channel_bandwidth.value = 106; + config[CC_id]->rf_config.ul_channel_bandwidth.value = 106; + config[CC_id]->rf_config.tx_antenna_ports.value = 1; + config[CC_id]->rf_config.rx_antenna_ports.value = 1; + config[CC_id]->sch_config.physical_cell_id.value = 0; + + /*frame_parms[CC_id]->frame_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 0; + //frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; + + frame_parms[CC_id]->nushift = 0;*/ + + ///frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; + //frame_parms[CC_id]->phich_config_common.phich_duration = normal; + // UL RS Config + /*frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 1;//n_DMRS1 set to 0 + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 1; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; + + frame_parms[CC_id]->pusch_config_common.n_SB = 1; + frame_parms[CC_id]->pusch_config_common.hoppingMode = 0; + frame_parms[CC_id]->pusch_config_common.pusch_HoppingOffset = 0; + frame_parms[CC_id]->pusch_config_common.enable64QAM = 0; + + frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0;*/ + + // NR: Init to legacy LTE 20Mhz params + frame_parms[CC_id]->numerology_index = 0; + frame_parms[CC_id]->ttis_per_subframe = 1; + frame_parms[CC_id]->slots_per_tti = 2; + + downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. + downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); + + } + +} +/*void init_openair0(void); +void init_openair0() { + + int card; + int i; + + for (card=0; card<MAX_CARDS; card++) { + + openair0_cfg[card].mmapped_dma=mmapped_dma; + openair0_cfg[card].configFilename = NULL; + + if(frame_parms[0]->N_RB_DL == 100) { + if (numerology==0) { + if (frame_parms[0]->threequarter_fs) { + openair0_cfg[card].sample_rate=23.04e6; + openair0_cfg[card].samples_per_frame = 230400; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } else { + openair0_cfg[card].sample_rate=30.72e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } + } else if (numerology==1) { + openair0_cfg[card].sample_rate=61.44e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 20e6; + openair0_cfg[card].rx_bw = 20e6; + } else if (numerology==2) { + openair0_cfg[card].sample_rate=122.88e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 40e6; + openair0_cfg[card].rx_bw = 40e6; + } else { + LOG_E(PHY,"Unsupported numerology!\n"); + exit(-1); + } + } else if(frame_parms[0]->N_RB_DL == 50) { + openair0_cfg[card].sample_rate=15.36e6; + openair0_cfg[card].samples_per_frame = 153600; + openair0_cfg[card].tx_bw = 5e6; + openair0_cfg[card].rx_bw = 5e6; + } else if (frame_parms[0]->N_RB_DL == 25) { + openair0_cfg[card].sample_rate=7.68e6; + openair0_cfg[card].samples_per_frame = 76800; + openair0_cfg[card].tx_bw = 2.5e6; + openair0_cfg[card].rx_bw = 2.5e6; + } else if (frame_parms[0]->N_RB_DL == 6) { + openair0_cfg[card].sample_rate=1.92e6; + openair0_cfg[card].samples_per_frame = 19200; + openair0_cfg[card].tx_bw = 1.5e6; + openair0_cfg[card].rx_bw = 1.5e6; + } + + if (frame_parms[0]->frame_type==TDD) + openair0_cfg[card].duplex_mode = duplex_mode_TDD; + else //FDD + openair0_cfg[card].duplex_mode = duplex_mode_FDD; + + printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx, + PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx); + openair0_cfg[card].Mod_id = 0; + + openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL; + + openair0_cfg[card].clock_source = clock_source; + + + openair0_cfg[card].tx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx); + openair0_cfg[card].rx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx); + + for (i=0; i<4; i++) { + + if (i<openair0_cfg[card].tx_num_channels) + openair0_cfg[card].tx_freq[i] = downlink_frequency[0][i]+uplink_frequency_offset[0][i]; + else + openair0_cfg[card].tx_freq[i]=0.0; + + if (i<openair0_cfg[card].rx_num_channels) + openair0_cfg[card].rx_freq[i] = downlink_frequency[0][i]; + else + openair0_cfg[card].rx_freq[i]=0.0; + + openair0_cfg[card].autocal[i] = 1; + openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; + openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off; + + + openair0_cfg[card].configFilename = rf_config_file; + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); + } + + + } +}*/ + +int main( int argc, char **argv ) { + int i,j,k,aa,re; +#if defined (XFORMS) + void *status; +#endif + + int CC_id; + uint8_t abstraction_flag=0; + uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; + +#if defined (XFORMS) + int ret; +#endif + + start_background_system(); + +#ifdef DEBUG_CONSOLE + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + PHY_VARS_NR_UE *UE[MAX_NUM_CCs]; + + mode = normal_txrx; + memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); + + memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); + + set_latency_target(); + + // set default parameters + //set_default_frame_parms(frame_parms); + + // initialize logging + logInit(); + + // get options and fill parameters from configuration file + get_options (argc, argv); //Command-line options, enb_properties + +#if T_TRACER + T_init(T_port, T_wait, T_dont_fork); +#endif + + // initialize the log (see log.h for details) + set_glog(glog_level, glog_verbosity); + + //randominit (0); + set_taus_seed (0); + + if (UE_flag==1) { + printf("configuring for UE\n"); + + set_comp_log(HW, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(PHY, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(MAC, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(RLC, LOG_INFO, LOG_HIGH | FLAG_THREAD, 1); + set_comp_log(PDCP, LOG_INFO, LOG_HIGH, 1); + set_comp_log(OTG, LOG_INFO, LOG_HIGH, 1); + set_comp_log(RRC, LOG_DEBUG, LOG_HIGH, 1); +#if defined(ENABLE_ITTI) + set_comp_log(EMU, LOG_INFO, LOG_MED, 1); +# if defined(ENABLE_USE_MME) + set_comp_log(NAS, LOG_INFO, LOG_HIGH, 1); +# endif +#endif + } + + if (ouput_vcd) { + if (UE_flag==1) + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd"); + else + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd"); + } + + //if (opp_enabled ==1) { + // reset_opp_meas(); + //} + cpuf=get_cpu_freq_GHz(); + +#if defined(ENABLE_ITTI) + + if (UE_flag == 1) { + log_set_instance_type (LOG_INSTANCE_UE); + } else { + log_set_instance_type (LOG_INSTANCE_ENB); + } + + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); + + // initialize mscgen log after ITTI + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); +#endif + + if (opt_type != OPT_NONE) { + radio_type_t radio_type; + + if (frame_parms[0]->frame_type == FDD) + radio_type = RADIO_TYPE_FDD; + else + radio_type = RADIO_TYPE_TDD; + + if (init_opt(in_path, in_ip, NULL, radio_type) == -1) + LOG_E(OPT,"failed to run OPT \n"); + } + +#ifdef PDCP_USE_NETLINK + netlink_init(); +#if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); +#endif +#endif + +#if !defined(ENABLE_ITTI) + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); +#endif + + + check_clock(); + +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + + // init the parameters + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + if (UE_flag==1) { + frame_parms[CC_id]->nb_antennas_tx = nb_antenna_tx; + frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later + + LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx); + } + + //init_ul_hopping(frame_parms[CC_id]); + //nr_init_frame_parms(frame_parms[CC_id],1); + // phy_init_top(frame_parms[CC_id]); + //phy_init_lte_top(frame_parms[CC_id]); + } + + + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + //init prach for openair1 test + + // prach_fmt = get_prach_fmt(frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, frame_parms->frame_type); + // N_ZC = (prach_fmt <4)?839:139; + } + + if (UE_flag==1) { + NB_UE_INST=1; + NB_INST=1; + + + PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE**)); + PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*)*MAX_NUM_CCs); + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + //PHY_vars_UE_g[0][CC_id] = init_lte_UE(frame_parms[CC_id], 0,abstraction_flag); + UE[CC_id] = PHY_vars_UE_g[0][CC_id]; + printf("PHY_vars_UE_g[0][%d] = %p\n",CC_id,UE[CC_id]); + + if (phy_test==1) + UE[CC_id]->mac_enabled = 0; + else + UE[CC_id]->mac_enabled = 1; + + if (UE[CC_id]->mac_enabled == 0) { //set default UL parameters for testing mode + for (i=0; i<NUMBER_OF_CONNECTED_eNB_MAX; i++) { + UE[CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + UE[CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = 0; + UE[CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(0%3); + UE[CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + UE[CC_id]->UE_scan = UE_scan; + UE[CC_id]->UE_scan_carrier = UE_scan_carrier; + UE[CC_id]->mode = mode; + printf("UE[%d]->mode = %d\n",CC_id,mode); + + for (uint8_t i=0; i<RX_NB_TH_MAX; i++) { + UE[CC_id]->pdcch_vars[i][0]->agregationLevel = agregation_Level; + UE[CC_id]->pdcch_vars[i][0]->dciFormat = dci_Format; + } + + /*compute_prach_seq(&UE[CC_id]->frame_parms.prach_config_common, + UE[CC_id]->frame_parms.frame_type, + UE[CC_id]->X_u);*/ + + if (UE[CC_id]->mac_enabled == 1) + { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1234; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1234; + } + else + { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1235; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1235; + } + + UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; + UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; + + if (frame_parms[CC_id]->frame_type==FDD) { + UE[CC_id]->N_TA_offset = 0; + } else { + if (frame_parms[CC_id]->N_RB_DL == 100) + UE[CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + UE[CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + UE[CC_id]->N_TA_offset = 624/4; + } + + } + + // printf("tx_max_power = %d -> amp %d\n",tx_max_power,get_tx_amp(tx_max_poHwer,tx_max_power)); + } + + fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); + cpuf=get_cpu_freq_GHz(); + + + //dump_frame_parms(frame_parms[0]); + + //init_openair0(); + + + +#ifndef DEADLINE_SCHEDULER + + /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */ + + cpu_set_t cpuset; + int s; + char cpu_affinity[1024]; + CPU_ZERO(&cpuset); +#ifdef CPU_AFFINITY + if (get_nprocs() > 2) { + CPU_SET(0, &cpuset); + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n"); + } +#endif + + /* Check the actual affinity mask assigned to the thread */ + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + memset(cpu_affinity, 0 , sizeof(cpu_affinity)); + for (int j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + char temp[1024]; + sprintf(temp, " CPU_%d ", j); + strcat(cpu_affinity, temp); + } + } + LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity); +#endif + + openair0_cfg[0].log_level = glog_level; + + + + + /*int eMBMS_active=0; + if (node_function[0] <= NGFI_RAU_IF4p5) { // don't initialize L2 for RRU + LOG_I(PHY,"Intializing L2\n"); + mac_xface = malloc(sizeof(MAC_xface)); + l2_init(frame_parms[0],eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL, + 0,// cba_group_active + 0); // HO flag + mac_xface->macphy_exit = &exit_fun; + } else if (node_function[0] == NGFI_RRU_IF4p5) { // Initialize PRACH in this case + + }*/ + + + +#if defined(ENABLE_ITTI) + + // don't create if node doesn't connect to RRC/S1/GTP + /*if (create_tasks(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + }*/ + + printf("ITTI tasks created\n"); +#endif + + /*if (phy_test==0) { + if (UE_flag==1) { + printf("Filling UE band info\n"); + fill_ue_band_info(); + mac_xface->dl_phy_sync_success (0, 0, 0, 1); + } else if (node_function[0]>NGFI_RRU_IF4p5) + mac_xface->mrbch_phy_sync_failure (0, 0, 0); + }*/ + + + + mlockall(MCL_CURRENT | MCL_FUTURE); + + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + +#ifdef XFORMS + int UE_id; + + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + + if (UE_flag==1) { + //form_stats = create_form_stats_form(); + //fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + UE_id = 0; + form_ue[UE_id] = create_lte_phy_scope_ue(); + sprintf (title, "LTE DL SCOPE UE"); + fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + /* + if (openair_daq_vars.use_ia_receiver) { + fl_set_button(form_ue[UE_id]->button_0,1); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); + } else { + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + }*/ + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + } + + ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); + + if (ret == 0) + pthread_setname_np( forms_thread, "xforms" ); + + printf("Scope thread created, ret=%d\n",ret); + } + +#endif + + rt_sleep_ns(10*100000000ULL); + + + + // start the main thread + if (UE_flag == 1) { + init_UE(1); + number_of_cards = 1; + + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + PHY_vars_UE_g[0][CC_id]->rf_map.card=0; + PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; + } + } + + // connect the TX/RX buffers + if (UE_flag==1) { + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + +#if defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706) + UE[CC_id]->hw_timing_advance = timing_advance; +#else + UE[CC_id]->hw_timing_advance = 160; +#endif + } + if (setup_ue_buffers(UE,&openair0_cfg[0])!=0) { + printf("Error setting up eNB buffer\n"); + exit(-1); + } + + + + if (input_fd) { + printf("Reading in from file to antenna buffer %d\n",0); + if (fread(UE[0]->common_vars.rxdata[0], + sizeof(int32_t), + frame_parms[0]->samples_per_subframe*10, + input_fd) != frame_parms[0]->samples_per_subframe*10) + printf("error reading from file\n"); + } + //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX; + } + sleep(3); + + + printf("Sending sync to all threads\n"); + + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + + // wait for end of program + printf("TYPE <CTRL-C> TO TERMINATE\n"); + //getchar(); + +#if defined(ENABLE_ITTI) + printf("Entering ITTI signals handler\n"); + itti_wait_tasks_end(); + oai_exit=1; +#else + + while (oai_exit==0) + rt_sleep_ns(100000000ULL); + +#endif + + // stop threads +#ifdef XFORMS + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + + if (UE_flag==1) { + fl_hide_form(form_ue[0]->lte_phy_scope_ue); + fl_free_form(form_ue[0]->lte_phy_scope_ue); + } else { + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + fl_hide_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + fl_free_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + } + } + } + } + +#endif + + printf("stopping MODEM threads\n"); + + // cleanup + if (UE_flag == 1) { + } else { + // stop_eNB(1); + } + + + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + + + // *** Handle per CC_id openair0 + if (UE_flag==1) { + if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func) + PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice); + } + if (ouput_vcd) + VCD_SIGNAL_DUMPER_CLOSE(); + + if (opt_enabled == 1) + terminate_opt(); + + logClean(); + + return 0; +} diff --git a/targets/RT/USER/nr-uesoftmodem.h b/targets/RT/USER/nr-uesoftmodem.h new file mode 100644 index 0000000000000000000000000000000000000000..64c7b9ea5c26cecf16f98fffc66f1bb9ecea6e83 --- /dev/null +++ b/targets/RT/USER/nr-uesoftmodem.h @@ -0,0 +1,83 @@ +#ifndef NR_UESOFTMODEM_H +#define NR_UESOFTMODEM_H + +#define _GNU_SOURCE +#include <execinfo.h> +#include <fcntl.h> +#include <getopt.h> +#include <linux/sched.h> +#include "rt_wrapper.h" +#include <sched.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syscall.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#include <unistd.h> + +#include <sys/sysinfo.h> +#include "rt_wrapper.h" +#include "../../ARCH/COMMON/common_lib.h" +#undef MALLOC +#include "assertions.h" +#include "msc.h" +#include "PHY/types.h" +#include "PHY/defs_nr_UE.h" +#include "SIMULATION/ETH_TRANSPORT/proto.h" + +#if defined(ENABLE_ITTI) +#if defined(ENABLE_USE_MME) +#include "s1ap_eNB.h" +#ifdef PDCP_USE_NETLINK +#include "SIMULATION/ETH_TRANSPORT/proto.h" +#endif +#endif +#endif + +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; + + +extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; +extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +extern int rx_input_level_dBm; +extern uint8_t exit_missed_slots; +extern uint64_t num_missed_slots; // counter for the number of missed slots + +extern int oaisim_flag; +extern volatile int oai_exit; + +extern openair0_config_t openair0_cfg[MAX_CARDS]; +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; +extern int transmission_mode; +extern double cpuf; + +#if defined(ENABLE_ITTI) +extern volatile int start_eNB; +extern volatile int start_UE; +#endif + +#include "threads_t.h" +extern threads_t threads; + +extern void exit_fun(const char* s); + +// In nr-ue.c +extern int setup_ue_buffers(PHY_VARS_NR_UE **phy_vars_ue, openair0_config_t *openair0_cfg); +extern void fill_ue_band_info(void); +extern void init_UE(int); +extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char * name); +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + +#endif