view src/cs/layer1/p_cfile/l1p_ctl.c @ 157:fd5202e290bc

targets: j100 added
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 17 Mar 2019 07:13:14 +0000
parents b6a5e36de839
children
line wrap: on
line source

/************* Revision Controle System Header *************
 *                  GSM Layer 1 software 
 * L1P_CTL.C
 *
 *        Filename l1p_ctl.c
 *  Copyright 2003 (C) Texas Instruments  
 *
 ************* Revision Controle System Header *************/

#include "l1_macro.h"
#include "l1_confg.h"

#if L1_GPRS
#if (CODE_VERSION == SIMULATION)
  #include <string.h>          
  #include "l1_types.h"
  #include "sys_types.h"
  #include "l1_const.h"        
  #include "l1_time.h"        
  #include "l1_signa.h"       
  #if TESTMODE
    #include "l1tm_defty.h"
  #endif
  #if (AUDIO_TASK == 1)
    #include "l1audio_const.h"
    #include "l1audio_cust.h"
    #include "l1audio_signa.h"
    #include "l1audio_defty.h"
    #include "l1audio_msgty.h"
  #endif  
  #if (L1_GTT == 1)
    #include "l1gtt_const.h"
    #include "l1gtt_defty.h"
  #endif
  #if (L1_MP3 == 1)
    #include "l1mp3_defty.h"
  #endif
  #if (L1_MIDI == 1)
    #include "l1midi_defty.h"
  #endif
  #include "l1_defty.h"
  #include "cust_os.h"
  #include "l1_msgty.h"
  #include "l1_varex.h"
  #include "l1_proto.h"
  #include "l1_mftab.h"
  #include "l1_tabs.h"
  #include "l1_ver.h"

  #include "l1_ctl.h"

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_sign.h"
#if (OP_L1_STANDALONE == 1)
  #ifdef _INLINE
    #define INLINE static inline // Inline functions when -v option is set 
  #else                          // when the compiler is ivoked.
    #define INLINE
  #endif
#endif  //0maps00090550
#else
  #include <string.h>
  #include "l1_types.h"
  #include "sys_types.h"
  #include "l1_const.h"
  #include "l1_time.h"
  #include "l1_signa.h"

  #if (RF_FAM == 61)
      #include "tpudrv61.h"
  #endif 

  #if TESTMODE
    #include "l1tm_defty.h"
  #endif
  #if (AUDIO_TASK == 1)
    #include "l1audio_const.h"
    #include "l1audio_cust.h"
    #include "l1audio_defty.h"
  #endif  
  #if (L1_GTT == 1)
    #include "l1gtt_const.h"
    #include "l1gtt_defty.h"
  #endif
  #if (L1_MP3 == 1)
    #include "l1mp3_defty.h"
  #endif
  #if (L1_MIDI == 1)
    #include "l1midi_defty.h"
  #endif
  #include "l1_defty.h"
  #include "cust_os.h"
  #include "l1_msgty.h"
  #include "l1_varex.h"
  #include "l1_proto.h"

  #include "l1_ctl.h"

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_sign.h"
  #if (OP_L1_STANDALONE == 1)
  #ifdef _INLINE
    #define INLINE static inline // Inline functions when -v option is set 
  #else                          // when the compiler is ivoked.
    #define INLINE
  #endif
#endif //omaps00090550
#endif

#if(RF_FAM == 61)
   #include "l1_rf61.h"
#endif


// Macro definition
//-----------------
#define min(value1,value2) \
  value1 < value2 ? value1 : value2

// External prototypes
//--------------------

WORD8 l1ctl_encode_delta1(UWORD16 radio_freq);

/*********************************************************/
/* GPRS AGC Algorithms                                   */
/*********************************************************/

/*-------------------------------------------------------*/
/* l1pctl_pagc_ctrl()                                    */
/*-------------------------------------------------------*/
/* Description:                                          */
/* ===========                                           */
/* Based on the same principle as the one used for PAGC  */
/* algorithm except that we also feed the beacon FIFO    */
/* with IL measured on other carriers (Pb parameter is   */
/* applied)                                              */
/* This function is used in the control phase of PCCCH,  */
/* serving PBCCH and PTCCH reading tasks to determine    */
/* which AGC and lna_off must apply                      */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*-------------------------------------------------------*/
void l1pctl_pagc_ctrl(WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq, UWORD8 serving_cell)
{
  UWORD8  pb;
  WORD16  input_level, new_calibrated_IL;
  WORD32  freq_index;
  UWORD16 beacon_frequency;
  UWORD8  *lna_off_ptr;
  UWORD8  curve_id;

  // We memorize the LNA state used for other serving frequencies that can be used
  // in Packet idle mode
  static UWORD8 lna_off_others = 0;

  if (serving_cell == TRUE)
  {
    beacon_frequency = l1a_l1s_com.Scell_info.radio_freq;
    pb               = l1a_l1s_com.Scell_info.pb;
    lna_off_ptr      = &lna_off_others;
    curve_id         = MAX_ID;
  }
  else
  {
    beacon_frequency = l1pa_l1ps_com.pbcchn.bcch_carrier;
    pb               = l1pa_l1ps_com.pbcchn.pb;
    lna_off_ptr      = lna_off;
    curve_id         = AV_ID;
  }

#if(L1_FF_MULTIBAND == 0)
  freq_index = beacon_frequency - l1_config.std.radio_freq_index_offset;
#else
  freq_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(beacon_frequency);
#endif
  

  // If the downlink channel is decoded on the beacon frequency
  if (radio_freq == beacon_frequency)
  {
    // Downlink task on the serving beacon: process AGC according to the "beacon IL"
    input_level = l1a_l1s_com.last_input_level[freq_index].input_level;

    // lna_off already processed in the read phase
    *lna_off = l1a_l1s_com.last_input_level[freq_index].lna_off;
  }

  // If the downlink channel is decoded on a frequency other than the beacon
  else
  {

    // Process AGC according to "beacon IL + Pb"
    input_level = (WORD16) (l1a_l1s_com.last_input_level[freq_index].input_level + pb);

    // IL_2_AGC_xx array size
    if (input_level>INDEX_MAX)
      input_level = INDEX_MAX;

    // lna_off must be processed in the control phase because input_level
    // depends on last_input_level and Pb, and last_input_level or pb can have changed
    // at any time

    // New calibrated IL to reach on radio freq other than beacon
    new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(radio_freq)
                                              - l1ctl_encode_delta2(radio_freq));

    // IL_2_AGC_xx array size
    if (new_calibrated_IL>INDEX_MAX)
      new_calibrated_IL = INDEX_MAX;

    // lna_off computing...
    l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1),
                     lna_off_ptr,
                     radio_freq);

    *lna_off = *lna_off_ptr;
  } // End if "radio_freq != beacon_frequency"

  // Process AGC to apply
  *agc     = Cust_get_agc_from_IL(radio_freq,
                                  input_level >> 1,
                                  curve_id);

  // Store lna_off and input_level field used for current CTRL in order to be able 
  // to build IL from pm in READ phase.
  l1a_l1s_com.Scell_used_IL.input_level = (UWORD8)input_level;
  l1a_l1s_com.Scell_used_IL.lna_off     = *lna_off;

} // End of "l1pctl_pagc_ctrl"

