view src/cs/layer1/p_cfile/l1p_driv.c @ 685:3fb7384e820d

tpudrv12.h: FCDEV3B goes back to being itself A while back we had the idea of a FreeCalypso modem family whereby our current fcdev3b target would some day morph into fcmodem, with multiple FC modem family products, potentially either triband or quadband, being firmware-compatible with each other and with our original FCDEV3B. But in light of the discovery of Tango modules that earlier idea is now being withdrawn: instead the already existing Tango hw is being adopted into our FreeCalypso family. Tango cannot be firmware-compatible with triband OM/FCDEV3B targets because the original quadband RFFE on Tango modules is wired in TI's original Leonardo arrangement. Because this Leonardo/Tango way is now becoming the official FreeCalypso way of driving quadband RFFEs thanks to the adoption of Tango into our FC family, our earlier idea of extending FIC's triband RFFE control signals with TSPACT5 no longer makes much sense - we will probably never produce any new hardware with that once-proposed arrangement. Therefore, that triband-or-quadband FCFAM provision is being removed from the code base, and FCDEV3B goes back to being treated the same way as CONFIG_TARGET_GTAMODEM for RFFE control purposes.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 24 Sep 2020 21:03:08 +0000
parents 0740b5ff15f6
children
line wrap: on
line source

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

#define L1P_DRIVE_C

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

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

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

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

#else

  #include <string.h>
  #include "l1_types.h"
  #include "sys_types.h"
  #include "l1_const.h"
  #include "l1_time.h"

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

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

  #include "l1_proto.h"
  #include "tpudrv.h"

#endif

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

/*-------------------------------------------------------*/
/* Prototypes of external functions used in this file.   */
/*-------------------------------------------------------*/
void   l1dmacro_synchro  (UWORD32 when, UWORD32 value);
void   l1dmacro_offset   (UWORD32 offset_value, WORD32 relative_time);
void   l1dmacro_afc      (UWORD16 afc_value, UWORD8 win_id);

#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61) )
  UWORD16 Cust_get_pwr_data(UWORD8 txpwr, UWORD16 radio_freq
  										  #if(REL99 && FF_PRF)
  										  ,UWORD8 number_uplink_timeslot
  										  #endif
  										  );
#endif
void Cust_get_ramp_tab(API *a_ramp, UWORD8 txpwr_ramp_up, UWORD8 txpwr_ramp_down, UWORD16 radio_freq);

BOOL   l1ps_swap_iq_ul   (UWORD16 radio_freq);
BOOL   l1ps_swap_iq_dl   (UWORD16 radio_freq);
#if (L1_MADC_ON == 1)
#if (RF_FAM == 61)
void   l1pdmacro_rx_up   (UWORD16 radio_freq,UWORD8 adc_active, UWORD8 csf_filter_choice
#if (NEW_SNR_THRESHOLD == 1)
      ,UWORD8 saic_flag
#endif /* NEW_SNR_THRESHOLD == 1*/
    );
#endif
#else /* RF_FAM == 61*/
void   l1pdmacro_rx_up   (UWORD16 radio_freq);
#endif
void   l1pdmacro_rx_down (UWORD16 radio_freq, UWORD8 num_rx, BOOL rx_done_flag);
void   l1pdmacro_tx_up   (UWORD16 radio_freq);
void   l1pdmacro_tx_down (UWORD16 radio_freq, WORD16 time, BOOL tx_flag, UWORD8 timing_advance,UWORD8  adc_active);
void   l1pdmacro_tx_synth(UWORD16 radio_freq);
void   l1pdmacro_anchor  (WORD16  time);

void l1dmacro_rx_synth(UWORD16  radio_freq);
void l1dmacro_agc(UWORD16 radio_freq, WORD8 agc_value, UWORD8 lna_off
                     	#if (RF_FAM == 61)
                              ,UWORD8 if_ctl
                     	#endif
	                           );
#if (CODE_VERSION == SIMULATION)
  void   l1dmacro_rx_ms    (UWORD16 arfcn, BOOL rxnb_select);
#else
#if (L1_MADC_ON == 1)
#if (RF_FAM == 61)
 void   l1dmacro_rx_ms    (UWORD16 arfcn,UWORD8 adc_active);
#endif
#else
  void   l1dmacro_rx_ms    (UWORD16 arfcn);
#endif
#endif
void l1pdmacro_it_dsp_gen(WORD16 time);

/*-------------------------------------------------------*/
/* Prototypes of functions defined in this file.         */
/*-------------------------------------------------------*/
// TPU Drivers...


// DSP Drivers...
void l1pddsp_synchro              (UWORD8 switch_mode, UWORD8  camp_timeslot);
void l1pddsp_idle_prach_data      (BOOL    polling, UWORD8  cs_type, UWORD16  channel_request_data,
                                   UWORD8  bsic, UWORD16 radio_freq);
void l1pddsp_idle_prach_power     (UWORD8 txpwr, UWORD16  radio_freq, UWORD8 ts);
void l1pddsp_single_tx_block      (UWORD8 burst_nb, UWORD8 *data, UWORD8  tsc,
                                   UWORD16 radio_freq);
#if FF_L1_IT_DSP_USF
void l1pddsp_idle_rx_nb           (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq,
                                   UWORD8 timeslot_no, BOOL ptcch_dl, BOOL usf_interrupt);
#else
void l1pddsp_idle_rx_nb           (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq,
                                   UWORD8 timeslot_no, BOOL ptcch_dl);
#endif
void l1pddsp_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
				   );
void l1pddsp_transfer_mslot_power (UWORD8 *txpwr, UWORD16 radio_freq, UWORD8 ul_bitmap);
void l1pddsp_ul_ptcch_data        (UWORD8 cs_type, UWORD16  channel_request_data, UWORD8  bsic,
                                   UWORD16 radio_freq, UWORD8 timeslot_no);
void l1pddsp_interf_meas_ctrl     (UWORD8 nb_meas_req);
void l1pddsp_transfer_meas_ctrl   (UWORD8 meas_position);

/*-------------------------------------------------------*/
/* l1pd_afc()                                            */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pd_afc(void)
{
  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
    l1ddsp_load_afc(l1s.afc);
  #endif
  #if (RF_FAM == 61)
      l1dtpu_load_afc(l1s.afc);
  #endif
}

