view src/cs/layer1/cmacs/macs.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 Control System Header *************
 *                  GSM Layer 1 software
 * MACS.C
 *
 *        Filename macs.c
 *  Copyright 2003 (C) Texas Instruments
 *
 ************* Revision Control System Header *************/


//---Configuration flags---------------------------------------------------

#define TFI_FILTERING   1   // TFI FILTERING activated if set to 1
//-------------------------------------------------------------------------


#include <stdlib.h>
#include <stdio.h>

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

#if L1_GPRS

#include "l1_types.h"
#include "l1_const.h"

#if TESTMODE
  #include "l1tm_defty.h"
  #include "l1tm_varex.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 "l1_varex.h"
#include "l1_signa.h"

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

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

#if FF_TBF
  #include "l1_trace.h"
  #if (CODE_VERSION == SIMULATION)
    #include "sim_cons.h"
    #include "sim_def.h"
    #include "sim_var.h"
  #endif
#endif
/**********************************************************/
/* MACS-S Prototypes                                      */
/**********************************************************/

void l1ps_macs_meas            (void);                // Measurement gap processing
void l1ps_macs_header_decoding (UWORD8 rx_no,
                                UWORD8 *tfi_result,
                                UWORD8 *pr);          // MAC header decoding
void l1ps_macs_read            (UWORD8 pr_table[8]);  // MAC-S control tasks processing
void l1ps_macs_ctrl            (void);                // MAC-S read tasks processing
void l1ps_macs_init            (void);                // MAC-S initialization

#if FF_TBF
void l1ps_macs_rlc_uplink_info (void);
#endif

/**********************************************************/
/* EXTERNAL Prototypes                                    */
/**********************************************************/

void l1pddsp_transfer_mslot_ctrl(UWORD8  burst_nb,
                                 UWORD8  dl_bitmap,
                                 UWORD8  ul_bitmap,
                                 UWORD8  *usf_table,
                                 UWORD8  mac_mode,
                                 UWORD8  *ul_buffer_index,
                                 UWORD8  tsc,
                                 UWORD16 radio_freq,
                                 UWORD8  synchro_timeslot,
                               #if FF_L1_IT_DSP_USF
                                 UWORD8  dsp_usf_interrupt
                               #else
                                 UWORD8  usf_vote_enable
                               #endif
                               );

/* RLC interface for uplink RLC/MAC blocks */
/*-----------------------------------------*/

void rlc_uplink(
                 UWORD8   assignment_id,
                 UWORD8   tx_data_no,            // Number of timeslot that can be used
                                                 //   for uplink data block transfer
                 UWORD32  fn,                    // Next frame number
                 UWORD8   timing_advance_value,  // Timing advance (255 if unknown)
                 API      *ul_poll_response,     // Pointer on a_pu_gprs (NDB): poll response blocks
                 API      *ul_data,              // Pointer on a_du_gprs (NDB): uplink data blocks
                 BOOL     allocation_exhausted   // Set to 1 if fixed allocation exhausted
               );

#if TESTMODE
void l1tm_rlc_uplink(UWORD8 tx, API *ul_data);
#endif

/* RLC interface for downlink RLC/MAC blocks */
/*-------------------------------------------*/
#if FF_TBF

void rlc_downlink_data(
                        UWORD8   assignment_id,
                        UWORD32  fn,             // Actual frame number
                        API      *dl             // Pointer on a_dd_gprs (NDB): downlink blocks
                      );
void rlc_uplink_info(
                     UWORD8   assignment_id,
                     UWORD32  fn,
                     UWORD8   rlc_blocks_sent,    // Number of uplink blocks that was transmitted
                                                  // during the last block period
                     UWORD8   last_poll_response  // Status of the poll responses of
                    );                            // the last block period

UWORD8 rlc_downlink_copy_buffer(UWORD8 isr);


#else

void rlc_downlink(
                   UWORD8   assignment_id,
                   UWORD32  fn,                  // Actual frame number
                   API      *dl,                 // Pointer on a_dd_gprs (NDB): downlink blocks
                   UWORD8   rlc_blocks_sent,     // Number of uplink blocks that was transmitted
                                                 //   during the last block period
                   UWORD8   last_poll_response   // Status of the poll responses of
                                                 //   the last block period
                 );

#endif

#if (TRACE_TYPE==1) || (TRACE_TYPE==4)
  #include "l1_trace.h"
#endif


#if FF_TBF
  #include <stddef.h>

  #if (CODE_VERSION == SIMULATION)
    API* const A_DD_XGPRS[1][4] =
    {
      {&buf.ndb_gprs.a_dd_gprs[0][0], &buf.ndb_gprs.a_dd_gprs[1][0], &buf.ndb_gprs.a_dd_gprs[2][0], &buf.ndb_gprs.a_dd_gprs[3][0]},
    };

    API* const A_DU_XGPRS[1][4] =
    {
      {&buf.ndb_gprs.a_du_gprs[0][0], &buf.ndb_gprs.a_du_gprs[1][0], &buf.ndb_gprs.a_du_gprs[2][0], &buf.ndb_gprs.a_du_gprs[3][0]}
    };

  #else
    API* const A_DD_XGPRS[1][4] =
    {
      {
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[0][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[1][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[2][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[3][0]))
      }
    };

    API* const  A_DU_XGPRS[1][4] =
    {
      {
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[0][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[1][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[2][0])),
        (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[3][0]))
      }
    };
  #endif

#endif
/*-----------------------------------------------------------*/
/* l1ps_macs_init()                                          */
/*-----------------------------------------------------------*/
/* Parameters:                                               */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: This function initializes MAC-S variables    */
/*              and must be called before the first call     */
/*              of MAC-S                                     */
/*-----------------------------------------------------------*/
void l1ps_macs_init(void)
{
  UWORD8 i;

  #if FF_TBF
    macs.dl_buffer_index            = INVALID;
    for (i=0;i<NBR_SHARED_BUFFER_RLC;i++)
      macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs = 0xff;
  #endif
  /* General TBF parameters processed by MAC-S */
  /*********************************************/

  macs.sti_block_id           = 0;

  /* Ressources allocated by MAC-S             */
  /*********************************************/

  macs.rx_allocation          = 0;
  macs.tx_allocation          = 0;
  macs.tx_prach_allocation    = 0;
  macs.tx_data                = 0;
  macs.pwr_allocation         = 0xff;
  macs.last_rx_alloc          = 0;

  #if FF_L1_IT_DSP_USF
    macs.dsp_usf_interrupt    = 0;
  #endif

  macs.rx_blk_period          = NO_DL_BLK;
  macs.rlc_blocks_sent        = 0;
  macs.rx_no                  = 0;
  macs.last_poll_response     = 0;

  macs.usf_good               = 0;
  macs.usf_vote_enable        = 0;
  macs.tra_gap                = 8;
  macs.fix_alloc_exhaust      = FALSE;
  macs.next_usf_mon_block[0]  = macs.next_usf_mon_block[1] = 0;

  for (i = 0; i < TS_NUMBER; i ++)
  {
    macs.ul_buffer_index[i] = INVALID;
  }
  #if L1_EDA
    for (i = 0; i < 4; i++)
    {
      macs.monitored_ts[i] = INVALID;
    }
    macs.rx_monitored      = 0;
    macs.last_rx_monitored = 0;
    macs.lowest_poll_ts    = INVALID;
  #endif

  #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
    // Reset PDTCH trace structure
    for(i=0; i<8; i++)
    {
      trace_info.pdtch_trace.dl_status[i] = 0;
      trace_info.pdtch_trace.ul_status[i] = 0;
      trace_info.pdtch_trace.blk_status   = 0;
    }
  #endif

} /* End of l1ps_macs_init */