/*-------------------------------------------------------*/
/* l1pctl_pagc_read()                                    */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* Based on the same principle as the one used for PAGC  */
/* algorithm except that we also feed the beacon FIFO    */
/* with IL measured on other carriers (Pb parameter is   */
/* applied)                                              */
/* This function is used in the read phase of PCCCH and  */
/* serving PBCCH reading tasks to determine the IL value */
/* store it in the FIFO and find the next IL to use      */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*-------------------------------------------------------*/
UWORD8 l1pctl_pagc_read(UWORD8 pm, UWORD16 radio_freq)
{
  UWORD8   i, new_IL;
  WORD8    delta1_freq, delta2_freq;
  WORD16   delta_drp_gain=0;
  UWORD16  lna_value;
  WORD16   used_agc, current_IL, new_calibrated_IL, current_calibrated_IL;
  WORD32   serving_index;
#if (RF_FAM == 61)
  UWORD16  arfcn;
#endif
  UWORD8   lna_off;
  UWORD16  dco_algo_ctl_pw_temp = 0;
  UWORD8   if_ctl = 0;
#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION)
  UWORD8   if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
#endif

#if (L1_FF_MULTIBAND == 0)
  serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset;

#else
  serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
#endif /*if (L1_FF_MULTIBAND == 0)*/
  

  // Calibration factors
  delta1_freq = l1ctl_encode_delta1(radio_freq);
  delta2_freq = l1ctl_encode_delta2(radio_freq);

  // AGC used in the control phase (format F7.1)
  used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1;

  // LNA attenuation
  lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq);

#if (RF_FAM == 61)
  // DRP correction 
#if (L1_FF_MULTIBAND == 0)  
  arfcn = Convert_l1_radio_freq(radio_freq);
#else
  arfcn=radio_freq;
#endif 

   #if (CODE_VERSION != SIMULATION)

    cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , 
                                          l1a_l1s_com.Scell_used_IL_dd.input_level,
                                         radio_freq,if_threshold);
     lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off;
     delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc);    // F7.1 format
     if(if_ctl == IF_100KHZ_DSP){
       delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ;
     }
     else{ /* i.e. if_ctl = IF_120KHZ_DSP*/
       delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ;    
     }
       
   #endif
#endif

  // current_IL processing

  if (0==pm)  // Check and filter illegal pm value by using last valid IL
  {
    current_IL = l1a_l1s_com.last_input_level[serving_index].input_level - lna_value;
  }
  else 
  { 
    current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq));

    // IL normalization to beacon (ILnorm = IL - Pb)
    if (radio_freq != l1a_l1s_com.Scell_info.radio_freq)
      current_IL -= l1a_l1s_com.Scell_info.pb;
  }

  // Calibrated IL processing
  // NOTE: calibrated_IL is normalized to beacon. This is needed for the
  //       pccch_lev processing
  current_calibrated_IL = (WORD16) (current_IL - delta1_freq - delta2_freq);
  
  // Protect IL stores against overflow
  if (current_calibrated_IL>INDEX_MAX)
    current_calibrated_IL=INDEX_MAX;
  if (current_IL>INDEX_MAX)
    current_IL=INDEX_MAX;

  // FIFO management
  for (i=3;i>0;i--)
    l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1];
  l1a_l1s_com.Scell_info.buff_beacon[0] = (UWORD8)current_IL;

  // Find min IL in FIFO
  new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon, 4);

  // Input levels are always stored with lna_on 
  new_calibrated_IL = (WORD16)  (new_IL - delta1_freq - delta2_freq);

  if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

  l1ctl_encode_lna( (UWORD8)(new_calibrated_IL>>1),
                    &(l1a_l1s_com.last_input_level[serving_index].lna_off),
                    radio_freq );

  l1a_l1s_com.last_input_level[serving_index].input_level = new_IL +
    l1a_l1s_com.last_input_level[serving_index].lna_off * l1ctl_get_lna_att(radio_freq);

  return((UWORD8)current_calibrated_IL);
} // End of "l1pctl_pagc_read"

/*-------------------------------------------------------*/
/* l1pctl_transfer_agc_init()                            */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* Packet transfer AGC algorithm initialization          */
/*-------------------------------------------------------*/
void l1pctl_transfer_agc_init()
{
  WORD16   calibrated_IL;
  UWORD16  radio_freq;
  WORD32   serving_index;
  WORD16   input_level;

#if (L1_FF_MULTIBAND ==0)
  serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset;

#else
  serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
#endif /*if L1_FF_MULTIBAND*/
  

  // Daughter frequencies input level initialization
  //------------------------------------------------
  if (l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0 == 255)
  {
    // No power control mode AGC algorithm
    input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level + l1a_l1s_com.Scell_info.pb);

    // Set fn_select to current_fn
    l1ps.fn_select                                   = l1s.actual_time.fn;
    // Initialize algorithm in "SEARCH" phase
    l1ps.phase                                       = SEARCH;
  }
  else
  {
    // Downlink power control AGC algorithms
    if (l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.bts_pwr_ctl_mode == 0)
    {
      // BTS Power control mode A
      input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level +
                              l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0 + 10);
      
    }
    else
    {
      // BTS power control mode B
      input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level +
                              l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0);

      // Initialization: PR = P0
      l1ps.last_PR_good = l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0;
    }
  }

  if (input_level>INDEX_MAX) input_level = INDEX_MAX;
  l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level;


  // Daughter frequencies lna_off processing
  //----------------------------------------

  // We need to know on which frequency band we work
  if (!l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.h)
  {
    // Single frequency
    radio_freq = l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.rf_channel.single_rf.radio_freq;
  }
  else
  {
    // Frequency hopping: all frequencies of the frequency list are on the same band
    // We take the first frequency of the list
    radio_freq = l1pa_l1ps_com.transfer.aset->freq_param.freq_list.rf_chan_no.A[0];
  }

  calibrated_IL = (WORD16) (l1a_l1s_com.Scell_info.transfer_meas.input_level
                  - l1ctl_encode_delta1(radio_freq) - l1ctl_encode_delta2(radio_freq)
                  - l1a_l1s_com.last_input_level[serving_index].lna_off * l1ctl_get_lna_att(radio_freq));
                  
  if (calibrated_IL>INDEX_MAX) calibrated_IL = INDEX_MAX; 

  l1ctl_encode_lna((UWORD8)(calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), radio_freq);

}  // End of "l1pctl_transfer_agc_init"

