view src/cs/layer1/p_cfile/l1p_cmpl.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents 4e78acac3d88
children
line wrap: on
line source

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

#define  L1P_CMPL_C

//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

#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_tabs.h"
  #include "l1_trace.h"
  #if L2_L3_SIMUL
    #include "l2_l3.h"
    #include "hw_debug.h"
  #endif

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_sign.h"

  #if TESTMODE
    #include "l1tm_msgty.h"
    #include "l1tm_signa.h"
  #endif

  #include "macs_def.h"
  #include "macs_cst.h"

  #include "sim_cons.h"
  #include "sim_def.h"
  extern T_hw FAR hw;

#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 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_tabs.h"
  #include "l1_trace.h"

  #if L2_L3_SIMUL
    #include "l2_l3.h"
    #include "hw_debug.h"
  #endif

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_sign.h"

  #if TESTMODE
    #include "l1tm_msgty.h"
    #include "l1tm_signa.h"
  #endif

  #include "macs_def.h"
  #include "macs_cst.h"
#endif

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

#include "l1_ctl.h"

/*-------------------------------------------------------*/
/* Prototypes of external functions used in this file.   */
/*-------------------------------------------------------*/
void l1dmacro_synchro             (UWORD32 when, UWORD32 value);
void l1dmacro_offset              (UWORD32 offset_value, WORD32 relative_time);
void l1dmacro_rx_synth            (UWORD16 arfcn);
void l1dmacro_agc                 (UWORD16 arfcn,WORD8 gain, UWORD8 lna
                                                 	#if (RF_FAM == 61)
                                                 	   ,UWORD8 if_ctl
                                                 	#endif
													);
#if (L1_MADC_ON == 1)
#if (RF_FAM == 61)
void l1dmacro_rx_nb               (UWORD16 arfcn, UWORD8 adc_active, UWORD8 csf_filter_choice
#if (NEW_SNR_THRESHOLD == 1)
    ,UWORD8 saic_flag
#endif /* NEW_SNR_THRESHOLD */
    );
#endif /* RF_FAM == 61*/
#else  /* L1_MADC_ON == 1*/
void l1dmacro_rx_nb               (UWORD16 arfcn);
#endif /* L1_MADC_ON == 1*/

void l1dmacro_afc                 (UWORD16 afc_value, UWORD8 win_id);
#if (RF_FAM == 61)
  void l1dtpu_serv_rx_nb            (UWORD16 radio_freq, WORD8 agc, UWORD8 lna_off,
                                     UWORD32 synchro_serv,UWORD32 new_offset,BOOL change_offset,
                                     UWORD8 adc_active, UWORD8 csf_filter_choice,
                                     UWORD8 if_ctl
#if (NEW_SNR_THRESHOLD == 1)
                                     ,UWORD8 saic_flag
#endif /* NEW_SNR_THRESHOLD */
                                     );

  void l1pdtpu_serv_rx_nb           (UWORD16 radio_freq, WORD8 agc, BOOL lna_off,
                                     UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx,
                                     UWORD8 rx_group_id, BOOL rx_done_flag,
                                     UWORD8 adc_active, UWORD8 csf_filter_choice,
                                     UWORD8 if_ctl
#if (NEW_SNR_THRESHOLD == 1)
                                    ,UWORD8 saic_flag
#endif /* NEW_SNR_THRESHOLD */
                                     );
#endif /* RF_FAM == 61*/
#if(RF_FAM != 61)
void l1dtpu_serv_rx_nb            (UWORD16 radio_freq, WORD8 agc, UWORD8 lna_off,
                                   UWORD32 synchro_serv,UWORD32 new_offset,BOOL change_offset, UWORD8 adc_active);

void l1pdtpu_serv_rx_nb           (UWORD16 radio_freq, WORD8 agc, BOOL lna_off,
                                   UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx,
                                   UWORD8 rx_group_id, BOOL rx_done_flag,UWORD8 adc_active);
#endif
void l1pdtpu_serv_tx              (UWORD16 radio_freq, UWORD8 timing_advance,
                                   UWORD32 offset_serv, UWORD8 tx_id, UWORD8 num_tx,
                                   UWORD8 tx_group_id, UWORD8 switch_flag, BOOL burst_type,
                                   BOOL rx_flag,UWORD8 adc_active);
UWORD8 l1pdtpu_interf_meas        (UWORD16 radio_freq,
                                   WORD8  agc,
                                   UWORD8  lna_off,
                                   UWORD8  meas_bitmap,
                                   UWORD32 offset_serv,
                                   UWORD16 win_id,
                                   UWORD8  synchro_ts
                                #if(RF_FAM == 61)
                                   ,UWORD8 if_ctl
                                #endif
                                );

void l1s_read_l3frm               (UWORD8 pwr_level, API *info_address, UWORD32 task_rx);
void l1ps_macs_read               (UWORD8 pr_table[8]);
void l1ps_macs_ctrl               (void);
#if TESTMODE
  void l1ps_tmode_macs_ctrl               (void);
#endif
void l1pddsp_transfer_mslot_power (UWORD8 *txpwr, UWORD16 radio_freq, UWORD8 ul_bitmap);

void l1pddsp_single_tx_block      (UWORD8 burst_nb, UWORD8 *data, UWORD8  tsc,
                                   UWORD16 radio_freq);
void l1pddsp_idle_prach_data      (BOOL    polling, UWORD8  cs_type, UWORD16  channel_request_data,
                                   UWORD8  bsic, UWORD16 radio_freq);
void l1pddsp_idle_prach_power     (UWORD8 txpwr, UWORD16  radio_freq, UWORD8 ts);
#if FF_L1_IT_DSP_USF
void l1pddsp_idle_rx_nb           (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq,
                                   UWORD8 timeslot_no, BOOL ptcch_dl, BOOL usf_interrupt);
#else
void l1pddsp_idle_rx_nb           (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq,
                                   UWORD8 timeslot_no, BOOL ptcch_dl);
#endif

void l1pddsp_ul_ptcch_data        (UWORD8 cs_type, UWORD16  channel_request_data, UWORD8  bsic, UWORD16 radio_freq, UWORD8 timeslot_no);
void l1ps_tcr_ctrl                (UWORD8 pm_position);
void l1pd_afc                     (void);
void l1pddsp_interf_meas_ctrl     (UWORD8  nb_meas_req);
void l1pddsp_meas_ctrl            (UWORD8 nbmeas, UWORD8 pm_pos);
void maca_power_control           (UWORD8 assignment_id, BOOL crc_error, WORD8 bcch_level, UWORD16 *radio_freq, WORD8 *burst_level, UWORD8 *pch);
WORD16 l1s_encode_rxlev           (UWORD8 inlevel);

void   l1pctl_pagc_ctrl           (WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq,UWORD8 serving_cell);
UWORD8 l1pctl_pagc_read           (UWORD8 pm, UWORD16 radio_freq);
void   l1pctl_transfer_agc_ctrl   (WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq);
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);
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]);
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]);
void l1ps_macs_header_decoding    (UWORD8 rx_no, UWORD8 *tfi_result, UWORD8 *pr);
void l1ps_update_read_set_parameters(void);
void l1ps_bcch_meas_ctrl          (UWORD8 ts);

//#pragma DUPLICATE_FOR_INTERNAL_RAM_END


/*-------------------------------------------------------*/
/* l1ps_ctrl_single()                                    */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_single(UWORD8 task, UWORD8 burst_id)
{
  UWORD16        radio_freq;
  T_INPUT_LEVEL *IL_info_ptr;
  #if (RF_FAM == 61)
    UWORD16 dco_algo_ctl_nb = 0;
    UWORD8 if_ctl = 0;
    UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
    // By default we choose the hardware filter
    UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER;
  #endif
  #if (NEW_SNR_THRESHOLD == 1)
  UWORD8 saic_flag=0;
  #endif /* NEW_SNR_THRESHOLD */
  // needs to be defined for maca_power_control() function call
  #define DL_pwr_ctrl   l1pa_l1ps_com.transfer.dl_pwr_ctrl

  if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) &&
    !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    // Catch ARFCN.
    // *************

    // Get ARFCN to be used for current control.
    radio_freq = l1a_l1s_com.dedic_set.radio_freq;

    // Traces and debug.
    // ******************

    #if (TRACE_TYPE==5) && FLOWCHART
      trace_flowchart_dsp_tpu(dltsk_trace[task].name);
      if(burst_id == BURST_1) trace_flowchart_dsptx(dltsk_trace[task].name);
    #endif

    #if (TRACE_TYPE!=0)
      if (l1pa_l1ps_com.transfer.single_block.activity & (SINGLE_DL | SINGLE_UL)) // trace only if a window is programmed
        trace_fct(CST_L1PS_CTRL_SINGLE, radio_freq);
    #endif

    l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

    /**************************************************************************/
    /* Program DSP for mulstislot operation...                                */
    /**************************************************************************/
    /*===============*/
    /* Downlink      */
    /*===============*/
    if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL)
    {
      // Programs DSP.
    #if FF_L1_IT_DSP_USF
      l1pddsp_idle_rx_nb(burst_id,
                         l1pa_l1ps_com.transfer.aset->tsc,
                         radio_freq,
                         0,
                         FALSE,
                         FALSE);
    #else
      l1pddsp_idle_rx_nb(burst_id,
                         l1pa_l1ps_com.transfer.aset->tsc,
                         radio_freq,
                         0,
                         FALSE);
    #endif

      // Flag DSP programmation.
      // Set "CTRL_RX" flag in the controle flag registers.
      l1s.dsp_ctrl_reg |= CTRL_RX;
    }

    /*===============*/
    /* Uplink        */
    /*===============*/
    if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_UL)
    {
      // Pgme DSP for Single block TX on TS=3.
      l1pddsp_single_tx_block (burst_id,
                               l1pa_l1ps_com.transfer.single_block.data_array,
                               l1pa_l1ps_com.transfer.aset->tsc,
                               radio_freq);

      // TXPWR control needs to take into account ALPHA, GAMMA and C values, not only TXPWR MAX
      // => maca_power_control() needs to be called
      // Initialization of txpwr control values for all time slots
      {
        UWORD8   txpwr[8];
        UWORD8   i;

        // Call Uplink Transmit Power level algorithm
#if 0	/* LoCosto version */
        maca_power_control(l1pa_l1ps_com.transfer.aset->assignment_id,
#else	/* TCS211 reconstruction */
        maca_power_control(DL_pwr_ctrl.assignment_id,
#endif
                           DL_pwr_ctrl.crc_error,
                           DL_pwr_ctrl.bcch_level,
                           DL_pwr_ctrl.radio_freq_tbl,
                           DL_pwr_ctrl.burst_level,
                           txpwr);

        for(i = 0; i < 8; i++)
        {
          l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = txpwr[i];
        }
      }

      // Pgme DSP for Transmit power on TS=3.
      l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, 0x80 >> 3);

      // Flag DSP programmation.
      // Set "CTRL_TX" flag in the controle flag registers.
      l1s.dsp_ctrl_reg |= CTRL_TX;
    }

    /**************************************************************************/
    /* Program TPU for single slot operation...                               */
    /**************************************************************************/

    /*===============*/
    /* Downlink      */
    /*===============*/
    if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL)
    {
      WORD8  agc;
      UWORD8  lna_off;

      // Update AGC
      l1pctl_transfer_agc_ctrl(&agc, &lna_off, radio_freq);


      #if (RF_FAM == 61)
          // Locosto DCO

         cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID,
                                                  l1a_l1s_com.Scell_used_IL.input_level ,
                                                  radio_freq, if_threshold);
         l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb);

      #if (L1_SAIC != 0)
        // If SAIC is enabled, call the low level SAIC control function
        // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
        //       the l1pctl_transfer_agc_ctrl above
        csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
        #if (NEW_SNR_THRESHOLD == 1)
            ,task
            ,&saic_flag
        #endif
        );
      #endif

         // tpu pgm...
        l1pdtpu_serv_rx_nb(radio_freq,
                           agc,
                           lna_off,
                           0,
                           l1s.tpu_offset,
                           1,
                           1,
                           TRUE,
                           INACTIVE,
                           csf_filter_choice,
                           if_ctl
      #if (NEW_SNR_THRESHOLD == 1)
                            ,saic_flag
      #endif /* NEW_SNR_THRESHOLD */
                           );
      #endif /* RF_FAM == 61*/
      #if (RF_FAM != 61)
        // tpu pgm...
         #if (L1_SAIC != 0)
           // If SAIC is enabled, call the low level SAIC control function
           // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
           //       the l1pctl_transfer_agc_ctrl above
           l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
          #if (NEW_SNR_THRESHOLD == 1)
               ,task
          #endif
          );
         #endif


        l1pdtpu_serv_rx_nb(radio_freq,
                           agc,
                           lna_off,
                           0,
                           l1s.tpu_offset,
                           1,
                           1,
                           TRUE,
                           INACTIVE);
      #endif

      // Set tpu window identifier for Synthesizer and
      // according to last RX group position.
      l1s.tpu_win = l1_config.params.rx_synth_load_split + RX_SPLIT_TABLE[0];

      // Flag TPU programmation.
      // Set "CTRL_RX" flag in the controle flag registers.
      l1s.tpu_ctrl_reg |= CTRL_RX;
    }

    /*===============*/
    /* Uplink        */
    /*===============*/
    if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_UL)
    {
      // Program single block UL slot.
      // ******************************
      l1pdtpu_serv_tx(radio_freq,
                      l1pa_l1ps_com.transfer.aset->packet_ta.ta,
                      l1s.tpu_offset,
                      3,
                      1,
                      1,
                      0,
                      TX_NB_BURST,
                      l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL,
                      INACTIVE);

      // Set tpu window identifier for Synthesizer and
      // according to last TX group position.
      l1s.tpu_win =(UWORD16)( (l1_config.params.rx_synth_load_split) +
                    ((UWORD16)3 * BP_SPLIT) + l1_config.params.tx_nb_load_split);

      // Flag TPU programmation.
      // Set "CTRL_TX" flag in the controle flag registers.
      l1s.tpu_ctrl_reg |= CTRL_TX;

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        RTTL1_FILL_UL_NB(task, l1pa_l1ps_com.transfer.aset->packet_ta.ta, l1s.applied_txpwr)
      #endif
    }

    /*===============*/
    /* General       */
    /*===============*/
    if(burst_id == BURST_4)
    {
      // Single block UL is now complete, reset its activity flag.
      l1pa_l1ps_com.transfer.single_block.activity &= SINGLE_UL_MASK;

      if(l1pa_l1ps_com.transfer.aset->allocated_tbf == SINGLE_BLOCK_DL)
      {
        // Single block UL is now complete.
        l1pa_l1ps_com.transfer.single_block.activity &= SINGLE_DL_MASK;
      }
    }
  } // End if(task enabled and semaphore false)

  else
  // When the task is aborted, we must continue to make dummy
  // DSP programming to avoid communication mismatch due
  // to C/W/R pipelining.
  {
    // Flag dummy DSP programmation.
    // Set "CTRL_TX" flag in the controle flag registers.
    l1s.dsp_ctrl_reg |= CTRL_TX;
  }
}

