view src/cs/layer1/tm_cfile/l1tm_func.c @ 356:984df0753560

gsmcomp.c: voice-only config partition pool sizing fixes from Citrine
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 25 Dec 2017 02:14:55 +0000
parents b870b6a44d31
children
line wrap: on
line source

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

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

#if TESTMODE
  #define L1TM_FUNC_C

  #include <string.h>
  #include <math.h>
  #include "abb.h"

  #include "general.h"

  #include "l1_types.h"
  #include "sys_types.h"
  #include "l1_const.h"
  #include "l1_time.h"
  #include "l1_signa.h"

  #include "l1tm_defty.h"

  #if 0 //(CODE_VERSION != SIMULATION)	// LoCosto-ism
    #include "pld.h"
  #endif

  #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0)
    #include "rvt_gen.h"
    extern T_RVT_USER_ID  tm_trace_user_id;
  #endif

  #if (AUDIO_TASK == 1)
    #include "l1audio_const.h"
    #include "l1audio_cust.h"
    #include "l1audio_defty.h"
  #endif

  #if (L1_GTT == 1)
    #include "l1gtt_const.h"
    #include "l1gtt_defty.h"
  #endif

  #if (L1_MP3 == 1)
    #include "l1mp3_defty.h"
  #endif

  #if (L1_MIDI == 1)
    #include "l1midi_defty.h"
  #endif

  #include "l1_defty.h"
  #include "cust_os.h"
  #include "l1_msgty.h"
  #include "l1_varex.h"
  #include "l1_proto.h"

  #include "mem.h"

  #if (CODE_VERSION != SIMULATION)

    #if (RF_FAM == 61)
      #include "tpudrv61.h"
      #include "l1_rf61.h"
      #include "l1tm_tpu61.h"
      #if (DRP_FW_EXT==1)
        #include "l1_drp_inc.h"
      #else
        #include "drp_drive.h"
      #endif
    #endif

    #if (RF_FAM == 60)
      #include "tpudrv60.h"
      #include "l1_rf60.h"
      #include "l1tm_tpu60.h"
      #include "drp_drive.h"
    #endif

    #if (RF_FAM==43)
      #include "tpudrv43.h"
      #include "l1_rf43.h"
      #include "l1tm_tpu43.h"
    #endif
    #if (RF_FAM == 35)
      #include "tpudrv35.h"
      #include "l1_rf35.h"
      #include "l1tm_tpu35.h"
    #endif

    #if (RF_FAM == 12)
      #include "tpudrv12.h"
      #include "l1_rf12.h"
      #include "l1tm_tpu12.h"
    #endif

    #if (RF_FAM == 10)
      #include "tpudrv10.h"
      #include "l1_rf10.h"
      #include "l1tm_tpu10.h"
    #endif

    #if (RF_FAM == 8)
      #include "tpudrv8.h"
      #include "l1_rf8.h"
      #include "l1tm_tpu8.h"
    #endif

    #if (RF_FAM == 2)
      #include "tpudrv2.h"
      #include "l1_rf2.h"
      #include "l1tm_tpu2.h"
    #endif

  #else

    #if (RF_FAM == 2)
      #include "l1_rf2.h"
    #endif

  #endif

  #include <assert.h>
  #include <string.h>

  #include "l1tm_msgty.h"
  #include "l1tm_signa.h"
  #include "l1tm_varex.h"
  #include "l1tm_ver.h"

  #if L1_GPRS
    #include "l1p_cons.h"
    #include "l1p_msgt.h"
    #include "l1p_deft.h"
    #include "l1p_vare.h"
    #include "l1p_sign.h"
  #endif

  #if ((L1_STEREOPATH == 1) && (OP_L1_STANDALONE == 1))
    #include "sys_dma.h"
  #endif

#if(L1_FF_MULTIBAND == 1)
extern UWORD8 tm_band;
#endif /*if (L1_FF_MULTIBAND == 1)*/
  

// Prototypes from external functions
//------------------------------------
UWORD16 Convert_l1_radio_freq(SYS_UWORD16 radio_freq);

void Cust_tm_rf_param_write        (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value);
void Cust_tm_rf_param_read         (T_TM_RETURN *tm_return, WORD16 index);
void Cust_tm_rf_table_write        (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]);
void Cust_tm_rf_table_read         (T_TM_RETURN *tm_return, WORD8 index);
void Cust_tm_rx_param_write        (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value);
void Cust_tm_rx_param_read         (T_TM_RETURN *tm_return, WORD16 index);
void Cust_tm_tx_param_write        (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value, UWORD8 band);
void Cust_tm_tx_param_read         (T_TM_RETURN *tm_return, WORD16 index, UWORD8 band);
void Cust_tm_tx_template_write     (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]);
void Cust_tm_tx_template_read      (T_TM_RETURN *tm_return, WORD8 index);
void Cust_tm_special_param_write   (T_TM_RETURN *tm_return, WORD16 index, UWORD16 value);
void Cust_tm_special_param_read    (T_TM_RETURN *tm_return, WORD16 index);
void Cust_tm_special_table_write   (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]);
void Cust_tm_special_table_read    (T_TM_RETURN *tm_return, WORD8 index);
void Cust_tm_special_enable        (T_TM_RETURN *tm_return, WORD16 action);

#if (CODE_VERSION != SIMULATION)
  void Cust_tm_tpu_table_write       (T_TM_RETURN *tm_return, WORD8 index, UWORD8 size, UWORD8 table[]);
  void Cust_tm_tpu_table_read        (T_TM_RETURN *tm_return, WORD8 index);
#endif

//------------------------------------
// Prototypes from external functions
//------------------------------------

void Cust_tm_init                   (void);
void l1tm_reset_rx_state            (void);
void l1tm_reset_rx_stats            (void);

#if L1_GPRS
  void l1pa_reset_cr_freq_list      (void);
#endif

//------------------------------------
// Prototypes from internal functions
//------------------------------------

void l1tm_initialize_var(void);
UWORD16 l1tm_convert_arfcn2l1ch(UWORD16 arfcn, UWORD8 *error_flag);
void l1tm_stats_read(T_TM_RETURN *tm_return, WORD16 type, UWORD16 bitmask);
void tm_transmit(T_TM_RETURN *tm_ret);
void l1tm_PRBS1_generate(UWORD16 *TM_ul_data);

#if ((L1_STEREOPATH == 1) && (OP_L1_STANDALONE == 1))
  void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status);
  void l1tm_stereopath_fill_buffer(void* buffer_address);
  UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type);
#endif

/***********************************************************************/
/*                           TESTMODE 3.X                              */
/***********************************************************************/

static UWORD8 tx_param_band=0;  // used in tx_param_write/read; default is GSM900




// RF,(ANALOG)or other hardware dependent functions
// - work done by tmrf.c functions for each product.

// TestMode functions that modify the state variables
// within the L1A - may need to allocate space
// dynamically if this is the first time calling
// these functions.

// TestMode functions that start L1A state machines
// may need to send L1A primitives to change L1A state.