/*-------------------------------------------------------*/
/* l1pdtpu_interf_meas()                                 */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
UWORD8 l1pdtpu_interf_meas(UWORD16 radio_freq,
                           WORD8  agc,
                           UWORD8  lna_off,
                           UWORD8  meas_bitmap,
                           UWORD32 offset_serv,
                           UWORD16 win_id,
                           UWORD8  synchro_ts
                       #if (RF_FAM == 61)
                          ,UWORD8 if_ctl
                       #endif
                       )
{
  UWORD8 bit_mask = 0x80;
  UWORD8 ts;
  BOOL   rf_programmed = FALSE;
  UWORD8 count = 0;

  if(!win_id)
  {
    // Nothing programmed yet, we must avoid Mirror effect in Ctrl phase.
    l1pdmacro_anchor(l1_config.params.rx_change_offset_time);
  }

  for (ts=0; ts<8; ts++)
  {
    // the bitmap corresponds to that of the idle frame of the network!!!
  #if ((CHIPSET==3)||(CHIPSET == 4))
    // limitation of 5 measurements for SAMSON (TPU RAM size limitation)
    if((meas_bitmap & bit_mask)&&(count <= 4))
  #else
    if(meas_bitmap & bit_mask)
  #endif
    {
      UWORD16 local_win_id;
      UWORD16 offset;
      WORD16  when;
      UWORD16 offset_chg;

      if((ts>synchro_ts) && (count==0))
      {
        // The 1st Work does not contain any Interf meas.
        // We must ovoid a possible Mirror effect for the rest of TS.
        l1pdmacro_anchor(l1_config.params.rx_change_offset_time);
      }

      // Increment nbr of meas. programmed.
      count++;

      local_win_id = (8 - synchro_ts + ts) * BP_SPLIT;
      if(local_win_id >= (BP_SPLIT * 8)) local_win_id -= BP_SPLIT * 8; // Modulo.

      // Compute offset
      offset_chg = ((local_win_id  * BP_DURATION) >> BP_SPLIT_PW2);
      offset     = offset_serv + offset_chg;
      if(offset >= TPU_CLOCK_RANGE) offset -= TPU_CLOCK_RANGE;

      if(!rf_programmed)
      {
        // Compute offset change timing
        when = offset_chg +
               PROVISION_TIME -
               l1_config.params.rx_synth_setup_time -
               EPSILON_OFFS;

        if(when < 0) when += TPU_CLOCK_RANGE;

        // Program TPU scenario
        l1dmacro_offset   (offset, when);               // change TPU offset according to win_id
        l1dmacro_rx_synth (radio_freq);                 // pgme SYNTH.
    #if (RF_FAM !=61)
	 l1dmacro_agc      (radio_freq, agc,lna_off);    // pgme AGC.
    #endif

    #if (RF_FAM == 61)
	l1dmacro_agc      (radio_freq, agc,lna_off, if_ctl);    // pgme AGC.
    #endif

        rf_programmed = TRUE;
      }
      else
      {
        // Compute offset change timing
        when = offset_chg - BP_DURATION + PROVISION_TIME + PW_ACQUIS_DURATION + 20;
        if(when < 0) when += TPU_CLOCK_RANGE;

        // Program TPU scenario
        l1dmacro_offset   (offset, when);    // change TPU offset according to win_id
      }

      #if (CODE_VERSION == SIMULATION)
        l1dmacro_rx_ms    (radio_freq, 1);     // pgm  PWR acquisition.
      #else
      #if (L1_MADC_ON == 1)
      #if (RF_FAM == 61)
	l1dmacro_rx_ms    (radio_freq,INACTIVE);        // pgm  PWR acquisition.
      #endif
      #else
        l1dmacro_rx_ms    (radio_freq);        // pgm  PWR acquisition.
      #endif
      #endif

      l1dmacro_offset   (offset_serv, IMM);  // restore offset
    }

    bit_mask >>= 1;

  } // for(ts...

  return(count);
}

/*-------------------------------------------------------*/
/* l1dtpu_serv_rx()                                      */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/*             rx_id: range 0-7, first slot of RX group  */
/*             rx_group_id: used in case |RX|  |RX|      */
/*                                                       */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pdtpu_serv_rx_nb(UWORD16 radio_freq, UWORD8 agc, UWORD8 lna_off,
                        UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx,
                        UWORD8 rx_group_id, BOOL rx_done_flag,UWORD8 adc_active
                        #if (RF_FAM == 61)
                          ,UWORD8 csf_filter_choice
                          ,UWORD8 if_ctl
                        #endif
                        #if (NEW_SNR_THRESHOLD == 1)
                          ,UWORD8 saic_flag
                        #endif /* NEW_SNR_THRESHOLD*/
                                           )
{
  UWORD16 offset;

  #if (CODE_VERSION == SIMULATION)
    UWORD32 tpu_w_page;

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

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

  offset = offset_serv + (rx_id * BP_DURATION);
  if(offset >= TPU_CLOCK_RANGE) offset -= TPU_CLOCK_RANGE;

  if (rx_group_id == 1)
  {
    // Time tracking.
    l1dmacro_synchro (l1_config.params.rx_change_synchro_time, offset_serv); // Adjust serving OFFSET.

    #if L2_L3_SIMUL
      #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET)
        buffer_trace(3, 0x43, offset_serv, l1s.actual_time.fn, 0);
      #endif
    #endif

    // Change offset to align on RX.
    l1dmacro_offset(offset, IMM);

    // Program Synth.
    // Program ADC measurement
    // Program AGC.
    l1dmacro_rx_synth(radio_freq);
    if(adc_active == ACTIVE)
      l1dmacro_adc_read_rx();

     l1dmacro_agc     (radio_freq, agc, lna_off
                                #if (RF_FAM == 61)
                                ,if_ctl
                                #endif
	                         );
  }
  else
  {
    // Change offset to align on RX.
    l1dmacro_offset(offset, IMM); // Change offset to align on RX.
  }

  l1pdmacro_rx_up  (radio_freq
  #if (RF_FAM == 61)
    ,adc_active
    ,csf_filter_choice
  #endif
  #if (NEW_SNR_THRESHOLD == 1)
    ,saic_flag
  #endif /* NEW_SNR_THRESHOLD*/

      ); // RX window opened.
  l1pdmacro_rx_down(radio_freq, num_rx, rx_done_flag); // RX window closed.

  // Restore offset to synchro value.
  l1dmacro_offset (offset_serv, IMM);
}

