view src/g23m-gsm/dl/dl_trace.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :
|  Modul   :
+-----------------------------------------------------------------------------
|  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 Modul defines the offline trace functions
|             for the component DL of the mobile station.
+-----------------------------------------------------------------------------
*/

#ifndef DL_TRACE_C
#define DL_TRACE_C

#define ENTITY_DL

/*==== INCLUDES ===================================================*/
#include "typedefs.h"
#include <string.h>
#include "vsi.h"
#include "pconst.cdg"
#include "custom.h"
#include "gsm.h"
#include "mon_dl.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "ccdapi.h"
#include "dl.h"

/*==== EXPORT =====================================================*/
/*==== PRIVAT =====================================================*/
#if defined(DL_TRACE_ENABLED)
#ifdef OPTION_MULTITHREAD
  #define TRACE_TYPE    _ENTITY_PREFIXED(TRACE_TYPE)
  #define CHANNEL       _ENTITY_PREFIXED(CHANNEL)
  #define STATES        _ENTITY_PREFIXED(STATES)
#endif  /* OPTION_MULTITHREAD */
LOCAL const char* const STATES[] =      {
                                "INVALID",
                                "DISABLED",
                                "IDLE_DL",
                                "SUSPENDED",
                                "AWAITING_ESTABLISHMENT",
                                "MULTI_FRAME_ESTABLISHED",
                                "TIMER_RECOVERY",
                                "AWAITING_RELEASE"
                             };
LOCAL const char* const TRACE_TYPE[] =  { "UL", "DL", "Ev", "St", "PL", "RR" };
LOCAL const char* const CH_TYPE[] =     { "  ", "SA", "SD", "FH", "FF", "CC", "BC", "PC", "PE", "CB", "BE" };
LOCAL const char  SAPI_TYPE[] =         { '0', '1', '2', '3', ' '};

LOCAL void  array2hex (UBYTE *inarray, char *outarray, int size);

#if !defined(DL_IMMEDIATE_TRACE)

/*==== TEST TRACE ===================================================*/
#define TEST_ENTITY_DL

/*==== VARIABLES ==================================================*/
/*==== FUNCTIONS ==================================================*/
/*
 * The Data Link Layer Trace is a cyclic buffer for
 * debugging layer 2 problems.
 *
 * The buffer will be initialized at startup and will
 * be filled by the function dl_trace() until it is full.
 * The size of the buffer is IDLE_TRACE_SIZE.
 *
 * The content is
 *
 * trace_type (uplink, downlink, event state, alr_event, rr_event)
 * Channel Type (SACCH, SDDCH, FACCH)
 * real system clock
 * State (DL states)
 * pending disc request
 * data (layer frame, eevnt strings, state)
 *
 * During IDLE mode (triggered by RX_PERIODIC_IND in ALR/TIL_main.c)
 * an output is written to as SYST trace.
 * (IDLE_TRACE_MAX_READED traces each trigger)
 */

#define IDLE_TRACE_SIZE       512
#define IDLE_TRACE_MAX_READED  16

#if (((IDLE_TRACE_SIZE-1) & (~IDLE_TRACE_SIZE)) == (IDLE_TRACE_SIZE-1))
#define POWER_OF_2
#pragma message("IDLE_TRACE_SIZE is power of 2")
#else
#pragma message("IDLE_TRACE_SIZE is NOT power of 2")
#endif

typedef struct
{
  UBYTE         trace_type;
  UBYTE         ch_type;
  UBYTE         sapi;
  T_TIME        sysClock;
  UBYTE         disc_request;
  UBYTE         state;
  UBYTE         data [MAX_L2_FRAME_SIZE];
} T_IDLE_TRACE_DATA;

#ifdef OPTION_MULTITHREAD
  #define IDLE_Trace_buffer       _ENTITY_PREFIXED(IDLE_Trace_buffer)
  #define IDLE_Trace_write_index  _ENTITY_PREFIXED(IDLE_Trace_write_index)
  #define IDLE_Trace_read_index   _ENTITY_PREFIXED(IDLE_Trace_read_index)
#endif  /* OPTION_MULTITHREAD */

GLOBAL T_IDLE_TRACE_DATA   IDLE_Trace_buffer [IDLE_TRACE_SIZE];
GLOBAL USHORT              IDLE_Trace_write_index  = 0;
GLOBAL USHORT              IDLE_Trace_read_index   = 0;

LOCAL  T_HANDLE            sem_DL_TRC;