void l1tm_rf_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;
  tm_return->size = 0;

  switch (prim->u.tm_params.index)
  {
	  #if (FF_REPEATED_SACCH == 1)
	      // Repeated SACCH mode
	   case REPEATED_SACCH_ENA_FLAG:
	   {
	    l1_config.repeat_sacch_enable = prim->u.tm_params.value;
	    #if (ETM_PROTOCOL == 1)
	            tm_return->status = -ETM_OK;
	    #else
	            tm_return->status = E_OK;
	    #endif
	          break;
	      }
	  #endif /* FF_REPEATED_SACCH */

	  #if (FF_REPEATED_DL_FACCH == 1)
	      // Repeated FACCH mode
	      case REPEATED_FACCHDL_ENA_FLAG:
	      {
	          l1_config.repeat_facch_dl_enable = prim->u.tm_params.value;
	       #if (ETM_PROTOCOL == 1)
	            tm_return->status = -ETM_OK;
	       #else
	            tm_return->status = E_OK;
	       #endif/*(ETM_PROTOCOL == 1)*/

	       break;
	      }
     #endif /* FF_REPEATED_DL_FACCH == 1 */
    case BCCH_ARFCN:
    {
      UWORD16 bcch_arfcn;
      UWORD8  error_flag;

      bcch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag);

      if (error_flag)
      {
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
      }
      else
      {
        l1_config.tmode.rf_params.bcch_arfcn = bcch_arfcn;

        // now change on the fly
        // no reason to check dedicated_active flag...
        // we just set these 2 globals for FB/SB/BCCH tests
        l1a_l1s_com.nsync.list[0].radio_freq = l1_config.tmode.rf_params.bcch_arfcn;
        l1a_l1s_com.Scell_info.radio_freq    = l1_config.tmode.rf_params.bcch_arfcn;
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_OK;
      #else
        tm_return->status = E_OK;
      #endif
      }
      break;
    }
    case TCH_ARFCN:
    {
      T_CHN_SEL *chan_sel;
      UWORD16    tch_arfcn;
      UWORD8     error_flag;

      tch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag);

      if (error_flag)
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
      else
      {
        l1_config.tmode.rf_params.tch_arfcn = tch_arfcn;

        // now change on the fly if necessary
        if (l1_config.TestMode && l1tm.tmode_state.dedicated_active)
        {
          chan_sel = &(l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->chan_sel);
          chan_sel->rf_channel.single_rf.radio_freq = l1_config.tmode.rf_params.tch_arfcn;
        }
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_OK;
      #else
        tm_return->status = E_OK;
      #endif
      }
      break;
    }
    case MON_ARFCN:
    {
      UWORD16 mon_arfcn;
      UWORD8  error_flag;

      mon_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag);

      if (error_flag)
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
      else
      {
        l1_config.tmode.rf_params.mon_arfcn = mon_arfcn;
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_OK;
      #else
        tm_return->status = E_OK;
      #endif
      }
      break;
    }
    #if L1_GPRS
      case PDTCH_ARFCN:
      {
        UWORD16    pdtch_arfcn;
        UWORD8     error_flag;

        pdtch_arfcn = l1tm_convert_arfcn2l1ch(prim->u.tm_params.value, &error_flag);

        if (error_flag)
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
        else
        {
          l1_config.tmode.rf_params.pdtch_arfcn = pdtch_arfcn;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
    #endif
    case AFC_ENA_FLAG:
    {
      l1_config.afc_enable = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case AFC_DAC_VALUE:
    {
      WORD16 afc_value = prim->u.tm_params.value;
      // 13-bit AFC DAC
     #if(RF_FAM != 61)
           if (afc_value<-4096 || afc_value>4095)
     #else
          if (afc_value<-8192 || afc_value>8191)
     #endif
       {
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
        break;
       }

      if (!l1_config.afc_enable)
      {
        // write AFC value to AFC DAC ASAP!! AFC DAC will be updated by any RX
        // or TX test.
        l1s.afc = afc_value;
      }

    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    #if L1_GPRS
      case MULTISLOT_CLASS:
      {
        UWORD8    multislot_class;

        multislot_class = prim->u.tm_params.value;

        if ((multislot_class < 1) || (multislot_class > 12))
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
        else
        {
          l1_config.tmode.rf_params.multislot_class = multislot_class;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
#endif // end of L1_GPRS
    default:
    {
      Cust_tm_rf_param_write(tm_return,
                             prim->u.tm_params.index,
                             prim->u.tm_params.value);
      break;
    }
  } // end switch
}

UWORD16 l1tm_convert_arfcn2l1ch(UWORD16 arfcn, UWORD8 *error_flag)
#if (L1_FF_MULTIBAND == 0)    
{
  /*  Here, before we store the channel numbers to the l1_config structure,
      we convert from ETSI to TI channel numbering system.  The GGT
      ALWAYS expects the ETSI numbering system as input and output.

      We need to do the OPPOSITE of what is done in convert_l1_arfcn() in
      tpudrvX.c

      ***************************************
      *** convert arfcn's from ETSI to TI ***
      ***************************************
      **                                   **
      **     ETSI                 TI       **
      **           0   GSM          174    **
      **    1 -  124   GSM      1 - 124    **
      **  975 - 1023  E-GSM   125 - 173    **
      **  512 -  885   DCS    174 - 548    **
      **                                   **
      ***************************************      */

  *error_flag = 0;

  switch (l1_config.std.id)
  {
    case GSM:
    case DCS1800:
    case PCS1900:
    case GSM850:
      break;

    case DUAL:
      if ((arfcn >= 512) && (arfcn <= 885)) arfcn -= 337;
      else if (arfcn > 124) *error_flag = 1; // invalid arfcn
      break;

    case DUALEXT:
      if (arfcn == 0) arfcn = 174;
      else if ((arfcn >= 975) && (arfcn <= 1023)) arfcn -= 850;
      else if ((arfcn >= 512) && (arfcn <= 885))  arfcn -= 337;
      else if ((arfcn >= 1)   && (arfcn <= 124));
      else *error_flag = 1; // invalide arfcn
      break;

    case DUAL_US:  // GSM850:128-251  PCS1900:512-810
      if ((arfcn >= 128) && (arfcn <= 251)) arfcn -= 127;
      else if ((arfcn >= 512) && (arfcn <= 810)) arfcn -= 387;
      else *error_flag = 1; // invalid arfcn
      break;

    default:
      *error_flag = 1; // invalid std.id
      break;
  } // end switch
  return arfcn;
}
#else // L1_FF_MULTIBAND = 1 below

{
    *error_flag=0;
    if(tm_band == RF_PCS1900)
    {
      arfcn = arfcn + 512;
    }
    return(arfcn);
#if 0
  UWORD16 l1_radio_freq = 0;
  UWORD8 effective_band_id = 0;
  *error_flag = 1; 
  for (effective_band_id = 0; effective_band_id < RF_NB_SUBBANDS; effective_band_id ++)
  {
    if( multiband_conversion_data[effective_band_id].physical_band_id == tm_band)
    {
      if( (arfcn - multiband_conversion_data[effective_band_id].first_tpu_radio_freq) < multiband_conversion_data[effective_band_id].nbmax_carrier)
      {
        l1_radio_freq =   arfcn - multiband_conversion_data[effective_band_id].first_tpu_radio_freq + multiband_conversion_data[effective_band_id].first_radio_freq;          
        *error_flag = 0; 
        return(l1_radio_freq);
      }
    }
  }
  return(l1_radio_freq);
#endif

}

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


void l1tm_rf_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  volatile UWORD16 value;

  tm_return->index = prim->u.tm_params.index;

  switch (prim->u.tm_params.index)
  {
    #if (FF_REPEATED_SACCH == 1 )
    /* Repeated SACCH mode */
    case REPEATED_SACCH_ENA_FLAG:
   {
     value = l1_config.repeat_sacch_enable;
     break;
   }
   #endif /* FF_REPEATED_SACCH */

   #if FF_REPEATED_DL_FACCH
       // Repeated FACCH mode
       case REPEATED_FACCHDL_ENA_FLAG:
       {
           value = l1_config.repeat_facch_dl_enable;
           break;
       }
   #endif /* FF_REPEATED_DL_FACCH */


    case BCCH_ARFCN:
    {
      // return ETSI value for channel number
      value = Convert_l1_radio_freq(l1_config.tmode.rf_params.bcch_arfcn);
      break;
    }
    case TCH_ARFCN:
    {
      // return ETSI value for channel number
      value = Convert_l1_radio_freq(l1_config.tmode.rf_params.tch_arfcn);
      break;
    }
    case MON_ARFCN:
    {
      // return ETSI value for channel number
      value = Convert_l1_radio_freq(l1_config.tmode.rf_params.mon_arfcn);
      break;
    }
    #if L1_GPRS
      case PDTCH_ARFCN:
      {
        // return ETSI value for channel number
        value = Convert_l1_radio_freq(l1_config.tmode.rf_params.pdtch_arfcn);
        break;
      }
    #endif
    case AFC_ENA_FLAG:
    {
      value = l1_config.afc_enable;
      break;
    }
    case AFC_DAC_VALUE:
    {
      value = l1s.afc; // returned as F13.3
      break;
    }
    #if L1_GPRS
      case MULTISLOT_CLASS:
      {
        value = l1_config.tmode.rf_params.multislot_class;
        break;
      }
    #endif
    default:
    {
      Cust_tm_rf_param_read(tm_return, prim->u.tm_params.index);
      return;
    }
  } // end switch

  memcpy(tm_return->result, (UWORD8 *)&value, 2);
  tm_return->size = 2;
#if (ETM_PROTOCOL == 1)
  tm_return->status = -ETM_OK;
#else
  tm_return->status = E_OK;
#endif
}

void l1tm_rf_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_rf_table_write(tm_return,
                         prim->u.tm_table.index,
                         prim->str_len_in_bytes - 1,    // subtract 8-bit index
                         prim->u.tm_table.table);
}

void l1tm_rf_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_rf_table_read(tm_return, prim->u.tm_table.index);
}

void l1tm_rx_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;
  tm_return->size = 0;

  switch (prim->u.tm_params.index)
  {
    case RX_AGC_GAIN:
    {
      WORD8 gain = prim->u.tm_params.value;

      // It is up to the user to write a valid gain,
      // one that falls within the range of gains in the current RF
      // AGC gain can only be controlled in 2dB steps as the bottom bit (bit zero)
      // corresponds to the lna_off bit
      l1_config.tmode.rx_params.agc     = gain & ~0x01;
      l1_config.tmode.rx_params.lna_off = gain &  0x01;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case RX_TIMESLOT:
    {
      if (prim->u.tm_params.value > 7)
      {
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
        break;
      }

      l1_config.tmode.rx_params.slot_num = prim->u.tm_params.value;
      if (l1_config.TestMode && l1tm.tmode_state.dedicated_active)
      {
        // currently CANNOT change RX slot on the fly!
      }

    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case RX_PM_ENABLE:
    {
      l1_config.tmode.rx_params.pm_enable = prim->u.tm_params.value;

    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    #if L1_GPRS
      case RX_GPRS_SLOTS:
      {
        // At least one DL TS needs to be allocated
        if (!prim->u.tm_params.value)
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_INVAL;
          #else
            tm_return->status = E_INVAL;
          #endif
        else
        {
          l1_config.tmode.rx_params.timeslot_alloc = prim->u.tm_params.value;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
      case RX_GPRS_CODING:
      {
        UWORD8 coding_scheme;

        coding_scheme = prim->u.tm_params.value;
        if ((coding_scheme < 1) || (coding_scheme > 6) || (coding_scheme == 3))
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_INVAL;
          #else
            tm_return->status = E_INVAL;
          #endif
        else
        {
          l1_config.tmode.rx_params.coding_scheme = prim->u.tm_params.value;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
    #endif
    case RX_AGC_ENA_FLAG:
    {
      l1_config.agc_enable = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    default:
    {
      Cust_tm_rx_param_write(tm_return,
                             prim->u.tm_params.index,
                             prim->u.tm_params.value);
      break;
    }
  } // end switch
}

void l1tm_rx_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  volatile UWORD16 value;

  tm_return->index = prim->u.tm_params.index;

  switch (prim->u.tm_params.index)
  {
    case RX_AGC_GAIN:
    {
      value = l1_config.tmode.rx_params.agc | l1_config.tmode.rx_params.lna_off;
      break;
    }
    case RX_TIMESLOT:
    {
      value = l1_config.tmode.rx_params.slot_num;
      break;
    }
    case RX_AGC_ENA_FLAG:
    {
      value = l1_config.agc_enable;
      break;
    }
    case RX_PM_ENABLE:
    {
      value = l1_config.tmode.rx_params.pm_enable;
      break;
    }
    #if L1_GPRS
      case RX_GPRS_SLOTS:
      {
        value = l1_config.tmode.rx_params.timeslot_alloc;
        break;
      }
      case RX_GPRS_CODING:
      {
        value = l1_config.tmode.rx_params.coding_scheme;
        break;
      }
    #endif
    default:
    {
      Cust_tm_rx_param_read(tm_return, prim->u.tm_params.index);
      return;
    }
  } // end switch

  memcpy(tm_return->result, (UWORD8 *)&value, 2);
  tm_return->size = 2;
#if (ETM_PROTOCOL == 1)
  tm_return->status = -ETM_OK;
#else
  tm_return->status = E_OK;
#endif
}

void l1tm_tx_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;
  tm_return->size = 0;

  switch (prim->u.tm_params.index)
  {
    case TX_PWR_LEVEL:
    {
      UWORD8 temp_txpwr, temp_band;

      if (prim->u.tm_params.value < 100)  // GSM900
      {
        temp_txpwr = prim->u.tm_params.value;
        temp_band = 0;
      }
      else if (prim->u.tm_params.value < 200)  // DCS1800
      {
        temp_txpwr = prim->u.tm_params.value - 100;
        temp_band = 1;
      }
      else if (prim->u.tm_params.value < 300)  // PCS1900
      {
        temp_txpwr = prim->u.tm_params.value - 200;
        temp_band = 2;
      }
      else  // force invalid values to return -ETM_INVAL or E_INVAL
      {
        temp_txpwr = 50;
        temp_band = 10;
      }

      // Note that the pwr level is only checked for being within the range [0..31]
      // because all pwr levels should be testable.
      // For subfunctions [TX_APC_DAC..TX_DELAY_DOWN]:
      //     temp_txpwr +   0 ==> GSM900
      //     temp_txpwr + 100 ==> DCS1800
      //     temp_txpwr + 200 ==> PCS1900

      // Changing tx pwr level on the fly while in continuous mode is not supported.
      if (temp_txpwr > 31 || temp_band > 2 ||
          l1_config.tmode.rf_params.tmode_continuous == TM_CONTINUOUS)
      {
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_INVAL;
        #else
          tm_return->status = E_INVAL;
        #endif
        break;
      }

      l1_config.tmode.tx_params.txpwr = temp_txpwr;
      tx_param_band = temp_band;

      // if in TX mode, change txpwr on the fly
      if ((l1_config.TestMode) &&
          (l1tm.tmode_state.dedicated_active) &&
          (l1_config.tmode.rf_params.down_up & TMODE_UPLINK))
      {
        // this causes 'direct' changing of TXPWR, which is OK in TestMode
        l1a_l1s_com.dedic_set.aset->new_target_txpwr = l1s.applied_txpwr = l1_config.tmode.tx_params.txpwr;
      }

    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case TX_TIMING_ADVANCE:
    {
      l1_config.tmode.tx_params.timing_advance = prim->u.tm_params.value;

      if (l1_config.TestMode && l1tm.tmode_state.dedicated_active)
      {
        // direct changing of Timing Advance
        l1a_l1s_com.dedic_set.aset->new_timing_advance = l1_config.tmode.tx_params.timing_advance;
        // new TA to take effect immediately
        l1a_l1s_com.dedic_set.aset->timing_advance = l1a_l1s_com.dedic_set.aset->new_timing_advance;
      }
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case TX_PWR_SKIP:
    {
      l1_config.tmode.tx_params.txpwr_skip = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    #if L1_GPRS
      case TX_GPRS_POWER0:
      case TX_GPRS_POWER1:
      case TX_GPRS_POWER2:
      case TX_GPRS_POWER3:
      case TX_GPRS_POWER4:
      case TX_GPRS_POWER5:
      case TX_GPRS_POWER6:
      case TX_GPRS_POWER7:
      {
        l1_config.tmode.tx_params.txpwr_gprs[prim->u.tm_params.index - TX_GPRS_POWER0] = prim->u.tm_params.value;
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_OK;
      #else
        tm_return->status = E_OK;
      #endif
        break;
      }
      case TX_GPRS_SLOTS:
      {
        l1_config.tmode.tx_params.timeslot_alloc = prim->u.tm_params.value;
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_OK;
      #else
        tm_return->status = E_OK;
      #endif
        break;
      }
      case TX_GPRS_CODING:
      {
        UWORD8 coding_scheme;

        coding_scheme = prim->u.tm_params.value;
        if ((coding_scheme < 2) || (coding_scheme > 6) || (coding_scheme == 3))
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_INVAL;
          #else
            tm_return->status = E_INVAL;
          #endif
        else
        {
          l1_config.tmode.tx_params.coding_scheme = prim->u.tm_params.value;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
    #endif
    default:
    {
      Cust_tm_tx_param_write(tm_return,
                             prim->u.tm_params.index,
                             prim->u.tm_params.value,
                             tx_param_band);
      break;
    }
  } // end switch
}

void l1tm_tx_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;

  Cust_tm_tx_param_read(tm_return,
                        prim->u.tm_params.index,
                        tx_param_band);
}

void l1tm_tx_template_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_tx_template_write(tm_return,
                            prim->u.tm_table.index,
                            prim->str_len_in_bytes - 1, // subtract 8-bit index
                            prim->u.tm_table.table);
}

void l1tm_tx_template_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_tx_template_read(tm_return, prim->u.tm_table.index);
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_mode_set(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  switch (prim->u.tm_params.index) {
  case 0:
    l1_config.TestMode = 0;
    tm_return->status = E_OK;
    break;
  case 1:
    l1_config.TestMode = 1;
    l1_config.tx_pwr_code = 1;
    l1_config.pwr_mngt = 0;
    tm_return->status = E_OK;
    Cust_tm_init();
    l1tm_initialize_var();
    break;
  default:
    tm_return->status = E_INVAL;
  }
  tm_return->index = 0;
  tm_return->size = 0;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_version_get(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  UWORD16 revision;
  extern  T_RF rf;

  tm_return->index = prim->u.tm_params.index;

  switch (prim->u.tm_params.index) {
    /* "meat" of this switch statement taken from LoCosto etm_tm3core.c */
    case BBCHIP_MODULE_REV:
        revision = CHIPSET;
        break;
    case CHIPID_MODULE_REV:
        revision = *( (volatile UWORD16 *) (MEM_JTAGID_PART));
        break;
    case CHIPVER_MODULE_REV:
        revision = *( (volatile UWORD16 *) (MEM_JTAGID_VER));
        break;
    case DSPSW_MODULE_REV:
        revision = l1s.version.dsp_code_version;
        break;
    case ANALOGCHIP_MODULE_REV:
        revision = ((ANLG_PG << 7) | ANLG_FAM);
        break;
    case LAYER1_MODULE_REV:
        revision = l1s.version.mcu_tcs_official;
        break;                
    case RFDRIVER_MODULE_REV:
        revision = rf.rf_revision;
        break;                
    case TM_API_MODULE_REV:
        revision = TMAPIVERSION;
        break;
    case L1_TM_CORE_MODULE_REV:
        revision = l1s.version.mcu_tm_version;
        break;
    case DSP_MODULE_REV:
        revision = DSP;
        break;
    case RF_MODULE_REV: 
        revision = ((RF_PA << 10) | (RF_PG << 7) | RF_FAM);
        break;
    default:
        tm_return->status = E_BADINDEX;
        tm_return->size = 0;
        return;
  }
  memcpy(tm_return->result, &revision, sizeof revision);
  tm_return->size = sizeof revision;
  tm_return->status = E_OK;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_mem_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  UWORD8 *mem_ptr;
  UWORD8 num_of_bytes;
  UWORD16 i;

  mem_ptr = (UWORD8 *) prim->u.mem_write.address;
  num_of_bytes = prim->str_len_in_bytes - 4;
  for (i = 0; i < num_of_bytes; i++)
    mem_ptr[i] = prim->u.mem_write.table[i];
  tm_return->size = 0;
  tm_return->index = 0;
  tm_return->status = E_OK;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_mem_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = 0;
  if (prim->u.mem_read.length > TM_PAYLOAD_UPLINK_SIZE_MAX - 4) {
    tm_return->size = 0;
    tm_return->status = E_BADSIZE;
    return;
  }
  memcpy(tm_return->result, &prim->u.mem_read.length, 4);
  memcpy(tm_return->result + 4, (UWORD8 *) prim->u.mem_read.src,
         prim->u.mem_read.length);
  tm_return->size = prim->u.mem_read.length + 4;
  tm_return->status = E_OK;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_codec_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  UWORD16 page, reg;

  page = (prim->u.tm_params.index >> 5) & 1;
  reg = prim->u.tm_params.index & 0x1F;
  if (!l1_config.TestMode) {
    tm_return->status = E_TESTMODE;
    goto out;
  }
  if (page >= 2 || reg >= 32) {
    tm_return->status = E_INVAL;
    goto out;
  }
  ABB_Write_Register_on_page(page + 1, reg << 1,
                             prim->u.tm_params.value & 0x3FF);
  tm_return->status = E_OK;
out:
  tm_return->index = 0;
  tm_return->size = 0;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_codec_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  UWORD16 page, reg;
  UWORD16 value;

  page = (prim->u.tm_params.index >> 5) & 1;
  reg = prim->u.tm_params.index & 0x1F;
  value = ABB_Read_Register_on_page(page + 1, reg << 1);
  memcpy(tm_return->result, &value, 2);
  tm_return->size = 2;
  tm_return->status = E_OK;
  tm_return->index = 0;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_misc_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;
  tm_return->size = 0;
  switch (prim->u.tm_params.index) {
  case ADC_ENA_FLAG:
    l1_config.adc_enable = prim->u.tm_params.value;
    break;
  default:
    Cust_tm_misc_param_write(tm_return, prim->u.tm_params.index,
                             prim->u.tm_params.value);
    return;
  }
  tm_return->status = E_OK;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_misc_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  UWORD16 value;

  tm_return->index = prim->u.tm_params.index;
  switch (prim->u.tm_params.index) {
  case ADC_ENA_FLAG:
    value = l1_config.adc_enable;
    break;
  case CURRENT_TM_MODE:
    value = l1_config.TestMode;
    break;
  default:
    Cust_tm_misc_param_read(tm_return, prim->u.tm_params.index);
    return;
  }
  memcpy(tm_return->result, &value, 2);
  tm_return->size = 2;
  tm_return->status = E_OK;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_misc_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_misc_enable(tm_return, prim->u.tm_params.index);
}

void l1tm_special_param_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_special_param_write(tm_return,
                              prim->u.tm_params.index,
                              prim->u.tm_params.value);
}

void l1tm_special_param_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_special_param_read(tm_return, prim->u.tm_params.index);
}

void l1tm_special_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_special_table_write(tm_return,
                              prim->u.tm_table.index,
                              prim->str_len_in_bytes - 1,
                              prim->u.tm_table.table);
}

void l1tm_special_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_special_table_read(tm_return, prim->u.tm_table.index);
}

void l1tm_special_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  Cust_tm_special_enable(tm_return, prim->u.tm_params.index);
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_initialize(T_TM_RETURN *tm_return)
{
  Cust_tm_init();
  tm_return->status = E_OK;
  tm_return->size = 0;
  tm_return->index = 0;
}

/* TCS211 function missing in LoCosto, reconstructed from disassembly */
void l1tm_ffs(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->size = tm_ffs(tm_return->result, 32, prim->u.ffs.packet,
                           prim->str_len_in_bytes);
  tm_return->status = E_OK;
  tm_return->index = 0;
}

/*-------------------------------------------------------*/
/* l1tm_initialize_var()                                 */
/*-------------------------------------------------------*/
/* Parameters  :                                         */
/* -------------                                         */
/* Return      :                                         */
/* -------------                                         */
/* Description :                                         */
/* -------------                                         */
/* This routine is used to switch to TestMode by re-     */
/* initializing the l1a, l1s and l1a_l1s_com global      */
/* structures. Re-initialization is kept at a minimum.   */
/*-------------------------------------------------------*/
void l1tm_initialize_var(void)
{
  UWORD32 i;
  UWORD8  task_id;


  // L1S tasks management...
  //-----------------------------------------
  for(task_id=0; task_id<NBR_DL_L1S_TASKS; task_id++)
  {
    l1s.task_status[task_id].new_status     = NOT_PENDING;
    l1s.task_status[task_id].current_status = INACTIVE;
  }
  l1s.frame_count = 0;
  l1s.forbid_meas = 0;

  // MFTAB management variables...
  //-----------------------------------------
  l1s.afrm = 0;
  l1s_clear_mftab(l1s.mftab.frmlst);

  // Flag registers for RF task controle...
  //-----------------------------------------
  l1s.tpu_ctrl_reg = 0;
  l1s.dsp_ctrl_reg = 0;

  //++++++++++++++++++++++++++++++++++++++++++
  //  Reset "l1a" structure.
  //++++++++++++++++++++++++++++++++++++++++++

  // Downlink tasks management...
  // Uplink tasks management...
  // Measurement tasks management...
  //-----------------------------------------
  for(i=0; i<NBR_L1A_PROCESSES; i++)
  {
    l1a.l1a_en_meas[i] = 0;
    l1a.state[i]       = 0; // RESET state.
  }

  // Flag for forward/delete message management.
  //---------------------------------------------
  l1a.l1_msg_forwarded = 0;


  //++++++++++++++++++++++++++++++++++++++++++
  //  Reset "l1a_l1s_com" structure.
  //++++++++++++++++++++++++++++++++++++++++++

  l1a_l1s_com.l1a_activity_flag      = TRUE;
  l1a_l1s_com.time_to_next_l1s_task  = 0;


  // sleep management configuration
  //===============================
  l1s.pw_mgr.mode_authorized  = NO_SLEEP;

  // L1S scheduler...
  //====================

  // L1S tasks management...
  //-----------------------------------------
  for(i=0; i<NBR_DL_L1S_TASKS; i++)
  {
    l1a_l1s_com.task_param[i]  = SEMAPHORE_RESET;
    l1a_l1s_com.l1s_en_task[i] = TASK_DISABLED;
  }

  // Measurement tasks management...
  //-----------------------------------------
  l1a_l1s_com.meas_param  = 0;
  l1a_l1s_com.l1s_en_meas = 0;

  #if L1_GPRS
    // Set DSP scheduler mode
    l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER;
    //  Packet measurement: Reset of the frequency list.
    //-------------------------------------------------
    l1pa_reset_cr_freq_list();
    // Initialize active list used in Neighbour Measurement Transfer Process
    l1pa_l1ps_com.cres_freq_list.alist = &(l1pa_l1ps_com.cres_freq_list.list[0]);

    l1pa_l1ps_com.transfer.semaphore = TRUE;
    l1pa_l1ps_com.transfer.aset      = &(l1pa_l1ps_com.transfer.set[0]);
    l1pa_l1ps_com.transfer.fset[0]   = &(l1pa_l1ps_com.transfer.set[1]);
    l1pa_l1ps_com.transfer.fset[1]   = &(l1pa_l1ps_com.transfer.set[2]);

    for(i=0;i<3;i++)
    {
      l1pa_l1ps_com.transfer.set[i].SignalCode                   = 0;
      l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot      = 0;
      l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot      = 0;
      l1pa_l1ps_com.transfer.set[i].transfer_synchro_timeslot    = 0;
      l1pa_l1ps_com.transfer.set[i].allocated_tbf                = NO_TBF;
      l1pa_l1ps_com.transfer.set[i].assignment_command           = NO_TBF;
      l1pa_l1ps_com.transfer.set[i].multislot_class              = 0;

      l1pa_l1ps_com.transfer.set[i].packet_ta.ta                 = 255;
      l1pa_l1ps_com.transfer.set[i].packet_ta.ta_index           = 255;
      l1pa_l1ps_com.transfer.set[i].packet_ta.ta_tn              = 255;

      l1pa_l1ps_com.transfer.set[i].tsc                          = 0;

      l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel.h        = 0;
      l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel.
                                 rf_channel.single_rf.radio_freq = 0;

      l1pa_l1ps_com.transfer.set[i].tbf_sti.present              = FALSE;

      l1pa_l1ps_com.transfer.set[i].mac_mode                     = 0;

      l1pa_l1ps_com.transfer.set[i].ul_tbf_alloc->tfi            = 255;
      l1pa_l1ps_com.transfer.set[i].dl_tbf_alloc.tfi             = 255;

      l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.p0                = 255;
      l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.bts_pwr_ctl_mode  = 0;
      l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.pr_mode           = 0;
    }
  #endif

  // Init global test mode variables
  l1tm.tmode_state.dedicated_active = 0;
  #if L1_GPRS
    l1tm.tmode_state.packet_transfer_active = FALSE;
  #endif

  // PRBS seed initialization with a random pattern
  l1tm.tmode_prbs.prbs1_seed = 0x5613;
}

void l1tm_rf_enable(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  unsigned SignalCode =0;
  unsigned size = 0;  //omaps00090550
  xSignalHeaderRec *msg;
  UWORD8 send_prim = FALSE;  // Flag to send TestMode primitive...
                             // Do not send primitive is the default; change it if necessary
  UWORD8 band;
  tm_return->index = 0;      // don't include index in header
#if (ETM_PROTOCOL == 1)
  tm_return->status = -ETM_OK;
#else
  tm_return->status = E_OK;
#endif

  // Function only valid in TEST mode
  if (l1_config.TestMode == 0)
  {
  #if (ETM_PROTOCOL == 1)
    tm_return->status = -ETM_L1TESTMODE;
  #else
    tm_return->status = E_TESTMODE;
  #endif
  }
  else
  {
    // Reset all statistics
    l1tm_reset_rx_stats();

    // Reset receive state counters, unless already in dedicated mode
    if (!l1tm.tmode_state.dedicated_active)
      l1tm_reset_rx_state();

    // Reset monitor task
    l1_config.tmode.rf_params.mon_report = 0;
    l1_config.tmode.rf_params.mon_tasks  = 0;

    switch (prim->u.tm_params.index)
    {
      // Stop all RX and TX operations
      case STOP_ALL:
      {
        SignalCode = TMODE_STOP_RX_TX;
        size = sizeof(T_TMODE_STOP_RX_TX);
        l1tm.tmode_state.dedicated_active = 0;
        #if (RF_FAM == 61)
          // Reset the APC back to Automatic Mode
          l1ddsp_apc_set_automatic_mode();
        #endif

        #if (RF_FAM == 35)
          pll_tuning.enable=0;
        #endif
        // Reset down_up flag only if not in continuous mode. If in continuous mode, down_up
        // will be reset after the proper TPU scenario is loaded.
        if (l1_config.tmode.rf_params.tmode_continuous != TM_CONTINUOUS)
	  l1_config.tmode.rf_params.down_up = 0;
        send_prim = TRUE;
        break;
      }
      // RX with or without network synchronization first
      case RX_TCH:
      {
        // if already in UL-only
        if (l1tm.tmode_state.dedicated_active &&
            l1_config.tmode.rf_params.down_up == TMODE_UPLINK)
        {
          // cannot start to RX while already TXing
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_AGAIN;
        #else
          tm_return->status = E_AGAIN;
        #endif
        }
        else
        {
          l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK;
          SignalCode = TMODE_IMMED_ASSIGN_REQ;
          size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
          send_prim = TRUE;
        }
        break;
      }
      // TX NB's or AB's on TCH with or without network synch. first
      case TX_TCH:
      {
        // Normal burst TX
        if (l1_config.tmode.tx_params.burst_type == 0)
        {
          // if already in DL-only, add UL
          if (l1tm.tmode_state.dedicated_active &&
              l1_config.tmode.rf_params.down_up == TMODE_DOWNLINK)
          {
            l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK);
          }
          else
          {
            l1_config.tmode.rf_params.down_up = TMODE_UPLINK;
            SignalCode = TMODE_IMMED_ASSIGN_REQ;
            size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
            send_prim = TRUE;
          }
        }
        // AB TX
        else if (l1_config.tmode.tx_params.burst_type == 1)
        {
          // cannot start RACH while already in dedicated mode
          if (l1tm.tmode_state.dedicated_active)
          {
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_AGAIN;
          #else
            tm_return->status = E_AGAIN;
          #endif
          }
          else
          {
            SignalCode = TMODE_RA_START;
            size = sizeof(TMODE_RA_START);
            send_prim = TRUE;
          }
        }
        break;
      }
      // RX & TX on TCH with or without network synch. first
      case RX_TX_TCH:
      {
        // if NB TX
        if (l1_config.tmode.tx_params.burst_type == 0)
        {
          // if already in DL-only, add UL
          if (l1tm.tmode_state.dedicated_active &&
              l1_config.tmode.rf_params.down_up == TMODE_DOWNLINK)
          {
            l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK);
          }
          // else if already in UL-only
          else if (l1tm.tmode_state.dedicated_active &&
                   l1_config.tmode.rf_params.down_up == TMODE_UPLINK)
          {
            // cannot start to RX while already TXing
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_AGAIN;
          #else
            tm_return->status = E_AGAIN;
          #endif
          }
          else
          {
            l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK);
            SignalCode = TMODE_IMMED_ASSIGN_REQ;
            size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
            send_prim = TRUE;
          }
        }
        // else if AB TX
        else if (l1_config.tmode.tx_params.burst_type == 1)
        {
          // Cannot TX RACH and RX simultaneously
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_AGAIN;
        #else
          tm_return->status = E_AGAIN;
        #endif
        }
        break;
      }
      // Continuous (all timeslots) reception on TCH
      case RX_TCH_CONT:
      {
        // if already in UL, DL or UL+DL
        if (l1tm.tmode_state.dedicated_active &&
            l1_config.tmode.rf_params.down_up != 0)
        {
          // cannot start to continously RX while already TXing or RXing
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_AGAIN;
        #else
          tm_return->status = E_AGAIN;
        #endif
        }
        else
        {
          l1_config.tmode.rf_params.tmode_continuous = TM_START_RX_CONTINUOUS;
          l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK;
          SignalCode = TMODE_IMMED_ASSIGN_REQ;
          size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
          send_prim = TRUE;
        }
        break;
      }
      // continuous (all timeslots) transmission
      case TX_TCH_CONT:
      {
        // PCS 1900 not supported yet.
#if (L1_FF_MULTIBAND == 0)       
        band = ((l1_config.tmode.rf_params.tch_arfcn >= 512) &&
                (l1_config.tmode.rf_params.tch_arfcn <= 885));
#else
        band = ( ((l1_config.tmode.rf_params.tch_arfcn >= 512) &&
                (l1_config.tmode.rf_params.tch_arfcn <= 885)) || 
                ((l1_config.tmode.rf_params.tch_arfcn >= 1024) &&
                (l1_config.tmode.rf_params.tch_arfcn <= 1322)) );
#endif        

        // if already in UL, DL or UL+DL
        if ((l1tm.tmode_state.dedicated_active && l1_config.tmode.rf_params.down_up != 0) ||
            (band == 0 && (l1_config.tmode.tx_params.txpwr < (5 + l1_config.tmode.tx_params.txpwr_skip)))  ||
            (band == 1 && (l1_config.tmode.tx_params.txpwr < (0 + l1_config.tmode.tx_params.txpwr_skip))))
        {
          // cannot start to continously TX while already TXing or RXing
          // or while adc reading are enabled
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_INVAL;
          #else
            tm_return->status = E_INVAL;
          #endif
        }
        else
        {
          #if (RF_FAM == 61)
            // Set APC in Manual Mode
            l1ddsp_apc_set_manual_mode();
          #endif
          l1_config.tmode.rf_params.tmode_continuous = TM_START_TX_CONTINUOUS;
          l1_config.tmode.rf_params.down_up = TMODE_UPLINK;
          SignalCode = TMODE_IMMED_ASSIGN_REQ;
          size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
          send_prim = TRUE;
         }
        break;
      }
      // Continuous BCCH
      case BCCH_LOOP:
      {
        SignalCode = TMODE_SCELL_NBCCH_REQ;
        size = sizeof(TMODE_SCELL_NBCCH_REQ);
        send_prim = TRUE;
        break;
      }
      // Continuous SB
      case SB_LOOP:
      {
        SignalCode = TMODE_SB_REQ;
        size = sizeof(T_TMODE_SB_REQ);
        send_prim = TRUE;
        break;
      }
      // Continuous FB1
      case FB1_LOOP:
      {
        SignalCode = TMODE_FB1_REQ;
        size = sizeof(T_TMODE_FB1_REQ);
        send_prim = TRUE;
        break;
      }
      // Continuous FB0
      case FB0_LOOP:
      {
        SignalCode = TMODE_FB0_REQ;
        size = sizeof(T_TMODE_FB0_REQ);
        send_prim = TRUE;
        break;
      }
      // TX + RX + MON on TCH
      case RX_TX_MON_TCH: // Stats collected from TCH Channel.
      case RX_TX_MON:     // Stats collected from MON Channel (except rxlev).
      {
        // Normal burst uplink
        if (l1_config.tmode.tx_params.burst_type == 0)
        {
          // If already in dedicated mode, return error
          if (l1tm.tmode_state.dedicated_active)
          {
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_AGAIN;
          #else
            tm_return->status = E_AGAIN;
          #endif
          }
          else
          {
            l1_config.tmode.rf_params.down_up = (TMODE_DOWNLINK | TMODE_UPLINK);
            l1_config.tmode.rf_params.mon_report = ((prim->u.tm_params.index & 0x08) >> 3);
            l1_config.tmode.rf_params.mon_tasks = 1;  // enable MON tasks
            SignalCode = TMODE_IMMED_ASSIGN_REQ;
            size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
            send_prim = TRUE;
          }
        }
        // else if Access burst uplink
        else if (l1_config.tmode.tx_params.burst_type == 1)
        {
          // Cannot TX RACH and RX simultaneously
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_AGAIN;
        #else
          tm_return->status = E_AGAIN;
        #endif
        }
        break;
      }
      case SINGLE_PM:
      {
        SignalCode = TMODE_RXLEV_REQ;
        size = sizeof(T_TMODE_RXLEV_REQ);
        send_prim = TRUE;
        break;
      }
      #if L1_GPRS
        // RX & TX on PDTCH with or without network synch. first
        case RX_TX_PDTCH:
        {
          UWORD8 bit_map = 0x80;

          // set uplink + downlink
          if (l1_config.tmode.tx_params.timeslot_alloc)
            l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK | TMODE_UPLINK;
          else
            l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK;

          while (bit_map)
          {
            if (bit_map & l1_config.tmode.stats_config.stat_gprs_slots)
              l1tm.tmode_stats.nb_dl_pdtch_slots ++;

            bit_map>>=1;
          }

          SignalCode = TMODE_PDTCH_ASSIGN_REQ;
          size = sizeof(T_TMODE_PDTCH_ASSIGN_REQ);
          send_prim = TRUE;
          break;
        }
      #endif
      #if L1_GPRS
        // RX & TX on PDTCH, FB on monitor arfcn
        case RX_TX_PDTCH_MON:
        {
          // set uplink + downlink
          if (l1_config.tmode.tx_params.timeslot_alloc)
            l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK | TMODE_UPLINK;
          else
            l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK;

          l1_config.tmode.rf_params.mon_report = 1;  // collect stats from MON channel
          l1_config.tmode.rf_params.mon_tasks  = 1;  // enable MON tasks

          SignalCode = TMODE_PDTCH_ASSIGN_REQ;
          size = sizeof(T_TMODE_PDTCH_ASSIGN_REQ);
          send_prim = TRUE;
          break;
        }
      #endif
      #if (RF_FAM == 35)
      case RX_PLL_TUNING:
      {
        // if already in UL-only
        if (l1tm.tmode_state.dedicated_active &&
            l1_config.tmode.rf_params.down_up == TMODE_UPLINK)
        {
          // cannot start to RX while already TXing
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_AGAIN;
        #else
          tm_return->status = E_AGAIN;
        #endif
        }
        else
        {
          pll_tuning.data[5]   = 0;
          pll_tuning.index     = 0;

          pll_tuning.enable    = 1;

          l1_config.tmode.rf_params.down_up = TMODE_DOWNLINK;
          SignalCode = TMODE_IMMED_ASSIGN_REQ;
          size = sizeof(T_TMODE_IMMED_ASSIGN_REQ);
          send_prim = TRUE;
        }
        break;
      }
      #endif
      default:
      {
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_INVAL;
      #else
        tm_return->status = E_BADINDEX;
      #endif
        break;
      }
    } //end switch
  } // end of else

  if (send_prim == TRUE)
  {
    // Allocate result message.
    msg = os_alloc_sig(size);
    DEBUGMSG(status,NU_ALLOC_ERR)
    msg->SignalCode = SignalCode;
    os_send_sig(msg, L1C1_QUEUE);
    DEBUGMSG(status,NU_SEND_QUEUE_ERR)
  }

  // always return a 0 in the result[], even if error
  tm_return->result[0] = 0;
  tm_return->size =  1;
}


void l1tm_stats_config_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  tm_return->index = prim->u.tm_params.index;
  tm_return->size = 0;

  switch (prim->u.tm_params.index)
  {
    case LOOPS:
    {
      l1_config.tmode.stats_config.num_loops = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case AUTO_RESULT_LOOPS:
    {
      l1_config.tmode.stats_config.auto_result_loops = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case AUTO_RESET_LOOPS:
    {
      l1_config.tmode.stats_config.auto_reset_loops = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case STAT_TYPE:
    {
      l1_config.tmode.stats_config.stat_type = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    case STAT_BITMASK:
    {
      l1_config.tmode.stats_config.stat_bitmask = prim->u.tm_params.value;
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    #if L1_GPRS
      case STAT_GPRS_SLOTS:
      {
        UWORD8 allocation, value;

        value = prim->u.tm_params.value;

        // Check for mismatch between DL TS allocation and stats bitmap
        allocation = value ^ l1_config.tmode.rx_params.timeslot_alloc;

        if (value & allocation)
          #if (ETM_PROTOCOL == 1)
            tm_return->status = -ETM_INVAL;
          #else
            tm_return->status = E_INVAL;
          #endif
        else
        {
          l1_config.tmode.stats_config.stat_gprs_slots = value;
        #if (ETM_PROTOCOL == 1)
          tm_return->status = -ETM_OK;
        #else
          tm_return->status = E_OK;
        #endif
        }
        break;
      }
    #endif
    default:
    {
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_INVAL;
      #else
        tm_return->status = E_BADINDEX;
      #endif
      break;
    }
  }  // end switch
}

void l1tm_stats_config_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
  volatile UWORD16 value;

  tm_return->index = prim->u.tm_params.index;

  switch (prim->u.tm_params.index)
  {
    case LOOPS:
    {
      value = l1_config.tmode.stats_config.num_loops;
      break;
    }
    case AUTO_RESULT_LOOPS:
    {
      value = l1_config.tmode.stats_config.auto_result_loops;
      break;
    }
    case AUTO_RESET_LOOPS:
    {
      value = l1_config.tmode.stats_config.auto_reset_loops;
      break;
    }
    case STAT_TYPE:
    {
      value = l1_config.tmode.stats_config.stat_type;
      break;
    }
    case STAT_BITMASK:
    {
      value = l1_config.tmode.stats_config.stat_bitmask;
      break;
    }
    #if L1_GPRS
      case STAT_GPRS_SLOTS:
      {
        value = l1_config.tmode.stats_config.stat_gprs_slots;
        break;
      }
    #endif
    default:
    {
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_INVAL;
      #else
        tm_return->status = E_BADINDEX;
      #endif
      tm_return->size = 0;
      return;
    }
  }  // end switch

  memcpy(tm_return->result, (UWORD8 *) &value, 2);
  tm_return->size = 2;
#if (ETM_PROTOCOL == 1)
  tm_return->status = -ETM_OK;
#else
  tm_return->status = E_OK;
#endif
}

void l1tm_statistics(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
{
    l1tm_stats_read(tm_return,
                    prim->u.tm_params.index,
                    prim->u.tm_params.value);
}

#if L1_GPRS
void l1tm_rlc_uplink(UWORD8 tx, API *ul_data)
{
  // Cast the ul_data_buffer
  typedef struct
  {
    API a_ul_data[4][29];
  }
  T_A_UL_DATA;

  T_A_UL_DATA *ptr = (T_A_UL_DATA*) ul_data;
  UWORD8 i,j;

  for (j=0; j<tx; j++)
  {
    ptr->a_ul_data[j][0] = l1_config.tmode.tx_params.coding_scheme;

    for (i=0;i<l1_config.tmode.tx_params.rlc_buffer_size;i++)
      ptr->a_ul_data[j][i+1] = l1_config.tmode.tx_params.rlc_buffer[i];
  }
}
#endif

void l1tm_stats_read(T_TM_RETURN *tm_return, WORD16 type, UWORD16 bitmask)
{
  extern T_L1A_L1S_COM l1a_l1s_com;
  extern T_L1S_GLOBAL l1s;
  volatile UWORD32 utemp = bitmask, temp_U32;
  volatile WORD32  temp = type;
  volatile WORD32  value_signed_int;
  volatile UWORD32 value_unsigned_int;
  volatile UWORD16 value_unsigned_short;
  UWORD8  j, offset=0;  // offset is index of tm_return->result[]
  UWORD16 rssi, len;
  WORD32  count;
  WORD32  runs = l1tm.tmode_stats.loop_count;

  /*
   * FreeCalypso TCS211 reconstruction: the following automatic var
   * is for the BLER code we have conditioned out below.
   */
  #if 0 //L1_GPRS
    volatile UWORD16 value_array_unsigned_short[4];
  #endif

   // Put type and bitmask in the front of tm_return->result[].
  // Use volatile vars for proper operation of memcpy().
  memcpy(&tm_return->result[offset], (UWORD8 *) &temp, 2);
  offset+=2;
  memcpy(&tm_return->result[offset], (UWORD8 *) &utemp, 2);
  offset+=2;

  switch (type)
  {
    // Accumulated receive burst stats
    case ACCUMULATED_RX_STATS:
    {
      // all stats saved when collected from TCH
      if (l1tm.tmode_state.dedicated_active && (l1_config.tmode.rf_params.mon_report == 0))
        count = l1tm.tmode_stats.loop_count;
      #if L1_GPRS
      else if (l1tm.tmode_state.packet_transfer_active && (l1_config.tmode.rf_params.mon_report == 0))
      {
        // loop_count contains the number of blocks
        // Stats (PM, TOA, SNR, ANGLE) are accumulated over all frames and all time slots
        count = l1tm.tmode_stats.loop_count * l1tm.tmode_stats.nb_dl_pdtch_slots * 4;

        // the count of runs vs. successes is accumulated over all time slots per block
        runs  = l1tm.tmode_stats.loop_count * l1tm.tmode_stats.nb_dl_pdtch_slots;
      }
      #endif
      else count = l1tm.tmode_stats.flag_count; // only PASS stats saved

      if (bitmask & RSSI) // rxlev: RSSI SF12.4 eventually (currently F7.1)
      {
        len = sizeof(l1tm.tmode_stats.rssi_fifo) / sizeof(l1tm.tmode_stats.rssi_fifo[0]);
        rssi = 0;
        for (j=0; j<len; j++)
          rssi += l1tm.tmode_stats.rssi_fifo[j];
        rssi /= len; // F7.1
        memcpy(&tm_return->result[offset], (UWORD8 *) &rssi, 2);
        offset+=2;
      }
      // pm: DSP MEAN power measurement UF10.6
      if (bitmask & DSP_PM)
      {
        if (count)
          value_unsigned_short = l1tm.tmode_stats.pm_sum / count;
        else value_unsigned_short = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2);
        offset+=2;
      }
      // angle mean
      if (bitmask & ANGLE_MEAN)
      {
        if (count) // non-zero
          value_signed_int = l1tm.tmode_stats.angle_sum / count;
        else value_signed_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4);
        offset+=4;
      }
      // angle variance
      if (bitmask & ANGLE_VAR)
      {
        // VAR[X] = E[X^2] - (E[X])^2
        if (count) // non-zero
        {
          temp_U32 = l1tm.tmode_stats.angle_sum / count;
          value_unsigned_int = l1tm.tmode_stats.angle_sq_sum / count - (temp_U32)*(temp_U32);
        }
        else value_unsigned_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // angle minimum
      if (bitmask & ANGLE_MIN)
      {
        value_signed_int = l1tm.tmode_stats.angle_min;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4);
        offset+=4;
      }
      // angle maximum
      if (bitmask & ANGLE_MAX)
      {
        value_signed_int = l1tm.tmode_stats.angle_max;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4);
        offset+=4;
      }
      // SNR mean
      if (bitmask & SNR_MEAN)
      {
        if (count) // non-zero
          value_unsigned_int = l1tm.tmode_stats.snr_sum / count;
        else value_unsigned_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // SNR variance
      if (bitmask & SNR_VAR)
      {
        if (count) // non-zero
        {
           temp_U32 = l1tm.tmode_stats.snr_sum / count;
           value_unsigned_int = l1tm.tmode_stats.snr_sq_sum / count -
                                temp_U32 * temp_U32;
        }
        else
        value_unsigned_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // TOA mean
      if (bitmask & TOA_MEAN)
      {
        if (count) // non-zero
          value_unsigned_int = l1tm.tmode_stats.toa_sum / count;
        else value_unsigned_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // TOA variance
      if (bitmask & TOA_VAR)
      {
        if (count) // non-zero
        {
           temp_U32 = l1tm.tmode_stats.toa_sum / count;
           value_unsigned_int = l1tm.tmode_stats.toa_sq_sum / count -
                                temp_U32 * temp_U32;
        }
        else value_unsigned_int = 0;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // Frame # mod 26*51
      if (bitmask & FRAME_NUMBER)
      {
        value_unsigned_int = l1s.actual_time.fn;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // Tot # of runs executed so far
      if (bitmask & RUNS)
      {
        memcpy(&tm_return->result[offset], (UWORD8 *) &runs, 4);
        offset+=4;
      }
      // Tot # of successes so far
      if (bitmask & SUCCESSES)
      {
        memcpy(&tm_return->result[offset], (UWORD8 *) &l1tm.tmode_stats.flag_count, 4);
        offset+=4;
      }
      // BSIC
      if (bitmask & BSIC)
      {
        value_unsigned_short = l1tm.tmode_stats.bsic;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2);
        offset+=2;
      }

/*
 * FreeCalypso TCS211 reconstruction: suspected LoCosto-ism,
 * removing in order to pass compilation.
 */
#if 0 //L1_GPRS
    if (bitmask & BLER)
        {
         UWORD8 j;
          if (count) // non-zero
          {
            float bler, remain_part;
            UWORD8  int_part, bitmap_remain;
            int i;

            //compute bler for each block
            for (j=0; j<4; j++)
            {
              bler = ((float) (l1tm.tmode_stats.bler_crc[j] * 100)) / ((float) l1tm.tmode_stats.bler_total_blocks);

              //conversion from floating to fixed format
              int_part = (UWORD8) bler;
              remain_part = bler - (float) int_part;
              bitmap_remain = 0;

              i=5;
              while (i >= 0)
              {
                bitmap_remain |= (UWORD8) (remain_part *2) << i;
                if (((UWORD8) (remain_part *2)) >= 1)
                  remain_part = (remain_part * 2) - 1;
                else
                  remain_part = (remain_part * 2);
                i--;
              }

              // Reporting the percentage of blocks in error (F10.6)
              value_array_unsigned_short[j] = bitmap_remain | (int_part << 6);
              }
          }
          // Reporting a BLER of 100, if no computation has been done
          else
          {
            for (j=0; j<4; j++)
              value_array_unsigned_short[j] = 100 << 6;
          }
          memcpy(&tm_return->result[offset], (UWORD8 *) &value_array_unsigned_short[0], 8);
          offset+=8;
    	}
#endif


    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    // Most recent receive burst stats
    case MOST_RECENT_RX_STATS:
    {
      // rxlev: RSSI SF12.4 eventually (F7.1 currently)
      if (bitmask & RSSI)
      {
        value_unsigned_short = l1tm.tmode_stats.rssi_recent;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2);
        offset+=2;
      }
      // pm: most recent DSP power measurement UF10.6
      if (bitmask & DSP_PM)
      {
        memcpy(&tm_return->result[offset], &l1tm.tmode_stats.pm_recent, 2);
        offset+=2;
      }
      // most recent ANGLE value
      if (bitmask & ANGLE_MEAN)
      {
        value_signed_int = l1tm.tmode_stats.angle_recent;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_signed_int, 4);
        offset+=4;
      }
      // doesn't make sense.
      if (bitmask & ANGLE_VAR)
      {
      }
      // doesn't make sense.
      if (bitmask & ANGLE_MIN)
      {
      }
      // doesn't make sense.
      if (bitmask & ANGLE_MAX)
      {
      }
      // most recent SNR value
      if (bitmask & SNR_MEAN)
      {
        value_unsigned_int = l1tm.tmode_stats.snr_recent;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // doesn't make sense.
      if (bitmask & SNR_VAR)
      {
      }
      // most recent TOA value
      if (bitmask & TOA_MEAN)
      {
        value_unsigned_int = l1tm.tmode_stats.toa_recent;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // doesn't make sense.
      if (bitmask & TOA_VAR)
      {
      }
      // Frame # mod 26*51
      if (bitmask & FRAME_NUMBER)
      {
        value_unsigned_int = l1s.actual_time.fn;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_int, 4);
        offset+=4;
      }
      // must be '1'
      if (bitmask & RUNS)
      {
      }
      // most recent Success flag
      if (bitmask & SUCCESSES)
      {
        memcpy(&tm_return->result[offset], (UWORD8 *)&l1tm.tmode_stats.flag_recent, 4);
        offset+=4;
      }
      // BSIC
      if (bitmask & BSIC)
      {
        value_unsigned_short = l1tm.tmode_stats.bsic;
        memcpy(&tm_return->result[offset], (UWORD8 *) &value_unsigned_short, 2);
        offset+=2;
      }
    #if (ETM_PROTOCOL == 1)
      tm_return->status = -ETM_OK;
    #else
      tm_return->status = E_OK;
    #endif
      break;
    }
    default:
    {
      #if (ETM_PROTOCOL == 1)
        tm_return->status = -ETM_INVAL;
      #else
        tm_return->status = E_BADINDEX;
      #endif
      break;
    }
  }  // end switch

  tm_return->size = offset;
  tm_return->index = 0;  // don't include index in header
}

/*-------------------------------------------------------*/
/* l1tm_fill_burst()                                     */
/*-------------------------------------------------------*/
/*                                                       */
/* Description:  Prepare bursts for transmission in case */
/* ------------  of UL test                              */
/*                                                       */
/* Simulation of IQ Swap does the following mapping:     */
/*                                                       */
/*             00 -> 01                                  */
/*             01 -> 00                                  */
/*             10 -> 11                                  */
/*             11 -> 10                                  */
/*                                                       */
/*-------------------------------------------------------*/
#if (L1_FF_MULTIBAND == 1)
extern const WORD8 rf_subband2band[];
#endif 
void l1tm_fill_burst (UWORD16 pattern, UWORD16 *TM_ul_data)
{
  UWORD32 i;
  UWORD8  swap_iq, swap_flag;
  UWORD16 gb_front, gb_end, tb_front, tb_end, even_bits, odd_bits;
#if (L1_FF_MULTIBAND == 1) 
  UWORD8 physical_band_id;
#endif  
  UWORD8 tsc_bits_in_first_word;
  UWORD16 tsc_front_mask,tsc_end_mask;
  extern  T_RF rf;

  // training sequences list......
  UWORD32 tsc[8]=
  {
    0x00970897,
    0x00B778B7,
    0x010EE90E,
    0x011ED11E,
    0x006B906B,
    0x013AC13A,
    0x029F629F,
    0x03BC4BBC
  };
#if (L1_FF_MULTIBAND == 0)

  if(((l1_config.std.id == DUAL) || (l1_config.std.id == DUALEXT) || (l1_config.std.id == DUAL_US)) &&
      (l1_config.tmode.rf_params.tch_arfcn >= l1_config.std.first_radio_freq_band2))
  {
    swap_iq = l1_config.std.swap_iq_band2;
  }
  else
  {
    swap_iq = l1_config.std.swap_iq_band1;
  }
  
#else // L1_FF_MULTIBAND = 1 below

  physical_band_id = 
      rf_subband2band[rf_convert_rffreq_to_l1subband(l1_config.tmode.rf_params.tch_arfcn)];

  swap_iq = rf_band[physical_band_id].swap_iq;

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

  // Swap IQ definitions...
  // 0=No Swap, 1=Swap RX only, 2=Swap TX only, 3=Swap RX and TX
  if (swap_iq & 0x2)
  {
    swap_flag = 1;
  }
  else
  {
    swap_flag = 0;
  }

  //===========================================
  // define uplink patterns
  //===========================================
  if (pattern == 0)       //  0's
    pattern = 0x0000;
  else if (pattern == 1)  //  1's
    pattern = 0xffff;
  else if (pattern == 2)  // 01's
    pattern = 0x5555;

  // first replicate pattern through all buffer
  if ((pattern == 3) || (pattern == 4))
  {
    // fill the uplink burst with PRBS1
    l1tm_PRBS1_generate(TM_ul_data);
  }
  else if ((pattern != 12) && (pattern != 13))
  {
    for (i=0;i<=15;i++)
      TM_ul_data[i] = (pattern << 6);
  }

  //===========================================
  // create front-end guard and tail bits masks
  //===========================================
  // guard bits mask
  gb_front = 0xFFC0 << (10 - rf.tx.guard_bits);  // max. of 10, min. of 2 guard bits allowed

  // check if guard bits > 7
  if (rf.tx.guard_bits > 7)
  {
    // tail bits mask
    tb_front = ~((UWORD16)(0xE000 << (10 - rf.tx.guard_bits))) & 0xFFC0;  // tail bits placed in TM_ul_data[1]  //oamps00090550
    // add tail bits to uplink data
    TM_ul_data[1] = TM_ul_data[1] & tb_front;
    // add guard bits to uplink data
    TM_ul_data[0] = gb_front;
  }
  else
  {
    // tail bits mask
    tb_front = ~((UWORD16)(0xE000 >> rf.tx.guard_bits) )& 0xFFC0;  // 3 tail bits
    // add tail bits to uplink data
    TM_ul_data[0] = (TM_ul_data[0] | gb_front) & tb_front;
  }

  //===========================================
  // create back-end guard and tail bits masks
  //===========================================
  // guard bits mask
  gb_end = (0xFFC0 >> (10 - (12 - rf.tx.guard_bits))) & 0xFFC0;  // max. of 10, min. of 2 guard bits allowed

  // check if guard bits < 5
  if (rf.tx.guard_bits < 5)
  {
    //tail bits mask
    tb_end = ~(UWORD16)((0x01C0 >> (rf.tx.guard_bits - 2))) & 0xFFC0;  // tail bits placed in TM_ul_data[14]
    // add tail bits to uplink data
    TM_ul_data[14] = TM_ul_data[14] & tb_end;
    // add guard bits to uplink data
    TM_ul_data[15] = gb_end;
  }
  else
  {
    // tail bits mask
    tb_end = ~(UWORD16)((0x01C0 << (12 - rf.tx.guard_bits))) & 0xFFC0;  // 3 tail bits
    // add tail bits to uplink data
    TM_ul_data[15] = (TM_ul_data[15] | gb_end) & tb_end;
  }

  //===========================================
  // Insert the training sequence pattern .The location of TSC bits will
  // vary according to the value of guard bits used.
  //===========================================
  if ((pattern == 13)||(pattern==3))
  {
    //   TM_ul_data[6]  = (TM_ul_data[6]  & 0xFE00) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>24) << 6 ) );   // tsc bits 1-2
    //    TM_ul_data[7]  = (TM_ul_data[7]  & 0x0000) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>14) << 6 ) );   // tsc bits 3-12
    //   TM_ul_data[8]  = (TM_ul_data[8]  & 0x0000) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>4 ) << 6 ) );   // tsc bits 13-22
    //   TM_ul_data[9]  = (TM_ul_data[9]  & 0x07C0) | ( (UWORD8) ((tsc[l1_config.tmode.tx_params.tsc]>>0 ) << 12) );   // tsc bits 23-26

    if (rf.tx.guard_bits <4) // TSC will be in [6],[7],[8]
    {
      tsc_bits_in_first_word = 9-rf.tx.guard_bits; // 7 bits when guard is 2, 6 bit when guard is 3
      tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right
      //tsc_bits_in_last_word = 26 -10 -tsc_bits_in_first_word = (16-tsc_bits_in_first_word)
      tsc_end_mask =  (((0xFFC0) >> (16-tsc_bits_in_first_word)) & 0xFFC0);   //insert zeros from left

      TM_ul_data[6]  = (TM_ul_data[6]  & tsc_front_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) );
      TM_ul_data[7]  = (TM_ul_data[7]  & 0x0000)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0));   //next 10 bits of TSC
      TM_ul_data[8]  = (TM_ul_data[8]  & tsc_end_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10))>>16) )& (~tsc_end_mask));
    }
    else if ((rf.tx.guard_bits >=4) && (rf.tx.guard_bits <9) )// TSC will be in [6],[7],[8],[9]
    {
      tsc_bits_in_first_word = 9-rf.tx.guard_bits; // 5 bits when guard is 4, 1 bit when guard is 8
      tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right
      //tsc_bits_in_last_word = 26 -10 -10 -tsc_bits_in_first_word = (6-tsc_bits_in_first_word)
      tsc_end_mask =  (((0xFFC0) >> (6-tsc_bits_in_first_word)) & 0xFFC0);   //insert zeros from left

      TM_ul_data[6]  = (TM_ul_data[6]  & tsc_front_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) );
      TM_ul_data[7]  = (TM_ul_data[7]  & 0x0000)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0)  );   //next 10 bits of TSC
      TM_ul_data[8]  = (TM_ul_data[8]  & 0x0000)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6+10))>>16)) & (0xFFC0) );   //next 10 bits of TSC
      TM_ul_data[9]  = (TM_ul_data[9]  & tsc_end_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10+10))>>16) ) & (~tsc_end_mask));
    }
    else   //(rf.tx.guard_bits>=9) : TSC will be in [7],[8],[9],
    {
      tsc_bits_in_first_word = 19-rf.tx.guard_bits; // 10 bits when guard is 9, 9 bits when guard is 10
      tsc_front_mask = ((0xFFC0) << tsc_bits_in_first_word); // insert zeros from right
      //tsc_bits_in_last_word = 26 -10 -tsc_bits_in_first_word = (16-tsc_bits_in_first_word)
      tsc_end_mask =  (((0xFFC0) >> (16-tsc_bits_in_first_word)) & 0xFFC0);   //insert zeros from left

      TM_ul_data[7]  = (TM_ul_data[7]  & tsc_front_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]>>(26-tsc_bits_in_first_word)) << 6 )) & (~tsc_front_mask) );
      TM_ul_data[8]  = (TM_ul_data[8]  & 0x0000)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc]<<(tsc_bits_in_first_word+6))>>16)) & (0xFFC0)  );   //next 10 bits of TSC
      TM_ul_data[9]  = (TM_ul_data[9]  & tsc_end_mask)
                       | ( ((UWORD16) ((tsc[l1_config.tmode.tx_params.tsc] << (tsc_bits_in_first_word+6+10))>>16)) & (~tsc_end_mask));
    }
  }

  // swap uplink data if IQ swap
  if(swap_flag)
  {
    for (i=0;i<=15;i++)
    {
      even_bits = TM_ul_data[i] & 0xAA80;  // keep bits in even positions
      odd_bits  = ~(TM_ul_data[i]) & 0x5540;  // keep and complement bits in odd positions
      TM_ul_data[i] = even_bits | odd_bits;  // swapped uplink data
    }
  }
}