/*-------------------------------------------------------*/
/* l1pctl_transfer_agc_ctrl()                            */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* This function is used in the control phase of PDTCH/D */
/* to determine which AGC and lna_off must apply         */
/*-------------------------------------------------------*/
void l1pctl_transfer_agc_ctrl(WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq)
{
  T_INPUT_LEVEL *selected_IL;
#if(L1_FF_MULTIBAND == 1)
  UWORD16 operative_radio_freq;
#endif
  

  // input_level selection
  if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
  {
    // Beacon frequency input_level used for AGC processing
#if(L1_FF_MULTIBAND == 0)    
    selected_IL = &l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq
                                                - l1_config.std.radio_freq_index_offset];

#else // L1_FF_MULTIBAND = 1 below

    operative_radio_freq = 
      l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
    selected_IL = &(l1a_l1s_com.last_input_level[operative_radio_freq]);


#endif // #if(L1_FF_MULTIBAND == 0) else

  }
  else
  {
    // Daughter frequency input_level used for AGC processing
    selected_IL = &l1a_l1s_com.Scell_info.transfer_meas;
  }
  *agc     = Cust_get_agc_from_IL(radio_freq,selected_IL->input_level >> 1, MAX_ID);
  *lna_off = selected_IL->lna_off;

  // Store lna_off and input_level field used for current CTRL in order to be able 
  // to build IL from pm in READ phase.
  l1a_l1s_com.Scell_used_IL.input_level = selected_IL->input_level;
  l1a_l1s_com.Scell_used_IL.lna_off     = *lna_off;

}

/*-------------------------------------------------------*/
/* l1pctl_npc_agc_read()                                 */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* AGC algorithm in packet transfer used when            */
/* NO POWER CONTROL is done by the BTS.                  */
/* This function is used during the read phase of PDTCH: */
/* 1- to determine the IL value for each timeslot in each*/
/*    TDMA                                               */
/* 2- to find the IL value to use for the next PDCH      */
/*    block                                              */
/*                                                       */
/* Algorithm                                             */
/* ---------                                             */
/* For each timeslot i used for PDCH                     */
/*   IL(i) = fct(used AGC, pm)                           */
/*   if (beacon)                                         */
/*     ILmax_beacon = max(ILmax_beacon, IL(i))           */
/*   else                                                */
/*     ILmax_others(i) = max(IL(i), ILmax_others(i))     */
/*                                                       */
/* If (burst_nb == 3)                                    */
/*   If (ILmax_beacon was found during the block)        */
/*     FIFO[beacon] updated with ILmax_beacon            */
/*     transfer_meas = max(FIFO[beacon])                 */
/*     Reset ILmax_beacon                                */
/*                                                       */
/*   For each timeslot i used for PDCH                   */
/*     if (CRC good)                                     */
/*       ILmax_correct = max(ILmax_correct,              */
/*                           ILmax_others(i))            */
/*     else                                              */
/*       ILmax_not_correct = max(ILmax_not_correct,      */
/*                               ILmax_others(i))        */
/*                                                       */
/*   If (no ILmax_correct was found)                     */
/*     ILselected = ILmax_correct                        */
/*     FNselected = current FN                           */
/*   else                                                */
/*     DeltaFN = (current FN - FNselected) % MAX_FN      */
/*                                                       */
/*     if (DeltaFN < 78)                                 */
/*       ILweighted = ILselected * (1 - DeltaFN/78)      */
/*                    - 120 * DeltaFN /78                */
/*                                                       */
/*       if (ILweighted < -120) ILweighted = -120        */
/*       if (ILmax_not_correct > ILweighted)             */
/*         ILselected = ILmax_not_correct                */
/*         FNselected = current FN                       */
/*     else                                              */
/*       ILselected = -120                               */
/*       FNselected = current FN                         */
/*                                                       */
/*   Reset ILmax_others[8]                               */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*                                                       */
/* Parameters                                            */
/* ----------                                            */
/* "calibrated_IL[8]"                                    */
/*   contains the IL found on timeslots                  */
/*   used for PDCH/D. These ILs can be used to process   */
/*   RXLEV values.                                       */
/*                                                       */
/* "*pdsp_db_r_ptr"                                      */
/*   Pointer on the DSP DB Read page, used to extract    */
/*   pm values, burst number and timeslot allocated      */
/*   for downlink PDCH                                   */
/*                                                       */
/* "*pdsp_ndb_ptr"                                       */
/*   Pointer on the DSP NDB page, used to extract the    */
/*   CRC value for each decoded burst                    */
/*                                                       */
/* Global parameters                                     */
/* -----------------                                     */
/* "l1a_l1s_com.Scell_info.transfer_meas.input_level"    */
/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off"        */
/*   Used to store the ILselected and the associated     */
/*   lna_off value.                                      */
/*                                                       */
/* "l1a_l1s_com.Scell_info.fn_select"                    */
/*   Used to store the FNselected value.                 */
/*                                                       */
/* "l1a_l1s_com.last_input_level[freq index]             */
/*     .input_level                                      */
/*     .lna_off"                                         */
/*   Used to store the beacon input level and            */
/*   the associated lna_off value.                       */
/*                                                       */
/* "l1ps.transfer_beacon_buf[4]"                         */
/*   FIFO[beacon]                                        */
/*                                                       */
/* "l1ps.ILmin_beacon"                                   */
/* "l1ps.ILmin_others[8]"                                */
/*-------------------------------------------------------*/
void l1pctl_npc_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr,
                         T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr)
{
  UWORD8       ts;
  UWORD8       rx_no                      = 0;
  UWORD8       bit_mask                   = 0x80;
  UWORD8       ILmin_correct              = 255;
  UWORD8       ILmin_not_correct          = 255;
  WORD8        delta1_freq, delta2_freq;
  WORD16       delta_drp_gain=0;
  UWORD16      radio_freq, lna_value;
  WORD16       used_agc;
  WORD32       serving_index;
#if (RF_FAM == 61)
  UWORD16      arfcn;
#endif
  UWORD8       lna_off;
  UWORD16 dco_algo_ctl_pw_temp = 0;
  UWORD8 if_ctl = 0;
#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION)
  UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
#endif

#if(L1_FF_MULTIBAND == 0)
  serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset;

#else
  serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
#endif
  

  // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH
  // ***************************************************************************

  // Get radio_freq on which the downlink block was received
  radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd;

  // Compute calibration factors
  delta1_freq                                      = l1ctl_encode_delta1(radio_freq);
  delta2_freq                                      = l1ctl_encode_delta2(radio_freq);

  // AGC used in the control phase (format F7.1)
  used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1;

  // LNA attenuation
  lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq);

  // Burst 0: Reset ILmin_beacon and ILmin_others
  if(pdsp_db_r_ptr->d_burst_nb_gprs == 0)
  {
    l1ps.ILmin_beacon = 255; // Not valid

    for (ts = 0; ts < 8; ts++)
    {
      l1ps.ILmin_others[ts] = (UWORD8) l1_config.params.il_min;
    }
  } // End if "burst 0"

  // IL processing for each received burst
  // **************************************

  // For each timeslot on which a burst was received
  for(ts = 0; ts < 8; ts ++)
  {
    if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask)
    {
      WORD16       current_IL, current_calibrated_IL;
      UWORD8       pm;

      // IL = fct(pm, last_known_agc, lna_value, g_magic)
      //-------------------------------------------------

      pm    = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts]   & 0xffff) >> 5);

      // current_IL processing
      if (0==pm)  // Check and filter illegal pm value by using last valid IL
      {
        if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
          current_IL = l1a_l1s_com.last_input_level[serving_index].input_level
                       - lna_value;
        else
          current_IL = l1a_l1s_com.Scell_info.transfer_meas.input_level
                       - lna_value;
      }
      else
      {

#if (RF_FAM == 61)
        // DRP correction 
#if (L1_FF_MULTIBAND == 0)  
  arfcn = Convert_l1_radio_freq(radio_freq);
#else
  arfcn=radio_freq;
#endif 

   #if (CODE_VERSION != SIMULATION)

    cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , 
                                         l1a_l1s_com.Scell_used_IL_dd.input_level,
                                         radio_freq,if_threshold);
     lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off;
     delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc);    // F7.1 format     
     if(if_ctl == IF_100KHZ_DSP){
       delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ;
     }
     else{ /* i.e. if_ctl = IF_120KHZ_DSP*/
       delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ;    
     }

   #endif
