/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-PS (6147)
|  Modul   :  PSA_CCS
+----------------------------------------------------------------------------- 
|  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 signalling functions of the 
|             protocol stack adapter for call control.
+----------------------------------------------------------------------------- 
*/ 

#ifndef PSA_CCS_C
#define PSA_CCS_C
#endif

#include "aci_all.h"

/*==== INCLUDES ===================================================*/
#include "ccdapi.h"

#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"
#include "aci.h"
#include "psa.h"
#include "psa_cc.h"
#include "psa_ss.h"
#include "aoc.h"
#include "l4_tim.h"

#if !defined (MFW)
#include "aci_io.h"
#endif

#include "aci_fd.h"
#include "cmh.h"

#include "cmh_cc.h"
#include "psa_cc.h"

#include "wap_aci.h"

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

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

/*==== IMPORT =====================================================*/

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

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


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : PSA_CCS                      |
|                            ROUTINE : psaCC_NewCall                |
+-------------------------------------------------------------------+

  PURPOSE : setup a new call

*/

GLOBAL SHORT psaCC_NewCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_NewCall()");

  if (pCtbNtry EQ NULL)
    return -1;

  /* get a valid ti for a MOC, otherwise return */
  if (psaCC_ctb(cId)->calType NEQ CT_NI_MOC )
  {
    if( psaCC_getMOCTi( cId ) < 0 ) return ( -1 );
  }

#if defined (FF_WAP) || defined (FF_GPF_TCPIP) || defined (FF_SAT_E)
  /* if this call is a WAP call then set wapId to the current Call Id */
  if (Wap_Call EQ TRUE)
  {
    wapId = cId;
  }
#endif /* defined(WAP) OR defined(FF_GPF_TCPIP) */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_setup_req, MNCC_SETUP_REQ);

    /*
     * fill in primitive parameter: setup request
     */
    mncc_setup_req -> ti               = pCtbNtry -> ti;
    mncc_setup_req -> prio             = pCtbNtry -> prio;
    mncc_setup_req -> ri               = pCtbNtry -> rptInd;

    mncc_setup_req->called_party.ton          = pCtbNtry->cldPty.ton;
    mncc_setup_req->called_party.npi          = pCtbNtry->cldPty.npi;
    mncc_setup_req->called_party.c_called_num = pCtbNtry->cldPty.c_called_num;
    memcpy (mncc_setup_req->called_party.called_num, 
            pCtbNtry->cldPty.called_num,
            pCtbNtry->cldPty.c_called_num);

    mncc_setup_req -> called_party_sub = pCtbNtry -> cldPtySub;
    mncc_setup_req -> clir_sup         = pCtbNtry -> CLIRsup;
    memcpy( &(mncc_setup_req->bcpara),&(pCtbNtry->BC[0]), 
          sizeof( T_bcpara) ); 
    memcpy( &(mncc_setup_req->bcpara2),&(pCtbNtry->BC[1]), 
          sizeof( T_bcpara) ); 

    /*
     * fill in CUG info facility
     */
    if( !(pCtbNtry -> CUGidx EQ NOT_PRESENT_8BIT AND
          pCtbNtry -> CUGprf EQ FALSE AND
          pCtbNtry -> OAsup  EQ FALSE    ))
    {
      CCD_START;
      psaCC_asmCUGInfo( cId );

      {
        UBYTE ccdRet;

        MCAST( com, COMPONENT );

        memset( com, 0, sizeof( T_COMPONENT ));

        com -> v_inv_comp = TRUE;
        com -> inv_comp.v_inv_id  = TRUE;
        com -> inv_comp.inv_id    = pCtbNtry -> iId 
                                  = ccShrdPrm.iIdNxt++;
        com -> inv_comp.v_op_code = TRUE;
        com -> inv_comp.op_code   = pCtbNtry -> opCode
                                  = ssFIECodeBuf.buf[0];
        com -> inv_comp.v_params  = TRUE;
        com -> inv_comp.params.l_params = ssFIECodeBuf.l_buf-8;
        com -> inv_comp.params.o_params = 8;
        memcpy( com -> inv_comp.params.b_params, 
                ssFIECodeBuf.buf, ssFIECodeBuf.l_buf );

        mncc_setup_req -> fac_inf.l_fac = FACILITY_LEN<<3;
        mncc_setup_req -> fac_inf.o_fac = 0;
        ccdRet = ccd_codeMsg (CCDENT_FAC,
                              UPLINK,
                              (T_MSGBUF *) &mncc_setup_req -> fac_inf,
                              (UBYTE    *) _decodedMsg,
                              COMPONENT);

        if( ccdRet NEQ ccdOK )
        {
          TRACE_EVENT_P1("CCD Coding Error: %d",ccdRet ); 
          memset( &mncc_setup_req -> fac_inf, 0, sizeof( T_fac_inf));
        }
      }
      CCD_END;
    }
    else
    {
      memset( &mncc_setup_req -> fac_inf, 0, sizeof( T_fac_inf));
    }

    if(pCtbNtry -> calType NEQ CT_MOC_RDL)
    {
      pCtbNtry -> calType = CT_MOC;
    }
    pCtbNtry -> curBC   = 0;

    PSENDX (CC, mncc_setup_req);

    /*
     * update call status
     */
    pCtbNtry -> calStat = CS_ACT_REQ;
  }