void l1a_tmode_send_ul_msg(T_TM_RETURN *tm_ret)
{
  tm_transmit(tm_ret);
}

/*******************************************************************************
 *
 *                             void tm_receive(void *inbuf, int size)
 *
 * Purpose  : Parses TestMode data and copies it directly into TESTMODE_PRIM.
 *            It forwards primitive to L1, except in the case of tm_init() which
 *            gets executed in the CST.
 *
 * Arguments: In : command
 *            Out:
 *
 * Returns  : void
 *
 ******************************************************************************/

void tm_receive(UWORD8 *inbuf, UWORD16 size)
{
  UWORD8 cksum, cid, error = 0;
  BOOL msg_used=FALSE;

  #if (ETM_PROTOCOL == 1)
    UWORD8 mid = 0;
  #endif

  UWORD8 *pmsg;
  xSignalHeaderRec *msg;

  msg = os_alloc_sig(sizeof(T_TESTMODE_PRIM));
  msg->SignalCode = TESTMODE_PRIM;

  // pmsg will be used to fill up the TestMode primitive with th
  // data, in consecutive order according to the definition of T_TESTMODE_PRIM.
  pmsg = (UWORD8 *)((T_TESTMODE_PRIM *)(msg->SigP));

#if (ETM_PROTOCOL == 1) // Use of ETM protocol
  #if (OP_L1_STANDALONE == 1)
    // Check MID
    *pmsg++ = mid = *inbuf++;
    if ((mid != ETM_RF) && (mid != ETM_CORE))    // check if coming from ETM RF or ETM CORE DLL
      error = -ETM_PACKET;
  #elif (OP_L1_STANDALONE == 0)
    *pmsg++ = mid = ETM_RF;
  #endif

  // Copy CID/FID
  *pmsg++ = cid = *inbuf++;
  #if (OP_L1_STANDALONE == 1)
    // Copy data payload size (size minus MID byte and checksum byte)
    size -= 2;
  #endif
  *pmsg++ = --size; // Size of TM payload -1 for cid/fid

  // Validate data payload size: check if longer than size of testmode
  // primitive minus cid, str_len_in_bytes, and two holes FIXME: This is a
  // really bad way of doing it!
  if (size > sizeof(T_TESTMODE_PRIM) - 4)
    error = -ETM_PACKET;

  // The CID have been received. The data that follows are part of a
  // unique struct within the union of T_TESTMODE_PRIM, so we now
  // need to align at a 32-bit word boundary.
  *pmsg++ = 0;

  // In a SSA integration the cksum is done in the etm_receive function
  #if (OP_L1_STANDALONE == 1)
    if (!error)
    {
      cksum   = mid;
      cksum  ^= cid;

      while (size--)
      {
        cksum  ^= *inbuf;
        *pmsg++ = *inbuf++;
      }
      if (cksum != *inbuf)
        error = -ETM_PACKET;
    }
  #elif (OP_L1_STANDALONE == 0)
    // Copy payload without cid/fid
    while (size--)
    {
      *pmsg++ = *inbuf++;
    }
  #endif

  // At this point, all the data have been parsed and copied into
  // the TestMode primitive.  Now we send the primitive to L1.
  if (!error)
  {
    os_send_sig(msg, L1C1_QUEUE);
    msg_used=TRUE;
  }
  else
  {
    UWORD8 mymsg[4];

    // on error, return short error message; cid, error, checksum
    mymsg[0] = mid;
    mymsg[1] = cid;         // the payload fid
    mymsg[2] = error;       // status
    mymsg[3] = cid ^ error; // checksum

    #if (TRACE_TYPE==0) || (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7)
      rvt_send_trace_cpy((T_RVT_BUFFER) mymsg,
                         tm_trace_user_id,
                         4,
                         RVT_BINARY_FORMAT);
    #endif
  }

#else // end of (ETM_PROTOCOL ==1)

  // Copy CID
  *pmsg++ = cid = *inbuf++;
  // Copy data payload size (size minus CID byte and checksum byte)
  size -= 2;
  *pmsg++ = size;

  // Validate data payload size: check if longer than size of testmode
  // primitive minus cid, str_len_in_bytes, and two holes FIXME: This is a
  // really bad way of doing it!
  if (size > sizeof(T_TESTMODE_PRIM) - 4)
    error = E_PACKET;

  // The CID have been received. The data that follows are part of a
  // unique struct within the union of T_TESTMODE_PRIM, so we now
  // need to align at a 32-bit word boundary.
  pmsg += 2;

  if (!error)
  {
    cksum = cid;
    while (size--)
    {
      cksum  ^= *inbuf;
      *pmsg++ = *inbuf++;
    }
    if (cksum != *inbuf)
      error = E_CHECKSUM;
  }

  // At this point, all the data have been parsed and copied into
  // the TestMode primitive.  Now we send the primitive to L1.
  if (!error)
  {
    os_send_sig(msg, L1C1_QUEUE);
    msg_used=TRUE;
  }
  else
  {
    UWORD8 mymsg[3];
    // on error, return short error message; error, cid/fid, checksum
    mymsg[0] = cid;
    mymsg[1] = error;
    mymsg[2] = cid ^ error; // checksum

    #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0)
       rvt_send_trace_cpy((T_RVT_BUFFER) mymsg, tm_trace_user_id,3, RVT_BINARY_FORMAT);
    #endif
  }

#endif // end of (ETM_PROTOCOL ==0)

  // if the message allocated is not sent to L1A, it has to be deallocated
  if(msg_used==FALSE)
    os_free_sig(msg);
}