/*-----------------------------------------------------------*/
/* l1ps_macs_ctrl()                                          */
/*-----------------------------------------------------------*/
/* Parameters:global l1ps_macs_com           changed         */
/*            global l1s                     unchanged       */
/*            global l1a_l1s_com             unchanged       */
/*            global l1ps_dsp_com            changed         */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: MAC_S manages the timeslot allocation for    */
/*              downlink and uplink transfer and assign a    */
/*              measurement gap according to the MS class,   */
/*              the frame number when it's called and the    */
/*              allocation information given by Layer 1.     */
/*              It also program the corresponding tasks on   */
/*              the DSP and asks the RLC layer for uplink    */
/*              blocks                                       */
/*-----------------------------------------------------------*/
void l1ps_macs_ctrl(void)
{
  #define NDB_PTR  l1ps_dsp_com.pdsp_ndb_ptr
  #define SET_PTR  l1pa_l1ps_com.transfer.aset

  #if MACS_STATUS
    // No error
    l1ps_macs_com.macs_status.nb = 0;
  #endif

  /***********************************************************/
  /* USF values updating in dynamic mode (first frames of    */
  /* block periods)                                          */
  /***********************************************************/

  if  ((SET_PTR->allocated_tbf == UL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF))
  {
  #if L1_EDA
    if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC))
  #else
    if (SET_PTR->mac_mode == DYN_ALLOC)
  #endif
    {
      // Test if the USF must be read in the current frame
      // Concern the first frames of each block period (useful when
      // some USF values weren't valid the frame before)
      //                                                            FN 13
      //    0   1   2   3    4   5   6   7    8   9   10  11   12
      // ----------------------------------------------------------
      // ||       B0      ||       B1      ||       B2      || I ||
      // ||   |   |   |   ||   | X |   |   ||   | X |   |   ||   ||
      // ----------------------------------------------------------
      //                                                            X:USF Reading

    #if FF_L1_IT_DSP_USF
      if (l1ps_macs_com.usf_status == USF_IT_DSP)
    #else
      if (   (l1s.next_time.fn_mod13 == 5)
          || (l1s.next_time.fn_mod13 == 9))
    #endif
      {
        // USF values are read
        // Uplink timeslots whose USF was INVALID the frame before are de-allocated
        // if their USF value is now BAD

        UWORD8 tn;

        // Reading of the d_usf_updated_gprs value
        API    usf_updated = NDB_PTR->d_usf_updated_gprs;

        #if !L1_EDA
        // For each timeslot that can be allocated in uplink...
        for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn ++)
        {
          // If USF vote was enabled on this timeslot
          if(macs.usf_vote_enable & (MASK_SLOT0 >> tn))
          {
            // Clear the USF vote flag
            macs.usf_vote_enable &= ~(MASK_SLOT0 >> tn);

            // Read USF value
            if (((usf_updated >> ((MAX_TS_NB - tn) * 2)) & MASK_2SLOTS) == USF_GOOD)
            {
              // This timeslot is valid and good
              macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (tn + 3));
              macs.next_usf_mon_block[tn - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
            }
            else
            {
              // This timeslot is bad or invalid
              // If the slot was allocated for data
              if (macs.tx_data & (MASK_SLOT0 >> (tn + RXTX_DELAY)))
              {
                // rlc_blocks_sent decremented
                macs.rlc_blocks_sent --;

              #if FF_L1_IT_DSP_USF
                    // If next timeslot is also a data block:
                    // Shift data block to next TX opportunity. For MS class 12
                    // with dynamic allocation, 2 TX data max and they are
                    // contiguous (optimization).
                    if (macs.tx_data & (MASK_SLOT0 >> (tn + 1 + RXTX_DELAY)))
                    {
                      macs.ul_buffer_index[tn + 1 + RXTX_DELAY] = macs.ul_buffer_index[tn + RXTX_DELAY];

                    }

                    // Cancel burst
                    macs.ul_buffer_index[tn + RXTX_DELAY] = INVALID;

              #endif // FF_L1_IT_DSP_USF

                #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
                  if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
                    trace_info.pdtch_trace.ul_status[tn + RXTX_DELAY] = 0;
                #endif

                #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
                  RTTL1_FILL_MACS_STATUS(TX_CANCELLED_USF, tn)
                #endif
              }
            }
          } // End if "USF vote enabled on this timeslot"
        } // End for

        /* Uplink resources de-allocated by the DSP are de-allocated by MAC-S */
        macs.tx_allocation &= (UWORD8)  (macs.usf_good | ~macs.tx_data);
        macs.tx_data       &= (UWORD8)  (macs.usf_good | ~macs.tx_data);
        #else //#if !L1_EDA
          UWORD8  i = 0;

          //for all timeslots that need to be monitored
          while ((macs.monitored_ts[i] != INVALID) && (i <= 3))
          {
            // If USF vote was enabled on this timeslot
            if(macs.usf_vote_enable & (MASK_SLOT0 >> macs.monitored_ts[i]))
            {
              // Clear the USF vote flag
              macs.usf_vote_enable &= ~(MASK_SLOT0 >> macs.monitored_ts[i]);

              // Read USF value
              if ((((usf_updated >> ((MAX_TS_NB - macs.monitored_ts[i]) * 2)) & MASK_2SLOTS) == USF_GOOD)
                  && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i])))
              {
                if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                {
                  //RX timeslots to monitor have to be updated upon USF status receipt (only first ts with
                  //good USF has to be considered)
                  if ((macs.monitored_ts[i] <= macs.lowest_poll_ts) ||
                      ((MASK_SLOT0 >> macs.monitored_ts[i]) & macs.rx_allocation))
                    macs.rx_monitored |= (UWORD8) (MASK_SLOT0 >> macs.monitored_ts[i]);

                  // Clear the USF vote flag
                  macs.usf_vote_enable = 0;

                  //if the USF value is GOOD all remaining timelots that needed to be monitored
                  //have to be considered as having GOOD USFs
                  while ((macs.monitored_ts[i] != INVALID) && (i <= 3))
                  {
                    // Update good USFs bitmap
                    macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                    i++;
                  }
                  macs.next_usf_mon_block[0] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
                  break;
                }
                else
                {
                  // This timeslot is valid and good
                  macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                  macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
                }
              }
              else //USF is BAD or INVALID
              {
                //The TDMA before USF status was not known so USF was supposed to be GOOD but
                // now it turns out to be BAD or INVALID so block is deallocated.
                if (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)))
                {
                  UWORD8 j;

                  // rlc_blocks_sent decremented
                  macs.rlc_blocks_sent --;

                  tn = macs.monitored_ts[i];

                  #if FF_L1_IT_DSP_USF
                    //For all monitored ts (beginning with last one), if the timeslot is a data block then
                    //data block is shifted to next monitored ts.
                    j=3;
                    while (macs.monitored_ts[j] != tn)
                    {
                      if ((macs.monitored_ts[j] != INVALID) &&
                          (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[j] + RXTX_DELAY))))
                      {
                        macs.ul_buffer_index[macs.monitored_ts[j] + RXTX_DELAY] = macs.ul_buffer_index[macs.monitored_ts[j-1] + RXTX_DELAY];
                        #if L1_EGPRS
                          macs.tx_modulation &= ~(MASK_SLOT0 >> (macs.monitored_ts[j] + RXTX_DELAY));
                          macs.tx_modulation |= ((macs.tx_modulation &
                                                (MASK_SLOT0 >> (macs.monitored_ts[j-1] + RXTX_DELAY)))
                                               >> (macs.monitored_ts[j]-macs.monitored_ts[j-1]));
                        #endif // L1_EGPRS
                      }
                      j--;
                    }

                    // Cancel burst
                    macs.ul_buffer_index[tn + RXTX_DELAY] = INVALID;
                    #if L1_EGPRS
                      macs.tx_modulation &= ~(MASK_SLOT0 >> (tn + RXTX_DELAY));
                    #endif // L1_EGPRS
                  #endif // FF_L1_IT_DSP_USF
                }//if (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)))
                if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                {
                  //USF for current timeslot is BAD so it has to be monitored for next USF
                  //period
                  if ((macs.monitored_ts[i] <= macs.lowest_poll_ts) ||
                      ((MASK_SLOT0 >> macs.monitored_ts[i]) & macs.rx_allocation))
                    macs.rx_monitored |= (UWORD8) (MASK_SLOT0 >> macs.monitored_ts[i]);
                }
              }
            }//if(macs.usf_vote_enable & (MASK_SLOT0 >> macs.monitored_ts[i]))
            i++;
          }//while ((macs.monitored_ts[i] != INVALID) && (i <= 3))

          if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
          {
            // Downlink monitoring is updated depending on USF status
            macs.rx_allocation |= macs.rx_monitored;
          }

          // Uplink resources de-allocated by the DSP are de-allocated by MAC-S
          macs.tx_allocation &= (UWORD8)  (macs.usf_good | ~macs.tx_data);
          macs.tx_data       &= (UWORD8)  (macs.usf_good | ~macs.tx_data);
        #endif //#if !L1_EDA

        // Measurement gap processing
        l1ps_macs_meas();

      } // End if FN13 = 4 OR 8
    } // End if dynamic allocation mode
  } // End if uplink TBF


  #if FF_L1_IT_DSP_USF
    if (l1ps_macs_com.usf_status != USF_IT_DSP)
    {
  #endif

  /************************************************************/
  /*****  RESSOURCE ALLOCATION FOR THE NEXT BLOCK PERIOD  *****/
  /************************************************************/

  // If the next frame is the first of a block period
  //                                                           FN 13
  //    0   1   2   3    4   5   6   7    8   9   10  11   12
  // ----------------------------------------------------------
  // ||       B0      ||       B1      ||       B2      || I ||
  // || X |   |   |   || X |   |   |   || X |   |   |   ||   ||
  // ----------------------------------------------------------

  if (   (l1s.next_time.fn_mod13 == 4)
      || (l1s.next_time.fn_mod13 == 8)
      || (l1s.next_time.fn_mod13 == 0))
  {
    UWORD8   tx                  = 0;      // MS class Tx parameter checked
    UWORD8   rx                  = 0;      // MS class Rx parameter checked
    UWORD8   tx_no;                        // Number of allocated uplink timeslots
    UWORD8   highest_ul_ts;                // Highest numbered allocated uplink resource
    UWORD8   lowest_ul_ts;                 // Lowest numbered allocated uplink resource
    UWORD8   highest_dl_ts;                // Highest numbered allocated uplink resource
    UWORD8   lowest_dl_ts;                 // Lowest numbered allocated uplink resource
    UWORD8   tra_before_frame;             // Number of free Tx slots at the end of the
                                           // previous frame


    /***********************************************************/
    /* New allocated ressources                                */
    /***********************************************************/

    /*---------------------------------------------------------*/
    /* New assignment or synchronization change                */
    /*---------------------------------------------------------*/

    if (   (l1ps_macs_com.new_set != FALSE)
        || (l1a_l1s_com.dl_tn != macs.old_synchro_ts))
    {
      UWORD8  tn;
      UWORD8  fn_mod13;
      UWORD32 fn_div13;

      /* Fixed allocation mode initialization */
      /*--------------------------------------*/

      if (SET_PTR->mac_mode == FIX_ALLOC_NO_HALF)
      {
        if (((SET_PTR->assignment_command == UL_TBF) || (SET_PTR->assignment_command == BOTH_TBF)) &&
            (l1ps_macs_com.new_set))
        {
          // Starting time block ID processing
          fn_div13 = (UWORD32) (SET_PTR->tbf_sti.absolute_fn / 13);             // FN / 13
          fn_mod13 = (UWORD8) (SET_PTR->tbf_sti.absolute_fn - (fn_div13 * 13)); // FN mod 13
          macs.sti_block_id = (UWORD32) (  (3 * (UWORD32) fn_div13)             // Block ID
                                       + (fn_mod13 / 4));

          // Starting time not aligned on a block period
          if ((fn_mod13 != 0) && (fn_mod13 != 4) && (fn_mod13 != 8) && (fn_mod13 != 12))
            macs.sti_block_id ++;

          // Reset the fixed allocation bitmap exhaustion flag only in case of a new assignment
          macs.fix_alloc_exhaust      = FALSE;
        }

      } // End of fixed mode initialization
      else

        #if L1_EDA
          /*  Extended Dynamic/Dynamic allocation mode initialization  */
          /*------------------------------------------*/

          if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC))
        #else
      /*  Dynamic allocation mode initialization  */
      /*------------------------------------------*/

      if (SET_PTR->mac_mode == DYN_ALLOC)
        #endif
      {
        if ((SET_PTR->assignment_command == UL_TBF) || (SET_PTR->assignment_command == BOTH_TBF) ||
            (l1a_l1s_com.dl_tn != macs.old_synchro_ts))
        {
          // USF value aren't kept
          macs.usf_good           = 0;
          macs.usf_vote_enable    = 0;         // No USF vote
          macs.rx_blk_period      = NO_DL_BLK;

          if (l1ps_macs_com.new_set)
          // USF monitoring block set to current block to immediately enable
          // the USF monitoring in case of new UL TBF
            macs.next_usf_mon_block[0] = macs.next_usf_mon_block[1] = l1s.next_time.block_id;

          // First and last allocated Tx number updating
          macs.first_monitored_ts = INVALID;
          macs.last_monitored_ts  = INVALID;

          tn = 0;
          // Search of the lowest timeslot allocated in uplink
          while (   !(SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> tn))
                 && (tn < TS_NUMBER))
            tn ++;

          if (tn != TS_NUMBER)
          {
            macs.first_monitored_ts = tn - l1a_l1s_com.dl_tn;
            tn = MAX_TS_NB;

            // Search of the highest timeslot allocated in uplink
            while (!(SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> tn)))
              tn --;
            macs.last_monitored_ts = tn - l1a_l1s_com.dl_tn;
                #if L1_EDA
                  //Extended Dynamic or Dynamic Allocation has been set
                  {
                    UWORD8  i=0;
                    macs.rx_monitored   = 0;
                    //Search among the timeslots allocated in uplink, the timeslots that are really
                    //allocated (macs.first_monitored_ts and macs.last_monitored_ts are for sure
                    //allocated but the allocation can have holes inbetween)
                    for (i = 0; i < 4; i++)
                    {
                      macs.monitored_ts[i] = INVALID;
                    }
                    i = 0;
                    for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn++)
                    {
                      //Find the ts that are allocated and need therefore to be monitored
                      if (((SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> (tn + l1a_l1s_com.dl_tn))) && (SET_PTR->mac_mode == EXT_DYN_ALLOC))
                         || (SET_PTR->mac_mode == DYN_ALLOC))
                      {
                        macs.monitored_ts[i]= tn;
                        i++;
                      }
                    }
                  }
                #endif //#if L1_EDA
              }
            }
            #if L1_EDA
              if((SET_PTR->mac_mode == EXT_DYN_ALLOC))
                l1ps_macs_com.fb_sb_task_detect = TRUE;
              else
                l1ps_macs_com.fb_sb_task_detect = FALSE;
            #endif
      } // End of dynamic mode initialization

      /* Reset of new_set */
      /*------------------*/

      l1ps_macs_com.new_set = FALSE;

    } // End of new allocation

    /*---------------------------------------------------------*/
    /* Resource initialization                                 */
    /*---------------------------------------------------------*/

    macs.pwr_allocation      = 0;  // Power measurements
    macs.rx_allocation       = 0;  // Rx allocation
    macs.tx_allocation       = 0;  // Tx allocation
    macs.tx_data             = 0;  // Tx data allocation
    macs.tx_prach_allocation = 0;  // Tx PRACH allocation
    #if FF_L1_IT_DSP_USF
     macs.dsp_usf_interrupt = 0;  // DSP interrupt for USF decoding needed
    #endif

    /***********************************************************/
    /* Downlink TBF processing                                 */
    /***********************************************************/

    if ((SET_PTR->allocated_tbf == DL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF))
    {
      /* Downlink resources are allocated */
      macs.rx_allocation = (UWORD8) (   SET_PTR->dl_tbf_alloc.timeslot_alloc
                                     << l1a_l1s_com.dl_tn);
    } /* End if downlink TBF processing  */

    /***********************************************************/
    /* Uplink TBF processing                                   */
    /***********************************************************/

    if ((SET_PTR->allocated_tbf == UL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF))
    {

      /*---------------------------------------------------------*/
      /* Dynamic allocation mode                                 */
      /*---------------------------------------------------------*/

        #if L1_EDA
          if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC))
        #else
          if (SET_PTR->mac_mode == DYN_ALLOC)
        #endif
      {
        UWORD8 i;
        UWORD8 tn;
        API    usf_updated;

            #if !L1_EDA
        /* Downlink resource monitoring */
        /*------------------------------*/

        macs.rx_allocation |= (UWORD8)  (   SET_PTR->ul_tbf_alloc->timeslot_alloc
                                        << l1a_l1s_com.dl_tn);

        /* USF values reading */
        /*--------------------*/

        // An uplink timeslot is allocated by MAC-S if it's allocated by the network and
        //    - USF is updated and good
        // OR - USF isn't updated

        // Reading of the d_usf_updated_gprs value
        usf_updated = NDB_PTR->d_usf_updated_gprs;

        // For each timeslot that can be allocated in uplink...
        for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn ++)
        {
          UWORD8 tn_usf;
          WORD32 delta;

          // Remaining blocks before a new USF reading
          delta = (WORD8) (macs.next_usf_mon_block[tn - macs.first_monitored_ts] - l1s.next_time.block_id);

          // MAX_FN modulo
          if (delta <= 0) delta += MAX_BLOCK_ID;

          if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity])
          {
            // USF no more usable
            // Clear USF in good USFs bitmap
            macs.usf_good &= (UWORD8) ~(MASK_SLOT0 >> (tn + 3));

            // Clear USF vote
            macs.usf_vote_enable &= (UWORD8) ~(MASK_SLOT0 >> tn);

            // If downlink blocks were entirely received during the last block period
            if (macs.rx_blk_period == l1s.next_time.block_id)
            {
              // Read USF
              tn_usf = (UWORD8) ((usf_updated >> ((MAX_TS_NB - tn) << 1)) & MASK_2SLOTS);

              if (tn_usf == USF_GOOD)
              {
                // Update good USFs bitmap
                macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (tn + 3));
                macs.next_usf_mon_block[tn - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
              }
              else
              if ((tn_usf == USF_INVALID) && (l1s.next_time.fn_mod13 != 0))
              {
                // Unknown USF:
                //    - TPU is programmed to tranmit a block on timeslot tn
                //    - DSP will set the TX PWR to 0 for this timeslot is USF is bad
                //      (USF vote mechanism)

                macs.tx_allocation   |= (MASK_SLOT0 >> (tn + 3));
                macs.usf_vote_enable |= (MASK_SLOT0 >> tn);
              }
            } // End if "downlink block entirely received"
          } // End if "USF no more usable"
        } // End for

            #else  //#if !L1_EDA
              {
                UWORD8 tn_usf;
                WORD32 delta;
                UWORD8 i=0;

                if (SET_PTR->mac_mode == DYN_ALLOC)
                {
                  /* Downlink resource monitoring */
                  /*------------------------------*/

                  macs.rx_allocation |= (UWORD8)  (   SET_PTR->ul_tbf_alloc->timeslot_alloc
                                                << l1a_l1s_com.dl_tn);

                  macs.last_rx_monitored = macs.rx_allocation;
                }
                else
                {
                  // Remaining blocks before a new USF reading
                  delta = (WORD8) (macs.next_usf_mon_block[0] - l1s.next_time.block_id);

                  // MAX_FN modulo
                  if (delta <= 0) delta += MAX_BLOCK_ID;

                  //Save last rx_monitored timeslots
                  macs.last_rx_monitored = macs.rx_monitored;

                  //for all timeslots to monitor (timeslots allocated in UL)
                  for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn++)
                  {
                    //All possible timeslots to monitor have to be monitored
                    // (USF validity period exhausted)
                    if (macs.monitored_ts[i] != INVALID)
                      macs.rx_monitored |= (MASK_SLOT0 >> macs.monitored_ts[i]);
                    i++;
                  }

                  //USF validity period is exhausted
                  if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity])
                  {
                    //USF need to be evaluated for next block period
                    macs.usf_good = 0;
                  }
                  else
                  {
                    //Set monitored ts again if poll occured on one ts during a block granularity period = 4
                    //note: macs.usf_good is always different from 0
                    i=0;
                    while (!(macs.usf_good & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY))))
                      i++;
                    macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]);
                  }
                }

                // Reading of the d_usf_updated_gprs value
                usf_updated = NDB_PTR->d_usf_updated_gprs;

                i=0;
                //for all possible timeslots to monitor
                while ((macs.monitored_ts[i] != INVALID) && (i <= 3))
                {
                  if (SET_PTR->mac_mode == DYN_ALLOC)
                  {
                    // Remaining blocks before a new USF reading
                    delta = (WORD8) (macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] - l1s.next_time.block_id);

                    // MAX_FN modulo
                    if (delta <= 0) delta += MAX_BLOCK_ID;
                  }

                  //USF validity period is exhausted
                  if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity])
                  {
                    if (SET_PTR->mac_mode == DYN_ALLOC)
                    {
                      // USF no more usable
                      // Clear USF in good USFs bitmap
                      macs.usf_good &= (UWORD8) ~(MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));

                      // Clear USF vote
                      macs.usf_vote_enable &= (UWORD8) ~(MASK_SLOT0 >> macs.monitored_ts[i]);
                    }

                    if ((macs.rx_blk_period == l1s.next_time.block_id) && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i])))
                    {

                      #if L1_EGPRS
                        // EGPRS switched radio loopback sub mode on: dynamic allocation
                        // but USF are always deemed to be good
                        if (l1ps_macs_com.loop_param.sub_mode == TRUE)
                          tn_usf = USF_GOOD;
                        else
                      #endif
                          // Read USF
                         tn_usf = (UWORD8) ((usf_updated >> ((MAX_TS_NB - macs.monitored_ts[i]) << 1)) & MASK_2SLOTS);

                      if (tn_usf == USF_GOOD)
                      {
                        if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                        {
                          //Deallocate monitored ts
                          macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]);

                          //As USF is good for current monitored ts, all subsequent monitored ts have
                          //to be deallocated and the associated USF set to USF_GOOD
                          while ((macs.monitored_ts[i] != INVALID) && (i <= 3))
                          {
                            //Update good USFs bitmap
                            macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                            i++;
                          }
                          macs.next_usf_mon_block[0] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
                          break;
                        }
                        else
                        {
                          // Update good USFs bitmap
                          macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                          macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity];
                        }
                      }
                      else
                      if ((tn_usf == USF_INVALID) && (l1s.next_time.fn_mod13 != 0))
                      {
                        if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                        {
                          //Deallocate monitored ts
                          macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]);

                          //As USF is invalid (status of USF not yet known) for current monitored ts, the USF is
                          //supposed to be good and therefore Tx is allocated and all subsequent monitored ts
                          //have to be deallocated. Vote mechanism is also enabled for these latter timeslots.
                          while ((macs.monitored_ts[i] != INVALID) && (i <= 3))
                          {
                            macs.tx_allocation |= (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                            macs.usf_vote_enable |= (MASK_SLOT0 >> macs.monitored_ts[i]);
                            i++;
                          }
                          break;
                        }
                        else
                        {
                          // Unknown USF:
                          //    - TPU is programmed to tranmit a block on timeslot tn
                          //    - DSP will set the TX PWR to 0 for this timeslot is USF is bad
                          //      (USF vote mechanism)

                          macs.tx_allocation   |= (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY));
                          macs.usf_vote_enable |= (MASK_SLOT0 >> macs.monitored_ts[i]);
                        }
                      }
                    }//if ((macs.rx_blk_period == l1s.next_time.block_id) && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i])))
                  }
                  i++;
                }//while ((tn != INVALID) && (i <= 3))
              }//if (SET_PTR->mac_mode == EXT_DYN_ALLOC)

              /* Downlink resource monitoring */
              /*------------------------------*/
              macs.rx_allocation |= macs.rx_monitored;
            #endif //#if !L1_EDA
        /* Uplink resources allocation according to USF values */
        /*-----------------------------------------------------*/

        i = l1a_l1s_com.dl_tn - RXTX_DELAY;
        if (i < TS_NUMBER)
        {
          macs.tx_allocation |= (UWORD8) (  macs.usf_good
                                          & (SET_PTR->ul_tbf_alloc->timeslot_alloc << i));
        }
        else
        {
          macs.tx_allocation |= (UWORD8) (  macs.usf_good
                                          & (SET_PTR->ul_tbf_alloc->timeslot_alloc >> (-i)));
        }

            #if L1_EDA
              //if FB/SB activity detected in comming idle frame, some TX burst have to be deallocated
              //to allow opening of FB/SB window (no TX activity should be scheduled in slots 6 and 7)
              if (l1ps_macs_com.fb_sb_task_enabled && l1ps_macs_com.fb_sb_task_detect)
              {
                macs.tx_allocation &= ~(MASK_SLOT0 >> 6);
              }
            #endif

       #if FF_L1_IT_DSP_USF
              // UL or BOTH TBF with dynamic allocation in use. DSP has to generate
              // an interrupt for USF validity for the block to be received if it
              // is either RBN (radio block number) % 3 = 0 or 1.

              if (   (l1s.next_time.fn_mod13 == 0)
                  || (l1s.next_time.fn_mod13 == 4))

                macs.dsp_usf_interrupt = 1;
       #endif

      } /* end if dynamic allocation mode */

      /*---------------------------------------------------------*/
      /* Fixed allocation mode                                   */
      /*---------------------------------------------------------*/

      if (SET_PTR->mac_mode == FIX_ALLOC_NO_HALF)
      {
        UWORD8   i;
        UWORD32  blk_id = l1s.next_time.block_id;

        /* Allocation bitmap isn't exhausted */
        /*-----------------------------------*/

        if(macs.fix_alloc_exhaust == FALSE)
        {

          // Allocation exhaustion detection
          //---------------------------------

          //
          // 0  current_fn  End of allocation                      STI  FN_MAX
          // |-----|---------|--------------------------------------|----||
          // |.....|.........|                                      |....||
          // |-----|---------|--------------------------------------|----||
          //
          // In this case, the Starting time is elapsed but current_fn < STI
          // ---> We must have (current block_ID - STI_block_ID) > 0
          //
          if (blk_id < macs.sti_block_id)
          {
            blk_id += MAX_BLOCK_ID;  // MAX_BLOCK_ID is the block ID obtained when fn = FN_MAX

          } // End of FN MAX modulo management

          #if TESTMODE
            // Never let exhaust the UL allocation in test mode packet transfer operation
            if (l1_config.TestMode)
              blk_id = macs.sti_block_id;
          #endif

          /* Allocation bitmap isn't exhausted */
          if (blk_id < (macs.sti_block_id + SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap_length))
          {

            // Uplink allocation
            //------------------

            // Resources are allocated according to the allocation bitmap or ts_override
            macs.tx_allocation = (UWORD8)
                       (  SET_PTR->ul_tbf_alloc->timeslot_alloc
                        & (  SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap[blk_id - macs.sti_block_id]
                           | SET_PTR->ts_override));
            // Delay
            i = l1a_l1s_com.dl_tn - RXTX_DELAY;
            if (i > MAX_TS_NB)
              macs.tx_allocation >>= (-i);
            else
              macs.tx_allocation <<= i;

            // Monitoring
            //-----------

            if ((l1s.next_time.fn_mod13 == 0) || (macs.rx_blk_period != l1s.next_time.block_id))
            {
              // Last frame was an idle frame or was used for another task --> considered as a free frame
              tra_before_frame = 8;
            }
            else
            {
              tra_before_frame = macs.tra_gap;  // Tra gap of last TDMA frame is saved
            }

            // DOWNLINK CONTROL TIMESLOT ALLOCATION

            if (  SET_PTR->ul_tbf_alloc->timeslot_alloc
                & (MASK_SLOT0 >> SET_PTR->ul_tbf_alloc->fixed_alloc.ctrl_timeslot))
            {
              // Tra and Ttb met --> allocates the downlink control timeslot
              macs.rx_allocation |= (UWORD8)
                               (MASK_SLOT0 >> (  SET_PTR->ul_tbf_alloc->fixed_alloc.ctrl_timeslot
                                               - l1a_l1s_com.dl_tn));
            }

            // UPLINK PDCH MONITORING
            else
            {
              // The control timeslot has been released

              // Allocates uplink TBF timeslots for monitoring
              macs.rx_allocation |= (UWORD8) (   SET_PTR->ul_tbf_alloc->timeslot_alloc
                                              << l1a_l1s_com.dl_tn);
            }

            // If Ttb or Tra not respected, the problem comes from uplink TBF
            // monitored timeslots
            // If Ttb not respected, downlink resources are removed
            for(i = 0; i <= MS_CLASS[SET_PTR->multislot_class].ttb; i++)
              macs.rx_allocation &=  (~((UWORD8)(macs.tx_allocation << i)));

            // Tra respect according to the current allocation
            for(i = 0; i <= MS_CLASS[SET_PTR->multislot_class].tra; i++)
              macs.rx_allocation &= (~((UWORD8)(macs.tx_allocation << (8-i))));

            // Tra respect according to the last allocation
            if (tra_before_frame < MS_CLASS[SET_PTR->multislot_class].tra)
            {
              macs.rx_allocation &= MASK_ALL_SLOTS >> (MS_CLASS[SET_PTR->multislot_class].tra - tra_before_frame);
            }

            #if MACS_STATUS
              if (macs.rx_allocation == 0)
              {
                l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = NO_RX_MONITORED;
                l1ps_macs_com.macs_status.nb ++;
              }
            #endif

            // Last block of the allocation bitmap... next block will use new settings
            // for timeslot monitoring
            if ((blk_id + 1) == (macs.sti_block_id + SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap_length))
            {
              macs.fix_alloc_exhaust               = TRUE;
              // Informs L1S
              l1ps_macs_com.fix_alloc_exhaust_flag = TRUE;
            }


          } // End if "allocation bitmap isn't exhausted"
          else

          // Allocation bitmap has exhausted
          {
            macs.fix_alloc_exhaust               = TRUE;
            // Informs L1S
            l1ps_macs_com.fix_alloc_exhaust_flag = TRUE;

            // Allocates uplink TBF timeslots for monitoring
            macs.rx_allocation |= (UWORD8) (   SET_PTR->ul_tbf_alloc->timeslot_alloc
                                            << l1a_l1s_com.dl_tn);

          }

        } // End if "allocation bitmap not exhausted"

        /* Allocation bitmap is exhausted */
        /*--------------------------------*/
        else
        {
          // Allocates uplink TBF timeslots for monitoring
          macs.rx_allocation |= (UWORD8) (   SET_PTR->ul_tbf_alloc->timeslot_alloc
                                          << l1a_l1s_com.dl_tn);

        } // End if fixed allocation exhausted

      } // End of fixed allocation processing

    } // End of uplink TBF processing

    /***********************************************************/
    /* Allocation parameters checking and updating             */
    /***********************************************************/
    {
      UWORD8 ts;
      BOOL   rx_ts;
      BOOL   tx_ts;

 #if MACS_STATUS
      UWORD8 time   = INVALID;  /* Timeslot counter */
 #endif

      tx_no         = 0;
      highest_ul_ts = INVALID;
      lowest_ul_ts  = INVALID;
      highest_dl_ts = INVALID;
      lowest_dl_ts  = INVALID;

      /*---------------------------------------------------------*/
      /* Trb, Ttb parameters verification and Rx, Tx number, Sum */
      /* and highest_ul_ts parameters processing                 */
      /*---------------------------------------------------------*/

      /* We verifies all allocated uplink and downlink timeslots */
      for (ts = 0; ts < TS_NUMBER; ts ++)
      {
        rx_ts = (UWORD8) (macs.rx_allocation & (MASK_SLOT0 >> ts));
        tx_ts = (UWORD8) (macs.tx_allocation & (MASK_SLOT0 >> ts));

      #if MACS_STATUS

        /* If Rx(ts) = 0 and Tx(ts) = 0 */
        /*------------------------------*/

        if ((!rx_ts) && (!tx_ts))
        {
          /* time is incremented */
          /* If time was invalid, it becomes active */
          if (time < TS_NUMBER)
            time ++;
          if ((time == RX_SLOT)||(time == TX_SLOT))
            time = 1;
        } /* End if Rx = 0 and Tx = 0 */

        /* If Rx(ts) = 1 and Tx(ts) = 1 */
        /*------------------------------*/

        if ((rx_ts) && (tx_ts))
        {
          /* error (only type 1 mobiles are supported) */
          l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR;
          l1ps_macs_com.macs_status.nb ++;
        } /* End if Rx = 1 and Tx = 1 */
      #endif

        /* If Rx(ts) = 1 */
        /*---------------*/

        if (rx_ts)
        {
          highest_dl_ts = ts;
        #if MACS_STATUS
          /* If time is valid (invalid=0xFF) and time<Trb --> error */
          if ((time < MS_CLASS[SET_PTR->multislot_class].trb) || (time == TX_SLOT))
          {
            l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR;
            l1ps_macs_com.macs_status.nb ++;
          }
          time = RX_SLOT;
        #endif
          /* First Rx updating */
          if (lowest_dl_ts == INVALID)
            lowest_dl_ts = ts;

        } /* End if Rx = 1 */

        /* If Tx(ts) = 1 */
        /*---------------*/

        if (tx_ts)
        {
          /* Number of Tx is incremented and highest_ul_ts is updated */
          tx_no ++;
          highest_ul_ts = ts;
        #if MACS_STATUS
          /* If time is valid (invalid=0xFF) and time<Ttb --> error */
          if (   (time < MS_CLASS[SET_PTR->multislot_class].ttb)
              || (time == RX_SLOT))
          {
            l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR;
            l1ps_macs_com.macs_status.nb ++;
          }
          time = TX_SLOT;
        #endif
          /* First Tx updating */
          if (lowest_ul_ts == INVALID)
            lowest_ul_ts = ts;

          #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
            if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
              trace_info.pdtch_trace.ul_status[ts] |= 0x4;
          #endif
        } /* End if Tx = 1 */

      } /* End for */

      /* Rx and Tx MS class parameters are updated */
      if (lowest_dl_ts != INVALID)
        rx = (UWORD8) (highest_dl_ts - lowest_dl_ts + 1);

      if (lowest_ul_ts != INVALID)
        tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1);

    #if MACS_STATUS
      // If the Trb parameter isn't respected at the end of
      // the TDMA frame --> MS Class isn't suported
      // Note: we considered that the first slot of the next TDMA is always a RX
      if (time < MS_CLASS[SET_PTR->multislot_class].trb)
      {
        l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR;
        l1ps_macs_com.macs_status.nb ++;
      }

      /*---------------------------------------------------------*/
      /* Sum, Rx and Tx parameters verification                  */
      /*---------------------------------------------------------*/

      if (  ((rx + tx) > MS_CLASS[SET_PTR->multislot_class].sum)
          ||(rx > MS_CLASS[SET_PTR->multislot_class].rx)
          ||(tx > MS_CLASS[SET_PTR->multislot_class].tx))
      {
        l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_SUM_ERROR;
        l1ps_macs_com.macs_status.nb ++;
      }

      // If all downlink timeslots are before the first uplink timeslot or after
      // the last uplink timeslot, Rx and Tx parameters are met
      if (   (   (highest_dl_ts > lowest_ul_ts)
              || (lowest_dl_ts > lowest_ul_ts))
          && (   (highest_dl_ts < highest_ul_ts)
              || (lowest_dl_ts < highest_ul_ts)))
      {
        l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_SUM_ERROR;
        l1ps_macs_com.macs_status.nb ++;
      }

    #endif

    } /* End of allocation parameters checking and updating */


    /***********************************************************/
    /* Uplink RLC/MAC blocks management (RLC - DSP interfaces) */
    /* PACCH/U placement (Poll response processing)            */
    /***********************************************************/

    {
      BOOL   poll;              // TRUE if the poll response is processed
      UWORD8 highest_ul_data;   // Highest uplink timeslot assigned for data transfer
      UWORD8 tx_allocation_s;   // Used for saving of macs.tx_allocation
      UWORD8 rx_allocation_s;   // Used for saving of macs.rx_allocation
      UWORD8 tx_data_s;         // Used for saving of macs.tx_data
      UWORD8 highest_ul_ts_s;   // Used for saving of highest_ul_ts
      UWORD8 lowest_ul_ts_s;    // Used for saving of lowest_ul_ts
      UWORD8 poll_resp_ts;      // Timeslot on which the MS must transmit a poll response
      UWORD8 ts;
      UWORD8 i;
          #if L1_EDA
            UWORD8 rx_monitored_s; // Used for saving of rx_monitored
          #endif

      /*---------------------------------------------------------*/
      /* Uplink buffer indexes initialization                    */
      /*---------------------------------------------------------*/

      macs.ul_buffer_index[0] = macs.ul_buffer_index[1] = macs.ul_buffer_index[2] =
        macs.ul_buffer_index[3] = macs.ul_buffer_index[4] = macs.ul_buffer_index[5] =
        macs.ul_buffer_index[6] = macs.ul_buffer_index[7] = INVALID;

      // Reset all uplink blocks CS-TYPE in order to disable the validity of blocks not sent
      for(i=0; i<4; i++)
      {
        NDB_PTR->a_du_gprs[i][0] = CS_NONE_TYPE;
        NDB_PTR->a_pu_gprs[i][0] = CS_NONE_TYPE;
      }

      /*---------------------------------------------------------*/
      /* Uplink RLC/MAC blocks request to RLC (RLC_UPLINK)       */
      /*---------------------------------------------------------*/

      /* All allocated uplink resources are used for data */
      macs.tx_data = macs.tx_allocation;
      highest_ul_data = highest_ul_ts;

      /* RLC UPLINK CALL */
      /*-----------------*/

      #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
        if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_UL_NO_TA)
          if ((SET_PTR->packet_ta.ta == 255) && (macs.tx_allocation != 0))
            Trace_uplink_no_TA();
      #endif

      #if TESTMODE
        if (l1_config.TestMode)
        {
          l1tm_rlc_uplink (tx_no, (API*) NDB_PTR->a_du_gprs);
        }
        else
      #endif
      {
        rlc_uplink(SET_PTR->assignment_id,         // Assignment ID
                   tx_no,                          // Number of timeslot that can be used
                                                   //   for uplink data block transfer
                   l1s.next_time.fn,               // Next frame number
                   SET_PTR->packet_ta.ta,          // Timing advance value
                   (API*) NDB_PTR->a_pu_gprs,      // Pointer on poll response struct
                   (API*) NDB_PTR->a_du_gprs,      // Pointer on uplink block struct
                   macs.fix_alloc_exhaust          // Set to 1 if fixed allocation exhausted
        );
      }

          #if FF_TBF
            #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
              if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_RLC_PARAM)
              {
                UWORD32 cs_type = 0;
                //Get the cs_type from the UL buffer API header
                //The cs_type format: byte0 (LSByte) -indicates the CS type of TS0
                //byte1- CS type of TS1
                //byt2 - CS type of TS2
                //byte3(MSBye) - CS type of TS3
                for (i=0;i<tx_no;i++)
                {
                                        cs_type |= ((((UWORD8) NDB_PTR->a_du_gprs[i][0]) & CS_GPRS_MASK) << (8*i));

                }
                Trace_rlc_ul_param(SET_PTR->assignment_id,         // Assignment ID
                                   l1s.next_time.fn,               // Next frame number
                                   tx_no,                          // Number of UL timeslot that can be used
                                   SET_PTR->packet_ta.ta,          // Timing advance value
                                   macs.fix_alloc_exhaust,
                                   cs_type );
              }
            #endif
          #else
      #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
        if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_RLC_PARAM)
        {
          Trace_rlc_ul_param(SET_PTR->assignment_id,         // Assignment ID
                             tx_no,                          // Number of timeslot that can be used
                                                             //   for uplink data block transfer
                             l1s.next_time.fn,               // Next frame number
                             SET_PTR->packet_ta.ta,          // Timing advance value
                             (UWORD32) NDB_PTR->a_pu_gprs,      // Pointer on poll response struct
                             (UWORD32) NDB_PTR->a_du_gprs,      // Pointer on uplink block struct
                             macs.fix_alloc_exhaust);
        }
      #endif
          #endif

      i = 0;

      /*---------------------------------------------------------*/
      /* Poll responses processing                               */
      /*---------------------------------------------------------*/
          #if L1_EDA
            macs.lowest_poll_ts = INVALID;
          #endif

      /* While a poll response is requested */
      while (  (   ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS1_TYPE_POLL)
                || ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS_PAB8_TYPE)
                || ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS_PAB11_TYPE))
             && (i < 4))
      {
        poll = TRUE;

        // The number of the timeslot on which the poll response is requested is converted to
        // become relative to L1 synchronization
        poll_resp_ts =   (UWORD8) NDB_PTR->a_pu_gprs[i][1]
                      -  l1a_l1s_com.dl_tn
                      +  RXTX_DELAY;

        // All timeslots on which a poll is requested are set in last_poll_response.
        // last_poll_response will be updated in FN13 = 2, 6 and 10, when the 4th control
        // task will be processed for the current block period --> we'll be sure the poll
        // responses are entirely transmitted (no BCCH monitoring)
        macs.last_poll_response |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts);

        // Allocations are saved: it's useful to restore uplink slots that were removed
        // for mapping a poll response that is finally not processed
        tx_allocation_s = macs.tx_allocation;
        rx_allocation_s = macs.rx_allocation;
        tx_data_s       = macs.tx_data;
        lowest_ul_ts_s  = lowest_ul_ts;
        highest_ul_ts_s = highest_ul_ts;
            #if L1_EDA
              rx_monitored_s  = macs.rx_monitored;
            #endif
          #if L1_EDA
            //In the case of concurrent TBFs in extended dynamic mode, poll response can be canceled
            //if response is not done on concurrent timeslots
            if (((SET_PTR->allocated_tbf == BOTH_TBF) && (SET_PTR->mac_mode == EXT_DYN_ALLOC)) &&
                (!((SET_PTR->dl_tbf_alloc.timeslot_alloc) & (SET_PTR->ul_tbf_alloc->timeslot_alloc)
                & (MASK_SLOT0 >> NDB_PTR->a_pu_gprs[i][1]))))
            {
              // Poll response not done
              poll = FALSE;
            }
            else
          #endif
        /* If the requested timeslot is allocated for data transfer */
        /*----------------------------------------------------------*/

        if (macs.tx_data & (MASK_SLOT0 >> poll_resp_ts))
        {
          /* The slot is removed in tx_data */
          /* No allocation modification */
          macs.tx_data &= (UWORD8) (~(MASK_SLOT0 >> poll_resp_ts));

          #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
            RTTL1_FILL_MACS_STATUS(TX_CANCELLED_POLL, poll_resp_ts)
          #endif

        } /* End if slot allocated for data */

        /* If the poll response is requested on an invalid timeslot    */
        /* i.e:                                                        */
        /*    - Timeslot > 7 or < 0                                    */
        /*    - Timeslot that avoid the RX on the first timeslot       */
        /*      according to Ttb                                       */
        /*-------------------------------------------------------------*/

        else
        if ((poll_resp_ts > 7) || (poll_resp_ts <= MS_CLASS[SET_PTR->multislot_class].ttb))
        {
          // Poll response not done
          poll = FALSE;
        }

        /* If the Tra parameter isn't respected */
        /*--------------------------------------*/

          #if L1_EDA
            //Tra does not always apply with EDA.
            else
            if ((  (MASK_SLOT0 >> poll_resp_ts)
                & (   macs.rx_allocation
                   >> (TS_NUMBER - MS_CLASS[SET_PTR->multislot_class].tra)) && (SET_PTR->mac_mode != EXT_DYN_ALLOC))
                || ((poll_resp_ts == 6) && (l1ps_macs_com.fb_sb_task_enabled)))
          #else
        else
        if (  (MASK_SLOT0 >> poll_resp_ts)
            & (   macs.rx_allocation
               >> (TS_NUMBER - MS_CLASS[SET_PTR->multislot_class].tra)))

          #endif
        {
          // Poll response not done
          poll = FALSE;
        }

        /* Ttb and Tra respected                                         */
        /* Poll on a slot not already allocated for uplink data transfer */
        /*---------------------------------------------------------------*/

        else
        {
          /* If Ttb parameter isn't respected  */
          /*-----------------------------------*/

          // If one or several downlink timeslots are allocated between:
          //    - Ttb timeslots before the timeslot to use for poll response
          //    - AND the last slot of the frame (optimization)
          //          --> Ttb parameter isn't respected if the poll response is transmitted
          //              so the RX resources are removed

          macs.rx_allocation &= ~((UWORD8) (  macs.rx_allocation
                                            & (   MASK_ALL_SLOTS
                                               >> (  poll_resp_ts
                                                   - MS_CLASS[SET_PTR->multislot_class].ttb))));

              #if L1_EDA
                if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                {
                  UWORD8 only_monitored_ts;

                  only_monitored_ts = ~((UWORD8)(SET_PTR->dl_tbf_alloc.timeslot_alloc << l1a_l1s_com.dl_tn)) & macs.rx_monitored;
                  macs.rx_allocation &= ~(only_monitored_ts & (MASK_ALL_SLOTS >> (poll_resp_ts + 1 - RXTX_DELAY)));
                  macs.rx_monitored &= macs.rx_allocation;
                }
              #endif
          /* The requested slot is allocated */
          macs.tx_allocation |= (UWORD8)  (MASK_SLOT0 >> poll_resp_ts);

          /* Lowest, highest numbered uplink timeslot and Tx parameter are updated */

          if (poll_resp_ts < lowest_ul_ts)
            lowest_ul_ts = poll_resp_ts;

          if ((poll_resp_ts > highest_ul_ts) || (highest_ul_ts == INVALID))
            highest_ul_ts = poll_resp_ts;

          tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1);

          /* Tx and Sum parameters checking */
          /*--------------------------------*/

          /* While Tx or Sum parameter isn't respected and the poll response hasn't */
          /* already been removed */
          while (   (   (tx > MS_CLASS[SET_PTR->multislot_class].tx)
                     || ((rx + tx) > MS_CLASS[SET_PTR->multislot_class].sum))
                 && (poll == TRUE))
          {
            /* If no uplink timeslot is used for data */
            if (macs.tx_data == 0)
            {
              /* The poll response isn't processed */
              poll = FALSE;
            }
            else
            {
              /* Highest uplink PDTCH is removed */
              macs.tx_allocation &= (UWORD8) (~(MASK_SLOT0 >> highest_ul_data));
              macs.tx_data       &= (UWORD8) (~(MASK_SLOT0 >> highest_ul_data));

              #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
                RTTL1_FILL_MACS_STATUS(TX_CANCELLED_POLL, highest_ul_data)
              #endif

              /* Lowest, highest numbered uplink timeslot and Tx parameter are updated */

              lowest_ul_ts    = INVALID;
              highest_ul_ts   = INVALID;
              highest_ul_data = INVALID;

              for (ts = 0; ts < TS_NUMBER; ts ++)
              {
                if (macs.tx_allocation & (MASK_SLOT0 >> ts))
                {
                  if (lowest_ul_ts == INVALID)
                    lowest_ul_ts = ts;
                  highest_ul_ts = ts;
                  if (macs.tx_data & (MASK_SLOT0 >> ts))
                    highest_ul_data = ts;
                }
              }

              tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1);

            }
          } /* End while Tx or Sum parameter not met */
        } /* End of case "poll on a timeslot not already allocated for uplink data transfer"
                         " Tra and Ttb respected " */

        /* If the poll response is done */
        /*------------------------------*/
        if (poll == TRUE)
        {
          // Note: Power measurement always found because Tra met

          UWORD8   cs_type;
          UWORD16  prach_info;
              #if L1_EDA
                UWORD8 only_monitored_ts;
              #endif

          cs_type    = (UWORD8)  ((NDB_PTR->a_pu_gprs[i][0]) & 0xF);
          prach_info = (UWORD16) l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2];

          if(cs_type == CS_PAB8_TYPE)
          {
            l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2] = ((API)(l1a_l1s_com.Scell_info.bsic << 2)) |
                                                         ((API)(prach_info) << 8);
            l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][3] = 0;

            // macs.tx_prach_allocation is updated
            macs.tx_prach_allocation |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts);
          }
          else
          if(cs_type == CS_PAB11_TYPE)
          {
            l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2] = ((API)(prach_info) << 5);
            l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][3] = ((API)(l1a_l1s_com.Scell_info.bsic << 10));

            // macs.tx_prach_allocation is updated
            macs.tx_prach_allocation |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts);
          }

              #if L1_EDA
                only_monitored_ts = ~((UWORD8)(SET_PTR->dl_tbf_alloc.timeslot_alloc << l1a_l1s_com.dl_tn)) & (SET_PTR->ul_tbf_alloc->timeslot_alloc<< l1a_l1s_com.dl_tn);
                //lowest_poll_ts variable is used to remove only monitored ts above a ts
                //used for a poll.
                if (SET_PTR->mac_mode == EXT_DYN_ALLOC)
                {
                  if ((poll_resp_ts - RXTX_DELAY) < macs.lowest_poll_ts)
                    macs.lowest_poll_ts = (poll_resp_ts - RXTX_DELAY);
                }
              #endif
          #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
            RTTL1_FILL_UL_PDTCH(cs_type, tx_allocation_s & (0x80 >> poll_resp_ts), poll_resp_ts + l1a_l1s_com.dl_tn)
          #endif

          // a_ul_buffer_gprs updating
          macs.ul_buffer_index[poll_resp_ts] = i + 8;

          #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
            if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
            {
              trace_info.pdtch_trace.ul_status[poll_resp_ts] |= cs_type << 4;
              trace_info.pdtch_trace.ul_status[poll_resp_ts] |= 1;
            }
          #endif
        } // End if the poll response is processed

        /* If the poll response isn't processed */
        /*--------------------------------------*/
        else
        {
          // All allocation parameters that may have been modified to map
          // this poll response are restored
          macs.tx_allocation = tx_allocation_s;
          macs.rx_allocation = rx_allocation_s;
          macs.tx_data       = tx_data_s;
          highest_ul_ts      = highest_ul_ts_s;
          lowest_ul_ts       = lowest_ul_ts_s;

        #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
          if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
            trace_info.pdtch_trace.blk_status |= 0x01;
        #endif

        #if MACS_STATUS
          l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb]= POLL_ERROR_MS_CLASS;
          l1ps_macs_com.macs_status.nb ++;
        #endif

        #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
          RTTL1_FILL_MACS_STATUS(POLL_REJECT, poll_resp_ts)
        #endif
        } // End if the poll response isn't processed
            //The trace for poll response
            #if FF_TBF
              #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
                if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_POLL_PARAM)
                {
                   Trace_rlc_poll_param ( poll, //Indicate whether L1 is going to transmit poll resp or not: 0-no, 1-yes
                                                     l1s.next_time.fn, //next frm on whih poll resp will be sent
                                                     poll_resp_ts, //Timseslot for poll response
                                                     macs.tx_allocation,
                                                     (UWORD32)macs.tx_data,
                                                     macs.rx_allocation,
                                                     (UWORD32)macs.last_poll_response,
                                                     ((NDB_PTR->a_pu_gprs[i][0]) & CS_GPRS_MASK));

                }
              #endif
            #endif
        i ++;

      } /* End while a poll response is requested and can be mapped */

      /*---------------------------------------------------------*/
      /* Uplink RLC/MAC data blocks processing                   */
      /*---------------------------------------------------------*/

      i                          = 0;
      ts                         = 0;
      macs.rlc_blocks_sent       = 0;

      // tx_data_s represents here the remaining timeslots that must be associated
      // with a RLC/MAC data block
      tx_data_s                  = macs.tx_data;

      /* While a timeslot is available to transmit an uplink RLC/MAC data block */
      while (tx_data_s != 0)
      {
        /* If slot is allocated for data transfer */
        if (macs.tx_data & (MASK_SLOT0 >> ts))
        {
          UWORD8 cs_type = (((UWORD8) NDB_PTR->a_du_gprs[i][0]) & 0xF);

          /* If no RLC/MAC block is sent by RLC */
          /*------------------------------------*/

          if (cs_type == CS_NONE_TYPE)
          {
            // All uplink timeslots used for data and situated after this timeslot
            // (inluding this timeslot) are removed
            macs.tx_allocation &= (UWORD8) (~(  macs.tx_data  & (MASK_ALL_SLOTS >> ts)));
            macs.tx_data &= (UWORD8) (~(MASK_ALL_SLOTS >> ts));
            tx_data_s = 0;

            #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
              RTTL1_FILL_MACS_STATUS(TX_ALLOWED_NO_BLK, ts)
                  #if FF_TBF
                    //Update the ul_status fileds for cond PDTCH trace
                    //Since this blcok doesn't have any valid CS scheme, cs_type=0 and payload=11
                    if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
                    {
                      //Bits7,6,5,4 (cs_type)of ul_status should all be zeros
                      trace_info.pdtch_trace.ul_status[ts] &= 0x0f;
                      //Make the payload as NA
                      trace_info.pdtch_trace.ul_status[ts] |= 0x03;
                    }
                  #endif
            #endif
          }

          /* Else: uplink RLC/MAC data block transfer processing */
          /*-----------------------------------------------------*/
          else
          {
            #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
              if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
              {
                trace_info.pdtch_trace.ul_status[ts] |= ((UWORD8) cs_type) << 4;
                trace_info.pdtch_trace.ul_status[ts] |= 2;
              }
            #endif

            /* A data block is assigned to timeslot ts */
            tx_data_s &= (UWORD8) (~(MASK_SLOT0 >> ts));
            /* rlc_blocks_sent value processed */
            macs.rlc_blocks_sent ++;
            /* Uplink buffer index stored in ul_buffer_index */
            macs.ul_buffer_index[ts] = i;

            /* Next data block */
            i ++;
          }

        } /* End if slot allocated for data transfer */

        /* Next timeslot */
        ts ++;
      } /* End while */

    } /* End of poll responses / uplink blocks processing */

    /***********************************************************/
    /* Measurement gap allocation                              */
    /***********************************************************/

    l1ps_macs_meas();

  #if MACS_STATUS
    if (macs.pwr_allocation == 0)
    {
      l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = NO_MEAS_MAPPED;
      l1ps_macs_com.macs_status.nb ++;
    }
  #endif

    // Initialize the reception block period
    macs.rx_blk_period   = NO_DL_BLK;

  } /* End if next frame is the first of a block period */

  /***********************************************************/
  /* RLC_DOWNLINK call enabling for uplink PDCH status       */
  /***********************************************************/

  //                                                           FN 13
  //    0   1   2   3    4   5   6   7    8   9   10  11   12
  // ----------------------------------------------------------
  // ||       B0      ||       B1      ||       B2      || I ||
  // ||   |   |   |   || X |   |   |   || X |   |   |   || X ||
  // ----------------------------------------------------------

  if (   (l1s.actual_time.fn_mod13 == 4)
      || (l1s.actual_time.fn_mod13 == 8)
      || (l1s.actual_time.fn_mod13 == 12))
  {
        #if (FF_TBF)
          l1ps_macs_rlc_uplink_info();
        #else
    l1ps_macs_com.rlc_downlink_call = TRUE;
        #endif

    // RTT: trace UL PDTCH blocks
    #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
      if (SELECTED_BITMAP(RTTL1_ENABLE_UL_PDTCH))
      {
        UWORD8 i,j = 0;

        for(i=2; i < 8; i++)
        {
          if (macs.tx_data & (0x80 >> i))
          {
            RTTL1_FILL_UL_PDTCH((((UWORD8) NDB_PTR->a_du_gprs[j][0]) & 0xF), 1, i)
            j++;
          }
        }
      }
    #endif
  }

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


  /***********************************************************/
  /* MAC-S control result for LAYER 1                        */
  /***********************************************************/

  /* We update allocation structures in Layer 1 - MAC-S interface */
  l1ps_macs_com.rx_allocation       = macs.rx_allocation;
  l1ps_macs_com.tx_nb_allocation    = macs.tx_allocation & (~macs.tx_prach_allocation);
  l1ps_macs_com.tx_prach_allocation = macs.tx_prach_allocation;
  l1ps_macs_com.pwr_allocation      = macs.pwr_allocation;


  #if FF_L1_IT_DSP_USF
    // When dynamic allocation is in use for uplink TBF, notifies L1S about
    // USF uncertainty for FN%13=3 and 7
    if (l1ps_macs_com.usf_status != USF_IT_DSP)
    {
      if (macs.usf_vote_enable)
        l1ps_macs_com.usf_status = USF_AWAITED;
      else
        l1ps_macs_com.usf_status = USF_AVAILABLE;
    }
  #endif // FF_L1_IT_DSP_USF

  /***********************************************************/
  /* DSP programming                                         */
  /***********************************************************/

  // Write uplink blocks - timeslots correspondance in a_ul_buffer_gprs
  // MAC mode in d_sched_mode_gprs and the USF table in a_usf_gprs (Each frame)

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

  l1pddsp_transfer_mslot_ctrl
      (l1s.next_time.fn_mod13_mod4,                   // Burst number (0 to 3)
       macs.rx_allocation,                            // DL Bitmap
       macs.tx_allocation,                            // UL Bitmap
       SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_table, // USF table
       SET_PTR->mac_mode,                             // MAC mode
       macs.ul_buffer_index,                          // UL buffer index
       SET_PTR->tsc,                                  // Training sequence code
       l1a_l1s_com.dedic_set.radio_freq,              // Radio Freq. used for I/Q swap.
       l1a_l1s_com.dl_tn,                             // DL Transfer Sync. TN.
         #if FF_L1_IT_DSP_USF
           macs.dsp_usf_interrupt                         // USF interrupt activation
         #else
           macs.usf_vote_enable                           // USF vote activation
         #endif
       );


  /*****************************************************************/
  /* TBF parameters saving and updating                            */
  /* last_rx_allocation, TFI, rlc_blocks_sent and last_poll_error  */
  /*****************************************************************/

  //                                                           FN 13
  //    0   1   2   3    4   5   6   7    8   9   10  11   12
  // ----------------------------------------------------------
  // ||       B0      ||       B1      ||       B2      || I ||
  // ||   |   |   | X ||   |   |   | X ||   |   |   | X ||   ||
  // ----------------------------------------------------------

  if (   (l1s.next_time.fn_mod13 == 3)
      || (l1s.next_time.fn_mod13 == 7)
      || (l1s.next_time.fn_mod13 == 11))
  {
    // Downlink blocks to report to RLC
    macs.last_rx_alloc  = macs.rx_allocation;
    macs.rx_blk_period  = l1s.next_time.block_id + 1;
    if (macs.rx_blk_period > MAX_BLOCK_ID)
      macs.rx_blk_period -= (UWORD32) (MAX_BLOCK_ID + 1);

    // Synchronization memorization for synchro. change detection
    macs.old_synchro_ts = l1a_l1s_com.dl_tn;

    macs.tx_allocation       = 0;
    macs.tx_prach_allocation = 0;
  } /* End if FN13 = 2, 6 OR 10 */

} /* END OF L1PS_MACS_CTRL() */