#ifdef FF_TTY
  /* TTY notification */
  cmhCC_notifyTTY (((pCtbNtry->BC[0].bearer_serv EQ BEARER_SERV_SPEECH_CTM OR
                     pCtbNtry->BC[0].bearer_serv EQ BEARER_SERV_AUX_SPEECH_CTM)?
                    CTTY_NEG_Request: CTTY_NEG_None),
                   CTTY_TRX_Unknown);
#endif /* FF_TTY */
  if(cmhCC_atdsendok ( cId ))
  {
    R_AT( RAT_OK, pCtbNtry->curSrc ) ( pCtbNtry->curCmd );
  }

  /* start call time measurement */
  aoc_info (cId, AOC_START_TIME);

  /* Disable voice path in case this is first call */
  psaCC_setSpeechMode ();

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_AcceptCall        |
+-------------------------------------------------------------------+
  PURPOSE : In addition to sending the setup response for an MT call
            this function enables the vocoder if the call is a voice
            call
*/

GLOBAL void psaCC_AcceptCall ( SHORT cId )
{
  T_CC_CALL_TBL * pCtbNtry;     /* holds pointer to call table entry */

  TRACE_FUNCTION ("psaCC_AcceptCall()");

  /* update call status and attach the user if not done previously */
  pCtbNtry = ccShrdPrm.ctb[cId];
  pCtbNtry -> calStat = CS_CPL_REQ;
  psaCC_setSpeechMode();
  
  /* create and send primitive */
  {
    PALLOC (mncc_setup_res, MNCC_SETUP_RES);
    mncc_setup_res -> ti = pCtbNtry -> ti;
    PSENDX (CC, mncc_setup_res);
    psaCC_send_satevent( EVENT_CALL_CONN, cId, NEAR_END, FALSE );
  }

  /* start call time measurement */
  aoc_info (cId, AOC_START_TIME);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ClearCall         |
+-------------------------------------------------------------------+

  PURPOSE : clear a call
*/

GLOBAL void psaCC_ClearCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_ClearCall()");

  if (!psaCC_ctbIsValid (cId))
    return; /* Ensure we are not dereferencing NULL */

  psaCC_StopDTMF ( cId );

  /* inform advice of charge module */
  aoc_info (cId, AOC_STOP_TIME);

  /*
   *-----------------------------------------------------------------
   * relase call if in disconnect request state
   *-----------------------------------------------------------------
   */
  if( pCtbNtry -> calStat EQ CS_DSC_REQ )
  {
    PALLOC (mncc_release_req, MNCC_RELEASE_REQ);

    /* fill in primitive parameter: release request */
    mncc_release_req -> ti    = pCtbNtry -> ti;
    mncc_release_req -> cause = pCtbNtry -> nrmCs;
      
    /* fill in CCBS request facility */
    if( pCtbNtry -> CCBSstat EQ CCBSS_REQ )
    {
      CCD_START;
      {
        psaCC_asmCCBSReq( cId );
        psaCC_asmComponent( cId );
      }
      CCD_END;
      
      mncc_release_req -> fac_inf.l_fac = ssFIECodeBuf.l_buf;
      mncc_release_req -> fac_inf.o_fac = 0;
      memcpy (mncc_release_req->fac_inf.fac, 
              ssFIECodeBuf.buf + (ssFIECodeBuf.o_buf >> 3),
              ssFIECodeBuf.l_buf >> 3);

      mncc_release_req -> ss_version = SS_VERSION_3;
    }
    else
    {
      memset( &mncc_release_req -> fac_inf, 0, sizeof( T_fac_inf));
      mncc_release_req -> ss_version = SS_VER_NOT_PRES;
    }

    PSENDX (CC, mncc_release_req);

    psaCC_send_satevent( EVENT_CALL_DISC, cId, NEAR_END, TRUE );
  }

  /*
   *-----------------------------------------------------------------
   * relase call if in activate request state, network initiated
   *-----------------------------------------------------------------
   */
  else if( pCtbNtry -> calStat EQ CS_ACT_REQ AND
           pCtbNtry -> calType EQ CT_NI_MOC      )
  {
    PALLOC (mncc_reject_req, MNCC_REJECT_REQ);

    /* fill in primitive parameter: release request */
    mncc_reject_req -> ti    = pCtbNtry -> ti;
    mncc_reject_req -> cause = pCtbNtry -> nrmCs;

    PSENDX (CC, mncc_reject_req);

    /* free call table entry */
    psaCC_retMOCTi( pCtbNtry -> ti );

    psaCC_FreeCtbNtry (cId);
  }
      
  /*
   *-----------------------------------------------------------------
   * disconnect all other calls
   *-----------------------------------------------------------------
   */
  else
  {
    PALLOC (disc_req, MNCC_DISCONNECT_REQ); /* T_MNCC_DISCONNECT_REQ */
    disc_req -> ti    = pCtbNtry -> ti;
    disc_req -> cause = pCtbNtry -> nrmCs;
    if (pCtbNtry -> curCmd EQ AT_CMD_CTFR)
    {
      /* We expect here an already built facility in ssFIECodeBuf */
      disc_req -> fac_inf.l_fac = ssFIECodeBuf.l_buf;
      disc_req -> fac_inf.o_fac = 0;
      memcpy (disc_req->fac_inf.fac, 
              ssFIECodeBuf.buf, 
              ssFIECodeBuf.l_buf >> 3);
      disc_req -> ss_version = SS_VERSION_2;
    }
    else
    {
      disc_req -> fac_inf.l_fac = 0;
      disc_req -> ss_version    = SS_VER_NOT_PRES;
    }
    PSENDX (CC, disc_req);

    /* update call status */
    pCtbNtry -> calStat = CS_DSC_REQ;

    /* monitoring for SAT */
    psaCC_send_satevent( EVENT_CALL_DISC, cId , NEAR_END, TRUE );
  }

  /* Switch off audio path after user action (e.g. hangup) */
/* clb this breaks ACI056 (among others..) necessary ??  pCtbNtry -> inBndTns = FALSE; */
  psaCC_setSpeechMode ();
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_HoldCall          |
+-------------------------------------------------------------------+

  PURPOSE : put a call into hold state

*/

GLOBAL void psaCC_HoldCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_HoldCall()");

  if (pCtbNtry EQ NULL)
    return; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  psaCC_StopDTMF ( cId );

  {
    PALLOC (mncc_hold_req, MNCC_HOLD_REQ);

    /*
     * fill in primitive parameter: hold request
     */

    mncc_hold_req -> ti = pCtbNtry -> ti;
      
    PSENDX (CC, mncc_hold_req);

    /* update call status */
    pCtbNtry -> calStat = CS_HLD_REQ;

  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_RetrieveCall      |
+-------------------------------------------------------------------+

  PURPOSE : retrieve a held call

*/

GLOBAL void psaCC_RetrieveCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_RetrieveCall()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_retrieve_req, MNCC_RETRIEVE_REQ);

    /*
     * fill in primitive parameter: retrieve request
     */

    mncc_retrieve_req -> ti = pCtbNtry -> ti;
      
    PSENDX (CC, mncc_retrieve_req);

    /*
     * update call status   ???
     */
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ModifyCall        |
+-------------------------------------------------------------------+

  PURPOSE : modify an active call 

*/

GLOBAL SHORT psaCC_ModifyCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];
  UBYTE nomBC;                  /* holds nominal bearer capabilities */

  TRACE_FUNCTION ("psaCC_ModifyCall()");

  if (pCtbNtry EQ NULL)
    return -1;

