/*
 * 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/sldch.c
 * \brief Functions to Generate and Receive PSDCH
 * \author R. Knopp
 * \date 2017
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr
 * \note
 * \warning
 */
#ifndef __LTE_TRANSPORT_SLSS__C__
#define __LTE_TRANSPORT_SLSS__C__
#include "PHY/defs.h"
#include "PHY/LTE_TRANSPORT/proto.h"

void sldch_decoding(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,int frame_rx,int subframe_rx,int npsdch,int nprb,int rvidx) {

  int Nsymb = 7;
  int16_t **rxdataF_ext      = (int16_t**)ue->pusch_sldch->rxdataF_ext;
  int16_t **drs_ch_estimates = (int16_t**)ue->pusch_sldch->drs_ch_estimates;
  int16_t **rxdataF_comp     = (int16_t**)ue->pusch_sldch->rxdataF_comp;
  int16_t **ul_ch_mag        = (int16_t**)ue->pusch_sldch->ul_ch_mag;
  int16_t **rxdata_7_5kHz    = (int16_t**)ue->sl_rxdata_7_5kHz;
  int16_t **rxdataF          = (int16_t**)ue->sl_rxdataF;
  int32_t avgs;
  uint8_t log2_maxh=0;
  int32_t avgU[2];


  LOG_I(PHY,"sldch_decoding %d.%d npsdch %d rvidx %d sl_fep_done %d\n",frame_rx,subframe_rx,npsdch,rvidx,proc->sl_fep_done);

  // slot FEP
  if (proc->sl_fep_done == 0) {
    proc->sl_fep_done = 1;
    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 = ue->common_vars.rxdata;
    ru_tmp.common.rxdata_7_5kHz = (int32_t**)rxdata_7_5kHz;
    ru_tmp.common.rxdataF = (int32_t**)rxdataF;
    ru_tmp.nb_rx = ue->frame_parms.nb_antennas_rx;
    
    remove_7_5_kHz(&ru_tmp,(subframe_rx<<1));
    remove_7_5_kHz(&ru_tmp,(subframe_rx<<1)+1);

    // extract symbols from slot  
    for (int l=0; l<Nsymb; l++) {
      slot_fep_ul(&ru_tmp,l,(subframe_rx<<1),0);
      if (l<Nsymb-1)  // skip last symbol in second slot
	slot_fep_ul(&ru_tmp,l,(subframe_rx<<1)+1,0);
    }
  }
   LOG_I(PHY,"sldch_decoding: FEP for npsdch %d rvidx %d rx signal energy %d dB %d dB\n",npsdch,rvidx,
         dB_fixed(signal_energy(&ue->common_vars.rxdata[0][ue->frame_parms.samples_per_tti*subframe_rx],ue->frame_parms.samples_per_tti)),
         dB_fixed(signal_energy(ue->sl_rxdata_7_5kHz,ue->frame_parms.samples_per_tti)));

  for (int l=0; l<Nsymb; l++) {
    ulsch_extract_rbs_single((int32_t**)rxdataF,
			     (int32_t**)rxdataF_ext,
			     nprb,
			     2,
			     l,
			     (subframe_rx<<1),
			     &ue->frame_parms);

    if (l<Nsymb-1)  // skip last symbol in second slot
      ulsch_extract_rbs_single((int32_t**)rxdataF,
			       (int32_t**)rxdataF_ext,
			       nprb,
			       2,
			       l,
			       (subframe_rx<<1)+1,
			       &ue->frame_parms);
    
  }

#ifdef PSDCH_DEBUG
  write_output("sldch_rxF.m",
	       "sldchrxF",
	       &rxdataF[0][0],
	       14*ue->frame_parms.ofdm_symbol_size,1,1);
  write_output("sldch_rxF_ext.m","sldchrxF_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,
			    2,
			    frame_rx,
			    subframe_rx,
			    0, //u
			    0, //v
			    0, //cyclic_shift
			    3,
			    0, // interpolation
			    0);

  lte_ul_channel_estimation(&ue->frame_parms,
			    (int32_t**)drs_ch_estimates,
			    (int32_t**)NULL,
			    (int32_t**)rxdataF_ext,
			    2,
			    frame_rx,
			    subframe_rx,
			    0,//u
			    0,//v
			    0,//cyclic_shift,
			    10,
			    0, // interpolation
			    0);

  ulsch_channel_level(drs_ch_estimates,
		      &ue->frame_parms,
		      avgU,
		      2);

#ifdef PSDCH_DEBUG
  write_output("drs_ext0.m","drsest0",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;

  LOG_I(PHY,"sldch_decoding %d.%d npsdch %d log2_maxh %d\n",frame_rx,subframe_rx,npsdch);



  for (int l=0; l<(Nsymb<<1)-1; l++) {

    if (((ue->frame_parms.Ncp == 0) && ((l==3) || (l==10)))||   // skip pilots
        ((ue->frame_parms.Ncp == 1) && ((l==2) || (l==8)))) {
      l++;
    }

    ulsch_channel_compensation(
			       (int32_t**)rxdataF_ext,
			       (int32_t**)drs_ch_estimates,
			       (int32_t**)ul_ch_mag,
			       NULL,
			       (int32_t**)rxdataF_comp,
			       &ue->frame_parms,
			       l,
			       2, //Qm
			       2, //nb_rb
			       log2_maxh); // log2_maxh+I0_shift

    if (ue->frame_parms.nb_antennas_rx > 1)
      ulsch_detection_mrc(&ue->frame_parms,
			  (int32_t**)rxdataF_comp,
			  (int32_t**)ul_ch_mag,
			  NULL,
			  l,
			  2 //nb_rb
			  );
    
    freq_equalization(&ue->frame_parms,
		      (int32_t**)rxdataF_comp,
		      (int32_t**)ul_ch_mag,
		      NULL,
		      l,
		      24,
		      2);
  
  }
  lte_idft(&ue->frame_parms,
           rxdataF_comp[0],
           24);

#ifdef PSDCH_DEBUG
  write_output("sldch_rxF_comp.m","sldchrxF_comp",rxdataF_comp[0],ue->frame_parms.N_RB_UL*12*14,1,1);
#endif

  int E = 12*2*2*((Nsymb-1)<<1);

  int16_t *llrp = ue->slsch_ulsch_llr;

  for (int l=0; l<(Nsymb<<1)-1; l++) {

    if (((ue->frame_parms.Ncp == 0) && ((l==3) || (l==10)))||   // skip pilots
        ((ue->frame_parms.Ncp == 1) && ((l==2) || (l==8)))) {
      l++;
    }

    ulsch_qpsk_llr(&ue->frame_parms,
		   (int32_t **)rxdataF_comp,
		   (int16_t *)ue->slsch_ulsch_llr,
		   l,
		   2,
		   &llrp);
  }
 /* 
  write_output("sldch_llr.m","sldchllr",ue->sldch_ulsch_llr[npsdch],
               12*2*(ue->frame_parms.symbols_per_tti),
               1,0);
  */

  // unscrambling

  uint32_t x1,x2=510;

  uint32_t s = lte_gold_generic(&x1, &x2, 1);
  int k=0;
  int16_t c;

  

  for (int i=0; i<(1+(E>>5)); i++) {
    for (int j=0; j<32; j++,k++) {
        c = (int16_t)((((s>>j)&1)<<1)-1);
        ue->sldch_ulsch_llr[k] = c*ue->sldch_ulsch_llr[k];
    }    
    s = lte_gold_generic(&x1, &x2, 0);
  }

  // Deinterleaving

  int Cmux = (Nsymb-1)*2;
  for (int i=0,j=0;i<Cmux;i++) {
    for (int r=0;r<24;r++) {
      ue->sldch_dlsch_llr[((r*Cmux)+i)<<1]     = ue->sldch_ulsch_llr[j++];
      ue->sldch_dlsch_llr[(((r*Cmux)+i)<<1)+1] = ue->sldch_ulsch_llr[j++];
      //	printf("dlsch_llr[%d] %d(%d) dlsch_llr[%d] %d(%d)\n",
      //	       ((r*Cmux)+i)<<1,ue->slsch_dlsch_llr[((r*Cmux)+i)<<1],j-2,(((r*Cmux)+i)<<1)+1,ue->slsch_dlsch_llr[(((r*Cmux)+i)<<1)+1],j-1);
    }
  }


  // Decoding

  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->rvidx = rvidx;
  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->nb_rb = 2;
  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->TBS   = 256;
  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->Qm    = 2;
  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->G     = E;
  ue->dlsch_rx_sldch[npsdch]->harq_processes[0]->Nl    = 1;

  //  for (int i=0;i<E/16;i++) printf("decoding: E[%d] %d\n",i,ue->slsch_dlsch_llr[i]);

  int ret = dlsch_decoding(ue,
			   ue->sldch_dlsch_llr,
			   &ue->frame_parms,
			   ue->dlsch_rx_sldch[npsdch],
			   ue->dlsch_rx_sldch[npsdch]->harq_processes[0],
			   frame_rx,
			   subframe_rx,
			   0,
			   0,
			   1);

//  printf("slsch decoding round %d ret %d\n",ue->dlsch_rx_sldch->harq_processes[0]->round,ret);
  if (ret<ue->dlsch_rx_sldch[npsdch]->max_turbo_iterations) {
    LOG_I(PHY,"SLDCH received for npsdch %d (rvidx %d, iter %d)\n",
	  npsdch,
	  rvidx,ret);
  }

}

void rx_sldch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, int frame_rx,int subframe_rx) {

  SLDCH_t *sldch = &ue->sldch_rx;

  AssertFatal(frame_rx<1024 && frame_rx>=0,"frame %d is illegal\n",frame_rx);
  AssertFatal(subframe_rx<10 && subframe_rx>=0,"subframe %d is illegal\n",subframe_rx);
  AssertFatal(sldch!=NULL,"SLDCH is null\n");

  uint32_t O = sldch->offsetIndicator;
  uint32_t P = sldch->discPeriod;
  uint32_t absSF = (frame_rx*10)+subframe_rx;
  uint32_t absSF_offset,absSF_modP;
  int rvtab[4]={0,2,3,1};

  absSF_offset = absSF-O;

  if (absSF_offset < O) return;

  absSF_modP = absSF_offset%P;
  // compute parameters
  AssertFatal(sldch->bitmap_length==4 || sldch->bitmap_length==8 ||
              sldch->bitmap_length==12 || sldch->bitmap_length==16 ||
              sldch->bitmap_length==30 || sldch->bitmap_length==40 ||
              sldch->bitmap_length==42,"SLDCH Bitmap_length %x not supported\n",
              sldch->bitmap_length);

  if (absSF_modP >= sldch->bitmap_length) return;
  uint64_t SFpos = ((uint64_t)1) << absSF_modP;
  if ((SFpos & sldch->bitmap1) == 0) return;

  // if we get here, then there is a PSDCH subframe for a potential reception

  // compute parameters
  AssertFatal(sldch->bitmap_length==4 || sldch->bitmap_length==8 ||
	      sldch->bitmap_length==12 || sldch->bitmap_length==16 ||
	      sldch->bitmap_length==30 || sldch->bitmap_length==40 ||
	      sldch->bitmap_length==42,"SLDCH Bitmap_length %x not supported\n",
	      sldch->bitmap_length);

  int LPSDCH=0;
  for (int i=0;i<sldch->bitmap_length;i++) if (((((uint64_t)1)<<i)&sldch->bitmap1) > 00) LPSDCH++;
  
  AssertFatal(sldch->type == disc_type1 || sldch->type == disc_type2B,
	      "unknown Discovery type %d\n",sldch->type);

  int N_TX_SLD = 1+sldch->numRetx;
  uint32_t M_RB_PSDCH_RP = sldch->N_SL_RB;

  if (sldch->type == disc_type1) {
    int Ni = LPSDCH/N_TX_SLD;
    int Nf = M_RB_PSDCH_RP>>1;
    //    int a_ji = (((sldch->j-1)*(Nf/N_TX_SLD)) + (sldch->n_psdch/Ni))%Nf;
    //    int b_1i = sldch->n_psdch%Ni;
    // repetition number
    int jrx;    
    int npsdch;
    int nprb;

    LOG_I(PHY,"LPSDCH %d (%llx), N_TX_SLD %d, Ni %d, Nf %d\n",LPSDCH,sldch->bitmap1,N_TX_SLD,Ni,Nf); 
    // loop over all candidate PRBs 
    for (int a_ji=0;a_ji<Nf;a_ji++){
      jrx = absSF_modP%N_TX_SLD;//i/(Nf/N_TX_SLD);
      // b_1= absSF_ModP/N_TX_SLD
      npsdch = Ni*((a_ji+Nf-(jrx*Nf/N_TX_SLD))%Nf) + ((absSF_modP/N_TX_SLD)%Ni);
      nprb = a_ji<<1;
      if (nprb<(sldch->N_SL_RB>>1)) nprb+=sldch->prb_Start;
      else                          nprb+=(sldch->prb_End-(sldch->N_SL_RB>>1));
      // call decoding for candidate npsdch
      LOG_I(PHY,"SLDCH (RX): absSF_modP %d Trying npsdch %d, j %d rvidx %d (nprb %d)\n",absSF_modP,npsdch,jrx,rvtab[jrx],nprb);
      sldch_decoding(ue,proc,frame_rx,subframe_rx,npsdch,nprb,rvtab[jrx]);
    }

  }
  else {
    AssertFatal(1==0,"Discovery Type 2B not supported yet\n");
  }
}