void tm_transmit(T_TM_RETURN *tm_ret)
{
  UWORD8 size, cksum;
  UWORD8 *pbuf, *ptmret;
  UWORD8 buf[TM_PAYLOAD_UPLINK_SIZE_MAX + TM_UPLINK_PACKET_OVERHEAD];

  pbuf = &buf[0];

  // move the header
  #if (ETM_PROTOCOL == 1)
    *pbuf++ = tm_ret->mid;
    cksum   = tm_ret->mid;
    *pbuf++ = tm_ret->status;
    cksum  ^= tm_ret->status;
    *pbuf++ = tm_ret->cid;
    cksum  ^= tm_ret->cid;

    // Include index if not equal to zero, and if not an error
    // Exception: in TX_TEMPLATE_READ we always include the index.
    if ((tm_ret->status == -ETM_OK) &&
      (tm_ret->index || tm_ret->cid == TX_TEMPLATE_READ)){
      *pbuf++ = tm_ret->index;
      cksum  ^= tm_ret->index;
    }

  #else
    *pbuf++ = tm_ret->cid;
    *pbuf++ = tm_ret->status;
    cksum = tm_ret->cid ^ tm_ret->status;

    // Include index if not equal to zero, and if not an error
    // Exception: in TX_TEMPLATE_READ we always include the index.
    if ((tm_ret->status == E_OK) &&
      (tm_ret->index || tm_ret->cid == TX_TEMPLATE_READ)){
      *pbuf++ = tm_ret->index;
      cksum  ^= tm_ret->index;
    }
  #endif

  ptmret = (UWORD8 *) &tm_ret->result[0];
  size = tm_ret->size;
  while (size--) {
    *pbuf++ = *ptmret;
    cksum ^= *ptmret++;
  }

  // move the checksum and append it to buf
  *pbuf++ = cksum;

  #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) || (TRACE_TYPE==0)
    rvt_send_trace_cpy(buf, tm_trace_user_id, pbuf - buf, RVT_BINARY_FORMAT);
  #endif
}