/*
 *-------------------------------------------------------------------
 * check if call is in a active state
 *-------------------------------------------------------------------
 */
 if(
     (pCtbNtry -> calStat NEQ CS_ACT)     AND
     (pCtbNtry -> calStat NEQ CS_ACT_REQ)
   )
   return( -1 );
/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  psaCC_StopDTMF ( cId );
  {
    PALLOC (mncc_modify_req, MNCC_MODIFY_REQ);

    /*
     * fill in primitive parameter: modify request
     */
    nomBC = (pCtbNtry -> curBC)?0:1;

    switch( pCtbNtry -> BC[nomBC].bearer_serv )
    {
    case( BEARER_SERV_AUX_SPEECH    ):
    case( BEARER_SERV_SPEECH        ):
    case( BEARER_SERV_AUX_SPEECH_CTM):
    case( BEARER_SERV_SPEECH_CTM    ):
      mncc_modify_req -> serv = SERV_SPEECH;
      break;

    case( BEARER_SERV_FAX           ):
    case( BEARER_SERV_ASYNC         ):
    case( BEARER_SERV_SYNC          ):
    case( BEARER_SERV_PAD_ACCESS    ):
    case( BEARER_SERV_PACKET_ACCESS ):
      mncc_modify_req -> serv = SERV_DATA;

      /* check for TTY service */
      cmhCC_TTY_Control ( cId, TTY_PAUSE );
      break;

    default:
      mncc_modify_req -> serv = SERV_NOT_PRES;
    }
    mncc_modify_req ->   ti = pCtbNtry -> ti;

    PSENDX (CC, mncc_modify_req);

    /*
     * update call status
     */
    pCtbNtry -> calStat = CS_MDF_REQ;
  }
  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SendDTMF          |