#endif

        current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq));
      }

      // Calibrated IL processing
      current_calibrated_IL = current_IL - delta1_freq - delta2_freq;
      
      // Protect IL stores against overflow
      if(current_calibrated_IL>INDEX_MAX)
        current_calibrated_IL=INDEX_MAX;
      if (current_IL>INDEX_MAX)
        current_IL=INDEX_MAX;
         
      calibrated_IL[ts] = (UWORD8)(current_calibrated_IL);  
   
      // Keep ILmax
      if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
      {
        // Beacon frequency
        l1ps.ILmin_beacon = min((UWORD8) current_IL, l1ps.ILmin_beacon);
      }
      else
      {
        // Daughter frequency
        l1ps.ILmin_others[ts] = min((UWORD8) current_IL,l1ps.ILmin_others[ts]);
      }

      // Input Level selection among ILmax found on each timeslot during the block (when burst = 3)
      // *******************************************************************************************

      if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
      {
        // If CRC good
        if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100))
        {
          // Find the min found IL for blocks that were correctly received
          ILmin_correct = min(l1ps.ILmin_others[ts],ILmin_correct);
        }
        // If CRC bad
        else
        {
          // Find the min found IL for blocks that were not correctly received
          ILmin_not_correct = min(l1ps.ILmin_others[ts],ILmin_not_correct);
        }
      } // End if "burst = 3"

      // Next downlink block
      rx_no ++;

    } // End if "timeslot used for downlink PDCH"

    // Next timeslot
    bit_mask >>= 1;
  } // End for "each timeslot...."


  // IL selection for the next block if burst = 3
  // **********************************************

  if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
  {
    WORD16 new_calibrated_IL;

    // Beacon frequency input level updating
    //--------------------------------------

    // If a PDCH has been received on the beacon
    if (l1ps.ILmin_beacon != 255)
    {
      UWORD8 i, new_IL;

      // FIFO management
      for (i=3;i>0;i--)
        l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1];
      l1a_l1s_com.Scell_info.buff_beacon[0] = l1ps.ILmin_beacon;

      // Find min IL in FIFO
      new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon, 4);

      // Input levels are always stored with lna_on

      // lna_off processing
      new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq));

      if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

      l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1),
                       &(l1a_l1s_com.last_input_level[serving_index].lna_off),
                       l1a_l1s_com.Scell_info.radio_freq);

      l1a_l1s_com.last_input_level[serving_index].input_level = new_IL +
        l1a_l1s_com.last_input_level[serving_index].lna_off *
          l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq);

    } // End of "beacon frequency input level updating"

    // Daughter frequencies input level updating
    //------------------------------------------

    // If at least one block was correctly received
    // (Note: ILs truncated to 240 so 255 isn't valid)
    if (ILmin_correct != 255)
    {
      // Select the min input level found on correctly received blocks
      l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_correct;
      l1ps.fn_select                                   = l1s.actual_time.fn;

      // Algorithm switch to "TRACK" phase if it was in "SEARCH" phase
      l1ps.phase                                       = TRACK;
    }

    // No block was correctly received
    else
    {
      UWORD8 input_level_ref = l1a_l1s_com.Scell_info.transfer_meas.input_level
        - l1a_l1s_com.Scell_info.transfer_meas.lna_off *
          l1ctl_get_lna_att(radio_freq);
      // SEARCH phase
      if (l1ps.phase == SEARCH)
      {
        // If measured level superior to currently tracket level, switch to TRACK mode
        if (input_level_ref > ILmin_not_correct)
          l1ps.phase = TRACK;

        // Select the min input level found on badly received blocks
        l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_not_correct;
        l1ps.fn_select                                   = l1s.actual_time.fn;
      }

      // TRACK phase
      else
      {
        // If the IL found on incorrect block is lower than current wanted IL
        if (ILmin_not_correct < input_level_ref)
        {
          // Select the new IL
          l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_not_correct;
          l1ps.fn_select = l1s.actual_time.fn;
        }

        // If the IL found on incorrect block is higher than current wanted IL
        else
        {
          UWORD32 delta_fn;

          // delta_fn processing for IL selection forgetting factor
          delta_fn = l1s.actual_time.fn - l1ps.fn_select;

          // MAX_FN modulo management
          if (l1s.actual_time.fn < l1ps.fn_select)
            delta_fn += MAX_FN;

          // If the last selected IL is more recent than 72 frames
          // 
          //  |....|R...............................C|....| 
          //        ^                               ^
          //     fn_selected                    IL reset to -120
          //  <-------------------------------------->
          //                    312
          // 306 = 312 - 4 (block_size) - 1 (Read phase fn delay) - 1 (Control phase fn advance)
          if (delta_fn > 306)
          {
            WORD16 input_level;

            // IL initialized to "beacon level - Pb"
            input_level = (WORD16)
              ((l1a_l1s_com.last_input_level[serving_index].input_level +
                l1a_l1s_com.Scell_info.pb) -
               (l1a_l1s_com.last_input_level[serving_index].lna_off *
                l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq)));

            if (input_level>INDEX_MAX) input_level = INDEX_MAX;    
            l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level;
            
            l1ps.fn_select                                   = l1s.actual_time.fn;
            // Returns to "SEARCH" phase
            l1ps.phase                                       = SEARCH;
          }
          else
          {
            WORD16 input_level;

            input_level = l1a_l1s_com.Scell_info.transfer_meas.input_level -
              l1a_l1s_com.Scell_info.transfer_meas.lna_off *
                l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna);

            if (input_level>INDEX_MAX) input_level = INDEX_MAX;

            l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level;
          }
        } // End if the IL found on incorrect block is higher than current wanted IL 
      } // End of "track phase"
    } // End if no block correctly received

    // lna_off processing
    new_calibrated_IL = (WORD16) (l1a_l1s_com.Scell_info.transfer_meas.input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna));
    if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

    l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna);

    l1a_l1s_com.Scell_info.transfer_meas.input_level +=
      l1a_l1s_com.Scell_info.transfer_meas.lna_off *
        l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna);
  } // End if "burst = 3"

} // End of "l1pctl_npc_agc_read"