void generate_sldch(PHY_VARS_UE *ue,SLDCH_t *sldch,int frame_tx,int subframe_tx) {

  UE_tport_t pdu;
  size_t sldch_header_len = sizeof(UE_tport_header_t);

  pdu.header.packet_type = SLDCH;
  pdu.header.absSF = (frame_tx*10)+subframe_tx;


  AssertFatal(sldch->payload_length <=1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*),
                "SLDCH payload length > %lu\n",
                1500-sldch_header_len - sizeof(SLDCH_t) + sizeof(uint8_t*));
  memcpy((void*)&pdu.sldch,
         (void*)sldch,
         sizeof(SLDCH_t));

  LOG_I(PHY,"SLDCH configuration %lu bytes, TBS payload %d bytes => %lu bytes\n",
        sizeof(SLDCH_t)-sizeof(uint8_t*),
        sldch->payload_length,
        sldch_header_len+sizeof(SLDCH_t)-sizeof(uint8_t*)+sldch->payload_length);

  multicast_link_write_sock(0,
                            &pdu,
                            sldch_header_len+sizeof(SLDCH_t));

}


#endif

void sldch_codingmodulation(PHY_VARS_UE *ue,int frame_tx,int subframe_tx,int nprb,int rvidx) {

  SLDCH_t *sldch         = ue->sldch;
  LTE_eNB_DLSCH_t *dlsch = ue->dlsch_sldch;
  LTE_UE_ULSCH_t *ulsch  = ue->ulsch_sldch;
  int tx_amp;
  uint32_t Nsymb = 7;
  // 24 REs/PRB * 2*(Nsymb-1) symbols * 2 bits/RE 

  AssertFatal(sldch!=NULL,"ue->sldch is null\n");
  



  LOG_I(PHY,"Generating SLDCH for rvidx %d, npsdch %d, first rb %d\n",
	rvidx,sldch->n_psdch,nprb);

  dlsch->harq_processes[0]->nb_rb       = 2;
  dlsch->harq_processes[0]->TBS         = 256;
  dlsch->harq_processes[0]->Qm          = 2;
  dlsch->harq_processes[0]->mimo_mode   = SISO;
  dlsch->harq_processes[0]->rb_alloc[0] = 0; // unused for SL
  dlsch->harq_processes[0]->rb_alloc[1] = 0; // unused for SL
  dlsch->harq_processes[0]->rb_alloc[2] = 0; // unused for SL
  dlsch->harq_processes[0]->rb_alloc[3] = 0; // unused for SL
  dlsch->harq_processes[0]->Nl          = 1;
  dlsch->harq_processes[0]->round       = sldch->j; 
  dlsch->harq_processes[0]->rvidx       = rvidx;

  dlsch_encoding0(&ue->frame_parms,
		 sldch->payload,
		 0, // means SL
		 dlsch,
		 frame_tx,
		 subframe_tx,
		 &ue->ulsch_rate_matching_stats,
		 &ue->ulsch_turbo_encoding_stats,
		 &ue->ulsch_interleaving_stats);

  int Cmux = (Nsymb-1)<<1;
  uint8_t *eptr;
  for (int i=0,j=0; i<Cmux; i++)
    // 24 = 12*(Nsymb-1)*2/(Nsymb-1)
    for (int r=0; r<24; r++) {
       if (dlsch->harq_processes[0]->Qm == 2) {
           eptr=&dlsch->harq_processes[0]->e[((r*Cmux)+i)<<1];
           ulsch->h[j++] = *eptr++;
           ulsch->h[j++] = *eptr++;
       }
       else if (dlsch->harq_processes[0]->Qm == 4) {
           eptr=&dlsch->harq_processes[0]->e[((r*Cmux)+i)<<2];
           ulsch->h[j++] = *eptr++;
           ulsch->h[j++] = *eptr++;
           ulsch->h[j++] = *eptr++;
           ulsch->h[j++] = *eptr++;
       }
       else {
            AssertFatal(1==0,"64QAM not supported for SL\n");
       }
    }

  // scrambling
  uint32_t cinit=510;

  ulsch->harq_processes[0]->nb_rb       = 2;
  ulsch->harq_processes[0]->first_rb    = nprb;
  ulsch->harq_processes[0]->mcs         = 8;
  ulsch->Nsymb_pusch                    = ((Nsymb-1)<<1);

  ue->sl_chan = PSDCH;

  ue->tx_power_dBm[subframe_tx] = 3;
  ue->tx_total_RE[subframe_tx] = 24;
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
  tx_amp = get_tx_amp(ue->tx_power_dBm[subframe_tx],
		      ue->tx_power_max_dBm,
		      ue->frame_parms.N_RB_UL,
		      2);
#else
  tx_amp = AMP;
#endif  

  if (ue->generate_ul_signal[subframe_tx][0] == 0) 
    for (int aa=0; aa<ue->frame_parms.nb_antennas_tx; aa++) {
      memset(&ue->common_vars.txdataF[aa][subframe_tx*ue->frame_parms.ofdm_symbol_size*ue->frame_parms.symbols_per_tti],
	     0,
	     ue->frame_parms.ofdm_symbol_size*ue->frame_parms.symbols_per_tti*sizeof(int32_t));
    }
 
  ulsch_modulation(ue->common_vars.txdataF,
		   tx_amp,
		   frame_tx,
                   subframe_tx,
		   &ue->frame_parms,
                   ulsch,
                   1,
                   cinit);

  generate_drs_pusch(ue,
		     NULL,
		     0,
		     tx_amp,
		     subframe_tx,
		     nprb,
		     2,
                     0,
                     NULL,
                     0);

  ue->generate_ul_signal[subframe_tx][0] = 1;

}
  
