- adapted the get_band function: the algorithm is now taking into account also the UL frequency in order to fetch the proper band (this was failing before as some NR bands have the same DL band, e.g. band 65 and 66) - added new bands to the NR table as per TS 38.101 V16.4.0 (2020) - made the from_nrarfcn function compatible with UL FDD (this function, used for both DL and UL was previously working with TDD only as it did not compute properly the frequency for the UL FDD, throwing asserts) - introduced common functions to get the NR table idx and the duplex mode, removing repeated code in the process - removed the unused function to get the uldl offset - improved some logging - other minor fixes to the relevant code
414 lines
15 KiB
C
414 lines
15 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
#include "phy_init.h"
|
|
#include "common/utils/LOG/log.h"
|
|
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
|
|
|
/// Subcarrier spacings in Hz indexed by numerology index
|
|
uint32_t nr_subcarrier_spacing[MAX_NUM_SUBCARRIER_SPACING] = {15e3, 30e3, 60e3, 120e3, 240e3};
|
|
uint16_t nr_slots_per_subframe[MAX_NUM_SUBCARRIER_SPACING] = {1, 2, 4, 8, 16};
|
|
|
|
|
|
|
|
int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp)
|
|
{
|
|
|
|
int mu = fp->numerology_index;
|
|
uint8_t half_frame_index = fp->half_frame_bit;
|
|
uint8_t i_ssb = fp->ssb_index;
|
|
int symbol = 0;
|
|
uint8_t n, n_temp;
|
|
nr_ssb_type_e type = fp->ssb_type;
|
|
int case_AC[2] = {2,8};
|
|
int case_BD[4] = {4,8,16,20};
|
|
int case_E[8] = {8, 12, 16, 20, 32, 36, 40, 44};
|
|
|
|
switch(mu) {
|
|
|
|
case NR_MU_0: // case A
|
|
n = i_ssb >> 1;
|
|
symbol = case_AC[i_ssb % 2] + 14*n;
|
|
break;
|
|
|
|
case NR_MU_1:
|
|
if (type == 1){ // case B
|
|
n = i_ssb >> 2;
|
|
symbol = case_BD[i_ssb % 4] + 28*n;
|
|
}
|
|
if (type == 2){ // case C
|
|
n = i_ssb >> 1;
|
|
symbol = case_AC[i_ssb % 2] + 14*n;
|
|
}
|
|
break;
|
|
|
|
case NR_MU_3: // case D
|
|
n_temp = i_ssb >> 2;
|
|
n = n_temp + (n_temp >> 2);
|
|
symbol = case_BD[i_ssb % 4] + 28*n;
|
|
break;
|
|
|
|
case NR_MU_4: // case E
|
|
n_temp = i_ssb >> 3;
|
|
n = n_temp + (n_temp >> 2);
|
|
symbol = case_E[i_ssb % 8] + 56*n;
|
|
break;
|
|
|
|
|
|
default:
|
|
AssertFatal(0==1, "Invalid numerology index %d for the synchronization block\n", mu);
|
|
}
|
|
|
|
if (half_frame_index)
|
|
symbol += (5 * fp->symbols_per_slot * fp->slots_per_subframe);
|
|
|
|
return symbol;
|
|
}
|
|
|
|
void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, uint16_t bw)
|
|
{
|
|
switch(mu) {
|
|
|
|
case NR_MU_0: //15kHz scs
|
|
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_0];
|
|
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_0];
|
|
fp->ssb_type = nr_ssb_type_A;
|
|
break;
|
|
|
|
case NR_MU_1: //30kHz scs
|
|
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_1];
|
|
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_1];
|
|
|
|
// selection of SS block pattern according to TS 38101-1 Table 5.4.3.3-1 for SCS 30kHz
|
|
if (fp->nr_band == 5 || fp->nr_band == 66)
|
|
fp->ssb_type = nr_ssb_type_B;
|
|
else{
|
|
if (fp->nr_band == 41 || ( fp->nr_band > 76 && fp->nr_band < 80) )
|
|
fp->ssb_type = nr_ssb_type_C;
|
|
else
|
|
AssertFatal(1==0,"NR Operating Band n%d not available for SS block SCS with mu=%d\n", fp->nr_band, mu);
|
|
}
|
|
|
|
switch(bw){
|
|
case 5:
|
|
case 15:
|
|
case 20:
|
|
case 25:
|
|
case 30:
|
|
case 40: //40 MHz
|
|
if (fp->threequarter_fs) {
|
|
fp->ofdm_symbol_size = 1536;
|
|
fp->first_carrier_offset = 900; //1536 - ( (106*12) / 2 )
|
|
fp->nb_prefix_samples0 = 132;
|
|
fp->nb_prefix_samples = 108;
|
|
}
|
|
else {
|
|
fp->ofdm_symbol_size = 2048;
|
|
fp->first_carrier_offset = 1412; //2048 - ( (106*12) / 2 )
|
|
fp->nb_prefix_samples0 = 176;
|
|
fp->nb_prefix_samples = 144;
|
|
}
|
|
break;
|
|
|
|
case 50:
|
|
case 60:
|
|
case 70:
|
|
|
|
case 80: //80 MHz
|
|
if (fp->threequarter_fs) {
|
|
fp->ofdm_symbol_size = 3072;
|
|
fp->first_carrier_offset = 1770; //3072 - ( (217*12) / 2 )
|
|
fp->nb_prefix_samples0 = 264;
|
|
fp->nb_prefix_samples = 216;
|
|
}
|
|
else {
|
|
fp->ofdm_symbol_size = 4096;
|
|
fp->first_carrier_offset = 2794; //4096 - ( (217*12) / 2 )
|
|
fp->nb_prefix_samples0 = 352;
|
|
fp->nb_prefix_samples = 288;
|
|
}
|
|
break;
|
|
|
|
case 90:
|
|
AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for %d MHz band and MU %d\n",bw,mu);
|
|
fp->ofdm_symbol_size = 4096;
|
|
fp->first_carrier_offset = 2626; //4096 - ( (245*12) / 2 )
|
|
fp->nb_prefix_samples0 = 352;
|
|
fp->nb_prefix_samples = 288;
|
|
break;
|
|
case 100:
|
|
AssertFatal(fp->threequarter_fs==0,"3/4 sampling impossible for %d MHz band and MU %d\n",bw,mu);
|
|
fp->ofdm_symbol_size = 4096;
|
|
fp->first_carrier_offset = 2458; //4096 - ( (273*12) / 2 )
|
|
fp->nb_prefix_samples0 = 352;
|
|
fp->nb_prefix_samples = 288;
|
|
break;
|
|
default:
|
|
AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp);
|
|
}
|
|
break;
|
|
|
|
case NR_MU_2: //60kHz scs
|
|
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_2];
|
|
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_2];
|
|
|
|
switch(bw){ //FR1 bands only
|
|
case 10:
|
|
case 15:
|
|
case 20:
|
|
case 25:
|
|
case 30:
|
|
case 40:
|
|
case 50:
|
|
case 60:
|
|
case 70:
|
|
case 80:
|
|
case 90:
|
|
case 100:
|
|
default:
|
|
AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp);
|
|
}
|
|
break;
|
|
|
|
case NR_MU_3:
|
|
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_3];
|
|
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_3];
|
|
fp->ssb_type = nr_ssb_type_D;
|
|
switch(bw){
|
|
case 100:
|
|
fp->ofdm_symbol_size = 1024;
|
|
fp->first_carrier_offset = 628; //1024 - ( (66*12) / 2 )
|
|
fp->nb_prefix_samples0 = 136;
|
|
fp->nb_prefix_samples = 72;
|
|
break;
|
|
case 50:
|
|
fp->ofdm_symbol_size = 512;
|
|
fp->first_carrier_offset = 320; //1024 - ( (66*12) / 2 )
|
|
fp->nb_prefix_samples0 = 68;
|
|
fp->nb_prefix_samples = 36;
|
|
break;
|
|
default:
|
|
AssertFatal(1==0,"%d MHz band undefined for mu %d, frame parms = %p\n", bw, mu, fp);
|
|
}
|
|
break;
|
|
|
|
case NR_MU_4:
|
|
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_4];
|
|
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_4];
|
|
fp->ssb_type = nr_ssb_type_E;
|
|
break;
|
|
|
|
default:
|
|
AssertFatal(1==0,"Invalid numerology index %d", mu);
|
|
}
|
|
}
|
|
|
|
uint32_t get_samples_per_slot(int slot, NR_DL_FRAME_PARMS* fp)
|
|
{
|
|
uint32_t samp_count;
|
|
|
|
if(fp->numerology_index == 0)
|
|
samp_count = fp->samples_per_subframe;
|
|
else
|
|
samp_count = (slot%(fp->slots_per_subframe/2)) ? fp->samples_per_slotN0 : fp->samples_per_slot0;
|
|
|
|
return samp_count;
|
|
}
|
|
|
|
uint32_t get_samples_slot_timestamp(int slot, NR_DL_FRAME_PARMS* fp, uint8_t sl_ahead)
|
|
{
|
|
uint32_t samp_count = 0;
|
|
|
|
if(!sl_ahead) {
|
|
for(uint8_t idx_slot = 0; idx_slot < slot; idx_slot++)
|
|
samp_count += fp->get_samples_per_slot(idx_slot, fp);
|
|
} else {
|
|
for(uint8_t idx_slot = slot; idx_slot < slot+sl_ahead; idx_slot++)
|
|
samp_count += fp->get_samples_per_slot(idx_slot, fp);
|
|
}
|
|
return samp_count;
|
|
}
|
|
|
|
int nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg,
|
|
NR_DL_FRAME_PARMS *fp)
|
|
{
|
|
|
|
fp->frame_type = cfg->cell_config.frame_duplex_type.value;
|
|
fp->L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value)<<32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value ;
|
|
fp->N_RB_DL = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value;
|
|
fp->N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value;
|
|
|
|
int Ncp = NFAPI_CP_NORMAL;
|
|
int mu = cfg!= NULL ? cfg->ssb_config.scs_common.value : 0;
|
|
|
|
#if DISABLE_LOG_X
|
|
printf("Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, fp->N_RB_DL, Ncp);
|
|
#else
|
|
LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, fp->N_RB_DL, Ncp);
|
|
#endif
|
|
|
|
if (Ncp == NFAPI_CP_EXTENDED)
|
|
AssertFatal(mu == NR_MU_2,"Invalid cyclic prefix %d for numerology index %d\n", Ncp, mu);
|
|
|
|
fp->half_frame_bit = 0; // half frame bit initialized to 0 here
|
|
fp->numerology_index = mu;
|
|
|
|
set_scs_parameters(fp, mu, cfg->carrier_config.dl_bandwidth.value);
|
|
|
|
fp->slots_per_frame = 10* fp->slots_per_subframe;
|
|
|
|
fp->nb_antenna_ports_gNB = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
fp->nb_antennas_rx = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
fp->nb_antennas_tx = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
|
|
fp->symbols_per_slot = ((Ncp == NORMAL)? 14 : 12); // to redefine for different slot formats
|
|
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
|
|
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
|
|
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
|
|
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
|
|
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
|
|
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
|
|
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
|
fp->get_samples_per_slot = &get_samples_per_slot;
|
|
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
|
fp->samples_per_frame = 10 * fp->samples_per_subframe;
|
|
fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2;
|
|
|
|
fp->Ncp = Ncp;
|
|
|
|
// definition of Lmax according to ts 38.213 section 4.1
|
|
if (fp->dl_CarrierFreq < 6e9) {
|
|
if(fp->frame_type && (fp->ssb_type==2))
|
|
fp->Lmax = (fp->dl_CarrierFreq < 2.4e9)? 4 : 8;
|
|
else
|
|
fp->Lmax = (fp->dl_CarrierFreq < 3e9)? 4 : 8;
|
|
} else {
|
|
fp->Lmax = 64;
|
|
}
|
|
|
|
fp->N_ssb = 0;
|
|
int num_tx_ant = (cfg == NULL) ? fp->Lmax : cfg->carrier_config.num_tx_ant.value;
|
|
|
|
for (int p=0; p<num_tx_ant; p++)
|
|
fp->N_ssb += ((fp->L_ssb >> (63-p)) & 0x01);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
|
|
fapi_nr_config_request_t* config,
|
|
int Ncp)
|
|
{
|
|
|
|
uint64_t dl_bw_khz = (12*config->carrier_config.dl_grid_size[config->ssb_config.scs_common])*(15<<config->ssb_config.scs_common);
|
|
fp->dl_CarrierFreq = ((dl_bw_khz>>1) + config->carrier_config.dl_frequency)*1000 ;
|
|
|
|
uint64_t ul_bw_khz = (12*config->carrier_config.ul_grid_size[config->ssb_config.scs_common])*(15<<config->ssb_config.scs_common);
|
|
fp->ul_CarrierFreq = ((ul_bw_khz>>1) + config->carrier_config.uplink_frequency)*1000 ;
|
|
|
|
fp->numerology_index = config->ssb_config.scs_common;
|
|
fp->N_RB_UL = config->carrier_config.ul_grid_size[fp->numerology_index];
|
|
fp->N_RB_DL = config->carrier_config.dl_grid_size[fp->numerology_index];
|
|
|
|
int32_t uplink_frequency_offset = 0;
|
|
|
|
get_band(fp->dl_CarrierFreq, fp->ul_CarrierFreq, &fp->nr_band, &uplink_frequency_offset, &fp->frame_type);
|
|
|
|
AssertFatal(fp->frame_type==config->cell_config.frame_duplex_type, "Invalid duplex type in config request file for band %d\n", fp->nr_band);
|
|
AssertFatal(fp->ul_CarrierFreq == (fp->dl_CarrierFreq + uplink_frequency_offset), "Disagreement in uplink frequency for band %d: ul_CarrierFreq = %lu Hz vs expected %lu Hz\n", fp->nr_band, fp->ul_CarrierFreq, fp->dl_CarrierFreq + uplink_frequency_offset);
|
|
|
|
#if DISABLE_LOG_X
|
|
printf("Initializing UE frame parms for mu %d, N_RB %d, Ncp %d\n",fp->numerology_index, fp->N_RB_DL, Ncp);
|
|
#else
|
|
LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",fp->numerology_index, fp->N_RB_DL, Ncp);
|
|
#endif
|
|
|
|
if (Ncp == NFAPI_CP_EXTENDED)
|
|
AssertFatal(fp->numerology_index == NR_MU_2,"Invalid cyclic prefix %d for numerology index %d\n", Ncp, fp->numerology_index);
|
|
|
|
fp->Ncp = Ncp;
|
|
|
|
set_scs_parameters(fp,fp->numerology_index,config->carrier_config.dl_bandwidth);
|
|
|
|
fp->slots_per_frame = 10* fp->slots_per_subframe;
|
|
|
|
fp->nb_antenna_ports_gNB = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
fp->nb_antennas_rx = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
fp->nb_antennas_tx = 1; // default value until overwritten by RRCConnectionReconfiguration
|
|
|
|
fp->symbols_per_slot = ((Ncp == NORMAL)? 14 : 12); // to redefine for different slot formats
|
|
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
|
|
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
|
|
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
|
|
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
|
|
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
|
|
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
|
|
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
|
fp->get_samples_per_slot = &get_samples_per_slot;
|
|
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
|
fp->samples_per_frame = 10 * fp->samples_per_subframe;
|
|
fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2;
|
|
|
|
uint8_t sco = 0;
|
|
if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset<24)) ||
|
|
((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) )
|
|
sco = config->ssb_table.ssb_subcarrier_offset;
|
|
|
|
fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco);
|
|
|
|
// definition of Lmax according to ts 38.213 section 4.1
|
|
if (fp->dl_CarrierFreq < 6e9) {
|
|
if(fp->frame_type && (fp->ssb_type==2))
|
|
fp->Lmax = (fp->dl_CarrierFreq < 2.4e9)? 4 : 8;
|
|
else
|
|
fp->Lmax = (fp->dl_CarrierFreq < 3e9)? 4 : 8;
|
|
} else {
|
|
fp->Lmax = 64;
|
|
}
|
|
|
|
fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[1].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[1].ssb_mask;
|
|
|
|
fp->N_ssb = 0;
|
|
for (int p=0; p<fp->Lmax; p++)
|
|
fp->N_ssb += ((fp->L_ssb >> (63-p)) & 0x01);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp)
|
|
{
|
|
LOG_I(PHY,"fp->scs=%d\n",fp->subcarrier_spacing);
|
|
LOG_I(PHY,"fp->ofdm_symbol_size=%d\n",fp->ofdm_symbol_size);
|
|
LOG_I(PHY,"fp->nb_prefix_samples0=%d\n",fp->nb_prefix_samples0);
|
|
LOG_I(PHY,"fp->nb_prefix_samples=%d\n",fp->nb_prefix_samples);
|
|
LOG_I(PHY,"fp->slots_per_subframe=%d\n",fp->slots_per_subframe);
|
|
LOG_I(PHY,"fp->samples_per_subframe_wCP=%d\n",fp->samples_per_subframe_wCP);
|
|
LOG_I(PHY,"fp->samples_per_frame_wCP=%d\n",fp->samples_per_frame_wCP);
|
|
LOG_I(PHY,"fp->samples_per_subframe=%d\n",fp->samples_per_subframe);
|
|
LOG_I(PHY,"fp->samples_per_frame=%d\n",fp->samples_per_frame);
|
|
LOG_I(PHY,"fp->dl_CarrierFreq=%lu\n",fp->dl_CarrierFreq);
|
|
LOG_I(PHY,"fp->ul_CarrierFreq=%lu\n",fp->ul_CarrierFreq);
|
|
}
|
|
|
|
|
|
|