+-------------------------------------------------------------------+

  PURPOSE : send DTMF tones

*/

GLOBAL SHORT psaCC_SendDTMF ( SHORT cId,
                              UBYTE digit,
                              UBYTE mode )
{

  TRACE_FUNCTION ("psaCC_SendDTMF()");

  if (ccShrdPrm.ctb[cId] EQ NULL)
    return -1; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_start_dtmf_req, MNCC_START_DTMF_REQ);

    /*
     * fill in primitive parameter: DTMF tone request
     */

    mncc_start_dtmf_req -> ti       = psaCC_ctb(cId)->ti;
    mncc_start_dtmf_req -> key      = digit;
    mncc_start_dtmf_req -> dtmf_mod = mode;
      
    PSENDX (CC, mncc_start_dtmf_req);
  }

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_Config            |
+-------------------------------------------------------------------+
  PURPOSE : configure CC entity
*/

GLOBAL void psaCC_Config ( void )
{
  T_bcpara *mtcBC;

  TRACE_FUNCTION ("psaCC_Config()");

  /* create and send primitive */
  {
    PALLOC (mncc_configure_req, MNCC_CONFIGURE_REQ);

    /* fill in primitive parameter: configure request */
    memset(&(mncc_configure_req -> called_party_sub), 0,
            sizeof(T_called_party_sub));

    /* MTC bearer caps */
    mtcBC = &mncc_configure_req -> bcpara;
    mtcBC->rate = cmhCC_SelRate( ccShrdPrm.CBSTspeed );

    if( ccShrdPrm.snsMode EQ CSNS_MOD_Fax      OR
        ccShrdPrm.snsMode EQ CSNS_MOD_VAFVoice OR
        ccShrdPrm.snsMode EQ CSNS_MOD_VAFFax )
    {
      mtcBC->bearer_serv = BEARER_SERV_FAX;
      mtcBC->modem_type  = MT_NONE;
      mtcBC->conn_elem   = CONN_ELEM_TRANS;
    }
    else
    {
      mtcBC->bearer_serv = cmhCC_SelServ( ccShrdPrm.CBSTname );
      mtcBC->modem_type  = cmhCC_SelMT  ( ccShrdPrm.CBSTspeed );
      mtcBC->conn_elem   = cmhCC_SelCE  ( ccShrdPrm.CBSTce );
    }

    /* not sure whether this is taken into account by CC */
    mtcBC->stop_bits   = DEF_BC1_SB; /*cmhCC_SelStopBit( srcId );*/
    mtcBC->data_bits   = DEF_BC1_DB; /*cmhCC_SelDataBit( srcId );*/
    mtcBC->parity      = DEF_BC1_PR; /*cmhCC_SelParity ( srcId );*/
    mtcBC->flow_control = DEF_BC1_FC;
    /*****************************************************/

/*    mncc_configure_req -> bcpara   = *mtcBC; superfluous */
    mncc_configure_req -> sns_mode = ccShrdPrm.snsMode;
#ifdef FF_TTY
    mncc_configure_req -> ctm_ena = ccShrdPrm.ctmReq;
#else
    mncc_configure_req -> ctm_ena = CTM_DISABLED;
#endif /* FF_TTY */
    PSENDX (CC, mncc_configure_req);
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SendSS            |
+-------------------------------------------------------------------+

  PURPOSE : send SS facility

*/

LOCAL SHORT psaCC_SendSS ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];
  UBYTE           ccdRet;       /* holds CCD return value */

  TRACE_FUNCTION ("psaCC_SendSS()");

  if (pCtbNtry EQ NULL)
    return -1; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_facility_req, MNCC_FACILITY_REQ);

    /*
     * fill in primitive parameter: facility request
     */

    mncc_facility_req -> ti          = pCtbNtry -> ti;
    mncc_facility_req -> ss_version  = pCtbNtry -> SSver;

    CCD_START;
    {
      MCAST( com, COMPONENT );

      memset( com, 0, sizeof( T_COMPONENT ));
      switch( ccShrdPrm.cmpType )
      {
        case( CT_INV ):
          com -> v_inv_comp = TRUE;
          com -> inv_comp.v_inv_id  = TRUE;
          com -> inv_comp.inv_id    = pCtbNtry -> iId 
                                    = ccShrdPrm.iIdNxt++;
          com -> inv_comp.v_op_code = TRUE;
          com -> inv_comp.op_code   = pCtbNtry -> opCode
                                    = ssFIECodeBuf.buf[0];
          com -> inv_comp.v_params  = TRUE;
          com -> inv_comp.params.l_params = ssFIECodeBuf.l_buf-8;
          com -> inv_comp.params.o_params = 8;
          memcpy( com -> inv_comp.params.b_params, 
                  ssFIECodeBuf.buf, ssFIECodeBuf.l_buf );
          break;
        case( CT_RET_RSLT ):
          break;
        case( CT_RET_ERR ):
          break;
        case( CT_RET_REJ ):
          break;
      }
      mncc_facility_req -> fac_inf.l_fac = FACILITY_LEN<<3;
      mncc_facility_req -> fac_inf.o_fac = 0;
      ccdRet = ccd_codeMsg (CCDENT_FAC,
                            UPLINK,
                            (T_MSGBUF *) &mncc_facility_req -> fac_inf,
                            (UBYTE    *) _decodedMsg,
                            COMPONENT);

      if( ccdRet NEQ ccdOK )
      {
        TRACE_EVENT_P1( "CCD Coding Error: %d",ccdRet ); 
        PFREE( mncc_facility_req );
        CCD_END;
        return( -1 );
      }
    }
    CCD_END;

    pCtbNtry -> srvType = ST_MOS;

    psaCC_DumpFIE ( &mncc_facility_req -> fac_inf );
    cmhCC_sendFie ( CSCN_FACILITY_DIRECTION_OUT,
                    cId,
                    &mncc_facility_req -> fac_inf );
    
    PSENDX (CC, mncc_facility_req);
  }

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BuildMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : build multiparty