/*-------------------------------------------------------*/
/* l1dtpu_serv_tx()                                      */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
  #ifndef  ABB_RAMP_UP_TIME  //Flexi ABB Delays defines it in tpudrvXX.h
    #define ABB_RAMP_UP_TIME    32  // maximum time for ramp up
  #endif

  #ifndef ABB_RAMP_DELAY//Flexi ABB Delays defines it in tpudrvXX.h
    #define ABB_RAMP_DELAY       6  // minimum ramp delay APCDEL
  #endif

#ifndef ABB_BULON_HOLD_TIME //Flexi ABB Delays defines it in tpudrvXX.h
	#define ABB_BULON_HOLD_TIME 32  // min. hold time for BULON after BULENA down
#endif


#endif
void l1pdtpu_serv_tx(UWORD16 radio_freq,
                     UWORD8  timing_advance,
                     UWORD32 offset_serv,
                     UWORD8  tx_id,
                     UWORD8  num_tx,
                     UWORD8  tx_group_id,
                     UWORD8  switch_flag,
                     BOOL    burst_type,
                     BOOL    rx_flag,
                     UWORD8  adc_active)
{
  WORD16      time;
  UWORD32     offset_tx;
  UWORD32     timing_advance_in_qbit = (UWORD32)timing_advance << 2;
  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61))
    UWORD16 apcdel1_data, apcdel1_data_up;
  #endif
  UWORD8      i;
  static UWORD8 static_switch_flag = 0;

  #if (CODE_VERSION == SIMULATION)
    UWORD32 tpu_w_page;

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

    hw.tx_id[tpu_w_page][tx_group_id-1]=tx_id;
    hw.num_tx[tpu_w_page][tx_group_id-1]=num_tx;
    hw.tx_group_id[tpu_w_page]=tx_group_id;
  #endif

  // Reset timing advance if TA_ALGO not enabled.
  #if !TA_ALGO
    timing_advance_in_qbit = 0;
  #endif

  // In case another group of TX bursts is called, the previous slot was a hole
  // An IT has to be generated to the DSP so that ramps and power level are reloaded
  // This does not apply to combinations of PRACH and TX NB
  if ((tx_group_id > 1) && (!static_switch_flag))
  {
    // exact timing for generation of IT during hole not required but
    // time > time of previous ramp down (BULENA -> BULON down = 32 qb) + margin (10 qb)
   #if (RF_FAM != 61)
    time = TX_TABLE[tx_id-1] + PROVISION_TIME + ABB_BULON_HOLD_TIME + 10
           - l1_config.params.prg_tx_gsm;
   #endif

   #if (RF_FAM == 61)
     time = TX_TABLE[tx_id-1] + PROVISION_TIME + APC_RAMP_DOWN_TIME + 10
           - l1_config.params.prg_tx_gsm;
   #endif

    if (burst_type == TX_NB_BURST)
      time -= timing_advance_in_qbit; // time can never be negative here

    l1pdmacro_it_dsp_gen(time);
  }


  if (tx_group_id == 1)
  {
    #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
      //MS TX, set ABB in MS mode
      #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37)
        // ABB set to MS mode if |TX|TX|.., |TX|PRACH|, |PRACH|TX| or |PRACH|PRACH|
        // switch_flag is set for the first burst of TX/PRACH or PRACH/PRACH combinations
        // MS mode in ABB must be maintained for second burst (static_switch_flag)
        if ((num_tx > 1) || (switch_flag) || (static_switch_flag))
          l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl | B_MSLOT;
        else
          l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl;
      #endif
    #endif
  }
  else
  {
    // handle special case |TX|  |TX|TX|
    #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
      //MS TX, set ABB in MS mode
      #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37)
        if ((num_tx > 1) || (switch_flag) || (static_switch_flag))
          l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl | B_MSLOT;
      #endif
    #endif
  }

  // Compute offset value for TX.
  // PRG_TX has become variable, no longer contained in TIME_OFFSET_TX !
  if ((burst_type == TX_NB_BURST) || (switch_flag==1))
  {
    offset_tx = offset_serv + TX_TABLE[tx_id] + PROVISION_TIME
                 - l1_config.params.prg_tx_gsm - timing_advance_in_qbit;
  }
  else
  {
    offset_tx = offset_serv + TX_TABLE[tx_id] + PROVISION_TIME
                 - l1_config.params.prg_tx_gsm;
  }

  // offset_tx mod 5000
  if (offset_tx >= TPU_CLOCK_RANGE)
    offset_tx -= TPU_CLOCK_RANGE;

  if(rx_flag == TRUE)
  {
    time = offset_tx -
           l1_config.params.tx_synth_setup_time -
           EPSILON_OFFS
           - offset_serv;
    if ((burst_type == TX_NB_BURST) || (switch_flag==1))
      time += timing_advance_in_qbit - TA_MAX;
  }
  else
    time = TPU_CLOCK_RANGE - EPSILON_SYNC;

  if (time < 0)
    time += TPU_CLOCK_RANGE;

  if (!static_switch_flag)
    l1dmacro_offset  (offset_tx, (WORD32) time);  // load OFFSET for TX before each burst.

  #if L2_L3_SIMUL
    #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET)
      buffer_trace(2, offset_tx,l1s.actual_time.fn,0,0);
    #endif
  #endif

  time=0;

  // program PLL only if no TX control carried out in same frame: |TX|  |TX|TX| possible
  // |PRACH|TX|, |TX|PRACH| or |PRACH|PRACH| also possible
  if (tx_group_id == 1)
  {
    l1pdmacro_tx_synth(radio_freq); // load SYNTH.
  }

  if (!static_switch_flag)  // window opened for previous time slot (TX/PRACH or PRACH/PRACH)
    l1pdmacro_tx_up(radio_freq);     // TX window opened


  #if (CODE_VERSION == SIMULATION)
    if (burst_type == TX_RA_BURST)
    {
      time += l1_config.params.tx_ra_duration;
    }
    else
    {
      if (num_tx > 1)
      //  num_tx * BP_DURATION
        time += TX_TABLE[num_tx - 1] + l1_config.params.tx_nb_duration;
      else
        time += l1_config.params.tx_nb_duration;
    }
  #else
    #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
      // Read APCDEL1 register DELU(4:0): delay of ramp up start, DELD (9:5) delay of ramp down start
      // This value is used for computations in MS TX or TX/PRACH combinations
      // This value is not modified by the computations
      apcdel1_data    = (l1s_dsp_com.dsp_ndb_ptr->d_apcdel1 >> 6) & 0x03ff;
      apcdel1_data_up = apcdel1_data & 0x001f;  //delay of ramp up start
    #endif