/*-----------------------------------------------------------*/
/* l1ps_macs_read()                                          */
/*-----------------------------------------------------------*/
/* Parameters: global l1ps_macs_com           unchanged      */
/*             global l1s                     unchanged      */
/*             global l1a_l1s_com             unchanged      */
/*             global l1ps_dsp_com            changed        */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: l1ps_macs_read checks the last received      */
/*              downlink blocks. It checks if the TFI field  */
/*              is present and good in the block header and  */
/*              write in the NDB the number of received      */
/*              received blocks and on which timeslot was    */
/*              received each data block and how much block. */
/*              Then the RLC layer is called (rlc_downlink)  */
/*-----------------------------------------------------------*/
void l1ps_macs_read(UWORD8 pr_table[8])
{
  #define NDB_PTR  l1ps_dsp_com.pdsp_ndb_ptr

  /***********************************************************/
  /* Downlink RLC/MAC block management                       */
  /***********************************************************/

  // If we are in the first frame after a block period */
  //                                                           FN 13
  //    0   1   2   3    4   5   6   7    8   9   10  11   12
  // ----------------------------------------------------------
  // ||       B0      ||       B1      ||       B2      || I ||
  // ||   |   |   |   || X |   |   |   || X |   |   |   || X ||
  // ----------------------------------------------------------
  //                                         X: Received downlink RLC/MAC block management
  if (  (l1s.actual_time.fn_mod13 == 4)
      ||(l1s.actual_time.fn_mod13 == 8)
      ||(l1s.actual_time.fn_mod13 == 12))
  {
    UWORD8            ts;            // Timeslot pointer
    BOOL              tfi_result;    // Set to 1 if the TFI field is present and good
    #if FF_TBF
      UWORD8         cs_type;
      BOOL           crc_error = 0;
    #endif

    /* For each radio block allocated for downlink transfer in the last block period */
    for (ts = 0; ts < TS_NUMBER; ts ++)
    {
      if (macs.last_rx_alloc & (MASK_SLOT0 >> ts))
      {
        l1ps_macs_header_decoding(macs.rx_no, &tfi_result, &(pr_table[ts]));

        #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
          if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
          {
            trace_info.pdtch_trace.dl_status[macs.rx_no] |= tfi_result << 4;
            #if FF_TBF
                  crc_error = NDB_PTR->a_dd_gprs[macs.rx_no][0] & (1<<B_CRC_BLOCK_ERROR);
                  //In the case of GPRS b_cs_type is 4bit info.
                  cs_type = NDB_PTR->a_dd_gprs[macs.rx_no][0] & CS_GPRS_MASK;
              #if L1_EGPRS
                }
              #endif
              //If the blcok received is in CRC error, update the bit0 of dl_status as 1
              if (crc_error == (1<<B_CRC_BLOCK_ERROR))
              {
                trace_info.pdtch_trace.dl_status[macs.rx_no] |= 0x01;
              }
              else
              {
                // No CRC error. Good Block
                //dl_cs_type used only for BINARY TRACE. We put the following limitation so that
                //in the case of EGPRS with MCS we don't enter here.
                if ((cs_type > CS1_TYPE_DATA) && (cs_type <= CS4_TYPE))
                {
                  trace_info.pdtch_trace.dl_cs_type |= ((cs_type - 3) & 3) << (macs.rx_no * 2);
                }
              }
            #else
            if (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[macs.rx_no][0] & 0x0100) // CRC error
              trace_info.pdtch_trace.dl_status[macs.rx_no] = 1;
            else
            {
              // CS type
              UWORD8 cs_type = NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0xf;

              if (cs_type != CS1_TYPE_DATA)
                trace_info.pdtch_trace.dl_cs_type |= ((cs_type - 3) & 3) << macs.rx_no;
            }
            #endif
          }
        #endif

        // TFI filtering result stored in the downlink block buffer header
        NDB_PTR->a_dd_gprs[macs.rx_no][0] &= (API) (TFI_BIT_MASK);
        NDB_PTR->a_dd_gprs[macs.rx_no][0] |= (API) (tfi_result << TFI_BIT_SHIFT);

        /*---------------------------------------------------------*/
        /* Timeslot and Rx_no values updating                      */
        /*---------------------------------------------------------*/

        // Timeslot number (relative to the network) on which the block was received is
        // stored in the downlink block buffer header

        NDB_PTR->a_dd_gprs[macs.rx_no][1] = ts + l1a_l1s_com.dl_tn;

        #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4)
          RTTL1_FILL_DL_PDTCH((UWORD8) (NDB_PTR->a_dd_gprs[macs.rx_no][4]),    \
                              tfi_result,                                      \
                              NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0x0100 >> 8, \
                              NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0x000f,      \
                              ts + l1a_l1s_com.dl_tn)
        #endif

        macs.rx_no ++;

      } /* End if timeslot was allocated in downlink for the last block period */
    } /* Next timeslot (FOR statement) */

    #if FF_TBF
      //The "rlc_downlink_bufferize_param" structure is used to memorize parameters
      //over a block period in order to cope with spreading issue.
      //
      // C|W R    |
      //  |C W R  |
      //  |  C W R|       TBF 1
      //  |    C W|R <------------
      //----------------------
      //  |      C|W R <--------------
      //  |       |C W R
      //  |       |  C W R       TBF 2
      //  |       |    C W R
      //                   ^
      //                   |
      //                   worst case where the rlc_downlink() function can be called
      //                   when spreading occurs

      //the case above depicts a new TBF assignment without change of the synchronization:
      //as the call to the rlc_downlink() function (that needs among other the assignment id parameter)
      //can be delayed due to spreading, the assignment id of TBF 1 should be memorized
      //until the call of the rlc_downlink() function that handles the last block of TBF 1

      l1ps_macs_com.rlc_downlink_bufferize_param.allocated_tbf = l1ps.read_param.allocated_tbf;
      l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id = l1ps.read_param.assignment_id;
      #if L1_EGPRS
        l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode      = l1ps.read_param.tbf_mode;
      #endif

      // New buffer to be allocated
      macs.dl_buffer_index = INVALID;
      // Initialize spreading counter
      macs.tdma_delay = 0;

      // rlc_uplink_info() invokation in case of block skipped due to resynchro
      // See L1_MCU-CHG-17924
      if (l1s.task_status[PDTCH].current_status != RE_ENTERED)
        l1ps_macs_rlc_uplink_info();
    #endif
    /***********************************************************/
    /* RLC_DOWNLINK call enabling for downlink PDCH status     */
    /***********************************************************/
    l1ps_macs_com.rlc_downlink_call = TRUE;

    #if (TRACE_TYPE==1) || (TRACE_TYPE==4)
    #if L1_BINARY_TRACE == 0
      if (trace_info.current_config->l1_dyn_trace & (1<<L1_DYN_TRACE_DL_PDTCH_CRC))
      {
        BOOL    crc_error=0;
        UWORD8  i;

        for(i=0;i<macs.rx_no;i++)
          crc_error |= ((NDB_PTR->a_dd_gprs[i][0] & 0x0100) >> (1+i));

        Trace_Packet_Transfer(crc_error); // Previous RX blocks CRC_ERROR summary
      }
    #endif
    #endif

  } /* End if first frame after a block period */

} /* END OF L1PS_MACS_READ */