/*-------------------------------------------------------*/
/* l1ps_ctrl_prach()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_prach(UWORD8 task, UWORD8 burst_id)
{
  UWORD16  radio_freq;
  UWORD8   txpwr;
  UWORD8   adc_active = INACTIVE;

  // Get ARFCN to be used for current control.
  // ******************************************

  radio_freq = l1pa_l1ps_com.p_idle_param.radio_freq;

  // Get TXPWR value
  txpwr = l1s.applied_txpwr;

  // Traces and debug.
  // ******************

  #if (TRACE_TYPE!=0)
    trace_fct(CST_L1S_CTRL_RACH, radio_freq);
  #endif

  #if (TRACE_TYPE==5) && FLOWCHART
    trace_flowchart_dsp_tpu(dltsk_trace[task].name);
  #endif

  #if FF_L1_IT_DSP_USF
    // Whenever the USF status is unknown then the PRACH control execution
    // has to be postponed until DSP USF interrupt fires.
    if (l1ps_macs_com.usf_status != USF_AWAITED)
    {
  #endif // FF_L1_IT_DSP_USF

  l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

      #if FF_L1_IT_DSP_USF
        // TPU and DSP have to be programmed for transmission only if the USF is
        // good otherwise this is not a valid opportunity. If there was no USF
        // uncertainty then the test is void.
        if ( (l1ps_macs_com.usf_status != USF_IT_DSP)
             || (((l1ps_dsp_com.pdsp_ndb_ptr->d_usf_updated_gprs >> ((7-0)*2)) & 0x0003) == USF_GOOD))
        {
          // Flags PRACH burst was controlled to TPU/DSP (not cancelled due to USF)
          l1pa_l1ps_com.pra_info.prach_controlled = TRUE;
      #endif // FF_L1_IT_DSP_USF

  #if (CODE_VERSION!=SIMULATION)
    #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3)
      L1_trace_string("PRA");
    #endif
  #endif

  // Programs DSP for required task.
  // ********************************
  {
    UWORD8  cs_type;

    if (l1pa_l1ps_com.access_burst_type == ACC_BURST_8)
      cs_type = CS_PAB8_TYPE;
    else
      cs_type = CS_PAB11_TYPE;

    // ACCESS PRACH dsp control.
    l1pddsp_idle_prach_data(FALSE,
                            cs_type,
                            l1pa_l1ps_com.pra_info.channel_request_data,
                            l1a_l1s_com.Scell_info.bsic,
                            radio_freq);
  }

  l1pddsp_idle_prach_power(txpwr,
                           radio_freq,
                           3);

  // ADC measurement
  // ***************

  // check if during the RACH an ADC measurement must be performed
  if (l1a_l1s_com.adc_mode & ADC_EACH_RACH)  // perform ADC on each burst
     adc_active = ACTIVE;

  // Programs TPU for required task.
  // ********************************

  // tpu pgm...
  l1dtpu_serv_tx_ra(radio_freq, l1s.tpu_offset, txpwr, adc_active);

  // Set tpu window identifier for Power meas if any.
  l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_ra_load_split + l1_config.params.rx_synth_load_split;

  // Store frame number to report to L3
  l1pa_l1ps_com.pra_info.fn_to_report = l1s.next_time.fn;

  #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
    RTTL1_FILL_UL_AB(task,txpwr)
  #endif

  // Flag DSP and TPU programmation.
  // ********************************

  // Set "CTRL_TX" flag in the controle flag register.
  l1s.tpu_ctrl_reg |= CTRL_PRACH;
  l1s.dsp_ctrl_reg |= CTRL_TX;

      #if FF_L1_IT_DSP_USF
        }// if ((l1ps_macs_com.usf_status != USF_IT_DSP) || USF_GOOD)
        else
        {
          // PRACH has been cancelled because USF not FREE. Hence Read is skipped.
          l1pa_l1ps_com.pra_info.prach_controlled = FALSE;
        }
      #endif

  #if FF_L1_IT_DSP_USF
    } // if (l1ps_macs_com.usf_status != USF_AWAITED)
  #endif
}

/*-------------------------------------------------------*/
/* l1ps_ctrl_poll()                                      */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_poll(UWORD8 task, UWORD8 burst_id)
{
  UWORD16  radio_freq;

  // Get ARFCN to be used for current control.
  // ******************************************
  if(l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED)
    radio_freq = l1a_l1s_com.dedic_set.radio_freq;
  else
    radio_freq = l1pa_l1ps_com.p_idle_param.radio_freq;

  // Traces and debug.
  // ******************

  #if (TRACE_TYPE!=0)
    trace_fct(CST_L1PS_CTRL_POLL, radio_freq);
  #endif

  #if (TRACE_TYPE==5) && FLOWCHART
    trace_flowchart_dsp_tpu(dltsk_trace[task].name);
  #endif

  l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

  #if (CODE_VERSION!=SIMULATION)
    #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3)
      L1_trace_string("PRA");
    #endif
  #endif

  // Programs DSP for required task.
  // ********************************
  {
    UWORD8  cs_type;

    cs_type = l1pa_l1ps_com.poll_info.pol_resp_type;

    if ((cs_type == CS_PAB8_TYPE) || (cs_type == CS_PAB11_TYPE))
    {
      // IDLE POLLING PRACH dsp control.
      l1pddsp_idle_prach_data(TRUE,
                              cs_type,
                              l1pa_l1ps_com.poll_info.chan_req.prach_data[0],
                              l1a_l1s_com.Scell_info.bsic,
                              radio_freq);

      l1pddsp_idle_prach_power(l1s.applied_txpwr,
                               radio_freq,
                               3);

      // Programs TPU for required task.
      // ********************************
      // tpu pgm...
      l1dtpu_serv_tx_ra(radio_freq, l1s.tpu_offset, l1s.applied_txpwr,INACTIVE);

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        RTTL1_FILL_UL_AB(task,l1s.applied_txpwr)
      #endif
    }
    else
    {
      UWORD8   tsc;

      if(l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED)
        tsc = l1pa_l1ps_com.transfer.aset->tsc;
      else
        tsc = l1pa_l1ps_com.pccch.packet_chn_desc.tsc;

      // Pgm DSP for Poll Response TX NB on TS=3.
      l1pddsp_single_tx_block (burst_id,
                              l1pa_l1ps_com.poll_info.chan_req.cs1_data,
                              tsc,
                              radio_freq);

      // Pgm DSP for Transmit power.
      l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, 0x80>>3);

      // Programs TPU for required task.
      // ********************************
      // tpu pgm...
      l1dtpu_serv_tx_nb(radio_freq,
                         l1pa_l1ps_com.poll_info.timing_advance,
                         l1s.tpu_offset,
                         l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[3],INACTIVE);

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        RTTL1_FILL_UL_NB(task, l1pa_l1ps_com.poll_info.timing_advance, l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[3])
      #endif
    }
  }


  // Set tpu window identifier for Power meas if any.
  l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split;

  // Store frame number to report to L3
  if (burst_id == BURST_4)
    l1pa_l1ps_com.poll_info.fn_to_report = l1s.next_time.fn;

  // Flag DSP and TPU programmation.
  // ********************************

  // Set "CTRL_TX" flag in the controle flag register.
  l1s.tpu_ctrl_reg |= CTRL_TX;
  l1s.dsp_ctrl_reg |= CTRL_TX;
}


#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1s_ctrl_pdtch()                                      */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:  This is the control function for Multislot Rx/Tx                */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */

/*-------------------------------------------------------*/
void l1ps_ctrl_pdtch(UWORD8 task, UWORD8 burst_id)
{
  if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) &&
    !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    UWORD16        radio_freq;
    #if (RF_FAM == 61)
      // By default we choose the hardware filter
      UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER;
    #endif
    #if (NEW_SNR_THRESHOLD == 1)
      UWORD8 saic_flag=0;
    #endif  /* NEW_SNR_THRESHOLD */
    // Traces and debug.
    // ******************

    #if (TRACE_TYPE==5) && FLOWCHART
      trace_flowchart_dsp_tpu(dltsk_trace[PDTCH].name);
    #endif

    l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

    // Catch channel description and ARFCN.
    // *************************************

    // Get ARFCN to be used for current control. This  ARFCN comes from
    // the HOPPING algorithm called just before calling this function.
    radio_freq = l1a_l1s_com.dedic_set.radio_freq;

    #if (TRACE_TYPE==5) // in simulation trace only one time by frame
      trace_fct(CST_L1PS_CTRL_PDTCH, radio_freq);
    #endif

    /**************************************************************************/
    /* Program DSP for mulstislot operation...                                */
    /**************************************************************************/
    {
      UWORD8  tx_allocation;

      #if TESTMODE
      if (l1_config.TestMode && (l1_config.tmode.tx_params.burst_data == 11))
        // Call dummy MACS for CMU200 loopback mode
        l1ps_tmode_macs_ctrl();
      else
      #endif
      {
        // Call MACS for Medium control, DATA control and RLC-MACS management
        l1ps_macs_ctrl();
      }

      #if FF_L1_IT_DSP_USF
        if (l1ps_macs_com.usf_status != USF_AWAITED)
        {
      #endif
      // Compute tx_allocation mixing NB and RA allocations.
      tx_allocation = l1ps_macs_com.tx_nb_allocation | l1ps_macs_com.tx_prach_allocation;

      // Pgme TXPWR only if any UL.
      if(tx_allocation)
      {
        // Pgme DSP for Transmit power.
        // !!! Warning: This function must be called before l1pdtpu_serv_tx()
        // !!! a_ctrl_abb_gprs is partly overwritten by l1pdtpu_serv_tx()
        l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, tx_allocation);
      }
      #if FF_L1_IT_DSP_USF
        }
      #endif
    }


    /**************************************************************************/
    /* Program TPU for mulstislot operation...                                */
    /**************************************************************************/
    {
      WORD8  ts             = 0;
      UWORD8 rx_group_id    = 0;
      UWORD8 tx_group_id    = 0;
      BOOL   pwr_programmed = FALSE;
      UWORD8 bit_mask       = 0x80;
      WORD8  agc;
      UWORD8 lna_off;
      BOOL   rx_done_flag;
      BOOL   adc_done = FALSE;
      UWORD8 adc_active = INACTIVE;

     #if (RF_FAM == 61)
       UWORD16 dco_algo_ctl_nb = 0;
       UWORD16 dco_algo_ctl_pw = 0;
       UWORD8 if_ctl =0;  //omaps00090550;
       UWORD8 tot_num_rx = 0;
	   UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
     #endif

      // AGC and LNA_OFF processing
      //---------------------------

      #if FF_L1_IT_DSP_USF
        #if L1_EDA
          if (l1ps_macs_com.usf_status != USF_AWAITED)
        #else
         if (l1ps_macs_com.usf_status != USF_IT_DSP)
      #endif
      #endif
      // Same AGC is used for all timeslots
      l1pctl_transfer_agc_ctrl(&agc, &lna_off, radio_freq);

      #if (L1_SAIC != 0)
        // If SAIC is enabled, call the low level SAIC control function
        // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
        //       the l1pctl_transfer_agc_ctrl above
        csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
        #if (NEW_SNR_THRESHOLD == 1)
            ,task
            ,&saic_flag
        #endif
            );
      #endif

      while(ts < 8)
      {

        #if FF_L1_IT_DSP_USF
          #if L1_EDA
            //Depending on USF status got from DSP, RX allocation may change after
            //receiving the USF interrupt due to USF status updates
            if ((l1ps_macs_com.rx_allocation & bit_mask)
                && (l1ps_macs_com.usf_status != USF_AWAITED))
          #else
               if ((l1ps_macs_com.rx_allocation & bit_mask)
                && (l1ps_macs_com.usf_status != USF_IT_DSP))
          #endif
        #else
        if(l1ps_macs_com.rx_allocation & bit_mask)
        #endif
        {
          // We have detected the 1st RX slot number for a new RX group.

          UWORD8  rx_id  = ts;   // Save 1st RX timeslot number.
          UWORD8  num_rx = 1;    // 1 RX in the RX group for the moment.

          // Increment the RX group ID.
          rx_group_id++;

          #if (RF_FAM == 61)
          //Increment the total number of RX slots
          tot_num_rx++;
          #endif

          // Increment TS.
          ts++;

          // Jump on next timeslot to keep looking for contiguous RX slots.
          bit_mask >>= 1;

          // Look for more contiguous RX slots.
          while((l1ps_macs_com.rx_allocation & bit_mask) && (ts < 8))
          {
            ts++;
            num_rx++;
            #if (RF_FAM == 61)
            tot_num_rx++;
            #endif
            bit_mask >>= 1;
          }

          // Check if more RX bursts follow
          if((l1ps_macs_com.rx_allocation << (ts+1)) & 0xFF)
            rx_done_flag = FALSE;
          else
            rx_done_flag = TRUE;

          #if (RF_FAM == 61) // Locosto DCO
           if(rx_group_id == 1)
           {
             cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID,
                  l1a_l1s_com.Scell_used_IL.input_level, radio_freq,if_threshold);
           }

           if(rx_done_flag == TRUE)
           {
             //dco_algo_ctl has 0000 00ZL
             dco_algo_ctl_nb *= 0x55;   // replicate 0000 00zL as ZLZL ZLZL
             // ZLZLZLZL >> 2*(4-tot_num_rx) where i is the tot_num_rx would produce the
             // desired dco_algo_ctl_nb For Eg if tot_num_rx is 2 the desired pattern is
             // 0000 ZLZL
             dco_algo_ctl_nb = dco_algo_ctl_nb >> (2*( 4 - tot_num_rx));
             l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb);
           }
          #endif
          // ADC measurement
          // ***************
          if (adc_done == FALSE)
          {
            // check if during the PDTCH burst an ADC measurement must be performed
             if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_DL)  // perform ADC only one time
             {
                adc_active = ACTIVE;
                adc_done   = TRUE;
                l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic
             }
             else
               if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_DL) // perform ADC on each period bloc
                 if (l1s.actual_time.fn_mod104 == 10) //periodic with each PDTCH burst in frame 11 (frame with the lowest CPU load)
                   if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period
                   {
                     adc_active = ACTIVE;
                     adc_done   = TRUE;
                     l1a_l1s_com.adc_cpt = 0;
                   }
           }

          // update the TPU with the new TOA if necessary
          if (rx_group_id == 1) // only if synchro performed
            l1ctl_update_TPU_with_toa();

          #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
            trace_fct(CST_L1PS_CTRL_PDTCH_DL_BURST0 + burst_id, radio_freq);
          #endif

          // Program RX scenario.
          l1pdtpu_serv_rx_nb(radio_freq,
                             agc,
                             lna_off,
                             rx_id,
                             l1s.tpu_offset,
                             num_rx,
                             rx_group_id,
                             rx_done_flag,adc_active
                          #if (RF_FAM == 61)
                             ,csf_filter_choice
                             ,if_ctl
                          #endif
                          #if (NEW_SNR_THRESHOLD == 1)
                             ,saic_flag
                          #endif
		                              );

          adc_active = INACTIVE;  // ADC performed only on the first RX burst

          // Set tpu window identifier for Synthesizer and
          // according to last RX group position.
          l1s.tpu_win = (l1_config.params.rx_synth_load_split) +
                        ((UWORD16)rx_id * BP_SPLIT) + RX_SPLIT_TABLE[num_rx-1];


          // Set "CTRL_RX" flag in the controle flag registers.
          l1s.tpu_ctrl_reg |= CTRL_RX;
          l1s.dsp_ctrl_reg |= CTRL_RX;
        }

        else
        #if FF_L1_IT_DSP_USF
          if ((l1ps_macs_com.tx_nb_allocation & bit_mask)
                  && (l1ps_macs_com.usf_status != USF_AWAITED))
        #else
        if(l1ps_macs_com.tx_nb_allocation & bit_mask)
        #endif
        {
          // We have detected the 1st TX NB slot number for a new TX group.

          UWORD8  tx_id       = ts; // Save 1st TX timeslot number.
          UWORD8  num_tx      = 1;  // 1 RX in the TX group for the moment.
          UWORD8  switch_flag;

          // Increment the TX group ID.
          tx_group_id++;

          // Increment TS.
          ts++;

          // Jump on next timeslot to keep looking for contiguous TX slots.
          bit_mask >>= 1;

          // Look for more contiguous TX slots.
          while((l1ps_macs_com.tx_nb_allocation & bit_mask) && (ts < 8))
          {
            ts++;
            num_tx++;
            bit_mask >>= 1;
          }

          // Detect special case: TX NB followed by PRACH.
          if(l1ps_macs_com.tx_prach_allocation & bit_mask)
          {
            switch_flag = 1;
          }
          else
          {
            switch_flag = 0;
          }

          #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
            trace_fct(CST_L1PS_CTRL_PDTCH_UL, radio_freq);
          #endif

          // Program TN NB scenario.
          l1pdtpu_serv_tx(radio_freq,
                          l1pa_l1ps_com.transfer.aset->packet_ta.ta,
                          l1s.tpu_offset,
                          tx_id,
                          num_tx,
                          tx_group_id,
                          switch_flag,
                          0,             // Driver called for Normal Burst.
                          TRUE,INACTIVE);// Flag RX in same frame as TX

          // Set tpu window identifier for Synthesizer and
          // according to last TX group position.
          // TX offset = tx_id * BP_SPLIT
          // TX load = (num_tx-1) * BP_SPLIT + l1_config.params.tx_load_split
          l1s.tpu_win = (l1_config.params.rx_synth_load_split) +
                        ((UWORD16)tx_id * BP_SPLIT) +
                        ((UWORD16)(num_tx -1) * BP_SPLIT) +
                        l1_config.params.tx_nb_load_split;

          // Set "CTRL_TX" flag in the controle flag registers.
          l1s.tpu_ctrl_reg |= CTRL_TX;
          l1s.dsp_ctrl_reg |= CTRL_TX;
        }

        else
            #if FF_L1_IT_DSP_USF
              if ((l1ps_macs_com.tx_prach_allocation & bit_mask)
                  && (l1ps_macs_com.usf_status != USF_AWAITED))
            #else
             if(l1ps_macs_com.tx_prach_allocation & bit_mask)
            #endif
        {
          // We have detected a TX RA.

          UWORD8 switch_flag;

          // Increment the TX group ID.
          tx_group_id++;

          // Jump on next timeslot.
          bit_mask >>= 1;

          // Detect special case: PRACH followed by TX NB.
          if(l1ps_macs_com.tx_nb_allocation & bit_mask)
          {
            switch_flag = 1;
          }
          // Detect special case: PRACH followed by PRACH
          else if (l1ps_macs_com.tx_prach_allocation & bit_mask)
          {
            // Solution with DSP patch supporting PRACH|PRACH
            switch_flag = 2;
          }
          else
          {
            switch_flag = 0;
          }

          #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
            trace_fct(CST_L1PS_CTRL_PDTCH_RA, radio_freq);
          #endif

          // Program TX RA scenario.
          l1pdtpu_serv_tx(radio_freq,
                          l1pa_l1ps_com.transfer.aset->packet_ta.ta,
                          l1s.tpu_offset,
                          ts,
                          1,               // Driver is called for each PRACH.
                          tx_group_id,
                          switch_flag,
                          TX_RA_BURST,     // Driver called for PRACH Burst.
                          TRUE,INACTIVE);  // Flag RX in same frame as TX

          // Set tpu window identifier for Synthesizer and
          // according to last TX group position.
          // TX offset = ts * BP_SPLIT
          // TX load = l1_config.params.tx_nb_load_split
          // original value of TX load (RACH) replaced by TX NB to take into account TX_NB|PRACH with max. TA
          l1s.tpu_win = (l1_config.params.rx_synth_load_split) +
                        ((UWORD16)ts * BP_SPLIT) +
                        l1_config.params.tx_nb_load_split;


          // Increment TS.
          ts++;

          // Set "CTRL_TX" flag in the controle flag registers.
          l1s.tpu_ctrl_reg |= CTRL_TX;
          l1s.dsp_ctrl_reg |= CTRL_TX;
        }

        else
        #if FF_L1_IT_DSP_USF
          if ((l1ps_macs_com.pwr_allocation & bit_mask)
              && (pwr_programmed == 0)
              && (l1ps_macs_com.usf_status != USF_AWAITED))
        #else
        if((l1ps_macs_com.pwr_allocation & bit_mask) && (pwr_programmed == 0))
        #endif
        {
          // We have detected a PWR allocation and no PWR programmed in current frame.
          if((l1pa_l1ps_com.transfer.aset->pc_meas_chan == FALSE) &&
              ((l1s.actual_time.t2 == 1) || (l1s.actual_time.t2 == 9)
               || (l1s.actual_time.t2 == 18)))
          {
            #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
              trace_fct(CST_CTRL_PC_MEAS_CHAN, (UWORD32)(-1));
            #endif

            // Measurement on the beacon (PC_MEAS_CHAN = 0)
            l1ps_bcch_meas_ctrl(ts);
          }
          else
          if(l1pa_l1ps_com.l1ps_en_meas & P_TCRMS_MEAS)
          {
            // Neighbour Measurement CTRL Phase

            // Note: Test on l1s.forbid_meas can't be done from the fact that at this
            // level, l1s.forbid_meas is not set.
            // l1ps_ctrl_pdtch is called before CTRL of FB26/SB26/SBCNF26.
            if(!((l1s.actual_time.t2 == 23) &&
                ((l1s.task_status[FB26].current_status    != INACTIVE) ||
                 (l1s.task_status[SB26].current_status    != INACTIVE) ||
                 (l1s.task_status[SBCNF26].current_status != INACTIVE)))&&
               !(l1pa_l1ps_com.tcr_freq_list.new_list_present &&
                 ((l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 0) ||
                  (l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 103))))
            {
              if(!(l1pa_l1ps_com.meas_param & P_TCRMS_MEAS))
              {
                #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
                  trace_fct(CST_CTRL_TCR_MEAS_1, (UWORD32)(-1));
                #endif

                l1ps_tcr_ctrl((UWORD8)ts);
              }
            }
          } // End of CTRL PDTCH phase

          // Increment TS.
          ts++;

          // Flag that a PWR as been programmed for current frame.
          pwr_programmed = TRUE;

          // Jump on next timeslot.
          bit_mask >>= 1;

          // Call PWR control function

        }

        else
        {
          // Increment TS.
          ts++;

          // Jump on next timeslot.
          bit_mask >>= 1;
        }

      } // End of "while(ts < 8)"

      #if FF_L1_IT_DSP_USF
        if (l1ps_macs_com.usf_status != USF_AWAITED)
      #endif
      // Update of AFC
      l1pd_afc();
    }
  } // End if(task enabled and semaphore false)

  else
  // When the task is aborted, we must continue to make dummy
  // DSP programming to avoid communication mismatch due
  // to C/W/R pipelining.
  {
    #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
      trace_fct(CST_L1PS_CTRL_PDTCH_DUMMY, (UWORD32)(-1));
    #endif

    // Flag dummy DSP programmation.
    // Set "CTRL_TX" flag in the controle flag registers.
    l1s.dsp_ctrl_reg |= CTRL_TX;
  }

}
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM


/*-------------------------------------------------------*/
/* l1s_read_single()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_read_single(UWORD8 task, UWORD8 burst_id)
{
  if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) &&
    !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    // Read param updating...
    if (l1ps.read_param.new_set == TRUE)
    {
      // If it's the first Read phase of the block (first of the new TBF)
      if (burst_id == BURST_1)
      {
        // Update the "read_param" structure
        l1ps_update_read_set_parameters();
      }
    }

    /*--------------------------------------------------------*/
    /* READ TRANSMIT TASK RESULTS...                          */
    /*--------------------------------------------------------*/

    l1_check_com_mismatch(task);

     // check PM error only in case of downlink single block
	if(l1ps.read_param.allocated_tbf == SINGLE_BLOCK_DL)
    {
       UWORD32   pm;
       pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[0] & 0xffff) >> 5;
       l1_check_pm_error(pm,task);
    }


    // Two phase access: downlink PDCH reading
    if((l1ps.read_param.allocated_tbf == TWO_PHASE_ACCESS)&&
       (l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & (0x80 >> 0)))
    {
      UWORD8 IL_for_rxlev[8];
      UWORD8 pr_table[8];

      if (burst_id == BURST_4)
        l1ps_macs_header_decoding(0, &(IL_for_rxlev[0]), &(pr_table[0]));

      // Update AGC and extract IL for RXLEV
      //------------------------------------
      if (l1ps.read_param.dl_pwr_ctl.p0 == 255)
      {
        // No power control mode AGC algorithm
        l1pctl_npc_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr);
      }
      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
          l1pctl_dpcma_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table);
        }
        else
        {
          // BTS power control mode B
          l1pctl_dpcmb_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table);
        }
      } // End of "AGC algorithm"
    }

    #if (TRACE_TYPE!=0) && (TRACE_TYPE !=5)
      trace_fct(CST_L1PS_READ_SINGLE, l1a_l1s_com.Scell_info.radio_freq);
    #endif

    // Read downlink DATA block from MCU/DSP interface.
    // *************************************************
    if(burst_id == BURST_4)
    {
      xSignalHeaderRec *msg;

      #if (TRACE_TYPE==5) // in simulation trace only the 4th burst
        trace_fct(CST_L1PS_READ_SINGLE, l1a_l1s_com.Scell_info.radio_freq);
      #endif

      if(l1ps.read_param.allocated_tbf == TWO_PHASE_ACCESS)
      // 2 phase ACCESS.
      {
        if((l1ps_dsp_com.pdsp_db_r_ptr->d_task_u_gprs & (0x80 >> 3)) &&
           (l1s.task_status[POLL].current_status == INACTIVE))
        // UL block sent...
        {
          // Send confirmation msg to L3/MACA.
          msg = os_alloc_sig(sizeof(T_MPHP_SINGLE_BLOCK_CON));
          DEBUGMSG(status,NU_ALLOC_ERR)

          // Return "Single block" purpose.
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose       =
            l1pa_l1ps_com.transfer.aset->assignment_command;
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->assignment_id =
            l1pa_l1ps_com.transfer.aset->assignment_id;

          // Return status and CRC error (CRC error not applicable).
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status        = SINGLE_UL_DONE;
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = 0;

          // MSG is sent to L1A to stop PCCCH or CCCH/BCCH reading.
          msg->SignalCode = L1P_SINGLE_BLOCK_CON;
          os_send_sig(msg, L1C1_QUEUE);
          DEBUGMSG(status,NU_SEND_QUEUE_ERR)
        }

        if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & (0x80 >> 0))
        // DL block received...
        {
          UWORD16 pwr_level;
          
#if (L1_FF_MULTIBAND == 1)
          UWORD16 operative_radio_freq;
#endif /*(L1_FF_MULTIBAND == 1)*/

          // this bloc doesn't compute the burst input level, so the last_input_level is used.
          
#if (L1_FF_MULTIBAND == 0)
          
          pwr_level = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq].input_level;

#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);
          pwr_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; 

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


          // Read L3 frame block and send msg to L1A.
          l1s_read_l3frm(pwr_level, &(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]), task);
        }
      }
      else
      {
        // SYNCHRO task is not schedule if we are in the specific case:
        // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode)
        // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339)
        if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET)
        {
          //----------------
          // Synchro back
          //----------------
          // Save the "timeslot difference" between new and old configuration
          // in "tn_difference".
          //   tn_difference -> loaded with the number of timeslot to shift.
          //   dl_tn         -> loaded with the new timeslot.
          l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore -
                                      l1a_l1s_com.dl_tn;
          l1a_l1s_com.dl_tn         = l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore;

          // Select DSP Scheduler used in packet Idle (can be CCCH or PCCCH).
          if((l1a_l1s_com.l1s_en_task[ALLC] == TASK_ENABLED)
            || (l1a_l1s_com.l1s_en_task[NP] == TASK_ENABLED)
            || (l1a_l1s_com.l1s_en_task[EP] == TASK_ENABLED))
          {
            // We are in CS Idle on CCCH.
            l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER;
          }

          // Enable SYNCHRO task.
          l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED;
        }

        //------------------
        // Confirmation msg
        //------------------
        // Common part...
        {
          // Send confirmation msg to L3/MACA.
          msg = os_alloc_sig(sizeof(T_MPHP_SINGLE_BLOCK_CON));
          DEBUGMSG(status,NU_ALLOC_ERR)


          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose       =
            l1pa_l1ps_com.transfer.aset->assignment_command;
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->assignment_id =
            l1pa_l1ps_com.transfer.aset->assignment_id;

          msg->SignalCode = L1P_SINGLE_BLOCK_CON;

          // Disable SINGLE task.
          l1s.task_status[task].current_status = INACTIVE;
          l1a_l1s_com.l1s_en_task[task]        = TASK_DISABLED;
        }

        // Differentiated part...

        if(l1pa_l1ps_com.transfer.aset->allocated_tbf == SINGLE_BLOCK_UL)
        // SINGLE UL task is complete.
        {
          // Return status and CRC error (CRC error not applicable).
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status        = SINGLE_UL_DONE;
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = 0;
        }
        else
        if(l1ps.read_param.allocated_tbf == SINGLE_BLOCK_DL)
        // SINGLE DL task is complete.
        {
          API     *info_address;
          UWORD32  i,j;
          UWORD32  word32;

          info_address = &(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]);

          // Return status and CRC error
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status        = SINGLE_DL_DONE;
          ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = ((*info_address & 0x0100) >> 8);

          // Download data from API to message.

          // Get 24 bytes info. from DSP: CS1 meaningful block is of size 12 UWORD16 data.
          // !!! WARNING: word32 type is for compatibility with chipset == 0.
          // Can be word16 if only chipset == 2 is used.
          for (j=0, i=0; i<12; i++)
          {
            word32 = info_address[4 + i]; // Get info word, rem: skip info. header.
            ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->data_array[j++] = (word32 & 0x000000ff);
            ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->data_array[j++] = (word32 & 0x0000ff00) >> 8;
          }
        }

        // send message...
        os_send_sig(msg, L1C1_QUEUE);
        DEBUGMSG(status,NU_SEND_QUEUE_ERR)

      } // End else (!TWO_PHASE_ACCESS)
    }

    // Set flag used to change the read page at the end of "l1_synch".
    l1s_dsp_com.dsp_r_page_used = TRUE;

  } // End if(task enabled and semaphore false)

  else
  // When the task is aborted, we must continue to make dummy
  // DSP/TPU programming to avoid communication mismatch due
  // to C/W/R pipelining. Dummy MCU/DSP reading is also done.
  {
    // Set flag used to change the read page at the end of "l1_synch".
    l1s_dsp_com.dsp_r_page_used = TRUE;
  }
}

