diff src/aci2/aci/aoc.c @ 3:93999a60b835

src/aci2, src/condat2: import of g23m/condat source pieces from TCS211
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 26 Sep 2016 00:29:36 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/aci2/aci/aoc.c	Mon Sep 26 00:29:36 2016 +0000
@@ -0,0 +1,2615 @@
+/*
++-----------------------------------------------------------------------------
+|  Project :  GSM-PS (6147)
+|  Modul   :  AOC
++-----------------------------------------------------------------------------
+|  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
+|             advice of charge handling of ACI.
++-----------------------------------------------------------------------------
+*/
+
+#include "aci_all.h"
+
+#include "l4_tim.h"
+
+#include "pcm.h"
+
+#include "aci_cmh.h"
+
+#include "psa.h"
+#include "psa_sim.h"
+#include "psa_mm.h"
+
+#include "aoc.h"
+#include "psa_cc.h"
+#include "cmh.h"
+#include "cmh_cc.h"
+
+#ifdef SIM_TOOLKIT
+#include "psa_sat.h"
+#endif
+
+#ifdef FAX_AND_DATA
+#include "aci_fd.h"
+#endif    /* of #ifdef FAX_AND_DATA */
+
+#ifdef UART
+#include "dti.h"
+#include "dti_conn_mng.h"
+#endif
+
+#include "cmh_sim.h"
+
+#define MC_AOC_ROUND_UP(X)  ((((X)%100) EQ 0) ? ((X)/100) : (((X)/100) + 1))
+#define E_IN_MS(X)          ((X)*100)
+
+/********* current define *********************************************/
+static   UBYTE   aoc_state = AOC_NULL;      /* actual AoC state       */
+static   UBYTE   sim_data[10];              /* SIM data exchange      */
+static   UBYTE   currency [4];              /* used for currency      */
+static   ULONG   ccm;                       /* current call meter     */
+static   ULONG   ccm_already_incremented;   /* value of CCM increm.   */
+static   ULONG   acm;                       /* accumulated call meter */
+static   UBYTE   acm_increment_flag;        /* counter for incr. ACM  */
+static   ULONG   acmmax;                    /* maximum of ACM         */
+static   ULONG   eppu;                      /* elementary unit price  */
+static   ULONG   sexp;                      /* sign of expression     */
+static   ULONG   exp;                       /* expression value       */
+static   UBYTE   pwd [9];                   /* password               */
+static   UBYTE   act_upd_op;                /* actual update operation*/
+static   ULONG   act_value;                 /* new value for ACM(Max) */
+static   T_ACI_CMD_SRC act_src_id;          /* source of AT command   */
+
+GLOBAL   T_CC_AOC_TBL cc_aoc_table[MAX_CALL_NR];  /* AoC Call Table   */
+EXTERN T_PCEER causeMod;
+EXTERN SHORT causeCeer;
+
+static   ULONG          cct;                /* current call timer     */
+/*static   ULONG          act;                *//* accumulated call timer */  /* never used */
+static   USHORT         ct_running;         /* call timer is running  */
+static   UBYTE          limit_reached = FALSE; /* ACM over limit ?    */
+
+static const ULONG ppu_values [12][2] =
+{
+    /*    exp,          sexp            index        */
+          1L,           0L,          /* 0            */
+          1L,           0L,          /* 1            */
+          10L,          0L,          /* 2            */
+          10L,          1L,          /* 3            */
+          100L,         0L,          /* 4            */
+          100L,         1L,          /* 5            */
+          1000L,        0L,          /* 6            */
+          1000L,        1L,          /* 7            */
+          10000L,       0L,          /* 8            */
+          10000L,       1L,          /* 9            */
+          100000L,      0L,          /* 10           */
+          100000L,      1L           /* 11           */
+};
+
+#ifdef SIM_TOOLKIT
+BOOL aoc_update (int ref, T_SIM_FILE_UPDATE_IND *fu);
+#endif
+static   UBYTE          ccwv_charging = CCWV_CHRG_Termination;
+
+/********* function prototypes **************************************/
+void aoc_calc_acm_wrn_evnt  ( ULONG           charge,
+                              BOOL            aoc_running  );
+
+void aoc_set_time_ut_charge ( SHORT           cId,
+                              T_TIME          time         );
+void aoc_calc_expct_charge  ( UBYTE           mode         );
+void aoc_ntfy_acm_wrn_evnt  ( T_ACI_CCWV_CHRG charging     );
+
+T_TIME       aoc_calc_time_ut_charge ( SHORT  cId,
+                                       UBYTE  e_value_flag );
+
+void aoc_start_info_newcall (SHORT Cid);
+void aoc_start_newinfo_existingcall (SHORT Cid);
+
+static void aoc_calculate_charging_parameter_part1 (SHORT Cid);
+static void aoc_calculate_charging_parameter_part2 (SHORT Cid);
+/********* functions ************************************************/
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_init            |
++--------------------------------------------------------------------+
+
+
+   PURPOSE : Initialisation of the Advice of charge module. The function
+             is called after PIN entering. The actual phase of the SIM
+             card, the SIM service table and the PCM entry is checked.
+             The return value indicates whether AoC is supported.
+
+*/
+
+UBYTE aoc_init (UBYTE phase, UBYTE * sim_service_table)
+{
+  EF_MSSUP mssup;
+  UBYTE    version;
+
+  TRACE_FUNCTION ("aoc_init()");
+
+  aoc_state = AOC_DISABLE;
+  /* Check Phase. It must be at least Phase 2 */
+  if (phase <= PHASE_1_SIM)
+    return FALSE;
+  TRACE_EVENT ("AOC: Card >= Phase 2");
+
+  /* Check SIM Service Table */
+  if (aoc_ssc(SRV_AOC,sim_service_table) NEQ ALLOCATED_AND_ACTIVATED)
+    return FALSE;
+  TRACE_EVENT ("AOC: Card supports AoC");
+
+  /* check PCM entry in MSCAP field */
+  pcm_Init ();
+  pcm_ReadFile ((UBYTE *)EF_MSSUP_ID, SIZE_EF_MSSUP, (UBYTE *)&mssup, &version);
+  if (FldGet(mssup.feat1, AoC))
+  {
+    /* start reading ACM, ACMMax and PUCT */
+    TRACE_EVENT ("AOC: MS supports AoC");
+    aoc_state = AOC_ENABLE;
+    aoc_read_acm ();
+    return TRUE;
+  }
+
+#ifdef _SIMULATION_
+  aoc_state = AOC_ENABLE;
+  return TRUE;
+#else
+  return FALSE;
+#endif
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_reset           |
++--------------------------------------------------------------------+
+
+   PURPOSE : Deactivation of AoC Service. Necessary, when SIM card
+             becomes unavailable
+*/
+
+void aoc_reset (void)
+{
+  TRACE_FUNCTION ("aoc_reset()");
+  aoc_state = AOC_DISABLE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_sms             |
++--------------------------------------------------------------------+
+
+
+   PURPOSE : Indication that a SMS has received. This can be a trigger
+             for changed ACM or ACMMax on the SIM card.
+*/
+
+void aoc_sms (void)
+{
+  TRACE_FUNCTION ("aoc_sms()");
+  if (aoc_state EQ AOC_ENABLE)
+  {
+    /* start reading ACM, ACMMax and PUCT again */
+    aoc_read_acm ();
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_update          |
++--------------------------------------------------------------------+
+
+   PURPOSE : Evaluation of File Change Notification and update AOC,
+             if required.
+*/
+
+#ifdef SIM_TOOLKIT
+BOOL aoc_update (int ref, T_SIM_FILE_UPDATE_IND *fu)
+{
+  BOOL found = FALSE;
+  int i;
+
+  TRACE_FUNCTION ("aoc_update ()");
+
+  if (aoc_state NEQ AOC_ENABLE)
+    return TRUE;   /* not used at all! */  /* AOC not supported */
+
+  for (i = 0; i < (int)fu->val_nr; i++)
+  {
+    if (fu->file_id[i] EQ SIM_ACM OR
+        fu->file_id[i] EQ SIM_ACMMAX OR
+        fu->file_id[i] EQ SIM_PUCT)
+    {
+      found = TRUE;
+      break;
+    }
+  }
+
+  if (found)
+  {
+    simShrdPrm.fuRef = ref;
+    aoc_read_acm ();
+    return FALSE;
+  }
+  else
+  {
+    simShrdPrm.fuRef = -1;            /* no update needed */
+    return TRUE;
+  }
+}
+#endif
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_info            |
++--------------------------------------------------------------------+
+
+   PURPOSE : Information of the Advice of charge module. The following
+             causes are defined:
+             AOC_START_TIME     Start call time measurements.
+             AOC_STOP_TIME      Stop call timer measurements.
+             AOC_START_AOC      Advice of Charge is started.
+             AOC_SUSPEND_AOC    Suspension of Call.
+             AOC_RESUME_AOC     Resumption of Call.
+*/
+
+UBYTE aoc_info (SHORT Cid, UBYTE cause)
+{
+  T_SIM_SET_PRM * pSIMSetPrm;  /* points to SIM parameter set */
+  BOOL calFlg;                 /* call flag */
+
+  TRACE_FUNCTION ("aoc_info()");
+
+  switch (cause)
+  {
+    case AOC_START_TIME: /* Indication of a new call. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("AOC_START_TIME");
+#endif
+      /* Call Time Measurements shall be
+       * started if it is the first call (ct_runnning = 0) */
+      if (ct_running EQ 0)
+      {
+        /* this is the first call. Then start call timer (periodic)
+         * and clear current calltimer value and current call meter. */
+        cct = ccm = ccm_already_incremented = 0L;
+        vsi_t_pstart (VSI_CALLER AOC_CALLTIMER, AOC_THOUSAND_MILLISECONDS, AOC_THOUSAND_MILLISECONDS);
+
+        pSIMSetPrm = &simShrdPrm.setPrm[CMD_SRC_LCL];
+        simShrdPrm.synCs = SYNC_START_CALL;
+        psaSIM_SyncSIM();
+      }
+
+      cmhCC_flagCall( Cid, &ct_running );
+
+      /* Clear aoc table parameter */
+      memset (&cc_aoc_table[Cid], 0, sizeof(T_CC_AOC_TBL));
+      break;
+
+    case AOC_STOP_TIME: /* Indication of the end of a call. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("AOC_STOP_TIME");
+#endif
+      TRACE_EVENT_P1("CT Running = %4X", ct_running);
+      calFlg = cmhCC_tstAndUnflagCall( Cid, &ct_running );
+
+      /*Call Time Measurements shall be
+       * stopped if it is the last call (ct_runnning <= 1) */
+      if (ct_running EQ 0 AND calFlg)
+      {
+        /* this is the last call. Then stop call timer. */
+        TRACE_EVENT ("Last Call Stop Call Timer");
+        vsi_t_stop (VSI_CALLER AOC_CALLTIMER);
+
+        pSIMSetPrm = &simShrdPrm.setPrm[CMD_SRC_LCL];
+        simShrdPrm.synCs = SYNC_STOP_CALL;
+        psaSIM_SyncSIM();
+
+        aoc_ntfy_acm_wrn_evnt ( CCWV_CHRG_Termination );
+      }
+
+      if (cc_aoc_table[Cid].aoc_timer_running) /* stop AoC timer if running */
+      {
+        vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER+Cid));
+        cc_aoc_table[Cid].aoc_timer_running = FALSE;
+        aoc_increment_charge (0L, TRUE);  /* add rest to SIM */
+      }
+      break;
+
+    case AOC_START_AOC: /* Advice of Charge information has received for the indicated call. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("*** AOC_START_AOC");
+#endif
+      TRACE_EVENT_P2("AOC started Cid = %u State = %u", Cid, aoc_state);
+
+      if (aoc_state EQ AOC_ENABLE) /* AoC is supported */
+      {
+        limit_reached = FALSE;
+
+        if (cc_aoc_table[Cid].aoc_timer_running)
+          aoc_start_newinfo_existingcall(Cid);
+        else
+          aoc_start_info_newcall(Cid);
+
+        return TRUE;
+      }
+      else   /* AoC not supported */
+      {
+        TRACE_EVENT ("AOC not supported");
+        return FALSE;
+      }
+
+    case AOC_SUSPEND_AOC: /* Suspension of Call is indicated. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("*** AOC_SUSPEND_AOC");
+#endif
+      if (aoc_state EQ AOC_ENABLE AND
+          cc_aoc_table[Cid].aoc_timer_running)  /* AoC timer is running, then stop it. */
+      {
+        /* save remaining timeslice prior stopping the timer */
+        vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
+        vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
+
+        cc_aoc_table[Cid].aoc_timer_running = FALSE;
+      }
+      break;
+
+    case AOC_RESUME_AOC: /* Resumption of Call is indicated. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("*** AOC_RESUME_AOC");
+#endif
+      if (aoc_state EQ AOC_ENABLE AND
+          aoc_non_zero_cai (Cid))
+      {
+        /* AoC info is available, then start again. calculate the remaining time */
+        vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
+                      cc_aoc_table[Cid].remaining_time,
+                      cc_aoc_table[Cid].next_interval);
+        cc_aoc_table[Cid].aoc_timer_running = TRUE;
+
+        aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
+      }
+      break;
+
+    case AOC_CALL_CONNECTED: /* Call active state of a Call is indicated. */
+#ifdef _SIMULATION_
+      TRACE_EVENT ("*** AOC_CALL_CONNECTED");
+#endif
+      if (aoc_state EQ AOC_ENABLE AND
+          aoc_non_zero_cai (Cid))
+      {
+        /* AoC info is available, then start send initial CCM value to MMI. */
+        aoc_send_ccm ();
+      }
+      break;
+
+    default:
+#ifdef _SIMULATION_
+      TRACE_EVENT ("*** Wrong cause ***");
+#endif
+      break;
+
+  }
+  return TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_get_values      |
++--------------------------------------------------------------------+
+
+   PURPOSE : Request of Advice of Charge Values.
+*/
+
+void aoc_get_values (UBYTE value_type, void * value)
+{
+  ULONG * longPtr = value;
+  T_puct_raw * raw_puct;
+
+  TRACE_FUNCTION ("aoc_get_values()");
+
+  switch (value_type)
+  {
+    case AOC_CTV: /* Current Timer Value */
+      *longPtr = cct;
+      break;
+
+    case AOC_CCM: /* Current Call Meter Value */
+#if defined _SIMULATION_
+      TRACE_EVENT_P1("CCM = %u", MC_AOC_ROUND_UP(ccm));
+#endif
+      *longPtr = MC_AOC_ROUND_UP(ccm);
+      break;
+
+    case AOC_ACM: /* Accumulated Call Meter Value */
+      *longPtr = MC_AOC_ROUND_UP(acm);
+      break;
+
+    case AOC_ACMMAX: /* Maximum Accumulated Call Meter Value */
+      *longPtr = MC_AOC_ROUND_UP(acmmax);
+      break;
+
+    case AOC_PUCT: /* Price per Unit and Currency */
+      aoc_calculate_puct (1L, (T_puct *)value);
+      break;
+
+    case AOC_PUCT_RAW: /* Price per Unit and Currency as RAW data */
+      raw_puct       = (T_puct_raw *)value;
+      raw_puct->exp  = exp;
+      raw_puct->sexp = sexp;
+      raw_puct->eppu = eppu;
+      memcpy (raw_puct->currency, currency, 4);
+      break;
+
+    case AOC_CCM_PUCT: /* CCM in Price per Unit and Currency */
+      aoc_calculate_puct (MC_AOC_ROUND_UP(ccm), (T_puct *)value);
+      break;
+
+    case AOC_ACM_PUCT: /* ACM in Price per Unit and Currency */
+      aoc_calculate_puct (MC_AOC_ROUND_UP(acm), (T_puct *)value);
+      break;
+
+    case AOC_ACMMAX_PUCT: /* ACMMax in Price per Unit and Currency */
+      aoc_calculate_puct (MC_AOC_ROUND_UP(acmmax), (T_puct *)value);
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_set_values      |
++--------------------------------------------------------------------+
+
+   PURPOSE : Setting of Advice of charge values.
+*/
+
+T_ACI_RETURN aoc_set_values (T_ACI_CMD_SRC srcId,
+                             UBYTE         value_type,
+                             void         *value,
+                             UBYTE        *password)
+{
+  TRACE_FUNCTION ("aoc_set_values()");
+
+  /* Store Password, if available and start writing to the SIM Card. */
+  memcpy (pwd, password, 9);
+  act_src_id = srcId;
+
+  /* AOC not supported in SIM, Check for aoc_state return AT_FAIL */
+  if( aoc_state NEQ AOC_ENABLE )
+  {
+    return( AT_FAIL );
+  }
+  
+  switch (value_type)
+  {
+    case AOC_ACM:
+      aoc_update_acm (FIRST_UPDATE, (ULONG)value);
+      break;
+
+    case AOC_ACMMAX:
+      aoc_update_acmmax (FIRST_UPDATE, (ULONG)value);
+      break;
+
+    case AOC_PUCT:
+      aoc_update_puct (FIRST_UPDATE, (T_puct *)value);
+      break;
+  }
+
+  return( AT_EXCT );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_check_moc       |
++--------------------------------------------------------------------+
+
+   PURPOSE : The function checks whether ACM is greater than ACMMax.
+             In this case only emergency calls are allowed for mobile
+             originated call direction.
+*/
+
+UBYTE aoc_check_moc (void)
+{
+  TRACE_FUNCTION ("aoc_check_moc()");
+
+  return aoc_check_acm();
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_ssc             |
++--------------------------------------------------------------------+
+
+  PURPOSE : Check SIM service status. The value of service nr is
+            extracted from the SIM service table.
+*/
+
+UBYTE aoc_ssc (UBYTE nr, UBYTE * serv_table)
+{
+  TRACE_FUNCTION ("aoc_ssc()");
+
+  if (nr > MAX_SRV_TBL*4)
+  {
+    TRACE_ERROR ("serv_table overflow in pb_ssc()");
+    return NO_ALLOCATED;
+  }
+
+  return ( *(serv_table+(nr-1)/4) >> (((nr-1)&3)*2)  & 0x03);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_acm        |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function starts reading of the SIM field ACM.
+*/
+
+void aoc_read_acm (void)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_read_acm()");
+
+  table_id = psaSIM_atbNewEntry();
+
+  if(table_id NEQ NO_ENTRY)
+  {
+    simShrdPrm.atb[table_id].accType      = ACT_RD_REC;
+    simShrdPrm.atb[table_id].reqDataFld   = SIM_ACM;
+    simShrdPrm.atb[table_id].recNr        = 1;
+    simShrdPrm.atb[table_id].dataLen      = 3;
+    simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+    simShrdPrm.atb[table_id].exchData     = sim_data;
+    simShrdPrm.atb[table_id].rplyCB       = aoc_read_acm_cb;
+
+    simShrdPrm.aId = table_id;
+    if(psaSIM_AccessSIMData() < 0)
+    {
+      TRACE_EVENT("FATAL ERROR");
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_acm_cb     |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for reading ACM.
+*/
+
+void aoc_read_acm_cb(SHORT table_id)
+{
+  TRACE_FUNCTION ("aoc_read_acm_cb()");
+
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+
+  if (simShrdPrm.atb[table_id].errCode NEQ SIM_NO_ERROR)
+  {
+    /* ACM is not readable, disable set to default values */
+    acm=0L;
+    TRACE_EVENT ("AOC: Card has no ACM field");
+#ifdef SIM_TOOLKIT
+    if (simShrdPrm.fuRef >= 0)
+    {
+      psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
+    }
+#endif
+  }
+  else
+  {
+    /* calculate ACM and start reading ACMMax  */
+    acm  = (sim_data[0]<<16) + (sim_data[1]<<8) + sim_data[2];
+    acm *= 100;    /* internal unit is 1/100 */
+    TRACE_EVENT_P1("ACM  value = %u", (USHORT)acm);
+    aoc_read_acmmax ();
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_acmmax     |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function starts reading of the SIM field ACMMax.
+*/
+
+void aoc_read_acmmax (void)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_read_acmmax()");
+
+  table_id = psaSIM_atbNewEntry();
+
+  if(table_id NEQ NO_ENTRY)
+  {
+    /*
+     * Fill formular for access
+     *
+     * set datafield type = Binary field
+     * set datafield      = SIM_ACMMAX
+     * set offset         = 0 Bytes
+     * set length         = 3 Bytes
+     */
+    simShrdPrm.atb[table_id].accType      = ACT_RD_DAT;
+    simShrdPrm.atb[table_id].reqDataFld   = SIM_ACMMAX;
+    simShrdPrm.atb[table_id].dataOff      = 0;
+    simShrdPrm.atb[table_id].dataLen      = 3;
+    simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+    simShrdPrm.atb[table_id].exchData     = sim_data;
+    simShrdPrm.atb[table_id].rplyCB       = aoc_read_acmmax_cb;
+
+    simShrdPrm.aId = table_id;
+
+    if(psaSIM_AccessSIMData() < 0)
+    {
+      TRACE_EVENT("FATAL ERROR");
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_acmmax_cb  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for reading ACMMax.
+*/
+
+void aoc_read_acmmax_cb(SHORT table_id)
+{
+  TRACE_FUNCTION ("aoc_read_acmmax_cb()");
+
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+
+  if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
+  {
+    /* calculate ACMMAX and start reading PUCT */
+    acmmax  = (sim_data[0]<<16) + (sim_data[1]<<8) + sim_data[2];
+    acmmax *= 100;    /* internal unit is 1/100 */
+    TRACE_EVENT_P1("ACMMAX  value = %u", (USHORT)acmmax);
+    aoc_read_puct ();
+  }
+  else
+  {
+    /* ACMMAX is not readable, disable set to default values */
+    acmmax=0;
+    TRACE_EVENT ("AOC: Card has no ACMmax field");
+#ifdef SIM_TOOLKIT
+    if (simShrdPrm.fuRef >= 0)
+    {
+      psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
+    }
+#endif
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_puct       |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function starts reading of the SIM field PUCT.
+*/
+
+void aoc_read_puct (void)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_read_puct()");
+
+  table_id = psaSIM_atbNewEntry();
+  if(table_id NEQ NO_ENTRY)
+  {
+    simShrdPrm.atb[table_id].accType      = ACT_RD_DAT;
+    simShrdPrm.atb[table_id].reqDataFld   = SIM_PUCT;
+    simShrdPrm.atb[table_id].dataOff      = 0;
+    simShrdPrm.atb[table_id].dataLen      = 5;
+    simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+    simShrdPrm.atb[table_id].exchData     = sim_data;
+    simShrdPrm.atb[table_id].rplyCB       = aoc_read_puct_cb;
+
+    simShrdPrm.aId = table_id;
+    if(psaSIM_AccessSIMData() < 0)
+    {
+      TRACE_EVENT("FATAL ERROR");
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_read_puct_cb    |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for reading PUCT.
+*/
+
+void aoc_read_puct_cb(SHORT table_id)
+{
+  UBYTE index;
+
+  TRACE_FUNCTION ("aoc_read_puct_cb()");
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+
+  if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
+  {
+    /* calculate PUCT */
+#if defined WIN32
+    TRACE_EVENT_P2("PUCT %x %x",sim_data[3],sim_data[4]);
+#endif
+
+    currency [0] = sim_data[0];
+    currency [1] = sim_data[1];
+    currency [2] = sim_data[2];
+    currency [3] = 0;
+    eppu         = (sim_data[3]<<4 & 0xFF0) + (sim_data[4] & 0x0F);
+    index        =  sim_data[4]>>4 & 0x0F;
+    if (index > 11)  /* only 0 to 11 */
+      index = 11;
+    exp          = ppu_values[index][0];
+    sexp         = ppu_values[index][1];
+  }
+  else
+  {
+    /* PUCT is not readable, disable set to default values */
+    eppu = exp = sexp = 0;
+    TRACE_EVENT ("AOC: Card has no PUCT field");
+  }
+
+#ifdef SIM_TOOLKIT
+  if (simShrdPrm.fuRef >= 0)
+  {
+    psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_SUCC_ADD);
+  }
+#endif
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_init_calltable  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Initialisation of the AoC parameters of the call table.
+
+*/
+
+void aoc_init_calltable (void)
+{
+  TRACE_FUNCTION ("aoc_init_calltable()");
+
+  /* Initialize AoC parameters and open
+   * the call dependent AoC timer */
+  memset (cc_aoc_table, 0, sizeof (cc_aoc_table));
+
+  /* Initialize AoC Parameter */
+  ccm                = 0L;
+  ccm_already_incremented = 0L;
+  acm_increment_flag = 0;
+
+  /* Initialize the Call Timer Variables */
+  cct        = 0L;
+  /*  act        = 0L; */
+  ct_running = 0;
+
+#ifdef SIM_TOOLKIT
+  simShrdPrm.fuRef = -1;
+  if (!psaSAT_FURegister (aoc_update))
+  {
+    TRACE_EVENT ("FAILED to register the handler aoc_update() for FU");
+  }
+
+#endif
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_timeout         |
++--------------------------------------------------------------------+
+
+  PURPOSE : A timeout has occured for a timer. The funtion returns
+            TRUE, if it is a call timer or a AoC timer, else FALSE
+            is returned to indicate that the timer has not been
+            processed.
+
+*/
+UBYTE aoc_timeout (USHORT index)
+{
+  if (index EQ AOC_CALLTIMER)
+  {
+    /* timeout call timer */
+    aoc_timeout_call_timer ();
+    return TRUE;
+  }
+  else if (index >= AOC_AOCTIMER AND index < AOC_AOCTIMER+MAX_CALL_NR)
+  {
+    /* Check Advice of Charge Timer */
+    aoc_timeout_aoc_timer ((USHORT)(index - AOC_AOCTIMER));
+    return TRUE;
+  }
+  else
+  {
+    /* the timeout is not for AoC */
+    return FALSE;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE : AOC                    |
+| STATE  : code                      ROUTINE: aoc_timeout_call_timer |
++--------------------------------------------------------------------+
+
+  PURPOSE : the call timer timeout has occured. The CCT and ACT are
+            increased.
+
+*/
+
+void aoc_timeout_call_timer (void)
+{
+  int Cid;
+  T_ACI_CMD_SRC idx;
+  UBYTE five_second_have_just_elapsed = FALSE;
+
+  /* TRACE_FUNCTION ("aoc_timeout_call_timer()"); */
+
+  cct++;
+  /*  act++; */
+
+  if (acm_increment_flag EQ 1)
+    five_second_have_just_elapsed = TRUE;
+
+  /* Flag to realize 5 second delay for incrementing ACM on the SIM card. */
+  if (acm_increment_flag)
+    acm_increment_flag--;
+
+  /* flush the charge on the SIM, 5 seconds after the last writing,
+   * if there some units to add */
+  if (five_second_have_just_elapsed)
+    aoc_increment_charge (0L, FALSE);
+
+  /* Update the remaining time for running AoC timer */
+  for (Cid=0; Cid<MAX_CALL_NR; Cid++)
+  {
+    if (cc_aoc_table[Cid].aoc_timer_running AND
+        cc_aoc_table[Cid].remaining_time > 0)
+    {
+      vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
+    }
+  }
+
+  for( idx = 0; idx < CMD_SRC_MAX; idx++ )
+  {
+    R_AT( RAT_CTV, idx )( );
+  }
+
+  aoc_set_time_ut_charge ( ACI_NumParmNotPresent, 0L );
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE : AOC                    |
+| STATE  : code                      ROUTINE: aoc_timeout_aoc_timer  |
++--------------------------------------------------------------------+
+
+  PURPOSE : An AoC timer timeout has occured.
+
+*/
+
+void aoc_timeout_aoc_timer (SHORT Cid)
+{
+  SHORT dummy_waitId;          /* holds call waiting id */
+  T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
+
+  TRACE_FUNCTION ("aoc_timeout_aoc_timer()");
+
+  if ((aoc_check_acm () EQ FALSE)              AND
+      (cc_aoc_table[Cid].aoci_active EQ FALSE) AND
+      (cc_aoc_table[Cid].next_unit)                ) /* check if the next intervall would charge (time related charge > 0)*/
+  {
+    /* ACM exceeds ACMMax, and call is not free, so disconnect call */
+    TRACE_EVENT ("ACM > ACMMax");
+    cmhCC_ClearCall (Cid,
+                     CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
+                     src_dummy, AT_CMD_NONE, &dummy_waitId);
+  }
+  else
+  {
+    /* e3 may have changed during the current intervall but recalc is already done */
+    aoc_increment_charge (cc_aoc_table[Cid].next_unit, FALSE);
+    if (cc_aoc_table[Cid].new_data_avail)
+    {
+      /* New Parameter available */
+      /* 4.3.e) bring parameters held in abeyance into operation */
+      if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
+
+      aoc_calculate_charging_parameter_part2 (Cid);
+
+      /* timing has changed? */
+      if (cc_aoc_table[Cid].e_next_bitmap & (E2_CHANGED | E7_CHANGED))
+      {
+        /* reschedule timer */
+        vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
+        vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
+                      cc_aoc_table[Cid].first_interval,
+                      cc_aoc_table[Cid].next_interval);
+        cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
+      }
+      else
+        /* ask the timer since we could already be ahead */
+        /* cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].next_interval; */
+        vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
+
+      cc_aoc_table[Cid].new_data_avail = FALSE;
+      cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
+    }
+    else
+    {
+      /* re-initialise remaining time counter */
+      /* ask the timer since we could already be ahead */
+      /* cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].next_interval; */
+      vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
+    }
+    
+    /* check if timer had e2=0 and e7>= */
+    if (cc_aoc_table[Cid].next_interval == 0)
+    {
+      cc_aoc_table[Cid].aoc_timer_running = FALSE;
+       /* cc_aoc_table[Cid].aoci_active = FALSE;*/
+      cc_aoc_table[Cid].remaining_time = 0L;
+      aoc_set_time_ut_charge ( Cid, ACI_NumParmNotPresent );
+    }
+    else
+      aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE : AOC                    |
+| STATE  : code                      ROUTINE: aoc_start_aoc_timer    |
++--------------------------------------------------------------------+
+
+  PURPOSE : AoC is started for the indicated call or
+            new AoC parameter are received.
+*/
+
+void aoc_start_newinfo_existingcall (SHORT Cid)
+{
+  UBYTE         no_more_timer_running = FALSE;
+  T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
+  SHORT         dummy_waitId;
+
+  TRACE_FUNCTION ("aoc_start_newinfo_existingcall()");
+
+  if(!aoc_non_zero_cai (Cid))
+  {
+    return;
+  }
+
+  if (cc_aoc_table[Cid].aoc_timer_running EQ FALSE)
+  {
+      /* New Parameter available */
+      /* 4.3.e) bring parameters held in abeyance into operation */
+      if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
+
+      aoc_calculate_charging_parameter_part2 (Cid);
+
+      /*    vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);*/
+
+      cc_aoc_table[Cid].new_data_avail = FALSE;
+      cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
+      no_more_timer_running = TRUE;
+  }
+
+
+  /* charging information available, else wait for end of interval.*/
+  if ( (cc_aoc_table[Cid].next_interval EQ 0) AND
+       ((cc_aoc_table[Cid].first_interval EQ 0) OR (cc_aoc_table[Cid].remaining_time EQ 0)) )
+  {
+    /* if CDUR is not actively timing (i.e. due to e2 being zero,
+     * e7 being zero or the processing of e7 has been completed),
+     * then a new value of e2 and/or e7 is applied immediately as per a normal call. */
+    no_more_timer_running = TRUE;
+  }
+
+  /* charging information available, else wait for end of interval. */
+  if ((aoc_check_acm () EQ TRUE)            OR
+      (cc_aoc_table[Cid].aoci_active EQ TRUE))
+  {
+    /* ACM has not exceeded ACMMax then calculate charging parameters and increment inital charge */
+    aoc_calculate_charging_parameter_part1 (Cid);
+    aoc_increment_initial_charge (Cid);
+    cc_aoc_table[Cid].new_data_avail = TRUE;
+  }
+  else
+  {
+    /*
+     * ACM has reached ACM max, the call is kept till the next interval elapses
+     * but if there is no timer running, for a new reception of CAI non zero,
+     * we behave as on reception of a first CAI for a call, if acm has reached ACM max,
+     * we disconnect the call.
+     * "Rec 2.24 : 4.2.2 ACM : If the ACM max is valid and the ACM is equal to or greater
+     * than the value of ACM max, and an incoming call is received and subsequently
+     * a non-zero CAI is received for that call, then the call shall be terminated by
+     * the ME with an appropriate indication given to the user."
+     */
+    if (no_more_timer_running)
+    {
+      /* if we are here, it means that it's a non-zero CAI, so no need to test it again */
+      TRACE_EVENT("no more timer running clear call");
+      cmhCC_ClearCall (Cid,
+                       CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
+                       src_dummy, AT_CMD_NONE, &dummy_waitId);
+     }
+  }
+
+  if (no_more_timer_running)
+  {
+    /* New Parameter available */
+    aoc_calculate_charging_parameter_part2 (Cid);
+
+    cc_aoc_table[Cid].new_data_avail = FALSE;
+    vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
+    vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
+                  cc_aoc_table[Cid].first_interval,
+                  cc_aoc_table[Cid].next_interval);
+    /* re-initialise remaining time counter for first interval */
+    cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
+  }
+}
+
+void aoc_start_info_newcall (SHORT Cid)
+{
+  T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
+  SHORT         dummy_waitId;
+
+  TRACE_FUNCTION ("aoc_start_info_newcall()");
+
+  if( !aoc_non_zero_cai(Cid) )
+  {
+    return;
+  }
+  /* charging information available */
+
+  if( (aoc_check_acm() EQ FALSE)           AND
+      (cc_aoc_table[Cid].aoci_active EQ FALSE) )
+  {
+    /* ACM exceeds ACMMax, disconnect call */
+    TRACE_EVENT("clear call on initial call");
+    cmhCC_ClearCall (Cid,
+                     CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
+                     src_dummy,
+                     AT_CMD_NONE,
+                     &dummy_waitId);
+    return;
+  }
+
+  /* ACM has not exceeded ACMMax then calculate charging parameters,
+   * increment inital charge and start AoC Timer. */
+  {
+    /* bring new parameters into operation */
+
+      if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
+      if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
+
+   /*    cc_aoc_table[Cid].new_data_avail = FALSE;*/
+    cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
+  }
+
+  aoc_calculate_charging_parameter (Cid);
+  aoc_increment_initial_charge (Cid);
+
+  if(cc_aoc_table[Cid].first_interval)
+  {
+    vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
+                  cc_aoc_table[Cid].first_interval,
+                  cc_aoc_table[Cid].next_interval);
+
+    cc_aoc_table[Cid].aoc_timer_running = TRUE;
+  }
+
+  cc_aoc_table[Cid].new_data_avail = FALSE;
+  cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
+
+  aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE : AOC                    |
+| STATE  : code                      ROUTINE: aoc_non_zero_cai       |
++--------------------------------------------------------------------+
+
+  PURPOSE : Checks whether the Advice of Charge parameter indicate
+            a free call (parameters are not available or equal zero).
+*/
+
+UBYTE aoc_non_zero_cai (SHORT Cid)
+{
+  TRACE_FUNCTION ("aoc_non_zero_cai()");
+
+  /* AoC = e3      * { e4       + e1*INT(CDUR/(e7,e2)) + e5*INT(SEG/e6) }
+   *     = scaling * { constant + time related         + data related}
+   *
+   * Ref. GSM 2.24 Section 4 Functional operation in MS */
+
+  if ((cc_aoc_table[Cid].e3 EQ 0) OR
+     ((cc_aoc_table[Cid].e1 EQ 0) AND (cc_aoc_table[Cid].e4 EQ 0) /* AND (cc_aoc_table[Cid].e5 EQ 0) */ ))
+     /* e5, e6 is currently not supported */
+    return FALSE;
+
+  return TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE : AOC                    |
+| STATE  : code                      ROUTINE: aoc_check_acm          |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function indicates whether ACM exceeds ACMMax.
+
+*/
+
+UBYTE aoc_check_acm (void)
+{
+  TRACE_FUNCTION ("aoc_check_acm()");
+
+  TRACE_EVENT_P2("ACM=%u ACMMax=%u", acm, acmmax);
+
+  if (acmmax NEQ 0)
+  {
+    /*
+     * ACMMax is valid
+     */
+    if (acm >= acmmax)
+    {
+      causeMod  =  P_CEER_sim;                       /* Set the module to sim to report ceer */
+      causeCeer =  P_CEER_ACMMaxReachedOrExceeded;   /* Set proprietary cause */
+      return FALSE;      /* ACM exceeds ACMMax */
+    }
+    else
+    {
+      causeMod  =  P_CEER_mod;          /* Clear module which is set */
+      causeCeer =  P_CEER_NotPresent;   /* Clear proprietary cause */
+    }
+  }
+  return TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_calculate_charging_params_part1 |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function calculates an initial rime related charge
+
+*/
+
+static void aoc_calculate_charging_parameter_part1 (SHORT Cid)
+{
+  TRACE_FUNCTION ("aoc_calculate_charging_parameter_part1()");
+
+  /*
+   * Calculation for inital charge
+   */
+  cc_aoc_table[Cid].first_unit =
+      ((ULONG)cc_aoc_table[Cid].e3 * (ULONG)cc_aoc_table[Cid].e4) / 10;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_calculate_charging_params_part2 |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function calculates the interval length and the
+            number of units which will be incremented at interval
+            end.
+
+*/
+
+static void aoc_calculate_charging_parameter_part2 (SHORT Cid)
+{
+  TRACE_FUNCTION ("aoc_calculate_charging_parameter_part2()");
+
+  /* Calculation of first time interval */
+  cc_aoc_table[Cid].first_interval = (T_TIME) E_IN_MS(cc_aoc_table[Cid].e7);
+
+  /* Calculation of next time interval */
+  cc_aoc_table[Cid].next_interval = (T_TIME) E_IN_MS(cc_aoc_table[Cid].e2);
+
+
+  /* 4.3.a) E7 is not available or E7 is equal zero then use E2 */
+  if (cc_aoc_table[Cid].first_interval EQ 0L)
+    cc_aoc_table[Cid].first_interval = cc_aoc_table[Cid].next_interval;
+
+  /*
+   * Calculation for charge of next units
+   */
+  cc_aoc_table[Cid].next_unit =
+      ((ULONG)cc_aoc_table[Cid].e3 * (ULONG)cc_aoc_table[Cid].e1) / 10;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_calculate_charging_params |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function calculates the interval length and the
+            number of units which will be incremented at interval
+            end.
+
+*/
+
+void aoc_calculate_charging_parameter (SHORT Cid)
+{
+  TRACE_FUNCTION ("aoc_calculate_charging_parameter()");
+
+  aoc_calculate_charging_parameter_part1 (Cid);
+  aoc_calculate_charging_parameter_part2 (Cid);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_increment_initial_charge  |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function increments the inital charge to CCM and ACM.
+
+*/
+
+void aoc_increment_initial_charge (SHORT Cid)
+{
+  TRACE_FUNCTION ("aoc_increment_inital_charge()");
+
+  if (cc_aoc_table[Cid].first_unit)
+  {
+    /*
+     * if initial charge is available, charge it and
+     * inform MMI about it although it has no charge.
+     */
+    aoc_increment_charge (cc_aoc_table[Cid].first_unit, FALSE);
+    cc_aoc_table[Cid].first_unit = 0L;
+  }
+  aoc_send_ccm ();
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_increment_charge          |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function increments charge to CCM and ACM. If necessary
+            the ACM is incremented on the SIM card.
+
+*/
+
+void aoc_increment_charge (ULONG charge, UBYTE ever)
+{
+  SHORT table_id;
+  ULONG acm_for_sim;
+
+  TRACE_FUNCTION ("aoc_increment_charge()");
+
+  /*
+   * Both CCM is incremented
+   */
+  ccm += charge;
+
+  if (ccm > (0xFFFFFF * 100))  /* limit to 0xffffff since datafeld is only 3 bytes long.*/
+    ccm = (0xFFFFFF * 100);
+
+
+
+  TRACE_EVENT_P2("NewCCM %u charge %u", ccm, charge);
+
+  /*
+   * the update on the SIM is the difference between the rounded up value of the current CCM
+   * and the old CCM (already rounded up)
+   */
+  acm_for_sim = MC_AOC_ROUND_UP(ccm) - MC_AOC_ROUND_UP(ccm_already_incremented);
+
+  if (acm_for_sim)
+  {
+    if (acm_increment_flag EQ 0 OR ever)
+    {
+      /* sync the calltimer to this SIM-Access */
+      vsi_t_config (VSI_CALLER AOC_CALLTIMER, TIMER_SET, AOC_THOUSAND_MILLISECONDS );
+
+      /*
+       * Nothing stored in the last five seconds on the SIM card
+       * and now something to store
+       */
+      acm_increment_flag = 5;
+
+      ccm_already_incremented += acm_for_sim * 100;
+
+      acm += acm_for_sim * 100;
+
+      if (acm > (0xFFFFFF * 100))
+        acm = (0xFFFFFF * 100);
+
+      if (limit_reached EQ FALSE)
+      {
+        /*
+         * request table id for SIM SAP access
+         */
+        table_id = psaSIM_atbNewEntry();
+
+        if(table_id NEQ NO_ENTRY)
+        {
+          /*
+           * Fill formular for access
+           *
+           * set datafield type = Binary field
+           * set datafield      = SIM_ACM
+           * set offset         = 0 Bytes
+           * set length         = 3 Bytes
+           */
+          simShrdPrm.atb[table_id].accType      = ACT_INC_DAT;
+          simShrdPrm.atb[table_id].reqDataFld   = SIM_ACM;
+          simShrdPrm.atb[table_id].dataOff      = 0;
+          simShrdPrm.atb[table_id].dataLen      = 3;
+          simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+          simShrdPrm.atb[table_id].exchData     = sim_data;
+          simShrdPrm.atb[table_id].rplyCB       = aoc_increment_cb;
+          simShrdPrm.aId = table_id;
+          sim_data[0] = (UBYTE)(acm_for_sim >> 16);
+          sim_data[1] = (UBYTE)(acm_for_sim >> 8);
+          sim_data[2] = (UBYTE)(acm_for_sim & 0xFF);
+
+          TRACE_EVENT_P1("ACM increment = %u", acm_for_sim);
+
+          if(psaSIM_AccessSIMData() < 0)
+          {
+            TRACE_EVENT("FATAL ERROR");
+          }
+        }
+      }
+    }
+    aoc_send_ccm ();
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_increment_cb    |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for incrementing ACM.
+
+*/
+
+void aoc_increment_cb(SHORT table_id)
+{
+  UBYTE i;
+  SHORT dummy_waitId;          /* holds call waiting id */
+  T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
+
+
+  TRACE_FUNCTION ("aoc_increment_cb()");
+
+  switch (simShrdPrm.atb[table_id].errCode)
+  {
+    case SIM_NO_ERROR:
+      break;
+    case SIM_CAUSE_MAX_INCREASE:
+      /*
+       * ACM has reached limit 0xFFFFFF,
+       * If ACMMAX is zero, ACM shall be cleared
+       * by MMI. Only an indication is forwarded
+       * to MMI, else the call is released.
+       */
+      if (acmmax EQ 0)
+      {
+        limit_reached = TRUE;
+        R_AT( RAT_CME, simEntStat.entOwn )
+              ( AT_CMD_CACM, CME_ERR_AcmResetNeeded );
+        break;
+      }
+      /* lint -fallthrough */
+    default:
+      /*
+       * ACM increment is not successfull
+       */
+      aoc_state = AOC_DISABLE;
+
+      /*
+       * release all chargeable calls
+       */
+      for (i=0;i<MAX_CALL_NR;i++)
+      {
+        if (aoc_non_zero_cai(i))
+        {
+          cmhCC_ClearCall (i,
+                           CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
+                           src_dummy, AT_CMD_NONE,
+                           &dummy_waitId);
+        }
+      }
+      break;
+  }
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_calculate_puct  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Calculate counter in PUCT.
+
+*/
+
+void aoc_calculate_puct (ULONG value, T_puct * result)
+{
+  TRACE_FUNCTION ("aoc_calculate_puct()");
+#if defined WIN32
+  {
+    TRACE_EVENT_P1("EPPU %u",eppu);
+    TRACE_EVENT_P1("SEXP %u",sexp);
+    TRACE_EVENT_P1("EXP  %u",exp);
+    TRACE_EVENT_P1("VAL  %u",value);
+  }
+#endif
+  /*
+   * copy currency
+   */
+  memcpy (result->currency, currency, 4);
+
+  /*
+   * Multiply counter value with elementary price per unit
+   */
+  value *= eppu;
+  value *= 100;    /* internal calculation is 1/100 unit */
+
+  /*
+   * If sexp is set divide by logarithm of ten, else multiply
+   */
+  if (sexp)
+    value /= exp;
+  else
+    value *= exp;
+
+  /*
+   * Create resulting string with two digits after the colon
+   */
+  if (value EQ 0)
+    result->value[0] = '\0';
+  else
+    sprintf ((char *) result->value, "%u.%02u", value / 100, value % 100);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_update_acm                |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function tries to reset the ACM field on the SIM card.
+
+*/
+
+void aoc_update_acm (UBYTE operation, ULONG value)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_update_acm()");
+
+  /*
+   * request table id for SIM SAP access
+   */
+  table_id   = psaSIM_atbNewEntry();
+  act_upd_op = operation;
+
+  if(table_id NEQ NO_ENTRY)
+  {
+    switch (operation)
+    {
+      case FIRST_UPDATE:
+        /*
+         * This is the first access to ACM. It may fail,
+         * because PIN2 is needed.
+         */
+        act_value  = 0L;
+        /*lint -fallthrough*/
+      case SECOND_UPDATE:
+        /*
+         * This is the second access to ACM after PIN entering.
+         */
+        simShrdPrm.atb[table_id].accType      = ACT_WR_REC;
+        simShrdPrm.atb[table_id].reqDataFld   = SIM_ACM;
+        simShrdPrm.atb[table_id].dataOff      = 0;
+        simShrdPrm.atb[table_id].dataLen      = 3;
+        simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+        simShrdPrm.atb[table_id].exchData     = sim_data;
+        simShrdPrm.atb[table_id].rplyCB       = aoc_update_acm_cb;
+        simShrdPrm.aId = table_id;
+        sim_data[0] = (UBYTE)(act_value >> 16);
+        sim_data[1] = (UBYTE)(act_value >> 8);
+        sim_data[2] = (UBYTE)(act_value & 0xFF);
+
+        if(psaSIM_AccessSIMData() < 0)
+        {
+          TRACE_EVENT("FATAL ERROR");
+        }
+        break;
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_update_acm_cb   |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for updating ACM.
+
+*/
+
+void aoc_update_acm_cb(SHORT table_id)
+{
+  T_SIM_SET_PRM * pSIMSetPrm;  /* points to MM parameter set */
+
+  TRACE_FUNCTION ("aoc_update_acm_cb()");
+
+  switch (simShrdPrm.atb[table_id].errCode)
+  {
+    case SIM_NO_ERROR:
+      /*
+       * No error has occured, read ACM etc. again from SIM Card
+       */
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CACM );
+      aoc_sms ();
+      break;
+    
+    case SIM_CAUSE_PIN2_EXPECT:
+      /*
+       * An error has occured, maybe PIN2 is needed
+       */
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      if (strlen ((char *) pwd) AND
+          act_upd_op EQ FIRST_UPDATE)
+      {
+        /*
+         * Password is available and
+         * it is the first update, then
+         * try to verify PIN2
+         */
+        act_upd_op = VERIFY_PWD;
+        pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
+
+        cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
+        pSIMSetPrm -> PINType = PHASE_2_PIN_2;
+        simEntStat.curCmd     = AT_CMD_CACM;
+        simEntStat.entOwn     = simShrdPrm.owner = act_src_id;
+
+        if ( psaSIM_VerifyPIN() < 0 )  /* verify PIN */
+        {
+          TRACE_EVENT( "FATAL RETURN psaSIM in +CACM" );
+        }
+      }
+      else
+      {
+        /*
+         * PIN2 not available or second attempt
+         */
+        simEntStat.curCmd     = AT_CMD_NONE;
+        simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+        if (act_upd_op EQ FIRST_UPDATE)
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+               ( AT_CMD_CACM, CME_ERR_SimPin2Req );
+        }
+        else
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+                ( AT_CMD_CACM, CME_ERR_WrongPasswd );
+        }
+      }
+      break;
+    default:
+      /*
+       * Any other error, respective error code is returned 
+       */
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_CME, simEntStat.entOwn )
+        (
+          AT_CMD_CACM, 
+          cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
+        );
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_update_acmmax             |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function tries to set the ACMMAX field on the SIM card.
+
+*/
+
+void aoc_update_acmmax (UBYTE operation, ULONG value)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_update_acmmax()");
+
+  /*
+   * request table id for SIM SAP access
+   */
+  table_id   = psaSIM_atbNewEntry();
+  act_upd_op = operation;
+
+  if(table_id NEQ NO_ENTRY)
+  {
+    switch (operation)
+    {
+      case FIRST_UPDATE:
+        /*
+         * This is the first access to ACMMAX. It may fail,
+         * because PIN2 is needed.
+         */
+        act_value  = value;
+        /*lint -fallthrough*/
+      case SECOND_UPDATE:
+        /*
+         * This is the second access to ACMMAX after PIN entering.
+         */
+        simShrdPrm.atb[table_id].accType      = ACT_WR_DAT;
+        simShrdPrm.atb[table_id].reqDataFld   = SIM_ACMMAX;
+        simShrdPrm.atb[table_id].dataOff      = 0;
+        simShrdPrm.atb[table_id].dataLen      = 3;
+        simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+        simShrdPrm.atb[table_id].exchData     = sim_data;
+        simShrdPrm.atb[table_id].rplyCB       = aoc_update_acmmax_cb;
+        simShrdPrm.aId = table_id;
+        sim_data[0] = (UBYTE)(act_value >> 16);
+        sim_data[1] = (UBYTE)(act_value >> 8);
+        sim_data[2] = (UBYTE)(act_value & 0xFF);
+
+        if(psaSIM_AccessSIMData() < 0)
+        {
+          TRACE_EVENT("FATAL ERROR");
+        }
+        break;
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)               MODULE:  AOC                  |
+| STATE  : code                        ROUTINE: aoc_update_acmmax_cb |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for updating ACMMax.
+
+*/
+
+void aoc_update_acmmax_cb(SHORT table_id)
+{
+  T_SIM_SET_PRM * pSIMSetPrm;  /* points to MM parameter set */
+
+  TRACE_FUNCTION ("aoc_update_acmmax_cb()");
+
+  switch (simShrdPrm.atb[table_id].errCode)
+  {
+    case SIM_NO_ERROR:
+      /*
+       * No error has occured, read ACM etc. again from SIM Card
+       */
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CAMM );
+      aoc_sms ();
+
+      aoc_set_time_ut_charge ( ACI_NumParmNotPresent, 0L );
+      break;
+    case SIM_CAUSE_PIN2_EXPECT:
+      /*
+       * error has occured, maybe PIN2 is needed
+       */
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      if (strlen ((char *) pwd) AND
+          act_upd_op EQ FIRST_UPDATE)
+      {
+        /*
+         * Password is available and
+         * it is the first update, then
+         * try to verify PIN2
+         */
+        act_upd_op = VERIFY_PWD;
+        pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
+
+        cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
+        pSIMSetPrm -> PINType = PHASE_2_PIN_2;
+        simEntStat.curCmd     = AT_CMD_CAMM;
+        simEntStat.entOwn     = simShrdPrm.owner = act_src_id;
+
+        if ( psaSIM_VerifyPIN() < 0 )  /* verify PIN */
+        {
+          TRACE_EVENT( "FATAL RETURN psaSIM in +CAMM" );
+        }
+      }
+      else
+      {
+        /*
+         * PIN2 not available or second attempt
+         */
+        simEntStat.curCmd     = AT_CMD_NONE;
+        simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+        if (act_upd_op EQ FIRST_UPDATE)
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+               ( AT_CMD_CAMM, CME_ERR_SimPin2Req );
+        }
+        else
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+                ( AT_CMD_CAMM, CME_ERR_WrongPasswd );
+        }
+      }
+      break;
+    default:
+      /*
+       * Any other error, respective error code is returned 
+       */
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_CME, simEntStat.entOwn )
+        (
+          AT_CMD_CAMM, 
+          cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
+        );
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)      MODULE : AOC                           |
+| STATE  : code               ROUTINE: aoc_update_puct               |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function tries to modify the PUCT field on the SIM card.
+
+*/
+
+void aoc_update_puct (UBYTE operation, T_puct * value)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("aoc_update_puct()");
+
+  /*
+   * request table id for SIM SAP access
+   */
+  table_id   = psaSIM_atbNewEntry();
+  act_upd_op = operation;
+
+  if(table_id NEQ NO_ENTRY)
+  {
+    switch (operation)
+    {
+      case FIRST_UPDATE:
+        /*
+         * This is the first access to PUCT. It may fail,
+         * because PIN2 is needed.
+         */
+        if (aoc_set_puct_values (value) EQ FALSE)
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+               ( AT_CMD_CPUC, CME_ERR_OpNotAllow );
+
+          simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+          return;
+        }
+        /*lint -fallthrough*/
+      case SECOND_UPDATE:
+        /*
+         * This is the second access to PUCT after PIN entering.
+         */
+        simShrdPrm.atb[table_id].accType      = ACT_WR_DAT;
+        simShrdPrm.atb[table_id].reqDataFld   = SIM_PUCT;
+        simShrdPrm.atb[table_id].dataOff      = 0;
+        simShrdPrm.atb[table_id].dataLen      = 5;
+        simShrdPrm.atb[table_id].ntryUsdFlg   = TRUE;
+        simShrdPrm.atb[table_id].exchData     = sim_data;
+        simShrdPrm.atb[table_id].rplyCB       = aoc_update_puct_cb;
+        simShrdPrm.aId = table_id;
+        if(psaSIM_AccessSIMData() < 0)
+        {
+          TRACE_EVENT("FATAL ERROR");
+        }
+        break;
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_update_puct_cb  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Callback function for updating PUCT.
+
+*/
+
+void aoc_update_puct_cb(SHORT table_id)
+{
+  T_SIM_SET_PRM * pSIMSetPrm;  /* points to MM parameter set */
+  UBYTE         index;
+
+  TRACE_FUNCTION ("aoc_update_puct_cb()");
+
+  switch (simShrdPrm.atb[table_id].errCode)
+  {
+    case SIM_NO_ERROR:
+      /*
+       * No error has occured, read ACM etc. again from SIM Card
+       */
+      currency [0] = sim_data[0];
+      currency [1] = sim_data[1];
+      currency [2] = sim_data[2];
+      currency [3] = 0;
+      eppu         = (sim_data[3]<<4 & 0xFF0) + (sim_data[4] & 0x0F);
+      index        =  sim_data[4]>>4 & 0x0F;
+      if (index > 11)  /* only 0 to 11 */
+        index = 11;
+      exp          = ppu_values[index][0];
+      sexp         = ppu_values[index][1];
+
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CPUC );
+      aoc_sms ();
+      break;
+    case SIM_CAUSE_PIN2_EXPECT:
+      /*
+       * error has occured, maybe PIN2 is needed
+       */
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      if (strlen ((char *) pwd) AND
+          act_upd_op EQ FIRST_UPDATE)
+      {
+        /*
+         * Password is available and
+         * it is the first update, then
+         * try to verify PIN2
+         */
+        act_upd_op = VERIFY_PWD;
+        pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
+
+        cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
+        pSIMSetPrm -> PINType = PHASE_2_PIN_2;
+        simEntStat.curCmd     = AT_CMD_CPUC;
+        simEntStat.entOwn     = simShrdPrm.owner = act_src_id;
+
+        if ( psaSIM_VerifyPIN() < 0 )  /* verify PIN */
+        {
+          TRACE_EVENT( "FATAL RETURN psaSIM in +CAMM" );
+        }
+      }
+      else
+      {
+        /*
+         * PIN2 not available or second attempt
+         */
+        simEntStat.curCmd     = AT_CMD_NONE;
+        simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+        if (act_upd_op EQ FIRST_UPDATE)
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+               ( AT_CMD_CPUC, CME_ERR_SimPin2Req );
+        }
+        else
+        {
+          R_AT( RAT_CME, simEntStat.entOwn )
+                ( AT_CMD_CPUC, CME_ERR_WrongPasswd );
+        }
+      }
+      break;
+    default:
+      /*
+       * Any other error, respective error code is returned 
+       */
+      simEntStat.curCmd     = AT_CMD_NONE;
+      simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+      R_AT( RAT_CME, simEntStat.entOwn )
+        (
+          AT_CMD_CPUC, 
+          cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
+        );
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_set_puct_values |
++--------------------------------------------------------------------+
+
+  PURPOSE : Converts the PUCT values from string to SIM format.
+*/
+
+UBYTE aoc_set_puct_values(T_puct * puct)
+{
+  UBYTE first_digit  = FALSE;
+  UBYTE colon_found  = FALSE;
+  UBYTE position_dot = 0;
+  SHORT temp_pos     = 0;
+  SHORT position     = 0;
+  SHORT length       = 0;
+  ULONG eppu         = 0L;
+  ULONG temp_eppu    = 0L;
+  UBYTE i;
+
+  TRACE_FUNCTION ("aoc_set_puct_values()");
+
+  sim_data[0] = puct->currency [0];
+  sim_data[1] = puct->currency [1];
+  sim_data[2] = puct->currency [2];
+
+  for (i=0;i<20;i++)
+  {
+    if (puct->value[i] EQ '\0')
+      break;
+
+    if (first_digit)
+    {
+      /* at least one digit detected */
+      if (colon_found)
+      {
+        /* checking the digits after the colon */
+        switch (puct->value[i])
+        {
+          case '0':
+            /* zeros after the colon are counted */
+            temp_eppu = temp_eppu * 10 + (puct->value[i] - '0');
+            temp_pos++;
+            break;
+
+          default:
+            /* digits available before the colon */
+            eppu = (temp_eppu * 10) + (puct->value[i] - '0');
+            temp_eppu = eppu;
+            length = length + temp_pos + 1;
+            temp_pos = 0;
+            if (position_dot)
+            {
+              position = position_dot;
+              position_dot = 0;
+            }
+            break;
+        }
+      }
+      else
+      {
+        /* checking the digits before the colon  */
+        switch (puct->value[i])
+        {
+          case '0':
+            /* zeros before the colon are counted */
+            temp_eppu = temp_eppu * 10 + (puct->value[i] - '0');
+            temp_pos++;
+            break;
+
+          case '.':
+            colon_found = TRUE;
+            position_dot = position + temp_pos;
+            length += temp_pos;
+            temp_pos = 0;
+            break;
+
+          default:
+            /* digits available before the colon */
+            if (temp_pos)
+              eppu = (temp_eppu * 10) + (puct->value[i] - '0');
+            else
+              eppu = eppu * 10 + (puct->value[i] - '0');
+            temp_eppu = eppu;
+            length = length + temp_pos + 1;
+            position = position + temp_pos + 1;
+            temp_pos = 0;
+            break;
+        }
+      }
+    }
+    else
+    {
+      /* no digit found */
+      if (colon_found)
+      {
+        /* searching for the first digit after the colon
+         * e.g.  0.0034 */
+        switch (puct->value[i])
+        {
+          case '0':
+            /* count the number of zeros after the colon */
+            temp_pos++;
+            break;
+
+          default:
+            /* digits available before the colon */
+            first_digit = TRUE;
+            position -= temp_pos;
+            temp_pos  = 0;
+            temp_eppu = eppu = puct->value[i]-'0';
+            length++;
+            break;
+        }
+      }
+      else
+      {
+        /* checking the digits before the colon
+         * e.g 234.56  looking for the 2 */
+        switch (puct->value[i])
+        {
+          case '0':
+            /* leading zeros are ignored */
+            break;
+          case '.':
+            /* no digits before the colon, e.g.  0.23 */
+            colon_found = TRUE;
+            break;
+          default:
+            /* digits available before the colon */
+            first_digit = TRUE;
+            temp_eppu = eppu = puct->value[i]-'0';
+            position++;
+            length++;
+            break;
+        }
+      }
+    }
+
+    if (puct->value[i] EQ 0)
+      break;
+  }
+
+#if defined WIN32
+  {
+    TRACE_EVENT_P2("PUCT POS=%d LEN=%d", position, length);
+    TRACE_EVENT_P1("EPPU=%d", eppu);
+  }
+#endif
+
+  /*
+   * check the maximum of EPPU
+   */
+  if (eppu > 0xFFF)
+    return FALSE;
+
+  /*
+   * set the EPPU, SEXP and EXP for the SIM Card
+   */
+
+  sim_data[3] = (UBYTE)(eppu >> 4);
+  sim_data[4] = (UBYTE)(eppu & 0xF);
+
+
+  /*
+   * for the case : reset PUCT
+   */
+  if (!first_digit)
+  {
+    /*
+     * set the first 4 bits of the fifth bytes to 0 (exp2, exp1, exp0, sexp)
+     */
+    sim_data[4] = sim_data[4] & 0x0F;
+  }
+  else
+  {
+    if (!colon_found)
+    {
+      if (temp_pos)
+      {
+        sim_data[4] += (temp_pos << 5);
+      }
+      else
+      {
+        sim_data[4] += ((length - position) << 5);
+      }
+    }
+    else
+    {
+      if (position_dot NEQ 0)
+        sim_data[4] += ((length - position) << 5);
+      else
+        sim_data[4] += 0x10 + ((length - position) << 5);
+    }
+  }
+  return TRUE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_parameter       |
++--------------------------------------------------------------------+
+
+  PURPOSE : Copies the e-parameters of the facility IE.
+
+*/
+void aoc_parameter(SHORT Cid, T_FWD_CHG_ADVICE_INV * aoc_para)
+{
+  T_chargingInformation * charge;
+
+  TRACE_FUNCTION ("aoc_parameter()");
+
+  switch (aoc_para->forwardChargeAdviceArg.ssCode)
+  {
+    case(SS_CD_AOCI):
+      cc_aoc_table[Cid].aoci_active=TRUE;
+      break;
+    case(SS_CD_AOCC):   
+      cc_aoc_table[Cid].aoci_active=FALSE;
+      break;
+    default:
+      TRACE_EVENT_P1("UNEXPECTED SS_CODE in FWD_AOC %d, assume AOCC", aoc_para->forwardChargeAdviceArg.ssCode);
+      cc_aoc_table[Cid].aoci_active=FALSE;
+  }   
+
+  charge = &aoc_para->forwardChargeAdviceArg.chargingInformation;
+
+  cc_aoc_table[Cid].new_data_avail = TRUE; 
+
+  if (charge->v_e1)
+  {
+    if (cc_aoc_table[Cid].aoc_timer_running)
+    {
+      /* E1 is available, 4.3.e) special */
+      cc_aoc_table[Cid].e1_next        = aoc_getEVal(&charge->e1);
+      cc_aoc_table[Cid].e_next_bitmap |= E1_CHANGED;
+      TRACE_EVENT_P1("E1 = %u", cc_aoc_table[Cid].e1_next);
+    }
+    else
+    {
+      cc_aoc_table[Cid].e1             = aoc_getEVal(&charge->e1);
+      TRACE_EVENT_P1("E1 = %u", cc_aoc_table[Cid].e1);
+    }
+
+  }
+
+  if (charge->v_e2)
+  {
+    if (cc_aoc_table[Cid].aoc_timer_running)
+    {
+      /* E2 is available, 4.3.e) special */
+      cc_aoc_table[Cid].e2_next        = aoc_getEVal(&charge->e2);
+      cc_aoc_table[Cid].e_next_bitmap |= E2_CHANGED;
+      TRACE_EVENT_P1("E2 = %u", cc_aoc_table[Cid].e2_next);
+    }
+    else
+    {
+      cc_aoc_table[Cid].e2             = aoc_getEVal(&charge->e2);
+      TRACE_EVENT_P1("E2 = %u", cc_aoc_table[Cid].e2);
+    }
+  }
+
+  if (charge->v_e3)
+  {
+    /* Special handling of E3, see  AOC08226 */
+    cc_aoc_table[Cid].e3_next        = aoc_getEVal(&charge->e3);
+    cc_aoc_table[Cid].e_next_bitmap |= E3_CHANGED;
+    TRACE_EVENT_P1("E3 = %u", cc_aoc_table[Cid].e3_next);
+  }
+
+  if (charge->v_e4)
+  {
+    cc_aoc_table[Cid].e4        = aoc_getEVal(&charge->e4);
+    cc_aoc_table[Cid].e_next_bitmap |= E4_CHANGED;
+    TRACE_EVENT_P1("E4 = %u", cc_aoc_table[Cid].e4);
+  }
+
+  /* e5 and e6 are not (yet?) supported */
+  if (charge->v_e5)
+  {
+    cc_aoc_table[Cid].e5        = aoc_getEVal(&charge->e5);
+    TRACE_EVENT_P1("E5 = %u", cc_aoc_table[Cid].e5);
+  }
+
+  if (charge->v_e6)
+  {
+    cc_aoc_table[Cid].e6        = aoc_getEVal(&charge->e6);
+    TRACE_EVENT_P1("E6 = %u", cc_aoc_table[Cid].e6);
+  }
+
+  if (charge->v_e7)
+  {
+    if (cc_aoc_table[Cid].aoc_timer_running)
+    {
+      /* E7 is available, 4.3.e) special */
+      cc_aoc_table[Cid].e7_next        = aoc_getEVal(&charge->e7);
+      cc_aoc_table[Cid].e_next_bitmap |= E7_CHANGED;
+      TRACE_EVENT_P1("E7 = %u", cc_aoc_table[Cid].e7_next);
+    }
+    else
+    {
+      cc_aoc_table[Cid].e7             = aoc_getEVal(&charge->e7);
+      TRACE_EVENT_P1("E7 = %u", cc_aoc_table[Cid].e7);
+    }
+
+  }
+
+  if(cc_aoc_table[Cid].e_next_bitmap & (E1_CHANGED | E2_CHANGED | E7_CHANGED))
+  {
+    /* e3 should be applied to the parameters held in abeyance, see  AOC08226 */
+  }
+  else
+  {
+    /* bring e3 immediately into operation */
+    cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
+  }
+
+
+
+  if(cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED)
+  {
+    /* e3 is updated recalc is needed now */
+    aoc_calculate_charging_parameter_part2( Cid );
+  }
+
+/*
+  if(cc_aoc_table[Cid].e_next_bitmap & E4_CHANGED)
+  {
+    /* if e4 is updated while charging running, charge amount now */
+   /* if (cc_aoc_table[Cid].aoc_timer_running EQ TRUE)
+    {
+      aoc_calculate_charging_parameter_part1( Cid );
+      aoc_increment_initial_charge( Cid );
+      cc_aoc_table[Cid].e_next_bitmap &= ~E4_CHANGED;
+    }
+  }
+*/
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_getEVal         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Assembles e-value out of the facility IE.
+*/
+
+USHORT aoc_getEVal( void * eBuf )
+{
+  T_e1    *pE  = (T_e1*)eBuf;
+  USHORT  val = 0;
+  UBYTE   len;
+
+  for( len = 0; len < pE->c_e_val; len++ )
+  {
+    val<<= 8;
+    val += pE->e_val[len];
+  }
+
+  return( val );
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)                MODULE:  AOC                 |
+| STATE  : code                         ROUTINE: aoc_send_ccm        |
++--------------------------------------------------------------------+
+
+  PURPOSE : The ccm is forwarded if at least one of the calls is
+            active.
+*/
+
+void aoc_send_ccm ()
+{
+  ULONG ccm_output;
+  T_ACI_CMD_SRC idx;
+
+  if (qAT_CallActive())
+  {
+    /* call back function to notify the MMI */
+    for( idx = 0; idx < CMD_SRC_MAX; idx++ )
+    {
+      /*
+       * forward ccm in whole units to MMI
+       */
+      ccm_output = MC_AOC_ROUND_UP(ccm);
+
+      R_AT( RAT_CCCM, idx )( &ccm_output );
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE:  AOC                    |
+| STATE  : code                      ROUTINE: aoc_set_time_ut_charge |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to set the period of time until
+            the next charging occur.
+*/
+
+void aoc_set_time_ut_charge ( SHORT cId, T_TIME      time )
+{
+  UBYTE mode = AOC_CALL_TIMER_ELAPSED; /* indicates the elapsed */
+                                       /* timer                 */
+  /*
+   * in case an AoC timer is elapsed the time until
+   * next charging will be fixed to the new value
+   */
+  if ( cId NEQ ACI_NumParmNotPresent )
+  {
+    cc_aoc_table[cId].time_ut_charge = time;
+    mode                             = AOC_AOC_TIMER_ELAPSED;
+  }
+
+  aoc_calc_expct_charge ( mode );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)             MODULE:  AOC                    |
+| STATE  : code                      ROUTINE: aoc_calc_expct_charge  |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to calculate the amount of charge
+            which is going to be consumed during the period of time
+            fixed by AOC_MAX_REMAIN_CALL_TIME.
+*/
+
+void aoc_calc_expct_charge ( UBYTE mode )
+{
+  ULONG         expct_charge  = 0;   /* expected charge            */
+  T_TIME        remain_time;         /* remaining time until next  */
+  ULONG         num_chrg_pts;        /* number of charging points  */
+  UBYTE         idx;                 /* used for counting          */
+  BOOL          aoc_running = FALSE; /* indicates whether at least */
+                                     /* one AoC timer is running   */
+
+  for ( idx = 0; idx < MAX_CALL_NR; idx++ )
+  {
+    if ( cc_aoc_table[idx].aoc_timer_running AND cc_aoc_table[idx].e1 )
+    {
+      aoc_running = TRUE;
+
+      if ( mode EQ AOC_CALL_TIMER_ELAPSED )
+      {
+#if defined (WIN32)
+        TRACE_EVENT_P1("time to charge: %d ms",
+                       cc_aoc_table[idx].time_ut_charge - AOC_THOUSAND_MILLISECONDS);
+#endif
+
+        /* in case the call timer is elapsed the actual
+         * time until next charging will be calculated */
+        if (cc_aoc_table[idx].time_ut_charge >= AOC_THOUSAND_MILLISECONDS)
+        {
+          cc_aoc_table[idx].time_ut_charge -= AOC_THOUSAND_MILLISECONDS;
+        }
+        else
+        {
+          /* calculate the expected charging intervals based on the E parameter */
+          if ( cc_aoc_table[idx].new_data_avail EQ TRUE AND
+               cc_aoc_table[idx].e_next_bitmap      & E7_CHANGED )
+          {
+            cc_aoc_table[idx].time_ut_charge = aoc_calc_time_ut_charge ( idx, E7_CHANGED );
+          }
+          else if ( cc_aoc_table[idx].e_next_bitmap & E2_CHANGED )
+          {
+            cc_aoc_table[idx].time_ut_charge = aoc_calc_time_ut_charge ( idx, E2_CHANGED );
+          }
+          else
+          {
+            cc_aoc_table[idx].time_ut_charge = ~0L;
+          }
+
+          /* calculate the expected initial charge and
+           * add to the expected charge */
+          /* The fixed amount is charged immediately and not somewhen later
+          if ( cc_aoc_table[idx].new_data_avail EQ TRUE         AND
+               cc_aoc_table[idx].e_bitmap       &  E4_AVAILABLE     )
+          {
+            expct_charge += ( ( ULONG ) cc_aoc_table[idx].e3   *
+                              ( ULONG ) cc_aoc_table[idx].e4 ) / 10;
+          }
+          */
+        }
+      }
+
+      /* calculate expected charge for next AOC_MAX_REMAIN_CALL_TIME milliseconds */
+      num_chrg_pts = 1;
+
+      if ( cc_aoc_table[idx].time_ut_charge <= AOC_MAX_REMAIN_CALL_TIME )
+      {
+        if (cc_aoc_table[idx].e2)
+        {
+          remain_time = AOC_MAX_REMAIN_CALL_TIME -
+                                     cc_aoc_table[idx].time_ut_charge;
+          num_chrg_pts +=
+              (ULONG)(remain_time / E_IN_MS ( cc_aoc_table[idx].e2 ));
+        }
+
+        expct_charge += (   num_chrg_pts *
+                          ( cc_aoc_table[idx].e1 * cc_aoc_table[idx].e3 ) / 10 );
+      }
+    }
+  }
+
+  aoc_calc_acm_wrn_evnt ( expct_charge, aoc_running );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)              MODULE:  AOC                   |
+| STATE  : code                       ROUTINE: aoc_calc_acm_wrn_evnt |
++--------------------------------------------------------------------+
+
+  PURPOSE : In case the remaining credit is low a call timer warning
+            event is generated.
+*/
+
+void aoc_calc_acm_wrn_evnt ( ULONG charge, BOOL aoc_running )
+{
+  ULONG           credit;      /* remaining credit             */
+  ULONG           acm_for_sim; /* lack of the actual ACM value */
+  T_ACI_CCWV_CHRG charging;    /* CCWV mode indicated to MMI   */
+
+  /*
+   * the update on the SIM is the difference between the rounded up
+   * value of the current CCM and the old CCM (already rounded up)
+   */
+  acm_for_sim = MC_AOC_ROUND_UP(ccm) - MC_AOC_ROUND_UP(ccm_already_incremented);
+  credit = acmmax - acm - ( acm_for_sim * 100 );
+
+#if defined (WIN32)
+  {
+    TRACE_EVENT_P2("AoC charge for next %u ms = %u", AOC_MAX_REMAIN_CALL_TIME, charge );
+  }
+#endif
+
+  if ( aoc_running EQ TRUE )
+  {
+    if ( charge >= credit )
+      charging = CCWV_CHRG_Shortage;
+    else
+      charging = CCWV_CHRG_Abundance;
+  }
+  else
+    charging = CCWV_CHRG_Termination;
+
+  aoc_ntfy_acm_wrn_evnt ( charging );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)              MODULE:  AOC                   |
+| STATE  : code                       ROUTINE: aoc_ntfy_acm_wrn_evnt |
++--------------------------------------------------------------------+
+
+  PURPOSE : Notifies the MMI about the call meter warning event.
+
+*/
+void aoc_ntfy_acm_wrn_evnt ( T_ACI_CCWV_CHRG charging )
+{
+  T_ACI_CMD_SRC idx;
+
+  if ( ccwv_charging NEQ charging )
+  {
+    ccwv_charging = charging;
+
+    for( idx=0; idx<CMD_SRC_MAX; idx++ )
+    {
+      R_AT( RAT_CCWV, idx )( charging );
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: GSM-PS (6147)            MODULE:  AOC                     |
+| STATE  : code                     ROUTINE: aoc_calc_time_ut_charge |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function calculates the new time to charge with
+            respect to the previous value.
+
+*/
+T_TIME aoc_calc_time_ut_charge       ( SHORT cId,
+                                       UBYTE e_value_flag )
+{
+  T_TIME       new_time = ~0L; /* new time until next charging */
+  T_TIME       e_value;        /* interval value               */
+
+  switch ( e_value_flag )
+  {
+    case (E2_CHANGED): e_value = E_IN_MS ( cc_aoc_table[cId].e2 );
+      break;
+    case (E7_CHANGED): e_value = E_IN_MS ( cc_aoc_table[cId].e7 );
+      break;
+    default            : e_value = 0L;
+      break;
+  }
+
+  if ( e_value <= ( AOC_THOUSAND_MILLISECONDS - cc_aoc_table[cId].time_ut_charge ) )
+  {
+    new_time = e_value;
+  }
+  else if ( e_value NEQ 0L )
+  {
+    new_time = e_value - ( AOC_THOUSAND_MILLISECONDS - cc_aoc_table[cId].time_ut_charge );
+  }
+
+  return new_time;
+}
+