FreeCalypso > hg > fc-magnetite
view src/aci2/aci/aoc.c @ 356:984df0753560
gsmcomp.c: voice-only config partition pool sizing fixes from Citrine
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 25 Dec 2017 02:14:55 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | 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; }