#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1ps_read_pdtch()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_read_pdtch(UWORD8 task, UWORD8 burst_id)
{
  if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) &&
    !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    BOOL            beacon;
    T_INPUT_LEVEL  *IL_info_ptr;
    UWORD16         radio_freq;
    WORD8           ts       = 0;
    UWORD8          bit_mask = 0x80;
    WORD8           bcch_level;
    UWORD8          rx_no = 0;
    BOOL            first_valid_block = TRUE;
    BOOL            crc_error =  TRUE;
    UWORD8          i;
    UWORD32         best_snr = 0;
    UWORD32         best_angle = 0;
    UWORD32         best_pm = 0;
    UWORD8          IL_for_rxlev[8], pr_table[8];
    WORD16          best_rxlev_accu = 0;


    static  BOOL    crc_error_tbl[8] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE};
    static  WORD16  rxlev_accu[8]    = {0, 0, 0, 0, 0, 0, 0, 0};
    static  WORD8   burst_level[4] = {(WORD8)0x80, (WORD8)0x80, (WORD8)0x80, (WORD8)0x80};
    static  UWORD16 radio_freq_tbl[4];
    static  UWORD32 toa_val[4] = {0, 0, 0, 0};
    static  UWORD32 snr_val[4] = {0, 0, 0, 0};

    #if TESTMODE
      xSignalHeaderRec *msg;
      static UWORD32 tm_pm_fullres = 0;
      static UWORD32 tm_snr        = 0;
      static UWORD32 tm_toa        = 0;
      static WORD16  tm_angle      = 0;
    #endif


    #define burst_number  l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs
    #define DL_pwr_ctrl   l1pa_l1ps_com.transfer.dl_pwr_ctrl

    // Read parameters updating
    // *************************

    // ***********
    // * WARNING *
    // ***********

    // Because of the STI implementation, the parameters under the "l1pa_l1ps_com.transfer.aset"
    // structure mustn't be used in the Read PDTCH functions
    // This is due to the following case that may happen:
    //
    // C|W R    |
    //  |C W R  |
    //  |  C W R|       TBF 1
    //  |    C W|R <--------------------------- (2) This "read phase" must use the TBF 1 parameters while "aset" has already been updated
    //----------------------                        so the read_param structure is used
    //  |      C|W R <------------------------- (3) The read_param is updated with TBF 2 parameters
    //  |       |C W R                              at the beguining of the first Read of TBF 2
    //  |       |  C W R       TBF 2                so when (l1ps.read_param.new_set = TRUE and burst_id = BURST_1)
    //  |       |    C W R
    //         ^
    //        (1) TBF 2 starting time detected on this frame (no SYNCHRO change needed between TBF1 and TBF 2)
    //         --> aset parameters updated to TBF 2
    //         --> l1ps.read_param.new_set set to TRUE

    // If a new TBF has been enabled...
    if (l1ps.read_param.new_set == TRUE)
    {
      // If it's the first Read phase of the block (first of the new TBF)
      if (burst_id == BURST_1)
      {
        // Update the "read_param" structure
        l1ps_update_read_set_parameters();
      }
    }

    // Traces and debug.
    // ******************

    l1_check_com_mismatch(task);

    radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd;

    if(l1ps.read_param.pc_meas_chan)
    {
      radio_freq_tbl[burst_number] =  radio_freq;
    }
    else
    {
      radio_freq_tbl[burst_number] =  l1a_l1s_com.Scell_info.radio_freq;
    }

    if (radio_freq == l1a_l1s_com.Scell_info.radio_freq)
    {
      beacon=1;
      IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon;
    }
    else
    {
      beacon=0;
      IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas;
    }

    // Call maca_power_control() in order to get TXPWR value
    if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 2)
    {
      UWORD8   txpwr[8];
      UWORD8   i;

      // Due to the CWR pipeleine, maca_power_control() has to be called before the
      // CTRL of the first PDTCH i.e. in l1ps_ctrl_pdtch(). It means that crc_error,
      // radio_freq_tbl[], burst_level[] and bcch_level information are stored on
      // burst4 of READ phase ("l1ps_ctrl_pdtch()") to be used on burst4 of CTRL phase.

      // Call Uplink Transmit Power level algorithm
#if 0	/* LoCosto version */
      maca_power_control(l1ps.read_param.assignment_id,
#else	/* TCS211 reconstruction */
      maca_power_control(DL_pwr_ctrl.assignment_id,
#endif
                         DL_pwr_ctrl.crc_error,
                         DL_pwr_ctrl.bcch_level,
                         DL_pwr_ctrl.radio_freq_tbl,
                         DL_pwr_ctrl.burst_level,
                         txpwr);

      #if TESTMODE
        if(!l1_config.TestMode)
      #endif
        {
          for(i = 0; i < 8; i++)
          {
            l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = txpwr[i];
          }
        }
      }


    if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3)
    /*---------------------------------------------------*/
    /* Complete PDTCH DL block has been processed by DSP */
    /*---------------------------------------------------*/
    {
      #if (TRACE_TYPE == 5) // in simulation trace only the latest burst
        trace_fct(CST_L1PS_READ_PDTCH, radio_freq);
      #endif

      // Call MACS...
      l1ps_macs_read(pr_table);
    }

    // Update AGC and extract IL for RXLEV
    //------------------------------------
    if (l1ps.read_param.dl_pwr_ctl.p0 == 255)
    {
      // No power control mode AGC algorithm
      l1pctl_npc_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr);
    }
    else
    {
      // Downlink power control AGC algorithms
      if (l1ps.read_param.dl_pwr_ctl.bts_pwr_ctl_mode == 0)
      {
        // BTS Power control mode A
        l1pctl_dpcma_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table);
      }
      else
      {
        // BTS power control mode B
        l1pctl_dpcmb_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table);
      }
    } // End of "AGC algorithm"

    // TOA algorithm is called with toa/snr pair from last block (N-1)
    // Feed TOA histogram with values from good bursts (crc_error = FALSE)
    // otherwise input snr = 0.
    #if (TOA_ALGO != 0)
      // Good block, TOA from TS=0
      #if (TOA_ALGO == 2)
        if(l1s.toa_var.toa_snr_mask == 0)
      #else
        if(l1s.toa_snr_mask == 0)
      #endif
      {
        #if (TOA_ALGO == 2)
        {
          UWORD32 snr_temp;
          snr_temp = (crc_error_tbl[0] == FALSE) ? snr_val[burst_id] : 0;
          l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa_val[burst_id]);
        }
        #else
        {
          /* FreeCalypso TCS211 reconstruction */
          if (crc_error_tbl[0] == FALSE)
          {
            l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode,
                                      snr_val[burst_id], toa_val[burst_id],
                                      &l1s.toa_update, &l1s.toa_period_count
                                   #if (FF_L1_FAST_DECODING == 1)
                                      ,0
                                   #endif
                            );
          }
          else
          {
            l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode,
                                      0, toa_val[burst_id],
                                      &l1s.toa_update, &l1s.toa_period_count
                                   #if (FF_L1_FAST_DECODING == 1)
                                      ,0
                                   #endif
                            );
          }
        }
        #endif
      }
    #endif

    /*---------------------------------------------------*/
    /* Read burst demodulation info for control algos    */
    /* Use all burst results to feed the algos.          */
    /*---------------------------------------------------*/
    while(ts < 8)
    {
      if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & bit_mask)
      {
        UWORD32   toa;
        UWORD32   pm;
        UWORD32   angle;
        UWORD32   snr;
        WORD8     rxlev;

        // Read control results and feed control algorithms.
        // **************************************************

        // Read control information.
        toa   = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_toa_gprs[ts]   & 0xffff;
        pm    = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts]   & 0xffff)>>5;
        angle = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_angle_gprs[ts] & 0xffff;
        snr   = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_snr_gprs[ts]   & 0xffff;

        #if (TRACE_TYPE != 0) && (TRACE_TYPE != 5) // for debug trace all bursts
          trace_fct(CST_L1PS_READ_PDTCH_BURST, (UWORD32)(-1));
        #endif

        l1_check_pm_error(pm,task);

        #if TESTMODE
        // Test mode stats
          if (l1_config.TestMode)
          {
            if (bit_mask & l1_config.tmode.stats_config.stat_gprs_slots)
            {
              tm_pm_fullres += (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts]   & 0xffff);
              tm_snr        += snr;
              tm_toa        += toa;
              tm_angle      += (WORD16) angle; // signed
            }
          }
        #endif

        #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
          RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts])
        #endif
        #if 0 //(TRACE_TYPE == 1) || (TRACE_TYPE == 4) // TCS211 reconstruction
          l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts]);
        #endif
        #if (BURST_PARAM_LOG_ENABLE == 1)
          l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts]);
        #endif

        //Look for the pairs angle, snr with the maximum snr
        if (snr > best_snr)
        {
          best_snr = snr;
          best_angle = angle;
          best_pm = pm;
        }

        // store toa value from first TS
        if (ts==0)
        {
          toa_val[burst_id]  = toa;
          snr_val[burst_id]  = snr;
        }

        // Store Received Signal Level to be used in Uplink Transmit Power Algorithm.

        // Compute RXLEV
        rxlev = l1s_encode_rxlev(IL_for_rxlev[ts]);

        // Find first correct PDTCH, save RXLEV and CRC
        if(!crc_error_tbl[ts] && first_valid_block)
        {
          if(l1ps.read_param.pc_meas_chan)
          {
            burst_level[burst_number] = rxlev;
          }
          else
          {
            burst_level[burst_number] = (WORD8)0x80;
          }

          // Measures on first valid block have been performed. Reset flag.
          first_valid_block = FALSE;

          //  Save crc_error
          crc_error = crc_error_tbl[ts];

        } // End of measurements storage

        // If All PDTCH are incorrect (bad CRC) save RXLEV and CRC of the best PDTCH
        if(first_valid_block)
        {
          rxlev_accu[ts] += rxlev;

          if(rxlev_accu[ts] > best_rxlev_accu)
          {
            best_rxlev_accu = rxlev_accu[ts];
            crc_error       = crc_error_tbl[ts];

            if(l1ps.read_param.pc_meas_chan)
            {
              burst_level[burst_number] = rxlev;
            }
            else
            {
              burst_level[burst_number] = (WORD8)0x80;
            }
          }
        }

        // Determine first valid block to be used in next radio block
        if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3)
        /*---------------------------------------------------*/
        /* Complete PDTCH DL block has been processed by DSP */
        /*---------------------------------------------------*/
        {
          crc_error_tbl[ts] = ((l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100) >> 8);

          // Increment Rx burst number
          rx_no++;
        }

        #if TRACE_TYPE==3
          stats_samples_nb(toa,pm,angle,snr,burst_id,task);
        #endif

      }  // End of if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & bit_mask)

      // Increment timeslot
      ts++;

      // Shift Mask.
      bit_mask >>= 1;

    } // End of while(ts < 8)

    // AFC control algorithm is called with values retrieved from
    // burst with max. snr
    // AFC algorithm is called on bursts 0 and 2: this is sufficient to
    // have a correct behavior and this permits to gain CPU
    // Update AFC: Call AFC control function (KALMAN filter).
    #if AFC_ALGO
      #if TESTMODE
        if (l1_config.afc_enable)
      #endif
        {
          if((burst_id == 0) || (burst_id == 2))
            #if (VCXO_ALGO == 0)
              l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)best_angle, best_snr, radio_freq);
            #else
              l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)best_angle, best_snr, radio_freq,l1a_l1s_com.mode);
            #endif
        }
    #endif

    #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4)
        if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
        {
          if ((l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd != 0) ||
              ((l1ps.pc_meas_chan_ctrl == TRUE) &&
               ((l1s.actual_time.t2 == 3) || (l1s.actual_time.t2 == 11) ||
                (l1s.actual_time.t2 == 20))))
            trace_info.pdtch_trace.blk_status |= 0x80 >> burst_id;
        }
    #endif

    if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3)
    /*---------------------------------------------------*/
    /* Complete PDTCH DL block has been processed by DSP */
    /*---------------------------------------------------*/
    {

      l1pa_l1ps_com.transfer.dl_pwr_ctrl.crc_error      = crc_error;
      /*
       * FreeCalypso TCS211 reconstruction: the following line
       * has been taken from the TSM30 source.
       */
      l1pa_l1ps_com.transfer.dl_pwr_ctrl.assignment_id  = l1ps.read_param.assignment_id;

      if(l1ps.read_param.pc_meas_chan)
      {

        // Due to the CWR pipeleine, maca_power_control() has to be called before the
        // CTRL of the first PDTCH i.e. in l1ps_ctrl_pdtch(). It means that crc_error,
        // radio_freq_tbl[], burst_level[] and bcch_level information are stored on
        // burst4 of READ phase to be used on burst4 of CTRL phase.

        l1pa_l1ps_com.transfer.dl_pwr_ctrl.bcch_level = (WORD8)0x80;

        for(i = 0; i < 4; i++)
        {
          l1pa_l1ps_com.transfer.dl_pwr_ctrl.radio_freq_tbl[i] = radio_freq_tbl[i];
          l1pa_l1ps_com.transfer.dl_pwr_ctrl.burst_level[i]    = burst_level[i];
        }

      }
      else
      {
        // Measures have been performed on BCCH Serving Cell. "burst_level" table is
        // not applicable.

        // Download measures made on BCCH Serving Cell.
        l1pa_l1ps_com.transfer.dl_pwr_ctrl.bcch_level = l1pa_l1ps_com.tcr_freq_list.beacon_meas;

        for(i = 0; i < 4; i++)
        {
          l1pa_l1ps_com.transfer.dl_pwr_ctrl.radio_freq_tbl[i] = radio_freq_tbl[i];
          l1pa_l1ps_com.transfer.dl_pwr_ctrl.burst_level[i]    = (WORD8)0x80;
        }

        // Measures on BCCH Serving Cell are only performed every 40ms while
        // maca_power_control() is called every 20ms. "beacon_meas" must then
        // be set to invalid (0x80) until next Serving Cell measure.
        l1pa_l1ps_com.tcr_freq_list.beacon_meas = (WORD8)0x80;

      }

      #if TESTMODE
      // Test mode stats
        if (l1_config.TestMode)
        {
          // Allocate result message.
          msg = os_alloc_sig(sizeof(T_TMODE_PDTCH_INFO));
          DEBUGMSG(status,NU_ALLOC_ERR)
          msg->SignalCode = TMODE_PDTCH_INFO;

          ((T_TMODE_PDTCH_INFO *)(msg->SigP))->pm_fullres    = tm_pm_fullres; // F26.6
          ((T_TMODE_PDTCH_INFO *)(msg->SigP))->snr           = tm_snr;
          ((T_TMODE_PDTCH_INFO *)(msg->SigP))->toa           = tm_toa;
          ((T_TMODE_PDTCH_INFO *)(msg->SigP))->angle         = tm_angle; // signed
          for (i=0;i<8;i++)
            ((T_TMODE_PDTCH_INFO *)(msg->SigP))->crc_error_tbl[i] = crc_error_tbl[i];

          // send TMODE_TCH_INFO message...
          os_send_sig(msg, L1C1_QUEUE);
          DEBUGMSG(status,NU_SEND_QUEUE_ERR)

          // reset static TM variables for stats collection
          tm_pm_fullres = 0;
          tm_snr        = 0;
          tm_toa        = 0;
          tm_angle      = 0;
        }
     #endif
    }

  } //end of test "if((en_task) && !(task_param))"

  // End of task -> task must become INACTIVE.
  // PDTCH can be pipelined and therefore must stay active if
  // it has already reentered the flow.
  if(burst_id == BURST_4)
  {
    if(l1s.task_status[task].current_status == RE_ENTERED)
      l1s.task_status[task].current_status = ACTIVE;
    else
      l1s.task_status[task].current_status = INACTIVE;
  }

  #if 0	/* FreeCalypso TCS211 reconstruction */
    l1ddsp_read_iq_dump(task);
  #endif
  // Flag the use of the MCU/DSP dual page read interface.
  // ******************************************************

  // Set flag used to change the read page at the end of "l1_synch".
  l1s_dsp_com.dsp_r_page_used = TRUE;
}
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM

/*-------------------------------------------------------*/
/* l1ps_read_pra_result()                                */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1ps_read_pra_result(UWORD8 task, UWORD8 burst_id)
{
  /*--------------------------------------------------------*/
  /* READ TRANSMIT TASK RESULTS...                          */
  /*--------------------------------------------------------*/

  /*---------------------------------------------------*/
  /* Packet Access task.                               */
  /*---------------------------------------------------*/
  // Rem: confirmation message is sent at "CTRL" to be able to give FN%42432.
  BOOL confirm_flag = TRUE; // Default is: confirmation message is sent.

  // Desactivate the PRACH task.
  l1s.task_status[task].current_status = INACTIVE;

  l1_check_com_mismatch(task);


  #if (TRACE_TYPE!=0)
    trace_fct(CST_L1PS_READ_PRA, l1pa_l1ps_com.p_idle_param.radio_freq);
  #endif

  #if FF_L1_IT_DSP_USF
    // Check PRACH was controlled
    if (l1pa_l1ps_com.pra_info.prach_controlled)
    {
  #endif

  // Check USF in case of Dynamic Allocation.
  if(l1pa_l1ps_com.pra_info.prach_alloc != FIX_PRACH_ALLOC)
  {
    API cs_type = l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][0];

    if(cs_type != CS_NONE_TYPE)
      confirm_flag = FALSE;
  }

  if (confirm_flag == TRUE)
  {
    // Send confirmation msg to L1A.
    // ******************************
    // For ACCESS phase, a confirmation msg is sent to L1A.
    xSignalHeaderRec *msg;

    // send L1C_RA_DONE to L1A...
    msg = os_alloc_sig(sizeof(T_MPHP_RA_CON));
    DEBUGMSG(status,NU_ALLOC_ERR)

    ((T_MPHP_RA_CON *)(msg->SigP))->fn                   = l1pa_l1ps_com.pra_info.fn_to_report;
    ((T_MPHP_RA_CON *)(msg->SigP))->channel_request_data = l1pa_l1ps_com.pra_info.channel_request_data;
    msg->SignalCode = L1P_RA_DONE;

    os_send_sig(msg, L1C1_QUEUE);
    DEBUGMSG(status,NU_SEND_QUEUE_ERR)

  }

  // Set flag used to change the read page at the end of "l1_synch".
  l1s_dsp_com.dsp_r_page_used = TRUE;

  #if FF_L1_IT_DSP_USF
    } // if (l1pa_l1ps_com.pra_info.prach_controlled)
  #endif
}

/*-------------------------------------------------------*/
/* l1ps_read_poll_result()                               */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1ps_read_poll_result(UWORD8 task, UWORD8 burst_id)
{
  /*--------------------------------------------------------*/
  /* READ TRANSMIT TASK RESULTS...                          */
  /*--------------------------------------------------------*/

  l1_check_com_mismatch(task);

  #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) // in debug trace all reads
    trace_fct(CST_L1PS_READ_POLL, l1pa_l1ps_com.p_idle_param.radio_freq);
  #endif

  /*--------------------------------------------------------*/
  /* POLL task (4xPRACH) upon packet queueing notification. */
  /*--------------------------------------------------------*/

  // Deactivate the PRACH task.
  if(burst_id == BURST_4)
  {
    // POLL is a 'one shot' task --> disable task
    l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED;

    l1s.task_status[task].current_status = INACTIVE;

    #if (TRACE_TYPE==5) // in simulation trace only the latest burst
      trace_fct(CST_L1PS_READ_POLL, l1pa_l1ps_com.p_idle_param.radio_freq);
    #endif

    // Send confirmation msg to L1A.
    // ******************************
    // For PACKET POLLING, a confirmation msg is sent to L1A.
    {
      xSignalHeaderRec *msg;

      // send L1C_RA_DONE to L1A...
      msg = os_alloc_sig(sizeof(T_MPHP_POLLING_IND));
      DEBUGMSG(status,NU_ALLOC_ERR)

      ((T_MPHP_POLLING_IND *)(msg->SigP))->fn = l1pa_l1ps_com.poll_info.fn_to_report;
      msg->SignalCode = L1P_POLL_DONE;

      os_send_sig(msg, L1C1_QUEUE);
      DEBUGMSG(status,NU_SEND_QUEUE_ERR)
    }
  }

  #if 0	/* FreeCalypso TCS211 reconstruction */
    l1ddsp_read_iq_dump(task);
  #endif
  // Set flag used to change the read page at the end of "l1_synch".
  l1s_dsp_com.dsp_r_page_used = TRUE;
}

#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM !=0))  // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM enabled
//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_START         // KEEP IN EXTERNAL MEM otherwise

/*-------------------------------------------------------*/
/* l1ps_ctrl_snb_dl()                                    */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/* This function is a "COMPLEX" function used by the L1S */
/* packet serving cell normal burst reading tasks: PNP,  */
/* PEP, PALLC. This function is the control function for */
/* reading a normal burst on the packet serving cell.    */
/* It programs the DSP and the TPU for reading a         */
/* normal burst. This function flags the reading of the  */
/* Packet Normal paging burst which flag is used in      */
/* measurement manager procedure.                        */
/* Here below is a summary of the execution:             */
/*                                                       */
/*  - If SEMAPHORE(task) is low.                         */
/*      - Catch ARFCN and set CIPHERING reduced frame    */
/*        number.                                        */
/*      - Traces and debug.                              */
/*      - Programs DSP for required task.                */
/*      - Programs TPU for required task.                */
/*      - Flag the reading of a Packet Normal Paging     */
/*        burst.                                         */
/*  - Flag DSP and TPU programmation.                    */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/* "l1a_l1s_com.task_param"                              */
/*   task semaphore bit register. Used to skip           */
/*   the body of this function if L1A has changed or     */
/*   is changing some of the task parameters.            */
/*                                                       */
/* "task"                                                */
/*   PNP, Packet Normal paging reading task.             */
/*   PEP, Packet Extended paging reading task.           */
/*   PALLC, All Packet serving cell PCCCH reading task.  */
/*                                                       */
/* "burst_id"                                            */
/*   BURST_1, 1st burst of the task.                     */
/*   BURST_2, 2nd burst of the task.                     */
/*   BURST_3, 3rd burst of the task.                     */
/*   BURST_4, 4th burst of the task.                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/* "l1a_l1s_com.Scell_info"                              */
/*  Serving cell information structure.                  */
/*    .radio_freq, serving cell beacon frequency.        */
/*                                                       */
/* "l1s.afc"                                             */
/*   current AFC value to be applied for the given task. */
/*                                                       */
/* "l1s.tpu_offset"                                      */
/*   value for the TPU SYNCHRO and OFFSET registers      */
/*   for current serving cell setting. It is used here   */
/*   to refresh the TPU SYNCHRO and OFFSET registers     */
/*   with a corrected (time tracking of the serving)     */
/*   value prior to reading a serving cell normal burst. */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/* "pnp_ctrl"                                            */
/*   Flag set when a packet normal paging burst reading  */
/*   is controled. This flag is used by the packet       */
/*   measurement manager procedure, at the end of L1S,   */
/*    in order to scheduling the neighbor cell           */
/*    measurements.                                      */
/*   -> set to 1.                                        */
/*                                                       */
/*                                                       */
/* "l1s.tpu_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/TPU com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*                                                       */
/* "l1s.dsp_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/DSP com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_snb_dl(UWORD8 task, UWORD8 burst_id)
{
  UWORD16  Scell_radio_freq;
  UWORD8   tsc;
  WORD8    agc;
  UWORD8   lna_off;
  UWORD8   adc_active = INACTIVE;
  #if (RF_FAM == 61)
    UWORD16 dco_algo_ctl_nb = 0;
    UWORD8 if_ctl = 0;
    UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
    // By default we choose the hardware filter
    UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER;
  #endif

  #if (NEW_SNR_THRESHOLD == 1)
    UWORD8 saic_flag = 0;
  #endif /* NEW_SNR_THRESHOLD */


#if (FF_L1_FAST_DECODING == 1)
  BOOL fast_decoding_authorized = FALSE;

  if ( (burst_id == BURST_1) && (l1a_apihisr_com.fast_decoding.status == C_FAST_DECODING_FORBIDDEN) )
  {
    l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_NONE;
  }

  fast_decoding_authorized = l1s_check_fast_decoding_authorized(task);

  if ( fast_decoding_authorized && l1s_check_deferred_control(task,burst_id) )
  {
    /* Control is deferred until the upcoming fast decoding IT */
    return;
  } /* if (fast_decoding_authorized)*/

  /* In all other cases, control must be performed now. */
#endif /* FF_L1_FAST_DECODING == 1 */

  if(!(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    Scell_radio_freq = l1a_l1s_com.Scell_info.radio_freq;

    // Catch training sequence code from serving cell BCC (part of BSIC).
    tsc = l1pa_l1ps_com.pccch.packet_chn_desc.tsc;

    // Packet PAGC Algorithm
    // **********************

    // for PCCCH serving blocks (PPCH, PEPCH, all PCCCH) we use
    // PAGC algorithm. Reference is serving cell.
    l1pctl_pagc_ctrl(&agc, &lna_off, l1pa_l1ps_com.p_idle_param.radio_freq,TRUE);

   #if(RF_FAM == 61)   // Locosto DCO
       cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID ,
                                             l1a_l1s_com.Scell_used_IL.input_level,
                                             l1pa_l1ps_com.p_idle_param.radio_freq, if_threshold);
    	l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb);
  #endif

    #if (L1_SAIC != 0)
      // If SAIC is enabled, call the low level SAIC control function
      // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
      //       the function l1pctl_pagc_ctrl
      csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
      #if (NEW_SNR_THRESHOLD == 1)
          ,task
          ,&saic_flag
      #endif
          );
   #endif

    // Debug.
    // ******************

    l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;
#if (FF_L1_FAST_DECODING == 1)
    l1ddsp_load_fast_dec_task(task,burst_id);
#endif

    // Programs DSP Rx Packet Idle burst, still on Timeslot number = 0
    // due to previous synchro.
  #if FF_L1_IT_DSP_USF
    {
      BOOL usf_it = FALSE;

      // Force IT USF interrupt during PCCCH reorg for Fast USF usage during
      // Packet Access. Switch to PA could happen any time during PCCCH reorg.
      // Only relevant for RBN%3 = 0 and 1
      if (l1a_l1s_com.l1s_en_task[PALLC] == TASK_ENABLED)
      {
        if (/*(l1s.next_time.fn_mod13 >= 0) && omaps00090550*/(l1s.next_time.fn_mod13 <= 7))
          usf_it = TRUE;
      }

      l1pddsp_idle_rx_nb(burst_id, tsc, l1pa_l1ps_com.p_idle_param.radio_freq, 0, FALSE, usf_it);
    }
  #else
    l1pddsp_idle_rx_nb(burst_id, tsc, l1pa_l1ps_com.p_idle_param.radio_freq, 0, FALSE);
  #endif

    // ADC measurement
    // ***************
    // check if during the 1st burst of the bloc an ADC measurement must be performed
    if ((burst_id == BURST_1) && (task == PNP))
    {
      if (l1a_l1s_com.l1s_en_task[PALLC] == TASK_DISABLED) // no reorg mode
      {
         if (l1a_l1s_com.adc_mode & ADC_NEXT_NORM_PAGING)  // perform ADC only one time
         {
            adc_active = ACTIVE;
            l1a_l1s_com.adc_mode &= ADC_MASK_RESET_IDLE; // reset in order to have only one ADC measurement in Idle
         }
         else
         {
           if (l1a_l1s_com.adc_mode & ADC_EACH_NORM_PAGING) // perform ADC on each "period" x bloc
             if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_idle_period) // wait for the period
             {
               adc_active = ACTIVE;
               l1a_l1s_com.adc_cpt = 0;
             }
         }
      }
      else  // ADC measurement in reorg mode
      {
         if (l1a_l1s_com.adc_mode & ADC_NEXT_NORM_PAGING_REORG)  // perform ADC only one time
         {
            adc_active = ACTIVE;
            l1a_l1s_com.adc_mode &= ADC_MASK_RESET_IDLE; // reset in order to have only one ADC measurement in Idle
         }
         else
         {
           if (l1a_l1s_com.adc_mode & ADC_EACH_NORM_PAGING_REORG) // perform ADC on each "period" x bloc
             if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_idle_period) // wait for the period
             {
               adc_active = ACTIVE;
               l1a_l1s_com.adc_cpt = 0;
             }
         }
      }
    }

    #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
      trace_fct(CST_L1PS_CTRL_SNB_DL, -1);
    #endif

    // Programs TPU for required task.
    // ********************************

    // update the TPU with the new TOA if necessary
    l1ctl_update_TPU_with_toa();

    // tpu pgm...
    l1dtpu_serv_rx_nb(l1pa_l1ps_com.p_idle_param.radio_freq,
                      agc,
                      lna_off,
                      l1s.tpu_offset,
                      l1s.tpu_offset,
                      FALSE,adc_active
                 #if (RF_FAM == 61)
                      ,csf_filter_choice
                      ,if_ctl
		   #endif
                #if (NEW_SNR_THRESHOLD == 1)
                      ,saic_flag
                #endif /* NEW_SNR_THRESHOLD */
	               );

    // Increment tpu window identifier.
    l1s.tpu_win += (l1_config.params.rx_synth_load_split + RX_LOAD);
  }

  // Flag the reading of a Normal Packet Paging burst.
  // *************************************************

  // Set PNP controlled flag, used in l1s_meas_manager() to generate measurement only
  // if we are not receiving a PPCH.
  if((task == PNP) || (task == PEP) || (task == PALLC))
    l1pa_l1ps_com.cr_freq_list.pnp_ctrl = burst_id + 1;


  // Flag DSP and TPU programmation.
  // ********************************

  // Set "CTRL_RX" flag in the controle flag register.
  l1s.tpu_ctrl_reg |= CTRL_RX;
  l1s.dsp_ctrl_reg |= CTRL_RX;

} // end of procedure