/*-------------------------------------------------------*/
/* l1pctl_dpcma_agc_read()                               */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* AGC algorithm in packet transfer used when the BTS    */
/* use DOWNLINK POWER CONTROL mode A.                    */
/* This function is used during the read phase of PDTCH: */
/* 1- to determine the IL value for each timeslot in each*/
/*    TDMA                                               */
/* 2- to find the IL value to use for the next PDCH      */
/*    block                                              */
/*                                                       */
/* Algorithm                                             */
/* ---------                                             */
/* For each timeslot i used for PDCH                     */
/*   IL(i) = fct(used AGC, pm)                           */
/*   if (beacon)                                         */
/*     ILmax_beacon = max(ILmax_beacon, IL(i))           */
/*   else                                                */
/*     ILmax_others(i) = max(IL(i), ILmax_others(i))     */
/*                                                       */
/* If (burst_nb == 3)                                    */
/*                                                       */
/*   For each timeslot i used for PDCH                   */
/*     if (CRC good) and                                 */
/*        ((PR_MODE A) or (PR_MODE B and TFI good))      */
/*       ILmax = max(ILmax, ILmax_others(i) + P0 + PR(i))*/
/*                                                       */
/*   ILmax=max(ILmax, ILmax_beacon)                      */
/*   FIFO[beacon] updated with ILmax                     */
/*   last_input_level[serving beacon] = max(FIFO[beacon])*/
/*   transfer_meas = max(FIFO[beacon]) - P0 - 5          */
/*                                                       */
/*   Reset ILmax_others[8] and ILmax_beacon              */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*                                                       */
/* Parameters                                            */
/* ----------                                            */
/* "calibrated_IL[8]"                                    */
/*   contains the IL found on timeslots                  */
/*   used for PDCH/D. These ILs can be used to process   */
/*   RXLEV values.                                       */
/*                                                       */
/* "*pdsp_db_r_ptr"                                      */
/*   Pointer on the DSP DB Read page, used to extract    */
/*   pm values, burst number and timeslot allocated      */
/*   for downlink PDCH                                   */
/*                                                       */
/* "*pdsp_ndb_ptr"                                       */
/*   Pointer on the DSP NDB page, used to extract the    */
/*   CRC value for each decoded burst                    */
/*                                                       */
/* Global parameters                                     */
/* -----------------                                     */
/* "l1a_l1s_com.Scell_info.transfer_meas.input_level"    */
/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off"        */
/*   Used to store the ILselected and the associated     */
/*   lna_off value.                                      */
/*                                                       */
/* "l1a_l1s_com.last_input_level[freq. index]            */
/*     .input_level                                      */
/*     .lna_off"                                         */
/*   Used to store the beacon input level and            */
/*   the associated lna_off value.                       */
/*                                                       */
/* "l1ps.transfer_beacon_buf[4]"                         */
/*   FIFO[beacon]                                        */
/*                                                       */
/* "l1ps.ILmin_beacon"                                   */
/* "l1ps.ILmin_others[8]"                                */
/*-------------------------------------------------------*/
void l1pctl_dpcma_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr,
                           T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, UWORD8 pr_table[8])
{
  UWORD8       ts                         = 0;
  UWORD8       rx_no                      = 0;
  UWORD8       bit_mask                   = 0x80;
  UWORD8       IL_norm_min                = 255;
  WORD8        delta1_freq, delta2_freq;
  WORD16       delta_drp_gain=0;
  UWORD16      radio_freq, lna_value;
  WORD16       used_agc;
  WORD32       serving_index;
#if (RF_FAM == 61)
  UWORD16      arfcn;
#endif
  UWORD8       lna_off;
  UWORD16 dco_algo_ctl_pw_temp = 0;
  UWORD8 if_ctl = 0;
#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION)
  UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
#endif

#if(L1_FF_MULTIBAND == 0)
  serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset;

#else
  serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
#endif


  // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH
  // ***************************************************************************

  // Get radio_freq on which the downlink block was received
  radio_freq     = l1a_l1s_com.dedic_set.radio_freq_dd;

  // Compute calibration factors
  delta1_freq = l1ctl_encode_delta1(radio_freq);
  delta2_freq = l1ctl_encode_delta2(radio_freq);

  // Last known AGC (format F7.1)
  used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1;

  // LNA attenuation
  lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq);

  // Burst 0: Reset ILmin_beacon and ILmin_others
  if(pdsp_db_r_ptr->d_burst_nb_gprs == 0)
  {
    l1ps.ILmin_beacon = 255;  // Not valid

    for (ts = 0; ts < 8; ts++)
    {
       l1ps.ILmin_others[ts] = 255;  // Not valid
    }
  }

  // IL processing for each received burst
  // **************************************

#if (RF_FAM == 61)
  // DRP correction
#if (L1_FF_MULTIBAND == 0)  
  arfcn = Convert_l1_radio_freq(radio_freq);
#else
  arfcn=radio_freq;
#endif 

   #if (CODE_VERSION != SIMULATION)
   
    cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , 
                                         l1a_l1s_com.Scell_used_IL_dd.input_level,
                                         radio_freq, if_threshold);
     lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off;
     delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc);    // F7.1 format

     if(if_ctl == IF_100KHZ_DSP){
       delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ;
     }
     else{ /* i.e. if_ctl = IF_120KHZ_DSP*/
       delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ;    
     }

   #endif