void check_and_generate_psdch(PHY_VARS_UE *ue,int frame_tx,int subframe_tx) {
  
  AssertFatal(frame_tx<1024 && frame_tx>=0,"frame %d is illegal\n",frame_tx);
  AssertFatal(subframe_tx<10 && subframe_tx>=0,"subframe %d is illegal\n",subframe_tx);
  
  SLDCH_t *sldch = ue->sldch;
  AssertFatal(sldch!=NULL,"SLDCH is null\n");
  uint32_t O = ue->sldch->offsetIndicator;
  uint32_t P = ue->sldch->discPeriod;
  uint32_t absSF = (frame_tx*10)+subframe_tx;
  uint32_t absSF_offset,absSF_modP;


  absSF_offset = absSF-O;

  if (absSF_offset < O) return;

  if (absSF_offset == 0) sldch->j = 0;

  absSF_modP = absSF_offset%P;

  uint64_t SFpos = ((uint64_t)1) << absSF_modP;
  LOG_D(PHY,"SLDCH: SFN.SF %d.%d : absSF_modP %d, bitmap1 %llx\n",frame_tx,subframe_tx,absSF_modP,sldch->bitmap1);

  if ((SFpos & sldch->bitmap1) == 0) return;

  // if we get here, then this is a potential PSDCH subframe 

  int rvtab[4] = {0,2,3,1};

  int rvidx = rvtab[sldch->j&3];
  int nprb;

  // compute parameters
  AssertFatal(sldch->bitmap_length==4 || sldch->bitmap_length==8 ||
	      sldch->bitmap_length==12 || sldch->bitmap_length==16 ||
	      sldch->bitmap_length==30 || sldch->bitmap_length==40 ||
	      sldch->bitmap_length==42,"SLDCH Bitmap_length %x not supported\n",
	      sldch->bitmap_length);

  int LPSDCH=0;
  for (int i=0;i<sldch->bitmap_length;i++) if (((((uint64_t)1)<<i)&sldch->bitmap1) >0) LPSDCH++;

  AssertFatal(LPSDCH>0,"LPSDCH is 0 (bitmap1 %lx, bitmap_length %d)\n",sldch->bitmap1,sldch->bitmap_length);
  AssertFatal(sldch->type == disc_type1 || sldch->type == disc_type2B,
	      "unknown Discovery type %d\n",sldch->type);

  int N_TX_SLD = 1+sldch->numRetx;
  uint32_t M_RB_PSDCH_RP = sldch->N_SL_RB;
  unsigned int Ni,Nf; 
  if (sldch->type == disc_type1) {
    Ni = LPSDCH/N_TX_SLD;
    Nf = M_RB_PSDCH_RP>>1;
    if (ue->is_SynchRef == 0) sldch->n_psdch = 2; //taus()%(Ni*Nf);
    int a_ji = ((sldch->j*(Nf/N_TX_SLD)) + (sldch->n_psdch/Ni))%Nf;
    
    int b_1i = sldch->n_psdch%Ni;

    if (absSF_modP != ((b_1i*N_TX_SLD)+sldch->j)) return;
    
    nprb = 2*a_ji;
  LOG_I(PHY,"Generating SLDCH in SFN.SF %d.%d (O %d, P %d, n_psdch %d, Nf %d, Ni %d, j %d, a_ji %d) \n",frame_tx,subframe_tx,O,P,sldch->n_psdch,Nf,Ni,sldch->j,a_ji);

  }
  else {
    AssertFatal(1==0,"Discovery Type 2B not supported yet\n");
  }


  if (nprb <(sldch->N_SL_RB>>1)) nprb+=sldch->prb_Start;
  else                           nprb+=(sldch->prb_End-(sldch->N_SL_RB>>1));

  sldch_codingmodulation(ue,frame_tx,subframe_tx,nprb,rvidx);
  ue->psdch_generated=1;
  sldch->j++;
  sldch->j&=3;
}