/*-------------------------------------------------------*/
/* l1ps_read_nb_dl()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/* This function is a "COMPLEX" function used by the L1S */
/* tasks: PNP,PEP,PALLC.                                 */
/*                                                       */
/* Here is a summary of the execution:                   */
/*                                                       */
/*  - If SEMAPHORE(task) is low and task still enabled.  */
/*      - Traces and debug.                              */
/*      - Read control results and feed control algo.    */
/*      - Read DL DATA block from MCU/DSP interface.     */
/*  - Disactivate task.                                  */
/*  - Flag the use of the MCU/DSP dual page read         */
/*    interface.                                         */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/* "task"                                                */
/*   PNP, Packet Normal paging reading task.             */
/*   PEP, Packet Extended paging reading task.           */
/*   PALLC, All packet serving cell PCCCH reading task.  */
/*                                                       */
/* "burst_id"                                            */
/*   BURST_1, 1st burst of the task.                     */
/*   BURST_2, 2nd burst of the task.                     */
/*   BURST_3, 3rd burst of the task.                     */
/*   BURST_4, 4th burst of the task.                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/* "l1pa_l1ps_com.task_param[NBR_DL_L1S_TASKS]"          */
/*   packet task semaphore table. Used to skip           */
/*   the body of this function if L1A has changed or     */
/*   is changing some of the task parameters.            */
/*                                                       */
/* "l1a_l1s_com.l1s_en_task[NBR_DL_L1S_TASKS]"           */
/*   L1S task enable.                                    */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/* "l1s.task_status[task].current_status"                */
/*   current task status. It must be reset (INACTIVE)    */
/*   when the task is completed.                         */
/*   -> disactivate task.                                */
/*                                                       */
/* "l1s_dsp_com.dsp_r_page_used"                         */
/*   Flag used by the function which closes L1S          */
/*   execution ("l1s_end_manager()") to know if the      */
/*   MCU/DSP read page must be switched.                 */
/*   -> Set to 1.                                        */
/*                                                       */
/* Use of MCU/DSP interface:                             */
/* -------------------------                             */
/* "l1s_dsp_com.dsp_ndb_ptr"                             */
/*   pointer to the non double buffered part (NDB) of    */
/*   the MCU/DSP interface. This part is R/W for both    */
/*   DSP and MCU.                                        */
/*                                                       */
/* "l1s_dsp_com.dsp_db_r_ptr"                            */
/*   pointer to the double buffered part (DB) of the     */
/*   MCU/DSP interface. This pointer points to the READ  */
/*   page.                                               */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_read_nb_dl(UWORD8 task, UWORD8 burst_id)
{
  UWORD32   toa=0; //omaps00090550
  UWORD32   pm=0; //omaps00090550;
  UWORD32   angle =0; //omaps00090550
  UWORD32   snr =0;  //omaps00090550
  BOOL      en_task;
  BOOL      task_param;
  UWORD16   scell_radio_freq;
  static UWORD16   pwr_level;

#if (FF_L1_FAST_DECODING == 1)
  UWORD8 skipped_bursts = 0;
  BOOL fast_decoding_authorized = l1s_check_fast_decoding_authorized(task);
  BOOL fast_decoded = (l1a_apihisr_com.fast_decoding.status == C_FAST_DECODING_COMPLETE);
  if (fast_decoded)
  {
    skipped_bursts = BURST_4 - burst_id;
  }
#endif /* if (FF_L1_FAST_DECODING == 1) */

  /*--------------------------------------------------------*/
  /* READ SERVING CELL RECEIVE TASK RESULTS...              */
  /*--------------------------------------------------------*/
  /* Rem: only a partial result is present in the mcu<-dsp  */
  /* communication buffer. The DATA BLOCK content itself is */
  /* in the last comm. (BURST_4)                            */
  /*--------------------------------------------------------*/
  // Get "enable" task flag and "synchro semaphore" for current task.
  en_task    = l1a_l1s_com.l1s_en_task[task];
  task_param = l1a_l1s_com.task_param[task];

  if((en_task) && !(task_param))
  // Check the task semaphore and the task enable bit. The reading
  // task body is executed only when the task semaphore is 0 and the
  // task is still enabled.
  // The semaphore can be set to 1 whenever L1A makes some changes
  // to the task parameters. The task can be disabled by L1A.
  {
    // Traces and debug.
    // ******************
    l1_check_com_mismatch(task);

    // Read control results and feed control algorithms.
    // **************************************************
    if ((task != PBCCHN_TRAN) && (task != PBCCHN_IDLE))
    {
      // From the fact that PBCCHS can be read in CS mode,
      // Idle mode and Packet Idle mode, a check on the current active DSP scheduler mode
      // has to be performed.
      // Read control information.
      // We keep compatibility with (chipset == 0) imply mask with 0xffff.
      // If only (chipset == 2) is used, mask can be removed.
      if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER)
      {
        toa   = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA]   & 0xffff;
        pm    = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM]   & 0xffff) >> 5;
        angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff;
        snr   = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR]   & 0xffff;
      }
      else
      {
        toa   =  l1ps_dsp_com.pdsp_db_r_ptr->a_burst_toa_gprs[0]   & 0xffff;
        pm    = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[0]    & 0xffff)>>5;
        angle =  l1ps_dsp_com.pdsp_db_r_ptr->a_burst_angle_gprs[0] & 0xffff;
        snr   =  l1ps_dsp_com.pdsp_db_r_ptr->a_burst_snr_gprs[0]   & 0xffff;
      }

      #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
        trace_fct(CST_L1PS_READ_NB_DL, -1);
      #endif

      l1_check_pm_error(pm,task);

      // Update AGC: Call PAGC algorithm
      l1a_l1s_com.Scell_IL_for_rxlev = l1pctl_pagc_read((UWORD8)pm, l1pa_l1ps_com.p_idle_param.radio_freq_dd);

#if (FF_L1_FAST_DECODING == 1)
    if (skipped_bursts>0)
    {
      l1ctl_pagc_missing_bursts(skipped_bursts);
    }
#endif /* if (FF_L1_FAST_DECODING == 1) */

      // Update AFC: Call AFC control function (KALMAN filter).
      #if AFC_ALGO
       {
         WORD16 old_afc  = l1s.afc;
         WORD16 old_count= l1s.afc_frame_count;

         scell_radio_freq = l1a_l1s_com.Scell_info.radio_freq;
         #if (VCXO_ALGO==0)
         l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, scell_radio_freq);
         #else
           l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, scell_radio_freq,l1a_l1s_com.mode);
         #endif
         #if L2_L3_SIMUL
           #if (DEBUG_TRACE == BUFFER_TRACE_AFC_OPEN)
             buffer_trace (4,(WORD16)angle,old_count,old_afc,l1s.afc);
           #endif
         #endif
       }
      #endif

      // Feed TOA histogram only when the TOA result is used in the task CTRL function
      if (task != PBCCHS)
      {
        //Feed TOA histogram.
        #if (TOA_ALGO != 0)
          #if (TOA_ALGO == 2)
            if(l1s.toa_var.toa_snr_mask == 0)
          #else
            if(l1s.toa_snr_mask == 0)
          #endif
          {
            #if (TOA_ALGO == 2)
              UWORD32 snr_temp;
              snr_temp = (l1a_l1s_com.Scell_IL_for_rxlev < IL_FOR_RXLEV_SNR) ? snr: 0;
              l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa);
            #else
              /* FreeCalypso TCS211 reconstruction */
              if (l1a_l1s_com.Scell_IL_for_rxlev < IL_FOR_RXLEV_SNR)
              {
                l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr, toa,
                                          &l1s.toa_update,
                                          &l1s.toa_period_count
                                       #if (FF_L1_FAST_DECODING == 1)
                                          ,0
                                       #endif
                                );
              }
              else
              {
                l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, 0, toa,
                                          &l1s.toa_update,
                                          &l1s.toa_period_count
                                       #if (FF_L1_FAST_DECODING == 1)
                                          ,0
                                       #endif
                                );
              }
            #endif
          }
        #endif
      }
    }

    #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
      RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb)
    #endif
    #if 0 //(TRACE_TYPE == 1) || (TRACE_TYPE == 4) // TCS211 reconstruction
      l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb);
    #endif
    #if (BURST_PARAM_LOG_ENABLE == 1)
      l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb);
    #endif
    // compute the Data bloc Power.
    // ******************************
    if(burst_id == BURST_1)
      pwr_level = 0;

    // add the burst power
    pwr_level += l1a_l1s_com.Scell_IL_for_rxlev;


    // Read downlink DATA block from MCU/DSP interface.
    // *************************************************
   #if (FF_L1_FAST_DECODING == 1)
    /* Perform the reporting if
        - Burst is the 4th one (whether CRC is ok or not)
        - Fast decoding enabled and CRC already ok
    */
    if ( (burst_id == BURST_4) || fast_decoded )
    #else /* #if (FF_L1_FAST_DECODING == 1) */
    if(burst_id == BURST_4)
    #endif /* FF_L1_FAST_DECODING */
    {
      #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3)
        uart_trace(task);
      #endif
#if (FF_L1_FAST_DECODING == 1)
      /* Data power block = pwr_level / (nb of bursts)*/
      pwr_level = pwr_level / (burst_id + 1);
#else /* #if (FF_L1_FAST_DECODING == 1) */
      // the data power bloc = pwr_level/4.
      pwr_level = pwr_level >> 2;
#endif /* #if (FF_L1_FAST_DECODING == 1) #else*/

      // Read L3 frame block and send msg to L1A.
#if (FF_L1_FAST_DECODING == 1)
      if(!fast_decoding_authorized)
      {
        /* When fast decoding wasn't used, burst_id is undefined (for the trace) */
        l1a_l1s_com.last_fast_decoding = 0;
      }
      else
      {
        l1a_l1s_com.last_fast_decoding = burst_id + 1;
      }
#endif /* #if (FF_L1_FAST_DECODING == 1) */

      // Read L3 frame block and send msg to L1A.
      if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER)
        l1s_read_l3frm(pwr_level,&(l1s_dsp_com.dsp_ndb_ptr->a_cd[0]), task);
      else
        l1s_read_l3frm(pwr_level,&(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]), task);

    } // End if...

  } //end of test "if((en_task) && !(task_param))"

  // Disactivate task.
  // ******************

  // End of task -> task must become INACTIVE.
  // Rem: some TASKS (PALLC, PNP (with SPLIT > M)) can be pipelined and therefore
  // must stay active if they have already reentered the flow.
#if (FF_L1_FAST_DECODING == 1)
    /*------------------------------------------------------*/
    /* Perform the reporting if                             */
    /* - Burst is the 4th one (whether CRC is ok or not)    */
    /* - Fast decoding enabled and CRC already ok           */
    /*------------------------------------------------------*/
  if ( (burst_id == BURST_4) || fast_decoded )
#else /* #if (FF_L1_FAST_DECODING == 1) */
  if(burst_id == BURST_4)
#endif /* #if (FF_L1_FAST_DECODING == 1) #else*/
  {
#if (FF_L1_FAST_DECODING == 1)
    if(task == PNP)
    {
      if (l1a_apihisr_com.fast_decoding.contiguous_decoding == TRUE)
      {
        /* A new block has started, a new fast API IT is expected */
        l1a_apihisr_com.fast_decoding.contiguous_decoding = FALSE;
        l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_AWAITED;
      }
      else if(task == l1a_apihisr_com.fast_decoding.task)
      {
        /* Reset decoding status */
        l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_NONE;
      }
    } /*task == PNP */
#endif /* #if (FF_L1_FAST_DECODING == 1) */    
    if(l1s.task_status[task].current_status == RE_ENTERED)
      l1s.task_status[task].current_status = ACTIVE;
    else
      l1s.task_status[task].current_status = INACTIVE;
#if (FF_L1_FAST_DECODING == 1)
 if (burst_id != BURST_4)
    {
     l1s_clean_mftab(task, burst_id + 3);
     if(l1s.frame_count == (4 -burst_id))
     {
          l1s.frame_count = 1;
     }
    }
#endif /* #if (FF_L1_FAST_DECODING == 1) */
  }

  #if 0	/* FreeCalypso TCS211 reconstruction */
    l1ddsp_read_iq_dump(task);
  #endif
  // Flag the use of the MCU/DSP dual page read interface.
  // ******************************************************

  // Set flag used to change the read page at the end of "l1_synch".
  l1s_dsp_com.dsp_r_page_used = TRUE;

} // end of procedure

