diff src/cs/layer1/tm_cfile/l1tm_func.c @ 0:4e78acac3d88

src/{condat,cs,gpf,nucleus}: import from Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:23:26 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/layer1/tm_cfile/l1tm_func.c	Fri Oct 16 06:23:26 2020 +0000
@@ -0,0 +1,3092 @@
+/************* 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
+
+