view src/cs/layer1/p_cfile/l1p_asyn.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_ASYN.C
 *
 *        Filename l1p_asyn.c
 *  Copyright 2003 (C) Texas Instruments
 *
 ************* Revision Controle System Header *************/

//#pragma DUPLICATE_FOR_INTERNAL_RAM_START
  #include "l1_macro.h"
  #include "l1_confg.h"
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END

#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

#define  L1P_ASYN_C

//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END         // KEEP IN EXTERNAL MEM otherwise
#endif

//#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"
  #if TESTMODE
    #include "l1tm_defty.h"
  #endif
  #if (AUDIO_TASK == 1)
    #include "l1audio_const.h"
    #include "l1audio_cust.h"
    #include "l1audio_defty.h"
  #endif
  #if (L1_GTT == 1)
    #include "l1gtt_const.h"
    #include "l1gtt_defty.h"
  #endif
  #if (L1_MP3 == 1)
    #include "l1mp3_defty.h"
  #endif
  #if (L1_MIDI == 1)
    #include "l1midi_defty.h"
  #endif
  #include "l1_defty.h"
  #include "cust_os.h"
  #include "l1_msgty.h"
  #include "l1_varex.h"
  #include "l1_signa.h"
  #include "l1_proto.h"
  #include "l1_time.h"
  #include "l1_ctl.h"

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_tabs.h"
  #include "l1p_sign.h"
  #include "l1p_mfta.h"
  #include "l1p_macr.h"

  #include "macs_def.h"
  #include "macs_cst.h"
#else
  #include <string.h>
  #include "l1_types.h"
  #include "sys_types.h"
  #include "l1_const.h"

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

  #include "l1p_cons.h"
  #include "l1p_msgt.h"
  #include "l1p_deft.h"
  #include "l1p_vare.h"
  #include "l1p_tabs.h"
  #include "l1p_sign.h"
  #include "l1p_mfta.h"
  #include "l1p_macr.h"

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

T_TRANSFER_SET   *l1pa_get_free_transfer_set              (UWORD8  new_tbf);
void              l1pa_transfer_process                   (xSignalHeaderRec *msg);
void              l1pa_access_process                     (xSignalHeaderRec *msg);
void              l1pa_idle_packet_polling_process        (xSignalHeaderRec *msg);
void              l1pa_idle_paging_process                (xSignalHeaderRec *msg);
void              l1pa_cr_meas_process                    (xSignalHeaderRec *msg);
void              l1pa_serving_cell_pbcch_read_process    (xSignalHeaderRec *msg);
void              l1pa_neighbor_cell_pbcch_read_process   (xSignalHeaderRec *msg);
int               l1pa_sort                               (const void *a, const void *b);
void              l1pa_reset_cr_freq_list                 (void);
void              l1pa_tcr_meas_process                   (xSignalHeaderRec *msg);
T_CRES_LIST_PARAM *l1pa_get_free_cres_list_set            (void);
void              l1pa_idle_interference_meas_process     (xSignalHeaderRec *msg);
void              l1pa_transfer_interference_meas_process (xSignalHeaderRec *msg);
void              l1pa_idle_smscb_process                 (xSignalHeaderRec *msg);

// External prototype
void l1pa_send_int_meas_report(UWORD32               SignalCode,
                               T_L1P_ITMEAS_IND     *last_l1s_msg,
                               T_L1A_INT_MEAS_PARAM *first_meas_ptr);
void l1pa_send_confirmation(UWORD32 SignalCode, UWORD8 id);
void l1pa_send_tbf_release_con(UWORD32 SignalCode, UWORD8 tbf_type);

//#pragma DUPLICATE_FOR_INTERNAL_RAM_END

#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1))  // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2
//#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START         // KEEP IN EXTERNAL MEM otherwise


/*-------------------------------------------------------*/
/* l1pa_task()                                           */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:                                          */
/* ------------                                          */
/* L1PA (Layer 1 Asynchronous) task function. This       */
/* function manages the GPRS interface between L3 and L1.*/
/* It is composed with a set of state machine, each      */
/* machine handles a particular GSM functionality. When  */
/* a message is received in L1_C1 message queue, it is   */
/* submitted to every state machine. The one which are   */
/* impacted by the message process it. At the end of     */
/* "l1pa_task()" function, a balance routine is called,  */
/* it enables L1S tasks consequently to the state machine*/
/* requests.                                             */
/*                                                       */
/*-------------------------------------------------------*/
void  l1pa_task(xSignalHeaderRec *msg)
{
  UWORD8  process;

  // Clear L1PA "enable meas and tasks" variables.
  //---------------------------------------------
  for(process=0; process<NBR_L1PA_PROCESSES; process++)
  {
    l1pa.l1pa_en_meas[process] = NO_TASK;
  }

  #if (GSM_IDLE_RAM != 0)
    if ((msg->SignalCode != L1P_PNP_INFO) && (msg->SignalCode != L1P_PEP_INFO))

    #if (GSM_IDLE_RAM > 1) // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM
          {
    #endif
            l1s.gsm_idle_ram_ctl.l1s_full_exec = TRUE;
  #endif // GSM_IDLE_RAM

  // Serving Cell Packet System Information Reading
  l1pa_serving_cell_pbcch_read_process(msg);

  // Neighbor Cell Packet System Information Reading
  l1pa_neighbor_cell_pbcch_read_process(msg);

  #if (GSM_IDLE_RAM <= 1)  // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM
  {
    // Serving Cell Packet Paging Reading
    l1pa_idle_paging_process(msg);
  }
  #endif
  // Cell reselection measurement process
  l1pa_cr_meas_process(msg);

  // Packet access proccess
  l1pa_access_process(msg);

  // Packet polling process
  l1pa_idle_packet_polling_process(msg);

  // Packet transfer process.
  l1pa_transfer_process(msg);

  // Neighbour Cell Measurement in Packet Transfer mode
  l1pa_tcr_meas_process(msg);

  // Intererence measurements in packet idle mode
  l1pa_idle_interference_meas_process(msg);

  // Intererence measurements in packet transfer mode
  l1pa_transfer_interference_meas_process(msg);

  #if (GSM_IDLE_RAM > 1)  // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM
  }else
  {
    // Serving Cell Packet Packet Idle Paging Reading
    l1pa_idle_paging_process(msg);
  }
  #endif
}

//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END         // KEEP IN EXTERNAL MEM otherwise
#endif

/*-------------------------------------------------------*/
/* l1pa_access_process()                                 */
/*-------------------------------------------------------*/
/* Description : This state machine handles the packet   */
/* access to the network while in PACKET IDLE mode.      */
/*                                                       */
/* Starting messages:        MPHP_RA_REQ                 */
/*                                                       */
/* Subsequent messages:      MPHP_RA_REQ                 */
/*                                                       */
/* Result messages (input):  L1P_PRA_DONE                */
/*                                                       */
/* Result messages (output): MPHP_RA_CON                 */
/*                                                       */
/* Reset message (input): MPHP_RA_STOP_REQ               */
/*                                                       */
/* Reset message (input): MPHP_RA_STOP_CON               */
/*-------------------------------------------------------*/
void l1pa_access_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET       = 0,
    WAIT_INIT   = 1,
    WAIT_RESULT = 2
  };

  UWORD8   *state      = &l1pa.state[P_ACC];
  UWORD32   SignalCode = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_INIT;

        // Reset PRACH process.
        l1a_l1s_com.l1s_en_task[PRACH]     = TASK_DISABLED;  // Clear PRACH task enable flag.
        l1pa_l1ps_com.pra_info.prach_alloc = 0;
      }
      break;


      case WAIT_INIT:
      {
        if(SignalCode == MPHP_RA_REQ)
        // 1st Random access request message.
        //-----------------------------------
        {

          // Download Transmit power configuration.
          // Given value must be used on 1st TX.
          // TXPWR value supplied by L3 is the max. TX power level the MS may use in the given band
          l1s.applied_txpwr = ((T_MPHP_RA_REQ *)(msg->SigP))->txpwr;


          #if L1_R99
          // Init PRACH process.
            // "rand" parameter chosen by protocol in range [1..4] for R99
            l1pa_l1ps_com.pra_info.rand                 = ((T_MPHP_RA_REQ *)(msg->SigP))->rand;
          #else
          // "rand" parameter from msg is not used for the 1st PRACH.
          l1pa_l1ps_com.pra_info.rand                 = 1; // First PRACH has to be sent immediately
          #endif
          l1pa_l1ps_com.pra_info.channel_request_data = ((T_MPHP_RA_REQ *)(msg->SigP))->channel_request_data;
          l1pa_l1ps_com.pra_info.bs_prach_blks        = ((T_MPHP_RA_REQ *)(msg->SigP))->bs_prach_blks;
          l1pa_l1ps_com.access_burst_type             = ((T_MPHP_RA_REQ *)(msg->SigP))->access_burst_type;

          // Increment rand parameter by 4 in order to avoid conflict between SYNCHRO and
          // PRACH tasks when MPHP_START_PCCCH_REQ and MPHP_RA_REQ are
          // sent at the same time by L3
          l1pa_l1ps_com.pra_info.rand+=4;

          if ((l1pa_l1ps_com.pra_info.bs_prach_blks == 0) || // no blocks allocated
              (l1pa_l1ps_com.pra_info.bs_prach_blks > 12))   // invalid number of blocks
            l1pa_l1ps_com.pra_info.prach_alloc = DYN_PRACH_ALLOC;

          // step in state machine.
          *state = WAIT_RESULT;

          // Change mode to connection establishment part 1.
          l1a_l1s_com.mode = CON_EST_MODE1;

          // Activate PRACH task (no semaphore for UL tasks).
          l1a_l1s_com.l1s_en_task[PRACH] = TASK_ENABLED; // Set PRACH task enable flag.

        }

        // end of process.
        end_process = 1;
      }
      break;

      case WAIT_RESULT:
      {
        if(SignalCode == L1P_RA_DONE)
        // Random access acknowledge message: PRACH sent.
        //-----------------------------------------------
        {
          // Forward result message to L3.
          l1a_send_result(MPHP_RA_CON, msg, GRRM1_QUEUE);

          // Change mode to connection establishment part 2.
          l1a_l1s_com.mode = CON_EST_MODE2;

          // end of process.
          return;
        }

        else
        if(SignalCode == MPHP_RA_REQ)
        // Random access message.
        //-----------------------
        {
          // REM: rand is added the msg content since its current content is the already
          // spent "slots" from the last PRACH sending.
          l1pa_l1ps_com.pra_info.rand                += ((T_MPHP_RA_REQ *)(msg->SigP))->rand + 1;
          l1pa_l1ps_com.pra_info.channel_request_data = ((T_MPHP_RA_REQ *)(msg->SigP))->channel_request_data;
          l1pa_l1ps_com.pra_info.bs_prach_blks        = ((T_MPHP_RA_REQ *)(msg->SigP))->bs_prach_blks;
          l1pa_l1ps_com.access_burst_type             = ((T_MPHP_RA_REQ *)(msg->SigP))->access_burst_type;

          if ((l1pa_l1ps_com.pra_info.bs_prach_blks == 0) || // no blocks allocated
              (l1pa_l1ps_com.pra_info.bs_prach_blks > 12))   // invalid number of blocks
            l1pa_l1ps_com.pra_info.prach_alloc = DYN_PRACH_ALLOC;
//          else
//            l1pa_l1ps_com.pra_info.prach_alloc = FIX_PRACH_ALLOC;
          else
            l1pa_l1ps_com.pra_info.prach_alloc = 0; //must be reset for each burst sent


          // Activate PRACH task (no semaphore for UL tasks).
          l1a_l1s_com.l1s_en_task[PRACH] = TASK_ENABLED;   // Set PRACH task enable flag.

          // end of process.
          return;
        }

        else
        if(SignalCode == MPHP_RA_STOP_REQ)
        // Request to STOP the LINK ACCESS procedure.
        //-------------------------------------------
        {
          UWORD8 i;

          // send confirmation
          l1a_send_confirmation(MPHP_RA_STOP_CON,GRRM1_QUEUE);

          // Store MAX TXPWR value to be used for first Tx PDCH blocks
          for(i = 0; i < 8; i++)
          {
            l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = l1s.applied_txpwr;
          }

          // This process must be reset.
          *state = RESET;
        }

        else
        if(SignalCode == MPHP_POLLING_RESPONSE_REQ)
        // Stop packet access when packet polling initiated.
        //--------------------------------------------------
        {
          // Unacknowledged

          // This process must be reset.
          *state = RESET;
        }

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          end_process = 1;
        }
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.