*/

GLOBAL void psaCC_BuildMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_BuildMPTY()");

/*
 *-------------------------------------------------------------------
 * set multiparty status for held calls
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat EQ CS_HLD )
    {
      if( psaCC_ctb(ctbIdx)->mptyStat NEQ CS_ACT )
      
        psaCC_ctb(ctbIdx)->mptyStat = CS_ACT_REQ;
    }
  }

  /* set multiparty status for active call */
  if( psaCC_ctb(cId)->mptyStat NEQ CS_ACT )
    psaCC_ctb(cId)->mptyStat = CS_ACT_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmBuildMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }
    
  psaCC_MPTY (cId, MPTY_BUILD_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_HoldMPTY          |
+-------------------------------------------------------------------+

  PURPOSE : hold multiparty

*/

GLOBAL void psaCC_HoldMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_HoldMPTY()");

/*
 *-------------------------------------------------------------------
 * set call status for multiparty members
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat  EQ CS_ACT AND 
        psaCC_ctb(ctbIdx)->mptyStat EQ CS_ACT)
    {
      psaCC_ctb(ctbIdx)->calStat = CS_HLD_REQ;
    }
  }

  /* set multiparty status for active call */
  psaCC_ctb(cId)->calStat = CS_HLD_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmHoldMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_HOLD_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_RetrieveMPTY      |
+-------------------------------------------------------------------+

  PURPOSE : retrieve multiparty

*/

GLOBAL void psaCC_RetrieveMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_RetrieveMPTY()");

/*
 *-------------------------------------------------------------------
 * set call status for multiparty members
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat  EQ CS_HLD AND 
        psaCC_ctb(ctbIdx)->mptyStat EQ CS_ACT)
    {
      psaCC_ctb(ctbIdx)->calStat = CS_ACT_REQ;
    }
  }

  /* set multiparty status for active call */
  psaCC_ctb(cId)->calStat = CS_ACT_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmRetrieveMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_RETRIEVE_SENT);

  return;
}