/*-----------------------------------------------------------*/
/* l1ps_macs_meas()                                          */
/*-----------------------------------------------------------*/
/* Parameters: global l1ps_macs_com           unchanged      */
/*             global l1a_l1s_com             unchanged      */
/*             static macs.rx_allocation      unchanged      */
/*             static macs.tx_allocation      unchanged      */
/*             static macs.pwr_allocation     changed        */
/* Return:                                                   */
/*                                                           */
/* Description: This function processes the power measurement*/
/*              gap according to the MS class and timeslots  */
/*              allocated in macs.tx_allocation and          */
/*              macs.rx_allocation fields.                   */
/*-----------------------------------------------------------*/
void l1ps_macs_meas()
{
  #define SET_PTR l1pa_l1ps_com.transfer.aset

  WORD8  ts                = 7;       // Timeslot pointer
  UWORD8 gap               = 0;       // Gap size counter
  UWORD8 meas              = 0;       // Temporary gap processing
  UWORD8 bitmap_rx, bitmap_tx;

  macs.pwr_allocation = 0;
  bitmap_rx = macs.rx_allocation;
  bitmap_tx = macs.tx_allocation;

  // Searching of the last allocated timeslot
  // Note: Layer 1 always synchronize on a RX event, so the Tra gap will always
  //       be found after the last allocated timeslot of a frame

  while (   (ts >= 0)
         && ((bitmap_rx & 0x01) == 0)
         && ((bitmap_tx & 0x01) == 0))
  {
    // Memorization of the timeslot
    meas |= (UWORD8) (MASK_SLOT0 >> ts);
    // Gap is incremented
    gap ++;

    bitmap_rx >>= 1;
    bitmap_tx >>= 1;
    ts --;
  }

  // Last allocated timeslot: ts
  // Power gap size: gap

  // Save the "tra gap" at the end of the frame
  macs.tra_gap = gap;

  // If Tra respected before the first Rx of the frame after
  // Here we consider that L1 is ALWAYS synchronized on a RX timeslot
  if (gap >= MS_CLASS[SET_PTR->multislot_class].tra)
  {
    // The gap is allocated
    macs.pwr_allocation |= meas;
  }
  else
  // If the first slot of the next frame is free and permit to respect the Tra parameter
  // in fixed mode
  // Notes:
  // - if Tra not respected and the current slot 0 isn't allocated --> the slot 0 of
  //   the next frame will not be allocated (only possible in Fixed mode)
  // - in all cases, only one timeslot need to be removed
  if (   (gap + 1 >= MS_CLASS[SET_PTR->multislot_class].tra)
      && (!(macs.rx_allocation & MASK_SLOT0)))
  {
    // The gap is allocated
    macs.pwr_allocation |= meas;
  }

#if L1_EDA
  //if in extended dynamic allocation and if no power measurement is set in Tra gap (Tra not fulfilled)
  //then power measurement is set in Tta gap if MS class supports it.
  if ((SET_PTR->mac_mode == EXT_DYN_ALLOC) && (!macs.pwr_allocation))
  {
    UWORD8  i = MAX_TS_NB;

    //compute tta
    while (!(macs.rx_allocation & (MASK_SLOT0 >> i)))
     i--;

    i++;
    gap = 0;
    meas = 0;
    while (!(macs.tx_allocation & (MASK_SLOT0 >> i)))
    {
     gap++;
     meas |= (UWORD8) (MASK_SLOT0 >> i);
     i++;
    }

    if (gap <= MS_CLASS[SET_PTR->multislot_class].tta)
      macs.pwr_allocation |= meas;
  }
#endif //#if L1_EDA
} /* End of l1ps_macs_meas */