#endif
	 
  // For each timeslot on which a burst was received
  for(ts = 0; ts < 8; ts ++)
  {
    if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask)
    {
      WORD16       current_IL, current_calibrated_IL;
      UWORD8       pm;

      // IL = fct(pm, last_known_agc, lna_value, g_magic)
      //-------------------------------------------------

      pm    = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts]   & 0xffff) >> 5);

      // current_IL processing
      if (0==pm)  // Check and filter illegal pm value by using last valid IL
      {
          current_IL = l1a_l1s_com.last_input_level[serving_index].input_level
                       - lna_value;

          if (radio_freq != l1a_l1s_com.Scell_info.radio_freq)
            current_IL += (l1ps.read_param.dl_pwr_ctl.p0 + 10);
      }
      else
	  {		  
        current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq));
	  }

      // Calibrated IL processing
      current_calibrated_IL = current_IL - delta1_freq - delta2_freq;
      
      // Protect IL stores against overflow
      if(current_calibrated_IL>INDEX_MAX)
        current_calibrated_IL=INDEX_MAX;
      if (current_IL>INDEX_MAX)
        current_IL=INDEX_MAX;
         
      calibrated_IL[ts] = (UWORD8)(current_calibrated_IL);  

      // Keep the minimum IL
      if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
      {
        // Beacon frequency
        l1ps.ILmin_beacon     = min((UWORD8) current_IL,l1ps.ILmin_beacon);
      }
      else
      {
        // Daughter frequency
        l1ps.ILmin_others[ts] = min((UWORD8) current_IL, l1ps.ILmin_others[ts]);
      }

      // Input Level selection among ILmax found on each timeslot during the block (when burst = 3)
      //-------------------------------------------------------------------------------------------

      if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
      {
        // If CRC good
        if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100))
        {
          // If ((PR_MODE A and TFI good) or (PR_MODE B)) AND PR != 0 [Not usable])
          if (((l1ps.read_param.dl_pwr_ctl.pr_mode != 0) || (!(pr_table[ts] & 0x80)))
              && ((pr_table[ts] & 0x1f) != 0))
          {
            if (l1ps.ILmin_others[ts] != 255)
            {
              UWORD8 IL_norm;

              // IL normalization to beacon (ILnorm = ILmax_others(ts) - P0 - PR)
              IL_norm = l1ps.ILmin_others[ts] - l1ps.read_param.dl_pwr_ctl.p0 - ((pr_table[ts] & 0x1f) << 1);

              // Update IL_min with the minimum found IL
              IL_norm_min = min(IL_norm, IL_norm_min);
            }
          }
        } // End if "CRC good"

      } // End if "burst = 3"

      // Next downlink block
      rx_no ++;

    } // End if "timeslot used for downlink PDCH"

    // Next timeslot
    bit_mask >>= 1;

  } // End for "each timeslot...."


  // IL selection for the next block if burst = 3
  // **********************************************

  if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
  {
    UWORD8  i, new_IL;
    UWORD16 input_level;
    WORD16  new_calibrated_IL;

    // Select the minimum IL between minimum IL found on daughter frequencies (normalized to beacon)
    // and minimum IL found on the beacon
    IL_norm_min = min(IL_norm_min, l1ps.ILmin_beacon);

    // If a valid IL has been found
    if (IL_norm_min != 255)
    {
      // FIFO management
      for (i=3;i>0;i--)
        l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1];

      l1a_l1s_com.Scell_info.buff_beacon[0] = IL_norm_min;

      // last_input_level[serving beacon] updating
      //------------------------------------------

      // Find min IL in FIFO
      new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4);
  
      // Input levels are always stored with lna_on

      // lna_off processing
      new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq));
      if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

      l1ctl_encode_lna((UWORD8)(new_calibrated_IL >> 1),
                       &(l1a_l1s_com.last_input_level[serving_index].lna_off),
                       l1a_l1s_com.Scell_info.radio_freq);

      l1a_l1s_com.last_input_level[serving_index].input_level = new_IL +
        l1a_l1s_com.last_input_level[serving_index].lna_off *
          l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq);
    }

    // transfer_meas updating
    //-----------------------

    // IL = (min IL in FIFO) + P0 + 10 (PR = 5 format 7.1)
    // Input levels are always stored with lna_on
    input_level = l1a_l1s_com.last_input_level[serving_index].input_level
                  - l1a_l1s_com.last_input_level[serving_index].lna_off *
                      l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq)
                  + l1ps.read_param.dl_pwr_ctl.p0 + 10;
  
    // IL_2_AGC_xx array size 
    if (input_level>INDEX_MAX) input_level = INDEX_MAX;

    // lna_off processing
    new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna));

    if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

    l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna);

    l1a_l1s_com.Scell_info.transfer_meas.input_level = input_level +
      l1a_l1s_com.Scell_info.transfer_meas.lna_off *
        l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna);
  } // End if "burst = 3"

} // End of "l1pctl_dpcma_agc_read"