#if ((L1_STEREOPATH == 1) && (CODE_VERSION == NOT_SIMULATION) && (OP_L1_STANDALONE == 1))
/*******************************************************************************
 *
 * UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type)
 *
 * Purpose  : this function is use to get a complete period of a sinusoide depending on
 *            the sinusoide freq (L+R), the sampling freq and the type of samples (S8,S16,S32)
 *
 * Arguments: sampling_freq  : sampling frequency
 *            sin_freq_left  : frequency of the left channel sinusoide
 *            sin_freq_right : frequency of the right channel sinusoide
 *            data_type      : type of samples
 *
 * Returns  : number of elements in the pattern
 *
 ******************************************************************************/

  UWORD16 l1tm_stereopath_get_pattern(UWORD16 sampling_freq, UWORD16 sin_freq_left,UWORD16 sin_freq_right, UWORD8 data_type)
  {
   float max_sin_period;
   float my_time;
   UWORD16 i;

   // get the lowest frequency to get the biggest period
   if (sin_freq_left > sin_freq_right)
   {
     max_sin_period =  1 / (float) sin_freq_right;
   }
   else
   {
     max_sin_period =  1 / (float) sin_freq_left;
   }

   my_time = 0;
   i = 0;

   if (data_type == AUDIO_SP_DATA_S8)
   {
     WORD8* my_ptr;

     // cast the steropath_pattern to a pointer on 8 bits samples
     my_ptr = (WORD8*) l1tm.stereopath.stereopath_pattern;

     // fill the pattern while the biggest period is not reached
     while (my_time < max_sin_period)
     {
       my_ptr[i++] = 0x7F * sin(2*3.1416*my_time*sin_freq_left);
       my_ptr[i++] = 0x7F * sin(2*3.1416*my_time*sin_freq_right);

       my_time = i/2/((float) sampling_freq);
     }
   }
   else  // S16
   {
     WORD16* my_ptr;

     // cast the steropath_pattern to a pointer on 16 bits samples
     my_ptr = (WORD16*) l1tm.stereopath.stereopath_pattern;

     // fill the pattern while the biggest period is not reached
     while (my_time < max_sin_period)
     {
       my_ptr[i++] = 0x7FFF * sin(2*3.1416*my_time*sin_freq_left);
       my_ptr[i++] = 0x7FFF * sin(2*3.1416*my_time*sin_freq_right);

       my_time = i/2/((float) sampling_freq);
     }

   }

   return (i);

  }