/*-----------------------------------------------------------*/
/* l1ps_macs_header_decoding()                               */
/*-----------------------------------------------------------*/
/* Parameters:                                               */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: This function process the TFI filtering and  */
/*              decode the PR value in the MAC header of the */
/*              block stored in buffer rx_no.                */
/*-----------------------------------------------------------*/
void l1ps_macs_header_decoding(UWORD8 rx_no, UWORD8 *tfi_result, UWORD8 *pr)
{
  UWORD8            payload;       // Payload type value in the RLC/MAC header
  UWORD8            tfi;           // TFI value
  UWORD16           mac_header[2]; // Downlink block MAC header

  *pr = 0;

  // DSP Driver
  // Downlink block MAC header reading

  mac_header[0] = NDB_PTR->a_dd_gprs[rx_no][4];
  mac_header[1] = NDB_PTR->a_dd_gprs[rx_no][5];

  *tfi_result = TFI_NOT_FILTERED;

#if TFI_FILTERING

  /*---------------------------------------------------------*/
  /* TFI Filtering                                           */
  /*---------------------------------------------------------*/

  *tfi_result = TFI_BAD;

  /* Payload reading in the block header */
  /*-------------------------------------*/

  payload = (UWORD8) (((mac_header[0]) >> PAYLOAD_SHIFT) & PAYLOAD_MASK);

  #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
    if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
    {
      trace_info.pdtch_trace.dl_status[rx_no] |= payload << 6;
      // RRBP + S/P trace
      trace_info.pdtch_trace.dl_status[rx_no] |= (mac_header[0] & (0x38)) >> 2;
    }
  #endif

  /* If the payload time isn't "RESERVED" */
  if (payload != RESERVED)
  {
    /* Data block case, processed if a downlink TBF is assigned */
    /*----------------------------------------------------------*/

    if (payload == DATA_BLOCK)
    {
      *pr = (UWORD8) ((mac_header[0] >> DATA_PR_SHIFT) & PR_MASK);

      if ((l1ps.read_param.allocated_tbf == DL_TBF) || (l1ps.read_param.allocated_tbf == BOTH_TBF))
      {
        // TFI value reading
        tfi = (UWORD8) ((mac_header[0] & DATA_TFI_MASK) >> DATA_TFI_SHIFT);

        // Downlink TFI control
        if (tfi == l1ps.read_param.dl_tfi)
        {
          *tfi_result    = TFI_GOOD;
        }
      } // End if "downlink TBF enabled"

    } /* End of data block case */

    /* Control block case */
    /*--------------------*/

    else
    {
      /* Optionnal field is no present */
      if (payload == CTRL_NO_OPTIONAL)
        *tfi_result = TFI_NOT_PRESENT;

      /* Optionnal field is present */
      if (payload == CTRL_OPTIONAL)
      {
        *pr = (UWORD8) ((mac_header[1] >> CTRL_PR_SHIFT) & PR_MASK);

        /* AC = 1 : TFI is present */
        if (mac_header[0] & AC_MASK)
        {
          // TFI value reading
          tfi = (UWORD8) ((mac_header[1] & CTRL_TFI_MASK) >> CTRL_TFI_SHIFT);

          /* If direction is downlink TBF (D = 1) and a downlink TBF is in progress */
          if ( mac_header[1] & MASK_D)
          {
            if (   (l1ps.read_param.allocated_tbf == DL_TBF)
                || (l1ps.read_param.allocated_tbf == BOTH_TBF))
            {
              // Downlink TFI value is checked
              if (tfi == l1ps.read_param.dl_tfi)
              {
                *tfi_result = TFI_GOOD;
              }
            }
          } /* End if direction is downlink */

          /* If direction is uplink TBF (D = 0) and an uplink TBF is in progress */
          else if (   (l1ps.read_param.allocated_tbf == UL_TBF)
                   || (l1ps.read_param.allocated_tbf == BOTH_TBF))
          {
            // Uplink TFI value is checked
            if (tfi == l1ps.read_param.ul_tfi)
            {
              *tfi_result = TFI_GOOD;
            }

          } /* End if direction is uplink */

        } /* End if AC = 1 */

        /* AC = 0 : TFI is no present */
        else
          *tfi_result = TFI_NOT_PRESENT;

      } // End if control block with optionnal field

    } // End of control block case

  } // End if PAYLOAD != "RESERVED"

#endif

  /*---------------------------------------------------------*/
  /* pr_table updating                                       */
  /*---------------------------------------------------------*/

  if(l1ps.read_param.dl_pwr_ctl.p0 == 255)
    *pr = 0; // PR unused in "No power control" mode
  else
    *pr = PR_CONVERSION[l1ps.read_param.dl_pwr_ctl.bts_pwr_ctl_mode][*pr];

  // If TFI isn't good
  if (*tfi_result != TFI_GOOD)
  {
    // Set bit 7 to 1
    *pr |= 0x80;
  }

}

