/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-PS (6147)
|  Modul   :  PSA_SSF
+----------------------------------------------------------------------------- 
|  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 functions for the protocol
|             stack adapter for supplementary services.
+----------------------------------------------------------------------------- 
*/ 

#ifndef PSA_SSF_C
#define PSA_SSF_C
#endif

#include "aci_all.h"

#undef TRACING

/*==== INCLUDES ===================================================*/
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"

#include "ksd.h"
#include "aci.h"
#include "psa.h"
#include "psa_ss.h"
#include "psa_util.h"
#include "cmh_ss.h"

/*==== CONSTANTS ==================================================*/
#define MAX_MOSTI_NR    (7)     /* max number of ti's for MOS */

#define MAX_ITM         (5)     /* max number of items per line */
#define ITM_WDT         (14)    /* item width in chars */
#define HDR_WDT         (10)    /* header width in chars */

/*==== TYPES ======================================================*/


/*==== EXPORT =====================================================*/

/*==== VARIABLES ==================================================*/
LOCAL UBYTE tiPool = 0xFF; /* holds pool of transaction identifiers */

/*==== FUNCTIONS ==================================================*/

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmEmptyRslt      |
+-------------------------------------------------------------------+

  PURPOSE : assemble an empty return result facility information
            element.

*/

GLOBAL void psaSS_asmEmptyRslt ( void )
{
  TRACE_FUNCTION("psaSS_asmEmptyRslt");

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));

  ssFIECodeBuf.l_buf = 8;

  ssShrdPrm.cmpType = CT_RET_RSLT;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmErrorRslt      |
+-------------------------------------------------------------------+

  PURPOSE : assemble an return error facility information
            element.

*/