/*-------------------------------------------------------*/
/* l1pa_cr_meas_process()                                */
/*-------------------------------------------------------*/
/* Description : This state machine handles periodic     */
/* signal strength monitoring on carriers specified      */
/* in a frequency list: BA(GPRS), NC_FREQUENCY_LIST,     */
/* EXT_FREEQUENCY_LIST (respectively: cell reselection   */
/* Network Control and Extended measurements.            */
/*                                                       */
/* Starting messages:        MPHP_CR_MEAS_REQ            */
/* ------------------                                    */
/*  L1 starts then the periodic FREQUENCY list receive   */
/*  level monitoring.                                    */
/*                                                       */
/* Subsequent messages:      MPHP_CR_MEAS_REQ            */
/* --------------------                                  */
/*  The frequency list is updated only when measures     */
/*  on all the carriers of the current list are          */
/*  performed.                                           */
/*                                                       */
/* Result messages (input):  L1P_RXLEV_PERIODIC_DONE     */
/* ------------------------                              */
/*  This is a message reported to L1A from L1S.          */
/*  Reporting is done when last carrier of the frequency */
/*  list is read.                                        */
/*                                                       */
/* Result messages (output): MPHP_CR_MEAS_IND            */
/* -------------------------                             */
/*  This is the periodic reporting message to L3.        */
/*                                                       */
/* Reset messages (input):   MPHP_CR_MEAS_STOP_REQ       */
/* -----------------------                               */
/*  Frequency list measurement process is stopped by     */
/*  this message.                                        */
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_cr_meas_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET       = 0,
    WAIT_INIT   = 1,
    WAIT_RESULT = 2

  };

  UWORD8   *state      = &l1pa.state[CR_MEAS];
  UWORD32   SignalCode = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // step in state machine.
        *state = WAIT_INIT;

        // Reset P_CRMS_MEAS process.
        l1pa_l1ps_com.l1ps_en_meas &= P_CRMS_MEAS_MASK; // Reset Packet Cell Reselection Measurement enable flag.
      }
      break;

      case WAIT_INIT:
      {
        if(SignalCode == MPHP_CR_MEAS_REQ)
        // We receive the Frequency list to be monitored.
        //----------------------------------------------
        {
          UWORD8  i;
          T_CRES_LIST_PARAM  *free_list;

          // Set parameter synchro semaphore for P_CRMS_MEAS task.
          l1pa_l1ps_com.meas_param |= P_CRMS_MEAS;

          // Reset the frequency list structure.
          l1pa_reset_cr_freq_list();

          // Get Ptr to the free Neighbour meas list.
          // The number of carriers in the list and the list
          // identification are initialized.
          free_list = l1pa_get_free_cres_list_set();

          // Set number of carrier in the frequency list.
          free_list->nb_carrier = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->nb_carrier;

          // Store ARFCN list in the Packet Cell Reselection structure.
          for(i=0;i<free_list->nb_carrier;i++)
            free_list->freq_list[i] = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i];

          // Download Frequency list identifier.
          free_list->list_id = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->list_id;

          // Set "flist" with new set of frequency list parameter
          l1pa_l1ps_com.cres_freq_list.flist = free_list;

          // Enable Packet Cell Reselection measurement task.
          l1pa.l1pa_en_meas[CR_MEAS] |= P_CRMS_MEAS;

          // step in state machine.
          *state = WAIT_RESULT;
        }

        // End of process.
        end_process = 1;
      }
      break;

      case WAIT_RESULT:
      {
        if(SignalCode == L1P_CR_MEAS_DONE)
        // One set of measurement has been completed.
        //---------------------------------------------
        {
          // Forward result message to L3.
          l1a_send_result(MPHP_CR_MEAS_IND, msg, GRRM1_QUEUE);

          // End of process.
          end_process = 1;
        }

        else
        if((SignalCode == MPHP_CR_MEAS_STOP_REQ) ||
           (SignalCode == L1P_TRANSFER_DONE)     ||
           (SignalCode == L1C_DEDIC_DONE))
        // Request to STOP this activity.
        //-------------------------------
        {
          // send confirmation message
          l1a_send_confirmation(MPHP_CR_MEAS_STOP_CON,GRRM1_QUEUE);
          // This process must be reset.
          *state = RESET;
        }

        else
        if (SignalCode == MPHP_CR_MEAS_REQ)
        {
          // This process must be reset.
          *state = RESET;
        }

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          end_process = 1;
        }
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.

#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1))  // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2
//#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START         // KEEP IN EXTERNAL MEM otherwise

/*-------------------------------------------------------*/
/* l1pa_idle_paging_process()                            */
/*-------------------------------------------------------*/
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_idle_paging_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET             = 0,
    WAIT_INIT         = 1,
    WAIT_MSG          = 2
  };

  enum pg_mode
  {
    NORM_PG           = 0,
    EXT_PG            = 1,
    REORG_PG          = 2
  };

  UWORD8  *state     = &l1pa.state[PI_SCP];
  UWORD32 SignalCode = msg->SignalCode;
  UWORD16 imsimod;
  UWORD16 split_pg_cycle;
  UWORD16 kcn;
  UWORD8  page_mode;

  BOOL end_process = 0;

  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_INIT;

        // Disable serving cell tasks.
        l1a_l1s_com.l1s_en_task[PALLC]   = TASK_DISABLED;     // Reset PALLC (reorg) task enable flag.
        l1a_l1s_com.l1s_en_task[PNP]     = TASK_DISABLED;     // Reset PNP     task enable flag.
        l1a_l1s_com.l1s_en_task[PEP]     = TASK_DISABLED;     // Reset PEP     task enable flag.

        // No Paging  => no gauging => no Deep sleep
        l1s.pw_mgr.enough_gaug = FALSE;  // forbid Deep sleep

      }
      break;

      case WAIT_INIT:
      {
        if(SignalCode == MPHP_START_PCCCH_REQ)
        {
          // Set semaphores for any PCCCH reading tasks.
          l1a_l1s_com.task_param[PALLC] = SEMAPHORE_SET;
          l1a_l1s_com.task_param[PNP]   = SEMAPHORE_SET;
          l1a_l1s_com.task_param[PEP]   = SEMAPHORE_SET;

          // Request to enter in PACKET PAGING REORGANIZATION or NORMAL mode.
          //----------------------------------------------------------------
          // The initial page mode in the Mobile Station shall be set to paging Reorganization
          // cf 04.08 section 3.3.2.1.1. however current implementation allows to init the Paging
          // procedure either in Reorganization or in Normal paging mode.

          // Download the PAGING PARAMETERS from the command message.
          page_mode                           = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->page_mode;
          imsimod                             = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->imsimod;
          kcn                                 = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->kcn;
          split_pg_cycle                      = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->split_pg_cycle;
          l1pa_l1ps_com.pccch.bs_pag_blks_res = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->bs_pag_blks_res;
          l1pa_l1ps_com.pccch.bs_pbcch_blks   = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->bs_pbcch_blks;
          l1pa_l1ps_com.pccch.frequency_list  = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->frequency_list;
          l1pa_l1ps_com.pccch.packet_chn_desc = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->packet_chn_desc;
          l1a_l1s_com.Scell_info.pb           = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1

          // Number of paging blocks "available" on one PCCCH = number of ppch blocks per MF52 * 64
          // = (12 - BS_PAG_BLKS_RES - BS_PBCCH_BLKS)*64
          l1pa_l1ps_com.pccch.nb_ppch_per_mf52 = (12 - l1pa_l1ps_com.pccch.bs_pag_blks_res - (l1pa_l1ps_com.pccch.bs_pbcch_blks + 1));

          // Compute M.
          l1pa_l1ps_com.pccch.pg_blks_avail    =  l1pa_l1ps_com.pccch.nb_ppch_per_mf52 * 64;

          // (IMSI mod 1000) div (KC*N) (Note: N = 1 for PCCCH)
          l1pa_l1ps_com.pccch.pg_offset        = imsimod / kcn;

          // First Paging Group value: PAGING_GROUP = ((IMSI mod 1000) div ((KC*N)*N)) (for m = 0)
          l1pa_l1ps_com.pccch.first_pg_grp     = (l1pa_l1ps_com.pccch.pg_offset % l1pa_l1ps_com.pccch.pg_blks_avail);

          // Split Paging computation = min (pg_blks_avail, SPLIT_PG_CYCLE)
          l1pa_l1ps_com.pccch.split_pg_value = Min(l1pa_l1ps_com.pccch.pg_blks_avail, split_pg_cycle);

          // Paging Period computation
          l1pa_l1ps_com.pccch.pnp_period = (64*52) / l1pa_l1ps_com.pccch.split_pg_value;

          // Rem: changing the paging parameters changes the place where "Periodic Packet
          //      Measurement" task must be executed. It implies to set semaphore for P_CRMS task.
          l1pa_l1ps_com.meas_param |= P_CRMS_MEAS;

          // Layer 1 internal mode is set to IDLE MODE.
          l1a_l1s_com.mode = I_MODE;

          // In order to keep tn_difference and dl_tn consistent, we need to avoid
          // the execution of the SYNCHRO task with tn_difference updated and
          // dl_tn not yet updated (this can occur if we go in the HISR just after
          // the update of tn_difference). To do this the solution is to use the Semaphore
          // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its
          // associated Semaphore is reset.
          // Note: Due to the specificity of the SYNCHRO task which can be enabled
          // by L1A state machines as by L1S processes, the semaphore can't followed
          // the generic rules of the Semaphore shared between L1A and L1S.
          // We must shift the mobile time setting to the timeslot provided by
          // ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->packet_chn_desc.timeslot_no parameter.
          //   tn_difference -> loaded with the number of timeslot to shift.
          //   dl_tn         -> loaded with the new timeslot.
          l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET;
          {
            l1a_l1s_com.tn_difference += l1pa_l1ps_com.pccch.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn;
            l1a_l1s_com.dl_tn          = l1pa_l1ps_com.pccch.packet_chn_desc.timeslot_no;

            // Select GPRS DSP Scheduler.
            l1a_l1s_com.dsp_scheduler_mode = GPRS_SCHEDULER;

            // Timing must be shifted to a new timeslot, enables SYNCHRO task..
            l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED;
          }
          l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET;
          // Note: The using of the semaphore associated to the SYNCHRO task can't be done
          // as it is for the other semaphores. This is due to the specificity of the SYNCHRO
          // task both touch by L1A and L1S. Here above the semaphore is set prior to touching
          // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's
          // seen SET then L1S will not execute SYNCHRO task nor modify its parameters.

          // Step in state machine.
          *state = WAIT_MSG;

          if(page_mode == REORG_PG)
          // Paging Reorganization mode...
          {
            // Enable Packet Paging Reorganisation tasks.
            l1a_l1s_com.l1s_en_task[PALLC] = TASK_ENABLED;
            l1a_l1s_com.l1s_en_task[PNP]   = TASK_ENABLED;

            // End of process.
            end_process = 1;
          }
          else
          if(page_mode == NORM_PG)
          // Normal Paging mode...
          {
            // Enable Packet Paging tasks in mode "NORMAL".
            l1a_l1s_com.l1s_en_task[PNP]  = TASK_ENABLED;

            // End of process.
            end_process = 1;
          }
          else
          // Extended Paging mode...
          {
            // Initialize Paging State for PAGING_GROUP computation (L1S part)
            l1pa_l1ps_com.pccch.epg_computation = PPCH_POS_NOT_COMP;

            // Enable Packet Paging tasks in mode "EXTENDED".
            l1a_l1s_com.l1s_en_task[PNP]  = TASK_ENABLED;
            l1a_l1s_com.l1s_en_task[PEP]  = TASK_ENABLED;

            // End of process.
            end_process = 1;
          }

        } // end of test on SignalCode == MPHP_START_PCCCH_REQ

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          end_process = 1;
        }

      } // end of case WAIT_INIT
      break;

      case WAIT_MSG:
      {
        if((SignalCode == L1P_PNP_INFO)   ||
           (SignalCode == L1P_PALLC_INFO) ||
           (SignalCode == L1P_PEP_INFO))
        // Paging Task results
        {
          // Forward result message to L3.
          l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE);

          // End of process.
          return;
        }

        else
        if(SignalCode == MPHP_START_PCCCH_REQ)
        // New PCCCH configuration is provided.
        //--------------------------------------------------------
          {
          // Step in state machine
            *state = RESET;
          }

        else
        if((SignalCode == MPHP_STOP_PCCCH_REQ) ||
           (SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1C_DEDIC_DONE))
        // Request to STOP any serving cell Packet Paging activity, OR
        // Packet Transfer has just started.
        // In both cases, PCCCH reading must be stopped.
        //--------------------------------------------------------
        {
          // Send confirmation message to L3.
          l1a_send_confirmation(MPHP_STOP_PCCCH_CON,GRRM1_QUEUE);

          // This process must be reset.
          *state = RESET;
        }

        else
        if((SignalCode == L1P_SINGLE_BLOCK_CON) ||
           (SignalCode == MPHP_SINGLE_BLOCK_CON))
        // If Two Phase Access is ongoing: Packet Resource Request
        // msg has been sent to the network. PCCCH reading must be
        // stopped to let PDCH reading going.
        // REM: we must check both L1P/MPHP messages since an other
        // process could have renamed L1P into MPHP.
        //--------------------------------------------------------
        {
          if(((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose == TWO_PHASE_ACCESS)
        {
          // This process must be reset.
          *state = RESET;
        }
        else
        {
            // End of process.
            return;
          }
        }

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          return;
        }

      } // end of case WAIT_MSG
      break;
    } // end of switch
  } // end of while
} // end of procedure