/*-----------------------------------------------------------*/
/* l1ps_macs_rlc_downlink_call()                             */
/*-----------------------------------------------------------*/
/* Parameters:                                               */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: This function is called at the end of L1S    */
/*              execution if RLC_DOWNLINK must be called.    */
/*                                                           */
/*-----------------------------------------------------------*/
void l1ps_macs_rlc_downlink_call(void)
{
  UWORD8 i;
  #if FF_TBF
    UWORD32         fn;
    BOOL            rlc_dl_call = FALSE;
    API*            rlc_buffer;
    API*            dummy_rlc_buffer = NULL;

    //correct reporting of FN to L3 should be TDMA 4, 8 or 12 of MF13
    fn=l1s.actual_time.fn-l1s.actual_time.fn_mod13_mod4;

    //when fn is in first block of the MF13 (which value is not a correct value
    //to report to upper layer) then fn should be decremented so that fn%13 = 12
    if(l1s.actual_time.fn_mod13 <= 3)
      fn--;

    //to cope with border case
//    if (fn < 0)  //OMAPS00090550
//      fn += MAX_FN - 1; //OMAPS00090550

    // Retrieve decoded blocks from API. All payload decoded check.
    if (!rlc_downlink_copy_buffer(FALSE))
    {
      // Flag RLC call
      rlc_dl_call = TRUE;

      // RLC buffer exhaustion check
      if ((macs.dl_buffer_index == INVALID) || (l1a_l1s_com.recovery_flag))
      {
        if (macs.tdma_delay >= 3)
        {
          // No block reported ever by DSP
      //    #if (TRACE_TYPE==1) || (TRACE_TYPE==4)
      //      l1_trace_egprs(NO_BLOCKS_PASSED_TO_L3);
       //   #endif

          #if (TRACE_TYPE==5)
            trace_fct_simu("MACS ERROR: No RLC blocks passed to L3 on current frame", 0);
            sprintf(errormsg,"MACS ERROR: No RLC blocks passed to L3 on current frame");
            log_sim_error(ERR);
          #endif
        }
        else
        {
          // No RLC buffer available

          #if (TRACE_TYPE==5)
            trace_fct_simu("MACS ERROR: No free buffer to copy RLC blocks on current frame", 0);
            //sprintf(errormsg,"MACS ERROR: No free buffer to copy RLC blocks on current frame");
            //log_sim_error(ERR);
          #endif
        }

        // Dummy buffer to be reported
        rlc_buffer = (API*) dummy_rlc_buffer;
      }
      // RLC buffer has been succesfully allocated
      else
      {
        // RLC buffer to be reported
        rlc_buffer = (API*) &(macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs);

        #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4)
          #if L1_BINARY_TRACE == 0
            if (trace_info.current_config->l1_dyn_trace & (1<<L1_DYN_TRACE_DL_PDTCH_CRC))
            {
              BOOL    crc_error=0;
              UWORD8  i;
              #if L1_EGPRS
                if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS)
                {
                  for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++)
                    crc_error |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> (1+i));
                }
                else
              #endif
                {
                  for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++)
                    crc_error |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_gprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> (1+i));
                }
              Trace_Packet_Transfer(crc_error); // Previous RX blocks CRC_ERROR summary
            }
          #endif
        #endif
        #if L1_EGPRS
          // IR testing specific trace
          #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4)
            if ((trace_info.current_config->l1_dyn_trace & (1<<L1_DYN_TRACE_IR))
                && (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS))
            {
              UWORD8 j ;
              // Clear ir trace variables
              trace_info.ir_trace.crc    = 0;
              trace_info.ir_trace.mcs    = 0;
		          trace_info.ir_trace.status_ir_tfi = 0;
              trace_info.ir_trace.puncturing = 0;

              for(j=0;j<MS_CLASS[MAX_CLASS].rx;j++)
              {
                trace_info.ir_trace.bsn[j] = 0;
                trace_info.ir_trace.cv_bep_egprs[j]= 0;
		            trace_info.ir_trace.mean_bep_egprs[j] = 0;
              }

              // Retrieve IR info from every PDCH
              for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++)
              {
                UWORD16 crc;
                UWORD16 bsn1, bsn2;
                UWORD8  mcs;
                UWORD8  cps;
                UWORD8  k;

                // retrieve coding scheme
                mcs = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & CS_EGPRS_MASK);

                j = k = 0 ;

                // retrieve BSN
                switch (mcs)
                {
                  case CS1_TYPE_POLL:
                  case CS1_TYPE_DATA:
                  case CS2_TYPE:
                  case CS3_TYPE:
                  case CS4_TYPE:
                    // GPRS data block
                    if ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) || (mcs == CS1_TYPE_POLL))
                      bsn1 = 0xffff;
                    else
                      bsn1 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] >> 1) & 0x7f);
                    bsn2 = 0;

                    crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_BLOCK_ERROR)));
                    crc = (crc >> B_CRC_HEADER_ERROR);
                    break;

                  case MCS1_TYPE:
                  case MCS2_TYPE:
                  case MCS3_TYPE:
                  case MCS4_TYPE:
                    // rlc mac header type 3
                    cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1]) >> 9) & 0x0F ;
                    j = 255 ; // cps is set
                  case MCS5_TYPE:
                  case MCS6_TYPE:
                      // rlc mac header type 2
                    if (j != 255)
                    {
                      cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1]) >> 9) & 0x07 ;
                    }
                    do
                    {
                      if (cps == CPS_value1_6[k][mcs-MCS1_TYPE])
                      { // set puncturing scheme for payload 1 and 2: 0x01 PS1 0x10 PS2 0x11 PS3 related to time slot i
                        trace_info.ir_trace.puncturing |= (((k+1) << 2) << (4*(3-i))) ;
                        break ;
                      }
                      k++;
                    } while (k < 3) ;

                    // EGPRS data block, Header Type 2 and 3
                    if (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_HEADER_ERROR))
                      bsn1 = 0xffff;
                    else
                    {
                      bsn1 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 0] >> 14) & 0x03);
                      bsn1 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] & 0x1ff) << 2);
                    }
                    bsn2 = 0;

                    crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_BLOCK_ERROR)));
                    crc = (crc >> B_CRC_HEADER_ERROR);
                    break;

                  case MCS7_TYPE:
                  case MCS8_TYPE:
                  case MCS9_TYPE:
                    // rlc mac header type 1
                    cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 2]) >> 3) & 0x1F ;
                    do
                    {
                      if (cps == CPS_value7_9[j][k][mcs-MCS7_TYPE])
                      {  // set puncturing scheme for payload 1 and 2: 0x01 PS1 0x10 PS2 0x11 PS3 related to time slot i
                        trace_info.ir_trace.puncturing |= ((((j+1) << 2) | (k+1)) << (4*(3-i))) ;
                        break ;
                      }
                      k++;
                      if (k == 3)
                      {
                        k = 0;
                        j++ ;
                      }
                    } while (j < 3) ;

                    // EGPRS data block, Header Type 1
                    if (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_HEADER_ERROR))
                    {
                      bsn1 = 0xffff;
                      bsn2 = 0xffff;
                    }
                    else
                    {
                      bsn1 =  ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 0] >> 14) & 0x03);
                      bsn1 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] & 0x1ff) << 2);

                      bsn2 =  ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] >> 9) & 0x7f);
                      bsn2 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 2] & 0x07) << 7);
                      bsn2 += bsn1;
                      if (bsn2 >= 2048)
                        bsn2 -= 2048;
                    }

                    crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_PAYLOAD2_ERROR) + (1 << B_CRC_BLOCK_ERROR)));
                    crc = (crc >> B_CRC_HEADER_ERROR);
                    break;

                  default:
                    bsn1 = 0xffff;
                    bsn2 = 0xffff;
                    crc = ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_PAYLOAD2_ERROR) + (1 << B_CRC_BLOCK_ERROR));
                    crc = (crc >> B_CRC_HEADER_ERROR);
                    break;
                }

                // Update IR info from current PDCH
                trace_info.ir_trace.crc    |= (crc << ((3-i)*8));
                trace_info.ir_trace.bsn[i] =  ((bsn1 << 16) | bsn2);
                trace_info.ir_trace.mcs    |= ((mcs << ((3-i)*8)));

                /* we take only the msb of cv_bep and mean_bep */
                trace_info.ir_trace.cv_bep_egprs[i] = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][2]) >> 8) ;
                trace_info.ir_trace.mean_bep_egprs[i] = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][3]) ;
                if (((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & TFI_BIT_MASK) >> TFI_BIT_SHIFT) == TFI_BAD)
                  trace_info.ir_trace.status_ir_tfi |= (0x1 << (3-i)) ; /* set tfi flag to 1 if block is not for MS */
              }

              trace_info.ir_trace.fn = l1s.actual_time.fn ;
              trace_info.ir_trace.status_ir_tfi |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status & (1 << IR_OUT_OF_MEMORY))<<(7-IR_OUT_OF_MEMORY)) ;

             // Output trace
              Trace_IR (&trace_info.ir_trace) ;
            }
          #endif //(TRACE_TYPE == 1)||(TRACE_TYPE == 4)
        #endif //L1_EGPRS
        #if TESTMODE
          if (l1_config.TestMode)
          {
            BOOL    crc_error_bler; //Local var used for accumulating BLER
            UWORD8  i;

            l1tm.tmode_stats.bler_total_blocks++;
            #if L1_EGPRS
              if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS)
              {
                for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++)
                {
                  //bler_total_blocks gives the total number of blocks for computing BLER
                  //The block error is assigned to crc_error_bler.
                  //If the block is in error bler_crc is incremented.
                  crc_error_bler = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> B_CRC_BLOCK_ERROR);
                  if (crc_error_bler == TRUE)
                    l1tm.tmode_stats.bler_crc[i]++;
                }
              }
              else
            #endif
              {
                for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++)
                {
                  //bler_total_blocks gives the total number of blocks for computing BLER
                  //The block error is assigned to crc_error_bler.
                  //If the block is in error bler_crc is incremented.
                  crc_error_bler = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_gprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> B_CRC_BLOCK_ERROR);
                  if (crc_error_bler == TRUE)
                    l1tm.tmode_stats.bler_crc[i]++;
                }
              }
          }
        #endif
      }
    }
    // Payload still awaited
    else // (!rlc_downlink_copy_buffer(FALSE)
    {
      // Check spreading limit not exceeded
      if ((macs.tdma_delay >= 3) || (l1a_l1s_com.recovery_flag))
      {
        // Free RLC buffer
        macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs = RLC_BLOCK_ACK;

        // Flag RLC call
        rlc_dl_call = TRUE;

        // Dummy buffer to be reported
        rlc_buffer = (API*) dummy_rlc_buffer;

        // No block reported ever by DSP

        #if (TRACE_TYPE==5)
          trace_fct_simu("MACS ERROR: No RLC blocks passed to L3 on current frame", 0);
          sprintf(errormsg,"MACS ERROR: No RLC blocks passed to L3 on current frame");
          log_sim_error(ERR);
        #endif
      }
      else
        // Increment spreading counter
        macs.tdma_delay++;
    } // (!rlc_downlink_copy_buffer(FALSE)

    // Function RLC_DOWNLINK_DATA() to be invoked
    if (rlc_dl_call)
    {

      rlc_downlink_data( l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id, // Assignment ID
                         fn,                                                       // Frame number
                         rlc_buffer                                                // Pointer on the DL structure
                       );

      // Add the RLC_D traces in the case of EGPRS also

      #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
        if ((trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_RLC_PARAM)
           && (rlc_buffer != NULL))
        {
          UWORD8 i;
          UWORD16 dl_blk_status[4] = {0,0,0,0};
          for (i=0;i<macs.rx_no;i++)
          {
            #if (L1_EGPRS)
              if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS)
              {
                dl_blk_status[i] = A_DD_XGPRS[TBF_MODE_EGPRS][i][0];
              }
              else
              {
            #endif
                dl_blk_status[i] = (((UWORD8) NDB_PTR->a_dd_gprs[i][0]) & 0x070F);
            #if (L1_EGPRS)
              }
            #endif
          }
          Trace_rlc_dl_param(l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id,
                       l1s.actual_time.fn,
                       macs.rx_no,
                       macs.rlc_blocks_sent,
                       macs.last_poll_response,
                       (dl_blk_status[1]<<16) |dl_blk_status[0], //dl_blk_status for TS1 and TS0
                       (dl_blk_status[3]<<16) |dl_blk_status[2]);//dl_blk_status for TS3 and TS2
        }
      #endif
      macs.rx_no                      = 0;
      l1ps_macs_com.rlc_downlink_call = FALSE;
    }

  #else

  #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
    if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
    {
      // If some RX have been received or some TX have been programmed
      if ((macs.last_rx_alloc != 0) || (macs.tx_allocation != 0))
      {
        // Send trace
        Trace_condensed_pdtch(macs.last_rx_alloc, macs.tx_allocation);
      }

      // Reset PDTCH trace structure
      for(i=0; i<8; i++)
      {
        trace_info.pdtch_trace.dl_status[i] = 0;
        trace_info.pdtch_trace.ul_status[i] = 0;
      }
      trace_info.pdtch_trace.dl_cs_type   = 0;
      trace_info.pdtch_trace.blk_status   = 0;
    }
  #endif


  // Last_poll_error processing
  //---------------------------

  // All slots allocated for poll response transmission (allocated in tx_allocation
  // but not in tx_data) are set to 0 (no error) in last_poll_response
  macs.last_poll_response &= (UWORD8) (~(macs.tx_allocation) | macs.tx_data);

  /* last_poll_response correspondance with network timeslot numbers */
  i = macs.old_synchro_ts - RXTX_DELAY;

  if (i > MAX_TS_NB)
  {
    macs.last_poll_response <<= (-i);
  }
  else
  {
    macs.last_poll_response >>= i;
  }

  // Store number of RX within NDB for RLC
  //--------------------------------------

  NDB_PTR->d_rlcmac_rx_no_gprs = macs.rx_no;

  #if L1_RECOVERY
    // blocks get a CRC error in case of COM error
    if (l1a_l1s_com.recovery_flag == TRUE)
    {
     // force bad CRC for 4 RX slots
      NDB_PTR->a_dd_gprs[0][0] |= 0x0100;
      NDB_PTR->a_dd_gprs[1][0] |= 0x0100;
      NDB_PTR->a_dd_gprs[2][0] |= 0x0100;
      NDB_PTR->a_dd_gprs[3][0] |= 0x0100;
    }
  #endif
  /******************/

  // Call RLC_DOWNLINK
  //------------------

  rlc_downlink( l1ps.read_param.assignment_id,            // Assignment ID
                l1s.actual_time.fn,                       // Frame number
                (API*) &(NDB_PTR->d_rlcmac_rx_no_gprs),   // Pointer on the DL structure
                 macs.rlc_blocks_sent,                    // ID of the last transmitted uplink
                                                          //   data block
                 macs.last_poll_response                  // Status of the poll responses of
              );                                          //   the last block period

  #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
    if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_RLC_PARAM)
    {
      Trace_rlc_dl_param(l1ps.read_param.assignment_id,
                         l1s.actual_time.fn,
                         (UWORD32) &(NDB_PTR->d_rlcmac_rx_no_gprs),
                         (UWORD8)  NDB_PTR->d_rlcmac_rx_no_gprs,
                         macs.rlc_blocks_sent,
                         macs.last_poll_response);
    }
  #endif

      /* FreeCalypso TCS211 reconstruction */
      #if 0 //TESTMODE
          if (l1_config.TestMode)
          {
            BOOL    crc_error_bler; //Local var used for accumulating BLER
            UWORD8  i;

            l1tm.tmode_stats.bler_total_blocks++;

            for(i=0; i < macs.rx_no; i++)
             {
                //bler_total_blocks gives the total number of blocks for computing BLER
                //The block error is assigned to crc_error_bler.
                //If the block is in error bler_crc is incremented.
               crc_error_bler = ( (NDB_PTR->a_dd_gprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> B_CRC_BLOCK_ERROR);
               if (crc_error_bler == TRUE)
                 l1tm.tmode_stats.bler_crc[i]++;
              }
          }
        #endif

  // Clear parameters
  //-----------------

  /* All downlink blocks were processed */
  macs.last_rx_alloc              = 0;
  macs.rx_no                      = 0;
  macs.rlc_blocks_sent            = 0;
  macs.last_poll_response         = 0;

  l1ps_macs_com.rlc_downlink_call = FALSE;

  // Reset CS type.
  //---------------
  #if (DSP == 33)  || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39)
    NDB_PTR->a_dd_gprs[0][0] = NDB_PTR->a_dd_gprs[1][0] = NDB_PTR->a_dd_gprs[2][0] =
    NDB_PTR->a_dd_gprs[3][0] = NDB_PTR->a_dd_gprs[4][0] = NDB_PTR->a_dd_gprs[5][0] =
    NDB_PTR->a_dd_gprs[6][0] = NDB_PTR->a_dd_gprs[7][0] = CS_NONE_TYPE;
  #else
    NDB_PTR->a_dd_gprs[0][0] = NDB_PTR->a_dd_gprs[1][0] = NDB_PTR->a_dd_gprs[2][0] =
    NDB_PTR->a_dd_gprs[3][0] = CS_NONE_TYPE;
  #endif
#endif
}//void l1ps_macs_rlc_downlink_call(void)
#if FF_TBF
/*-----------------------------------------------------------*/
/* l1ps_macs_rlc_uplink_info()                             */
/*-----------------------------------------------------------*/
/* Parameters:                                               */
/*                                                           */
/* Return:                                                   */
/*                                                           */
/* Description: This function is called in the               */
/*              l1ps_macs_ctrl() function on TDMA 4, 8 or 12 */
/*              of MF13                                      */
/*                                                           */
/*-----------------------------------------------------------*/
void l1ps_macs_rlc_uplink_info(void)
{
  UWORD8 i;

  #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4))
    if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH)
    {
      // If some RX have been received or some TX have been programmed
      if ((macs.last_rx_alloc != 0) || (macs.tx_allocation != 0))
      {
        // Send trace
        Trace_condensed_pdtch(macs.last_rx_alloc, macs.tx_allocation);
      }

      // Reset PDTCH trace structure
      for(i=0; i<8; i++)
      {
        trace_info.pdtch_trace.dl_status[i] = 0;
        trace_info.pdtch_trace.ul_status[i] = 0;
      }
      trace_info.pdtch_trace.dl_cs_type   = 0;
      trace_info.pdtch_trace.blk_status   = 0;
    }
  #endif

  // Last_poll_error processing
  //---------------------------

  /* All slots allocated for poll response transmission (allocated in tx_allocation
     but not in tx_data) are set to 0 (no error) in last_poll_response */
  macs.last_poll_response &= (UWORD8) (~(macs.tx_allocation) | macs.tx_data);

  /* last_poll_response correspondance with network timeslot numbers */
  i = macs.old_synchro_ts - RXTX_DELAY;

  if (i > MAX_TS_NB)
  {
    macs.last_poll_response <<= (-i);
  }
  else
  {
    macs.last_poll_response >>= i;
  }

  #if L1_EGPRS
    //sub_mode is ON
    if (l1ps_macs_com.loop_param.sub_mode == TRUE)
    {
      macs.rlc_blocks_sent    = 0;
      macs.last_poll_response = 0;
    }
  #endif

  rlc_uplink_info(l1ps.read_param.assignment_id,
                  l1s.actual_time.fn,
                  macs.rlc_blocks_sent,
                  macs.last_poll_response);

  //While the initialization of these variables is performed in the
  //l1ps_macs_rlc_downlink_call() for GPRS, for EGPRS the initialization
  //is done here below. Note that it is still performed on frame index 0
  //of MF13 in the l1s_end_manager() function whether in EGPRS or GPRS mode.
  //The variable below is set in the l1ps_macs_ctrl() function on frame index 2 of MF13
  //and stores the rx allocation. This allocation is used later in the l1ps_macs_read()
  //function to pass the blocks that were received in the previous block period.
  macs.last_rx_alloc              = 0;
  macs.rlc_blocks_sent            = 0;
  macs.last_poll_response         = 0;
}