/*******************************************************************************
 *
 * void l1tm_stereopath_fill_buffer(void* buffer_address)
 *
 * Purpose  : this function is use to fill a buffer with a predefined pattern
 *
 * Arguments: buffer_address  : address of the buffer to fill
 *
 * Returns  : none
 *
 ******************************************************************************/

  void l1tm_stereopath_fill_buffer(void* buffer_address)
  {
   static UWORD16 my_counter = 0;
   UWORD16 copied_samples;

   UWORD16 i;


   if (l1a_l1s_com.stereopath_drv_task.parameters.data_type == AUDIO_SP_DATA_S8)
   {
     WORD8* start_address;
     WORD8* my_ptr;

     // l1tm.stereopath.stereopath_buffer_number is a variable used to know which half of the buffer we have to fill
     if (l1tm.stereopath.stereopath_buffer_number == 0)
     {
      // first half
      start_address = (WORD8*) buffer_address;
      l1tm.stereopath.stereopath_buffer_number = 1;
     }
     else
     {
      // second half, add the frame number to get the half buffer address
      start_address = ((WORD8*) buffer_address) + l1a_l1s_com.stereopath_drv_task.parameters.frame_number;
      l1tm.stereopath.stereopath_buffer_number = 0;
     }

     // copied_samples is the number of samples copied to the half buffer
     copied_samples = 0;
     // cast the steropath_pattern to a pointer on 8 bits samples
     my_ptr = (WORD8*) l1tm.stereopath.stereopath_pattern;

     if (l1a_l1s_com.stereopath_drv_task.parameters.frame_number > l1tm.stereopath.stereopath_nb_samples)
     {
       // size of the half buffer to fill is bigger than the predefined pattern
       // start to fill the buffer with the end of the not complete previous pattern (from current_sample to the last one)
       memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample);
       copied_samples = l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample;

       // while there is still enough place in the buffer to copy a complete pattern ...
       while (copied_samples<l1a_l1s_com.stereopath_drv_task.parameters.frame_number-l1tm.stereopath.stereopath_nb_samples)
       {
         // ... copy a complete pattern
         memcpy(start_address+copied_samples,my_ptr,l1tm.stereopath.stereopath_nb_samples);
         copied_samples += l1tm.stereopath.stereopath_nb_samples;
       }

       // fill the rest of the buffer with a part of the pattern
       memcpy(start_address+copied_samples,my_ptr,l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples);
       // save the last pattern sample copied in the buffer for next time (to get a continuous sound)
       l1tm.stereopath.stereopath_current_sample = l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples;

     }
     else
     {
       // size of the half buffer to fill is smaller than the predefined pattern
       // fill the buffer with a part of the pattern
       memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1a_l1s_com.stereopath_drv_task.parameters.frame_number);
       // save the last pattern sample copied in the buffer for next time (to get a continuous sound)
       l1tm.stereopath.stereopath_current_sample += l1a_l1s_com.stereopath_drv_task.parameters.frame_number;

       if (l1tm.stereopath.stereopath_current_sample > l1tm.stereopath.stereopath_nb_samples)
       {
         l1tm.stereopath.stereopath_current_sample -= l1tm.stereopath.stereopath_nb_samples;
       }
     }
   }
   else    // S16
   {
     WORD16* start_address;
     WORD16* my_ptr;

     // l1tm.stereopath.stereopath_buffer_number is a variable used to know which half of the buffer we have to fill
     if (l1tm.stereopath.stereopath_buffer_number == 0)
     {
      // first half
      start_address = (WORD16*) buffer_address;
      l1tm.stereopath.stereopath_buffer_number = 1;
     }
     else
     {
      // second half, add the frame number to get the half buffer address
      start_address = ((WORD16*) buffer_address) + l1a_l1s_com.stereopath_drv_task.parameters.frame_number;
      l1tm.stereopath.stereopath_buffer_number = 0;
     }

     // copied_samples is the number of samples copied to the half buffer
     copied_samples = 0;
     // cast the steropath_pattern to a pointer on 16 bits samples
     my_ptr = (WORD16*) l1tm.stereopath.stereopath_pattern;

     if (l1a_l1s_com.stereopath_drv_task.parameters.frame_number > l1tm.stereopath.stereopath_nb_samples)
     {
       // size of the half buffer to fill is bigger than the predefined pattern
       // start to fill the buffer with the end of the not complete previous pattern (from current_sample to the last one)
       memcpy(start_address, my_ptr+l1tm.stereopath.stereopath_current_sample,(l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample)*2);
       copied_samples = l1tm.stereopath.stereopath_nb_samples-l1tm.stereopath.stereopath_current_sample;

       // while there is still enough place in the buffer to copy a complete pattern ...
       while (copied_samples<l1a_l1s_com.stereopath_drv_task.parameters.frame_number-l1tm.stereopath.stereopath_nb_samples)
       {
         // ... copy a complete pattern
         memcpy(start_address+copied_samples,my_ptr,l1tm.stereopath.stereopath_nb_samples*2);
         copied_samples += l1tm.stereopath.stereopath_nb_samples;
       }

       // fill the rest of the buffer with a part of the pattern
       memcpy(start_address+copied_samples,my_ptr,(l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples)*2);
       // save the last pattern sample copied in the buffer for next time (to get a continuous sound)
       l1tm.stereopath.stereopath_current_sample = l1a_l1s_com.stereopath_drv_task.parameters.frame_number-copied_samples;

     }
     else
     {
       // size of the half buffer to fill is smaller than the predefined pattern
       // fill the buffer with a part of the pattern
       memcpy(start_address,my_ptr+l1tm.stereopath.stereopath_current_sample,l1a_l1s_com.stereopath_drv_task.parameters.frame_number);
       l1tm.stereopath.stereopath_current_sample += l1a_l1s_com.stereopath_drv_task.parameters.frame_number;

       // save the last pattern sample copied in the buffer for next time (to get a continuous sound)
       if (l1tm.stereopath.stereopath_current_sample > l1tm.stereopath.stereopath_nb_samples)
       {
         l1tm.stereopath.stereopath_current_sample -= l1tm.stereopath.stereopath_nb_samples;
       }

     }
   }
  }