//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END
#endif

/*-------------------------------------------------------*/
/* l1pa_idle_packet_polling_process()                    */
/*-------------------------------------------------------*/
/* Description :                    .                    */
/* This state machine handles packet polling after       */
/* initiation of the packet acces procedure, when a      */
/* packet queuing notification is sent by the network    */
/*                                                       */
/* Starting messages:        MPHP_POLLING_RESPONSE_REQ   */
/*                                                       */
/* Subsequent messages:                                  */
/*                                                       */
/* Result messages (input):  L1P_PRA_DONE                */
/*                                                       */
/* Result messages (output): MPHP_POLLING_IND            */
/*                                                       */
/* Reset message (input):                                */
/*                                                       */
/* Reset message (input):                                */
/*-------------------------------------------------------*/
void l1pa_idle_packet_polling_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET       = 0,
    WAIT_INIT   = 1,
    WAIT_RESULT = 2
  };

  UWORD8   *state      = &l1pa.state[P_POLL];
  UWORD32   SignalCode = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_INIT;

        // Reset POLL process.
        l1a_l1s_com.l1s_en_task[POLL] = TASK_DISABLED;  // Clear RAACC task enable flag.
      }
      break;


      case WAIT_INIT:
      {
        if(SignalCode == MPHP_POLLING_RESPONSE_REQ)
        // Polling response request for access procedure.
        //-----------------------------------------------
        {
          UWORD8 i;

          // Init POLL process.
          l1pa_l1ps_com.poll_info.pol_resp_type = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->pol_resp_type;
          l1pa_l1ps_com.poll_info.fn            = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->fn;

         // TXPWR value supplied by L3 is the max. TX power level the MS may use in the given band
          l1s.applied_txpwr                     = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->txpwr;

          // 1 RLC/MAC block is sent:
          // This is a special case, only possible if the MS has a valid TA available from a pending
          // assignment and is pooled for an RLC/MAC block.
          if (l1pa_l1ps_com.poll_info.pol_resp_type == CS1_TYPE_POLL)
          {
            for (i=0; i<24; i++)
            {
              // download 24 bytes from message
              l1pa_l1ps_com.poll_info.chan_req.cs1_data[i] =
                ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[i];
            }
            l1pa_l1ps_com.poll_info.timing_advance = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->timing_advance;

            // Store MAX TXPWR value to be used for first POLL RESPONSE
            // if not already done by Packet Access process...
            for(i = 0; i < 8; i++)
            {
              l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = l1s.applied_txpwr;
            }
          }
          // 4 identical PRACH are sent
          else
          {
            // UWORD16 = data[1]<<8 | data[0]
            l1pa_l1ps_com.poll_info.chan_req.prach_data[0] =
              ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[0];
            l1pa_l1ps_com.poll_info.chan_req.prach_data[0] |=
              (((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[1] << 8);

            l1pa_l1ps_com.poll_info.timing_advance = 0;
          }

          // step in state machine.
          *state = WAIT_RESULT;

          // Change mode to connection establishment part 1.
          l1a_l1s_com.mode = CON_EST_MODE1;

          // Activate POLL task (no semaphore for UL tasks).
          // Enable Paging Reorg and Normal paging tasks.
          l1a_l1s_com.l1s_en_task[POLL] = TASK_ENABLED; // Set PRACH task enable flag.
        }

        // end of process.
        end_process = 1;
      }
      break;

      case WAIT_RESULT:
      {
        if(SignalCode == L1P_POLL_DONE)
        // Random access acqnowledge message.
        //-----------------------------------
        {
          // Forward result message to L3.
          l1a_send_result(MPHP_POLLING_IND, msg, GRRM1_QUEUE);

          // Change mode to connection establishment part 2.
          l1a_l1s_com.mode = CON_EST_MODE2;

          // This state machine has to be reset
          *state = RESET;

          // end of process.
          end_process = 1;
        }

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          end_process = 1;
        }
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.


/*-------------------------------------------------------*/
/* l1pa_transfer_process()                               */
/*-------------------------------------------------------*/
/* Description:                                          */
/* ------------                                          */
/*                                                       */
/* Starting messages:                                    */
/* ------------------                                    */
/*                                                       */
/* Subsequent messages:                                  */
/* --------------------                                  */
/*                                                       */
/* Result messages (input):                              */
/* ------------------------                              */
/*                                                       */
/* Result messages (output):                             */
/* -------------------------                             */
/*                                                       */
/* Reset messages (input):                               */
/* -----------------------                               */
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_transfer_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET       = 0,
    WAIT_MSG    = 1
  };

  UWORD8   *state     = &l1pa.state[TRANSFER];
  UWORD32  SignalCode = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_MSG;

        // Rise transfert parameter semaphore.
        l1pa_l1ps_com.transfer.semaphore = TRUE;
      }
      break;

      case WAIT_MSG:
      {
        switch(SignalCode)
        // switch on input message.
        //-------------------------
        {
          case MPHP_SINGLE_BLOCK_REQ:
          // Repeat fixed allocation.
          //-------------------------
          {
            T_TRANSFER_SET  *free_set;
            UWORD8           purpose;
            UWORD8           i;

            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            purpose = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->purpose;

            // Get Ptr to the free dedicated parameter set.
            // All important fields are initialised.
            free_set = l1pa_get_free_transfer_set(purpose);

            // Fill Transfer mode generic parameters.
            free_set->assignment_id      = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->assignment_id;
            free_set->assignment_command = purpose;
            free_set->allocated_tbf      = purpose;
            free_set->packet_ta          = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->packet_ta;

            if((purpose == SINGLE_BLOCK_DL)||(purpose == SINGLE_BLOCK_UL))
            {
              free_set->packet_ta.ta_index = 255;
              free_set->packet_ta.ta_tn    = 255;
            }

            free_set->dl_pwr_ctl         = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->dl_pwr_ctl;
            if (free_set->dl_pwr_ctl.p0 != 255)
              free_set->dl_pwr_ctl.p0    <<= 2;  // P0 format 7.1
            free_set->tsc                = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->tsc;
            free_set->freq_param         = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->freq_param;
            free_set->tbf_sti            = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->tbf_sti;
            free_set->pc_meas_chan       = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->pc_meas_chan;

            // Download access_burst_type
            l1pa_l1ps_com.transfer.psi_param.access_burst_type    = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->access_burst_type;
            // Keep the same Pb factor
            l1pa_l1ps_com.transfer.psi_param.Scell_pb             = l1a_l1s_com.Scell_info.pb;
            // Enable PSI param updating in order to update access_burst_type in L1S
            l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE;

            // Fill single block specific parameters.
            for(i=0;i<23;i++)
            {
              l1pa_l1ps_com.transfer.single_block.data_array[i] =
                ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->data_array[i];
            }
            l1pa_l1ps_com.transfer.single_block.tn =
              ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->timeslot_number;

            l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore = l1a_l1s_com.dl_tn;

            // Fill "synchro_timeslot" which will be the frame synchro slot.
            free_set->ul_tbf_synchro_timeslot   = l1pa_l1ps_com.transfer.single_block.tn;
            free_set->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.single_block.tn;

            // Step in state machine.
            *state = WAIT_MSG;

            // Store signalcode.
            free_set->SignalCode = MPHP_SINGLE_BLOCK_REQ;

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case MPHP_ASSIGNMENT_REQ:
          // Assignement message.
          //---------------------
          {
            static int count =0;

            T_TRANSFER_SET  *free_set;
            UWORD8           assignment_command;
            UWORD8           timeslot_alloc;
            UWORD8           timeslot;	/* TCS211 reconstruction, =0 in TCS3 */

	// TBF_changes

            #if FF_TBF

              BOOL             pseudo_tbf_two_phase_acc;

              // Special case for two phase access (single or multi allocation):
              // It is handled as a pseudo UL TBF using a fixed allocation.
              // Still needs to be flagged to preempt TBF establishment switch in
              // transfer manager.
              if (((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command == TWO_PHASE_ACCESS)
              {
                ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command = UL_TBF;
                pseudo_tbf_two_phase_acc = TRUE;
              }
              else
                pseudo_tbf_two_phase_acc = FALSE;
            #endif
            count++ ;

            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            assignment_command = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command;

            // Get Ptr to the free dedicated parameter set.
            // All important fields are initialised.
            free_set = l1pa_get_free_transfer_set(assignment_command);

            // Download message containt.
            free_set->assignment_id      = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_id;
            free_set->assignment_command = assignment_command;
            free_set->multislot_class    = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->multislot_class;
            free_set->dl_pwr_ctl         = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_pwr_ctl;
            if (free_set->dl_pwr_ctl.p0 != 255)
              free_set->dl_pwr_ctl.p0    <<= 2;  // P0 format 7.1
            free_set->packet_ta          = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->packet_ta;
            free_set->tsc                = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->tsc;
            free_set->freq_param         = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->freq_param;
            free_set->mac_mode           = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->mac_mode;
            free_set->tbf_sti            = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->tbf_sti;
            free_set->interf_meas_enable = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->interf_meas_enable;
            free_set->pc_meas_chan       = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->pc_meas_chan;

// TBF_changes

            #if FF_TBF
              // Two phase access condition is stored in FSET structure to be
              // transfered in ASET for transfer mode manager use.
              free_set->pseudo_tbf_two_phase_acc = pseudo_tbf_two_phase_acc;
            #endif

            // Download access_burst_type
            l1pa_l1ps_com.transfer.psi_param.access_burst_type    = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->access_burst_type;
            // Keep the same Pb factor
            l1pa_l1ps_com.transfer.psi_param.Scell_pb             = l1a_l1s_com.Scell_info.pb;
            // Enable PSI param updating in order to update access_burst_type in L1S
            l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE;

            switch(assignment_command)
            {
              case DL_TBF:
              {
                free_set->dl_tbf_alloc = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_ressource_alloc;

                if((free_set->allocated_tbf == UL_TBF) ||
                   (free_set->allocated_tbf == BOTH_TBF))
                  free_set->allocated_tbf = BOTH_TBF;
                else
                  free_set->allocated_tbf = DL_TBF;

                // Look for 1st allocated timeslot.
                // MSB=TS0...LSB=TS7
                timeslot_alloc = free_set->dl_tbf_alloc.timeslot_alloc;
                timeslot       = 0;
                while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot)))
                {
                  timeslot++;
                }

                // Fill "synchro_timeslot" which will be the frame synchro slot.
                free_set->dl_tbf_synchro_timeslot   = timeslot;
                free_set->transfer_synchro_timeslot = timeslot;
              }
              break;

              case UL_TBF:
              {
                *(free_set->ul_tbf_alloc) = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->ul_ressource_alloc;

                if((free_set->allocated_tbf == DL_TBF) ||
                   (free_set->allocated_tbf == BOTH_TBF))
                  free_set->allocated_tbf = BOTH_TBF;
                else
                  free_set->allocated_tbf = UL_TBF;

                // Look for 1st allocated timeslot.
                // MSB=TS0...LSB=TS7

                // Dynamic mode: the uplink PDCH are always monitored
                // The 1st allocated timeslot is a RX on the lowest numbered
                // timeslot allocated in uplink
              #if L1_EDA
                if((free_set->mac_mode == DYN_ALLOC) || (free_set->mac_mode == EXT_DYN_ALLOC))
              #else
                if(free_set->mac_mode == DYN_ALLOC)
              #endif
                {
                  timeslot_alloc = free_set->ul_tbf_alloc->timeslot_alloc;

                  timeslot = 0;
                  while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot)))
                  {
                    timeslot++;
                  }
                }
                else

                // Fixed mode: the 1st allocated timeslot is the downlink control
                // timeslot allocated by the network, which is a timeslot allocated
                // in uplink
                if(free_set->mac_mode == FIX_ALLOC_NO_HALF)
                {
                  timeslot = free_set->ul_tbf_alloc->fixed_alloc.ctrl_timeslot;
                }

                // Fill "synchro_timeslot" which will be the frame synchro slot.
                free_set->ul_tbf_synchro_timeslot   = timeslot;
                free_set->transfer_synchro_timeslot = timeslot;
              }
              break;

              case BOTH_TBF:
              {
                free_set->dl_tbf_alloc    = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_ressource_alloc;
                *(free_set->ul_tbf_alloc) = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->ul_ressource_alloc;
                free_set->allocated_tbf   = BOTH_TBF;

                // Process the downlink TBF first allocated timeslot
                timeslot_alloc = free_set->dl_tbf_alloc.timeslot_alloc;
                timeslot       = 0;

                while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot)))
                {
                  timeslot++;
                }

                free_set->dl_tbf_synchro_timeslot   = timeslot;

                // Process the uplink TBF first allocated timeslot

                // Dynamic mode: the uplink PDCH are always monitored
                // The 1st allocated timeslot is a RX on the lowest numbered
                // timeslot allocated in uplink
              #if L1_EDA
                if((free_set->mac_mode == DYN_ALLOC) || (free_set->mac_mode == EXT_DYN_ALLOC))
              #else
                if(free_set->mac_mode == DYN_ALLOC)
              #endif
                {
                  timeslot_alloc = free_set->ul_tbf_alloc->timeslot_alloc;

                  timeslot = 0;
                  while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot)))
                  {
                    timeslot++;
                  }
                }
                else

                // Fixed mode: the 1st allocated timeslot is the downlink control
                // timeslot allocated by the network, which is a timeslot allocated
                // in uplink
                if(free_set->mac_mode == FIX_ALLOC_NO_HALF)
                {
                  timeslot = free_set->ul_tbf_alloc->fixed_alloc.ctrl_timeslot;
                }

                free_set->ul_tbf_synchro_timeslot   = timeslot;

                // Fill "synchro_timeslot" which will be the frame synchro slot.
                if (free_set->dl_tbf_synchro_timeslot > free_set->ul_tbf_synchro_timeslot)
                {
                  free_set->transfer_synchro_timeslot = free_set->ul_tbf_synchro_timeslot;
                }
                else
                {
                  free_set->transfer_synchro_timeslot = free_set->dl_tbf_synchro_timeslot;
                }

              }
              break;
            }

            // Cancel any pending release on the assigned TBF
            if (l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd == TRUE)
            {
              // If pending released TBF = assigned TBF or assigned TBF = BOTH
              if ((assignment_command == l1pa_l1ps_com.transfer.tbf_release_param.released_tbf) ||
                  (assignment_command == BOTH_TBF))
              {
		/*
		 * FreeCalypso TCS211 reconstruction: in the LoCosto version
		 * the call to l1pa_send_tbl_release_con() came first,
		 * but in the TCS211 object it comes after the two
		 * assignments.
		 */

                // Cancel the TBF release order
                l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = FALSE;
                l1pa_l1ps_com.transfer.tbf_release_param.released_tbf    = NO_TBF;

		// Send a "TBF Release confirmation" msg to L3  : CQ 46842
		l1pa_send_tbf_release_con(MPHP_TBF_RELEASE_CON,l1pa_l1ps_com.transfer.tbf_release_param.released_tbf);
              }
              // If BOTH TBF release order pending and no BOTH TBF assigned
              else if (l1pa_l1ps_com.transfer.tbf_release_param.released_tbf == BOTH_TBF)
              {
                // Keep the release of the TBF which is not assigned by this message
                if (assignment_command == DL_TBF)
                  l1pa_l1ps_com.transfer.tbf_release_param.released_tbf    = UL_TBF;
                else
                  l1pa_l1ps_com.transfer.tbf_release_param.released_tbf    = DL_TBF;
              }
            }

            // Step in state machine.
            *state = WAIT_MSG;

            // Store signalcode.
            free_set->SignalCode = MPHP_ASSIGNMENT_REQ;

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_TRANSFER_DONE:
          // Switch to TRANSFER mode has been done. Send a Assignment confirmation
          // msg to L3.
          {
            l1pa_send_confirmation(MPHP_ASSIGNMENT_CON,
                                   ((T_L1P_TRANSFER_DONE *) msg->SigP)->assignment_id);

            // End of process.
            end_process = 1;
          }
          break;

          case MPHP_TBF_RELEASE_REQ:
          // TBF Release.
          //-------------
          {
            UWORD8 i;

            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            // Cumulate with a possible TBF release request received during the same block period
            if (l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd == TRUE)
            {
              if (l1pa_l1ps_com.transfer.tbf_release_param.released_tbf != ((T_MPHP_TBF_RELEASE_REQ *)(msg->SigP))->tbf_type)
              {
                l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = BOTH_TBF;
              }
            }
            else
            {
              // Enables the TBF release processing in L1S.
              l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = TRUE;

              // Download msg info into L1PA_L1PS_COM.
              l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = ((T_MPHP_TBF_RELEASE_REQ *)(msg->SigP))->tbf_type;
            }

            // Disable all pending TBFs those type is the same as the released TBF
            for(i = 0; i < 2; i++)
            {
              // Pending assignment
              if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_ASSIGNMENT_REQ)
              {
              #if !FF_TBF
                switch(l1pa_l1ps_com.transfer.tbf_release_param.released_tbf)
              #else
                UWORD8 released_tbf;

                // Special case if we got a request to release a two phase access TBF:
                // It is registered within FSET structure as an uplink TBF. If current
                // structure is pseudo TBF for two phase access, we process the request
                // like an uplink release, otherwise we skip it.

                released_tbf = l1pa_l1ps_com.transfer.tbf_release_param.released_tbf;

                if (released_tbf == TWO_PHASE_ACCESS)
                {
                  if (l1pa_l1ps_com.transfer.fset[i]->pseudo_tbf_two_phase_acc)
                    released_tbf = UL_TBF;
                  else
                    released_tbf = NO_TBF;
                }

                switch(released_tbf)
              #endif // FF_TBF
                {
                  case UL_TBF:
                  {
                    if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == UL_TBF)
                    {
                      l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF;
                      l1pa_l1ps_com.transfer.fset[i]->SignalCode    = NULL;
                    }
                    if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == BOTH_TBF)
                    {
                      l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = DL_TBF;
                    }
                  } break;

                  case DL_TBF:
                  {
                    if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == DL_TBF)
                    {
                      l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF;
                      l1pa_l1ps_com.transfer.fset[i]->SignalCode    = NULL;
                    }
                    if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == BOTH_TBF)
                    {
                      l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = UL_TBF;
                    }
                  } break;

                  case BOTH_TBF:
                  {
                    l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF;
                    l1pa_l1ps_com.transfer.fset[i]->SignalCode    = NULL;
                  } break;

                } // End of switch "tbf_release"
              } // End if SignalCode = MPHP_ASSIGNMENT_REQ or MPHP_REPEAT_UL_FIXED_ALLOC
            } // End "for"

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_TBF_RELEASED:
          // TBF has been release by L1S. Send a "TBF Release confirmation"
          // msg to L3
          {
            // Send confirmation message to L3.
            l1pa_send_tbf_release_con(MPHP_TBF_RELEASE_CON,((T_L1P_TBF_RELEASED *)(msg->SigP))->tbf_type);

            // End of process.
            end_process = 1;
          }
          break;

          case MPHP_STOP_SINGLE_BLOCK_REQ:
          // Stop SINGLE block activity.
          //----------------------------
          {
            UWORD8 i;

            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            // Disable SINGLE task.
            l1a_l1s_com.l1s_en_task[SINGLE] = TASK_DISABLED;

            // No more TBF...
            // Disable PDTCH task.
            l1a_l1s_com.l1s_en_task[PDTCH] = TASK_DISABLED;

            // Disable PTCCH task.
            l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED;

            // Free the active set.
            l1pa_l1ps_com.transfer.aset->allocated_tbf = NO_TBF;

            // Send confirmation message to L3.
            l1a_send_confirmation(MPHP_STOP_SINGLE_BLOCK_CON,GRRM1_QUEUE);

            // disable all pending TBF those type is a single block
            for(i = 0; i < 2; i++)
            {
              // check for pending single block req (MPHP_SINGLE_BLOCK_REQ)
              if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_SINGLE_BLOCK_REQ)
              {
                // disable the fset corresponding to single blocks
                l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF;
                l1pa_l1ps_com.transfer.fset[i]->SignalCode    = NULL;
              }
            }

            // This process must be reset.
            *state = RESET;

            // end of process.
            end_process = 1;
          }
          break;

          case MPHP_PDCH_RELEASE_REQ:
          // PDCH Release.
          //--------------
          {
            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            // Enables the PDCH release processing in L1S.
            l1pa_l1ps_com.transfer.pdch_release_param.pdch_release_cmd  = TRUE;

            // Download msg info into L1PA_L1PS_COM.
            l1pa_l1ps_com.transfer.pdch_release_param.timeslot_available = ((T_MPHP_PDCH_RELEASE_REQ *)(msg->SigP))->timeslot_available;
            l1pa_l1ps_com.transfer.pdch_release_param.assignment_id      = ((T_MPHP_PDCH_RELEASE_REQ *)(msg->SigP))->assignment_id;

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_PDCH_RELEASED:
          // PDCHs have been release by L1S. Send a "PDCH Release confirmation"
          // msg to L3
          {
            // Send confirmation message to L3.
            l1pa_send_confirmation(MPHP_PDCH_RELEASE_CON,
                                   ((T_L1P_PDCH_RELEASE_CON *) msg->SigP)->assignment_id);

            // End of process.
            end_process = 1;
          }
          break;

          case MPHP_TIMING_ADVANCE_REQ:
          // TA configuration.
          //------------------
          {
            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            // Enables the timing advance update in L1S.
            l1pa_l1ps_com.transfer.ptcch.ta_update_cmd = TRUE;

            // Download message content.
            l1pa_l1ps_com.transfer.ptcch.packet_ta     = ((T_MPHP_TIMING_ADVANCE_REQ *)(msg->SigP))->packet_ta;
            l1pa_l1ps_com.transfer.ptcch.assignment_id = ((T_MPHP_TIMING_ADVANCE_REQ *)(msg->SigP))->assignment_id;

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_TA_CONFIG_DONE:
          // TA configuration done.
          //-----------------------
          {
            // Send confirmation message to L3.
            l1pa_send_confirmation(MPHP_TIMING_ADVANCE_CON,
                                   ((T_MPHP_TIMING_ADVANCE_CON *) msg->SigP)->assignment_id);

            // end of process.
            end_process = 1;
          }
          break;

          case MPHP_UPDATE_PSI_PARAM_REQ:
          // Update PSI Parameters.
          //----------------------
          {
            // Download msg content
            l1pa_l1ps_com.transfer.psi_param.Scell_pb          = ((T_MPHP_UPDATE_PSI_PARAM_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1
            l1pa_l1ps_com.transfer.psi_param.access_burst_type = ((T_MPHP_UPDATE_PSI_PARAM_REQ *)(msg->SigP))->access_burst_type;

            l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE;

            // send confirmation message
            l1a_send_confirmation(MPHP_UPDATE_PSI_PARAM_CON,GRRM1_QUEUE);

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_PACCH_INFO:
          // Two Phase Access is ongoing: Packet Resource Request
          // msg has been sent to the network. CCCH reading must be
          // stopped to let PDCH reading going.
          //--------------------------------------------------------
          {
            // Forward result message to RR.
            l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE);

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_SINGLE_BLOCK_CON:
          // Two Phase Access is ongoing: Packet Resource Request
          // msg has been sent to the network. CCCH reading must be
          // stopped to let PDCH reading going.
          //--------------------------------------------------------
          {
            // Forward result message to RR.
            l1a_send_result(MPHP_SINGLE_BLOCK_CON, msg, GRRM1_QUEUE);

            // This process must be reset.
            *state = RESET;

            // end of process.
            end_process = 1;
          }
          break;

          case MPHP_REPEAT_UL_FIXED_ALLOC_REQ:
          // Repeat uplink fixed mode allocation bitmap
          //-------------------------------------------
          {
            // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
            l1pa_l1ps_com.transfer.semaphore = TRUE;

            // If an UL TBF is running...
            if ((l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) ||
                (l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF))
            {
              // Download info. from message
              l1pa_l1ps_com.transfer.repeat_alloc = *((T_MPHP_REPEAT_UL_FIXED_ALLOC_REQ *) msg->SigP);
            }

            // Send confirmation if this message was a repeat allocation cancelling
            if (!((T_MPHP_REPEAT_UL_FIXED_ALLOC_REQ *) msg->SigP)->repeat_allocation)
            {
              l1a_send_confirmation(MPHP_REPEAT_UL_FIXED_ALLOC_CON,GRRM1_QUEUE);
            }
            else
            {
              UWORD8 i;

              // Disable all pending UL TBF
              for(i = 0; i < 2; i++)
              {
                // Pending assignment
                if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_ASSIGNMENT_REQ)
                {
                  switch(l1pa_l1ps_com.transfer.fset[i]->allocated_tbf)
                  {
                    // Remove pending UL TBF
                    case UL_TBF:
                    {
                        l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF;
                        l1pa_l1ps_com.transfer.fset[i]->SignalCode    = NULL;
                    }
                    break;

                    // Change pending BOTH_TBF in pending DL_TBF
                    case BOTH_TBF:
                    {
                        l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = DL_TBF;
                    }
                    break;

                  } // End of switch "allocated_tbf"
                } // End if SignalCode = MPHP_ASSIGNMENT_REQ
              } // End "for"
            }

            // Clear transfer parameter semaphore to let L1S use the new parameters.
            l1pa_l1ps_com.transfer.semaphore = FALSE;

            // end of process.
            end_process = 1;
          }
          break;

          case L1P_REPEAT_ALLOC_DONE:
          {
            // Send confirmation message to L3.
            l1a_send_confirmation(MPHP_REPEAT_UL_FIXED_ALLOC_CON,GRRM1_QUEUE);

            // end of process.
            end_process = 1;
          }
          break;

          default:
          // End of process.
          //----------------
          {
            return;
          }
        } // end of switch(SignalCode)
      } // end of case WAIT_CONFIG.
    } // end of "switch".
  } // end of "while"
} // end of procedure.