#if (RF_FAM == 61)
      // Read APCDEL1 register DELU(4:0): delay of ramp up start, DELD (9:5) delay of ramp down start
      // This value is used for computations in MS TX or TX/PRACH combinations
      // This value is not modified by the computations
      apcdel1_data    = (l1s_dsp_com.dsp_ndb_ptr->d_apcdel1) & 0x03ff;
      apcdel1_data_up = apcdel1_data & 0x001f;  //delay of ramp up start
#endif

    if (!switch_flag)
    {
      if (burst_type == TX_NB_BURST)
      {
        // If PRACH precedes TX normal burst(s) we have to add BP_DURATION
        if (static_switch_flag)
          time += BP_DURATION;

        // generate DSP IT for each TX slot after ramp up
        // Margin:
        // ABB_RAMP_DELAY = 4*1.5bits internal ABB delay BULENA ON -> ramp up
        // apcdel1_data_up = additional delay BULENA ON -> ramp up
        // ABB_RAMP_UP_TIME: maximum time for ramp up: 16 coeff.
        // 10 qbits of additional margin
        #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
          for (i=0; i<num_tx; i++)
            l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + i*BP_DURATION + apcdel1_data_up + 10);
        #endif

        #if (RF_FAM == 61)
          for (i=0; i<num_tx; i++)
            l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + i*BP_DURATION + apcdel1_data_up + 10);
        #endif


        if (num_tx > 1)
        //  (num_tx - 1) * BP_DURATION + normal burst duration
          time += TX_TABLE[num_tx - 1] + l1_config.params.tx_nb_duration - (num_tx - 1);
        else
          time += l1_config.params.tx_nb_duration;
      }
      else //PRACH
      {
        // If TX NB precedes PRACH we have to add BP_DURATION and TA (in qbits)
        if (static_switch_flag == 1)
        {
          if (timing_advance_in_qbit > 240) // clip TA, cf. comment below
            timing_advance_in_qbit = 240;
          time += BP_DURATION + timing_advance_in_qbit;
        }
        // If PRACH precedes PRACH we have to add BP_DURATION
        else if (static_switch_flag == 2)
          time += BP_DURATION ;

        #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
          l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10);
        #endif

	 #if (RF_FAM == 61)
          l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10);
        #endif

        time += l1_config.params.tx_ra_duration;
      }

    }
    else if (switch_flag == 1) // |TX|PRACH| or |PRACH|TX|
    {
      #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39)
        // => ABB windows are opened as for TX_NB in MS mode
        // => Ramp up start of PRACH is delayed inside this window by the TA of the TX_NB
        // => DSP inserts dummy bits such that ramp and modulation match
        // Rem.: the TA passed for the PRACH is the one for the following TX_NB!!!
        #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) || (RF_FAM == 61)
          // In combinations of TX_NB and PRACH apcdel1_bis and apcdel2_bis apply to the PRACH
          UWORD16 apcdel1_bis_data, apcdel1_bis_data_up, apcdel2_bis_data_up, prach_delay;
          API d_ctrl_abb_gprs;

          // clip TA (in qbit): max. TA supported = BP_DURATION - PRACH duration - max. ramp time
          //                                      = 625 - 88*4 - 32 = 241
          if (timing_advance_in_qbit > 240)
            timing_advance_in_qbit = 240;

          prach_delay = apcdel1_data_up + timing_advance_in_qbit;
          apcdel1_bis_data_up = prach_delay & 0x001f;
          apcdel2_bis_data_up = (prach_delay >> 5) & 0x001f;

          // For ramp down delay we need to keep the original value from APCDEL1 (bits 9:5)
          // APCDEL2 default value is '0'
          apcdel1_bis_data = apcdel1_bis_data_up | (apcdel1_data & 0x03e0);

       #if(RF_FAM != 61)
                 l1s_dsp_com.dsp_ndb_ptr->d_apcdel1_bis  = (apcdel1_bis_data << 6) | 0x04;
                 l1s_dsp_com.dsp_ndb_ptr->d_apcdel2_bis = (apcdel2_bis_data_up << 6) | 0x34;
       #else
                 l1s_dsp_com.dsp_ndb_ptr->d_apcdel1_bis  = (apcdel1_bis_data );
                 l1s_dsp_com.dsp_ndb_ptr->d_apcdel2_bis = (apcdel2_bis_data_up);
       #endif

                 if (burst_type == TX_RA_BURST) // |PRACH|TX|
                 {

       #if(RF_FAM != 61)
                   l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + prach_delay + 10);
       #else
                   l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + prach_delay + 10);
       #endif
            // apcdel1_bis, apcdel2_bis must be programmed for the current ts (PRACH)
            // here we need to overwrite (mask) bits for APCDEL1, APCDEL2 programming done in l1pddsp_transfer_mslot_power()
            d_ctrl_abb_gprs = l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id];
            d_ctrl_abb_gprs |= ((1 << B_BULRAMPDEL_BIS) | (1 << B_BULRAMPDEL2_BIS));
            d_ctrl_abb_gprs &= ~((1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));
            l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id] = d_ctrl_abb_gprs;
          }
          else // |TX|PRACH|
          {
          #if(RF_FAM != 61)
            l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10);
  	   #else
            l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10);
	   #endif

            // apcdel1_bis, apcdel2_bis must be programmed for the next ts (PRACH)
            d_ctrl_abb_gprs = l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id + 1];
            d_ctrl_abb_gprs |= ((1 << B_BULRAMPDEL_BIS) | (1 << B_BULRAMPDEL2_BIS));
            d_ctrl_abb_gprs &= ~((1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));
            l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id + 1] = d_ctrl_abb_gprs;
          }
        #endif // ANALOG

        static_switch_flag = 1;

      #endif // DSP == 33 || DSP == 34 || (DSP == 36)  || (DSP == 37)
    }
    else if (switch_flag == 2) // |PRACH|PRACH|
    // Combination handled by programming ABB with MS mode = 1
    // => first burst length of first PRACH = BP_DURATION
    {
      #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
        l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10);
      #endif

      #if (RF_FAM == 61)
        l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10);
      #endif

      static_switch_flag = 2;
    }
  #endif //Codeversion

  // In case of combinations TX_NB/PRACH or PRACH/PRACH the TX window is kept open
  if (!switch_flag)
  {
    l1pdmacro_tx_down(radio_freq, time, switch_flag, timing_advance_in_qbit,adc_active);     // TX window closed

    l1dmacro_offset  (offset_serv, IMM); // Restore offset with serving value.

    static_switch_flag = 0;
  }

  #if L2_L3_SIMUL
    #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET)
      buffer_trace(2, offset_serv,l1s.actual_time.fn,0,0);
    #endif
  #endif
}

