/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2011 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fsr/openairinterface
  Address      : Eurecom, 2229, route des crĂȘtes, 06560 Valbonne Sophia Antipolis, France

*******************************************************************************/

/*! \file PHY/LTE_TRANSPORT/pucch.c
* \brief Top-level routines for generating and decoding the PUCCH physical channel V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "LAYER2/MAC/extern.h"

//uint8_t ncs_cell[20][7];
//#define DEBUG_PUCCH_TX
//#define DEBUG_PUCCH_RX

int16_t cfo_pucch_np[24*7] = {20787,-25330,27244,-18205,31356,-9512,32767,0,31356,9511,27244,18204,20787,25329,
			  27244,-18205,30272,-12540,32137,-6393,32767,0,32137,6392,30272,12539,27244,18204,
			  31356,-9512,32137,-6393,32609,-3212,32767,0,32609,3211,32137,6392,31356,9511,
			  32767,0,32767,0,32767,0,32767,0,32767,0,32767,0,32767,0,
			  31356,9511,32137,6392,32609,3211,32767,0,32609,-3212,32137,-6393,31356,-9512,
			  27244,18204,30272,12539,32137,6392,32767,0,32137,-6393,30272,-12540,27244,-18205,
			  20787,25329,27244,18204,31356,9511,32767,0,31356,-9512,27244,-18205,20787,-25330};

int16_t cfo_pucch_ep[24*6] = {24278,-22005,29621,-14010,32412,-4808,32412,4807,29621,14009,24278,22004,
			  28897,-15447,31356,-9512,32609,-3212,32609,3211,31356,9511,28897,15446,
			  31785,-7962,32412,-4808,32727,-1608,32727,1607,32412,4807,31785,7961,
			  32767,0,32767,0,32767,0,32767,0,32767,0,32767,0,
			  31785,7961,32412,4807,32727,1607,32727,-1608,32412,-4808,31785,-7962,
			  28897,15446,31356,9511,32609,3211,32609,-3212,31356,-9512,28897,-15447,
			  24278,22004,29621,14009,32412,4807,32412,-4808,29621,-14010,24278,-22005};


void init_ncs_cell(LTE_DL_FRAME_PARMS *frame_parms,uint8_t ncs_cell[20][7]) {

  uint8_t ns,l,reset=1,i,N_UL_symb;
  uint32_t x1,x2,j=0,s=0;
  
  N_UL_symb = (frame_parms->Ncp==0) ? 7 : 6;
  x2 = frame_parms->Nid_cell;

  for (ns=0;ns<20;ns++) {

    for (l=0;l<N_UL_symb;l++) {
      ncs_cell[ns][l]=0;

      for (i=0;i<8;i++) {
	if ((j%32) == 0) {
	  s = lte_gold_generic(&x1,&x2,reset);
	  //	  printf("s %x\n",s);
	  reset=0;
	}
	if (((s>>(j%32))&1)==1)
	  ncs_cell[ns][l] += (1<<i);
	j++;
      }
#ifdef DEBUG_PUCCH_TX
      msg("[PHY] PUCCH ncs_cell init (j %d): Ns %d, l %d => ncs_cell %d\n",j,ns,l,ncs_cell[ns][l]);
#endif
    }

  }
}

int16_t alpha_re[12] = {32767, 28377, 16383,     0,-16384,  -28378,-32768,-28378,-16384,    -1, 16383, 28377};
int16_t alpha_im[12] = {0,     16383, 28377, 32767, 28377,   16383,     0,-16384,-28378,-32768,-28378,-16384};

int16_t W4[3][4] = {{32767, 32767, 32767, 32767},
		{32767,-32768, 32767,-32768},
		{32767,-32768,-32768, 32767}};
int16_t W3_re[3][6] = {{32767, 32767, 32767},
		   {32767,-16384,-16384},
		   {32767,-16384,-16384}};

int16_t W3_im[3][6] = {{0    ,0     ,0     },
		   {0    , 28377,-28378},
		   {0    ,-28378, 28377}};

char pucch_format_string[6][20] = {"format 1\0","format 1a\0","format 1b\0","format 2\0","format 2a\0","format 2b\0"};

void generate_pucch(mod_sym_t **txdataF,
		    LTE_DL_FRAME_PARMS *frame_parms,
		    uint8_t ncs_cell[20][7],
		    PUCCH_FMT_t fmt,
		    PUCCH_CONFIG_DEDICATED *pucch_config_dedicated,
		    uint16_t n1_pucch,
		    uint16_t n2_pucch,
		    uint8_t shortened_format,
		    uint8_t *payload,
		    int16_t amp,
		    uint8_t subframe) {
  
  uint32_t u,v,n;
  uint32_t z[12*14],*zptr;
  int16_t d0;
  uint8_t ns,N_UL_symb,nsymb,n_oc,n_oc0,n_oc1;
  uint8_t c = (frame_parms->Ncp==0) ? 3 : 2;
  uint16_t nprime,nprime0,nprime1;
  uint16_t i,j,re_offset,thres,h;
  uint8_t Nprime_div_deltaPUCCH_Shift,Nprime,d;
  uint8_t m,l,refs;
  uint8_t n_cs,S,alpha_ind,rem;
  int16_t tmp_re,tmp_im,ref_re,ref_im,W_re=0,W_im=0;
  mod_sym_t *txptr;
  uint32_t symbol_offset;

  uint8_t deltaPUCCH_Shift          = frame_parms->pucch_config_common.deltaPUCCH_Shift;
  uint8_t NRB2                      = frame_parms->pucch_config_common.nRB_CQI;
  uint8_t Ncs1_div_deltaPUCCH_Shift = frame_parms->pucch_config_common.nCS_AN;

  uint32_t u0 = (frame_parms->Nid_cell + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[subframe<<1]) % 30;
  uint32_t u1 = (frame_parms->Nid_cell + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[1+(subframe<<1)]) % 30;
  uint32_t v0=frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[subframe<<1];
  uint32_t v1=frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)];
  
  if ((deltaPUCCH_Shift==0) || (deltaPUCCH_Shift>3)) {
    msg("[PHY] generate_pucch: Illegal deltaPUCCH_shift %d (should be 1,2,3)\n",deltaPUCCH_Shift);
    return;
  }

  if (NRB2 > 2047) {
    msg("[PHY] generate_pucch: Illegal NRB2 %d (should be 0...2047)\n",NRB2);
    return;
  }

  if (Ncs1_div_deltaPUCCH_Shift > 7) {
    msg("[PHY] generate_pucch: Illegal Ncs1_div_deltaPUCCH_Shift %d (should be 0...7)\n",Ncs1_div_deltaPUCCH_Shift);
    return;
  }

  zptr = z;
  thres = (c*Ncs1_div_deltaPUCCH_Shift);
  Nprime_div_deltaPUCCH_Shift = (n1_pucch < thres) ? Ncs1_div_deltaPUCCH_Shift : (12/deltaPUCCH_Shift);
  Nprime = Nprime_div_deltaPUCCH_Shift * deltaPUCCH_Shift;

#ifdef DEBUG_PUCCH_TX
  msg("[PHY] PUCCH: cNcs1/deltaPUCCH_Shift %d, Nprime %d, n1_pucch %d\n",thres,Nprime,n1_pucch);
#endif

  N_UL_symb = (frame_parms->Ncp==0) ? 7 : 6;

  if (n1_pucch < thres)
    nprime0=n1_pucch;
  else
    nprime0 = (n1_pucch - thres)%(12*c/deltaPUCCH_Shift); 
  
  if (n1_pucch >= thres)
    nprime1= ((c*(nprime0+1))%((12*c/deltaPUCCH_Shift)+1))-1;
  else {
    d = (frame_parms->Ncp==0) ? 2 : 0;
    h= (nprime0+d)%(c*Nprime_div_deltaPUCCH_Shift);
    nprime1 = (h/c) + (h%c)*Nprime_div_deltaPUCCH_Shift; 
  }

#ifdef DEBUG_PUCCH_TX
  msg("[PHY] PUCCH: nprime0 %d nprime1 %d, %s, payload (%d,%d)\n",nprime0,nprime1,pucch_format_string[fmt],payload[0],payload[1]);
#endif

  n_oc0 = nprime0/Nprime_div_deltaPUCCH_Shift;
  if (frame_parms->Ncp==1)
    n_oc0<<=1;

  n_oc1 = nprime1/Nprime_div_deltaPUCCH_Shift;
  if (frame_parms->Ncp==1)  // extended CP
    n_oc1<<=1;

#ifdef DEBUG_PUCCH_TX
  msg("[PHY] PUCCH: noc0 %d noc11 %d\n",n_oc0,n_oc1);
#endif

  nprime=nprime0;
  n_oc  =n_oc0;

  // loop over 2 slots
  for (ns=(subframe<<1),u=u0,v=v0;ns<(2+(subframe<<1));ns++,u=u1,v=v1) {

    if ((nprime&1) == 0)
      S=0;  // 1
    else
      S=1;  // j

    //loop over symbols in slot
    for (l=0;l<N_UL_symb;l++) {
      // Compute n_cs (36.211 p. 18)
      n_cs = ncs_cell[ns][l];
      if (frame_parms->Ncp==0) { // normal CP
	n_cs = ((uint16_t)n_cs + (nprime*deltaPUCCH_Shift + (n_oc%deltaPUCCH_Shift))%Nprime)%12;
      }
      else {
	n_cs = ((uint16_t)n_cs + (nprime*deltaPUCCH_Shift + (n_oc>>1))%Nprime)%12;	
      }


      refs=0;
      // Comput W_noc(m) (36.211 p. 19)
      if ((ns==(1+(subframe<<1))) && (shortened_format==1)) {  // second slot and shortened format

	if (l<2) {                                         // data
	  W_re=W3_re[n_oc][l];
	  W_im=W3_im[n_oc][l];
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==0)) { // reference and normal CP 
	  W_re=W3_re[n_oc][l-2];
	  W_im=W3_im[n_oc][l-2];
	  refs=1;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==1)) {  // reference and extended CP 
	  W_re=W4[n_oc][l-2];                          
	  W_im=0;
	  refs=1;
	}     
	else if ((l>=N_UL_symb-2)) {                        // data
	  W_re=W3_re[n_oc][l-N_UL_symb+4];
	  W_im=W3_im[n_oc][l-N_UL_symb+4];
	}
      }
      else {
	if (l<2) {                                         // data
	  W_re=W4[n_oc][l];
	  W_im=0;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==0)) { // reference and normal CP 
	  W_re=W3_re[n_oc][l-2];
	  W_im=W3_im[n_oc][l-2];
	  refs=1;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==1)) { // reference and extended CP 
	  W_re=W4[n_oc][l-2];
	  W_im=0;
	  refs=1;
	}
	else if ((l>=N_UL_symb-2)) {                       // data
	  W_re=W4[n_oc][l-N_UL_symb+4];
	  W_im=0;
	}
      }

      // multiply W by S(ns) (36.211 p.17). only for data, reference symbols do not have this factor  
      if ((S==1)&&(refs==0)) {
	tmp_re = W_re;
	W_re = -W_im;
	W_im = tmp_re;
      }

#ifdef DEBUG_PUCCH_TX
      msg("[PHY] PUCCH: ncs[%d][%d]=%d, W_re %d, W_im %d, S %d, refs %d\n",ns,l,n_cs,W_re,W_im,S,refs);
#endif
      alpha_ind=0;
	// compute output sequence

      for (n=0;n<12;n++) {

	// this is r_uv^alpha(n)
	tmp_re = (int16_t)(((int32_t)alpha_re[alpha_ind] * ul_ref_sigs[u][v][0][n<<1] - (int32_t)alpha_im[alpha_ind] * ul_ref_sigs[u][v][0][1+(n<<1)])>>15);
	tmp_im = (int16_t)(((int32_t)alpha_re[alpha_ind] * ul_ref_sigs[u][v][0][1+(n<<1)] + (int32_t)alpha_im[alpha_ind] * ul_ref_sigs[u][v][0][n<<1])>>15);

	// this is S(ns)*w_noc(m)*r_uv^alpha(n)
	ref_re = (tmp_re*W_re - tmp_im*W_im)>>15;
	ref_im = (tmp_re*W_im + tmp_im*W_re)>>15;

	if ((l<2)||(l>=(N_UL_symb-2))) { //these are PUCCH data symbols
	  switch (fmt) {
	  case pucch_format1:   //OOK 1-bit
	    
	    ((int16_t *)&zptr[n])[0] = ((int32_t)amp*ref_re)>>15;
	    ((int16_t *)&zptr[n])[1] = ((int32_t)amp*ref_im)>>15;
	    
	    break;
	    
	  case pucch_format1a:  //BPSK 1-bit
	    d0 = (payload[0]&1)==0 ? amp : -amp;
	    ((int16_t *)&zptr[n])[0] = ((int32_t)d0*ref_re)>>15;
	    ((int16_t *)&zptr[n])[1] = ((int32_t)d0*ref_im)>>15;
	    //	    printf("d0 %d\n",d0);
	    break;
	    
	  case pucch_format1b:  //QPSK 2-bits (Table 5.4.1-1 from 36.211, pg. 18)
	    if (((payload[0]&1)==0) && ((payload[1]&1)==0))  {// 1
	      ((int16_t *)&zptr[n])[0] = ((int32_t)amp*ref_re)>>15;
	      ((int16_t *)&zptr[n])[1] = ((int32_t)amp*ref_im)>>15;
	    }
	    else if (((payload[0]&1)==0) && ((payload[1]&1)==1))  {// -j
	      ((int16_t *)&zptr[n])[0] = ((int32_t)amp*ref_im)>>15;
	      ((int16_t *)&zptr[n])[1] = (-(int32_t)amp*ref_re)>>15;
	    }
	    else if (((payload[0]&1)==1) && ((payload[1]&1)==0))  {// j
	      ((int16_t *)&zptr[n])[0] = (-(int32_t)amp*ref_im)>>15;
	      ((int16_t *)&zptr[n])[1] = ((int32_t)amp*ref_re)>>15;
	    }
	    else  {// -1
	      ((int16_t *)&zptr[n])[0] = (-(int32_t)amp*ref_re)>>15;
	      ((int16_t *)&zptr[n])[1] = (-(int32_t)amp*ref_im)>>15;
	    }
	    break;
	    
	  case pucch_format2:
	    msg("[PHY] PUCCH format 2 not implemented\n");
	    break;
	    
	  case pucch_format2a:
	    msg("[PHY] PUCCH format 2a not implemented\n");
	    break;
	    
	  case pucch_format2b:
	    msg("[PHY] PUCCH format 2b not implemented\n");
	    break;
	  } // switch fmt
	}
	else {   // These are PUCCH reference symbols

	  ((int16_t *)&zptr[n])[0] = ((int32_t)amp*ref_re)>>15;
	  ((int16_t *)&zptr[n])[1] = ((int32_t)amp*ref_im)>>15;
	  //	  printf("ref\n");
	}
#ifdef DEBUG_PUCCH_TX
	msg("[PHY] PUCCH subframe %d z(%d,%d) => %d,%d, alpha(%d) => %d,%d\n",subframe,l,n,((int16_t *)&zptr[n])[0],((int16_t *)&zptr[n])[1],
	    alpha_ind,alpha_re[alpha_ind],alpha_im[alpha_ind]);
#endif
	alpha_ind = (alpha_ind + n_cs)%12;
      } // n
      zptr+=12;
    } // l

  nprime=nprime1;
  n_oc  =n_oc1;
  } // ns

  rem = ((((12*Ncs1_div_deltaPUCCH_Shift)>>3)&7)>0) ? 1 : 0;

  m = (n1_pucch < thres) ? NRB2 : (((n1_pucch-thres)/(12*c/deltaPUCCH_Shift))+NRB2+((deltaPUCCH_Shift*Ncs1_div_deltaPUCCH_Shift)>>3)+rem);

#ifdef DEBUG_PUCCH_TX
  msg("[PHY] PUCCH: m %d\n",m);
#endif
  nsymb = N_UL_symb<<1;

  //for (j=0,l=0;l<(nsymb-1);l++) {
  for (j=0,l=0;l<(nsymb);l++) {

    if ((l<(nsymb>>1)) && ((m&1) == 0))
      re_offset = (m*6) + frame_parms->first_carrier_offset;
    else if ((l<(nsymb>>1)) && ((m&1) == 1))
      re_offset = frame_parms->first_carrier_offset + (frame_parms->N_RB_DL - (m>>1) - 1)*12;
    else if ((m&1) == 0)
      re_offset = frame_parms->first_carrier_offset + (frame_parms->N_RB_DL - (m>>1) - 1)*12;
    else
      re_offset = ((m-1)*6) + frame_parms->first_carrier_offset;

    if (re_offset > frame_parms->ofdm_symbol_size)
      re_offset -= (frame_parms->ofdm_symbol_size);

    symbol_offset = (unsigned int)frame_parms->ofdm_symbol_size*(l+(subframe*nsymb));
    txptr = &txdataF[0][symbol_offset];

    for (i=0;i<12;i++,j++) {
      txptr[re_offset++] = z[j];
      if (re_offset==frame_parms->ofdm_symbol_size)
	re_offset = 0; 
#ifdef DEBUG_PUCCH_TX
      msg("[PHY] PUCCH subframe %d (%d,%d,%d,%d) => %d,%d\n",subframe,l,i,re_offset-1,m,((int16_t *)&z[j])[0],((int16_t *)&z[j])[1]);
#endif
    }
  }

}

void generate_pucch_emul(PHY_VARS_UE *phy_vars_ue,
			 PUCCH_FMT_t format,
			 uint8_t ncs1,
			 uint8_t *pucch_payload,
			 uint8_t sr,
			 uint8_t subframe) {

  UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.pucch_flag    = format;
  UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.pucch_Ncs1    = ncs1;


  UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.sr            = sr;
  // the value of phy_vars_ue->pucch_sel[subframe] is set by get_n1_pucch
  UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.pucch_sel      = phy_vars_ue->pucch_sel[subframe];
  
  // LOG_I(PHY,"subframe %d emu tx pucch_sel is %d sr is %d \n", subframe, UE_transport_info[phy_vars_ue->Mod_id].cntl.pucch_sel, sr);
  
  if (format == pucch_format1a) {
    
    phy_vars_ue->pucch_payload[0] = pucch_payload[0];
    UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.pucch_payload = pucch_payload[0];
  }
  else if (format == pucch_format1b) {
    phy_vars_ue->pucch_payload[0] = pucch_payload[0] + (pucch_payload[1]<<1);
    UE_transport_info[phy_vars_ue->Mod_id][phy_vars_ue->CC_id].cntl.pucch_payload = pucch_payload[0] + (pucch_payload[1]<<1);
  }
  else if (format == pucch_format1) {
    LOG_D(PHY,"[UE %d] Frame %d subframe %d Generating PUCCH for SR %d\n",phy_vars_ue->Mod_id,phy_vars_ue->frame,subframe,sr);
  }
  phy_vars_ue->sr[subframe] = sr; 

}

int32_t rx_pucch(PHY_VARS_eNB *phy_vars_eNB,
	     PUCCH_FMT_t fmt,
	     uint8_t UE_id,
	     uint16_t n1_pucch,
	     uint16_t n2_pucch,
	     uint8_t shortened_format,
	     uint8_t *payload,
	     uint8_t subframe,
	     uint8_t pucch1_thres) {


  LTE_eNB_COMMON *eNB_common_vars                = &phy_vars_eNB->lte_eNB_common_vars;
  LTE_DL_FRAME_PARMS *frame_parms                = &phy_vars_eNB->lte_frame_parms;
  //  PUCCH_CONFIG_DEDICATED *pucch_config_dedicated = &phy_vars_eNB->pucch_config_dedicated[UE_id];
  int8_t sigma2_dB                                   = phy_vars_eNB->PHY_measurements_eNB[0].n0_power_tot_dB;
  uint32_t u,v,n,aa;
  uint32_t z[12*14];
  int16_t *zptr;
  int16_t rxcomp[NB_ANTENNAS_RX][2*12*14];
  uint8_t ns,N_UL_symb,nsymb,n_oc,n_oc0,n_oc1;
  uint8_t c = (frame_parms->Ncp==0) ? 3 : 2;
  uint16_t nprime,nprime0,nprime1;
  uint16_t i,j,re_offset,thres,h,off;
  uint8_t Nprime_div_deltaPUCCH_Shift,Nprime,d;
  uint8_t m,l,refs,phase,re,l2,phase_max=0;
  uint8_t n_cs,S,alpha_ind,rem;
  int16_t tmp_re,tmp_im,W_re=0,W_im=0;
  int16_t *rxptr;
  uint32_t symbol_offset;
  int16_t stat_ref_re,stat_ref_im,*cfo,chest_re,chest_im;
  int32_t stat_re=0,stat_im=0;
  int32_t stat,stat_max=0;

  uint8_t deltaPUCCH_Shift          = frame_parms->pucch_config_common.deltaPUCCH_Shift;
  uint8_t NRB2                      = frame_parms->pucch_config_common.nRB_CQI;
  uint8_t Ncs1_div_deltaPUCCH_Shift = frame_parms->pucch_config_common.nCS_AN;

  uint32_t u0 = (frame_parms->Nid_cell + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[subframe<<1]) % 30;
  uint32_t u1 = (frame_parms->Nid_cell + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[1+(subframe<<1)]) % 30;
  uint32_t v0=frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[subframe<<1];
  uint32_t v1=frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)];


  if ((deltaPUCCH_Shift==0) || (deltaPUCCH_Shift>3)) {
    LOG_E(PHY,"[eNB] rx_pucch: Illegal deltaPUCCH_shift %d (should be 1,2,3)\n",deltaPUCCH_Shift);
    return(-1);
  }

  if (NRB2 > 2047) {
    LOG_E(PHY,"[eNB] rx_pucch: Illegal NRB2 %d (should be 0...2047)\n",NRB2);
    return(-1);
  }

  if (Ncs1_div_deltaPUCCH_Shift > 7) {
    LOG_E(PHY,"[eNB] rx_pucch: Illegal Ncs1_div_deltaPUCCH_Shift %d (should be 0...7)\n",Ncs1_div_deltaPUCCH_Shift);
    return(-1);
  }

  zptr = (int16_t *)z;
  thres = (c*Ncs1_div_deltaPUCCH_Shift);
  Nprime_div_deltaPUCCH_Shift = (n1_pucch < thres) ? Ncs1_div_deltaPUCCH_Shift : (12/deltaPUCCH_Shift);
  Nprime = Nprime_div_deltaPUCCH_Shift * deltaPUCCH_Shift;

#ifdef DEBUG_PUCCH_RX
  LOG_D(PHY,"[eNB] PUCCH: cNcs1/deltaPUCCH_Shift %d, Nprime %d, n1_pucch %d\n",thres,Nprime,n1_pucch);
#endif

  N_UL_symb = (frame_parms->Ncp==0) ? 7 : 6;

  if (n1_pucch < thres)
    nprime0=n1_pucch;
  else
    nprime0 = (n1_pucch - thres)%(12*c/deltaPUCCH_Shift); 
  
  if (n1_pucch >= thres)
    nprime1= ((c*(nprime0+1))%((12*c/deltaPUCCH_Shift)+1))-1;
  else {
    d = (frame_parms->Ncp==0) ? 2 : 0;
    h= (nprime0+d)%(c*Nprime_div_deltaPUCCH_Shift);
    nprime1 = (h/c) + (h%c)*Nprime_div_deltaPUCCH_Shift; 
  }

#ifdef DEBUG_PUCCH_RX
  LOG_D(PHY,"PUCCH: nprime0 %d nprime1 %d\n",nprime0,nprime1);
#endif

  n_oc0 = nprime0/Nprime_div_deltaPUCCH_Shift;
  if (frame_parms->Ncp==1)
    n_oc0<<=1;

  n_oc1 = nprime1/Nprime_div_deltaPUCCH_Shift;
  if (frame_parms->Ncp==1)  // extended CP
    n_oc1<<=1;

#ifdef DEBUG_PUCCH_RX
  LOG_D(PHY,"[eNB] PUCCH: noc0 %d noc11 %d\n",n_oc0,n_oc1);
#endif

  nprime=nprime0;
  n_oc  =n_oc0;

  // loop over 2 slots
  for (ns=(subframe<<1),u=u0,v=v0;ns<(2+(subframe<<1));ns++,u=u1,v=v1) {

    if ((nprime&1) == 0)
      S=0;  // 1
    else
      S=1;  // j

    //loop over symbols in slot
    for (l=0;l<N_UL_symb;l++) {
      // Compute n_cs (36.211 p. 18)
      n_cs = phy_vars_eNB->ncs_cell[ns][l];
      if (frame_parms->Ncp==0) { // normal CP
	n_cs = ((uint16_t)n_cs + (nprime*deltaPUCCH_Shift + (n_oc%deltaPUCCH_Shift))%Nprime)%12;
      }
      else {
	n_cs = ((uint16_t)n_cs + (nprime*deltaPUCCH_Shift + (n_oc>>1))%Nprime)%12;	
      }


      refs=0;
      // Comput W_noc(m) (36.211 p. 19)
      if ((ns==(1+(subframe<<1))) && (shortened_format==1)) {  // second slot and shortened format

	if (l<2) {                                         // data
	  W_re=W3_re[n_oc][l];
	  W_im=W3_im[n_oc][l];
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==0)) { // reference and normal CP 
	  W_re=W3_re[n_oc][l-2];
	  W_im=W3_im[n_oc][l-2];
	  refs=1;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==1)) {  // reference and extended CP 
	  W_re=W4[n_oc][l-2];                          
	  W_im=0;
	  refs=1;
	}     
	else if ((l>=N_UL_symb-2)) {                        // data
	  W_re=W3_re[n_oc][l-N_UL_symb+4];
	  W_im=W3_im[n_oc][l-N_UL_symb+4];
	}
      }
      else {
	if (l<2) {                                         // data
	  W_re=W4[n_oc][l];
	  W_im=0;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==0)) { // reference and normal CP 
	  W_re=W3_re[n_oc][l-2];
	  W_im=W3_im[n_oc][l-2];
	  refs=1;
	}
	else if ((l<N_UL_symb-2)&&(frame_parms->Ncp==1)) { // reference and extended CP 
	  W_re=W4[n_oc][l-2];
	  W_im=0;
	  refs=1;
	}
	else if ((l>=N_UL_symb-2)) {                       // data
	  W_re=W4[n_oc][l-N_UL_symb+4];
	  W_im=0;
	}
      }

      // multiply W by S(ns) (36.211 p.17). only for data, reference symbols do not have this factor  
      if ((S==1)&&(refs==0)) {
	tmp_re = W_re;
	W_re = -W_im;
	W_im = tmp_re;
      }

#ifdef DEBUG_PUCCH_RX
      LOG_D(PHY,"[eNB] PUCCH: ncs[%d][%d]=%d, W_re %d, W_im %d, S %d, refs %d\n",ns,l,n_cs,W_re,W_im,S,refs);
#endif
      alpha_ind=0;
	// compute output sequence

      for (n=0;n<12;n++) {

	// this is r_uv^alpha(n)
	tmp_re = (int16_t)(((int32_t)alpha_re[alpha_ind] * ul_ref_sigs[u][v][0][n<<1] - (int32_t)alpha_im[alpha_ind] * ul_ref_sigs[u][v][0][1+(n<<1)])>>15);
	tmp_im = (int16_t)(((int32_t)alpha_re[alpha_ind] * ul_ref_sigs[u][v][0][1+(n<<1)] + (int32_t)alpha_im[alpha_ind] * ul_ref_sigs[u][v][0][n<<1])>>15);

	// this is S(ns)*w_noc(m)*r_uv^alpha(n)
	zptr[n<<1] = (tmp_re*W_re - tmp_im*W_im)>>15;
	zptr[1+(n<<1)] = -(tmp_re*W_im + tmp_im*W_re)>>15;

#ifdef DEBUG_PUCCH_RX
	LOG_D(PHY,"[eNB] PUCCH subframe %d z(%d,%d) => %d,%d, alpha(%d) => %d,%d\n",subframe,l,n,zptr[n<<1],zptr[(n<<1)+1],
	    alpha_ind,alpha_re[alpha_ind],alpha_im[alpha_ind]);
#endif
	alpha_ind = (alpha_ind + n_cs)%12;
      } // n
      zptr+=24;
    } // l

  nprime=nprime1;
  n_oc  =n_oc1;
  } // ns

  rem = ((((deltaPUCCH_Shift*Ncs1_div_deltaPUCCH_Shift)>>3)&7)>0) ? 1 : 0;

  m = (n1_pucch < thres) ? NRB2 : (((n1_pucch-thres)/(12*c/deltaPUCCH_Shift))+NRB2+((deltaPUCCH_Shift*Ncs1_div_deltaPUCCH_Shift)>>3)+rem);

#ifdef DEBUG_PUCCH_RX
  LOG_D(PHY,"[eNB] PUCCH: m %d\n",m);
#endif
  nsymb = N_UL_symb<<1;

  zptr = (int16_t*)z;

  // Do detection
  for (aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
    
    //for (j=0,l=0;l<(nsymb-1);l++) {
    for (j=0,l=0;l<nsymb;l++) {
      if ((l<(nsymb>>1)) && ((m&1) == 0))
	re_offset = (m*6) + frame_parms->first_carrier_offset;
      else if ((l<(nsymb>>1)) && ((m&1) == 1))
	re_offset = frame_parms->first_carrier_offset + (frame_parms->N_RB_DL - (m>>1) - 1)*12;
      else if ((m&1) == 0)
	re_offset = frame_parms->first_carrier_offset + (frame_parms->N_RB_DL - (m>>1) - 1)*12;
      else
	re_offset = ((m-1)*6) + frame_parms->first_carrier_offset;
      
      if (re_offset > frame_parms->ofdm_symbol_size)
	re_offset -= (frame_parms->ofdm_symbol_size);
      
      symbol_offset = (unsigned int)frame_parms->ofdm_symbol_size*l;
#ifndef NEW_FFT
      rxptr = (int16_t *)&eNB_common_vars->rxdataF[0][aa][2*symbol_offset];
#else
      rxptr = (int16_t *)&eNB_common_vars->rxdataF[0][aa][symbol_offset];
#endif      
      for (i=0;i<12;i++,j+=2,re_offset++) {
#ifndef NEW_FFT	
	rxcomp[aa][j]   = (int16_t)((rxptr[re_offset<<2]*(int32_t)zptr[j])>>15)   - ((rxptr[1+(re_offset<<2)]*(int32_t)zptr[1+j])>>15);
	rxcomp[aa][1+j] = (int16_t)((rxptr[re_offset<<2]*(int32_t)zptr[1+j])>>15) + ((rxptr[1+(re_offset<<2)]*(int32_t)zptr[j])>>15);
#else
	rxcomp[aa][j]   = (int16_t)((rxptr[re_offset<<1]*(int32_t)zptr[j])>>15)   - ((rxptr[1+(re_offset<<1)]*(int32_t)zptr[1+j])>>15);
	rxcomp[aa][1+j] = (int16_t)((rxptr[re_offset<<1]*(int32_t)zptr[1+j])>>15) + ((rxptr[1+(re_offset<<1)]*(int32_t)zptr[j])>>15);
#endif
	if (re_offset==frame_parms->ofdm_symbol_size)
	  re_offset = 0; 
#ifdef DEBUG_PUCCH_RX
	LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d,%d,%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,i,re_offset,m,j,
	    rxptr[re_offset<<2],rxptr[1+(re_offset<<2)],
	    zptr[j],zptr[1+j],
	    rxcomp[aa][j],rxcomp[aa][1+j]);
#endif
      } //re
    } // symbol
  }  // antenna


  // PUCCH Format 1
  // Do cfo correction and MRC across symbols

  if (fmt == pucch_format1) {
#ifdef DEBUG_PUCCH_RX
    LOG_D(PHY,"Doing PUCCH detection for format 1\n");
#endif

    stat_max = 0;
    
    
    for (phase=0;phase<7;phase++) {
      stat=0;
      for (aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
	for (re=0;re<12;re++) {
	  stat_re=0;
	  stat_im=0;
	  off=re<<1;
	  cfo =  (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase] : &cfo_pucch_ep[12*phase];
	  
	  for (l=0;l<(nsymb>>1);l++) {
	    stat_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    stat_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		rxcomp[aa][off],rxcomp[aa][1+off],
		cfo[l<<1],cfo[1+(l<<1)],
		stat_re,stat_im);
#endif	    
	  }
	  for (l2=0,l=(nsymb>>1);l<(nsymb-1);l++,l2++) {
	    stat_re += ((rxcomp[aa][off]*(int32_t)cfo[l2<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l2<<1)])>>15);
	    stat_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l2<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l2<<1)])>>15);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l2,re,
		rxcomp[aa][off],rxcomp[aa][1+off],
		cfo[l2<<1],cfo[1+(l2<<1)],
		stat_re,stat_im);
#endif	    
	    
	  }
	} //re 
      } // aa

      stat = (stat_re*stat_re) + (stat_im*stat_im);
      
      if (stat>stat_max) {
	stat_max = stat;
	phase_max = phase;
      }
#ifdef DEBUG_PUCCH_RX
      LOG_D(PHY,"[eNB] PUCCH: stat %d, stat_max %d, phase_max %d\n", stat,stat_max,phase_max);
#endif
    } //phase
#ifdef DEBUG_PUCCH_RX 
      LOG_D(PHY,"[eNB] PUCCH fmt0:  stat_max : %d, sigma2_dB %d, phase_max : %d\n",dB_fixed(stat_max),sigma2_dB,phase_max);
#endif
    if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres))  //
      *payload = 1;
    else
      *payload = 0;

  }
  else if ((fmt == pucch_format1a)||(fmt == pucch_format1b)) {
    stat_max = 0;
#ifdef DEBUG_PUCCH_RX
    LOG_I(PHY,"Doing PUCCH detection for format 1a/1b\n");    
#endif
    for (phase=0;phase<7;phase++) {
      stat=0;
      for (aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
	for (re=0;re<12;re++) {
	  stat_re=0;
	  stat_im=0;
	  stat_ref_re=0;
	  stat_ref_im=0;
	  off=re<<1;
	  cfo =  (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase] : &cfo_pucch_ep[12*phase];
	  
	  
	  for (l=0;l<(nsymb>>1);l++) {
	    if ((l<2)||(l>(nsymb>>1) - 3)) {  //data symbols
	      stat_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	      stat_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    } 
	    else {   //reference symbols
	      stat_ref_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	      stat_ref_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    }
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		rxcomp[aa][off],rxcomp[aa][1+off],
		cfo[l<<1],cfo[1+(l<<1)],
		stat_re,stat_im);
#endif	    
	  }

	  for (l2=0,l=(nsymb>>1);l<(nsymb-1);l++,l2++) {
	    if ((l2<2) || ((l2>(nsymb>>1) - 3)) ) {  // data symbols
	      stat_re += ((rxcomp[aa][off]*(int32_t)cfo[l2<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l2<<1)])>>15);
	      stat_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l2<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l2<<1)])>>15);
	    }
	    else {  //reference_symbols
	      stat_ref_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	      stat_ref_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    }
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l2,re,
		rxcomp[aa][off],rxcomp[aa][1+off],
		cfo[l2<<1],cfo[1+(l2<<1)],
		stat_re,stat_im);
#endif	    
	    
	  }
	  stat += (((stat_re*stat_re)) + ((stat_im*stat_im)) + 
		   ((stat_ref_re*stat_ref_re)) + ((stat_ref_im*stat_ref_im)));
#ifdef DEBUG_PUCCH_RX
	  LOG_D(PHY,"aa%d re %d : phase %d : stat %d\n",aa,re,phase,stat);
#endif
	} //re 
      } // aa
#ifdef DEBUG_PUCCH_RX      
      LOG_I(PHY,"phase %d : stat %d\n",phase,stat);
#endif 
      if (stat>stat_max) {
	stat_max = stat;
	phase_max = phase;
      }
    } //phase
#ifdef DEBUG_PUCCH_RX 
    LOG_I(PHY,"[eNB] PUCCH fmt1:  stat_max : %d, phase_max : %d\n",stat_max,phase_max);
#endif

    // Do detection now
    stat_re=0;
    stat_im=0;

    if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres))  {//


      for (aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
	for (re=0;re<12;re++) {
	  chest_re=0;
	  chest_im=0;
	  cfo =  (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase_max] : &cfo_pucch_ep[12*phase_max];
	  
	  // channel estimate for first slot
	  for (l=2;l<(nsymb>>1)-2;l++) {
	    off=(re<<1) + (24*l);
	    chest_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    chest_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	  }
#ifdef DEBUG_PUCCH_RX
	  LOG_D(PHY,"[eNB] PUCCH subframe %d l %d re %d chest1 => (%d,%d)\n",subframe,l,re,
		chest_re,chest_im);
#endif	    
	  for (l=0;l<2;l++) {
	    off=(re<<1) + (24*l);
	    tmp_re = ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    tmp_im = ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    stat_re += ((tmp_re*chest_re)>>15) + ((tmp_im*chest_im)>>15);
	    stat_im += ((tmp_re*chest_im)>>15) - ((tmp_im*chest_re)>>15);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		  rxcomp[aa][off],rxcomp[aa][1+off],
		  cfo[l<<1],cfo[1+(l<<1)],
		  stat_re,stat_im);
#endif	    
	  }
	  for (l=(nsymb>>1)-2;l<(nsymb>>1);l++) {
	    off=(re<<1) + (24*l);
	    tmp_re = ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    tmp_im = ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    stat_re += ((tmp_re*chest_re)>>15) + ((tmp_im*chest_im)>>15);
	    stat_im += ((tmp_re*chest_im)>>15) - ((tmp_im*chest_re)>>15);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		  rxcomp[aa][off],rxcomp[aa][1+off],
		  cfo[l<<1],cfo[1+(l<<1)],
		  stat_re,stat_im);
#endif	    
	  }	
	  
	  chest_re=0;
	  chest_im=0;
	  // channel estimate for second slot
	  for (l=2;l<(nsymb>>1)-2;l++) {
	    off=(re<<1) + (24*l) + (nsymb>>1)*24;
	    chest_re += ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    chest_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	  }
#ifdef DEBUG_PUCCH_RX
	  LOG_D(PHY,"[eNB] PUCCH subframe %d l %d re %d chest2 => (%d,%d)\n",subframe,l,re,
		chest_re,chest_im);
#endif	    
	  for (l=0;l<2;l++) {
	    off=(re<<1) + (24*l) + (nsymb>>1)*24;
	    tmp_re = ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    tmp_im = ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    stat_re += ((tmp_re*chest_re)>>15) + ((tmp_im*chest_im)>>15);
	    stat_im += ((tmp_re*chest_im)>>15) - ((tmp_im*chest_re)>>15);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[PHY][eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		  rxcomp[aa][off],rxcomp[aa][1+off],
		  cfo[l<<1],cfo[1+(l<<1)],
		  stat_re,stat_im);
#endif	    
	  }
	  for (l=(nsymb>>1)-2;l<(nsymb>>1)-1;l++) {
	    off=(re<<1) + (24*l) + (nsymb>>1)*24;
	    tmp_re = ((rxcomp[aa][off]*(int32_t)cfo[l<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l<<1)])>>15);
	    tmp_im = ((rxcomp[aa][off]*(int32_t)cfo[1+(l<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l<<1)])>>15);
	    stat_re += ((tmp_re*chest_re)>>9) + ((tmp_im*chest_im)>>9);
	    stat_im += ((tmp_re*chest_im)>>9) - ((tmp_im*chest_re)>>9);
	    off+=2;
#ifdef DEBUG_PUCCH_RX
	    LOG_D(PHY,"[PHY][eNB] PUCCH subframe %d (%d,%d) => (%d,%d) x (%d,%d) : (%d,%d)\n",subframe,l,re,
		  rxcomp[aa][off],rxcomp[aa][1+off],
		  cfo[l<<1],cfo[1+(l<<1)],
		  stat_re,stat_im);
#endif	
	  }
	  
#ifdef DEBUG_PUCCH_RX
	  LOG_D(PHY,"aa%d re %d : stat %d,%d\n",aa,re,stat_re,stat_im);
#endif
	  
	} //re 
      } // aa
      
#ifdef DEBUG_PUCCH_RX
      LOG_I(PHY,"stat %d,%d\n",stat_re,stat_im);
#endif    
      *payload = (stat_re<0) ? 1 : 0;
      if (fmt==pucch_format1b) 
	*(1+payload) = (stat_im<0) ? 1 : 0;
    }
    else {  // insufficient energy on PUCCH so NAK
      *payload = 0;
      if (fmt==pucch_format1b) 
	*(1+payload) = 0;
    }
  }
  else {
    LOG_E(PHY,"[eNB] PUCCH fmt2/2a/2b not supported\n");
  }

  return((int32_t)stat_max);

}


int32_t rx_pucch_emul(PHY_VARS_eNB *phy_vars_eNB,
		  uint8_t UE_index,
		  PUCCH_FMT_t fmt,
		  uint8_t n1_pucch_sel,
		  uint8_t *payload,
		  uint8_t sched_subframe) {
  uint8_t UE_id;
  uint16_t rnti;
  int subframe = phy_vars_eNB->proc[sched_subframe].subframe_rx;
  uint8_t CC_id = phy_vars_eNB->CC_id;

  rnti = phy_vars_eNB->ulsch_eNB[UE_index]->rnti;
  for (UE_id=0;UE_id<NB_UE_INST;UE_id++) {
    if (rnti == PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->lte_ue_pdcch_vars[0]->crnti)
      break;
  }
  if (UE_id==NB_UE_INST) {
    LOG_E(PHY,"rx_pucch_emul: FATAL, didn't find UE with rnti %x\n",rnti);
    return(-1);
  }

  if (fmt == pucch_format1) {
    payload[0] = PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->sr[subframe];
  }
  else if (fmt == pucch_format1a) {
    payload[0] = PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->pucch_payload[0];
  }
  else if (fmt == pucch_format1b) {
    payload[0] = PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->pucch_payload[0];
    payload[1] = PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->pucch_payload[1];    
  }
  else 
    LOG_E(PHY,"[eNB] Frame %d: Can't handle formats 2/2a/2b\n",phy_vars_eNB->proc[sched_subframe].frame_rx);

  if (PHY_vars_UE_g[UE_id][phy_vars_eNB->CC_id]->pucch_sel[subframe] == n1_pucch_sel)
    return(99);
  else
    return(0);
}