/*-------------------------------------------------------*/
/* l1pa_serving_cell_pbcch_read_process()                */
/*-------------------------------------------------------*/
/* Description : This state machine handles Packet       */
/* serving cell PBCCH reading.                           */
/*                                                       */
/* Starting messages:        MPHP_SCELL_PBCCH_REQ        */
/* ------------------                                    */
/*                                                       */
/*  L1 continuously reads the serving cell PBCCH         */
/*  as requested by the scheduling info (PSI1 repeat     */
/*  period and relative position.                        */
/*                                                       */
/* Result messages (input):  L1C_PBCCHS_INFO             */
/* ------------------------                              */
/*  System information data block from L1S.              */
/*                                                       */
/* Reset messages (input):   MPHP_SCELL_PBCCH_STOP_REQ   */
/* -----------------------                               */
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_serving_cell_pbcch_read_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET              = 0,
    WAIT_PBCCHS_CONFIG = 1,
    WAIT_PBCCHS_RESULT = 2,
    PBCCHS_CONFIG      = 3
  };

  UWORD8  *state      = &l1pa.state[SCPB];
  UWORD32  SignalCode = msg->SignalCode;

  #define  PbcchS  l1pa_l1ps_com.pbcchs

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_PBCCHS_CONFIG;

        // Reset PBCCHS process.
        l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_DISABLED;  // Clear PBCCHS task enable flag.
      }
      break;

      case WAIT_PBCCHS_CONFIG:
      {
        // Request to read Normal BCCH from serving cell.
        if(SignalCode == MPHP_SCELL_PBCCH_REQ)
        {
          #define MAX_PSI1_PERIOD  16

          UWORD8  i;

          // Set semaphores for Serving Cell PBCCH reading task.
          l1a_l1s_com.task_param[PBCCHS] = SEMAPHORE_SET;

          // Download message content.
          //--------------------------
          PbcchS.nbr_psi                 = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->nbr_psi;
          PbcchS.bs_pbcch_blks           = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->bs_pbcch_blks;
          PbcchS.packet_chn_desc         = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->packet_chn_desc;
          PbcchS.frequency_list          = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->frequency_list;
          l1a_l1s_com.Scell_info.pb      = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->pb << 2;  // Pb format 7.1
          PbcchS.psi1_repeat_period      = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->psi1_repeat_period;

          // PBCCH Period is: MF52 * psi1_repeat_period
          PbcchS.pbcch_period = 52L * PbcchS.psi1_repeat_period;

          if(PbcchS.nbr_psi == 0)
          // Full PBCCH reading: Emulated throw "relative positions".
          //---------------------------------------------------------
          {
            // Emulate full PBCCH reading throw "relative positions" and a repeat period
            // of 1 MF52.
            //   bs_pbcch_blks= 0 -> Read B0
            //   bs_pbcch_blks= 1 -> Read B0,B6
            //   bs_pbcch_blks= 2 -> Read B0,B6,B3
            //   bs_pbcch_blks= 3 -> Read B0,B6,B3,B9

            PbcchS.nbr_psi      = PbcchS.bs_pbcch_blks+1;
            PbcchS.read_all_psi = TRUE;

            for(i=0;i<PbcchS.nbr_psi;i++)
            {
              ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->relative_position_array[i] = i;
            }
          }

          else
          // PBCCH reading: use provided "relative positions".
          //--------------------------------------------------
          {
            PbcchS.read_all_psi = FALSE;
          }

          // Compute FN offset for each PSI.
          //--------------------------------
          for(i=0;i<l1pa_l1ps_com.pbcchs.nbr_psi;i++)
          {
            WORD8   nbr_mf52;          // Range 0..MAX_PSI1_PERIOD (can be negative along its estimation)
            UWORD8  nbr_rest;          // Range 0..3
            UWORD8  relative_position; // Range 0..4*MAX_PSI1_PERIOD
            UWORD8  psi_period;        // psi1_repeat_period = 1 if nbr_psi = 0

            relative_position = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->relative_position_array[i];

            nbr_mf52 = relative_position / (PbcchS.bs_pbcch_blks+1);
            nbr_rest = relative_position % (PbcchS.bs_pbcch_blks+1);

            // Block B0 is a special case since CTRL phase occurs during
            // the MF52 before.
            if(nbr_rest == 0)
            {
              nbr_mf52 -= 1;

              // Set psi_period to 1 when all PSI have to be read (nbr_psi = 0)
              if(PbcchS.read_all_psi)
                psi_period = 1;
              else
                psi_period = PbcchS.psi1_repeat_period;

              if(nbr_mf52 < 0)
                nbr_mf52 += psi_period;
            }

            PbcchS.offset_array[i]            = (nbr_mf52 * 52L) + PBCCH_POSITION[PbcchS.bs_pbcch_blks][nbr_rest];
            PbcchS.relative_position_array[i] = relative_position;
          }

          // Step in state machine.
          *state = PBCCHS_CONFIG;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process.
          return;
        }
      }
      break;

      case PBCCHS_CONFIG:
      {
        WORD8   tn_pbcch;

        // If PBCCH TS is inferior to L1 synchronization TS, the PBCCH reading
        // control must be done one frame in advance
        if (PbcchS.packet_chn_desc.timeslot_no < l1a_l1s_com.dl_tn)
          PbcchS.control_offset = TRUE;
        else
          PbcchS.control_offset = FALSE;

        // Set "change_synchro" flag to trigger L1S to change the synchro on fly
        // within PBCCHS and to restore current synchro when PBCCHS task is completed.
        if(((PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn + 8) % 8) >=4)
        {
          // L1S will make a intra PBCCHS task synchro to current TS + 4.
          PbcchS.change_synchro = TRUE;
          tn_pbcch              = PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn - 4;
        }
        else
        {
          // L1S will NOT make the intra PBCCHS task synchro.
          PbcchS.change_synchro = FALSE;
          tn_pbcch              = PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn;
        }

        if(tn_pbcch < 0)
          PbcchS.tn_pbcch = tn_pbcch + 8;
        else
          PbcchS.tn_pbcch = tn_pbcch;

        // Enable PBCCHS task.
        l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_ENABLED;


        // Step in state machine.
        *state = WAIT_PBCCHS_RESULT;

        // End of process.
        end_process = 1;
      }
      break;

      case WAIT_PBCCHS_RESULT:
      {
        if(SignalCode == L1P_PBCCHS_INFO)
        // Serving cell BCCH reading result.
        //----------------------------------
        {
          // Forward result message to L3.
          l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE);

          // End of process.
          return;
        }

        else
        if(SignalCode == MPHP_SCELL_PBCCH_REQ)
        // Request to re-configure PBCCH reading.
        //--------------------------------------
        {
          // Step in state machine.
          *state = WAIT_PBCCHS_CONFIG;
        }

        else
        if(SignalCode == MPHP_SCELL_PBCCH_STOP_REQ)
        // Request to STOP any serving cell pbcch activity.
        //------------------------------------------------
        {
          // Send confirmation message to L3.
          l1a_send_confirmation(MPHP_SCELL_PBCCH_STOP_CON,GRRM1_QUEUE);

          // This process must be reset.
          *state = RESET;
        }

        else
        // End of packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released
        if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))
        {
           // This process must be reset.
          *state = RESET;
        }

        else
        if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_TBF_RELEASED) ||           //change of Time Slot
            (SignalCode  == L1P_REPEAT_ALLOC_DONE) || (SignalCode == L1P_ALLOC_EXHAUST_DONE))
        {
          // Clear PBCCHS  task enable flag.
          l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_DISABLED;

          // Set semaphores for Serving Cell PBCCH reading task.
          l1a_l1s_com.task_param[PBCCHS] = SEMAPHORE_SET;

          // l1a_l1s_com.dl_tn was changed. Check if a change synchro is needed
          *state = PBCCHS_CONFIG; // Step in state machine.
        }

        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          return;
        }
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.