/*-------------------------------------------------------*/
/* l1pddsp_synchro()                                     */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_synchro(UWORD8 switch_mode, UWORD8  camp_timeslot)
{
  // Set "b_abort" to TRUE.
  l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= (1 << B_TASK_ABORT);

  // Set switch mode within "b_switch_to_gprs" & "b_switch_to_gms"
  l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs = (switch_mode << B_SWITCH);

  // In case of a switch to GPRS_SCHEDULER, last_used_txpwr is set to "NO_TXPWR"
  // in order to force GSM ramp programming when the MS will switch back to
  // GSM_SCHEDULER
  // Moreover, the d_win_start_gprs register must be initialized only during the
  // GSM->GPRS switch too.
  if(switch_mode == GPRS_SCHEDULER)
  {
    l1s.last_used_txpwr = NO_TXPWR;

    // Set camp timeslot.
    l1ps_dsp_com.pdsp_ndb_ptr->d_win_start_gprs = camp_timeslot;
  }
}


/*-------------------------------------------------------*/
/* l1pddsp_idle_prach_data()                             */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_idle_prach_data(BOOL    polling,
                             UWORD8  cs_type,
                             UWORD16  channel_request_data,
                             UWORD8  bsic,
                             UWORD16 radio_freq)
{
  UWORD16  swap_bit; // 16 bit wide to allow shift left.

  // UL on TS=3.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> 3;

  // Swap I/Q management.
  swap_bit = l1ps_swap_iq_ul(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15;

  // Load UL buffer according to "polling" bit.
  if(polling)
  {
    // Select first UL polling buffer.
    l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 8;

    // Store CS type.
    l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][0] = cs_type;

    // Store UL data block.
    if(cs_type == CS_PAB8_TYPE)
    {
      l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2] = ((API)(bsic << 2)) |
                                                   ((API)(channel_request_data) << 8);
      l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][3] = 0;
    }
    else
    {
      l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2] = ((API)(channel_request_data) << 5);
      l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][3] = ((API)(bsic << 10));
    }
  }
  else
  {
    // Set "b_access_prach" to indicate 1 Prach only to DSP.
    l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= (1 << B_ACCESS_PRACH);

    // Select first UL data buffer.
    l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 0;

    // Store CS type.
    l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][0] = cs_type;

    // Store UL data block.
    if(cs_type == CS_PAB8_TYPE)
    {
      l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][1] = ((API)(bsic << 2)) |
                                                   ((API)(channel_request_data) << 8);
      l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][2] = 0;
    }
    else
    {
      l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][1] = ((API)(channel_request_data) << 5);
      l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][2] = ((API)(bsic << 10));
    }

    if (l1pa_l1ps_com.pra_info.prach_alloc == FIX_PRACH_ALLOC)
    {
      // Set fix alloc bit.
      l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs |= (2 << B_MAC_MODE);
    }
    else
    {
      // Reset MAC mode to dynamic allocation
      l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= ~(3 << B_MAC_MODE);

      #if !FF_L1_IT_DSP_USF
      #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39)
        // Enable USF vote on timeslot 0
        l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = 0x80;
      #endif
      #endif
    }
  }
}

/*-------------------------------------------------------*/
/* l1pddsp_idle_prach_power()                            */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_idle_prach_power(UWORD8   txpwr,
                              UWORD16  radio_freq,
                              UWORD8   ts)
{
  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61))
    UWORD16 pwr_data;
  #endif

  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) )
    // Force FIXED transmit power if requested.
    if(l1_config.tx_pwr_code == 0)
    {
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = l1_config.params.fixed_txpwr;

      // Control bitmap: update RAMP, use RAMP[5][..].
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] =
                      ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

             // Store Ramp.
	  #if (CODE_VERSION != SIMULATION)
        Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[5],
                                            0, /* not used */
                                            0, /* not used */
                                            1  /* arbitrary value for arfcn */ );
	  #endif
    }
    else
    {
      // Get H/W value corresponding to txpwr command.
      pwr_data = Cust_get_pwr_data(txpwr, radio_freq
                                          #if(REL99 && FF_PRF)
                                          ,1
                                          #endif
                                          );

      // Store Transmit power.
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = ((pwr_data << 6) | 0x12);

      // Control bitmap: update RAMP, use RAMP[5][..].
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

      // Store Ramp.
	  #if (CODE_VERSION != SIMULATION)
        Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[5][0]), txpwr, txpwr, radio_freq);
	  #endif
    }
  #endif

  #if (RF_FAM == 61)
    // Force FIXED transmit power if requested.
    if(l1_config.tx_pwr_code == 0)
    {
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = l1_config.params.fixed_txpwr;

      // Control bitmap: update RAMP, use RAMP[5][..].
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] =
                      ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

      // Store Ramp.
    #if (DSP ==38) || (DSP == 39)
       Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[5],
                                        0, /* not used */
                                        0, /* not used */
                                        1  /* arbitrary value for arfcn */ );
    #endif
    }
    else
    {
      // Get H/W value corresponding to txpwr command.
      pwr_data = Cust_get_pwr_data(txpwr, radio_freq
      									  #if(REL99 && FF_PRF)
      									  ,1
      									  #endif
      									  );

      // Store Transmit power.
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = (API) (pwr_data);

      // Control bitmap: update RAMP, use RAMP[5][..].
      l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

      // Store Ramp.
      #if(DSP == 38) || (DSP == 39)
        Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[5][0]), txpwr, txpwr, radio_freq);
     #endif
    }
  #endif //RF_FAM == 61

}