GLOBAL void psaSS_asmErrorRslt ( SHORT sId, UBYTE err )
{
  TRACE_FUNCTION("psaSS_asmErrorRslt");

  ssShrdPrm.stb[sId].failType = SSF_SS_ERR;
  ssShrdPrm.stb[sId].errCd    = err;
  ssShrdPrm.cmpType = CT_RET_ERR;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmInterrogateSS  |
+-------------------------------------------------------------------+

  PURPOSE : assemble the interrogate SS facility information element.

*/

GLOBAL void psaSS_asmInterrogateSS ( UBYTE ssCode,
                                     UBYTE bscSrvType,
                                     UBYTE bscSrv  )
{
  MCAST( irgtSS, INTERROGATE_SS_INV );

  TRACE_FUNCTION("psaSS_asmInterrogateSS");

  memset( irgtSS, 0, sizeof( T_INTERROGATE_SS_INV ));

  /* set basic settings */
  irgtSS->msg_type  = INTERROGATE_SS_INV;
  irgtSS->v_ssForBS = TRUE;

  /* set service code */
  irgtSS->ssForBS.v_ssCode = TRUE;
  irgtSS->ssForBS.ssCode   = ssCode;

  /* set basic service type */
  switch( bscSrvType )
  {
    case( BS_BEAR_SRV ):

      irgtSS->ssForBS.basicService.v_bearerService = TRUE;
      irgtSS->ssForBS.basicService.bearerService   = bscSrv;
      break;

    case( BS_TELE_SRV ):

      irgtSS->ssForBS.basicService.v_teleservice = TRUE;
      irgtSS->ssForBS.basicService.teleservice   = bscSrv;
      break;

    default:
      irgtSS->ssForBS.basicService.v_bearerService = FALSE;
      irgtSS->ssForBS.basicService.v_teleservice = FALSE;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmRegisterSS     |
+-------------------------------------------------------------------+

  PURPOSE : assemble the register SS facility information element.

*/

GLOBAL void  psaSS_asmRegisterSS    ( UBYTE ssCode, UBYTE bscSrvType,
                                      UBYTE bscSrv, UBYTE ton, UBYTE npi,
                                      UBYTE *num, UBYTE tos, UBYTE oe,
                                      UBYTE *sub, UBYTE time )
{
  MCAST( regSS, REGISTER_SS_INV );

  TRACE_FUNCTION("psaSS_asmRegisterSS");

  memset( regSS, 0, sizeof( T_REGISTER_SS_INV ));

  /* set basic settings */
  regSS->msg_type        = REGISTER_SS_INV;
  regSS->v_registerSSArg = TRUE;

  /* set service code */
  regSS->registerSSArg.v_ssCode = TRUE;
  regSS->registerSSArg.ssCode   = ssCode;

  /* set basic service type */
  switch( bscSrvType )
  {
    case( BS_BEAR_SRV ):

      regSS->registerSSArg.basicService.v_bearerService = TRUE;
      regSS->registerSSArg.basicService.bearerService   = bscSrv;
      break;

    case( BS_TELE_SRV ):

      regSS->registerSSArg.basicService.v_teleservice = TRUE;
      regSS->registerSSArg.basicService.teleservice   = bscSrv;
      break;
  }

  /* set forwarded to number */
  if( num NEQ NULL )
  {
    regSS->registerSSArg.v_forwardedToNumber = TRUE;
    regSS->registerSSArg.forwardedToNumber.c_bcdDigit
        = (UBYTE)utl_dialStr2BCD((char *) num,
                                 regSS->registerSSArg.forwardedToNumber.bcdDigit,
                                 MAX_PARTY_NUM);

    if(ton NEQ TON_NOT_PRES AND
       npi NEQ NPI_NOT_PRES)
    {
      regSS->registerSSArg.forwardedToNumber.v_noa = TRUE;
      regSS->registerSSArg.forwardedToNumber.noa   = ton;

      regSS->registerSSArg.forwardedToNumber.v_npi = TRUE;
      regSS->registerSSArg.forwardedToNumber.npi   = npi;
    }
  }

  /* set forwarded to subaddress */
  if( sub NEQ NULL )
  {
    regSS->registerSSArg.v_forwardedToSubaddress = TRUE;
    regSS->registerSSArg.forwardedToSubaddress.c_bcdDigit
        = (UBYTE)utl_dialStr2BCD((char *) sub,
                                 regSS->registerSSArg.forwardedToSubaddress.bcdDigit,
                                 MAX_SUBADDR_NUM);

    regSS->registerSSArg.forwardedToSubaddress.v_tos = TRUE;
    regSS->registerSSArg.forwardedToSubaddress.tos   = tos;

    regSS->registerSSArg.forwardedToSubaddress.v_oei = TRUE;
    regSS->registerSSArg.forwardedToSubaddress.oei   = oe;
  }

  /* set no reply timer */
  if( ssCode EQ SS_CD_CFNRY AND time NEQ KSD_TIME_NONE )
  {
    regSS->registerSSArg.v_noReplyConditionTime = TRUE;
    regSS->registerSSArg.noReplyConditionTime   = time;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmEraseSS        |
+-------------------------------------------------------------------+

  PURPOSE : assemble the erase SS facility information element.

*/

GLOBAL void psaSS_asmEraseSS ( UBYTE ssCode, UBYTE bscSrvType,
                               UBYTE bscSrv )
{
  MCAST( ersSS, ERASE_SS_INV );

  TRACE_FUNCTION("psaSS_asmEraseSS");

  memset( ersSS, 0, sizeof( T_ERASE_SS_INV ));

  /* set basic settings */
  ersSS->msg_type  = ERASE_SS_INV;
  ersSS->v_ssForBS = TRUE;

  /* set service code */
  ersSS->ssForBS.v_ssCode = TRUE;
  ersSS->ssForBS.ssCode   = ssCode;

  /* set basic service type */
  switch( bscSrvType )
  {
    case( BS_BEAR_SRV ):

      ersSS->ssForBS.basicService.v_bearerService = TRUE;
      ersSS->ssForBS.basicService.bearerService   = bscSrv;
      break;

    case( BS_TELE_SRV ):

      ersSS->ssForBS.basicService.v_teleservice = TRUE;
      ersSS->ssForBS.basicService.teleservice   = bscSrv;
      break;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;

}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmActivateSS     |
+-------------------------------------------------------------------+

  PURPOSE : assemble the interrogate SS facility information element.

*/

GLOBAL void psaSS_asmActivateSS ( UBYTE ssCode, UBYTE bscSrvType,
                                   UBYTE bscSrv )
{
  MCAST( actSS, ACTIVATE_SS_INV );

  TRACE_FUNCTION("psaSS_asmActivateSS");

  memset( actSS, 0, sizeof( T_ACTIVATE_SS_INV ));

  /* set basic settings */
  actSS->msg_type  = ACTIVATE_SS_INV;
  actSS->v_ssForBS = TRUE;

  /* set service code */
  actSS->ssForBS.v_ssCode = TRUE;
  actSS->ssForBS.ssCode   = ssCode;

  /* set basic service type */
  switch( bscSrvType )
  {
    case( BS_BEAR_SRV ):

      actSS->ssForBS.basicService.v_bearerService = TRUE;
      actSS->ssForBS.basicService.bearerService   = bscSrv;
      break;

    case( BS_TELE_SRV ):

      actSS->ssForBS.basicService.v_teleservice = TRUE;
      actSS->ssForBS.basicService.teleservice   = bscSrv;
      break;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;

}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmDeactivateSS   |
+-------------------------------------------------------------------+

  PURPOSE : assemble the deactivate SS facility information element.

*/

GLOBAL void psaSS_asmDeactivateSS ( UBYTE ssCode, UBYTE bscSrvType,
                                     UBYTE bscSrv )
{
  MCAST( deactSS, DEACTIVATE_SS_INV );

  TRACE_FUNCTION("psaSS_asmDeactivateSS");

  memset( deactSS, 0, sizeof( T_DEACTIVATE_SS_INV ));

  /* set basic settings */
  deactSS->msg_type  = DEACTIVATE_SS_INV;
  deactSS->v_ssForBS = TRUE;

  /* set service code */
  deactSS->ssForBS.v_ssCode = TRUE;
  deactSS->ssForBS.ssCode   = ssCode;

  /* set basic service type */
  switch( bscSrvType )
  {
    case( BS_BEAR_SRV ):

      deactSS->ssForBS.basicService.v_bearerService = TRUE;
      deactSS->ssForBS.basicService.bearerService   = bscSrv;
      break;

    case( BS_TELE_SRV ):

      deactSS->ssForBS.basicService.v_teleservice = TRUE;
      deactSS->ssForBS.basicService.teleservice   = bscSrv;
      break;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;

}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmRegisterPWD    |
+-------------------------------------------------------------------+

  PURPOSE : assemble the register password facility information
            element.

*/

GLOBAL void psaSS_asmRegisterPWD ( UBYTE ssCode )
{
  MCAST( regPWD, REGISTER_PWD_INV );

  TRACE_FUNCTION("psaSS_asmRegisterPWD");

  memset( regPWD, 0, sizeof( T_REGISTER_PWD_INV ));

  /* set service code */
  regPWD->v_ssCode = TRUE;
  regPWD->ssCode   = ssCode;
  regPWD->msg_type = REGISTER_PWD_INV;

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;

}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmVerifyPWD      |
+-------------------------------------------------------------------+

  PURPOSE : assemble the verify password facility information
            element.

*/

GLOBAL void psaSS_asmVerifyPWD ( UBYTE *pwd )
{
  MCAST( vrfPWD, GET_PWD_RES );

  TRACE_FUNCTION("psaSS_asmVerifyPWD");

  memset( vrfPWD, 0, sizeof( T_GET_PWD_RES ));

  /* set service code */
  vrfPWD->v_currPassword = TRUE;
  vrfPWD->msg_type = GET_PWD_RES;

  strncpy( (char *) vrfPWD->currPassword.digit, (char *) pwd, MAX_PWD_NUM );

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_RET_RSLT;

}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmProcUSSDReq    |
+-------------------------------------------------------------------+

  PURPOSE : assemble the process USSD request facility information
            element.

*/

GLOBAL void psaSS_asmProcUSSDReq ( UBYTE dcs, UBYTE *ussd, UBYTE len )
{
/*  UBYTE cmpLen;*/

  MCAST( ussdReq, PROCESS_USSD_REQ_INV );

  TRACE_FUNCTION("psaSS_asmProcUSSDReq");

  memset( ussdReq, 0, sizeof( T_PROCESS_USSD_REQ_INV ));

  /* set service code */
  ussdReq->v_ussdArg = TRUE;
  ussdReq->msg_type = PROCESS_USSD_REQ_INV;

  /* set data coding scheme */
  ussdReq->ussdArg.v_ussdDataCodingScheme = TRUE;
  ussdReq->ussdArg.ussdDataCodingScheme   = dcs;

  /* set ussd response string */
/*  if( utl_getAlphabetCb( dcs ) EQ 0 ) *//* 7bit alphabet */
/*    cmpLen = utl_cvt8To7( ussd, (UBYTE)MINIMUM( MAX_USSD_STRING, len),
                          ussdReq->ussdArg.ussdString.b_ussdString, 0 );
    else*/
  {
/*    cmpLen = len;*/
    memcpy( ussdReq->ussdArg.ussdString.b_ussdString, ussd,
            MINIMUM( MAX_USSD_STRING, len));
  }

  ussdReq->ussdArg.v_ussdString = TRUE;
  ussdReq->ussdArg.ussdString.o_ussdString = 0;
  ussdReq->ussdArg.ussdString.l_ussdString = len<<3; /*cmpLen<<3;*/

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmCnfUSSDReq     |
+-------------------------------------------------------------------+

  PURPOSE : assemble the confirm USSD request facility information
            element.
*/

GLOBAL void psaSS_asmCnfUSSDReq ( UBYTE dcs, UBYTE *ussd, UBYTE len )
{
  UBYTE cmpLen;
  UBYTE src_len;

  MCAST( ussdReq, USSD_REQ_RES );

  TRACE_FUNCTION("psaSS_asmCnfUSSDReq");

  memset( ussdReq, 0, sizeof( T_USSD_REQ_RES ));

  /* set service code */
  ussdReq->v_ussdRes = TRUE;
  ussdReq->msg_type = USSD_REQ_RES;

  /* set data coding scheme */
  ussdReq->ussdRes.v_ussdDataCodingScheme = TRUE;
  ussdReq->ussdRes.ussdDataCodingScheme   = dcs;

  /* set ussd response string */
  if( utl_getAlphabetCb( dcs ) EQ 0 ) /* 7bit alphabet */
  {
    src_len = (UBYTE)MINIMUM( MAX_USSD_STRING, len);
    cmpLen = utl_cvt8To7( ussd, src_len,
                          ussdReq->ussdRes.ussdString.b_ussdString, 0 );
    /* According to spec 23.038 section 6.1.2.3 for USSD packing, for bytes end with
     * (8*n)-1 i.e where n is 1,2,3....i.e byte 7, 15, 23 ... to be padded 
     * with carriage return <CR>(0xD) 
     */
    if ((src_len+1)%8 EQ 0)
    {
      ussdReq->ussdRes.ussdString.b_ussdString[cmpLen-1] |= (0xD << 1);
    }
  }
  else
  {
    cmpLen = len;
    memcpy( ussdReq->ussdRes.ussdString.b_ussdString, ussd,
            MINIMUM( MAX_USSD_STRING, len));
  }

  ussdReq->ussdRes.v_ussdString = TRUE;
  ussdReq->ussdRes.ussdString.o_ussdString = 0;
  ussdReq->ussdRes.ussdString.l_ussdString = cmpLen<<3;

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_RET_RSLT;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_USSDProt1         |
+-------------------------------------------------------------------+

  PURPOSE : send USSD according to protocol version 1.
*/

GLOBAL BOOL psaSS_asmUSSDProt1 ( SHORT sId )
{
  UBYTE  ussdBuf8Bit[MAX_USSD_STRING];   /* buffers 8 bit ussd string */
  USHORT ussdLen8Bit;

  TRACE_FUNCTION("psaSS_asmUSSDProt1");

  if( ssShrdPrm.ussdLen AND
      ssShrdPrm.stb[sId].SSver NEQ NOT_PRESENT_8BIT )
  {
    MCAST( ussdData, PROCESS_USSD_INV );

    memset( ussdData, 0, sizeof( T_PROCESS_USSD_INV ));

    /* set service code */
    ussdData->v_ssUserData = TRUE;
    ussdData->msg_type = PROCESS_USSD_INV;

    /* GSM data must be 8-bit coded */
    if (ssShrdPrm.ussdDcs EQ 0x0F)
    {
      ussdLen8Bit = utl_cvt7To8 (ssShrdPrm.ussdBuf, ssShrdPrm.ussdLen, ussdBuf8Bit, 0);
    }
    else
    {
      memcpy ( ussdBuf8Bit, ssShrdPrm.ussdBuf, ssShrdPrm.ussdLen);
               ussdLen8Bit = ssShrdPrm.ussdLen;
    }

    /* set ussd data string, if convertible */
    if( !utl_cvtGsmIra ( ussdBuf8Bit,
                         ussdLen8Bit,
                         ussdData->ssUserData.b_ssUserData,
                         MAX_USSD_DATA,
                         CSCS_DIR_GsmToIra ) )
    {
      return( FALSE );
    }

    ussdData->ssUserData.o_ssUserData = 0;
    ussdData->ssUserData.l_ssUserData = ssShrdPrm.ussdLen<<3;

    memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
    ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
    ccd_codeMsg (CCDENT_FAC, UPLINK,
                 (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
                 NOT_PRESENT_8BIT);

    ssShrdPrm.cmpType = CT_INV;

    /* skip SS version indicator */
    ssShrdPrm.stb[sId].SSver = NOT_PRESENT_8BIT;

    /* repeat USSD string */
    psaSS_NewTrns(sId);

    return( TRUE );
  }

  return( FALSE );
}


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_asmDeactivateCCBS |
+-------------------------------------------------------------------+

  PURPOSE : assemble the deactivate CCBS facility information
            element.

*/

GLOBAL void psaSS_asmDeactivateCCBS ( UBYTE idx )
{
  MCAST( ersCCBS, ERASE_CC_ENTRY_INV );

  TRACE_FUNCTION("psaSS_asmDeactivateCCBS");

  memset( ersCCBS, 0, sizeof( T_ERASE_CC_ENTRY_INV ));

  /* set service code */
  ersCCBS->v_eraseCCEntryArg = TRUE;
  ersCCBS->msg_type = ERASE_CC_ENTRY_INV;

  ersCCBS->eraseCCEntryArg.v_ssCode = TRUE;
  ersCCBS->eraseCCEntryArg.ssCode   = SS_CD_CCBS;

  if( idx NEQ KSD_IDX_NONE )
  {
    ersCCBS->eraseCCEntryArg.v_ccbsIndex = TRUE;
    ersCCBS->eraseCCEntryArg.ccbsIndex   = idx;
  }

  memset( &ssFIECodeBuf, 0, sizeof( ssFIECodeBuf ));
  ssFIECodeBuf.l_buf = MAX_FIE_CODE_BUF_LEN<<3;
  ccd_codeMsg (CCDENT_FAC, UPLINK,
               (T_MSGBUF *)&ssFIECodeBuf, _decodedMsg,
               NOT_PRESENT_8BIT);

  ssShrdPrm.cmpType = CT_INV;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_dasmInvokeCmp     |
+-------------------------------------------------------------------+

  PURPOSE : disassemble the result component.
*/

GLOBAL void psaSS_dasmInvokeCmp ( SHORT sId, T_inv_comp *invCmp )
{
  USHORT ivId;                /* holds invoke Id */
  UBYTE  opCode;              /* holds operation code */

  TRACE_FUNCTION("psaSS_dasmInvokeCmp");

  if( invCmp -> v_inv_id )
    ivId = invCmp -> inv_id;
  else
    ivId = NOT_PRESENT_16BIT;

  if( invCmp -> v_op_code )
    opCode = invCmp -> op_code;
  else
    opCode = NOT_PRESENT_8BIT;

  /* store op code and invoke id for result */
  ssShrdPrm.stb[sId].iId = (UBYTE)ivId;
  ssShrdPrm.stb[sId].opCode = opCode;

  if( invCmp -> params.l_params )
  {
    UBYTE ccdRet;

    memcpy( ssFIEDecodeBuf, &invCmp -> params, FACILITY_LEN );

    ccdRet = ccd_decodeMsg (CCDENT_FAC,
                            DOWNLINK,
                            (T_MSGBUF *) ssFIEDecodeBuf,
                            (UBYTE    *) _decodedMsg,
                            opCode);

    if( ccdRet NEQ ccdOK )
    {
      TRACE_EVENT_P1("CCD Decoding Error: %d",ccdRet );
      ssShrdPrm.stb[sId].failType = SSF_CCD_DEC;
      cmhSS_TransFail(sId);
    }
  }
  else
    memset( ssFIEDecodeBuf, 0, FACILITY_LEN );  /* put all valid flags to FALSE */

  switch( opCode )
  {
    case( OPC_GET_PASSWORD ):
      {
        MCAST( getPWD, GET_PWD_INV );

        cmhSS_getPassword( sId, getPWD );
      }
      break;

    case( OPC_UNSTRUCT_SS_NOTIFY ):
      {
        MCAST( ussdNtfy, USSD_NOTIFY_INV );

        cmhSS_USSDNotify( sId, ussdNtfy );
      }
      break;

    case( OPC_UNSTRUCT_SS_REQ ):
      {
        MCAST( ussdReq, USSD_REQ_INV );

        cmhSS_USSDRequest( sId, ussdReq );
      }
      break;

    case( OPC_FWD_CHECK_SS_IND ):
      {
        cmhSS_FwdChckSS( sId );
      }
      break;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_dasmResultCmp     |
+-------------------------------------------------------------------+

  PURPOSE : disassemble the result component.
*/

GLOBAL void psaSS_dasmResultCmp ( SHORT sId, T_res_comp *resCmp )
{
  UBYTE  opCode;              /* holds operation code */

  TRACE_FUNCTION("psaSS_dasmResultCmp");

  /* get operation code of the result */
  if( resCmp -> v_sequence         AND 
      resCmp -> sequence.v_op_code )
  {
    opCode = resCmp -> sequence.op_code;
  }
  else
    opCode = ssShrdPrm.stb[sId].opCode;

  /* decode additional parameters of result */
  if( resCmp -> v_sequence               AND 
      resCmp -> sequence.params.l_params )
  {
    UBYTE ccdRet;

    memcpy( ssFIEDecodeBuf, &resCmp -> sequence.params, FACILITY_LEN);

    ccdRet = ccd_decodeMsg (CCDENT_FAC,
                            DOWNLINK,
                            (T_MSGBUF *) ssFIEDecodeBuf,
                            (UBYTE    *) _decodedMsg,
                            opCode);

    if( ccdRet NEQ ccdOK )
    {
      CHAR buf[25];
      sprintf( buf, "CCD Decoding Error: %d",ccdRet );
      TRACE_EVENT( buf );
      cmhSS_SSResultFailure( sId );
      return;
    }
  }

  /* determine to which operation the result belongs to */
  switch( opCode )
  {
    case( OPC_REGISTER_SS ):
      {
        MCAST( regSS, REGISTER_SS_RES );

        cmhSS_SSRegistrated( sId, regSS );
      }
      break;

    case( OPC_ERASE_SS ):
      {
        MCAST( ersSS, ERASE_SS_RES );

        cmhSS_SSErased( sId, ersSS );
      }
      break;

    case( OPC_ACTIVATE_SS ):
      {
        MCAST( actSS, ACTIVATE_SS_RES );

        if( !(resCmp -> v_sequence) OR !(resCmp -> sequence.params.l_params) )
        {
          memset(actSS, 0, sizeof(T_ACTIVATE_SS_RES));
        }
        cmhSS_SSActivated( sId, actSS );
      }
      break;

    case( OPC_DEACTIVATE_SS ):
      {
        MCAST( deactSS, DEACTIVATE_SS_RES );

        cmhSS_SSDeactivated( sId, deactSS );
      }
      break;

    case( OPC_INTERROGATE_SS ):
      {
        MCAST( irgtSS, INTERROGATE_SS_RES );

        cmhSS_SSInterrogated( sId, irgtSS );
      }
      break;

    case( OPC_REGISTER_PASSWORD ):
      {
        MCAST( regPWD, REGISTER_PWD_RES );

        cmhSS_SSPWDRegistrated( sId, regPWD );
      }
      break;

    case( OPC_PROC_UNSTRUCT_SS_DATA ):
      {
        MCAST( prcUSSDDat, PROCESS_USSD_RES );

        cmhSS_USSDDatProcessed( sId, prcUSSDDat );
      }
      break;

    case( OPC_PROC_UNSTRUCT_SS_REQ ):
      {
        MCAST( prcUSSDReq, PROCESS_USSD_REQ_RES );

        cmhSS_USSDReqProcessed( sId, prcUSSDReq );
      }
      break;

    case( OPC_ERASE_CC_ENTRY ):
      {
        MCAST( ersCCNtry, ERASE_CC_ENTRY_RES );

        cmhSS_CCNtryErased( sId, ersCCNtry );
      }
      break;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_dasmErrorCmp      |
+-------------------------------------------------------------------+

  PURPOSE : disassemble the error component.
*/

GLOBAL T_ACI_RETURN psaSS_dasmErrorCmp ( SHORT sId, T_err_comp *errCmp, BOOL is_fac_ussd  )
{
  TRACE_EVENT_P1("psaSS_dasmErrorCmp: errCmp: %02x",errCmp -> err_code);

  if( errCmp -> v_err_code )
  {
    ssShrdPrm.stb[sId].failType = SSF_SS_ERR;
    ssShrdPrm.stb[sId].errCd    = errCmp -> err_code;

    
    switch(errCmp -> err_code)
    {
      case ERR_PWD_REG_FAIL:
        if( errCmp -> v_params AND errCmp -> params.l_params )
        {  
          T_PW_REGISTRATION_FAILURE_ERR *pwRegFail; 
            
          pwRegFail = (T_PW_REGISTRATION_FAILURE_ERR *)errCmp -> params.b_params;

          TRACE_EVENT_P1("VGK:Error reported %d", errCmp -> err_code);
          TRACE_EVENT_P1("VGK:Error params %d", pwRegFail->pwRegistrationFailureCause);

          if (pwRegFail->v_pwRegistrationFailureCause)
            ssShrdPrm.stb[sId].errPrms = pwRegFail->pwRegistrationFailureCause;
        }
        break;

      default:
        break;
    }

    /* check for protocol incompatibility for USSD */
    if( is_fac_ussd                                 AND
        errCmp -> err_code EQ ERR_FAC_NOT_SUPPORTED )
    {
      if( psaSS_asmUSSDProt1(sId) )
      {
        return( AT_CMPL );
      }
    }
    
  }
  return( AT_FAIL );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_dasmRejectCmp     |
+-------------------------------------------------------------------+

  PURPOSE : disassemble the error component.
*/

GLOBAL T_ACI_RETURN psaSS_dasmRejectCmp ( SHORT sId, T_rej_comp *rejCmp, BOOL is_fac_ussd  )
{
  TRACE_FUNCTION("psaSS_dasmRejectCmp");

  if( rejCmp -> v_gen_problem )
  {
    ssShrdPrm.stb[sId].failType = SSF_GEN_PRB;
    ssShrdPrm.stb[sId].rejPrb   = rejCmp -> gen_problem;
  }

  else if( rejCmp -> v_inv_problem )
  {
    ssShrdPrm.stb[sId].failType = SSF_INV_PRB;
    ssShrdPrm.stb[sId].rejPrb   = rejCmp -> inv_problem;

    /* check for protocol incompatibility for USSD */
    if( is_fac_ussd                                  AND
        rejCmp -> inv_problem EQ INV_PROB_UNRECOG_OP )
    {
      if( psaSS_asmUSSDProt1(sId) )
      {
        return( AT_CMPL );
      }
    }
  }

  else if( rejCmp -> v_res_problem )
  {
    ssShrdPrm.stb[sId].failType = SSF_RSL_PRB;
    ssShrdPrm.stb[sId].rejPrb   = rejCmp -> res_problem;
  }

  else if( rejCmp -> v_err_problem )
  {
    ssShrdPrm.stb[sId].failType = SSF_ERR_PRB;
    ssShrdPrm.stb[sId].rejPrb   = rejCmp -> err_problem;
  }
  return( AT_FAIL );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SATF                |
|                                 ROUTINE : psaSAT_ss_end_ind       |
+-------------------------------------------------------------------+

  PURPOSE : handles responses to user after a SS.
            is_fac_ussd TRUE if facility is a USSD
*/

GLOBAL T_ACI_RETURN psaSS_ss_end_ind ( SHORT sId, T_COMPONENT *com, BOOL is_fac_ussd )
{
  if( com->v_res_comp )
  {
    psaSS_dasmResultCmp( sId, &com->res_comp );
    return( AT_EXCT );
  }
  
  if( com->v_err_comp )
  {
    return(psaSS_dasmErrorCmp( sId, &com->err_comp, is_fac_ussd ));
  }

  if( com->v_rej_comp )
  {
    return(psaSS_dasmRejectCmp( sId, &com->rej_comp, is_fac_ussd ));
  }
  
  TRACE_EVENT( "WRONG COMPONENT TYPE RECEIVED" );
  return(AT_FAIL);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbNewEntry       |
+-------------------------------------------------------------------+

  PURPOSE : returns the service table index for a free entry to be
            used, otherwise the function returns -1 to indicate that
            no entry is free.
*/

GLOBAL SHORT psaSS_stbNewEntry ( void )
{
  SHORT stbIdx;             /* holds service table index */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    if( (ssShrdPrm.stb[stbIdx].ntryUsdFlg EQ FALSE) OR
        (ssShrdPrm.stb[stbIdx].srvStat    EQ SSS_IDL)    )
    {
      psaSS_InitStbNtry( stbIdx );

      return( stbIdx );
    }
  }

  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbFindTi         |
+-------------------------------------------------------------------+

  PURPOSE : returns the service table index for the entry that holds
            service parameters for the passed transaction identifier.
            Returning -1 indicates that the passed ti was not found.
*/

GLOBAL SHORT psaSS_stbFindTi ( UBYTE ti2Find )
{
  SHORT stbIdx;             /* holds service table index */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    if( ssShrdPrm.stb[stbIdx].ti EQ ti2Find )

      return( stbIdx );
  }

  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbFindInvId      |
+-------------------------------------------------------------------+

  PURPOSE : returns the service table index for the entry that holds
            service parameters for the passed invoke id.
            Returning -1 indicates that the passed ti was not found.
*/

GLOBAL SHORT psaSS_stbFindInvId ( UBYTE iId2Find )
{
  SHORT stbIdx;             /* holds service table index */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    if( ssShrdPrm.stb[stbIdx].ntryUsdFlg EQ TRUE AND
        ssShrdPrm.stb[stbIdx].iId        EQ iId2Find )

      return( stbIdx );
  }

  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_chgSrvTypCnt      |
+-------------------------------------------------------------------+

  PURPOSE : this function modifies the service type counter (MOS/MTS)
            defined by the passed service id by the passed delta value.
*/

GLOBAL void psaSS_chngSrvTypCnt ( SHORT sId, SHORT dlt )
{

  switch( ssShrdPrm.stb[sId].srvType )
  {
    case( ST_MOS ):

      ssShrdPrm.nrOfMOS += dlt;

      if( ssShrdPrm.nrOfMOS < 0 ) ssShrdPrm.nrOfMOS = 0;

      break;

    case( ST_MTS ):

      ssShrdPrm.nrOfMTS += dlt;

      if( ssShrdPrm.nrOfMTS < 0 ) ssShrdPrm.nrOfMTS = 0;

      break;

    default:

      TRACE_EVENT( "UNEXP SERVICE TYPE IN STB" );
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_getMOSTi          |
+-------------------------------------------------------------------+

  PURPOSE : this function selects a ti out of a pool of valid ti's
            and inserts it into the passed service table entry. if no
            ti is available the function returns -1.
            a bit of the pool stands for a valid ti.
            0 indicates a used ti, 1 indicates a free ti.
*/

GLOBAL SHORT psaSS_getMOSTi( SHORT sId )
{
  UBYTE idx;               /* holds pool idx */

  for( idx = 0; idx < MAX_MOSTI_NR; idx++ )
  {
    if( tiPool & (1u << idx) )
    {
      tiPool &= ~(1u << idx);
      ssShrdPrm.stb[sId].ti = idx;
      return( 0 );
    }
  }
  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_retMOSTi          |
+-------------------------------------------------------------------+

  PURPOSE : this function returns a used ti to the ti pool if the
            call was a MOS. the ti is free for the next MOS
            afterwards.
            a bit of the pool stands for a valid ti.
            0 indicates a used ti, 1 indicates a free ti.
*/

GLOBAL void psaSS_retMOSTi( SHORT sId )
{
  if( ssShrdPrm.stb[sId].srvType EQ ST_MOS )

    if( ssShrdPrm.stb[sId].ti < MAX_MOSTI_NR )

      tiPool |= (0x01 << ssShrdPrm.stb[sId].ti);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SS                  |
|                                 ROUTINE : psaSS_InitStbNtry       |
+-------------------------------------------------------------------+

  PURPOSE : initialize the indexed service table entry.

*/

GLOBAL void psaSS_InitStbNtry ( SHORT idx )
{

/*
 *-------------------------------------------------------------------
 * initialize call table entry
 *-------------------------------------------------------------------
 */
  ssShrdPrm.stb[idx].ntryUsdFlg   = FALSE;
  ssShrdPrm.stb[idx].ti           = NO_ENTRY;
  ssShrdPrm.stb[idx].iId          = 0;
  ssShrdPrm.stb[idx].srvStat      = NO_VLD_SSS;
  ssShrdPrm.stb[idx].srvType      = NO_VLD_ST;
  ssShrdPrm.stb[idx].orgOPC       = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].opCode       = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].ssCode       = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].ussdReqFlg   = FALSE;
  ssShrdPrm.stb[idx].failType     = NO_VLD_SSF;
  ssShrdPrm.stb[idx].entCs        = NOT_PRESENT_16BIT;
  ssShrdPrm.stb[idx].rejPrb       = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].errCd        = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].errPrms      = NOT_PRESENT_8BIT;
  ssShrdPrm.stb[idx].curCmd       = AT_CMD_NONE;
  ssShrdPrm.stb[idx].srvOwn       = OWN_NONE;
  ssShrdPrm.stb[idx].SSver        = DEF_SS_VER;
  ssShrdPrm.stb[idx].ussd_operation = FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbFindUssdReq    |
+-------------------------------------------------------------------+

  PURPOSE : returns the service table index for the entry that has a
            USSD request pending.
            Returning -1 indicates that no such service was found.
*/

GLOBAL SHORT psaSS_stbFindUssdReq ( void )
{
  SHORT stbIdx;             /* holds call table index */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    if( ssShrdPrm.stb[stbIdx].ntryUsdFlg EQ TRUE    AND
        ssShrdPrm.stb[stbIdx].ussdReqFlg EQ TRUE    AND
        ssShrdPrm.stb[stbIdx].srvStat    EQ SSS_ACT )
    {
          return( stbIdx );
    }
  }

  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbFindActSrv     |
+-------------------------------------------------------------------+

  PURPOSE : returns the service table index for the first entry that
            holds an active service which is not the passed index.
            Returning -1 indicates that no active service was found.
*/

GLOBAL SHORT psaSS_stbFindActSrv ( SHORT sId )
{
  SHORT stbIdx;             /* holds call table index */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    if( ssShrdPrm.stb[stbIdx].ntryUsdFlg EQ TRUE    AND
        ssShrdPrm.stb[stbIdx].srvStat    EQ SSS_ACT )
    {
      if( stbIdx NEQ sId )

        return( stbIdx );
    }
  }

  return( -1 );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SS                  |
|                                 ROUTINE : psaSS_Init              |
+-------------------------------------------------------------------+

  PURPOSE : initialize the protocol stack adapter for SS.

*/

GLOBAL void psaSS_Init ( void )
{
  UBYTE stbIdx;            /* holds index to service table */

/*
 *-------------------------------------------------------------------
 * initialize service table
 *-------------------------------------------------------------------
 */
  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx++ )
  {
    psaSS_InitStbNtry( stbIdx );
  }

 /*
  *-------------------------------------------------------------------
  * initialize shared parameter
  *-------------------------------------------------------------------
  */
  ssShrdPrm.nrOfMOS = 0;
  ssShrdPrm.nrOfMTS = 0;
  ssShrdPrm.iIdNxt  = 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SS                  |
|                                 ROUTINE : psaSS_DumpFIE           |
+-------------------------------------------------------------------+

  PURPOSE : Dump facility information element to debug output.

*/

GLOBAL void psaSS_DumpFIE ( T_fac_inf * fie )
{

  CHAR  strBuf[40+1];           /* holds string buffer */
  UBYTE idx, cnt, mcnt;         /* buffer index */
  CHAR  *pDest;                 /* points to destination */

/*
 *-------------------------------------------------------------------
 * format FIE
 *-------------------------------------------------------------------
 */
  TRACE_EVENT( "FIE SENT/RECEIVED:" );

  mcnt = fie->l_fac >> 3;

  if( mcnt EQ 0 )
  {
    TRACE_EVENT("Empty Facility");
    return;
  }

  for( cnt = 0; cnt < mcnt; cnt+=idx )
  {
    pDest = strBuf;

    for( idx = 0; idx < 20 AND idx+cnt < mcnt; idx++ )
    {
      pDest += sprintf( pDest, "%02X", (UBYTE)fie->fac[idx+cnt] );
    }

    *pDest = 0x0;

    TRACE_EVENT( strBuf );
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_stbDump           |
+-------------------------------------------------------------------+

  PURPOSE : this function dumps the service table to the debug output.
*/

GLOBAL void psaSS_stbDump ( void )
{
#ifdef TRACING

  SHORT stbIdx;                             /* holds service table index */
  char  lnBuf[HDR_WDT+(MAX_ITM*ITM_WDT)+1]; /* holds buffer for output line */
  char  verBuf[VERSION_LEN+1];              /* holds buffer for SS version */
  SHORT itmIdx;                             /* holds items per line index */
  SHORT chrNr;                              /* holds number of processed chars */

  for( stbIdx = 0; stbIdx < MAX_SS_NR; stbIdx+=MAX_ITM )
  {
    /* --- service id ----------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "   srv id");

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx+stbIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT, stbIdx + itmIdx );
    }
    TRACE_EVENT( lnBuf );

    /* --- entry used flag -----------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "entry used" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].ntryUsdFlg );
    }
    TRACE_EVENT( lnBuf );

    /* --- transaction identifier ----------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "        ti" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].ti );
    }
    TRACE_EVENT( lnBuf );

    /* --- service status ------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "srv status" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].srvStat );
    }
    TRACE_EVENT( lnBuf );

    /* --- service type --------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "  srv type" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].srvType );
    }
    TRACE_EVENT( lnBuf );

    /* --- SS version ----------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "SS version" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].SSver );
    }
    TRACE_EVENT( lnBuf );

    /* --- failure type ------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "fail. type" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].failType );
    }
    TRACE_EVENT( lnBuf );

    /* --- entity cause ------------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "ent. cause" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].entCs );
    }
    TRACE_EVENT( lnBuf );

    /* --- reject problem ----------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, " rej. prob" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].rejPrb );
    }
    TRACE_EVENT( lnBuf );

    /* --- error code ----------------------------------------------------*/
    chrNr = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, " err. code" );

    for( itmIdx = 0; (itmIdx<MAX_ITM)AND(itmIdx<MAX_SS_NR); itmIdx++ )
    {
      chrNr += sprintf( lnBuf+chrNr, "%*hd", ITM_WDT,
                        ssShrdPrm.stb[stbIdx+itmIdx].errCd );
    }
    TRACE_EVENT( lnBuf );

  }

#endif  /* of #ifdef TRACING */
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_SSF                 |
|                                 ROUTINE : psaSS_shrPrmDump        |
+-------------------------------------------------------------------+

  PURPOSE : this function dumps the shared parameter to the debug
            output.
*/

GLOBAL void psaSS_shrPrmDump ( void )
{
#ifdef TRACING

  char  lnBuf[80];              /* holds buffer for output line */
  SHORT chrNr;                  /* holds number of processed chars */

  /* --- nr of MOSs -----------------------------------------------*/
  chrNr  = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "nr. of MOS" );
  chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT,
                                        ssShrdPrm.nrOfMOS );
  TRACE_EVENT( lnBuf );

  /* --- nr of MTSs -----------------------------------------------*/
  chrNr  = sprintf( lnBuf, "%*.*s", HDR_WDT, HDR_WDT, "nr. of MTS" );
  chrNr += sprintf( lnBuf+chrNr, "%*d", ITM_WDT,
                                        ssShrdPrm.nrOfMTS );
  TRACE_EVENT( lnBuf );

#endif  /* of #ifdef TRACING */
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_F                   |
|                                 ROUTINE : psaSS_GetPendingTrn     |
+-------------------------------------------------------------------+

  PURPOSE : Find Id of a pending call for multy-transaction operation

*/

GLOBAL SHORT psaSS_GetPendingTrn ( void )
{
  SHORT bit_len;
  SHORT i;

  bit_len = 8 * sizeof(ssShrdPrm.mltyTrnFlg);
  for (i = 0; i < bit_len; i++)
  {
    if ( ssShrdPrm.mltyTrnFlg & ( 0x1 << i ) )
      return i;
  }

  return -1;
}

GLOBAL void psaSS_KillAllPendingTrn ( void ) /* sId: main transaction: not to be killed */
{
  SHORT          pending_idx;

  TRACE_FUNCTION("psaSS_KillAllPendingTrn( )");

  while ( ssShrdPrm.mltyTrnFlg )
  {
    pending_idx = psaSS_GetPendingTrn( );
    ssShrdPrm.mltyTrnFlg &= ~( 1u << pending_idx );  /* unsent id flag */

    ssShrdPrm.stb[ pending_idx ].ntryUsdFlg = FALSE;  /* free entry in ss table */
    ssShrdPrm.stb[ pending_idx ].srvStat = NO_VLD_SSS; /* not sure if it's necessary...? */

    PFREE( ssShrdPrm.stb[pending_idx].save_prim ); /* free pending primitive */
  }
}

/*==== EOF ========================================================*/