/*-------------------------------------------------------*/
/* l1pa_neighbor_cell_pbcch_read_process()                */
/*-------------------------------------------------------*/
/* Description : This state machine handles Packet       */
/* neighbor cell PBCCH reading.                           */
/*                                                       */
/* Starting messages:        MPHP_NCELL_PBCCH_REQ        */
/* ------------------                                    */
/*                                                       */
/*  L1 continuously reads the neighbor cell PBCCH        */
/*  as requested by the scheduling info (PSI1 repeat     */
/*  period and relative position.                        */
/*                                                       */
/* Result messages (input):  L1C_PBCCHN_INFO             */
/* ------------------------                              */
/*  System information data block from L1S.              */
/*                                                       */
/* Reset messages (input):   MPHP_NCELL_PBCCH_STOP_REQ   */
/* -----------------------                               */
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_neighbor_cell_pbcch_read_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET              = 0,
    WAIT_PBCCHN_CONFIG = 1,
    WAIT_PBCCHN_RESULT = 2,
    PBCCHN_CONFIG      = 3
  };

  UWORD8  *state      = &l1pa.state[NCPB];
  UWORD32  SignalCode = msg->SignalCode;

  #define  PbcchN  l1pa_l1ps_com.pbcchn

  static  WORD32  fn_offset_mem;
  static  WORD32  time_alignmt_mem;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_PBCCHN_CONFIG;

        // Reset PBCCHS process.
        l1a_l1s_com.l1s_en_task[PBCCHN_IDLE] = TASK_DISABLED;  // Clear PBCCHN task enable flag used in IDLE mode
        l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_DISABLED;  // Clear PBCCHN task enable flag used in Transfer Packet mode
      }
      break;

      case WAIT_PBCCHN_CONFIG:
      {
        // Request to read Normal PBCCH from neighbor cell.
        if(SignalCode == MPHP_NCELL_PBCCH_REQ)
        {
          #define MAX_PSI1_PERIOD  16

          // Set semaphores for Neighbor Cell PBCCH reading task.
          l1a_l1s_com.task_param[PBCCHN_IDLE] = SEMAPHORE_SET;
          l1a_l1s_com.task_param[PBCCHN_TRAN] = SEMAPHORE_SET;

          // Download message content.
          //--------------------------
          PbcchN.bcch_carrier       = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->bcch_carrier;
          PbcchN.bs_pbcch_blks      = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->bs_pbcch_blks;
          PbcchN.packet_chn_desc    = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->packet_chn_desc;
          PbcchN.frequency_list     = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->frequency_list;
          PbcchN.psi1_repeat_period = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->psi1_repeat_period;
          PbcchN.relative_position  = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->relative_position;
          fn_offset_mem             = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->fn_offset;
          time_alignmt_mem          = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->time_alignment;
          PbcchN.pb                 = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->pb  << 2; // Pb format 7.1

          // PBCCH Period is: MF52 * psi1_repeat_period
          PbcchN.pbcch_period = 52L * PbcchN.psi1_repeat_period;

          // Compute FN offset.
          //------------------
          {
            WORD8   nbr_mf52;          // Range 0..MAX_PSI1_PERIOD (can be negative along its estimation)
            UWORD8  nbr_rest;          // Range 0..3
            UWORD8  relative_position; // Range 0..4*MAX_PSI1_PERIOD

            relative_position = PbcchN.relative_position;

            // number of PBCCH blocs
            nbr_mf52 = relative_position / (PbcchN.bs_pbcch_blks+1);
            nbr_rest = relative_position % (PbcchN.bs_pbcch_blks+1);

            // Block B0 is a special case since CTRL phase occurs during the MF52 before.
            if(nbr_rest == 0)
            {
              nbr_mf52 -= 1;

              if(nbr_mf52 < 0)
                nbr_mf52 += PbcchN.psi1_repeat_period;
            }

            PbcchN.offset = (nbr_mf52 * 52L) + PBCCH_POSITION[PbcchN.bs_pbcch_blks][nbr_rest];

            // In case of idle mode
            if (l1a_l1s_com.mode != PACKET_TRANSFER_MODE)
            {
              PbcchN.offset -= 2 ;  // because of the 2 frames for the measurement windows
              // note: PbcchN.offset can not be negative (PbcchN.offset > 12).
            }
          }
          // Step in state machine.
          *state = PBCCHN_CONFIG;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process.
          return;
        }
      }
      break;

      case PBCCHN_CONFIG:
      {
         //==================================================================================
         // choose a relative base time in the neighbor cell in order to simplify the L1S scheduling.
         //==================================================================================
         PbcchN.fn_offset    = fn_offset_mem;
         PbcchN.time_alignmt = time_alignmt_mem;

         //the new relative base time is set in order to have the Neighbor burst in position 0.
         //update with the burts position of the neighor cell     : PbcchN.packet_chn_desc.timeslot_no
         //update according to the current serving cell synchro   : l1a_l1s_com.dl_tn
         PbcchN.time_alignmt += (PbcchN.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn ) * TN_WIDTH;

         // PbcchN.time_alignmt is in [-7TS..+16TS[.
         // more than 1 frame between the serving cell and the neighbor burst
         if ( PbcchN.time_alignmt >= 8*TN_WIDTH)
         {
           PbcchN.time_alignmt -= 8*TN_WIDTH;
           PbcchN.fn_offset --;
         }
         else
         if ( PbcchN.time_alignmt < 0)
         {
           PbcchN.time_alignmt += 8*TN_WIDTH;
           PbcchN.fn_offset ++;
         }

         // Set "change_synchro" flag to trigger L1S to change the synchro on fly
         // within PBCCHN and to restore current synchro when PBCCHN task is completed.
         if (PbcchN.time_alignmt >= 4 * TN_WIDTH)
         {
           PbcchN.time_alignmt -= 4 * TN_WIDTH;
           PbcchN.change_synchro = TRUE;
         }
         else
           PbcchN.change_synchro = FALSE;

         // In case of packet transfer mode
         if (l1a_l1s_com.mode == PACKET_TRANSFER_MODE)
         {
           // Enable Packet Transfer PBCCHN task
           l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_ENABLED;

         }
         // in case of Idle mode
         else
         {
           // Enable IDLE PBCCHN task
           l1a_l1s_com.l1s_en_task[PBCCHN_IDLE] = TASK_ENABLED;
         }

         // Step in state machine.
         *state = WAIT_PBCCHN_RESULT;

         // End of process.
         end_process = 1;
      }
      break;

      case WAIT_PBCCHN_RESULT:
      {
        if(SignalCode == L1P_PBCCHN_INFO)
        // Serving cell BCCH reading result.
        //----------------------------------
        {
          // Forward result message to L3.
         l1a_send_result(MPHP_NCELL_PBCCH_IND, msg, GRRM1_QUEUE);

          // This process must be reset.
          *state = RESET;
        }

        else
        if(SignalCode == MPHP_NCELL_PBCCH_REQ)
        // Request to re-configure PBCCH reading.
        //--------------------------------------
        {
          // Step in state machine.
          *state = WAIT_PBCCHN_CONFIG;
        }

        else
        if(SignalCode == MPHP_NCELL_PBCCH_STOP_REQ)
        // Request to STOP any serving cell pbcch activity.
        //------------------------------------------------
        {
          // Send confirmation message to L3.
          l1a_send_confirmation(MPHP_NCELL_PBCCH_STOP_CON,GRRM1_QUEUE);

          // This process must be reset.
          *state = RESET;
        }
        else
        // End of packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released
        if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))
        {
           // This process must be reset.
          *state = RESET;
        }
        else
        if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_TBF_RELEASED) ||          //change of Time Slot
            (SignalCode  == L1P_REPEAT_ALLOC_DONE) || (SignalCode == L1P_ALLOC_EXHAUST_DONE))
        {
          // We consider only the case: packet Transfer => packet Transfer,the serving TS may be changed
          // For other cases such as Idle -> Transfer... decision not yet taken.

          // update the PBCCHN parameters
          // Clear PBCCHN_TRAN task disable flag.
          l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_DISABLED;

          // Set semaphores for Neighbor Cell PBCCH reading task.
          l1a_l1s_com.task_param[PBCCHN_TRAN] = SEMAPHORE_SET;

          // update the PBCCHN parameters
          *state = PBCCHN_CONFIG;// Step in state machine.
        }
        else
        // No action in this machine for other messages.
        //----------------------------------------------
        {
          // End of process.
          return;
        }
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.