/*-------------------------------------------------------*/
/* l1pctl_dpcmb_agc_read()                               */
/*-------------------------------------------------------*/
/* Description :                                         */
/* ===========                                           */
/* AGC algorithm in packet transfer used when the BTS    */
/* use DOWNLINK POWER CONTROL mode B.                    */
/* This function is used during the read phase of PDTCH: */
/* 1- to determine the IL value for each timeslot in each*/
/*    TDMA                                               */
/* 2- to find the IL value to use for the next PDCH      */
/*    block                                              */
/*                                                       */
/* Algorithm                                             */
/* ---------                                             */
/* For each timeslot i used for PDCH                     */
/*   IL(i) = fct(used AGC, pm)                           */
/*   if (beacon)                                         */
/*     ILmax_beacon = max(ILmax_beacon, IL(i))           */
/*   else                                                */
/*     ILmax_others(i) = max(IL(i), ILmax_others(i))     */
/*                                                       */
/* If (burst_nb == 3)                                    */
/*                                                       */
/*   For each timeslot i used for PDCH                   */
/*     if (CRC good)                                     */
/*       if (TFI good) last_PR_good = PR(i)              */
/*       if ((PR_MODE A) or (PR_MODE B and TFI good))    */
/*         ILmax = max(ILmax, ILmax_others(i)            */
/*                 + P0 + PR(i))                         */
/*                                                       */
/*   ILmax=max(ILmax, ILmax_beacon)                      */
/*   FIFO[beacon] updated with ILmax                     */
/*   last_input_level[serving beacon] = max(FIFO[beacon])*/
/*   transfer_meas = max(FIFO[beacon]) - last_PR_good    */
/*                                                       */
/*   Reset ILmax_others[8] and ILmax_beacon              */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*                                                       */
/* Parameters                                            */
/* ----------                                            */
/* "calibrated_IL[8]"                                    */
/*   contains the IL found on timeslots                  */
/*   used for PDCH/D. These ILs can be used to process   */
/*   RXLEV values.                                       */
/*                                                       */
/* "*pdsp_db_r_ptr"                                      */
/*   Pointer on the DSP DB Read page, used to extract    */
/*   pm values, burst number and timeslot allocated      */
/*   for downlink PDCH                                   */
/*                                                       */
/* "*pdsp_ndb_ptr"                                       */
/*   Pointer on the DSP NDB page, used to extract the    */
/*   CRC value for each decoded burst                    */
/*                                                       */
/* Global parameters                                     */
/* -----------------                                     */
/* "l1a_l1s_com.Scell_info.transfer_meas.input_level"    */
/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off"        */
/*   Used to store the ILselected and the associated     */
/*   lna_off value.                                      */
/*                                                       */
/* "l1a_l1s_com.last_input_level[freq. index]            */
/*     .input_level                                      */
/*     .lna_off"                                         */
/*   Used to store the beacon input level and            */
/*   the associated lna_off value.                       */
/*                                                       */
/* "l1ps.transfer_beacon_buf[4]"                         */
/*   FIFO[beacon]                                        */
/*                                                       */
/* "l1ps.ILmin_beacon"                                   */
/* "l1ps.ILmin_others[8]"                                */
/*-------------------------------------------------------*/
void l1pctl_dpcmb_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr,
                           T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, UWORD8 pr_table[8])
{
  UWORD8       ts                         = 0;
  UWORD8       rx_no                      = 0;
  UWORD8       bit_mask                   = 0x80;
  UWORD8       IL_norm_min                = 255;
  WORD8        delta1_freq, delta2_freq;
  WORD16       delta_drp_gain=0;
  UWORD16      radio_freq, lna_value;
  WORD16       used_agc;
  WORD32       serving_index;
#if (RF_FAM == 61)
  UWORD16      arfcn;
#endif
  UWORD8       lna_off;
  UWORD16 dco_algo_ctl_pw_temp = 0;
  UWORD8 if_ctl = 0;
#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION)
  UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
#endif

#if(L1_FF_MULTIBAND == 0)
  serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset;
#else
  serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq);
#endif


  // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH
  // ***************************************************************************

  // Get radio_freq on which the downlink block was received
  radio_freq     = l1a_l1s_com.dedic_set.radio_freq_dd;

  // Compute calibration factors
  delta1_freq = l1ctl_encode_delta1(radio_freq);
  delta2_freq = l1ctl_encode_delta2(radio_freq);

  // Last known AGC (format F7.1)
  used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1;

  // LNA attenuation
  lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq);

  // Burst 0: Reset ILmin_beacon and ILmin_others
  if(pdsp_db_r_ptr->d_burst_nb_gprs == 0)
  {
    l1ps.ILmin_beacon = 255;  // Not valid

    for (ts = 0; ts < 8; ts++)
    {
       l1ps.ILmin_others[ts] = 255;  // Not valid
    }
  }

  // IL processing for each received burst
  // **************************************

  // For each timeslot on which a burst was received
  for(ts = 0; ts < 8; ts ++)
  {
    if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask)
    {
      WORD16       current_IL, current_calibrated_IL;
      UWORD8       pm;

      // IL = fct(pm, last_known_agc, lna_value, g_magic)
      //-------------------------------------------------

      pm    = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts]   & 0xffff) >> 5);

      // current_IL processing
      if (0==pm)  // Check and filter illegal pm value by using last valid IL
      {
          current_IL = l1a_l1s_com.last_input_level[serving_index].input_level
                       - lna_value;

          if (radio_freq != l1a_l1s_com.Scell_info.radio_freq)
            current_IL += (l1ps.last_PR_good);
      }
      else
      {

#if (RF_FAM == 61)
	    // DRP correction
#if (L1_FF_MULTIBAND == 0)  
  arfcn = Convert_l1_radio_freq(radio_freq);
#else
  arfcn=radio_freq;
#endif 

   #if (CODE_VERSION != SIMULATION)


    cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , 
                                         l1a_l1s_com.Scell_used_IL_dd.input_level,
                                         radio_freq, if_threshold);
     lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off;
     delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc);    // F7.1 format

     if(if_ctl == IF_100KHZ_DSP){
       delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ;
     }
     else{ /* i.e. if_ctl = IF_120KHZ_DSP*/
       delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ;    
     }


   #endif
#endif

        current_IL = -(pm - ( used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq));
      }

      // Calibrated IL processing
      current_calibrated_IL = current_IL - delta1_freq - delta2_freq;
      
      // Protect IL stores against overflow
      if(current_calibrated_IL>INDEX_MAX)
        current_calibrated_IL=INDEX_MAX;
      if (current_IL>INDEX_MAX)
        current_IL=INDEX_MAX;
         
      calibrated_IL[ts] = (UWORD8)(current_calibrated_IL);  

      // Keep the minimum IL
      if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
      {
        // Beacon frequency
        l1ps.ILmin_beacon     = min((UWORD8) current_IL,l1ps.ILmin_beacon);
      }
      else
      {
        // Daughter frequency
        l1ps.ILmin_others[ts] = min((UWORD8) current_IL, l1ps.ILmin_others[ts]);
      }

      // Input Level selection among ILmax found on each timeslot during the block (when burst = 3)
      //-------------------------------------------------------------------------------------------

      if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
      {
        // If CRC good
        if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100))
        {
          // If ((PR_MODE A and TFI good) or (PR_MODE B))
          if ((l1ps.read_param.dl_pwr_ctl.pr_mode != 0) || (!(pr_table[ts] & 0x80)))
          {

            // If TFI good
            if (!(pr_table[ts] & 0x80))
            {
              // Memorize decoded PR
              l1ps.last_PR_good = ((pr_table[ts] & 0x1f) << 1);
            }            

            if (l1ps.ILmin_others[ts] != 255)
            {
              UWORD8 IL_norm;

              // IL normalization to beacon (ILnorm = ILmax_others(ts) - PR)
              IL_norm = l1ps.ILmin_others[ts] - ((pr_table[ts] & 0x1f) << 1);

              // Update IL_min with the minimum found IL
              IL_norm_min = min(IL_norm, IL_norm_min);
            }
          }
        } // End if "CRC good"

      } // End if "burst = 3"

      // Next downlink block
      rx_no ++;

    } // End if "timeslot used for downlink PDCH"

    // Next timeslot
    bit_mask >>= 1;

  } // End for "each timeslot...."


  // IL selection for the next block if burst = 3
  // **********************************************

  if(pdsp_db_r_ptr->d_burst_nb_gprs == 3)
  {
    UWORD8  i, new_IL;
    UWORD16 input_level;
    WORD16  new_calibrated_IL;

    // Select the minimum IL between minimum IL found on daughter frequencies (normalized to beacon)
    // and minimum IL found on the beacon
    IL_norm_min = min(IL_norm_min, l1ps.ILmin_beacon);

    // If a valid IL has been found
    if (IL_norm_min != 255)
    {
      // FIFO management
      for (i=3;i>0;i--)
        l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1];

      l1a_l1s_com.Scell_info.buff_beacon[0] = IL_norm_min;

      // last_input_level[serving beacon] updating
      //------------------------------------------

      // Find min IL in FIFO
      new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4);
  
      // Input levels are always stored with lna_on

      // lna_off processing
      new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq));

      if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

      l1ctl_encode_lna((UWORD8)(new_calibrated_IL >> 1),
                       &(l1a_l1s_com.last_input_level[serving_index].lna_off),
                       l1a_l1s_com.Scell_info.radio_freq);

      l1a_l1s_com.last_input_level[serving_index].input_level = new_IL +
        l1a_l1s_com.last_input_level[serving_index].lna_off *
          l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq);
    }

    // transfer_meas updating
    //-----------------------

    // IL = (min IL in FIFO) + PR (Middle of the range specified by the last decoded PR with CRC and TFI good)
    // Input levels are always stored with lna_on
    input_level = l1a_l1s_com.last_input_level[serving_index].input_level
                  - l1a_l1s_com.last_input_level[serving_index].lna_off *
                    l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq)
                  + l1ps.last_PR_good;

    // IL_2_AGC_xx array size 
    if (input_level>INDEX_MAX) input_level = INDEX_MAX;

    // lna_off processing
    new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna));
    
    if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

    l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna);

    l1a_l1s_com.Scell_info.transfer_meas.input_level = input_level +
      l1a_l1s_com.Scell_info.transfer_meas.lna_off *
        l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna);

  } // End if "burst = 3"

} // End of "l1pctl_dpcmb_agc_read"