/*-------------------------------------------------------*/
/* l1pddsp_single_block()                                */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_single_tx_block(UWORD8  burst_nb,
                             UWORD8 *data,
                             UWORD8  tsc,
                             UWORD16 radio_freq)
{
  UWORD16  swap_bit; // 16 bit wide to allow shift left.

  // Burst number within a block.
  l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb;

  // UL on TS=3.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> 3;

  // Swap I/Q management.
  swap_bit = l1ps_swap_iq_ul(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15;

  // Select first UL polling buffer.
  l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 8;

  // Store CS type: CS1 for Polling.
  l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][0] = CS1_TYPE_POLL;

  if(burst_nb == BURST_1)
  // Store UL data block.
  {
    API    *ul_block_ptr = &(l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2]);
    UWORD8  i,j;

    // Copy first 22 bytes in the first 11 words after header.
    for (i=0, j=0; j<11; j++)
    {
      ul_block_ptr[j] = ((API)(data[i])) | ((API)(data[i+1]) << 8);
      i += 2;
    }
    // Copy last UWORD8 (23rd) in the 12th word after header.
    ul_block_ptr[11] = data[22];
  }

  // Training sequence.
  // Rem: bcch_freq_ind is set within Hopping algo.
  l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ;
}

/*-------------------------------------------------------*/
/* l1pddsp_idle_rx_nb()                                  */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
#if FF_L1_IT_DSP_USF
void l1pddsp_idle_rx_nb(UWORD8  burst_nb,
                        UWORD8  tsc,
                        UWORD16 radio_freq,
                        UWORD8  timeslot_no,
                        BOOL    ptcch_dl,
                        BOOL    usf_interrupt)
#else
void l1pddsp_idle_rx_nb(UWORD8  burst_nb,
                        UWORD8  tsc,
                        UWORD16 radio_freq,
                        UWORD8  timeslot_no,
                        BOOL    ptcch_dl)