/*-------------------------------------------------------*/
/* l1pa_tcr_meas_process()                               */
/*-------------------------------------------------------*/
/* Description : This state machine handles Neigbor cell */
/* measurement process in Packet Transfer mode.          */
/* Measurement are made on a specified frequency list.   */
/* The process is started automatically by L1 (on receipt*/
/* of a L1P_TRANSFER_DONE message from L1S) and doesn't  */
/* need to receive any message from L3.                  */
/* In order to update the frequency list, a              */
/* MHPC_TCR_MEAS_REQ msg will be sent from L3 to L1      */
/*                                                       */
/* Starting messages:        L1P_TRANSFER_DONE           */
/* ------------------                                    */
/*  L1 starts then measures on carriers specified in the */
/*  frequency list. Measures are performed on every      */
/*  frames with the occurence of 1 measure per frame     */
/*                                                       */
/* Subsequent messages:      MPHP_TCR_MEAS_REQ           */
/* --------------------                                  */
/*  The update is not done asap but postponed until the  */
/*  end of the reporting period. Frequency list is       */
/*  updated with the new list.                           */
/*                                                       */
/* Result messages (input):  L1P_TRANSFER_MEAS_DONE      */
/* ------------------------                              */
/*  This is the periodic reporting message sent by L1S.  */
/*  The reporting is done every "reporting period".      */
/*  The beguining of the reporting period is arbitrary   */
/*  and starts when the Neigh Meas task is enabled.      */
/*                                                       */
/* Result messages (output): MPHP_TCR_MEAS_IND           */
/* -------------------------                             */
/*  This is the periodic reporting message to L3.        */
/*                                                       */
/* Reset messages (input):   MPHP_TCR_MEAS_STOP_REQ      */
/* -----------------------                               */
/*  Frequency list neigbor cell measurement process in   */
/*  Packet Transfer mode is stopped by this message.     */
/*                                                       */
/*-------------------------------------------------------*/
void l1pa_tcr_meas_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET       = 0,
    WAIT_INIT   = 1,
    WAIT_RESULT = 3

  };

  UWORD8            *state      = &l1pa.state[TCR_MEAS];
  UWORD32           SignalCode  = msg->SignalCode;
  UWORD8            i;
  UWORD8            list_size;
  T_CRES_LIST_PARAM *free_list;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // step in state machine.
        *state = WAIT_INIT;

        // Reset TCR_MEAS process.
        l1pa_l1ps_com.l1ps_en_meas &= P_TCRMS_MEAS_MASK; // Disable Neighbour Measurement task.
      }
      break;

      case WAIT_INIT:
      {
        if(SignalCode == L1P_TRANSFER_DONE)
        // We enter in Packet Transfer mode.
        //---------------------------------
        {
#if 0	/* FreeCalypso: the following code is not present in TCS211 */
        #if (CODE_VERSION != SIMULATION)
          //no meas when entering in Transfer if no BA list initialized
          //stay in this state and wait for a MPHP_TCR_MEAS_REQ from L3
          if((l1pa_l1ps_com.cres_freq_list.alist->nb_carrier == 0) &&
             (l1pa_l1ps_com.tcr_freq_list.new_list_present == FALSE) && (l1a_l1s_com.ba_list.nbr_carrier == 0))
            return;
        #endif
#endif
          // Set parameter synchro semaphore for P_TCRMS_MEAS task.
          l1pa_l1ps_com.meas_param |= P_TCRMS_MEAS;

          // Reset Neighbour Cell measurement parameters.
          l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl        = 0;
          l1pa_l1ps_com.tcr_freq_list.tcr_next_to_read        = 0;
          l1pa_l1ps_com.tcr_freq_list.last_stored_tcr_to_read = 0;
          l1pa_l1ps_com.tcr_freq_list.first_pass_flag  = TRUE;

          // Initialize counter used to report measurements
          l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0;


          // If no Packet Idle phase has been done and no BA(GPRS) list has been
          // downloaded, init BA(GPRS) list with BA list used in CS Idle mode.
          if((l1pa_l1ps_com.cres_freq_list.alist->nb_carrier == 0) &&
             (l1pa_l1ps_com.tcr_freq_list.new_list_present == FALSE))
          {
            // Get Ptr to the free Neighbour meas list.
            // The number of carriers in the list and the list
            // identification are initialized.
            free_list = l1pa_get_free_cres_list_set();

            // Download new list within T_CRES_LIST_PARAM structure.
            free_list->nb_carrier = l1a_l1s_com.ba_list.nbr_carrier;

            for(i = 0; i < free_list->nb_carrier; i++)
            {
              free_list->freq_list[i] = l1a_l1s_com.ba_list.A[i].radio_freq;
            }

            free_list->list_id = l1a_l1s_com.ba_list.ba_id;

            // Set "flist" with Circuit Swithed BA frequency list parameters
            l1pa_l1ps_com.cres_freq_list.alist = free_list;
          }

          // Reset flags.
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl      = 0;
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d    = 0;
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd   = 0;

          // Reset measures made on beacon frequency.
          l1pa_l1ps_com.tcr_freq_list.beacon_meas  = 0;

          // Enable Packet Transfer Neighbour Measurement task.
          l1pa.l1pa_en_meas[TCR_MEAS] |= P_TCRMS_MEAS;

          // step in state machine.
          *state = WAIT_RESULT;
        }
        else
        if(SignalCode == MPHC_RXLEV_PERIODIC_REQ)
        // We receive the BA list to be monitored in Idle mode
        //----------------------------------------------------
        {
          // When enter in Transfer the Idle list must be used
          // =>reset the packet Transfert list in order to use the Idle list
          l1pa_l1ps_com.cres_freq_list.alist->nb_carrier = 0;
          l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE;
        }
#if 0	/* FreeCalypso: the following code is not present in TCS211 */
        else
        if(SignalCode == MPHP_TCR_MEAS_REQ)
        // Restart Packet Transfer measurement in TBF after
        // MPHP_TCR_MEAS_STOP_REQ
        // ### Check reason why was missing (s921_bis note)...
        //----------------------------------------------------
        {

          // Set parameter synchro semaphore for P_TCRMS_MEAS task.
          l1pa_l1ps_com.meas_param |= P_TCRMS_MEAS;

          free_list = l1pa_get_free_cres_list_set();


          // Download new list within T_CRES_LIST_PARAM structure.
          free_list->nb_carrier = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->nb_carrier;

          for(i = 0; i < free_list->nb_carrier; i++)
          {
            free_list->freq_list[i] = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i];
          }

          free_list->list_id    = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->list_id;

          // Set "flist" with Circuit Swithed BA frequency list parameters
          l1pa_l1ps_com.cres_freq_list.alist = free_list;

          // Reset Neighbour Cell measurement parameters.
          l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl        = 0;
          l1pa_l1ps_com.tcr_freq_list.tcr_next_to_read        = 0;
          l1pa_l1ps_com.tcr_freq_list.last_stored_tcr_to_read = 0;
          l1pa_l1ps_com.tcr_freq_list.first_pass_flag  = TRUE;

          // Initialize counter used to report measurements
          l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0;

          // Reset flags.
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl      = 0;
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d    = 0;
          l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd   = 0;

          // Reset measures made on beacon frequency.
          l1pa_l1ps_com.tcr_freq_list.beacon_meas  = 0;

          // Enable Packet Transfer Neighbour Measurement task.
          l1pa.l1pa_en_meas[TCR_MEAS] |= P_TCRMS_MEAS;

          // step in state machine.
          *state = WAIT_RESULT;
        }