/*-------------------------------------------------------*/
/* l1pctl_pgc()                                          */
/*-------------------------------------------------------*/
/* Description :                                         */
/* =============                                         */
/*  This function is used in packet transfer mode for the*/
/*  Read phase of power measurements. It permits to:     */
/*  - Process the IL value in function of the Pm and AGC */
/*    used                                               */
/*  - Update the FIFO[beacon] used in packet transfer AGC*/
/*    algorithms                                         */
/*  - Update last_input_level                            */
/*                                                       */
/* WARNING: in the layer 1 code, input levels IL(l1) use */
/*          format 7.1:                                  */
/*               *********************                   */
/*               * IL(l1) = - 2 x IL *                   */
/*               *********************                   */
/*          -> Reversed sign, reversed test conditions   */
/*          -> max replaced by min                       */
/*          ex: if IL -120 dBm, IL(l1) = 240             */
/*-------------------------------------------------------*/
UWORD8 l1pctl_pgc(UWORD8 pm, UWORD8 last_known_il, UWORD8 lna_off, UWORD16 radio_freq)
{
  UWORD8       i, new_IL;
  WORD8        delta1_freq, delta2_freq;
  WORD16       delta_drp_gain=0;
  UWORD16      lna_value;
  WORD16       used_agc, current_IL, current_calibrated_IL, new_calibrated_IL;
  WORD32       index;
#if (RF_FAM == 61)
  UWORD16      arfcn;
#endif
  UWORD16 dco_algo_ctl_pw_temp = 0;
  UWORD8 if_ctl = 0;
#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION)
  UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
#endif

  // Calibration factors
  delta1_freq = l1ctl_encode_delta1(radio_freq);
  delta2_freq = l1ctl_encode_delta2(radio_freq);

  // initialize index
#if(L1_FF_MULTIBAND == 0)
  index = radio_freq - l1_config.std.radio_freq_index_offset;

#else
  index = l1_multiband_radio_freq_convert_into_operative_radio_freq(radio_freq);
#endif


  // LNA attenuation
  lna_value = lna_off * l1ctl_get_lna_att(radio_freq);

  // Used AGC in the control phase (format F7.1)
  used_agc = (Cust_get_agc_from_IL(radio_freq, last_known_il >> 1, PWR_ID)) << 1;


#if (RF_FAM == 61)
  // DRP correction
#if (L1_FF_MULTIBAND == 0)  
  arfcn = Convert_l1_radio_freq(radio_freq);
#else
  arfcn=radio_freq;
#endif 

   #if (CODE_VERSION != SIMULATION)


#if (PWMEAS_IF_MODE_FORCE == 0)            
       cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , 
           last_known_il,
           radio_freq, if_threshold);
     #else
       if_ctl = IF_120KHZ_DSP;
       dco_algo_ctl_pw_temp = DCO_IF_0KHZ;                     
     #endif        
    
     lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off;
     delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc);    // F7.1 format

     if(if_ctl == IF_100KHZ_DSP){
       delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ;
     }
     else{ /* i.e. if_ctl = IF_120KHZ_DSP*/
       delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ;    
     }


   #endif
#endif

  if (0==pm)  // Check and filter illegal pm value by using last valid IL
    current_IL = l1a_l1s_com.last_input_level[index].input_level - lna_value;
  else
    current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq));

  // Calibrated IL processing
  current_calibrated_IL = current_IL - delta1_freq - delta2_freq;
  
  // Protect IL stores against overflow 
  if (current_calibrated_IL>INDEX_MAX)
    current_calibrated_IL=INDEX_MAX;
  if (current_IL>INDEX_MAX)
    current_IL=INDEX_MAX;

  // if radio freq is the serving beacon
  //------------------------------------
  if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
  {
    // FIFO management
    for (i=3;i>0;i--)
      l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1];
    l1a_l1s_com.Scell_info.buff_beacon[0] = (UWORD8) current_IL;

      // Find min IL in FIFO
    new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4);

    // lna_off processing
    new_calibrated_IL = (WORD16) (new_IL - delta1_freq - delta2_freq);
    if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX;

    l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1),
                     &(l1a_l1s_com.last_input_level[index].lna_off),
                     radio_freq);

    l1a_l1s_com.last_input_level[index].input_level = new_IL +
      l1a_l1s_com.last_input_level[index].lna_off *
        l1ctl_get_lna_att(radio_freq);
  }

  // if radio freq is a neighbor beacon
  //-----------------------------------
  else
  {
    // Update last_input_level (IL with LNA ON)
    l1ctl_encode_lna((UWORD8)(current_calibrated_IL>>1), 
                     &(l1a_l1s_com.last_input_level[index].lna_off),
                     radio_freq);

    l1a_l1s_com.last_input_level[index].input_level = current_IL +
      l1a_l1s_com.last_input_level[index].lna_off *
        l1ctl_get_lna_att(radio_freq);
  }

  return((UWORD8)current_calibrated_IL);

} // End of "l1pctl_pgc"
#endif