//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END         // KEEP IN EXTERNAL MEM otherwise
#endif
/*-------------------------------------------------------*/
/* l1ps_ctrl_pbcch()                                    */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/* This function is a "COMPLEX" function used by the L1S */
/* tasks: neighbor cell PBCCH.                           */
/* This function is the control function                 */
/* for reading a PBCCH burst on the neighbor cell.       */
/* This control function:                                */
/* a) shifts the OFFSET register to match the normal     */
/*    burst received task with the PBCCH timeslot number.*/
/*                                                       */
/* b) programs a normal burst reading and restores the   */
/*    OFFSET to the serving cell timeslot. On the last   */
/*    control (4th burst), the SYNCHRO/OFFSET registers  */
/*    are shifted back to the normal idle mode PCCH      */
/*    reading setting. Here is a summary of the          */
/*    execution:                                         */
/*                                                       */
/*  - If SEMAPHORE(task) is low.                         */
/*    - Traces and debug.                                */
/*    - Programs DSP for PBCCH task, reading 1 burst.    */
/*    - Programs TPU for PBCCH task, reading 1 burst.    */
/*    - Shift TPU SYNCHRO/OFFSET registers back to the   */
/*      PACKET PAGING TASK timeslot.                     */
/*  - Flag DSP and TPU programmation.                    */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/* "task"                                                */
/*   PBCCH_TRA or PBCCH_IDLE or PBCCHS                   */
/*    Serving Cell PBCCH reading task.                   */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/* "l1pa_l1ps_com.pbcch "                                */
/*   Neigh/serv Cell PBCCH description structure.        */
/*                                                       */
/* "l1a_l1s_com.Scell_info.radio_freq"                   */
/*   BSIC of the serving cell. It is used here to pass   */
/*   the training sequence number (part of BSIC) to the  */
/*   DSP.                                                */
/*                                                       */
/* "l1a_l1s_com.offset_tn0"                              */
/*   value to load in the OFFSET register to shift then  */
/*   any receive task to the timeslot 0 of the neighbor  */
/*   cell or PBCCH timeslot number .                     */
/*                                                       */
/* "l1s.tpu_offset"                                      */
/*   value for the TPU SYNCHRO and OFFSET registers      */
/*   for current serving cell setting. It is used here   */
/*   at the end of the PBCCH  task controls to restore   */
/*   the SYNCHRO/OFFSET registers to the normal setting  */
/*   in idle mode.                                       */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/* "l1s.actual_time, l1s.next_time"                      */
/*   frame number and derived numbers for current frame  */
/*   and next frame.                                     */
/*   -> update to cope with side effect due to synchro.  */
/*      changes/restores.                                */
/*                                                       */
/* "l1s.tpu_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/TPU com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*                                                       */
/* "l1s.dsp_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/DSP com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_pbcch(UWORD8 task, UWORD8 burst_id)
{
  UWORD16  rx_radio_freq;
  UWORD32  offset_pbcch;
  WORD8    agc;
  UWORD8   lna_off;
  UWORD32  dsp_task;
  UWORD8   tsc;
  UWORD8   serving_cell;
  #if (RF_FAM == 61)
    UWORD16 dco_algo_ctl_nb=0;
    UWORD8 if_ctl = 0;
    UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
    // By default we choose the hardware filter
    UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER;
  #endif
  #if (NEW_SNR_THRESHOLD == 1)
    UWORD8 saic_flag=0;
  #endif /* NEW_SNR_THRESHOLD */
  static   WORD32 new_tpu_offset;
  static   BOOL   change_synchro;

  #define  PbcchS  l1pa_l1ps_com.pbcchs
  #define  PbcchN  l1pa_l1ps_com.pbcchn

  #if (CODE_VERSION == SIMULATION)
    UWORD32 tpu_w_page;

    if (hw.tpu_r_page==0)
     tpu_w_page=1;
    else
     tpu_w_page=0;

    hw.rx_id[tpu_w_page][0]=0;
    hw.num_rx[tpu_w_page][0]=1;
    hw.rx_group_id[tpu_w_page]=1;
  #endif

  if (task == PBCCHS)
  {
    tsc            = PbcchS.packet_chn_desc.tsc;
    offset_pbcch   = (PbcchS.tn_pbcch * TN_WIDTH);
    serving_cell   = TRUE;
  }
  else
  {
    tsc            = PbcchN.packet_chn_desc.tsc;
    offset_pbcch   = PbcchN.time_alignmt;
    serving_cell   = FALSE;
  }

  if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) &&
    !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    // Get ARFCN to be used for current control. Output of the hopping algorithm.
    rx_radio_freq    = l1pa_l1ps_com.p_idle_param.radio_freq;

    // Traces and debug.
    // ******************

    #if (TRACE_TYPE==5) && FLOWCHART
      trace_flowchart_dsp_tpu(dltsk_trace[task].name);
    #endif

    #if (TRACE_TYPE!=0)
      if (task == PBCCHS)
        trace_fct(CST_L1PS_CTRL_PBCCHS, l1a_l1s_com.Scell_info.radio_freq);
      else
        trace_fct(CST_L1PS_CTRL_PBCCHN, PbcchN.bcch_carrier);
    #endif

    l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

    // Programs DSP for PBCCHN task according to the DSP scheduler used
    // *****************************************************************
    switch(l1a_l1s_com.dsp_scheduler_mode)
    {
      // dsp pgm is made using GSM scheduler...
      case GSM_SCHEDULER:
        dsp_task = l1s_swap_iq_dl(rx_radio_freq, task);

        // dsp pgm...
        l1ddsp_load_rx_task(dsp_task,burst_id,tsc);
      break;

      // dsp pgm is made using GPRS scheduler...
      case GPRS_SCHEDULER:
          #if FF_L1_IT_DSP_USF
             l1pddsp_idle_rx_nb(burst_id,tsc,rx_radio_freq,0,FALSE,FALSE);
          #else
        l1pddsp_idle_rx_nb(burst_id,tsc,rx_radio_freq,0,FALSE);
          #endif
      break;
    }

    // Check if "Synchro" change is needed.
    // *************************************
    // If so the synchro is changed by 4 timeslots.
    if(burst_id == BURST_1)
    {
      if (task == PBCCHS)
        change_synchro = PbcchS.change_synchro;
      else
        change_synchro = PbcchN.change_synchro;

      if(change_synchro)
      {
        // compute TPU offset for "current timeslot + 4 timeslot"
        new_tpu_offset = l1s.tpu_offset + (4 * TN_WIDTH);

        if(new_tpu_offset >= TPU_CLOCK_RANGE)
          new_tpu_offset -= TPU_CLOCK_RANGE;

        // Slide synchro to match current timeslot + 4 timeslot.
        l1dmacro_synchro(SWITCH_TIME, new_tpu_offset);
      }
      else
      {
        new_tpu_offset = l1s.tpu_offset;
      }
    }

    // TPU pgm...
    //-----------
    offset_pbcch += new_tpu_offset;
    if (offset_pbcch >= TPU_CLOCK_RANGE)
      offset_pbcch -= TPU_CLOCK_RANGE;

    // add for debug TPU simu
    #if (CODE_VERSION == SIMULATION)
    if (task == PBCCHS) // PBCCH serving, compute Ts related to the L1 synchro on the serving
      hw.rx_id[tpu_w_page][0]=((TPU_CLOCK_RANGE-new_tpu_offset+offset_pbcch)%TPU_CLOCK_RANGE)/TN_WIDTH;
    else // PBCCH Neighbor -> special value for PBCCHN detection in the DSP task
      hw.rx_id[tpu_w_page][0]=10;
    #endif

    // agc is set with the input_level computed from PAGC algo
    l1pctl_pagc_ctrl(&agc, &lna_off, rx_radio_freq, serving_cell);

#if(RF_FAM == 61)   // Locosto DCO
    cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID ,
                                             l1a_l1s_com.Scell_used_IL.input_level  , rx_radio_freq, if_threshold);
    l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb);
#endif

    #if (L1_SAIC != 0)
      // If SAIC is enabled, call the low level SAIC control function
      // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
      //       l1pctl_pagc_ctrl
      if(task == PBCCHS)
      {
        // Call SAIC only for PBCCHS, not for PBCCHN_TRAN or PBCCHN_IDLE
        csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
        #if (NEW_SNR_THRESHOLD == 1)
            ,task
            ,&saic_flag
        #endif
        );
      }
#endif

    l1dmacro_offset  (offset_pbcch, l1_config.params.rx_change_offset_time);  // Slide offset to cope with PBCCHN in the new sychro.
    l1dmacro_rx_synth(rx_radio_freq);                                         // load SYNTH.
    l1dmacro_agc     (rx_radio_freq,agc, lna_off
                                #if(RF_FAM == 61)
                                  ,if_ctl
				     #endif
	                         );                            // load AGC.
#if (L1_MADC_ON == 1)
#if (RF_FAM == 61)
    l1dmacro_rx_nb   (rx_radio_freq,INACTIVE, csf_filter_choice
#if (NEW_SNR_THRESHOLD == 1)
    ,saic_flag
#endif /* NEW_SNR_THRESHOLD */
        );   // RX window for NB.
#endif /* RF_FAM == 61*/
#else  /* L1_MADC_ON == 1*/
    l1dmacro_rx_nb   (rx_radio_freq);            // RX window for NB.
#endif

    if (task == PBCCHS)
    {
      #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
          l1ddsp_load_afc(l1s.afc);  // Loading the afc value in DB,Flag the presence of a new afc value to send
      #endif
	  #if (RF_FAM == 61)
          l1dtpu_load_afc(l1s.afc);
      #endif
    }
    l1dmacro_offset  (new_tpu_offset, IMM); // Restore offset.
  } // End if(task enabled and semaphore false)

  // Remark:
  //--------
  // When the task is aborted, we must continue to make dummy
  // DSP programming to avoid communication mismatch due
  // to C/W/R pipelining.

  // We must also ensure the Synchro back since synchro change has surely be done
  // in the 1st CTRL phase.

  // Shift TPU SYNCHRO/OFFSET registers back to the default timeslot (normally PCCCH one).
  // **************************************************************************************
  // When the PBCCHN or PBCCHS reading control is completed ,
  // the SYNCHRO/OFFSET registers are shifted back to the normal idle
  // setting used for PCCH reading on the serving cell.
  // Check if "Synchro" change was needed.
  // If so the synchro is changed to recover normal synchro.
  if(burst_id == BURST_4)
  {
    if(change_synchro)
    {
      // Slide synchro back to mach current serving timeslot.
      l1dmacro_synchro(SWITCH_TIME, l1s.tpu_offset);

      // Increment frame number.
      l1s.actual_time    = l1s.next_time;
      l1s.next_time      = l1s.next_plus_time;
      l1s_increment_time(&(l1s.next_plus_time), 1);  // Increment "next_plus time".

      l1s.tpu_ctrl_reg |= CTRL_SYCB;
      l1s.dsp_ctrl_reg |= CTRL_SYNC;

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        trace_fct(CST_L1S_ADJUST_TIME, -1);
      #endif
    }
  }

  // Flag DSP and TPU programmation.
  // ********************************

  // Set "CTRL_RX" flag in the controle flag register.
  l1s.tpu_ctrl_reg |= CTRL_RX;
  l1s.dsp_ctrl_reg |= CTRL_RX;

  // This task is not compatible with Neigh. Measurement. Store task length
  // in "forbid_meas" to indicate when the task will last.
  if((burst_id == BURST_1) && (task != PBCCHN_IDLE))
  {
    // In PBCCHN_IDLE task, l1s.forbid_meas is set by the AGC ctrl
    l1s.forbid_meas = TASK_ROM_MFTAB[task].size;
  }
}

#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1ps_ctrl_ptcch()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_ctrl_ptcch(UWORD8 param1, UWORD8 param2)
{
  UWORD16  radio_freq;
  UWORD8   burst_nb;
  #if (RF_FAM == 61)
    UWORD16 dco_algo_ctl_nb = 0;
    UWORD8 if_ctl = 0;
	UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
  #endif
  #if (NEW_SNR_THRESHOLD == 1)
    UWORD8 saic_flag=0;
  #endif /* NEW_SNR_THRESHOLD*/

  if(!(l1a_l1s_com.task_param[PTCCH] == SEMAPHORE_SET))
  // Check the task semaphore. The control body is executed only
  // when the task semaphore is 0. This semaphore can be set to
  // 1 whenever L1A makes some changes to the task parameters.
  {
    WORD8  ts;

    radio_freq = l1pa_l1ps_com.transfer.ptcch.radio_freq;

    // Traces and debug.
    // ******************
    #if (TRACE_TYPE!=0)
      if(l1pa_l1ps_com.transfer.ptcch.activity && (PTCCH_DL || PTCCH_UL ) == 0) // trace only if a window is programmed.
        trace_fct(CST_L1PS_CTRL_PTCCH_EMPTY, radio_freq);
    #endif

    #if (TRACE_TYPE==5) && FLOWCHART
      trace_flowchart_dsp_tpu(dltsk_trace[PTCCH].name);
    #endif

    l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ;

    switch (l1s.next_time.fn_mod104)
    {
      case 12: burst_nb=0; break;
      case 38: burst_nb=1; break;
      case 64: burst_nb=2; break;
      case 90: burst_nb=3; break;
      default: burst_nb=0; break;
    }

    // Compute timeslot number referenced to current camp timeslot.
    ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn;
    if(ts < 0) ts += 8;
    else if(ts >= 8) ts -= 8;

    if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL)
    // PTCCH DL activity bit is set: PTCCH DL programmation is required.
    {
      #if (TRACE_TYPE!=0)
            trace_fct(CST_L1PS_CTRL_PTCCH_DL_BURST0 + burst_nb, radio_freq);
      #endif

      // Programs DSP for PTCCH/DL.
      // ***************************
      {
      #if FF_L1_IT_DSP_USF
        l1pddsp_idle_rx_nb(burst_nb,
                           l1pa_l1ps_com.transfer.aset->tsc,
                           radio_freq,
                           ts,
                           TRUE,
                           FALSE);
      #else
        l1pddsp_idle_rx_nb(burst_nb,
                           l1pa_l1ps_com.transfer.aset->tsc,
                           radio_freq,
                           ts,
                           TRUE);
      #endif
      }


      // Programs TPU for PTCCH/DL task.
      // ********************************
      {
        WORD8  agc;
        UWORD8  lna_off;

        // AGC updating
        //-------------
        l1pctl_pagc_ctrl(&agc, &lna_off, radio_freq,TRUE);

      #if(RF_FAM == 61)   // Locosto DCO
       cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID,
                                             l1a_l1s_com.Scell_used_IL.input_level  , radio_freq, if_threshold);
      	l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb);
      #endif

     #if (L1_SAIC != 0)
          // If SAIC is enabled, call the low level SAIC control function
          // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within
          //       the function l1pctl_pagc_ctrl
          l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode
          #if (NEW_SNR_THRESHOLD == 1)
              ,PTCCH
              ,&saic_flag
          #endif
          );
      #endif

        // Compute timeslot number referenced to current camp timeslot.
        // Rem: COULD BE DONE ASYNCHRONOUSLY changing ta_tn definition!!!
        ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn;
        if(ts < 0) ts += 8;
        else if(ts >= 8) ts -= 8;

        // Program RX Normal Burst scenario.
        l1pdtpu_serv_rx_nb(radio_freq,
                           agc,
                           lna_off,
                           ts,
                           l1s.tpu_offset,
                           1,
                           1,
                           TRUE,INACTIVE
                           #if(RF_FAM == 61)
                            ,L1_SAIC_HARDWARE_FILTER
                            ,if_ctl
                           #endif
                           #if (NEW_SNR_THRESHOLD == 1)
                            ,saic_flag
                           #endif /* NEW_SNR_THRESHOLD */
    		                                );

        // Set "CTRL_RX" flag in the controle flag registers.
        l1s.tpu_ctrl_reg |= CTRL_RX;
        l1s.dsp_ctrl_reg |= CTRL_RX;
      }
    }

    if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_UL)
    // PTCCH UL activity bit is set: PTCCH UL programmation required.
    {
      UWORD8 adc_active = INACTIVE;

      #if (TRACE_TYPE!=0)
          trace_fct(CST_L1PS_CTRL_PTCCH_UL, radio_freq);
      #endif

      // Programs DSP for PTCCH/UL.
      // ***************************
      {
        UWORD8  cs_type;
        UWORD16 ptcch_ul_data;

        // Access burst type ?
        if (l1pa_l1ps_com.access_burst_type == ACC_BURST_8)
        {
          // PRACH 8 bits: data = (0111 1111)b
          cs_type       = CS_PAB8_TYPE;
          ptcch_ul_data = 0x7F;
        }
        else
        {
          // PRACH 11 bits: data = (111 1111 1111)b
          cs_type       = CS_PAB11_TYPE;
          ptcch_ul_data = 0x7FF;
        }

        // "As" IDLE POLLING PRACH dsp control.
        l1pddsp_ul_ptcch_data(cs_type,
                              ptcch_ul_data,
                              l1a_l1s_com.Scell_info.bsic,
                              radio_freq,
                              ts+3);

        l1pddsp_idle_prach_power(l1s.applied_txpwr,
                                 radio_freq,
                                 ts+3);
      }

      // ADC measurement
      // ***************
      {
        // check if during the SACCH burst an ADC measurement must be performed
         if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_UL)  // perform ADC only one time
         {
            adc_active = ACTIVE;
            l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic
         }
         else
           if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_UL) // perform ADC on each period bloc
               if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period
               {
                 adc_active = ACTIVE;
                 l1a_l1s_com.adc_cpt = 0;
               }
      }
      // Programs TPU for PTCCH/UL task.
      // ********************************
      {
        // Program TX RA scenario.
        l1pdtpu_serv_tx(radio_freq,
                        0,               // TA=0.
                        l1s.tpu_offset,
                        ts+3,            // tx_id.
                        1,               // 1 PRACH.
                        1,               // tx_group_id.
                        0,               // No switch NB->RA
                        1,               // Driver called for PRACH Burst.
                        l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL,adc_active);
                                         // Flag RX in same frame as TX
      }

      // PTCCH/UL has been executed,
      //  -> PTCCH/DL is then requested for schedule.
      //  -> PTCCH/UL activity flag must be reset.
      l1pa_l1ps_com.transfer.ptcch.request_dl  = TRUE;
      l1pa_l1ps_com.transfer.ptcch.activity   ^= PTCCH_UL;

      // Set "CTRL_TX" flag in the controle flag register.
      l1s.tpu_ctrl_reg |= CTRL_TX;
      l1s.dsp_ctrl_reg |= CTRL_TX;

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        RTTL1_FILL_UL_AB(PTCCH,l1s.applied_txpwr)
      #endif

    } // End of PTCCH UL programmation
  } // End of if(...semaphore...)

  // This task is not compatible with Neigh. Measurement. Store task length
  // in "forbid_meas" to indicate when the task will last.
  l1s.forbid_meas = TASK_ROM_MFTAB[PTCCH].size;
}
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM


