diff --git a/openair1/PHY/NR_TRANSPORT/nr_prs.c b/openair1/PHY/NR_TRANSPORT/nr_prs.c index 53fbb1a391..a4cec432de 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prs.c @@ -1,4 +1,50 @@ -//int nr_generate_prs(){} +/* + * 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/nr_pbch.c +* \brief Top-level routines for generating the PBCH/BCH physical/transport channel V15.1 03/2018 +* \author Guy De Souza +* \thanks Special Thanks to Son Dang for helpful contributions and testing +* \date 2018 +* \version 0.1 +* \company Eurecom +* \email: desouza@eurecom.fr +* \note +* \warning +*/ + +#include "PHY/defs_gNB.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/LTE_REFSIG/lte_refsig.h" +#include "PHY/sse_intrin.h" + +//#define DEBUG_PBCH +//#define DEBUG_PBCH_ENCODING +//#define DEBUG_PBCH_DMRS + +extern short nr_qpsk_mod_table[8]; + +const uint8_t nr_pbch_payload_interleaving_pattern[32] = {16, 23, 18, 17, 8, 30, 10, 6, 24, 7, 0, 5, 3, 2, 1, 4, + 9, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29, 31 + }; int nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, int32_t *txdataF, @@ -94,3 +140,295 @@ int nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, #endif return 0; } + +static void nr_pbch_scrambling(NR_gNB_PBCH *pbch, + uint32_t Nid, + uint8_t nushift, + uint16_t M, + uint16_t length, + uint8_t encoded, + uint32_t unscrambling_mask) { + uint8_t reset, offset; + uint32_t x1, x2, s=0; + uint32_t *pbch_e = pbch->pbch_e; + reset = 1; + // x1 is set in lte_gold_generic + x2 = Nid; + + // The Gold sequence is shifted by nushift* M, so we skip (nushift*M /32) double words + for (int i=0; i<(uint16_t)ceil(((float)nushift*M)/32); i++) { + s = lte_gold_generic(&x1, &x2, reset); + reset = 0; + } + + // Scrambling is now done with offset (nushift*M)%32 + offset = (nushift*M)&0x1f; +#ifdef DEBUG_PBCH_ENCODING + printf("Scrambling params: nushift %d M %d length %d encoded %d offset %d\n", nushift, M, length, encoded, offset); +#endif +#ifdef DEBUG_PBCH_ENCODING + printf("s: %04x\t", s); +#endif + int k = 0; + + if (!encoded) { + /// 1st Scrambling + for (int i = 0; i < length; ++i) { + if ((unscrambling_mask>>i)&1) + pbch->pbch_a_prime ^= ((pbch->pbch_a_interleaved>>i)&1)<pbch_a_prime ^= (((pbch->pbch_a_interleaved>>i)&1) ^ ((s>>((k+offset)&0x1f))&1))<>5] ^= (((s>>((i+offset)&0x1f))&1)<<(i&0x1f)); + } + } +} + + +void nr_init_pbch_interleaver(uint8_t *interleaver) { + uint8_t j_sfn=0, j_hrf=10, j_ssb=11, j_other=14; + memset((void *)interleaver,0, NR_POLAR_PBCH_PAYLOAD_BITS); + + for (uint8_t i=0; ipbch_a=0; + uint8_t ssb_index = ssb_pdu->ssb_pdu_rel15.SsbBlockIndex; + uint8_t *pbch_pdu = (uint8_t*)&ssb_pdu->ssb_pdu_rel15.bchPayload; + uint8_t Lmax = frame_parms->Lmax; + for (int i=0; ipbch_a |= ((pbch_pdu[i>>3]>>(7-(i&7)))&1)<pbch_a); + #endif + + // Extra byte generation + for (int i=0; i<4; i++) + pbch->pbch_a |= ((sfn>>(3-i))&1)<<(24+i); // resp. 4th, 3rd, 2nd ans 1st lsb of sfn + + pbch->pbch_a |= n_hf<<28; // half frame index bit + + if (Lmax == 64) + for (int i=0; i<3; i++) + pbch->pbch_a |= ((ssb_index>>(5-i))&1)<<(29+i); // resp. 6th, 5th and 4th bits of ssb_index + else + pbch->pbch_a |= ((config->ssb_table.ssb_subcarrier_offset.value>>4)&1)<<29; //MSB of k_SSB (bit index 4) + + LOG_D(PHY,"After extra byte: pbch_a = 0x%08x\n",pbch->pbch_a); + + // Payload interleaving + + for (int i=0; ipbch_a_interleaved |= ((pbch->pbch_a>>i)&1)<<(*(interleaver+i)); +#ifdef DEBUG_PBCH_ENCODING + printf("i %d out 0x%08x ilv %d (in>>i)&1) %d\n", i, pbch->pbch_a_interleaved, *(interleaver+i), (pbch->pbch_a>>i)&1); +#endif + } + +#ifdef DEBUG_PBCH_ENCODING + printf("Interleaving:\n"); + printf("pbch_a_interleaved: 0x%08x\n", pbch->pbch_a_interleaved); +#endif + // Scrambling + unscrambling_mask = (Lmax ==64)? 0x100006D:0x1000041; + M = (Lmax == 64)? (NR_POLAR_PBCH_PAYLOAD_BITS - 6) : (NR_POLAR_PBCH_PAYLOAD_BITS - 3); + nushift = (((sfn>>2)&1)<<1) ^ ((sfn>>1)&1); + pbch->pbch_a_prime = 0; + nr_pbch_scrambling(pbch, (uint32_t)config->cell_config.phy_cell_id.value, nushift, M, NR_POLAR_PBCH_PAYLOAD_BITS, 0, unscrambling_mask); +#ifdef DEBUG_PBCH_ENCODING + printf("Payload scrambling: nushift %d M %d sfn3 %d sfn2 %d\n", nushift, M, (sfn>>2)&1, (sfn>>1)&1); + printf("pbch_a_prime: 0x%08x\n", pbch->pbch_a_prime); +#endif + + // Encoder reversal + for (int i=0; ipbch_a_prime>>i)&1)<<(31-i); + + /// CRC, coding and rate matching + polar_encoder_fast (&a_reversed, (void*)pbch->pbch_e, 0, 0, + nr_polar_params( NR_POLAR_PBCH_MESSAGE_TYPE, NR_POLAR_PBCH_PAYLOAD_BITS, NR_POLAR_PBCH_AGGREGATION_LEVEL,0,NULL) + ); +#ifdef DEBUG_PBCH_ENCODING + printf("Channel coding:\n"); + + for (int i=0; ipbch_e[i]); + + printf("\n"); +#endif + /// Scrambling + M = NR_POLAR_PBCH_E; + nushift = (Lmax==4)? ssb_index&3 : ssb_index&7; + nr_pbch_scrambling(pbch, (uint32_t)config->cell_config.phy_cell_id.value, nushift, M, NR_POLAR_PBCH_E, 1, 0); +#ifdef DEBUG_PBCH_ENCODING + printf("Scrambling:\n"); + + for (int i=0; ipbch_e[i]); + + printf("\n"); +#endif + + /// QPSK modulation + for (int i=0; i>1; i++) { + idx = ((pbch->pbch_e[(i<<1)>>5]>>((i<<1)&0x1f))&3); + mod_pbch_e[i<<1] = nr_qpsk_mod_table[idx<<1]; + mod_pbch_e[(i<<1)+1] = nr_qpsk_mod_table[(idx<<1)+1]; +#ifdef DEBUG_PBCH + printf("i %d idx %d mod_pbch %d %d\n", i, idx, mod_pbch_e[2*i], mod_pbch_e[2*i+1]); +#endif + } + + /// Resource mapping + nushift = config->cell_config.phy_cell_id.value &3; + // PBCH modulated symbols are mapped within the SSB block on symbols 1, 2, 3 excluding the subcarriers used for the PBCH DMRS + ///symbol 1 [0:239] -- 180 mod symbols + k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + l = ssb_start_symbol + 1; + m = 0; + + for (int ssb_sc_idx = 0; ssb_sc_idx < 240; ssb_sc_idx++) { + if ((ssb_sc_idx&3) == nushift) { //skip DMRS + k++; + continue; + } else { +#ifdef DEBUG_PBCH + printf("m %d ssb_sc_idx %d at k %d of l %d\n", m, ssb_sc_idx, k, l); +#endif + ((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1] = (amp * mod_pbch_e[m<<1]) >> 15; + ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * mod_pbch_e[(m<<1) + 1]) >> 15; + k++; + m++; + } + + if (k >= frame_parms->ofdm_symbol_size) + k-=frame_parms->ofdm_symbol_size; + } + + ///symbol 2 [0:47 ; 192:239] -- 72 mod symbols + k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + l++; + m=180; + + for (int ssb_sc_idx = 0; ssb_sc_idx < 48; ssb_sc_idx++) { + if ((ssb_sc_idx&3) == nushift) { + k++; + continue; + } else { +#ifdef DEBUG_PBCH + printf("m %d ssb_sc_idx %d at k %d of l %d\n", m, ssb_sc_idx, k, l); +#endif + ((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1] = (amp * mod_pbch_e[m<<1]) >> 15; + ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * mod_pbch_e[(m<<1) + 1]) >> 15; + k++; + m++; + } + + if (k >= frame_parms->ofdm_symbol_size) + k-=frame_parms->ofdm_symbol_size; + } + + k += 144; + + if (k >= frame_parms->ofdm_symbol_size) + k-=frame_parms->ofdm_symbol_size; + + m=216; + + for (int ssb_sc_idx = 192; ssb_sc_idx < 240; ssb_sc_idx++) { + if ((ssb_sc_idx&3) == nushift) { + k++; + continue; + } else { +#ifdef DEBUG_PBCH + printf("m %d ssb_sc_idx %d at k %d of l %d\n", m, ssb_sc_idx, k, l); +#endif + ((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1] = (amp * mod_pbch_e[m<<1]) >> 15; + ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * mod_pbch_e[(m<<1) + 1]) >> 15; + k++; + m++; + } + + if (k >= frame_parms->ofdm_symbol_size) + k-=frame_parms->ofdm_symbol_size; + } + + ///symbol 3 [0:239] -- 180 mod symbols + k = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; + l++; + m=252; + + for (int ssb_sc_idx = 0; ssb_sc_idx < 240; ssb_sc_idx++) { + if ((ssb_sc_idx&3) == nushift) { + k++; + continue; + } else { +#ifdef DEBUG_PBCH + printf("m %d ssb_sc_idx %d at k %d of l %d\n", m, ssb_sc_idx, k, l); +#endif + ((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1] = (amp * mod_pbch_e[m<<1]) >> 15; + ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1] = (amp * mod_pbch_e[(m<<1) + 1]) >> 15; + k++; + m++; + } + + + if (k >= frame_parms->ofdm_symbol_size) + k-=frame_parms->ofdm_symbol_size; + } + + + return 0; +}