/*******************************************************************************
 *
 * void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status)
 *
 * Purpose  : this function is the stereopath DMA interrupt handler
 *
 * Arguments: dma_status  : type of interrupt
 *
 * Returns  : none
 *
 ******************************************************************************/
  void l1tm_stereopath_DMA_handler(SYS_UWORD16 dma_status)
  {
     // stereopath DMA handler, check which type of interrupt it is
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_BLOCK(dma_status))
       {
         l1tm.stereopath.stereopath_block++;
         // Block --> fill a new buffer
         l1tm_stereopath_fill_buffer((void*) l1a_l1s_com.stereopath_drv_task.parameters.source_buffer_address);
       }
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_HALF_BLOCK(dma_status))
       {
         l1tm.stereopath.stereopath_half_block++;
         // Half Block --> fill a new buffer
         l1tm_stereopath_fill_buffer((void*) l1a_l1s_com.stereopath_drv_task.parameters.source_buffer_address);
       }
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_TIME_OUT_SRC(dma_status))
       l1tm.stereopath.stereopath_source_timeout++;
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_TIME_OUT_DST(dma_status))
       l1tm.stereopath.stereopath_dest_timeout++;
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_DROP(dma_status))
       l1tm.stereopath.stereopath_drop++;
     if (F_DMA_COMPARE_CHANNEL_IT_STATUS_FRAME(dma_status))
       l1tm.stereopath.stereopath_frame++;
  }