#endif
{
  UWORD16  swap_bit; // 16 bit wide to allow shift left.

  // DL on TS=0.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= 0x80 >> timeslot_no;

  // Swap I/Q management.
  swap_bit = l1ps_swap_iq_dl(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= swap_bit << 15;

  if(ptcch_dl)
  {
    // PTCCH/DL case must be flagged to DSP.
    l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= (1 << B_PTCCH_DL);
  }

  // Burst number within a block.
  l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb;

  // Channel coding is forced to CS1.
  l1ps_dsp_com.pdsp_ndb_ptr->a_ctrl_ched_gprs[timeslot_no] = CS1_TYPE_DATA;

  // pass information to DSP which good USF value is to be expected
  l1ps_dsp_com.pdsp_ndb_ptr->a_usf_gprs[0] = (API) 0x07;

  #if FF_L1_IT_DSP_USF
    // In case of connection establishment mode with dynamic or fixed
    // allocation scheme we need to request the DSP USF interrupt for PRACH
    // scheduling. Latched by DSP during Work3
    if  (burst_nb == 3)
    {
      if (usf_interrupt)
        l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable |= (1 << B_USF_IT);
      else
        l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable &= ~(1 << B_USF_IT);
    }
  #endif

  // RIF receiver algorithm: select 156.25.
  l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= 0xFFFF ^ (1 << B_RIF_RX_MODE);

  // Training sequence.
  // Rem: bcch_freq_ind is set within Hopping algo.
  l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ;

}


/*-------------------------------------------------------*/
/* l1pddsp_transfer_mslot_ctrl()                         */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
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
                                  )
{
  UWORD8   i;
  UWORD16  swap_bit; // 16 bit wide to allow shift left.

  // Burst number within a block.
  l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb;

  // DL bitmap.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs = dl_bitmap;

  // UL bitmap.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs = ul_bitmap;

  // Swap I/Q management for DL.
  swap_bit = l1ps_swap_iq_dl(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= swap_bit << 15;

  // Swap I/Q management for UL.
  swap_bit = l1ps_swap_iq_ul(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15;

  if(burst_nb == 0)
  {
    // Store USF table
    for(i=0;i<(8 - synchro_timeslot);i++)
      l1ps_dsp_com.pdsp_ndb_ptr->a_usf_gprs[i] = usf_table[i+synchro_timeslot];

    // Automatic CS detection.
    for(i=0;i<8;i++)
    {
      l1ps_dsp_com.pdsp_ndb_ptr->a_ctrl_ched_gprs[i] = CS_AUTO_DETECT;

      // Select first UL polling buffer.
      l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[i] = ul_buffer_index[i];
    }

    #if !FF_L1_IT_DSP_USF
    // USF vote enable programming

    #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39)
      // Multislot TX allowed and usf_vote_enable suported: programs usf_vote_enable
      l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = usf_vote_enable;
    #else
      // Single slot TX only and usf_vote_enable not supported
      // Modify MAC mode
      if (usf_vote_enable)
        // USF vote enabled  --> Set MAC mode to dynamic mode
        mac_mode = DYN_ALLOC;
      else
        // USF vote disabled --> Set MAC mode to fixed mode
        mac_mode = FIX_ALLOC_NO_HALF;
    #endif

    #endif // !FF_L1_IT_DSP_USF

    // MAC mode.
    l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= ~(3 << B_MAC_MODE);
    l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs |= mac_mode << B_MAC_MODE;
  }

  #if FF_L1_IT_DSP_USF
    if(burst_nb == 3)
    {
      // Program DSP to generate an interrupt once USF available if
      // required. Latched by DSP during Work3.
      if (dsp_usf_interrupt)
        l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = (1 << B_USF_IT);
      else
        l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = 0;
    }
  #endif

  // RIF receiver algorithm: select 156.25.
  l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= 0xFFFF ^ (1 << B_RIF_RX_MODE);

  // d_fn
  // ----
  //   bit [0..7]  -> b_fn_report, unused for GPRS
  //   bit [8..15] -> b_fn_sid   , FN%104
  l1s_dsp_com.dsp_db_w_ptr->d_fn = ((l1s.next_time.fn_mod104)<<8);

  // Training sequence.
  // Rem: bcch_freq_ind is set within Hopping algo.
  l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ;

}


/*-------------------------------------------------------*/
/* l1pddsp_transfer_mslot_power()                        */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_transfer_mslot_power(UWORD8  *txpwr,
                                  UWORD16  radio_freq,
                                  UWORD8   ul_bitmap)
{
  #define  NO_TX   100

  UWORD16  i;        // 16 bit needed for shifting pupose.
  UWORD8   last_TX = NO_TX;
  UWORD8   txpwr_ramp_up;
  UWORD8   txpwr_ramp_down;
  UWORD8   cpt_TX = 0;
  UWORD8   ts_mask;

    #if (REL99 && FF_PRF)
      UWORD8 number_uplink_timeslot = 0 ; // number of uplink timeslot for power reduction feature
    #endif


  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61))
    UWORD16 pwr_data;
    UWORD16 d_ramp_idx;
    WORD16  ts_conv;
  #endif

//Locosto  #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))

    // This function is called with an ul_bitmap which represents the abolute
    // position of any Tx bursts in this frame. This bitmap has already
    // absorbed any synchro change (in dl_tn), hence we need to do some
    // processing to recover the actual Tx timeslot number which is used
    // as an index into the txpwr array.
    //
    // Example : MS Class 8 with 4 Rx and 1 Tx :
    //
    //
    // dl_ts_alloc      :   0x0f         0 0 0 0 R R R R
    // ul_ts_alloc      :   0x02         0 0 0 0 0 0 T 0
    // shift + combine  :                0 0 0 0 R R R R 0 T
    // set dl_tn=4      :                R R R R 0 T 0 0
    // ul_bitmap        :   0x04         0 0 0 0 0 1 0 0
    // i                :      5
    //
    // Example : MS Class 8 with 1 Rx and 1 Tx on TS=7
    //
    // dl_ts_alloc      :   0x01         0 0 0 0 0 0 0 R
    // ul_ts_alloc      :   0x01         0 0 0 0 0 0 0 T
    // shift + combine  :                0 0 0 0 0 0 0 R 0 0 T
    // set dl_tn=7      :                R 0 0 T 0 0 0 0
    // ul_bitmap        :   0x10         0 0 0 1 0 0 0 0
    // i                :      3
    //
    // We recover the actual timeslot from the ul_bitmap by the following
    // method :
    //
    //  ts = (i + dl_tn) - 3
    //
    //  Where i is the loopindex usd to detect "1" in the ul_bitmap.
    //  This works for MS class 8 because (3 <= i <= 5) if the
    //  multislot class is respected.

        #if (REL99 && FF_PRF)// power reduction feature
	      for (i=0; i<8; i++)
	      {
	        // computed number of uplink timeslot in order to determine uplink power reduction
	        ts_mask = (0x80>>i);
	        if (ul_bitmap & ts_mask)
	          number_uplink_timeslot++;
	      }
	    #endif


    ts_conv = l1a_l1s_com.dl_tn - 3;

    // Index of the programmed ramps
    d_ramp_idx = 0;

    for(i=0;i<8;i++)
    {
      // Program Transmit power and ramp for allocated timeslots.
      if(ul_bitmap & (0x80>>i))
      {
        // Fixe transmit power.
        if(l1_config.tx_pwr_code == 0)
        {
          // Store Transmit power.
          l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = l1_config.params.fixed_txpwr;

          // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..].
          l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] =
                          ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

          // Store Ramp.
#if (RF_FAM == 61)
  #if (DSP ==38) || (DSP == 39)
          Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx++],
                                         0, /* not used */
                                         0, /* not used */
                                         1  /* arbitrary value for arfcn */ );
    #endif
#else
			#if (CODE_VERSION != SIMULATION)
          Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx++],
                                         0, /* not used */
                                         0, /* not used */
                                         1  /* arbitrary value for arfcn */ );
#endif
		  #endif
        }
        else
        {
          // count the number of TX windows
          cpt_TX ++;

          // Get power amplifier data.
          #if(REL99 && FF_PRF)
          pwr_data = Cust_get_pwr_data(txpwr[i+ts_conv], radio_freq, number_uplink_timeslot);
          #else
          pwr_data = Cust_get_pwr_data(txpwr[i+ts_conv], radio_freq);
          #endif


          // Store Transmit power.
          #if(RF_FAM == 61)
            l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = (pwr_data);
          #else
            l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = ((pwr_data << 6) | 0x12);
          #endif

          // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..] for slot i.
          l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] = ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2));

          // Store Ramp.
          // ==========
          // for the 1st  TX the RAMP is:        RAMP_UP_TX1     / RAMP_DOWN_TX1
          // for the 2nd  TX the RAMP is:        RAMP_UP_TX2     / RAMP_DOWN_TX1
          // for the 3rd   TX the RAMP is:        RAMP_UP_TX3    / RAMP_DOWN_TX2
          // (...)
          // for the (i)th TX the RAMP is:        RAMP_UP_TX_(i) / RAMP_DOWN_TX_(i-1)
          // for the additionnal RAMP   :            xxxx        / RAMP_DOWN_TX_last

          txpwr_ramp_up = txpwr[i+ts_conv]; // the ramp up is the current TX

          if(last_TX == NO_TX)  // specific case of the first TX
            txpwr_ramp_down = txpwr[i+ts_conv];       // the ramp down is the current TX
          else
            txpwr_ramp_down = txpwr[last_TX+ts_conv]; // the ramp down is the previous TX

         #if(RF_FAM == 61)
	    #if(DSP == 38) || (DSP == 39)
             Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx++][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq);
	    #endif
        #else
			#if (CODE_VERSION != SIMULATION)
             Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx++][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq);
         #endif
		  #endif
        }

        // memorize the last TX window
        last_TX = i;
      }
      else
      {
         // program an interrupt in the TS following
         // the last TX window and needed by the DSP

         // Is it the TS following a TX window ?
#if 0	/* original LoCosto code */
         if((i == last_TX+1) && (i<8))
#else	/* FreeCalypso TCS211 reconstruction */
         if (i == last_TX+1)
#endif
         {
           // program the interrupt
           l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] = (1 << B_MS_RULE);
         }
        }
      }

    // in a multi-TX case an additionnal ramp down must be set
    if(cpt_TX > 1)
    {
       // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..] for slot i and set the interrupt
#if 0	/* FreeCalypso TCS211 reconstruction */
	   if((last_TX+1) <= 7)
#endif
       l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[last_TX+1] = ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_MS_RULE));

       // Store Ramp.
       // ==========
       txpwr_ramp_up   = txpwr[last_TX+ts_conv]; // this ramp up is unused (default: set to last_TX)
       txpwr_ramp_down = txpwr[last_TX+ts_conv]; // the  ramp down is the last TX

      #if(RF_FAM == 61)
        #if(DSP ==38) || (DSP == 39)
             Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq);
	 #endif
      #else
		#if (CODE_VERSION != SIMULATION)
             Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq);
		#endif
      #endif
    }
 //  #endif Locosto
}