#endif

        // End of process.
        end_process = 1;
      }
      break;

      case WAIT_RESULT:
      {
        switch(SignalCode)
        {
          case L1P_TCR_MEAS_DONE:
          // One reporting period has been completed. A set of measures is forward to L3.
          //-----------------------------------------------------------------------------
          {
            // Forward result message to L3.
            l1a_send_result(MPHP_TCR_MEAS_IND, msg, GRRM1_QUEUE);

            // End of process.
            end_process = 1;
          }
          break;

          case MPHP_TCR_MEAS_REQ:
          // Update of the parameters are postponed until end of the reporting period.
          // Parameters are saved in a double buffer.
          {
            // Reset present flag to avoid to mix 2 updates in case of
            // an update already pending within "l1pa_l1ps_com.cres_freq_list.flist".
            l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE;

            // Get Ptr to the free Neighbour meas list.
            // The number of carriers in the list and the list
            // identification are initialized.
            free_list = l1pa_get_free_cres_list_set();


            // Download new list within T_CRES_LIST_PARAM structure.
            list_size             = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->nb_carrier;
            free_list->nb_carrier = list_size;

            for(i = 0; i < list_size; i++)
            {
              free_list->freq_list[i] = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i];
            }

            free_list->list_id    = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->list_id;

            // Set "flist" with new set of frequency list parameter
            l1pa_l1ps_com.cres_freq_list.flist = free_list;

            // Set present flag only when the list has been downloaded.
            l1pa_l1ps_com.tcr_freq_list.new_list_present = TRUE;

            // End of process.
            end_process = 1;
          }
          break;

          case L1P_TBF_RELEASED:
          {
            // Test if all TBF have been released
            // Then stop Neighbour Measurement process
            if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)
            {
              // This process must be reset.
              *state = RESET;
            }
            else
            {
              return;
            }
          }
          break;

          case MPHP_TCR_MEAS_STOP_REQ:
          // Note: A TBF stop do not imply a stop of the Neighbour Measurement process.
          // L3 has to send a MPHP_TCR_MEAS_STOP message to stop the measurement process.
          {
            // send confirmation message
            l1a_send_confirmation(MPHP_TCR_MEAS_STOP_CON,GRRM1_QUEUE);

            // This process must be reset.
            *state = RESET;
          }
          break;

          default:
          // No action in this machine for other messages.
          // Note: No action is performed on receipt of a L1P_TRANSFER_DONE
          // message. However a SYNCHRO task is programmed, which implies
          // a reset of measures related to the Serving Cell (cf. L1S).
          //--------------------------------------------------------------
          {
            return;
          }
        } // end of switch(SignalCode)
      }
      break;
    } // end of "switch".
  } // end of "while"
} // end of procedure.

/*-------------------------------------------------------*/
/* l1pa_idle_interference_meas_process()                 */
/*-------------------------------------------------------*/
/* Description :                                         */
/*                                                       */
/* Starting messages:        MPHP_INT_MEAS_REQ           */
/*                                                       */
/* This message requests signal strength measurements    */
/* on several channels of a specific carrier.            */
/* Measurements must be done on one search frame and one */
/* PTCCH frame.                                          */
/*                                                       */
/* Result messages (input):  L1PS_ITMEAS_IND             */
/*                                                       */
/* This message is reported to L1A when signal strength  */
/* has been measured on one idle frame (PTCCH or search) */
/*                                                       */
/* Result messages (output): MPHP_INT_MEAS_IND           */
/*                                                       */
/* This message is reported to L3 when measurements have */
/* been done on two contiguous idle frames               */
/*                                                       */
/* Reset message (input):    MPHP_INT_MEAS_STOP_REQ      */
/*                                                       */
/* Interference measurement processing is stopped by     */
/* this message                                          */
/*-------------------------------------------------------*/
void l1pa_idle_interference_meas_process(xSignalHeaderRec *msg)
{
  enum states
  {
    RESET             = 0,
    WAIT_INIT         = 1,
    WAIT_1ST_RESULT   = 2,
    WAIT_2ND_RESULT   = 3
  };

  static   T_L1A_INT_MEAS_PARAM int_meas_param;
  UWORD8   *state      = &l1pa.state[PI_INT_MEAS];
  UWORD32  SignalCode  = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_INIT;

        // Reset ITMEAS process.
        l1a_l1s_com.l1s_en_task[ITMEAS]    = TASK_DISABLED;  // Clear ITMEAS task enable flag.
      }
      break;

      case WAIT_INIT:
      {
        // Interference measurement request
        //---------------------------------
        if (SignalCode == MPHP_INT_MEAS_REQ)
        {
          UWORD8 bitmap,i;

          // Set semaphore
          l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET;

          // Download message content
          l1pa_l1ps_com.itmeas.packet_intm_freq_param  = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->packet_intm_freq_param;
          l1pa_l1ps_com.itmeas.multislot_class         = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->multislot_class;
          int_meas_param.id                           = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->carrier_id;

          // Processing of the 2 possible measurement bitmaps
          //-------------------------------------------------

          // 1- Without Rx on the frame before

          l1pa_l1ps_com.itmeas.idle_tn_no_rx = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->tn;

          // Trb respect after measurements
          // We consider that the timeslot on which the Layer 1 is synchronized is
          // always allocated on the frame after the idle frame.
          // For the Trb multi-slot class parameter respect, we must clear the bits at
          // the right of the interference measurement bitmap
          l1pa_l1ps_com.itmeas.idle_tn_no_rx &= (UWORD8)
                           ~(   0xFF
                             >> (  8 + l1a_l1s_com.dl_tn
                                 - MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb));

          // 2- With a Rx programmed on the frame before
          // Note: This Rx is always on the dl_tn

          l1pa_l1ps_com.itmeas.idle_tn_rx = l1pa_l1ps_com.itmeas.idle_tn_no_rx;

          // Trb respect before measurements
          // The timeslot on which the Layer 1 is synchronized is allocated on the frame
          // before the idle frame.
          // For the Trb multi-slot class parameter respect, we must clear the bits at
          // the left of the interference measurement bitmap
          bitmap = 0x80;

          i = 8 - l1a_l1s_com.dl_tn - MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb;
          if (i > 8)
            bitmap >>= (-i);
          else
            bitmap <<= i;

          for (i = 1; i<= MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb; i++)
          {
            l1pa_l1ps_com.itmeas.idle_tn_rx &= (UWORD8) ~bitmap;
            bitmap <<= 1;
          }

          // Initialize parameters
          l1pa_l1ps_com.itmeas.position        = ANY_IDLE_FRAME;  // First measurement on any idle frame

          // Enable synchronous task
          l1a_l1s_com.l1s_en_task[ITMEAS]      = TASK_ENABLED;

          // Step in state machine
          *state = WAIT_1ST_RESULT;

          // End of process
          end_process = 1;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process.
          end_process = 1;
        }
      }
      break;

      case WAIT_1ST_RESULT:
      {
        // Reporting of 1st measurement session
        //-------------------------------------
        if (SignalCode == L1P_ITMEAS_IND)
        {
          UWORD8  i;

          // Set semaphore
          l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET;

          // Save interference measurements
          for(i=0; i<8; i++)
            int_meas_param.rxlev[i]  = ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i];

          // Save bitmap
          int_meas_param.meas_bitmap = ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap;

           // Save reported fn
          int_meas_param.fn          = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn;

          // Position = complement of reported position
          if (((T_L1P_ITMEAS_IND *)(msg->SigP))->position == PTCCH_FRAME)
            l1pa_l1ps_com.itmeas.position = SEARCH_FRAME;
          else
            l1pa_l1ps_com.itmeas.position = PTCCH_FRAME;

            // Enable ITMEAS
            l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED;

          // Step in state machine
          *state = WAIT_2ND_RESULT;

          // End of process
          return;
        }

          else
        if (SignalCode == MPHP_INT_MEAS_STOP_REQ)
          {
          // Send confirmation
          l1a_send_confirmation(MPHP_INT_MEAS_STOP_CON,GRRM1_QUEUE);

          // Reset process
          *state = RESET;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process
          return;
        }
      }
      break;

      case WAIT_2ND_RESULT:
      {
        // Reporting subsequent measurement session
        //-----------------------------------------
        if (SignalCode == L1P_ITMEAS_IND)
        {
          // At least one measurement session has already been reported
          //-----------------------------------------------------------
          UWORD32 reported_fn;

          // Check fn
          // The two measurement sessions must be done in two contiguous idle frames

          // Modulo
          if (((T_L1P_ITMEAS_IND *)(msg->SigP))->fn < int_meas_param.fn)
          {
            reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn + MAX_FN;
          }
          else
          {
            reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn;
          }

          // The two last measurement sessions are enough close
          if ((reported_fn - int_meas_param.fn) == 13)
          {
            // Build and send result msg to L3.
            l1pa_send_int_meas_report(MPHP_INT_MEAS_IND,
                                      ((T_L1P_ITMEAS_IND *)(msg->SigP)),
                                      &int_meas_param);

            // Only one measurement session per request
            *state = RESET;
          }

          // The two last measurement sessions aren't enough close
          else
          {
            // 1st measurement result is no more valid, second result
            // must replace it: this is achieved by WAIT_1ST_RESULT state!!!

            // Step in state machine
            *state = WAIT_1ST_RESULT;
          }
        }

        else
        if (SignalCode == MPHP_INT_MEAS_STOP_REQ)
        {
          // Send confirmation
          l1a_send_confirmation(MPHP_INT_MEAS_STOP_CON,GRRM1_QUEUE);

          // Reset process
          *state = RESET;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process
          return;
        }
      }
      break;

    } // End of "switch"
  } // End of "while"
} // End of "procedure"

/*-------------------------------------------------------*/
/* l1pa_transfer_interference_meas_process()             */
/*-------------------------------------------------------*/
/* Description :                                         */
/*                                                       */
/* Starting messages:        L1P_TRANFSER_DONE           */
/*                                                       */
/* Interference measurement processing starts each time  */
/* a new starting time occurs if the interference        */
/* measurements are enabled                              */
/* Measurements must be done on one search frame and one */
/* PTCCH frame.                                          */
/*                                                       */
/* Result messages (input):  L1PS_ITMEAS_IND             */
/*                                                       */
/* This message is reported to L1A when signal strength  */
/* has been measured on one idle frame (PTCCH or search) */
/*                                                       */
/* Result messages (output): MPHP_TINT_MEAS_IND          */
/*                                                       */
/* This message is reported to L3 when measurements have */
/* been done on two idle frames as close as possible     */
/*                                                       */
/* Reset message (input):    L1P_TBF_RELEASED            */
/*                                                       */
/* Interference measurement processing is stopped when   */
/* all TBF are released                                  */
/*-------------------------------------------------------*/
void l1pa_transfer_interference_meas_process(xSignalHeaderRec *msg)
{
  /* Bitmaps used for the processing of full_allocation */
  /*----------------------------------------------------*/
  const UWORD8 FULL_ALLOCATION[9]=
{
    0x00,
    0x80,
    0xc0,
    0xe0,
    0xf0,
    0xf8,
    0xfc,
    0xfe,
    0xff
  };

  enum states
  {
    RESET             = 0,
    WAIT_INIT         = 1,
    CONFIG            = 2,
    WAIT_1ST_RESULT   = 3,
    WAIT_2ND_RESULT   = 4
  };

  static   T_L1A_INT_MEAS_PARAM int_meas_param;
  UWORD8   *state      = &l1pa.state[PT_INT_MEAS];
  UWORD32  SignalCode  = msg->SignalCode;

  BOOL end_process = 0;
  while(!end_process)
  {
    switch(*state)
    {
      case RESET:
      {
        // Step in state machine.
        *state = WAIT_INIT;

        // Reset ITMEAS process.
        l1a_l1s_com.l1s_en_task[ITMEAS]    = TASK_DISABLED;  // Clear ITMEAS task enable flag.
      }
      break;

      case WAIT_INIT:
      {
        // New channel assignment
        //-----------------------
        if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) ||
            (SignalCode == L1P_ALLOC_EXHAUST_DONE))
        {
          *state = CONFIG;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process.
          return;
        }
      }
      break;

      case CONFIG:
      {
        // Rise transfert parameter semaphore to prevent L1S to use partial configuration.
        l1pa_l1ps_com.transfer.semaphore = TRUE;

        // If the interference measurements are disabled
        if (l1pa_l1ps_com.transfer.aset->interf_meas_enable == FALSE)
        {
          *state = WAIT_INIT;
        }
        else
        {
          // Set semaphore
          l1a_l1s_com.task_param[ITMEAS]   = SEMAPHORE_SET;

          // Initialize parameters
          l1pa_l1ps_com.itmeas.position    = ANY_IDLE_FRAME;  // First measurement on any idle frame

          // Save assignment ID for the interference measurements reporting message
          int_meas_param.id = l1pa_l1ps_com.transfer.aset->assignment_id;

          // Processing of the measurement bitmap
          l1pa_l1ps_com.itmeas.meas_bitmap = (UWORD8)
               FULL_ALLOCATION[MS_CLASS[l1pa_l1ps_com.transfer.aset->multislot_class].rx] >>
               l1a_l1s_com.dl_tn;

          // Enable synchronous task
          l1a_l1s_com.l1s_en_task[ITMEAS]  = TASK_ENABLED;

          // Step in state machine
          *state = WAIT_1ST_RESULT;
        }

        // Clear transfer parameter semaphore to let L1S use the new parameters.
        l1pa_l1ps_com.transfer.semaphore = FALSE;

        // End of process.
        end_process = 1;
      }
      break;

      case WAIT_1ST_RESULT:
      {
        // Reporting of 1st measurement session
        //-------------------------------------
        if (SignalCode == L1P_ITMEAS_IND)
        {
          UWORD8  i;

          // Set semaphore
          l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET;

          // Save interference measurements
          for(i=0; i<8; i++)
            int_meas_param.rxlev[i]  = ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i];

          // Save bitmap
          int_meas_param.meas_bitmap = ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap;

            // Save reported fn
          int_meas_param.fn          = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn;

          // Position = complement of reported position
          if (((T_L1P_ITMEAS_IND *)(msg->SigP))->position == PTCCH_FRAME)
            l1pa_l1ps_com.itmeas.position = SEARCH_FRAME;
          else
            l1pa_l1ps_com.itmeas.position = PTCCH_FRAME;

            // Enable ITMEAS
            l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED;

          // Step in state machine
          *state = WAIT_2ND_RESULT;

            // End of process
            return;
        }

        else
        if (SignalCode == L1P_TRANSFER_DONE)
        // The starting time of a new TBF occurs
        {
          // Reset process
          *state = RESET;
        }

        else
        if (SignalCode == L1P_TBF_RELEASED)
        // A TBF has been released
        {
          // No remaining TBF
          if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)
          {
            // Reset process
            *state = RESET;
          }
          else
          {
            // Enable a new measurement session
            *state = CONFIG;
          }
        }

        else
        if (SignalCode == L1P_PDCH_RELEASED)
        // PDCH have been released
        {
          // Enable a new measurement session
          *state = CONFIG;
        }

        // No action in this machine for other messages.
          else
          {
          // End of process
          return;
        }
      }
      break;

      case WAIT_2ND_RESULT:
      {
        // Reporting subsequent measurement session
        //-----------------------------------------
        if (SignalCode == L1P_ITMEAS_IND)
        {
          // At least one measurement session has already been reported
          //-----------------------------------------------------------
          UWORD32 reported_fn;

          // Check fn
          // The two measurement sessions must be done in two contiguous idle frames

          // Modulo
          if (((T_L1P_ITMEAS_IND *)(msg->SigP))->fn < int_meas_param.fn)
          {
            reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn + MAX_FN;
          }
          else
          {
            reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn;
          }

            // The two last measurement sessions are enough close
          if ((reported_fn - int_meas_param.fn) <= 104)
          {
            // Build and send result msg to L3.
            l1pa_send_int_meas_report(MPHP_TINT_MEAS_IND,
                                      ((T_L1P_ITMEAS_IND *)(msg->SigP)),
                                      &int_meas_param);

              // Enable a new measurement session
              *state = CONFIG;
          }

          // The two last measurement sessions aren't enough close
          else
          {
            // 1st measurement result is no more valid, second result
            // must replace it: this is achieved by WAIT_1ST_RESULT state!!!

            // Step in state machine
            *state = WAIT_1ST_RESULT;
          }
        }

        else

        // New channel assignment
        //-----------------------
        if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) ||
            (SignalCode == L1P_ALLOC_EXHAUST_DONE))
        {
          // Reset process
          *state = RESET;
        }

        else
        if (SignalCode == L1P_TBF_RELEASED)
        // A TBF has been released
        {
          // No remaining TBF
          if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)
          {
            // Reset process
            *state = RESET;
          }
          else
          {
            // Enable a new measurement session
            *state = CONFIG;
          }
        }

        else
        if (SignalCode == L1P_PDCH_RELEASED)
        // PDCH have been released
        {
          // Enable a new measurement session
          *state = CONFIG;
        }

        // No action in this machine for other messages.
        else
        {
          // End of process
          return;
        }
      }
      break;

    } // End of "switch"
  } // End of "while"
} // End of "procedure"
//#pragma DUPLICATE_FOR_INTERNAL_RAM_START
#endif
//#pragma DUPLICATE_FOR_INTERNAL_RAM_END