#endif



#if (CODE_VERSION != SIMULATION)
  void l1tm_tpu_table_write(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
  {
    Cust_tm_tpu_table_write(tm_return,
      prim->u.tm_table.index,
      prim->str_len_in_bytes - 1,    // subtract 8-bit index
      prim->u.tm_table.table);
  }

  void l1tm_tpu_table_read(T_TESTMODE_PRIM *prim, T_TM_RETURN *tm_return)
  {
    Cust_tm_tpu_table_read(tm_return, prim->u.tm_table.index);
  }
#endif // (CODE_VERSION != SIMULATION)


  /*------------------------------------------------------------------*/
  /* l1tm_PRBS1_generate()                                            */
  /*------------------------------------------------------------------*/
  /*                                                                  */
  /* Parameters  :         UWORD16 *TM_ul_data                        */
  /* -------------                                                    */
  /*                point to the uplink burts table to be filled      */
  /*                with the PRBS 1 of bits                           */
  /*                                                                  */
  /* Return      :                Void                                */
  /* -------------                                                    */
  /*                                                                  */
  /* Description :                                                    */
  /* -------------                                                    */
  /* This algorithm generates  a Pseudo Random Bit Sequence           */
  /* using a method called method  "Primitive Polynomial Modulo 2"    */
  /* For a sequence length of (2^15-1) we a polynomial of order 15    */
  /* is used, the coefficients are [ 15,  1,  0 ]                     */
  /* The basic idea is to generate the new bit by XORing  all the     */
  /* coefficients  of the polynomial except coeff 0                   */
  /* i.e newbit = ( B15 XOR B1  )                                     */
  /* The following notation must be used for the bit numbering:       */
  /* _______________________________________________________          */
  /*|B16|B15|B14|B13|B12|B11|B10|B9|B8|B7|B6|B5|B4|B3|B2|B1|          */
  /*------------------------------------------------------------------*/
  /*                                                                  */
  /* each word of the uplink buffer needs to be filled by new 10 bits */
  /*------------------------------------------------------------------*/
  void l1tm_PRBS1_generate(UWORD16 *TM_ul_data)
  {
    #define B15_MASK 	0x4000
    #define B1_MASK 	0x0001
    #define MASK_16BITS	0xFFFF

    UWORD16 newbit =0x0000;
    UWORD8 index ,word;

    //generate 16 words to fill Uplink table
    for (word=0;word<16;word++)
    {
      // generate new 10 bits from the sequence
      for (index =0; index< 10;index++)
      {
        // generate new bit , using the "Primitive Polynomial Modulo 2 " method with coeff. ( 15, 1, 0 )
        //XOR bit 15 with bit 1.
        newbit =     (((l1tm.tmode_prbs.prbs1_seed& B15_MASK)>>14)^(l1tm.tmode_prbs.prbs1_seed & B1_MASK));
        // insert new bit in the sequence.
        l1tm.tmode_prbs.prbs1_seed =	(l1tm.tmode_prbs.prbs1_seed << 1) | newbit;
      }
      TM_ul_data[word]=(UWORD16)((l1tm.tmode_prbs.prbs1_seed&MASK_16BITS)<<6);
    }
  }

#endif // TESTMODE