Commit 9b3fc8b3 authored by Agustin Mico Pereperez's avatar Agustin Mico Pereperez

Merge branch 'develop-nr-prach-integration' into develop-nr

NR PRACH development integration
parents ee6239a8 dbbc9c41
......@@ -1321,6 +1321,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_prach.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/dci_tools_nr.c
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/LTE_TRANSPORT/prach_common.c
* \brief Common routines for UE/eNB PRACH physical channel V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/sse_intrin.h"
//#include "PHY/defs_common.h"
//#include "PHY/phy_extern.h"
//#include "PHY/phy_extern_ue.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
//#include "PHY/defs.h"
#include "PHY/impl_defs_nr.h"
//#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/NR_UE_TRANSPORT/nr_prach.h"
//#include "PHY/extern.h"
//#include "LAYER2/MAC/extern.h"
//#include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "T.h"
#define NR_PRACH_DEBUG 1
void dump_nr_prach_config(NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe)
{
FILE *fd;
fd = fopen("prach_config.txt","w");
fprintf(fd,"prach_config: subframe = %d\n",subframe);
fprintf(fd,"prach_config: N_RB_UL = %d\n",frame_parms->N_RB_UL);
fprintf(fd,"prach_config: frame_type = %s\n",(frame_parms->frame_type==1) ? "TDD":"FDD");
if(frame_parms->frame_type==1) fprintf(fd,"prach_config: tdd_config = %d\n",frame_parms->tdd_config);
fprintf(fd,"prach_config: rootSequenceIndex = %d\n",frame_parms->prach_config_common.rootSequenceIndex);
fprintf(fd,"prach_config: prach_ConfigIndex = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex);
fprintf(fd,"prach_config: Ncs_config = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig);
fprintf(fd,"prach_config: highSpeedFlag = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.highSpeedFlag);
fprintf(fd,"prach_config: n_ra_prboffset = %d\n",frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset);
fclose(fd);
}
// This function computes the du
void nr_fill_du(uint8_t prach_fmt)
{
uint16_t iu,u,p;
uint16_t N_ZC;
uint16_t *prach_root_sequence_map;
if (prach_fmt<4) {
N_ZC = 839;
prach_root_sequence_map = prach_root_sequence_map_0_3;
} else {
N_ZC = 139;
prach_root_sequence_map = prach_root_sequence_map_abc;
}
for (iu=0; iu<(N_ZC-1); iu++) {
u=prach_root_sequence_map[iu];
p=1;
while (((u*p)%N_ZC)!=1)
p++;
nr_du[u] = ((p<(N_ZC>>1)) ? p : (N_ZC-p));
}
}
#if 0
uint8_t get_num_prach_tdd(module_id_t Mod_id)
{
NR_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][0]->frame_parms;
return(tdd_preamble_map[fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex][fp->tdd_config].num_prach);
}
uint8_t get_fid_prach_tdd(module_id_t Mod_id,uint8_t tdd_map_index)
{
NR_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][0]->frame_parms;
return(tdd_preamble_map[fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex][fp->tdd_config].map[tdd_map_index].f_ra);
}
#endif
uint16_t get_nr_prach_fmt(uint8_t prach_ConfigIndex)
{
//return (table_6_3_3_2_2_prachConfig_Index[prach_ConfigIndex][0]); // if using table 6.3.3.2-2: Random access configurations for FR1 and paired spectrum/supplementary uplink
return (table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][0]); // if using table 6.3.3.2-3: Random access configurations for FR1 and unpaired spectrum
// For FR2 not implemented. FIXME
}
#if 0
uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type)
{
if (frame_type == FDD) // FDD
return(prach_ConfigIndex>>4);
else {
if (prach_ConfigIndex < 20)
return (0);
if (prach_ConfigIndex < 30)
return (1);
if (prach_ConfigIndex < 40)
return (2);
if (prach_ConfigIndex < 48)
return (3);
else
return (4);
}
}
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, uint16_t prach_fmt)
{
lte_frame_type_t frame_type = frame_parms->frame_type;
uint8_t tdd_config = frame_parms->tdd_config;
uint8_t n_ra_prb;
uint8_t f_ra,t1_ra;
uint8_t Nsp=2;
if (frame_type == TDD) { // TDD
if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
LOG_E(PHY, "Illegal prach_ConfigIndex %"PRIu8"", prach_ConfigIndex);
return(-1);
}
// adjust n_ra_prboffset for frequency multiplexing (p.36 36.211)
f_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[tdd_mapindex].f_ra;
if (prach_fmt < 4) {
if ((f_ra&1) == 0) {
n_ra_prb = n_ra_prboffset + 6*(f_ra>>1);
} else {
n_ra_prb = frame_parms->N_RB_UL - 6 - n_ra_prboffset + 6*(f_ra>>1);
}
} else {
if ((tdd_config >2) && (tdd_config<6))
Nsp = 2;
t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
if ((((Nf&1)*(2-Nsp)+t1_ra)&1) == 0) {
n_ra_prb = 6*f_ra;
} else {
n_ra_prb = frame_parms->N_RB_UL - 6*(f_ra+1);
}
}
}
else { //FDD
n_ra_prb = n_ra_prboffset;
}
return(n_ra_prb);
}
#endif //0
int is_nr_prach_subframe(NR_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe) {
uint8_t prach_ConfigIndex = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
/*
// For FR1 paired
if (((frame%table_6_3_3_2_2_prachConfig_Index[prach_ConfigIndex][2]) == table_6_3_3_2_2_prachConfig_Index[prach_ConfigIndex][3]) &&
((table_6_3_3_2_2_prachConfig_Index[prach_ConfigIndex][4]&(1<<subframe)) == 1)) {
// using table 6.3.3.2-2: Random access configurations for FR1 and paired spectrum/supplementary uplink
return(1);
} else {
return(0);
}
*/
// For FR1 unpaired
if (((frame%table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][2]) == table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][3]) &&
((table_6_3_3_2_3_prachConfig_Index[prach_ConfigIndex][4]&(1<<subframe)) == 1)) {
// using table 6.3.3.2-2: Random access configurations for FR1 and unpaired
return(1);
} else {
return(0);
}
/*
// For FR2: FIXME
if ((((frame%table_6_3_3_2_4_prachConfig_Index[prach_ConfigIndex][2]) == table_6_3_3_2_4_prachConfig_Index[prach_ConfigIndex][3]) ||
((frame%table_6_3_3_2_4_prachConfig_Index[prach_ConfigIndex][2]) == table_6_3_3_2_4_prachConfig_Index[prach_ConfigIndex][4]))
&&
((table_6_3_3_2_4_prachConfig_Index[prach_ConfigIndex][5]&(1<<subframe)) == 1)) {
// using table 6.3.3.2-2: Random access configurations for FR1 and unpaired
return(1);
} else {
return(0);
}
*/
}
#if 0
int is_prach_subframe0(NR_DL_FRAME_PARMS *frame_parms,uint8_t prach_ConfigIndex,uint32_t frame, uint8_t subframe)
{
// uint8_t prach_ConfigIndex = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
uint8_t tdd_config = frame_parms->tdd_config;
uint8_t t0_ra;
uint8_t t1_ra;
uint8_t t2_ra;
int prach_mask = 0;
if (frame_parms->frame_type == FDD) { //FDD
//implement Table 5.7.1-2 from 36.211 (Rel-10, p.41)
if ((((frame&1) == 1) && (subframe < 9)) ||
(((frame&1) == 0) && (subframe == 9))) // This is an odd frame, ignore even-only PRACH frames
if (((prach_ConfigIndex&0xf)<3) || // 0,1,2,16,17,18,32,33,34,48,49,50
((prach_ConfigIndex&0x1f)==18) || // 18,50
((prach_ConfigIndex&0xf)==15)) // 15,47
return(0);
switch (prach_ConfigIndex&0x1f) {
case 0:
case 3:
if (subframe==1) prach_mask = 1;
break;
case 1:
case 4:
if (subframe==4) prach_mask = 1;
break;
case 2:
case 5:
if (subframe==7) prach_mask = 1;
break;
case 6:
if ((subframe==1) || (subframe==6)) prach_mask=1;
break;
case 7:
if ((subframe==2) || (subframe==7)) prach_mask=1;
break;
case 8:
if ((subframe==3) || (subframe==8)) prach_mask=1;
break;
case 9:
if ((subframe==1) || (subframe==4) || (subframe==7)) prach_mask=1;
break;
case 10:
if ((subframe==2) || (subframe==5) || (subframe==8)) prach_mask=1;
break;
case 11:
if ((subframe==3) || (subframe==6) || (subframe==9)) prach_mask=1;
break;
case 12:
if ((subframe&1)==0) prach_mask=1;
break;
case 13:
if ((subframe&1)==1) prach_mask=1;
break;
case 14:
prach_mask=1;
break;
case 15:
if (subframe==9) prach_mask=1;
break;
}
} else { // TDD
AssertFatal(prach_ConfigIndex<64,
"Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
AssertFatal(tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach>0,
"Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
t0_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t0_ra;
t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
t2_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t2_ra;
#ifdef PRACH_DEBUG
LOG_I(PHY,"[PRACH] Checking for PRACH format (ConfigIndex %d) in TDD subframe %d (%d,%d,%d)\n",
prach_ConfigIndex,
subframe,
t0_ra,t1_ra,t2_ra);
#endif
if ((((t0_ra == 1) && ((frame &1)==0))|| // frame is even and PRACH is in even frames
((t0_ra == 2) && ((frame &1)==1))|| // frame is odd and PRACH is in odd frames
(t0_ra == 0)) && // PRACH is in all frames
(((subframe<5)&&(t1_ra==0)) || // PRACH is in 1st half-frame
(((subframe>4)&&(t1_ra==1))))) { // PRACH is in 2nd half-frame
if ((prach_ConfigIndex<48) && // PRACH only in normal UL subframe
(((subframe%5)-2)==t2_ra)) prach_mask=1;
else if ((prach_ConfigIndex>47) && (((subframe%5)-1)==t2_ra)) prach_mask=1; // PRACH can be in UpPTS
}
}
return(prach_mask);
}
int is_prach_subframe(NR_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe) {
uint8_t prach_ConfigIndex = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
int prach_mask = is_prach_subframe0(frame_parms,prach_ConfigIndex,frame,subframe);
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
int i;
for (i=0;i<4;i++) {
if (frame_parms->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] == 1)
prach_mask|=(is_prach_subframe0(frame_parms,frame_parms->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i],frame,subframe)<<(i+1));
}
#endif
return(prach_mask);
}
#endif //0
void compute_nr_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])
{
// Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC)
unsigned int k,inv_u,i,NCS=0,num_preambles;
int N_ZC;
uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
uint16_t *prach_root_sequence_map;
uint16_t u, preamble_offset;
uint16_t n_shift_ra,n_shift_ra_bar, d_start,numshift;
uint8_t not_found;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN);
#ifdef PRACH_DEBUG
LOG_I(PHY,"compute_prach_seq: NCS_config %d, prach_fmt %d\n",zeroCorrelationZoneConfig, prach_fmt);
#endif
AssertFatal(prach_fmt<4,
"PRACH sequence is only precomputed for prach_fmt<4 (have %"PRIu8")\n", prach_fmt );
N_ZC = (prach_fmt < 4) ? 839 : 139;
//init_prach_tables(N_ZC); //moved to phy_init_lte_ue/eNB, since it takes to long in real-time
if (prach_fmt < 4) {
prach_root_sequence_map = prach_root_sequence_map_0_3;
} else {
// FIXME cannot be reached
prach_root_sequence_map = prach_root_sequence_map_abc;
}
#ifdef PRACH_DEBUG
LOG_I( PHY, "compute_prach_seq: done init prach_tables\n" );
#endif
int restricted_Type = 0; //this is hardcoded ('0' for restricted_TypeA; and '1' for restricted_TypeB). FIXME
if (highSpeedFlag== 0) {
#ifdef PRACH_DEBUG
LOG_I(PHY,"Low speed prach : NCS_config %d\n",zeroCorrelationZoneConfig);
#endif
AssertFatal(zeroCorrelationZoneConfig<=15,
"FATAL, Illegal Ncs_config for unrestricted format %"PRIu8"\n", zeroCorrelationZoneConfig );
if (prach_fmt<3) NCS = NCS_unrestricted_delta_f_RA_125[zeroCorrelationZoneConfig];
if (prach_fmt==3) NCS = NCS_unrestricted_delta_f_RA_5[zeroCorrelationZoneConfig];
if (prach_fmt>3) NCS = NCS_unrestricted_delta_f_RA_15[zeroCorrelationZoneConfig];
num_preambles = (NCS==0) ? 64 : ((64*NCS)/N_ZC);
if (NCS>0) num_preambles++;
preamble_offset = 0;
} else {
#ifdef PRACH_DEBUG
LOG_I( PHY, "high speed prach : NCS_config %"PRIu8"\n", zeroCorrelationZoneConfig );
#endif
AssertFatal(zeroCorrelationZoneConfig<=14,
"FATAL, Illegal Ncs_config for restricted format %"PRIu8"\n", zeroCorrelationZoneConfig );
if (prach_fmt<3){
if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_125[zeroCorrelationZoneConfig]; // for TypeA, this is hardcoded. FIXME
if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_125[zeroCorrelationZoneConfig]; // for TypeB, this is hardcoded. FIXME
}
if (prach_fmt==3){
if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_5[zeroCorrelationZoneConfig]; // for TypeA, this is hardcoded. FIXME
if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_5[zeroCorrelationZoneConfig]; // for TypeB, this is hardcoded. FIXME
}
if (prach_fmt>3){
}
//NCS = NCS_restricted[zeroCorrelationZoneConfig];
nr_fill_du(prach_fmt);
num_preambles = 64; // compute ZC sequence for 64 possible roots
// find first non-zero shift root (stored in preamble_offset)
not_found = 1;
preamble_offset = 0;
while (not_found == 1) {
// current root depending on rootSequenceIndex
int index = (rootSequenceIndex + preamble_offset) % N_ZC;
if (prach_fmt<4) {
// prach_root_sequence_map points to prach_root_sequence_map0_3
DevAssert( index < sizeof(prach_root_sequence_map_0_3) / sizeof(prach_root_sequence_map_0_3[0]) );
} else {
// prach_root_sequence_map points to prach_root_sequence_map4
DevAssert( index < sizeof(prach_root_sequence_map_abc) / sizeof(prach_root_sequence_map_abc[0]) );
}
u = prach_root_sequence_map[index];
uint16_t n_group_ra = 0;
if ( (nr_du[u]<(N_ZC/3)) && (nr_du[u]>=NCS) ) {
n_shift_ra = nr_du[u]/NCS;
d_start = (nr_du[u]<<1) + (n_shift_ra * NCS);
n_group_ra = N_ZC/d_start;
n_shift_ra_bar = max(0,(N_ZC-(nr_du[u]<<1)-(n_group_ra*d_start))/N_ZC);
} else if ( (nr_du[u]>=(N_ZC/3)) && (nr_du[u]<=((N_ZC - NCS)>>1)) ) {
n_shift_ra = (N_ZC - (nr_du[u]<<1))/NCS;
d_start = N_ZC - (nr_du[u]<<1) + (n_shift_ra * NCS);
n_group_ra = nr_du[u]/d_start;
n_shift_ra_bar = min(n_shift_ra,max(0,(nr_du[u]- (n_group_ra*d_start))/NCS));
} else {
n_shift_ra = 0;
n_shift_ra_bar = 0;
}
// This is the number of cyclic shifts for the current root u
numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;
// skip to next root and recompute parameters if numshift==0
if (numshift>0)
not_found = 0;
else
preamble_offset++;
}
}
#ifdef PRACH_DEBUG
if (NCS>0)
LOG_I( PHY, "Initializing %u preambles for PRACH (NCS_config %"PRIu8", NCS %u, N_ZC/NCS %u)\n",
num_preambles, zeroCorrelationZoneConfig, NCS, N_ZC/NCS );
#endif
for (i=0; i<num_preambles; i++) {
int index = (rootSequenceIndex+i+preamble_offset) % N_ZC;
if (prach_fmt<4) {
// prach_root_sequence_map points to prach_root_sequence_map0_3
DevAssert( index < sizeof(prach_root_sequence_map_0_3) / sizeof(prach_root_sequence_map_0_3[0]) );
} else {
// prach_root_sequence_map points to prach_root_sequence_map4
DevAssert( index < sizeof(prach_root_sequence_map_abc) / sizeof(prach_root_sequence_map_abc[0]) );
}
u = prach_root_sequence_map[index];
inv_u = nr_ZC_inv[u]; // multiplicative inverse of u
// X_u[0] stores the first ZC sequence where the root u has a non-zero number of shifts
// for the unrestricted case X_u[0] is the first root indicated by the rootSequenceIndex
for (k=0; k<N_ZC; k++) {
// 420 is the multiplicative inverse of 2 (required since ru is exp[j 2\pi n])
X_u[i][k] = ((uint32_t*)nr_ru)[(((k*(1+(inv_u*k)))%N_ZC)*420)%N_ZC];
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_OUT);
}
void init_nr_prach_tables(int N_ZC)
{
int i,m;
// Compute the modular multiplicative inverse 'iu' of u s.t. iu*u = 1 mod N_ZC
nr_ZC_inv[0] = 0;
nr_ZC_inv[1] = 1;
for (i=2; i<N_ZC; i++) {
for (m=2; m<N_ZC; m++)
if (((i*m)%N_ZC) == 1) {
nr_ZC_inv[i] = m;
break;
}
#ifdef PRACH_DEBUG
if (i<16)
printf("i %d : inv %d\n",i,nr_ZC_inv[i]);
#endif
}
// Compute quantized roots of unity
for (i=0; i<N_ZC; i++) {
nr_ru[i<<1] = (int16_t)(floor(32767.0*cos(2*M_PI*(double)i/N_ZC)));
nr_ru[1+(i<<1)] = (int16_t)(floor(32767.0*sin(2*M_PI*(double)i/N_ZC)));
#ifdef PRACH_DEBUG
if (i<16)
printf("i %d : runity %d,%d\n",i,nr_ru[i<<1],nr_ru[1+(i<<1)]);
#endif
}
}
int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf )
{
//lte_frame_type_t frame_type = ue->frame_parms.frame_type;
//uint8_t tdd_config = ue->frame_parms.tdd_config;
uint16_t rootSequenceIndex = ue->frame_parms.prach_config_common.rootSequenceIndex;
uint8_t prach_ConfigIndex = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
uint8_t Ncs_config = ue->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
uint8_t restricted_set = ue->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag;
//uint8_t n_ra_prboffset = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset;
uint8_t preamble_index = ue->prach_resources[eNB_id]->ra_PreambleIndex;
uint8_t tdd_mapindex = ue->prach_resources[eNB_id]->ra_TDD_map_index;
int16_t *prachF = ue->prach_vars[eNB_id]->prachF;
static int16_t prach_tmp[45600*2] __attribute__((aligned(32)));
int16_t *prach = prach_tmp;
int16_t *prach2;
int16_t amp = ue->prach_vars[eNB_id]->amp;
int16_t Ncp;
uint8_t n_ra_prb;
uint16_t NCS;
uint16_t *prach_root_sequence_map;
uint16_t preamble_offset,preamble_shift;
uint16_t preamble_index0,n_shift_ra,n_shift_ra_bar;
uint16_t d_start,numshift;
uint16_t prach_fmt = get_nr_prach_fmt(prach_ConfigIndex);
//uint8_t Nsp=2;
//uint8_t f_ra,t1_ra;
uint16_t N_ZC = (prach_fmt<4)?839:139;
uint8_t not_found;
int k;
int16_t *Xu;
uint16_t u;
int32_t Xu_re,Xu_im;
uint16_t offset,offset2;
int prach_start;
int i, prach_len;
uint16_t first_nonzero_root_idx=0;
#if defined(EXMIMO) || defined(OAI_USRP)
prach_start = (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset);
#ifdef PRACH_DEBUG
LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id,
prach_start,
ue->rx_offset,
ue->hw_timing_advance,
ue->N_TA_offset);
#endif
if (prach_start<0)
prach_start+=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
if (prach_start>=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
prach_start-=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
#else //normal case (simulation)
prach_start = subframe*ue->frame_parms.samples_per_tti-ue->N_TA_offset;
LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id,
prach_start,
ue->rx_offset,
ue->hw_timing_advance,
ue->N_TA_offset);
#endif
// First compute physical root sequence
/************************************************************************
* 4G and NR NCS tables are slightly different and depend on prach format
* Table 6.3.3.1-5: for preamble formats with delta_f_RA = 1.25 Khz (formats 0,1,2)
* Table 6.3.3.1-6: for preamble formats with delta_f_RA = 5 Khz (formats 3)
* NOTE: Restricted set type B is not implemented
*************************************************************************/
int restricted_Type = 0; //this is hardcoded ('0' for restricted_TypeA; and '1' for restricted_TypeB). FIXME
if (prach_fmt<3){
if (restricted_set == 0) {
NCS = NCS_unrestricted_delta_f_RA_125[Ncs_config];
} else {
if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_125[Ncs_config]; // for TypeA, this is hardcoded. FIXME
if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_125[Ncs_config]; // for TypeB, this is hardcoded. FIXME
}
}
if (prach_fmt==3){
if (restricted_set == 0) {
NCS = NCS_unrestricted_delta_f_RA_5[Ncs_config];
} else {
if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_5[Ncs_config]; // for TypeA, this is hardcoded. FIXME
if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_5[Ncs_config]; // for TypeB, this is hardcoded. FIXME
}
}
if (prach_fmt>3){
NCS = NCS_unrestricted_delta_f_RA_15[Ncs_config];
}
n_ra_prb = ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset;
// n_ra_prb = get_nr_prach_prb_offset(&(ue->frame_parms),
// ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex,
// ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset,
// tdd_mapindex,
// Nf,
// prach_fmt);
prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;
/*
// this code is not part of get_prach_prb_offset
if (frame_type == TDD) { // TDD
if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
LOG_E( PHY, "[PHY][UE %"PRIu8"] Illegal prach_ConfigIndex %"PRIu8" for ", ue->Mod_id, prach_ConfigIndex );
}
// adjust n_ra_prboffset for frequency multiplexing (p.36 36.211)
f_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[tdd_mapindex].f_ra;
if (prach_fmt < 4) {
if ((f_ra&1) == 0) {
n_ra_prb = n_ra_prboffset + 6*(f_ra>>1);
} else {
n_ra_prb = ue->frame_parms.N_RB_UL - 6 - n_ra_prboffset + 6*(f_ra>>1);
}
} else {
if ((tdd_config >2) && (tdd_config<6))
Nsp = 2;
t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
if ((((Nf&1)*(2-Nsp)+t1_ra)&1) == 0) {
n_ra_prb = 6*f_ra;
} else {
n_ra_prb = ue->frame_parms.N_RB_UL - 6*(f_ra+1);
}
}
}
*/
// This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS)));
if (restricted_set == 0) {
// This is the \nu corresponding to the preamble index
preamble_shift = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS));