/*
+--------------------------------------------------------------------+
/*
+-------------------------------------------------------------------+
| PROJECT: GSM-F&D (8411)               $Workfile:: cst_pei.c       $|
| $Author:: Be $ CONDAT GmbH            $Revision:: 14              $|
| CREATED: 01.02.99                     $Modtime:: 14.02.00 12:14   $|
| STATE  : code                                                      |
+--------------------------------------------------------------------+

   MODULE  : CST_PEI

   PURPOSE : This Modul defines the process body interface for the
             component CST of the mobile station.

   EXPORT  : pei_create    - Create the Protocol Stack Entity
             pei_init      - Initialize Protocol Stack Entity
             pei_primitive - Process Primitive
             pei_timeout   - Process Timeout
             pei_exit      - Close resources and terminate
             pei_run       - Process Primitive
             pei_config    - Dynamic Configuration
             pei_monitor   - Monitoring of physical Parameters
*/

#ifndef CST_PEI_C
#define CST_PEI_C
#endif

#include "config/swconfig.cfg"
#include "config/chipset.cfg"


#define ENTITY_CST

/*==== INCLUDES ===================================================*/

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "typedefs.h"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "prim.h"
#include "cst/cnf_cst.h"
#include "cst/cus_cst.h"
#include "cst/mon_cst.h"
#include "tok.h"
#include "p_cst.h"
#include "cst/cst.h"
#include "rx.h"
#include "audio.h"

/*==== CONSTANTS ==================================================*/

// token processing
#define ERROR     -1
#define EOS        1
#define COMMA      2
#define EQUAL      3
#define IDENT      4
#define STRING     5
#define LBRACK     6
#define RBRACK     7

/*==== EXPORT =====================================================*/
extern void CST_stack_trace(void);
int cst_gsm_parameters(TOK_DCB *dcb);
extern void l1_cst_l1_parameters(char*); 
extern void csf_adc_start (UBYTE tx_flag, UBYTE traffic_period, UBYTE idle_period);
extern void spi_adc_on (void); 

GLOBAL T_HANDLE t_adc_timer    = VSI_ERROR;
GLOBAL T_HANDLE hCommPL        = VSI_ERROR;    /* PL Communication */
GLOBAL T_HANDLE hCommL1        = VSI_ERROR;    /* L1 Communication */
       T_HANDLE cst_handle;
GLOBAL UBYTE extDisplay = 0;

EXTERN UBYTE audio_is_free;
/*==== PRIVATE ====================================================*/

LOCAL const void pei_not_supported (void *data);

#ifdef OPTION_RELATIVE
LOCAL ULONG offset;
#endif

/*==== VARIABLES ==================================================*/

LOCAL USHORT            t_flag = 0;
LOCAL BOOL              exit_flag = FALSE;
LOCAL BOOL              first_access = TRUE;
LOCAL T_MONITOR         cst_mon;

/*==== FUNCTIONS ==================================================*/
LOCAL const T_FUNC cst_table[] =
{
  MAK_FUNC_0 ( csf_adc_process          , CST_ADC_IND             )
};

/*==== PROTOTYPES==================================================*/

#if defined (_TMS470)

static SHORT cst_tok_gettok (TOK_DCB *dcb, char ** token);
static SHORT cst_tok_value (TOK_DCB *dcb, char * value []);
static int   cst_tokenizer_has_more_data(const TOK_DCB *dcb);
static SHORT cst_tok_issep (char c);
static void  cst_tok_init (char * s, TOK_DCB *dcb, char *buf, int buf_len);
static SHORT cst_get_values(TOK_DCB *dcb, char *value[]);
static int   cst_getbyte(TOK_DCB *dcb);

#endif

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_primitive       |
+--------------------------------------------------------------------+

  PURPOSE : This function processes protocol specific primitives.
*/
LOCAL SHORT pei_primitive (void * ptr)
{
  T_PRIM *prim = ptr;

  if (prim NEQ NULL)
  {
    USHORT           opc = prim->custom.opc;
    USHORT           n;
    const T_FUNC    *table;

    VSI_PPM_REC ((T_PRIM_HEADER*)prim, __FILE__, __LINE__);

    switch (opc & OPC_MASK)
    {
      case    CST_DL: table =     cst_table; n = TAB_SIZE     (cst_table); break;
      default : table = NULL; n = 0; break;
    }

    if (table != NULL )
    {
      if ((opc & PRM_MASK) < n)
      {
        table += opc & PRM_MASK;
#ifdef PALLOC_TRANSITION
        P_SDU(prim) = table->soff ? (T_sdu*) (((char*)&prim->data) + table->soff) : 0;
        P_LEN(prim) = table->size + sizeof (T_PRIM_HEADER);
#endif
        JUMP (table->func) (P2D(prim));
      }
      else
      {
        pei_not_supported (P2D(prim));
      }
      return PEI_OK;
    }

#ifdef GSM_ONLY
    PFREE (P2D(prim))
    return PEI_ERROR;
#else
    if (opc & SYS_MASK)
    {
      vsi_c_primitive (VSI_CALLER prim);
    }
    else
    {
      PFREE (P2D(prim))
      return PEI_ERROR;
    }
#endif
  }
  return PEI_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_not_supported   |
+--------------------------------------------------------------------+

  PURPOSE : This function handles an unsupported primitive.
*/
LOCAL const void pei_not_supported (void *data)
{
  TRACE_FUNCTION ("pei_not_supported()");

  PFREE (data);
}


/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_init            |
+--------------------------------------------------------------------+

  PURPOSE : This function initializes the protocol stack entity

*/

LOCAL SHORT pei_init (T_HANDLE handle)
{
  cst_handle = handle;

  TRACE_FUNCTION ("pei_init()");

  exit_flag = FALSE;

  if (hCommPL < VSI_OK)
  {
    if ((hCommPL = vsi_c_open (VSI_CALLER PL_NAME)) < VSI_OK)
    {
      return PEI_ERROR;
  	}
    }

  if (hCommL1 < VSI_OK)
  {
    if ((hCommL1 = vsi_c_open (VSI_CALLER L1_NAME)) < VSI_OK)
    {
      return PEI_ERROR;
    }
  }

  vsi_t_start (VSI_CALLER CST_ADC_TIMER, 230);  // equal to 50 TDMA frames

#if defined (_TMS470)
  // Set the sleep mode authorized for the layer1 synchronous.
  // Possible modes are :
  //          for CHIPSET = 0 : NO_SLEEP, SMALL_SLEEP, BIG_SLEEP.
  //                            It is necessary to indicate in the prototype of power_down_config()
  //                            function which clocks (amongst ARMIO_CLK, UWIRE_CLK, SIM_CLK and UART_CLK)
  //                            to be stopped in case of BIG_SLEEP mode.
  //                            With this default init, ARMIO_CLK, UWIRE_CLK, SIM_CLK and UART_CLK will be stopped
  //                            in case of BIG_SLEEP mode, but it can be changed here.

  //          other CHIPSETs  : NO_SLEEP, SMALL_SLEEP, BIG_SLEEP, DEEP_SLEEP, ALL_SLEEP.
  //                            It is necessary to indicate in the prototype of power_down_config()
  //                            function which clocks to be stopped in case of BIG_SLEEP mode,
  //                            amongst ARMIO and UWIRE clocks.
  //                            With this default init, UWIRE_CLK will always be stopped
  //                            in case of BIG_SLEEP mode, but it can be changed here.

  // The default configuration is ALL SLEEP. It can be changed in this init.

  // WARNING !!     THE SLEEP MODE SHOULD NOT BE MODIFIED ONCE THE SYSTEM INIT IS FINISHED     !!

  #if !defined (TI_VERSION)
    #if (CHIPSET == 0)
      power_down_config(NO_SLEEP, ARMIO_CLK | UWIRE_CLK | SIM_CLK | UART_CLK);
    #elif ((CHIPSET == 2) || (CHIPSET == 3) ||  \
           (CHIPSET == 5) || (CHIPSET == 6) || (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 10) || (CHIPSET == 11))
      power_down_config(ALL_SLEEP, UWIRE_CLK_CUT);
    #elif ((CHIPSET == 4) || (CHIPSET == 9))
        power_down_config(NO_SLEEP, UWIRE_CLK_CUT);
    #endif
  #endif
#endif

  return PEI_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_timeout         |
+--------------------------------------------------------------------+

  PURPOSE : This function processes timeouts.
*/

LOCAL SHORT pei_timeout (USHORT index)
{
  rx_timeout    (index);
  audio_timeout (index);

  if (index EQ CST_ADC_TIMER)
  {
    // start the AD conversions in layer1 synchronous
    // this function will send MMI_ADC_REQ primitive to L1A for test reason.
    // The user has to implement it by himself in the MMI.
    // The parameters are : tx_flag, traffic_period, idle_period.
    // Please refer to the ADC specification for details.
    
	// WCS Patch : Schedule ADC on RX and TX
    #if (OP_WCP == 1)
	  csf_adc_start(1, 10, 1);    
    #else
      csf_adc_start(0, 10, 1);
    #endif
    
    spi_adc_on();
  }

  return PEI_OK;
}


/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_exit            |
+--------------------------------------------------------------------+

  PURPOSE : This function closes all resources and terminates.
*/

LOCAL SHORT pei_exit (void)
{
  TRACE_FUNCTION ("pei_exit()");

  /*
   * clean up communication
   */

  vsi_c_close (VSI_CALLER hCommPL);
  hCommPL = VSI_ERROR;

  vsi_c_close (VSI_CALLER hCommL1);
  hCommL1 = VSI_ERROR;

  exit_flag = TRUE;

  return PEI_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_config          |
+--------------------------------------------------------------------+

  PURPOSE : Dynamic Configuration

*/

#if !defined (NCONFIG)
LOCAL KW_DATA kwtab[] = {
                   CST_CONFIG,           ID_CONFIG,
                   CST_MUTE,             ID_MUTE,
                   CST_GSM_PARAMETERS,	 ID_GSM_PARAMETERS,
                   CST_L1_PARAMETERS,    ID_L1_PARAMETERS,
                   "",                   0
       	          };

GLOBAL KW_DATA partab[] = {
                   "",                 0
       	          };
#endif


GLOBAL SHORT pei_config (T_PEI_CONFIG inString)
{
#if !defined (NCONFIG)
  char    * s = inString;
  SHORT     valno;
  USHORT    keyno;
  char    * keyw;
  char    * val [10];
  TOK_DCB   tokenizer;
  char      token_buf[80];
  SHORT     token_type;
  int       error;      /* terminate processing */

  TRACE_FUNCTION ("pei_config()");

  TRACE_FUNCTION (s);

  cst_tok_init(s, &tokenizer, &token_buf[0], sizeof(token_buf));

  /*
   * Parse next keyword and number of variables
   */
  error = 0;
  while (!error && cst_tokenizer_has_more_data(&tokenizer))
  {
    token_type = cst_tok_gettok(&tokenizer, &keyw);
    if (token_type != IDENT)
    {
      error = 1;
    }
    else
    {
      switch ((keyno = tok_key((KW_DATA *)kwtab, keyw)))
      {
        case ID_CONFIG:
          valno = cst_get_values(&tokenizer, val);
          if (valno EQ 3)
          {
            extDisplay = 1;
          }
          break;
        case ID_MUTE:
          valno = cst_get_values(&tokenizer, val);  /* eat up rest of line */
          /*
           * FTA testcase 26.6.3.4 needs the the MS is in audio free
           * environment. This config disables opening of the audio
           * path.
           */
          audio_is_free = FALSE;
          break;
        case ID_GSM_PARAMETERS:
          cst_gsm_parameters(&tokenizer);
          break;
        case ID_L1_PARAMETERS:
          /* pass parameters to L1 function for further process */
          l1_cst_l1_parameters(s); 
          valno = cst_get_values(&tokenizer, val);  /* eat up rest of line */
          break;
        default:
          TRACE_ERROR ("[PEI_CONFIG]: Illegal Keyword");
          break;
      }
    }
  }
#endif
  return PEI_OK;
}

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

  PURPOSE : Dynamic Configuration

*/

GLOBAL SHORT cst_pei_config ( char * inString, char * dummy )
{
  pei_config ( inString );
}


/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_monitor         |
+--------------------------------------------------------------------+

  PURPOSE : This function monitors physical parameters.
*/
LOCAL SHORT pei_monitor (void ** monitor)
{
  TRACE_FUNCTION ("pei_monitor()");

  cst_mon.version = VERSION_CST;

  *monitor = &cst_mon;

  return PEI_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : pei_create          |
+--------------------------------------------------------------------+

  PURPOSE : This function creates the protocol stack entity.
*/

GLOBAL SHORT cst_pei_create (T_PEI_INFO **info)
{
  static const T_PEI_INFO pei_info =
  {
    "CST",
    {
      pei_init,
      pei_exit,
      pei_primitive,
      pei_timeout,
      NULL,             /* no signal function  */
      NULL,             /* no run function     */
      pei_config,
      pei_monitor,
    },
    1536,     /* Stack Size      */
    10,       /* Queue Entries   */
    55,       /* Priority        */
    MAX_CST_TIMER,        /* number of timer */
    0x03      /* flags           */
  };

  TRACE_FUNCTION ("pei_create()");

  /*
   *  Close Resources if open
   */

  if (first_access)
    first_access = FALSE;
  else
    pei_exit ();

  /*
   *  Export startup configuration data
   */

  *info = (T_PEI_INFO *)&pei_info;

  return PEI_OK;
}


/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_tok_init        |
+--------------------------------------------------------------------+

   PURPOSE : Initialize token scanner.

*/
static void cst_tok_init (char * s, TOK_DCB *dcb, char *buf, int buf_len)
{
  int i;
  dcb->nexttok = dcb->tokbuf = buf;
  // can't use strcpy since it stops at 0s
  for (i=0; i<buf_len-1; i++)
  {
    dcb->tokbuf[i] = s[i];
  }
  dcb->tokbuf[buf_len-1]  = '\0';
  dcb->lastchar    = 0;
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_get_values      |
+--------------------------------------------------------------------+
*/
static SHORT cst_get_values(TOK_DCB *dcb, char *value[])
{
  char * val;  /* not identifier, so thrown away */
  /*
   * Check next token
   */
  switch (cst_tok_gettok (dcb, &val))
  {
    /*
     * No value present
     */
    case COMMA:
      return (0);
    /*
     * Value(s) follows
     */
    case EQUAL:
      return (cst_tok_value (dcb, value));
    /*
     * No value present and EOS
     */
    case EOS:
      dcb->nexttok = NULL;
      return (0);
    /*
     * Syntax error
     */
    default:
      dcb->nexttok = NULL;
      return (TOK_EOCS);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_tok_value		 |
+--------------------------------------------------------------------+
*/
static SHORT cst_tok_value (TOK_DCB *dcb, char * value [])
{
  SHORT   count;
  SHORT   tok;
  SHORT   inbrack;
  char  * val;
  char  * val2;

  inbrack = 0;
  /*
   * Get next token
   */
  tok = cst_tok_gettok (dcb, &val);

  switch (tok)
  {
    case LBRACK:
      inbrack++;
      break;

    case IDENT  :
    case STRING :
      tok = cst_tok_gettok (dcb, &val2);  /* val2 ignored since next tok */
      if ((tok == COMMA) || (tok == EOS)) /* shouldn't be an IDENT       */
      {
        /* just single value, return */
        value[0] = val;
        return (1);
      }
      else
      {
        /* error */
        dcb->nexttok = NULL;
        return (0);
      }

    case EOS :
    default  :
      dcb->nexttok = NULL;
      return (0);
  }

  /*
   * Get first token of list
   */

  tok = cst_tok_gettok (dcb, &val);
  count = 0;
  while (1)
  {
    if ((tok == IDENT) || (tok == STRING))
    {
      value[count++] = val;
    }
    else
    {
      dcb->nexttok = NULL;
      return (0);
    }

    tok = cst_tok_gettok (dcb, &val);
    switch (tok)
    {
      case COMMA:
        break;

      case RBRACK :
        if (inbrack)
        {
          if (((tok = cst_tok_gettok (dcb, &val)) == COMMA) ||
               (tok == EOS))
          {
            return (count);
          }
        }
        /*
         * Fall through
         */
      default:
        dcb->nexttok = NULL;
        return (0);
    }
    tok = cst_tok_gettok (dcb, &val);
  }
  return (0);
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_tok_gettok		 |
+--------------------------------------------------------------------+

   PURPOSE : Get list of values for token.
             Return number of values found.

             Formats:  Value
                       (Value)
                       (Value, Value,...)
                       ()
*/
static SHORT cst_tok_gettok (TOK_DCB *dcb, char ** token)
{
  SHORT   tok;
  /* if previous token was IDENT, a '\0' was placed afterwards
   * for string processing and the overwritten character was
   * placed in lastchar.  We now replace this character.
   */
  if (dcb->lastchar)
  {
    *(dcb->nexttok) = dcb->lastchar;
    dcb->lastchar = 0;
  }
  /*
   * Skip leading white space
   */
  while (isspace (*(dcb->nexttok)))
  {
    dcb->nexttok++;
  }

  * token = dcb->nexttok++;

  switch (** token)
  {
    case '\0':                         /* End of string             */
    case '\n':
      tok = EOS;
      break;

    case ',':
      ** token = '\0';
      tok = COMMA;
      break;

    case '=':
      ** token = '\0';
      tok = EQUAL;
      break;

      case '(':
      case '<':
      case '[':
        ** token = '\0';
        tok = LBRACK;
        break;

      case ')':
      case '>':
      case ']':
        ** token = '\0';
        tok = RBRACK;
        break;

      case '"':
        /*
         * Get first char of string
         */
        * token = dcb->nexttok;
        while ((*(dcb->nexttok) != '\0') && (*(dcb->nexttok) != '"'))
        {
          dcb->nexttok++;
        }

        if (*(dcb->nexttok) != '\0')
        {
          *(dcb->nexttok++) = '\0';
        }

        tok = STRING;
        break;

      default:
        /*
         * Read an identifier
         */
        while ( !cst_tok_issep (*(dcb->nexttok)) )
        {
          dcb->nexttok++;
        }

        dcb->lastchar = *(dcb->nexttok);
        *(dcb->nexttok) = '\0';

        if (*token == dcb->nexttok)
        {
          /* no characters in identifier. Error in code! */
          tok = ERROR;
        }
        else
        {
          tok = IDENT;
        }
        break;
  }
  return (tok);
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_tok_issep       |
+--------------------------------------------------------------------+

  PURPOSE : Return 1 if special character.
*/
static SHORT cst_tok_issep (char c)
{
  switch (c)
  {
    case '\0' :
    case '\n' :
    case ','  :
    case '='  :
    case '('  :
    case '<'  :
    case '['  :
    case ')'  :
    case '>'  :
    case ']'  :
    case '"'  : return (1);

    default   : return (isspace (c));
  }
}

/* if string in tokenizer state has unprocessed tokens return 1 */
/*
+--------------------------------------------------------------------+
| PROJECT : XXX                MODULE  : CST_PEI                     |
| STATE   : code               ROUTINE : cst_tokenizer_has_more_data |
+--------------------------------------------------------------------+

  PURPOSE : Return 1 if string in tokenizer state has unprocessed tokens.
*/
static int cst_tokenizer_has_more_data(const TOK_DCB *dcb)
{
  return (dcb->nexttok != NULL);
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_getbyte		 |
+--------------------------------------------------------------------+
*/

static int cst_getbyte(TOK_DCB *dcb)
{
  if (dcb->nexttok)
  {
    return *(dcb->nexttok++);
  }
  else
  {
    return -1;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : XXX                        MODULE  : CST_PEI             |
| STATE   : code                       ROUTINE : cst_gsm_parameters	 |
+--------------------------------------------------------------------+
*/

int cst_gsm_parameters(TOK_DCB *dcb)
{
  unsigned char id;
  char str[80];
  int i;

  // STRIP FIRST TWO DELIMITERS
  {
    char *tok_string;

    if (cst_tok_gettok(dcb, &tok_string) != EQUAL)
    {
       return (0);
    }
    if (cst_tok_gettok(dcb, &tok_string) != LBRACK)
    {
       return (0);
    }
  }

  // GET CONTROL ID
  if ((id = cst_getbyte(dcb)) == -1)
  {
    // vsi_o_trace("CST", 0x08, "gsm_parameters() parser error: out of bytes");
    return (0);
  }

  // STACK TRACE
  else if (id == '1')
  {
  CST_stack_trace();
  } //end else if (id == '1')

  // Crash Me
  else if (id == '2')
  {
    // No instruction before setting the reset vector
    void (*reset_vector)() = (void (*)()) 0x3000000;
    (*reset_vector)();
  } //end else if (id == '2')
#if defined (ALR)
  // Print Reg Copy
  else if (id == '3')
  {
    extern int xdump_buffer;
    int *xp = &xdump_buffer;
    int magic_word;

    // displays the 16 User mode 32bits registers saved on exception
    // vsi_o_trace("CST", 0x08, "User mode registers [r0-r15] = ...");
    for (i=0; i<4; i++)
	{
	   sprintf(str, "%08x  %08x  %08x  %08x", *(xp++), *(xp++),
	                                       *(xp++), *(xp++));
       // vsi_o_trace("CST", 0x08, str);
	}

    // displays the User mode CPSR saved on exception
	sprintf(str, "User mode CPSR = %08x", *(xp++));
    // vsi_o_trace("CST", 0x08, str);

    // displays the magic word and the index of vector taken
    magic_word = *(xp++);
    sprintf(str, "Magic Word + Index of Vector = %08x", magic_word);
    // vsi_o_trace("CST", 0x08, str);

    // displays the cause of the exception
	magic_word &= 0x000F;

    switch (magic_word) {

        case 1:
            // vsi_o_trace("CST", 0x08, "Exception: Undefined Instruction");
			break;

        case 2:
            // vsi_o_trace("CST", 0x08, "Exception: Unexpected Software Interrupt");
			break;

        case 3:
            // vsi_o_trace("CST", 0x08, "Exception: Abort Prefetch");
			break;

        case 4:
            // vsi_o_trace("CST", 0x08, "Exception: Abort Data");
			break;

        case 5:
            // vsi_o_trace("CST", 0x08, "Exception: Reserved");
			break;

        default:
		    break;
	}

    // displays the bottom 20 words of user mode stack saved on exception
    // vsi_o_trace("CST", 0x08, "Bottom 20 words of User mode stack = ...");
    for (i=0; i<5; i++)
	{
	   sprintf(str, "%08x  %08x  %08x  %08x", *(xp++), *(xp++),
	                                       *(xp++), *(xp++));
       // vsi_o_trace("CST", 0x08, str);
	}
  } //end else if (id == '3')

  // Clear Reg Copy
  else if (id == '4')
  {
    extern int xdump_buffer;
	int *xp = &xdump_buffer;
    // Clears the 38 32bits registers saved on exception
    for (i=0; i<38; i++)
	{
       *(xp+i) = 0;
	}
    // vsi_o_trace("CST", 0x08, "Registers Copy cleared ...");
  } //end else if (id == '4')
#endif
#if (OP_WCP == 1)
#if (WCP_PROF == 1)
  // Enable/disable MC profiler
  else if (id == '5')
  {
    PR_EnableProfiler(0);
  } 
  else if (id == '6')
  {
    PR_EnableProfiler(1);
    power_down_config(0, 0x5ff);  // disable sleep, which interferes with profiler
  } 

  // Enable/disable CPU Meter
  else if (id == '7')
  {
    PR_EnableCpuMeter(0);
  } 
  else if (id == '8')
  {
    PR_EnableCpuMeter(1);
    power_down_config(0, 0x5ff);  // disable sleep, which interferes with CPU meter
  } 
#endif
#endif

  // STRIP LAST DELIMITER
  {
    char *tok_string;

    if (cst_tok_gettok(dcb, &tok_string) != RBRACK)
    {
       return (0);
    }
  }
}  // end cst_gsm_parameters

/*
 * Reach here if unexpected event occurs (e.g. Undefined instruction, Abort,
 * out of memory); choose whether to restart or stay in datadump mode to find
 * out cause of problem
 */
void exception_handler(void)
{
   void (*jump_address)() = (void (*)()) ((unsigned)0x0);

   (*jump_address)();
}