/*-------------------------------------------------------*/
/* l1pddsp_ul_ptcch_data()                               */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_ul_ptcch_data(UWORD8   cs_type,
                           UWORD16  channel_request_data,
                           UWORD8   bsic,
                           UWORD16  radio_freq,
                           UWORD8   timeslot_no)
{
  UWORD16  swap_bit; // 16 bit wide to allow shift left.

  // UL on TS=timeslot_no.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> timeslot_no;

  // Swap I/Q management.
  swap_bit = l1ps_swap_iq_ul(radio_freq);
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15;

  // Set "b_ptcch_ul" to indicate PTCCH/UL to DSP.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= (1 << B_PTCCH_UL);

  // Store CS type.
  l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[0] = cs_type;

  // Store UL data block.
  if(cs_type == CS_PAB8_TYPE)
  {
    l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[1] = ((API)(bsic << 2)) |
                                                  ((API)(channel_request_data) << 8);
    l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[2] = 0;
  }
  else
  {
    l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[1] = ((API)(channel_request_data) << 5);
    l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[2] = ((API)(bsic << 10));
  }
}


/*-------------------------------------------------------*/
/* l1pddsp_interf_meas_ctrl()                            */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
void l1pddsp_interf_meas_ctrl(UWORD8  nb_meas_req)
{
  // Interference measurement task set as a monitoring task within GSM interface.
  // 101 means 1 meas, 102 means 2 meas ...
  // Rem: swap I/Q is not managed for power measurements.
  l1s_dsp_com.dsp_db_w_ptr->d_task_md = INTERF_DSP_TASK + nb_meas_req;
}


/*-------------------------------------------------------*/
/* l1pddsp_transfer_meas_ctrl()                          */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_transfer_meas_ctrl(UWORD8  meas_position)
{
  // Store measurement position.
  // Rem: This is a L1S filtered information giving the position of the meas. as a
  // bitmap.
  // Rem: swap I/Q is not managed for power measurements.
  l1ps_dsp_com.pdsp_db_w_ptr->d_task_pm_gprs = meas_position;
}

/*-------------------------------------------------------*/
/* l1pddsp_meas_ctrl()                                   */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_meas_ctrl(UWORD8 nbmeas, UWORD8 pm_pos)
{
  // Request Signal level measurement task to DSP. A bit map is passed
  // to DSP in order to specify the position of the measurement.
  // Note: MSB is TN = 0 and LSB is TN = 7.
  // Rem: swap I/Q is not managed for power measurements.
  // Note: currently a maximum of four Pm can be performed / TDMA. This would
  // be modified in a near futur.
  // Note: If a Rx is programmed i.e. pm_pos = 1, only a maximum
  // of 3 Pm is requested to DSP and position of the Pm are  right shifted (Rx on TN = 0).
  // Remark: In packet Idle mode Rx are still on TN = 0. This implies three Pm
  // always after the Rx.
    l1ps_dsp_com.pdsp_db_w_ptr->d_task_pm_gprs = ((UWORD8) (0xff << (8 - nbmeas))) >> pm_pos;
}

/*-------------------------------------------------------*/
/* l1pddsp_meas_read()                                   */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_meas_read(UWORD8 nbmeas, UWORD8 *a_pm)
{
  UWORD8 i = 0;
  UWORD8 j;
  UWORD8 bit_mask = 0x80;

  // Looks for first PM position
  while ((i < 8) && (l1ps_dsp_com.pdsp_db_r_ptr->d_task_pm_gprs & bit_mask) == 0)
  {
    i++;
    bit_mask >>= 1;
  }

  // Read 'nbmeas' contiguous PM levels from the first PM position
  // Note: PM are always programmed on contiguous timeslots
#if 0	/* original LoCosto code */
  for (j = 0; ((j < nbmeas)&&(i < 8)); j++)
#else	/* FreeCalypso TCS211 reconstruction */
  for (j = 0; j < nbmeas; j++)
#endif
  {
    // Download PM from DSP/MCU memory interface
    a_pm[j] = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[i] & 0xffff) >> 5;

    // Read next PM on following TN
    i++;
  }
}

/*-------------------------------------------------------*/
/* l1pddsp_load_bcchn_task()                             */
/*-------------------------------------------------------*/
/* Parameters :                                          */
/* Return     :                                          */
/* Functionality :                                       */
/*-------------------------------------------------------*/
void l1pddsp_load_bcchn_task(UWORD8 tsq,UWORD16 radio_freq )
{
  UWORD16 swap_bit = l1ps_swap_iq_dl(radio_freq);

  l1s_dsp_com.dsp_db_w_ptr->d_task_md      = NBN_DSP_TASK | (swap_bit << 15);  // Load BCCHN task
  l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsq << B_TSQ;
}
#endif