/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_CountMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : counts the number of parties in a MPTY

*/

GLOBAL int psaCC_CountMPTY ( void )
{
  int i = 0;
  SHORT cId;
  TRACE_FUNCTION ("psaCC_CountMPTY()");
  
  for( cId = 0; cId < MAX_CALL_NR; cId++ )
  {
    if (ccShrdPrm.ctb[cId] NEQ NULL AND
        psaCC_ctb(cId)->mptyStat EQ CS_ACT)
    {
      i++;
    }
  }
  return i;
}



/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SplitMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : split multiparty

*/

GLOBAL void psaCC_SplitMPTY ( SHORT cId )
{
  TRACE_FUNCTION ("psaCC_SplitMPTY()");

  /* set multiparty status for active call */
  psaCC_ctb(cId)->mptyStat = CS_DSC_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmSplitMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_SPLIT_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ECT               |
+-------------------------------------------------------------------+

  PURPOSE : explicit call transfer

*/

GLOBAL SHORT psaCC_ECT ( SHORT cId )
{
  SHORT psa_ret;
  
  TRACE_FUNCTION ("psaCC_ECT()");

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmECT();

  psa_ret = psaCC_SendSS(cId);
    
  if( psa_ret EQ 0 )
  {
    TIMERSTART( TECT_VALUE, ACI_TECT );
  }
 
  return(psa_ret);
}

#if 0 /* HM 3-May-2005: This function is not used, but it's still planned for some day */
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BCapCode          |
+-------------------------------------------------------------------+

  PURPOSE : code bearer capabilites according GSM 04.08

*/

GLOBAL SHORT psaCC_BCapCode ( UBYTE reqId, SHORT cId, UBYTE bc )
{
  TRACE_FUNCTION ("psaCC_BCapCode()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_bearer_cap_req, MNCC_BEARER_CAP_REQ);

    /*
     * fill in primitive parameter: bearer capability coding request
     */
    mncc_bearer_cap_req -> req_id = reqId;
    mncc_bearer_cap_req -> bc_mod = BC_MOD_CODE;
    mncc_bearer_cap_req -> bcpara = psaCC_ctb(cId)->BC[bc];

    PSENDX (CC, mncc_bearer_cap_req);
  }

  return 0;
}
#endif /* #if 0 */

#if 0 /* HM 3-May-2005: This function is not used, but it's still planned for some day */
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BCapDecode        |
+-------------------------------------------------------------------+

  PURPOSE : decode bearer cpabilities according GSM 04.08 into struct
            bcpara.

*/

GLOBAL SHORT psaCC_BCapDecode ( UBYTE reqId, UBYTE bcLen, UBYTE *bc )
{
  TRACE_FUNCTION ("psaCC_BCapDecode()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  if( bcLen > MAX_BC_LEN ) return -1;

  {
    PALLOC (mncc_bearer_cap_req, MNCC_BEARER_CAP_REQ);

    /*
     * fill in primitive parameter: bearer capability decoding request
     */
    mncc_bearer_cap_req -> req_id        = reqId;
    mncc_bearer_cap_req -> bc_mod        = BC_MOD_DECODE;
    mncc_bearer_cap_req -> bcconf.bc_len = bcLen;

    memcpy( mncc_bearer_cap_req -> bcconf.bc, bc, bcLen );

    PSENDX (CC, mncc_bearer_cap_req);
  }

  return 0;
}
#endif /* #if 0 */


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_MPTY              |
+-------------------------------------------------------------------+

  PURPOSE : Inform CC about an event related to a multiparty call
            which may change the auxiliary state hold or mpty in CC.

*/

GLOBAL SHORT psaCC_MPTY ( SHORT cId, UBYTE mpty_event )
{
  TRACE_FUNCTION ("psaCC_MPTY()");
  
  /* Send the synchronization request to CC */
  {
    PALLOC (mncc_sync_req, MNCC_SYNC_REQ); /* T_MNCC_SYNC_REQ */
    mncc_sync_req->synccs     = SYNCCS_MPTY_EVENT;
    mncc_sync_req->ti         = psaCC_ctb(cId)->ti;
    mncc_sync_req->mpty_event = mpty_event;
    PSENDX (CC, mncc_sync_req);
  }
  return 0;
}

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