/*-----------------------------------------------------------*/
/* rlc_downlink_copy_buffer()                                */
/*-----------------------------------------------------------*/
/* Parameters:  isr: flag that indicates whether the call    */
/*                   of this function is performed at the    */
/*                   beginning of the hisr() function        */
/*                   (hisr = TRUE) or not.                   */
/*                                                           */
/* Return:      missing_payload: flag that indicates if still*/
/*                               payloads are missing after  */
/*                               the copy                    */
/*                                                           */
/* Description: This function is called in the hisr()        */
/*              function with hisr = TRUE and in the         */
/*              l1ps_macs_rlc_downlink_call() function       */
/*              with hisr = FALSE                            */
/*-----------------------------------------------------------*/
  UWORD8 rlc_downlink_copy_buffer(UWORD8 isr)
  {
    BOOL missing_payload   = FALSE;
    BOOL allocation_needed = FALSE;

    UWORD32 i,j;

    // Downlink blocks expected
    if (l1ps_macs_com.rlc_downlink_call)
    {
      // Not in TDMA3 unless we are in ISR so we may have blocks to copy
      if ( ((macs.tdma_delay < 3) && (!isr)) // No logical XOR in C
           || ((macs.tdma_delay >= 3) && (isr))
         )

      {
        // Test buffer allocation requirement if not already allocated
        if (macs.dl_buffer_index == INVALID)
        {
            allocation_needed = TRUE;
        }

        // Look for an available buffer and initialize it
        if (allocation_needed)
        {
          for (i = 0; i < NBR_SHARED_BUFFER_RLC; i++)
          {
            //as soon as one free block is found
            if (macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs == RLC_BLOCK_ACK)
            {
              // Store buffer index
              macs.dl_buffer_index = i;
              // Store number of blocks in buffer passed to RLC
              macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs = macs.rx_no;
              break;
            }
          }
        }

        // Copy available blocks if buffer allocated
        if (macs.dl_buffer_index != INVALID)
        {
          // GPRS mode, no spreading
        #if L1_EGPRS
          if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_GPRS)
        #endif
          {
            // Copy whole bunch of blocks (4 downlink, worst case)
            for (i=0;i<NBR_BUFFER_GPRS;i++)
            {
              memcpy((char*) &macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_gprs[i][0],
                     (char*) A_DD_XGPRS[TBF_MODE_GPRS][i],
                     SIZE_GPRS_DL_BUFF * sizeof(API));
            }
          }
          // EGPRS mode
        #if L1_EGPRS
          else
          {
            // Parse every expected block
            for (i = 0; i < macs.rx_no; i++)
            {
              // If not already copied
              if ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & CS_EGPRS_MASK) == CS_NONE_TYPE)
              {
                // New block available in API
                if (A_DD_XGPRS[TBF_MODE_EGPRS][i][0] & (1 << B_BLK_READY))
                {
                  // Copy block from API to SRAM
                  memcpy((char*) &macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0],
                         (char*) A_DD_XGPRS[TBF_MODE_EGPRS][i],
                         SIZE_EGPRS_DL_BUFF * sizeof(API));

                  // Acknowledge DSP
                  A_DD_XGPRS[TBF_MODE_EGPRS][i][0] &= ~(1 << B_BLK_READY);
                }
                else
                  missing_payload = TRUE;
              }
            }
          } // TBF mode
        #endif

          // Store "missing payload" flag used for TDMA3 limit case.
          macs.dl_missing_payload = missing_payload;

        } // Buffer is allocated
        else
        {
          // No buffer allocated yet
          if (allocation_needed)
            // RLC Buffer exhaustion - abort
            missing_payload = FALSE;
          else
           // No buffer allocated yet as no block present
           missing_payload = TRUE;

          // Still some buffer expected
          macs.dl_missing_payload = TRUE;
        }
      } // Not in ISR TDMA 0,1,2, or ISR from TDMA 3
      else if ((macs.tdma_delay >= 3) && (!isr))
      {
        // End of L1S in TDMA3, we need to report the status from ISR call.
        missing_payload = macs.dl_missing_payload;
      }

      // IR status reporting (relevant for EGPRS only)
      //----------------------------------------------

      // RLC buffer allocated, all blocks received
      if ((macs.dl_buffer_index != INVALID) && (!missing_payload))
      {
      #if L1_EGPRS
        if ( (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS)
             && (l1ps_dsp_com.edsp_ndb_ptr->d_modem_status_egprs & (1 << B_IR_OUT_OF_MEM)) )
        {
          // EGPRS TBF mode, IR out of memory status flag is set
          macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status |= (1 << IR_OUT_OF_MEMORY);
        }
        else
      #endif
        {
          // GPRS TBF mode or EGPRS but IR out of memory not detected
          macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status &= (~(1 << IR_OUT_OF_MEMORY));
        }
      }
    } // if (l1ps_macs_com.rlc_downlink_call)

    // Return blocks receipt completion status
    return missing_payload;
}