GLOBAL void dl_trace_init (void)
{
  sem_DL_TRC  = vsi_s_open (VSI_CALLER "DL_IDLE_TRACE",1);
  if (sem_DL_TRC NEQ VSI_ERROR)
    dl_trace_clear (0);
  else
    SYST_TRACE ("DL:canīt open semaphore \"DL_IDLE_TRACE\"");
}

GLOBAL void dl_trace_exit (void)
{
  if (sem_DL_TRC NEQ VSI_ERROR)
    vsi_s_close (VSI_CALLER sem_DL_TRC);
}

GLOBAL void dl_trace_clear ()
{
  dl_trace_read_all (0); /* first, get all remaining traces (if exists) */

  ENTER_CRITICAL_SECTION (sem_DL_TRC);
  IDLE_Trace_write_index = IDLE_Trace_read_index = 0;
  LEAVE_CRITICAL_SECTION (sem_DL_TRC);

  TRACE_EVENT ("offline trace reset");
  DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, 0, "offline trace reset");
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
| STATE   : code                     ROUTINE : dl_trace              |
+--------------------------------------------------------------------+

  PURPOSE : Fill in a trace.

*/
GLOBAL void dl_trace (UCHAR trace_type, UCHAR channel, UCHAR ch_type, UCHAR* data)
{
  T_IDLE_TRACE_DATA*  trace_data;
  USHORT              write_index1, write_index2;/* trace_size must not be greater than 2 */
  UBYTE               trace_size;

  if (data)
  {
#if defined (DISABLE_MEASREPORT_TRACE)
    if ((ch_type EQ L2_CHANNEL_SACCH) AND
        (data[2] EQ 0x01) AND
        (data[3] EQ 0x03) AND
        (data[4] EQ 0x49))
      return;
#endif  /* DISABLE_MEASREPORT_TRACE */

#if defined (DISABLE_EMPTY_UI)
    if ((trace_type EQ TRACE_DOWNLINK) OR (trace_type EQ TRACE_UPLINK))
    {
      if ((ch_type EQ L2_CHANNEL_SACCH) AND
        (data[3] EQ 0x03) AND
        (data[4] EQ 0x01))
        return;
      else if (
        (data[1] EQ 0x03) AND
        (data[2] EQ 0x01))
        return;
    }
#endif  /* DISABLE_EMPTY_UI */
  }

  TEST_SEMAPHORE (sem_DL_TRC);
  ENTER_CRITICAL_SECTION(sem_DL_TRC);

  trace_size = 1;
  if ((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT))
  {
    if (data AND strlen ((char *)data) >= 23)
      trace_size = 2;
  }

#if defined(POWER_OF_2)
  write_index1 = (IDLE_Trace_write_index + 1) & (IDLE_TRACE_SIZE - 1);  /* if IDLE_TRACE_SIZE power of 2 */
  write_index2 = (IDLE_Trace_write_index + trace_size) & (IDLE_TRACE_SIZE - 1);  /* if IDLE_TRACE_SIZE power of 2 */
#else
  write_index1 = (IDLE_Trace_write_index + 1) % IDLE_TRACE_SIZE;      /* if IDLE_TRACE_SIZE not power of 2 */
  write_index2 = (IDLE_Trace_write_index + trace_size) % IDLE_TRACE_SIZE;      /* if IDLE_TRACE_SIZE not power of 2 */
#endif  /* POWER_OF_2 */
  if ((write_index1 NEQ IDLE_Trace_read_index) AND (write_index2 NEQ IDLE_Trace_read_index))
  { /* buffer is not full */
    trace_data = &IDLE_Trace_buffer[IDLE_Trace_write_index];

    trace_data->trace_type = trace_type;
    if ((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT))
    {
      trace_data->state = trace_size;
    }
    else
    {
  GET_INSTANCE_DATA; 
      trace_data->ch_type = ch_type;
      switch (channel)
      {
      case C_SACCH0:
      case C_DCCH0:
        trace_data->disc_request = dl_data->dcch0_disc_request;
        trace_data->state = dl_data->state [C_DCCH0];
        trace_data->sapi = PS_SAPI_0;
        break;
      case C_DCCH3:
        trace_data->disc_request = dl_data->dcch3_disc_request;
        trace_data->state = dl_data->state [C_DCCH3];
        trace_data->sapi = PS_SAPI_3;
        break;
      default:
        trace_data->disc_request = 0;
        trace_data->state = 0;
        trace_data->sapi = NOT_PRESENT_8BIT;
        break;
      }
    }

    vsi_t_time (VSI_CALLER &trace_data->sysClock);

    if (data)
    {
      memcpy (trace_data->data, data, MAX_L2_FRAME_SIZE);
      if ((trace_type NEQ TRACE_UPLINK) AND (trace_type NEQ TRACE_DOWNLINK))
      {
        trace_data->data[MAX_L2_FRAME_SIZE-1] = 0;
      }

      if (trace_size EQ 2)
      {
        if (IDLE_Trace_write_index EQ (IDLE_TRACE_SIZE - 1))/* the last buffer index ? */
          trace_data = &IDLE_Trace_buffer[0];/* -> overflow to the first buffer index */
        else
          trace_data++;
        memcpy (trace_data->data, data+MAX_L2_FRAME_SIZE-1, MAX_L2_FRAME_SIZE-1);
        trace_data->data[MAX_L2_FRAME_SIZE-1] = 0;
      }
    }

    IDLE_Trace_write_index = write_index2;
  }/* endif buffer is not full */

  LEAVE_CRITICAL_SECTION (sem_DL_TRC);

#if defined(_SIMULATION_)
  dl_trace_read (0);
#endif  /* _SIMULATION_ */
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
| STATE   : code                     ROUTINE : dl_trace_read         |
+--------------------------------------------------------------------+

  PURPOSE : Fill in a trace.

*/
GLOBAL void dl_trace_read_all ()
{
  USHORT  write_index, read_index;

  do
  {
    dl_trace_read ();

    ENTER_CRITICAL_SECTION (sem_DL_TRC);
    write_index = IDLE_Trace_write_index;
    read_index = IDLE_Trace_read_index;
    LEAVE_CRITICAL_SECTION (sem_DL_TRC);
  } while (read_index NEQ write_index);
}

GLOBAL void dl_trace_read ()
{
  T_IDLE_TRACE_DATA*  trace_data;
  USHORT              write_index, read_index, left;
  UBYTE               trace_size;
  static char         buffer[80];
  UBYTE               j, o, readed = 0;

  TEST_SEMAPHORE (sem_DL_TRC);

  ENTER_CRITICAL_SECTION (sem_DL_TRC);
  write_index = IDLE_Trace_write_index;
  read_index = IDLE_Trace_read_index;
  LEAVE_CRITICAL_SECTION (sem_DL_TRC);

  if (read_index EQ write_index)
  {
    #if defined (_TARGET_) AND !defined( GPRS ) AND defined(FF_GTI)
      sleep_mode ();
    #endif  /* _TARGET_ AND !GPRS AND !FF_GTI */
    return;
  }

  while (read_index NEQ write_index)
  {
    ENTER_CRITICAL_SECTION (sem_DL_TRC);
    trace_data = &IDLE_Trace_buffer[read_index];
    LEAVE_CRITICAL_SECTION (sem_DL_TRC);

#if defined(POWER_OF_2)
    left = (write_index - read_index - 1) & (IDLE_TRACE_SIZE-1);
#else
    left = (IDLE_TRACE_SIZE + write_index - read_index - 1) % IDLE_TRACE_SIZE;
#endif  /* POWER_OF_2 */

    if (trace_data->ch_type > ELEMENTS(CH_TYPE))
      trace_data->ch_type = 0;

    if (trace_data->sapi >= ELEMENTS (SAPI_TYPE))
      trace_data->sapi = ELEMENTS (SAPI_TYPE) - 1;

    trace_size = 1;/* default */
    switch (trace_data->trace_type)
    {
    case TRACE_UPLINK:
    case TRACE_DOWNLINK:
      sprintf (buffer, "[%03d]:%07lu %c%d %s %s ",
        left,
        trace_data->sysClock,
        trace_data->disc_request?'D':' ',
        trace_data->state,
        TRACE_TYPE[trace_data->trace_type],
        CH_TYPE[trace_data->ch_type]);
      o = strlen (buffer);
      array2hex (trace_data->data, buffer+o, 23);
      break;

    case TRACE_DL_EVENT:
      sprintf (buffer, "[%03d]:%07lu %c%d Ev %s%c %s",
        left,
        trace_data->sysClock,
        trace_data->disc_request?'D':' ',
        trace_data->state,
        CH_TYPE[trace_data->ch_type],
        SAPI_TYPE[trace_data->sapi],
        trace_data->data);
      break;

    case TRACE_PL_EVENT:
    case TRACE_RR_EVENT:
      trace_size = trace_data->state;
      if (trace_size EQ 2)
      {
        T_IDLE_TRACE_DATA *trace_data2;
        if (read_index EQ (IDLE_TRACE_SIZE - 1))/* the last buffer index ? */
          trace_data2 = &IDLE_Trace_buffer[0];/* -> overflow to the first buffer index */
        else
          trace_data2 = trace_data+1;

        sprintf (buffer, "[%03d]:%07lu %d  Ev %s %s%s",
          left,
          trace_data->sysClock,
          trace_data->state,
          TRACE_TYPE[trace_data->trace_type],
          trace_data->data,
          trace_data2->data);
      }
      else
      {
        sprintf (buffer, "[%03d]:%07lu %d  Ev %s %s",
          left,
          trace_data->sysClock,
          trace_data->state,
          TRACE_TYPE[trace_data->trace_type],
          trace_data->data);
      }
      break;

    case TRACE_CHSTATE:
      sprintf (buffer, "[%03d]:%07lu %c%d ST %s%c state=%s",
        left,
        trace_data->sysClock,
        trace_data->disc_request?'D':' ',
        trace_data->state,
        CH_TYPE[trace_data->ch_type],
        SAPI_TYPE[trace_data->sapi],
        STATES[trace_data->state]);
      break;

    default:
      buffer[0] = 0;
      break;
    }

    if (buffer[0])
    {
      SYST_TRACE (buffer);
    }
    else
    {
      SYST_TRACE ("dl_trace_read() failed");
    }

    ENTER_CRITICAL_SECTION (sem_DL_TRC);
    trace_data->sysClock = 0; /* readed */
    IDLE_Trace_read_index += trace_size;
#if defined(POWER_OF_2)
    IDLE_Trace_read_index &= (IDLE_TRACE_SIZE-1);/* if power of 2 */
#else
    IDLE_Trace_read_index %= IDLE_TRACE_SIZE; /* if not power of 2 */
#endif  /* POWER_OF_2 */
    read_index = IDLE_Trace_read_index;
    write_index = IDLE_Trace_write_index;
    LEAVE_CRITICAL_SECTION (sem_DL_TRC);

    if (readed++ >= IDLE_TRACE_MAX_READED)
      break;
  }/* endwhile */
}

#else  /* DL_IMMEDIATE_TRACE */

#define IMM_TRACE_SIZE       2
typedef struct
{
  UBYTE         sapi;
  T_TIME        sysClock;
  UBYTE         disc_request;
  UBYTE         state;
  UBYTE         data [IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE];
} T_TRACE_DATA;

#ifdef OPTION_MULTITHREAD
  #define print_buffer  _ENTITY_PREFIXED(print_buffer)
  #define trace_buffer  _ENTITY_PREFIXED(trace_buffer)
#endif  /* OPTION_MULTITHREAD */
LOCAL char          print_buffer[25+IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE];
LOCAL T_TRACE_DATA  trace_buffer;

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
| STATE   : code                     ROUTINE : dl_trace              |
+--------------------------------------------------------------------+

  PURPOSE : Fill in a trace.

*/

GLOBAL void dl_fast_trace (UBYTE trace_type, UBYTE channel, UBYTE ch_type,
                    T_TIME trace_time, ULONG trace_mask, UBYTE* data)
{
  T_TRACE_DATA*  trace_data;
  UBYTE          o;

  /* While TC_USER2 is set, measurements and empty frames will be traced always */
  if (data AND ((trace_mask & TC_USER2) EQ 0))
  {
    if ((ch_type EQ L2_CHANNEL_SACCH) AND
        (data[2] EQ 0x01) AND
        (data[3] EQ 0x03) AND
        (data[4] EQ 0x49))
      return;

    if ((trace_type EQ TRACE_DOWNLINK) OR (trace_type EQ TRACE_UPLINK))
    {
      if ((ch_type EQ L2_CHANNEL_SACCH) AND
        (data[3] EQ 0x03) AND
        (data[4] EQ 0x01))
        return;
      else if (
        (data[1] EQ 0x03) AND
        (data[2] EQ 0x01))
        return;
    }
  }

  trace_data = &trace_buffer;
  trace_data->sysClock = trace_time;
  if (!((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT)))
  {
  GET_INSTANCE_DATA; 
    switch (channel)
    {
    case C_SACCH0:
    case C_DCCH0:
      trace_data->disc_request = dl_data->dcch0_disc_request;
      trace_data->state = dl_data->state [C_DCCH0];
      trace_data->sapi = PS_SAPI_0;
      break;
    case C_DCCH3:
      trace_data->disc_request = dl_data->dcch3_disc_request;
      trace_data->state = dl_data->state [C_DCCH3];
      trace_data->sapi = PS_SAPI_3;
      break;
    default:
      trace_data->disc_request = 0;
      trace_data->state = 0;
      trace_data->sapi = NOT_PRESENT_8BIT;
      break;
    }
  }

  if (data)
  {
    if ((trace_type EQ TRACE_UPLINK) OR (trace_type EQ TRACE_DOWNLINK))
    {
      memcpy (trace_data->data, data, MAX_L2_FRAME_SIZE);
    }
    else
    {
      strncpy ((char *)trace_data->data, (char *)data, IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE-1);
      trace_data->data[IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE-1] = 0;
    }
  }
  else
  {
    trace_data->data[0] = 0;
  }


  if (ch_type > ELEMENTS(CH_TYPE))
    ch_type = 0;

  if (trace_data->sapi >= ELEMENTS (SAPI_TYPE))
    trace_data->sapi = ELEMENTS (SAPI_TYPE) - 1;

  switch (trace_type)
  {
  case TRACE_UPLINK:
  case TRACE_DOWNLINK:
    sprintf (print_buffer, "DLTRC:%07lu %c%d %s %s%c ",
      trace_data->sysClock,
      trace_data->disc_request?'D':' ',
      trace_data->state,
      TRACE_TYPE[trace_type],
      CH_TYPE[ch_type],
      SAPI_TYPE[trace_data->sapi]);
    o = strlen (print_buffer);
    array2hex (trace_data->data, print_buffer+o, 23);
    break;

  case TRACE_DL_EVENT:
    sprintf (print_buffer, "DLTRC:%07lu %c%d Ev %s%c %s",
      trace_data->sysClock,
      trace_data->disc_request?'D':' ',
      trace_data->state,
      CH_TYPE[ch_type],
      SAPI_TYPE[trace_data->sapi],
      trace_data->data);
    break;

  case TRACE_PL_EVENT:
  case TRACE_RR_EVENT:
    sprintf (print_buffer, "DLTRC:%07lu %d  Ev %s %s",
      trace_data->sysClock,
      trace_data->state,
      TRACE_TYPE[trace_type],
      trace_data->data);
    break;

  case TRACE_CHSTATE:
    sprintf (print_buffer, "DLTRC:%07lu %c%d ST %s%c state=%s",
      trace_data->sysClock,
      trace_data->disc_request?'D':' ',
      trace_data->state,
      CH_TYPE[ch_type],
      SAPI_TYPE[trace_data->sapi],
      STATES[trace_data->state]);
    break;

  default:
    print_buffer[0] = 0;
    break;
  }

  TRACE_USER_CLASS (TC_USER1, print_buffer);

#if 0
  if (print_buffer[0])
  {
    #if defined(_SIMULATION_)
      TRACE_EVENT_WIN (print_buffer);
    #else  /* _SIMULATION_ */
      SYST_TRACE_P ((DLTRC,print_buffer));
    #endif  /* _SIMULATION_ */
  }
#endif /* 0 */
}
#endif  /* DL_IMMEDIATE_TRACE */

LOCAL void  array2hex (UBYTE *inarray, char *outarray, int size)
{
  int col=0, n=0;
  UBYTE b, nh, nl;

  while (n < size)
  {
    b = inarray[n++];
    nh = b>>4;
    nl = b&0x0f;
    outarray[col++] = nh > 9 ? nh + 'A' - 10 : nh + '0';
    outarray[col++] = nl > 9 ? nl + 'A' - 10 : nl + '0';
  }
  outarray[col] = 0;
}
#endif  /* DL_TRACE_ENABLED */

#if defined (DL_TRACE_PFREE)
GLOBAL void* my_pfree(void *pointer, int line, char *file)
{

  char buffer[23];
  sprintf (buffer, "%s#%u:%p", file+2, line, pointer);
  dl_trace (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, buffer);

  if (pointer)
  {
    PFREE (pointer);
  }
  else
  {
    SYST_TRACE_P((SYST, "%s#%u: PFREE(NULL)", file, line));
  }

  return NULL;
}
#endif /* DL_TRACE_PFREE */

#endif  /* DL_TRACE_C */