diff g23m/condat/com/src/driver/em.c @ 0:509db1a7b7b8

initial import: leo2moko-r1
author Space Falcon <falcon@ivan.Harhan.ORG>
date Mon, 01 Jun 2015 03:24:05 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/g23m/condat/com/src/driver/em.c	Mon Jun 01 03:24:05 2015 +0000
@@ -0,0 +1,1096 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  GSM-PS
+|  Modul   :  DRV_RX
++----------------------------------------------------------------------------- 
+|  Copyright 2002 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  This Module defines the engineering mode
+|             device driver for the G23 protocol stack.
+|             
+|             This driver is used to control all engineering mode related
+|             functions. 
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifndef DRV_EM_C
+#define DRV_EM_C
+#define ENTITY_CST
+/*==== INCLUDES ===================================================*/
+#if defined (NEW_FRAME)
+
+#include <string.h>
+#include "typedefs.h"
+#include "vsi.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "gdi.h"
+#include "em.h"
+
+#else
+
+#include <string.h>
+#include "stddefs.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "vsi.h"
+#include "gdi.h"
+#include "em.h"
+
+#endif
+
+/*==== EXPORT =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+#define EV_BUFFER_SIZE 512
+
+#if defined (NEW_FRAME)
+EXTERN USHORT cst_handle;
+#endif
+
+UBYTE  ev_enabled = FALSE;
+USHORT ev_first_read;
+USHORT ev_first_write;
+USHORT ev_size;
+UBYTE  ev_buffer [EV_BUFFER_SIZE];
+/*==== FUNCTIONS ==================================================*/
+LOCAL void  em_get_size                  (UBYTE          size);
+LOCAL UBYTE em_check_em_class_infra_data (UBYTE          em_subclass,
+                                          UBYTE          em_type,
+                                          em_data_type * out_em_data);
+LOCAL UBYTE em_check_em_subclass_sc_info (UBYTE          em_type,
+                                          em_data_type * out_em_data);
+LOCAL UBYTE em_check_em_subclass_nc_info (UBYTE          em_type,
+                                          em_data_type * out_em_data);
+LOCAL UBYTE em_check_em_subclass_lup_and_pag (UBYTE          em_type,
+                                              em_data_type * out_em_data);
+
+/*==== CONSTANTS ==================================================*/
+#ifndef FF_EM_MODE 
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Init                    |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function initializes the driverīs internal data.
+            The function returns DRV_OK in case of a successful
+            completition. The function returns DRV_INITIALIZED if
+            the driver has already been initialized and is ready to
+            be used or is already in use. In case of an initialization
+            failure, which means the that the driver cannot be used,
+            the function returns DRV_INITFAILURE.
+
+*/
+
+GLOBAL UBYTE em_Init (void)
+{
+  ev_enabled = FALSE;
+
+  return DRV_OK;
+}
+#endif /* FF_EM_MODE */
+
+#ifndef FF_EM_MODE 
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Exit                    |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function is used to indicate that the driver
+            and its functionality isnīt needed anymore.
+
+*/
+
+GLOBAL void em_Exit (void)
+{
+}
+#endif /* FF_EM_MODE */
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Read_Parameter          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to read a parameter of the mobile.
+  
+*/
+
+GLOBAL UBYTE em_Read_Parameter (UBYTE          em_class,
+                                UBYTE          em_subclass,
+                                UBYTE          em_type,
+                                em_data_type * out_em_data)
+{
+  switch (em_class)
+  {
+    case EM_CLASS_INFRA_DATA:
+      return (em_check_em_class_infra_data (em_subclass, em_type, out_em_data));
+    default:
+      return EM_INVALID_CLASS;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Enable_Post_Mortem      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function enables recording of event data in the 
+            post mortem memory.
+              
+*/
+
+GLOBAL UBYTE em_Enable_Post_Mortem ()
+{
+  ev_first_read  = 0;
+  ev_first_write = 0;
+  ev_size        = EV_BUFFER_SIZE;
+  ev_enabled     = TRUE;
+  return DRV_OK;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Disable_Post_Mortem     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function disables recording of event data in the 
+            post mortem memory and allows reading of the data.
+              
+*/
+
+GLOBAL UBYTE em_Disable_Post_Mortem ()
+{
+  ev_enabled     = FALSE;
+  return DRV_OK;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6103)       MODULE  : DRV_EM                     |
+| STATE   : code                ROUTINE : em_Read_Post_Mortem        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to read a parameter of the 
+            post mortem memory.
+  
+*/
+
+GLOBAL UBYTE em_Read_Post_Mortem (em_data_type * out_em_data)
+{
+  UBYTE subclass;
+  UBYTE i;
+#if defined (WIN32)
+  char buf[60];
+  sprintf (buf, "before %d %d read", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+  if (ev_enabled EQ FALSE)
+  {
+    if (ev_size EQ EV_BUFFER_SIZE)
+      return EM_NO_MORE_DATA;
+
+    out_em_data->em_class    = EM_CLASS_EVENT_TRACE;
+    subclass = ev_buffer [ev_first_read++];
+    out_em_data->em_subclass = subclass & 0x3F;
+    if (ev_first_read >= EV_BUFFER_SIZE)
+      ev_first_read -= EV_BUFFER_SIZE;
+    out_em_data->em_type = ev_buffer [ev_first_read++];
+    if (ev_first_read >= EV_BUFFER_SIZE)
+      ev_first_read -= EV_BUFFER_SIZE;
+#if defined (WIN32)
+    sprintf (buf, "subclass %x read", subclass);
+    TRACE_EVENT (buf);
+#endif
+    switch (subclass & 0xC0)
+    {
+      case 0x00:   
+        // single entry
+        ev_size += 2;
+        out_em_data->em_length = 0;
+        break;
+      case 0x40:   
+        // ubyte entry
+        ev_size += 3;
+        out_em_data->em_length = 1;
+        out_em_data->em_parameter[0] = ev_buffer [ev_first_read++];
+        if (ev_first_read >= EV_BUFFER_SIZE)
+          ev_first_read -= EV_BUFFER_SIZE;
+        break;
+      case 0x80:   
+        // ushort entry
+        ev_size += 4;
+        out_em_data->em_length = 2;
+        out_em_data->em_parameter[0] = ev_buffer [ev_first_read++];
+        if (ev_first_read >= EV_BUFFER_SIZE)
+          ev_first_read -= EV_BUFFER_SIZE;
+        out_em_data->em_parameter[1] = ev_buffer [ev_first_read++];
+        if (ev_first_read >= EV_BUFFER_SIZE)
+          ev_first_read -= EV_BUFFER_SIZE;
+        break;
+      case 0xC0:   
+        // array entry
+        // skip to length
+        out_em_data->em_length = ev_buffer [ev_first_read++];
+        if (ev_first_read >= EV_BUFFER_SIZE)
+          ev_first_read -= EV_BUFFER_SIZE;
+        for (i=0;i<out_em_data->em_length;i++)
+        {
+          out_em_data->em_parameter[i] = ev_buffer[ev_first_read++];
+          if (ev_first_read >= EV_BUFFER_SIZE)
+            ev_first_read -= EV_BUFFER_SIZE;
+        }
+        ev_size += (out_em_data->em_length+3);
+        break;
+    }
+#if defined (WIN32)
+    sprintf (buf, "after %d %d read", ev_first_read, ev_first_write);
+    TRACE_EVENT (buf);
+#endif
+    return DRV_OK;
+  }
+  else
+  {
+    return EM_INVALID_ACCESS;
+  }
+}
+
+
+/*
+ *************************************************************************************
+ *
+ * Internal Functions
+ *
+ *************************************************************************************
+ */
+
+/*
+ * the internal event buffer is organised as a ring buffer. Using different
+ * access functions the data is stored in one of the four following ways:
+ *
+ * SINGLE TRACE (no parameter)
+ *
+ * Byte 1:     00 xxxxxx  subclass
+ * Byte 2:     yyyyyyyyy  type
+ *
+ * UBYTE TRACE (one byte parameter)
+ *
+ * Byte 1:     01 xxxxxx  subclass
+ * Byte 2:     yyyyyyyyy  type
+ * Byte 3:     zzzzzzzzz  parameter
+ *
+ * USHORT TRACE (two bytes parameter)
+ *
+ * Byte 1:     10 xxxxxx  subclass
+ * Byte 2:     yyyyyyyyy  type
+ * Byte 3:     zzzzzzzzz  parameter
+ * Byte 4:     zzzzzzzzz  parameter
+ *
+ * ARRAY TRACE (n bytes parameter)
+ *
+ * Byte 1:     11 xxxxxx  subclass
+ * Byte 2:     yyyyyyyyy  type
+ * Byte 3:     aaaaaaaaa  len
+ * Byte 4-n+3: zzzzzzzzz  parameter
+ *
+ * The parameter ev_enabled defines whether recording is enabled or not.
+ * after power on it is disabled.
+ *
+ * The parameter ev_first_read indicates the first position in the ev_buffer
+ * which shall be read.
+ * 
+ * The parameter ev_first_write indicates the first position in the ev_buffer
+ * which shall be used for the next recorded event.
+ *
+ * The parameter ev_size defines the free memory in the ev_buffer. If the next
+ * write event is greater than the free memory the ev_first_read is changed to
+ * have enough memory.
+ *
+ */
+
+GLOBAL void em_trace_single (UBYTE class,
+                             UBYTE subclass,
+                             UBYTE type)
+{
+#if defined (WIN32)
+  char buf[60];
+#endif
+  TRACE_FUNCTION ("em_trace_single");
+
+#if defined (WIN32)  
+  sprintf (buf, "before %d %d Single", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+  if (ev_enabled)
+  {
+    // get memory if needed
+    em_get_size (2);
+    // write subclass
+    ev_buffer[ev_first_write++] = subclass;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write type
+    ev_buffer[ev_first_write++] = type;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    ev_size -= 2;
+  }
+#if defined (WIN32)
+  sprintf (buf, "after %d %d Single", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+}
+
+GLOBAL void em_trace_ubyte  (UBYTE  class,
+                             UBYTE  subclass,
+                             UBYTE  type,
+                             UBYTE  para_ubyte)
+{
+#if defined (WIN32)
+  char buf[60];
+
+  TRACE_FUNCTION ("em_trace_ubyte");
+
+  sprintf (buf, "before %d %d ubyte", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+
+  if (ev_enabled)
+  {
+    // get memory if needed
+    em_get_size (3);
+    // write subclass
+    ev_buffer[ev_first_write++] = subclass + 0x40;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write type
+    ev_buffer[ev_first_write++] = type;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write parameter
+    ev_buffer[ev_first_write++] = para_ubyte;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    ev_size -= 3;
+  }
+#if defined (WIN32)
+  sprintf (buf, "after %d %d ubyte", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+}
+
+GLOBAL void em_trace_ushort (UBYTE  class,
+                             UBYTE  subclass,
+                             UBYTE  type,
+                             USHORT para_ushort)
+{
+#if defined (WIN32)
+  char buf[60];
+
+  TRACE_FUNCTION ("em_trace_ushort");
+  
+  sprintf (buf, "before %d %d ushort", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+
+  if (ev_enabled)
+  {
+    // get memory if needed
+    em_get_size (4);
+    // write subclass
+    ev_buffer[ev_first_write++] = subclass + 0x80;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write type
+    ev_buffer[ev_first_write++] = type;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write parameter
+    ev_buffer[ev_first_write++] = para_ushort >> 8;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write parameter
+    ev_buffer[ev_first_write++] = para_ushort & 8;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    ev_size -= 4;
+  }
+#if defined (WIN32)
+  sprintf (buf, "after %d %d ushort", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+}
+
+
+GLOBAL void em_trace_array  (UBYTE    class,
+                             UBYTE    subclass,
+                             UBYTE    type,
+                             UBYTE  * array,
+                             UBYTE    length)
+{
+  UBYTE i;
+#if defined (WIN32)
+  char buf[60];
+
+  TRACE_FUNCTION ("em_trace_array");
+  
+  sprintf (buf, "before %d %d array", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+#endif
+
+  if (ev_enabled)
+  {
+    // get memory if needed
+    em_get_size ((UBYTE)(length+3));
+    // write subclass
+    ev_buffer[ev_first_write++] = subclass + 0xC0;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write type
+    ev_buffer[ev_first_write++] = type;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write length
+    ev_buffer[ev_first_write++] = length;
+    if (ev_first_write >= EV_BUFFER_SIZE)
+      ev_first_write -= EV_BUFFER_SIZE;
+    // write parameter
+    for (i=0;i<length;i++)
+    {
+      ev_buffer[ev_first_write++] = array[i];
+      if (ev_first_write >= EV_BUFFER_SIZE)
+        ev_first_write -= EV_BUFFER_SIZE;
+    }
+    ev_size -= (length+3);
+  }
+#if defined (WIN32)
+  sprintf (buf, "after %d %d array", ev_first_read, ev_first_write);
+  TRACE_EVENT (buf);
+  sprintf (buf, "%x %x %x %x %x",
+                ev_buffer[0],
+                ev_buffer[1],
+                ev_buffer[2],
+                ev_buffer[3],
+                ev_buffer[4]);
+  TRACE_EVENT (buf);
+#endif
+}
+
+
+LOCAL void em_get_size (UBYTE size)
+{
+  while (ev_size < size)
+  {
+    /*
+     * increase ev_first_read to get memory
+     */
+    switch (ev_buffer [ev_first_read & 0xC0])
+    {
+      case 0x00:   
+        // single entry
+        ev_size += 2;
+        ev_first_read += 2;
+        break;
+      case 0x40:   
+        // ubyte entry
+        ev_size += 3;
+        ev_first_read += 3;
+        break;
+      case 0x80:   
+        // ushort entry
+        ev_size += 3;
+        ev_first_read += 3;
+        break;
+      case 0xC0:   
+        // array entry
+        // skip to length
+        ev_first_read += 2;
+        if (ev_first_read >= EV_BUFFER_SIZE)
+          ev_first_read -= EV_BUFFER_SIZE;
+        ev_first_read += (1+ev_buffer[ev_first_read]);
+        break;
+    }
+    // align if at the end of the buffer
+    if (ev_first_read >= EV_BUFFER_SIZE)
+      ev_first_read -= EV_BUFFER_SIZE;
+  }
+}
+
+LOCAL UBYTE em_check_em_class_infra_data (UBYTE          em_subclass,
+                                          UBYTE          em_type,
+                                          em_data_type * out_em_data)
+{
+  switch (em_subclass)
+  {
+    case EM_SUBCLASS_SC_INFO:
+      return (em_check_em_subclass_sc_info (em_type, out_em_data));
+    case EM_SUBCLASS_NC_INFO:
+      return (em_check_em_subclass_nc_info (em_type, out_em_data));
+    case EM_SUBCLASS_LUP_AND_PAG:
+      return (em_check_em_subclass_lup_and_pag (em_type, out_em_data));
+    default:
+      return EM_INVALID_SUBCLASS;
+  }
+}
+
+LOCAL UBYTE em_check_em_subclass_sc_info (UBYTE          em_type,
+                                          em_data_type * out_em_data)
+{
+  T_EM_NC_DATA em_nc_data;
+  /*
+   * ret   0   not available
+   *       1   idle mode
+   *       2   dedicated mode
+   */
+  UBYTE        ret;
+
+  out_em_data->em_class    = EM_CLASS_INFRA_DATA;
+  out_em_data->em_subclass = EM_SUBCLASS_SC_INFO;
+  out_em_data->em_type     = em_type;
+
+  ret = em_get_nc_data (&em_nc_data, 6);  // serving cell data
+  
+  switch (em_type)
+  {
+    case EM_IN_SC_BCCH_ARFCN:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.arfcn);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_C1:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.c1);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_C2:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.c2);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_BSIC:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.bsic);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_LAC:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.lac);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_BA:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.cba);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_BQ:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.cbq);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_TIL_STATE:
+#if !defined(FF_GTI)
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.til_state);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+#endif  /* !FF_GTI */
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_RX:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.rxlev);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_SC_NMR_RAW:
+      if (em_get_network_meas (out_em_data->em_parameter) EQ 1)
+      {
+        out_em_data->em_length = 16;
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+  
+    case EM_IN_SC_BCCH_LIST_RAW:
+      if (em_get_bcch_chan_list (out_em_data) NEQ 1)
+        return DRV_OK;
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    default:
+      return EM_INVALID_TYPE;
+  }
+}
+
+LOCAL UBYTE em_check_em_subclass_nc_info (UBYTE          em_type,
+                                          em_data_type * out_em_data)
+{
+  T_EM_NC_DATA em_nc_data;
+  /*
+   * ret   0   not available
+   *       1   idle mode
+   *       2   dedicated mode
+   */
+  UBYTE        ret;
+  UBYTE        cell_id;
+
+  out_em_data->em_class    = EM_CLASS_INFRA_DATA;
+  out_em_data->em_subclass = EM_SUBCLASS_NC_INFO;
+  out_em_data->em_type     = em_type;
+
+  switch( em_type )
+  {
+    case EM_IN_NC_BCCH_1:
+    case EM_IN_NC_RX_1:
+    case EM_IN_NC_C1_1:
+    case EM_IN_NC_C2_1:
+    case EM_IN_NC_BSIC_1:
+    case EM_IN_NC_CID_1:
+    case EM_IN_NC_FN_OFFSET_1:
+    case EM_IN_NC_TA_OFFSET_1:
+    case EM_IN_NC_LAC_1:
+    case EM_IN_NC_BA_1:
+    case EM_IN_NC_BQ_1:
+    case EM_IN_NC_TIL_STATE_1:
+          cell_id = 0;
+    break;
+
+    case EM_IN_NC_BCCH_2:
+    case EM_IN_NC_RX_2:
+    case EM_IN_NC_C1_2:
+    case EM_IN_NC_C2_2:
+    case EM_IN_NC_BSIC_2:
+    case EM_IN_NC_CID_2:
+    case EM_IN_NC_FN_OFFSET_2:
+    case EM_IN_NC_TA_OFFSET_2:
+    case EM_IN_NC_LAC_2:
+    case EM_IN_NC_BA_2:
+    case EM_IN_NC_BQ_2:
+    case EM_IN_NC_TIL_STATE_2:
+      cell_id = 1;
+    break;
+
+    case EM_IN_NC_BCCH_3:
+    case EM_IN_NC_RX_3:
+    case EM_IN_NC_C1_3:
+    case EM_IN_NC_C2_3:
+    case EM_IN_NC_BSIC_3:
+    case EM_IN_NC_CID_3:
+    case EM_IN_NC_FN_OFFSET_3:
+    case EM_IN_NC_TA_OFFSET_3:
+    case EM_IN_NC_LAC_3:
+    case EM_IN_NC_BA_3:
+    case EM_IN_NC_BQ_3:
+    case EM_IN_NC_TIL_STATE_3:
+      cell_id = 2;
+    break;
+
+    case EM_IN_NC_BCCH_4:
+    case EM_IN_NC_RX_4:
+    case EM_IN_NC_C1_4:
+    case EM_IN_NC_C2_4:
+    case EM_IN_NC_BSIC_4:
+    case EM_IN_NC_CID_4:
+    case EM_IN_NC_FN_OFFSET_4:
+    case EM_IN_NC_TA_OFFSET_4:
+    case EM_IN_NC_LAC_4:
+    case EM_IN_NC_BA_4:
+    case EM_IN_NC_BQ_4:
+    case EM_IN_NC_TIL_STATE_4:
+      cell_id = 3;
+    break;
+
+    case EM_IN_NC_BCCH_5:
+    case EM_IN_NC_RX_5:
+    case EM_IN_NC_C1_5:
+    case EM_IN_NC_C2_5:
+    case EM_IN_NC_BSIC_5:
+    case EM_IN_NC_CID_5:
+    case EM_IN_NC_FN_OFFSET_5:
+    case EM_IN_NC_TA_OFFSET_5:
+    case EM_IN_NC_LAC_5:
+    case EM_IN_NC_BA_5:
+    case EM_IN_NC_BQ_5:
+    case EM_IN_NC_TIL_STATE_5:
+      cell_id = 4;
+    break;
+
+    case EM_IN_NC_BCCH_6:
+    case EM_IN_NC_RX_6:
+    case EM_IN_NC_C1_6:
+    case EM_IN_NC_C2_6:
+    case EM_IN_NC_BSIC_6:
+    case EM_IN_NC_CID_6:
+    case EM_IN_NC_FN_OFFSET_6:
+    case EM_IN_NC_TA_OFFSET_6:
+    case EM_IN_NC_LAC_6:
+    case EM_IN_NC_BA_6:
+    case EM_IN_NC_BQ_6:
+    case EM_IN_NC_TIL_STATE_6:
+      cell_id = 5;
+    break;
+
+    case EM_IN_NC_TIL_SYNC_CNT:
+    case EM_IN_NC_TIL_BCCH_CNT:
+       cell_id = 6; // Serving cell
+    break;
+
+    default:
+      return EM_DATA_NOT_AVAIL;
+  }
+
+
+  ret = em_get_nc_data (&em_nc_data, cell_id);  // ncell data
+
+  switch (em_type)
+  {
+    case EM_IN_NC_BCCH_1:
+    case EM_IN_NC_BCCH_2:
+    case EM_IN_NC_BCCH_3:
+    case EM_IN_NC_BCCH_4:
+    case EM_IN_NC_BCCH_5:
+    case EM_IN_NC_BCCH_6:
+      if (ret NEQ 0)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.arfcn);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_RX_1:
+    case EM_IN_NC_RX_2:
+    case EM_IN_NC_RX_3:
+    case EM_IN_NC_RX_4:
+    case EM_IN_NC_RX_5:
+    case EM_IN_NC_RX_6:
+      if (ret NEQ 0)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.rxlev);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_BSIC_1:
+    case EM_IN_NC_BSIC_2:
+    case EM_IN_NC_BSIC_3:
+    case EM_IN_NC_BSIC_4:
+    case EM_IN_NC_BSIC_5:
+    case EM_IN_NC_BSIC_6:
+      if (ret NEQ 0)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.bsic);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_C1_1:
+    case EM_IN_NC_C1_2:
+    case EM_IN_NC_C1_3:
+    case EM_IN_NC_C1_4:
+    case EM_IN_NC_C1_5:
+    case EM_IN_NC_C1_6:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.c1);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_C2_1:
+    case EM_IN_NC_C2_2:
+    case EM_IN_NC_C2_3:
+    case EM_IN_NC_C2_4:
+    case EM_IN_NC_C2_5:
+    case EM_IN_NC_C2_6:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.c2);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_LAC_1:
+    case EM_IN_NC_LAC_2:
+    case EM_IN_NC_LAC_3:
+    case EM_IN_NC_LAC_4:
+    case EM_IN_NC_LAC_5:
+    case EM_IN_NC_LAC_6:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.lac);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_BA_1:
+    case EM_IN_NC_BA_2:
+    case EM_IN_NC_BA_3:
+    case EM_IN_NC_BA_4:
+    case EM_IN_NC_BA_5:
+    case EM_IN_NC_BA_6:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.cba);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_BQ_1:
+    case EM_IN_NC_BQ_2:
+    case EM_IN_NC_BQ_3:
+    case EM_IN_NC_BQ_4:
+    case EM_IN_NC_BQ_5:
+    case EM_IN_NC_BQ_6:
+      if (ret EQ 1)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3x",em_nc_data.cbq);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_TIL_STATE_1:
+    case EM_IN_NC_TIL_STATE_2:
+    case EM_IN_NC_TIL_STATE_3:
+    case EM_IN_NC_TIL_STATE_4:
+    case EM_IN_NC_TIL_STATE_5:
+    case EM_IN_NC_TIL_STATE_6:
+#if !defined(FF_GTI)
+      if (ret NEQ 0)
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.til_state);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+#endif  /* !FF_GTI */
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_TIL_SYNC_CNT:
+#if !defined(FF_GTI)
+      if ( (ret EQ 1) && (em_nc_data.sync_cnt NEQ 0xFF) )
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.sync_cnt);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+#endif  /* !FF_GTI */
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    case EM_IN_NC_TIL_BCCH_CNT:
+#if !defined(FF_GTI)
+      if ( (ret EQ 1) && (em_nc_data.bcch_cnt NEQ 0xFF) )
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%3d",em_nc_data.bcch_cnt);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+      else
+#endif  /* !FF_GTI */
+        return EM_DATA_NOT_AVAIL;
+      break;
+
+    default:
+          return EM_INVALID_TYPE;
+      break;
+
+  }
+}
+
+LOCAL UBYTE em_check_em_subclass_lup_and_pag (UBYTE          em_type,
+                                              em_data_type * out_em_data)
+{
+  UBYTE * sys_info_3 = NULL;
+
+  out_em_data->em_class    = EM_CLASS_INFRA_DATA;
+  out_em_data->em_subclass = EM_SUBCLASS_LUP_AND_PAG;
+  out_em_data->em_type     = em_type;
+
+#if defined(FF_GTI)
+  sys_info_3 = em_get_sysinfo_type3 ();  // sys info 3
+#else
+  sys_info_3 = em_get_sys_info (0x1B);  // sys info 3
+#endif  /* FF_GTI */
+
+  switch (em_type)
+  {
+    case EM_IN_LP_BS_PA_MFRMS:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%d",(sys_info_3[10]&7)+2);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+    case EM_IN_LP_T3212:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        sprintf ((char *)out_em_data->em_parameter,"%d",sys_info_3[11]);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+    case EM_IN_LP_MCC:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        USHORT mcc;
+
+        mcc = (sys_info_3[4] & 0x0F)*100 + 
+              ((sys_info_3[4] & 0xF0)>>4)*10 +
+               (sys_info_3[5] & 0x0F);
+        sprintf ((char *)out_em_data->em_parameter,"%d",mcc);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+    case EM_IN_LP_MNC:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        USHORT mnc;
+
+        mnc = (sys_info_3[6] & 0x0F)*10 + 
+              ((sys_info_3[6] & 0xF0)>>4);
+        sprintf ((char *)out_em_data->em_parameter,"%d",mnc);
+        out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        return DRV_OK;
+      }
+    case EM_IN_LP_LAC:
+    case EM_IN_LP_LAC_RAW:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        USHORT lac;
+
+        lac = (sys_info_3[7] << 8) + 
+               sys_info_3[8];
+        if (em_type EQ EM_IN_LP_LAC)
+        {
+          sprintf ((char *)out_em_data->em_parameter,"%d",lac);
+          out_em_data->em_length = strlen ((char *)out_em_data->em_parameter);
+        }
+        else
+        {
+          out_em_data->em_parameter[0] = sys_info_3[7];
+          out_em_data->em_parameter[1] = sys_info_3[8];
+          out_em_data->em_length       = 2;
+        }
+        return DRV_OK;
+      }
+    case EM_IN_LP_CI_RAW:
+      if (sys_info_3 EQ NULL)
+        return EM_DATA_NOT_AVAIL;
+      else
+      {
+        out_em_data->em_parameter[0] = sys_info_3[2];
+        out_em_data->em_parameter[1] = sys_info_3[3];
+        out_em_data->em_length       = 2;
+      }
+      return DRV_OK;
+
+   default:
+      return EM_INVALID_TYPE;
+  }
+}
+
+#endif