#endif //FF_TBF

#if TESTMODE
  //===========================================================================
  // Function called instead of l1ps_macs_ctrl if CMU200 loop mode is selected
  //===========================================================================

  void l1ps_tmode_macs_ctrl(void)
  {
    #define NDB_PTR  l1ps_dsp_com.pdsp_ndb_ptr
    #define SET_PTR  l1pa_l1ps_com.transfer.aset

    NDB_PTR->a_du_gprs[0][0]     = l1_config.tmode.tx_params.coding_scheme;

    /* Enable loop */
    NDB_PTR->d_sched_mode_gprs |= (1<<6);

    // Force single slot allocation for CMU loop: 1RX, 1TX
    macs.rx_allocation = 0x80;
    macs.tx_allocation = 0x10;
    macs.tx_prach_allocation = 0;
    macs.pwr_allocation = 0;

    macs.ul_buffer_index[0] = 0xFF;                          // UL buffer index
    macs.ul_buffer_index[1] = 0xFF;
    macs.ul_buffer_index[2] = 0xFF;
    macs.ul_buffer_index[3] = 0;
    macs.ul_buffer_index[4] = 0xFF;
    macs.ul_buffer_index[5] = 0xFF;
    macs.ul_buffer_index[6] = 0xFF;
    macs.ul_buffer_index[7] = 0xFF;

    /* Disable USF management in the DSP */
    macs.usf_vote_enable = 0;

    /***********************************************************/
    /* MAC-S control result for LAYER 1                        */
    /***********************************************************/

    /* We update allocation structures in Layer 1 - MAC-S interface */
    l1ps_macs_com.rx_allocation       = macs.rx_allocation;
    l1ps_macs_com.tx_nb_allocation    = macs.tx_allocation & (~macs.tx_prach_allocation);
    l1ps_macs_com.tx_prach_allocation = macs.tx_prach_allocation;
    l1ps_macs_com.pwr_allocation      = macs.pwr_allocation;

    /***********************************************************/
    /* DSP programming                                         */
    /***********************************************************/

    // Write uplink blocks - timeslots correspondance in a_ul_buffer_gprs
    // MAC mode in d_sched_mode_gprs and the USF table in a_usf_gprs (Each frame)

    l1pddsp_transfer_mslot_ctrl
        (l1s.next_time.fn_mod13_mod4,                   // Burst number (0 to 3)
         macs.rx_allocation,                            // DL Bitmap
         macs.tx_allocation,                            // UL Bitmap
         SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_table, // USF table
         SET_PTR->mac_mode,                             // MAC mode
         macs.ul_buffer_index,                          // UL buffer index
         SET_PTR->tsc,                                  // Training sequence code
         l1a_l1s_com.dedic_set.radio_freq,              // Radio Freq. used for I/Q swap.
         l1a_l1s_com.dl_tn,                             // DL Transfer Sync. TN.
       #if FF_L1_IT_DSP_USF
         macs.dsp_usf_interrupt                         // USF interrupt activation
       #else
         macs.usf_vote_enable                           // USF vote activation
       #endif
     );

   //NDB_PTR->a_ctrl_ched_gprs[0] = CS1_TYPE_DATA;
   NDB_PTR->a_ctrl_ched_gprs[0] = NDB_PTR->a_du_gprs[0][0];

  }
#endif
#endif // L1_GPRS