#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1s_read_ptcch()                                      */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/*-------------------------------------------------------*/
void l1ps_read_ptcch(UWORD8 param1, UWORD8 param2)
{
  // Traces and debug.
  // ******************

  l1_check_com_mismatch(PTCCH);

  if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL)
  // PTCCH/DL has been executed,
  {
    UWORD32   pm;
    WORD8     ts;

    // Compute timeslot number referenced to current camp timeslot.
    ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn;
    if(ts < 0) ts += 8;
    else if(ts >= 8) ts -= 8;

    #if (TRACE_TYPE!=0)
           trace_fct(CST_L1PS_READ_PTCCH_DL, l1pa_l1ps_com.transfer.ptcch.radio_freq);
    #endif

    // Read control results and feed control algorithms.
    // **************************************************

    // Read control information.
    pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff) >> 5;
    l1_check_pm_error(pm,PTCCH);

    if(l1s.actual_time.fn_mod104 == 91)
    // Read PTCCH/DL data block from DSP/MCU interface, a_dd_md_gprs[].
    {
      BOOL   crc;
      UWORD8 ordered_ta;

      crc = (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[0] & 0x0100) >> 8;

      if(!crc)
      // Block correct, we extract new TA...
      {
        UWORD8 word_position = 4+ (l1pa_l1ps_com.transfer.aset->packet_ta.ta_index >> 1);
        UWORD8 byte_position = l1pa_l1ps_com.transfer.aset->packet_ta.ta_index & 0x01;

        // Download ordered TA...
        // IF byte_position
        //   Upper byte contains TA...
        // ELSE
        //   Lower byte contains TA...
        // (see GSM04.04)

        ordered_ta = (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[word_position] >> (8*byte_position)) & 0x7f;

        if (ordered_ta < 64)
        {
          // PTCCH/DL contains a valid TA for MS: update TA
          l1pa_l1ps_com.transfer.aset->packet_ta.ta = ordered_ta;

          // PTCCH/DL activity bit must reset when new TA has been successfully received.
          l1pa_l1ps_com.transfer.ptcch.activity ^= PTCCH_DL;
        }
      }

      #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
        if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_DL_PTCCH)
        // whatever the value is, trace it
        {
            Trace_dl_ptcch(ordered_ta,
                           crc,
                           l1pa_l1ps_com.transfer.aset->packet_ta.ta_index,
                           l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn,
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[4],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[5],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[6],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[7],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[8],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[9],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[10],
                           l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[11]);
        }
      #endif

      #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
        RTTL1_FILL_DL_PTCCH(crc, ordered_ta) // Replace with ordered TA
      #endif

      // Reset CS type.
      l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[0] = CS_NONE_TYPE;
    }
  }
  else
  {
     #if (TRACE_TYPE!=0)
       trace_fct(CST_L1PS_READ_PTCCH_UL, l1pa_l1ps_com.transfer.ptcch.radio_freq);
     #endif
  }

  // Set flag used to change the read page at the end of "l1_synch".
  l1s_dsp_com.dsp_r_page_used = TRUE;

  // End of task -> task must become INACTIVE.
  l1s.task_status[PTCCH].current_status = INACTIVE;
}
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM


#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1ps_ctrl_itmeas()                                    */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/* This function is a "COMPLEX" function used by the L1S */
/* task ITMEAS.                                          */
/* This function is the control function for measuring   */
/* the signal strength on several specified timeslots (on*/
/* which it's possible according to the multi-slot class)*/
/* of an indicated carrier.                              */
/* It programs the DSP and the TPU for doing these       */
/* measurements                                          */
/* Here below is a summary of the execution:             */
/*                                                       */
/*  - If SEMAPHORE(task) is low.                         */
/*      - Traces and debug.                              */
/*      - Determines on which timeslots measurements can */
/*        be done                                        */
/*      - Programs DSP for required task.                */
/*      - Programs TPU for required task.                */
/*  - Flag DSP and TPU programmation.                    */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/* "l1pa_l1ps_com.itmeas"                                */
/* Interference measurement parameters structure         */
/*                                                       */
/* "l1a_l1s_com.dl_tn"                                   */
/* Timeslot on which L1 is synchronized                  */
/*                                                       */
/* "l1pa_l1ps_com.transfer.aset->multislot_class"        */
/* Multi-slot class in Packet transfer                   */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/*                                                       */
/* "l1s.tpu_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/TPU com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*                                                       */
/* "l1s.dsp_ctrl_reg"                                    */
/*   bit register used to know at the end of L1S if      */
/*   something has been programmed on the MCU/DSP com.   */
/*   This is used mainly to swap then the com. page at   */
/*   the end of a control frame.                         */
/*   -> set CTRL_RX bit in the register.                 */
/*-------------------------------------------------------*/
void l1ps_ctrl_itmeas(UWORD8 param1, UWORD8 param2)
{

#if (RF_FAM == 61)
  UWORD16 dco_algo_ctl_pw = 0;
  UWORD8 if_ctl = 0;
  UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS;
  UWORD8 ts = 0;
#endif

  // Traces and debug.
  // ******************

  #if (TRACE_TYPE==5)
    trace_fct(CST_L1PS_CTRL_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq);
  #endif

  // Timeslots selection
  // ********************

  // Packet transfer mode <-> PDTCH task enabled: condition to check !!!!
  //---------------------

  // Timeslots already selected in l1p_asyn.c

  // Packet idle mode
  //-----------------
  if (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_DISABLED)
  {
    // If a RX has been programmed on this frame
    if (l1s.dsp_ctrl_reg & CTRL_RX)
    {
      // The pre-processed bitmap with Rx taken into account is taken
      l1pa_l1ps_com.itmeas.meas_bitmap = l1pa_l1ps_com.itmeas.idle_tn_rx;
    }
    else
    {
      // The pre-processed bitmap without Rx taken into account is taken
      l1pa_l1ps_com.itmeas.meas_bitmap = l1pa_l1ps_com.itmeas.idle_tn_no_rx;
    }

  } // End if 'packet idle mode'

  l1pa_l1ps_com.itmeas.dsp_r_page_switch_req = FALSE;

  // If some measurements can be done
  if (l1pa_l1ps_com.itmeas.meas_bitmap != 0)
  {
    UWORD8 nbmeas;

    // DSP read page switched or not during the ITMEAS read phase ?

    if (l1s.dsp_ctrl_reg == NO_CTRL)
    {
      // A control task hasn't already been done in this frame --> Read page switch
      l1pa_l1ps_com.itmeas.dsp_r_page_switch_req = TRUE;
    }

    // Traces and debug.
    // ******************
    #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5)
      trace_fct(CST_L1PS_CTRL_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq);
    #endif


#if(RF_FAM == 61)   // Locosto DCO
    #if (PWMEAS_IF_MODE_FORCE == 0)
        cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw, &if_ctl, (UWORD8) L1_IL_INVALID ,
            0, l1pa_l1ps_com.itmeas.radio_freq, if_threshold);
      #else
        if_ctl = IF_120KHZ_DSP;
        dco_algo_ctl_pw = DCO_IF_0KHZ;
      #endif



#endif

    // Program TPU
    // ************
#if (RF_FAM != 61)
    nbmeas = l1pdtpu_interf_meas(l1pa_l1ps_com.itmeas.radio_freq,
                                 l1_config.params.high_agc,
                                 0,
                                 l1pa_l1ps_com.itmeas.meas_bitmap,
                                 l1s.tpu_offset,
                                 l1s.tpu_win,
                                 l1a_l1s_com.dl_tn);
#endif

#if (RF_FAM == 61)
    nbmeas = l1pdtpu_interf_meas(l1pa_l1ps_com.itmeas.radio_freq,
                                 l1_config.params.high_agc,
                                 0,
                                 l1pa_l1ps_com.itmeas.meas_bitmap,
                                 l1s.tpu_offset,
                                 l1s.tpu_win,
                                 l1a_l1s_com.dl_tn,
                                 if_ctl);
#endif


    // Program DSP
    // ************

    l1pddsp_interf_meas_ctrl(nbmeas);

#if(RF_FAM == 61) // TBD
    // Reproduce the DCO control for all the power measurement
     dco_algo_ctl_pw = dco_algo_ctl_pw * 0x55; // Replicate ZLZLZLZL
     dco_algo_ctl_pw = dco_algo_ctl_pw >> (2*(4 - nbmeas)); // reduce to ZLs of Nbr
     if(l1s.tcr_prog_done==1)
     {
       dco_algo_ctl_pw=((dco_algo_ctl_pw<<2)|(l1s_dsp_com.dsp_db_common_w_ptr->d_dco_algo_ctrl_pw&0x3));
     }
     l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw);
    // of Meas Programmed
#endif
    // Flag DSP and TPU programmation.
    // ********************************

    // Set "CTRL_RX" flag in the controle flag register.
    l1s.tpu_ctrl_reg |= CTRL_MS;
    l1s.dsp_ctrl_reg |= CTRL_MS;

  } // End if 'nbmeas != 0'

  // This task is not compatible with Neigh. Measurement. Store task length
  // in "forbid_meas" to indicate when the task will last.
  // Rem: Only FB51 task starts from this ctrl function.
  l1s.forbid_meas = TASK_ROM_MFTAB[ITMEAS].size;
}
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM


#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START

/*-------------------------------------------------------*/
/* l1ps_read_itmeas()                                    */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* This function is a "COMPLEX" function used for the    */
/* L1S ITMEAS task.                                      */
/*                                                       */
/* Here is a summary of the execution:                   */
/*                                                       */
/*  - If SEMAPHORE(task) is low and task still enabled.  */
/*      - Traces and debug.                              */
/*      - Read interference measurement results in NDB   */
/*      - Fill and send reporting message                */
/*  - Disactivate task.                                  */
/*  - Flag the use of the MCU/DSP dual page read         */
/*    interface if needed.                               */
/*                                                       */
/* Input parameters:                                     */
/* -----------------                                     */
/*                                                       */
/* Input parameters from globals:                        */
/* ------------------------------                        */
/* "l1pa_l1ps_com.itmeas"                                */
/* Interference measurement parameters structure         */
/*                                                       */
/* Modified parameters from globals:                     */
/* ---------------------------------                     */
/* "l1s.task_status[task].current_status"                */
/*   current task status. It must be reset (INACTIVE)    */
/*   when the task is completed.                         */
/*   -> disactivate task.                                */
/*                                                       */
/* "l1s_dsp_com.dsp_r_page_used"                         */
/*   Flag used by the function which closes L1S          */
/*   execution ("l1s_end_manager()") to know if the      */
/*   MCU/DSP read page must be switched.                 */
/*   -> Set to 1 only if no other task was controlled    */
/*      in the same frame as ITMEAS                      */
/*                                                       */
/* Use of MCU/DSP interface:                             */
/* -------------------------                             */
/* "l1s_dsp_com.dsp_ndb_ptr"                             */
/*   pointer to the non double buffered part (NDB) of    */
/*   the MCU/DSP interface. This part is R/W for both    */
/*   DSP and MCU.                                        */
/*-------------------------------------------------------*/
void l1ps_read_itmeas(UWORD8 param1, UWORD8 param2)
{
  xSignalHeaderRec *msg;
  UWORD8           i;
  WORD8            delta1_freq, delta2_freq;
  UWORD16          g_magic;

  if(!(l1a_l1s_com.task_param[ITMEAS]) &&
      (l1a_l1s_com.l1s_en_task[ITMEAS]))
  {
    // Traces and debug.
    // ******************

    #if (TRACE_TYPE!=0)
      trace_fct(CST_L1PS_READ_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq);
    #endif

    // Allocate result message.
    // ************************

    msg = os_alloc_sig(sizeof(T_L1P_ITMEAS_IND));
    DEBUGMSG(status,NU_ALLOC_ERR)

    // Fill msg signal code
    msg->SignalCode = L1P_ITMEAS_IND;

    // Fill msg contents
    // ******************

    ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn = l1s.actual_time.fn;
    // Report measurement bitmap
    ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap = l1pa_l1ps_com.itmeas.meas_bitmap;

    // Read result from DSP
    g_magic     = l1ctl_get_g_magic(l1pa_l1ps_com.itmeas.radio_freq);
    delta1_freq = l1ctl_encode_delta1(l1pa_l1ps_com.itmeas.radio_freq);
    delta2_freq = l1ctl_encode_delta2(l1pa_l1ps_com.itmeas.radio_freq);

    for (i = 0; i < 8; i++)
    {
      UWORD8 pm;
      WORD16 IL_for_rxlev;

      pm = (l1ps_dsp_com.pdsp_ndb_ptr->a_interf_meas_gprs[i] & 0xffff) >> 5;

      // IL processing
      if (pm == 0)
      {
        ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i] = (WORD8)0x80;
      }
      else
      {
        IL_for_rxlev = -(pm - (l1_config.params.high_agc << 1) - g_magic) - delta1_freq - delta2_freq;


        ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i] = l1s_encode_rxlev(IL_for_rxlev);
      }
    }

    // If the Read phase is done during fn_mod26 = 13 --> measurements have been done
    // during a PTCCH frame
    if (l1s.actual_time.t2 == 13)
    {
      ((T_L1P_ITMEAS_IND *)(msg->SigP))->position  = PTCCH_FRAME;
    }
    else  // Measurements done during a search frame
    {
      ((T_L1P_ITMEAS_IND *)(msg->SigP))->position  = SEARCH_FRAME;
    }

    // send message...
    os_send_sig(msg, L1C1_QUEUE);
    DEBUGMSG(status,NU_SEND_QUEUE_ERR)

    // ITMEAS is a 'one shot' task --> disable task
    l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_DISABLED;
  } // End if "task enabled and semaphore false"

  // End of task -> task must become INACTIVE.
  l1s.task_status[ITMEAS].current_status = INACTIVE;

  // Switch DSP read page if needed
  if(l1pa_l1ps_com.itmeas.dsp_r_page_switch_req)
  {
    // Set flag used to change the read page at the end of "l1_synch".
    l1s_dsp_com.dsp_r_page_used = TRUE;
  }
}

//#pragma DUPLICATE_FOR_INTERNAL_RAM_END
#endif // MOVE_IN_INTERNAL_RAM

//#pragma DUPLICATE_FOR_INTERNAL_RAM_START
#endif
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END