/* * 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/pss.c * \brief Top-level routines for generating primary synchronization signal (PSS) V8.6 2009-03 * \author F. Kaltenberger, O. Tonelli, R. Knopp * \date 2011 * \version 0.1 * \company Eurecom * \email: florian.kaltenberger@eurecom.fr, oscar.tonelli@yahoo.it,knopp@eurecom.fr * \note * \warning */ /* file: slbch.c purpose: TX and RX procedures for Sidelink Broadcast Channel author: raymond.knopp@eurecom.fr date: 02.05.2018 */ //#include "defs.h" #include "PHY/defs.h" #include "PHY/extern.h" #define PSBCH_A 40 #define PSBCH_E 1008 //12REs/PRB*6PRBs*7symbols*2 bits/RB #define PSBCH_DEBUG 1 int generate_slbch(int32_t **txdataF, short amp, LTE_DL_FRAME_PARMS *frame_parms, int subframe, uint8_t *slmib) { uint8_t slbch_a[PSBCH_A>>3]; uint32_t psbch_D; uint8_t psbch_d[96+(3*(16+PSBCH_A))]; uint8_t psbch_w[3*3*(16+PSBCH_A)]; uint8_t psbch_e[PSBCH_E]; uint8_t RCC; int a; psbch_D = 16+PSBCH_A; AssertFatal(frame_parms->Ncp==NORMAL,"Only Normal Prefix supported for Sidelink\n"); AssertFatal(frame_parms->Ncp==NORMAL,"Only Normal Prefix supported for Sidelink\n"); bzero(slbch_a,PSBCH_A>>3); bzero(psbch_e,PSBCH_E); memset(psbch_d,LTE_NULL,96); for (int i=0; i<(PSBCH_A>>3); i++) slbch_a[(PSBCH_A>>3)-i-1] = slmib[i]; ccodelte_encode(PSBCH_A,2,slbch_a,psbch_d+96,0); RCC = sub_block_interleaving_cc(psbch_D,psbch_d+96,psbch_w); lte_rate_matching_cc(RCC,PSBCH_E,psbch_w,psbch_e); // for (int i=0;i<PSBCH_E;i++) printf("PSBCH E[%d] %d\n",i,psbch_e[i]); pbch_scrambling(frame_parms, psbch_e, PSBCH_E, 1); int symb=0; uint8_t *eptr = psbch_e; int16_t *txptr; int k; a = (amp*SQRT_18_OVER_32_Q15)>>(15-2); int Nsymb=14; int16_t precin[144*12]; int16_t precout[144*12]; for (int i=0;i<144*7;i++) if (*eptr++ == 1) precin[i] =-a; else precin[i] = a; dft_lte((int32_t*)precout, (int32_t*)precin, 72, 12); int j=0; for (symb=0;symb<10;symb++) { k = (frame_parms->ofdm_symbol_size<<1)-72; // printf("Generating PSBCH in symbol %d offset %d\n",symb, // (subframe*Nsymb*frame_parms->ofdm_symbol_size)+(symb*frame_parms->ofdm_symbol_size)); txptr = (int16_t*)&txdataF[0][(subframe*Nsymb*frame_parms->ofdm_symbol_size)+(symb*frame_parms->ofdm_symbol_size)]; // first half (negative frequencies) for (int i=0;i<72;i++,j++,k++) txptr[k] = precout[j]; // second half (positive frequencies) for (int i=0,k=0;i<72;i++,j++,k++) txptr[k] = precout[j]; if (symb==0) symb+=3; } // scale by sqrt(72/62) // note : we have to scale for TX power requirements too, beta_PSBCH ! // //printf("[PSS] amp=%d, a=%d\n",amp,a); return(0); } int rx_psbch(PHY_VARS_UE *ue) { int16_t **rxdataF = ue->sl_rxdataF; int16_t **rxdataF_ext = ue->pusch_slbch->rxdataF_ext; int16_t **drs_ch_estimates = ue->pusch_sldch->drs_ch_estimates; int16_t **rxdataF_comp = ue->pusch_sldch->rxdataF_comp; int16_t **ul_ch_mag = ue->pusch_sldch->ul_ch_mag; int32_t avgs; uint8_t log2_maxh=0; int32_t avgU[2]; int Nsymb=7; RU_t ru_tmp; memset((void*)&ru_tmp,0,sizeof(RU_t)); memcpy((void*)&ru_tmp.frame_parms,(void*)&ue->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); ru_tmp.N_TA_offset=0; ru_tmp.common.rxdata_7_5kHz = (int32_t**)malloc16(ue->frame_parms.nb_antennas_rx*sizeof(int32_t*)); for (int aa=0;aa<ue->frame_parms.nb_antennas_rx;aa++) ru_tmp.common.rxdata_7_5kHz[aa] = (int32_t*)&ue->common_vars.rxdata_syncSL[aa][ue->rx_offsetSL*2]; ru_tmp.common.rxdataF = (int32_t**)rxdataF; ru_tmp.nb_rx = ue->frame_parms.nb_antennas_rx; LOG_I(PHY,"Running PBCH detection with Nid_SL %d\n",ue->frame_parms.Nid_SL); for (int l=0; l<11; l++) { slot_fep_ul(&ru_tmp,l%7,(l>6)?1:0,0); ulsch_extract_rbs_single((int32_t**)rxdataF, (int32_t**)rxdataF_ext, (ue->frame_parms.N_RB_UL/2)-3, 6, l, 0, &ue->frame_parms); if (l==0) l+=2; } #ifdef PSBCH_DEBUG write_output("slbch_rxF.m", "slbchrxF", &rxdataF[0][0], 14*ue->frame_parms.ofdm_symbol_size,1,1); write_output("slbch_rxF_ext.m","slbchrxF_ext",rxdataF_ext[0],14*12*ue->frame_parms.N_RB_DL,1,1); #endif lte_ul_channel_estimation(&ue->frame_parms, (int32_t**)drs_ch_estimates, (int32_t**)NULL, (int32_t**)rxdataF_ext, 6, 0, 0, ue->gh[0][0], //u 0, //v (ue->frame_parms.Nid_SL>>1)&7, //cyclic_shift 3, 1, // interpolation 0); lte_ul_channel_estimation(&ue->frame_parms, (int32_t**)drs_ch_estimates, (int32_t**)NULL, (int32_t**)rxdataF_ext, 6, 0, 0, ue->gh[0][1],//u 0,//v (ue->frame_parms.Nid_SL>>1)&7,//cyclic_shift, 10, 1, // interpolation 0); ulsch_channel_level(drs_ch_estimates, &ue->frame_parms, avgU, 2); #ifdef PSBCH_DEBUG write_output("drsbch_ext0.m","drsbchest0",drs_ch_estimates[0],ue->frame_parms.N_RB_UL*12*14,1,1); #endif avgs = 0; for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) avgs = cmax(avgs,avgU[aarx]); // log2_maxh = 4+(log2_approx(avgs)/2); log2_maxh = (log2_approx(avgs)/2)+ log2_approx(ue->frame_parms.nb_antennas_rx-1)+4; for (int l=0; l<10; l++) { ulsch_channel_compensation( rxdataF_ext, drs_ch_estimates, ul_ch_mag, NULL, rxdataF_comp, &ue->frame_parms, l, 2, //Qm 6, //nb_rb log2_maxh); // log2_maxh+I0_shift if (ue->frame_parms.nb_antennas_rx > 1) ulsch_detection_mrc(&ue->frame_parms, rxdataF_comp, ul_ch_mag, NULL, l, 6 //nb_rb ); freq_equalization(&ue->frame_parms, rxdataF_comp, ul_ch_mag, NULL, l, 72, 2); if (l==0) l=3; } lte_idft(&ue->frame_parms, rxdataF_comp[0], 72); #ifdef PSBCH_DEBUG write_output("slbch_rxF_comp.m","slbchrxF_comp",rxdataF_comp[0],ue->frame_parms.N_RB_UL*12*14,1,1); #endif int8_t llr[PSBCH_E]; int8_t *llrp = llr; for (int l=0; l<10; l++) { pbch_quantize(llrp, &rxdataF_comp[0][l*ue->frame_parms.N_RB_UL*12*2], 72*2); llrp += 72*2; if (l==0) l=3; } pbch_unscrambling(&ue->frame_parms, llr, PSBCH_E, 0, 1); #ifdef PSBCH_DEBUG write_output("slbch_llr.m","slbch_llr",llr,PSBCH_E,1,4); #endif uint8_t slbch_a[2+(PSBCH_A>>3)]; uint32_t psbch_D; uint8_t psbch_d_rx[96+(3*(16+PSBCH_A))]; uint8_t dummy_w_rx[3*3*(16+PSBCH_A)]; uint8_t psbch_w_rx[3*3*(16+PSBCH_A)]; uint8_t *psbch_e_rx=llr; uint8_t RCC; int a; uint8_t *decoded_output = ue->slss_rx.slmib; psbch_D = 16+PSBCH_A; memset(dummy_w_rx,0,3*3*(psbch_D)); RCC = generate_dummy_w_cc(psbch_D, dummy_w_rx); lte_rate_matching_cc_rx(RCC,PSBCH_E,psbch_w_rx,dummy_w_rx,psbch_e_rx); sub_block_deinterleaving_cc(psbch_D, &psbch_d_rx[96], &psbch_w_rx[0]); memset(slbch_a,0,((16+PSBCH_A)>>3)); phy_viterbi_lte_sse2(psbch_d_rx+96,slbch_a,16+PSBCH_A); // Fix byte endian of PSBCH (bit 39 goes in first) for (int i=0; i<(PSBCH_A>>3); i++) decoded_output[(PSBCH_A>>3)-i-1] = slbch_a[i]; // for (int i=0; i<(PSBCH_A>>3); i++) printf("SLBCH %d : %x\n",i,decoded_output[i]); #ifdef DEBUG_PSBCH LOG_I(PHY,"PSBCH CRC %x : %x\n", crc16(slbch_a,PSBCH_A), ((uint16_t)slbch_a[PSBCH_A>>3]<<8)+slbch_a[(PSBCH_A>>3)+1]); #endif uint16_t crc = (crc16(slbch_a,PSBCH_A)>>16) ^ (((uint16_t)slbch_a[PSBCH_A>>3]<<8)+slbch_a[(PSBCH_A>>3)+1]); if (crc>0) return(-1); else return(0); }