comparison 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
comparison
equal deleted inserted replaced
2:c41a534f33c6 3:93999a60b835
1 /*
2 +-----------------------------------------------------------------------------
3 | Project : GSM-PS (6147)
4 | Modul : AOC
5 +-----------------------------------------------------------------------------
6 | Copyright 2002 Texas Instruments Berlin, AG
7 | All rights reserved.
8 |
9 | This file is confidential and a trade secret of Texas
10 | Instruments Berlin, AG
11 | The receipt of or possession of this file does not convey
12 | any rights to reproduce or disclose its contents or to
13 | manufacture, use, or sell anything it may describe, in
14 | whole, or in part, without the specific written consent of
15 | Texas Instruments Berlin, AG.
16 +-----------------------------------------------------------------------------
17 | Purpose : This module defines the functions for the
18 | advice of charge handling of ACI.
19 +-----------------------------------------------------------------------------
20 */
21
22 #include "aci_all.h"
23
24 #include "l4_tim.h"
25
26 #include "pcm.h"
27
28 #include "aci_cmh.h"
29
30 #include "psa.h"
31 #include "psa_sim.h"
32 #include "psa_mm.h"
33
34 #include "aoc.h"
35 #include "psa_cc.h"
36 #include "cmh.h"
37 #include "cmh_cc.h"
38
39 #ifdef SIM_TOOLKIT
40 #include "psa_sat.h"
41 #endif
42
43 #ifdef FAX_AND_DATA
44 #include "aci_fd.h"
45 #endif /* of #ifdef FAX_AND_DATA */
46
47 #ifdef UART
48 #include "dti.h"
49 #include "dti_conn_mng.h"
50 #endif
51
52 #include "cmh_sim.h"
53
54 #define MC_AOC_ROUND_UP(X) ((((X)%100) EQ 0) ? ((X)/100) : (((X)/100) + 1))
55 #define E_IN_MS(X) ((X)*100)
56
57 /********* current define *********************************************/
58 static UBYTE aoc_state = AOC_NULL; /* actual AoC state */
59 static UBYTE sim_data[10]; /* SIM data exchange */
60 static UBYTE currency [4]; /* used for currency */
61 static ULONG ccm; /* current call meter */
62 static ULONG ccm_already_incremented; /* value of CCM increm. */
63 static ULONG acm; /* accumulated call meter */
64 static UBYTE acm_increment_flag; /* counter for incr. ACM */
65 static ULONG acmmax; /* maximum of ACM */
66 static ULONG eppu; /* elementary unit price */
67 static ULONG sexp; /* sign of expression */
68 static ULONG exp; /* expression value */
69 static UBYTE pwd [9]; /* password */
70 static UBYTE act_upd_op; /* actual update operation*/
71 static ULONG act_value; /* new value for ACM(Max) */
72 static T_ACI_CMD_SRC act_src_id; /* source of AT command */
73
74 GLOBAL T_CC_AOC_TBL cc_aoc_table[MAX_CALL_NR]; /* AoC Call Table */
75 EXTERN T_PCEER causeMod;
76 EXTERN SHORT causeCeer;
77
78 static ULONG cct; /* current call timer */
79 /*static ULONG act; *//* accumulated call timer */ /* never used */
80 static USHORT ct_running; /* call timer is running */
81 static UBYTE limit_reached = FALSE; /* ACM over limit ? */
82
83 static const ULONG ppu_values [12][2] =
84 {
85 /* exp, sexp index */
86 1L, 0L, /* 0 */
87 1L, 0L, /* 1 */
88 10L, 0L, /* 2 */
89 10L, 1L, /* 3 */
90 100L, 0L, /* 4 */
91 100L, 1L, /* 5 */
92 1000L, 0L, /* 6 */
93 1000L, 1L, /* 7 */
94 10000L, 0L, /* 8 */
95 10000L, 1L, /* 9 */
96 100000L, 0L, /* 10 */
97 100000L, 1L /* 11 */
98 };
99
100 #ifdef SIM_TOOLKIT
101 BOOL aoc_update (int ref, T_SIM_FILE_UPDATE_IND *fu);
102 #endif
103 static UBYTE ccwv_charging = CCWV_CHRG_Termination;
104
105 /********* function prototypes **************************************/
106 void aoc_calc_acm_wrn_evnt ( ULONG charge,
107 BOOL aoc_running );
108
109 void aoc_set_time_ut_charge ( SHORT cId,
110 T_TIME time );
111 void aoc_calc_expct_charge ( UBYTE mode );
112 void aoc_ntfy_acm_wrn_evnt ( T_ACI_CCWV_CHRG charging );
113
114 T_TIME aoc_calc_time_ut_charge ( SHORT cId,
115 UBYTE e_value_flag );
116
117 void aoc_start_info_newcall (SHORT Cid);
118 void aoc_start_newinfo_existingcall (SHORT Cid);
119
120 static void aoc_calculate_charging_parameter_part1 (SHORT Cid);
121 static void aoc_calculate_charging_parameter_part2 (SHORT Cid);
122 /********* functions ************************************************/
123 /*
124 +--------------------------------------------------------------------+
125 | PROJECT: GSM-PS (6147) MODULE: AOC |
126 | STATE : code ROUTINE: aoc_init |
127 +--------------------------------------------------------------------+
128
129
130 PURPOSE : Initialisation of the Advice of charge module. The function
131 is called after PIN entering. The actual phase of the SIM
132 card, the SIM service table and the PCM entry is checked.
133 The return value indicates whether AoC is supported.
134
135 */
136
137 UBYTE aoc_init (UBYTE phase, UBYTE * sim_service_table)
138 {
139 EF_MSSUP mssup;
140 UBYTE version;
141
142 TRACE_FUNCTION ("aoc_init()");
143
144 aoc_state = AOC_DISABLE;
145 /* Check Phase. It must be at least Phase 2 */
146 if (phase <= PHASE_1_SIM)
147 return FALSE;
148 TRACE_EVENT ("AOC: Card >= Phase 2");
149
150 /* Check SIM Service Table */
151 if (aoc_ssc(SRV_AOC,sim_service_table) NEQ ALLOCATED_AND_ACTIVATED)
152 return FALSE;
153 TRACE_EVENT ("AOC: Card supports AoC");
154
155 /* check PCM entry in MSCAP field */
156 pcm_Init ();
157 pcm_ReadFile ((UBYTE *)EF_MSSUP_ID, SIZE_EF_MSSUP, (UBYTE *)&mssup, &version);
158 if (FldGet(mssup.feat1, AoC))
159 {
160 /* start reading ACM, ACMMax and PUCT */
161 TRACE_EVENT ("AOC: MS supports AoC");
162 aoc_state = AOC_ENABLE;
163 aoc_read_acm ();
164 return TRUE;
165 }
166
167 #ifdef _SIMULATION_
168 aoc_state = AOC_ENABLE;
169 return TRUE;
170 #else
171 return FALSE;
172 #endif
173
174 }
175
176 /*
177 +--------------------------------------------------------------------+
178 | PROJECT: GSM-PS (6147) MODULE: AOC |
179 | STATE : code ROUTINE: aoc_reset |
180 +--------------------------------------------------------------------+
181
182 PURPOSE : Deactivation of AoC Service. Necessary, when SIM card
183 becomes unavailable
184 */
185
186 void aoc_reset (void)
187 {
188 TRACE_FUNCTION ("aoc_reset()");
189 aoc_state = AOC_DISABLE;
190 }
191
192 /*
193 +--------------------------------------------------------------------+
194 | PROJECT: GSM-PS (6147) MODULE: AOC |
195 | STATE : code ROUTINE: aoc_sms |
196 +--------------------------------------------------------------------+
197
198
199 PURPOSE : Indication that a SMS has received. This can be a trigger
200 for changed ACM or ACMMax on the SIM card.
201 */
202
203 void aoc_sms (void)
204 {
205 TRACE_FUNCTION ("aoc_sms()");
206 if (aoc_state EQ AOC_ENABLE)
207 {
208 /* start reading ACM, ACMMax and PUCT again */
209 aoc_read_acm ();
210 }
211 }
212
213 /*
214 +--------------------------------------------------------------------+
215 | PROJECT: GSM-PS (6147) MODULE: AOC |
216 | STATE : code ROUTINE: aoc_update |
217 +--------------------------------------------------------------------+
218
219 PURPOSE : Evaluation of File Change Notification and update AOC,
220 if required.
221 */
222
223 #ifdef SIM_TOOLKIT
224 BOOL aoc_update (int ref, T_SIM_FILE_UPDATE_IND *fu)
225 {
226 BOOL found = FALSE;
227 int i;
228
229 TRACE_FUNCTION ("aoc_update ()");
230
231 if (aoc_state NEQ AOC_ENABLE)
232 return TRUE; /* not used at all! */ /* AOC not supported */
233
234 for (i = 0; i < (int)fu->val_nr; i++)
235 {
236 if (fu->file_id[i] EQ SIM_ACM OR
237 fu->file_id[i] EQ SIM_ACMMAX OR
238 fu->file_id[i] EQ SIM_PUCT)
239 {
240 found = TRUE;
241 break;
242 }
243 }
244
245 if (found)
246 {
247 simShrdPrm.fuRef = ref;
248 aoc_read_acm ();
249 return FALSE;
250 }
251 else
252 {
253 simShrdPrm.fuRef = -1; /* no update needed */
254 return TRUE;
255 }
256 }
257 #endif
258
259 /*
260 +--------------------------------------------------------------------+
261 | PROJECT: GSM-PS (6147) MODULE: AOC |
262 | STATE : code ROUTINE: aoc_info |
263 +--------------------------------------------------------------------+
264
265 PURPOSE : Information of the Advice of charge module. The following
266 causes are defined:
267 AOC_START_TIME Start call time measurements.
268 AOC_STOP_TIME Stop call timer measurements.
269 AOC_START_AOC Advice of Charge is started.
270 AOC_SUSPEND_AOC Suspension of Call.
271 AOC_RESUME_AOC Resumption of Call.
272 */
273
274 UBYTE aoc_info (SHORT Cid, UBYTE cause)
275 {
276 T_SIM_SET_PRM * pSIMSetPrm; /* points to SIM parameter set */
277 BOOL calFlg; /* call flag */
278
279 TRACE_FUNCTION ("aoc_info()");
280
281 switch (cause)
282 {
283 case AOC_START_TIME: /* Indication of a new call. */
284 #ifdef _SIMULATION_
285 TRACE_EVENT ("AOC_START_TIME");
286 #endif
287 /* Call Time Measurements shall be
288 * started if it is the first call (ct_runnning = 0) */
289 if (ct_running EQ 0)
290 {
291 /* this is the first call. Then start call timer (periodic)
292 * and clear current calltimer value and current call meter. */
293 cct = ccm = ccm_already_incremented = 0L;
294 vsi_t_pstart (VSI_CALLER AOC_CALLTIMER, AOC_THOUSAND_MILLISECONDS, AOC_THOUSAND_MILLISECONDS);
295
296 pSIMSetPrm = &simShrdPrm.setPrm[CMD_SRC_LCL];
297 simShrdPrm.synCs = SYNC_START_CALL;
298 psaSIM_SyncSIM();
299 }
300
301 cmhCC_flagCall( Cid, &ct_running );
302
303 /* Clear aoc table parameter */
304 memset (&cc_aoc_table[Cid], 0, sizeof(T_CC_AOC_TBL));
305 break;
306
307 case AOC_STOP_TIME: /* Indication of the end of a call. */
308 #ifdef _SIMULATION_
309 TRACE_EVENT ("AOC_STOP_TIME");
310 #endif
311 TRACE_EVENT_P1("CT Running = %4X", ct_running);
312 calFlg = cmhCC_tstAndUnflagCall( Cid, &ct_running );
313
314 /*Call Time Measurements shall be
315 * stopped if it is the last call (ct_runnning <= 1) */
316 if (ct_running EQ 0 AND calFlg)
317 {
318 /* this is the last call. Then stop call timer. */
319 TRACE_EVENT ("Last Call Stop Call Timer");
320 vsi_t_stop (VSI_CALLER AOC_CALLTIMER);
321
322 pSIMSetPrm = &simShrdPrm.setPrm[CMD_SRC_LCL];
323 simShrdPrm.synCs = SYNC_STOP_CALL;
324 psaSIM_SyncSIM();
325
326 aoc_ntfy_acm_wrn_evnt ( CCWV_CHRG_Termination );
327 }
328
329 if (cc_aoc_table[Cid].aoc_timer_running) /* stop AoC timer if running */
330 {
331 vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER+Cid));
332 cc_aoc_table[Cid].aoc_timer_running = FALSE;
333 aoc_increment_charge (0L, TRUE); /* add rest to SIM */
334 }
335 break;
336
337 case AOC_START_AOC: /* Advice of Charge information has received for the indicated call. */
338 #ifdef _SIMULATION_
339 TRACE_EVENT ("*** AOC_START_AOC");
340 #endif
341 TRACE_EVENT_P2("AOC started Cid = %u State = %u", Cid, aoc_state);
342
343 if (aoc_state EQ AOC_ENABLE) /* AoC is supported */
344 {
345 limit_reached = FALSE;
346
347 if (cc_aoc_table[Cid].aoc_timer_running)
348 aoc_start_newinfo_existingcall(Cid);
349 else
350 aoc_start_info_newcall(Cid);
351
352 return TRUE;
353 }
354 else /* AoC not supported */
355 {
356 TRACE_EVENT ("AOC not supported");
357 return FALSE;
358 }
359
360 case AOC_SUSPEND_AOC: /* Suspension of Call is indicated. */
361 #ifdef _SIMULATION_
362 TRACE_EVENT ("*** AOC_SUSPEND_AOC");
363 #endif
364 if (aoc_state EQ AOC_ENABLE AND
365 cc_aoc_table[Cid].aoc_timer_running) /* AoC timer is running, then stop it. */
366 {
367 /* save remaining timeslice prior stopping the timer */
368 vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
369 vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
370
371 cc_aoc_table[Cid].aoc_timer_running = FALSE;
372 }
373 break;
374
375 case AOC_RESUME_AOC: /* Resumption of Call is indicated. */
376 #ifdef _SIMULATION_
377 TRACE_EVENT ("*** AOC_RESUME_AOC");
378 #endif
379 if (aoc_state EQ AOC_ENABLE AND
380 aoc_non_zero_cai (Cid))
381 {
382 /* AoC info is available, then start again. calculate the remaining time */
383 vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
384 cc_aoc_table[Cid].remaining_time,
385 cc_aoc_table[Cid].next_interval);
386 cc_aoc_table[Cid].aoc_timer_running = TRUE;
387
388 aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
389 }
390 break;
391
392 case AOC_CALL_CONNECTED: /* Call active state of a Call is indicated. */
393 #ifdef _SIMULATION_
394 TRACE_EVENT ("*** AOC_CALL_CONNECTED");
395 #endif
396 if (aoc_state EQ AOC_ENABLE AND
397 aoc_non_zero_cai (Cid))
398 {
399 /* AoC info is available, then start send initial CCM value to MMI. */
400 aoc_send_ccm ();
401 }
402 break;
403
404 default:
405 #ifdef _SIMULATION_
406 TRACE_EVENT ("*** Wrong cause ***");
407 #endif
408 break;
409
410 }
411 return TRUE;
412 }
413
414 /*
415 +--------------------------------------------------------------------+
416 | PROJECT: GSM-PS (6147) MODULE: AOC |
417 | STATE : code ROUTINE: aoc_get_values |
418 +--------------------------------------------------------------------+
419
420 PURPOSE : Request of Advice of Charge Values.
421 */
422
423 void aoc_get_values (UBYTE value_type, void * value)
424 {
425 ULONG * longPtr = value;
426 T_puct_raw * raw_puct;
427
428 TRACE_FUNCTION ("aoc_get_values()");
429
430 switch (value_type)
431 {
432 case AOC_CTV: /* Current Timer Value */
433 *longPtr = cct;
434 break;
435
436 case AOC_CCM: /* Current Call Meter Value */
437 #if defined _SIMULATION_
438 TRACE_EVENT_P1("CCM = %u", MC_AOC_ROUND_UP(ccm));
439 #endif
440 *longPtr = MC_AOC_ROUND_UP(ccm);
441 break;
442
443 case AOC_ACM: /* Accumulated Call Meter Value */
444 *longPtr = MC_AOC_ROUND_UP(acm);
445 break;
446
447 case AOC_ACMMAX: /* Maximum Accumulated Call Meter Value */
448 *longPtr = MC_AOC_ROUND_UP(acmmax);
449 break;
450
451 case AOC_PUCT: /* Price per Unit and Currency */
452 aoc_calculate_puct (1L, (T_puct *)value);
453 break;
454
455 case AOC_PUCT_RAW: /* Price per Unit and Currency as RAW data */
456 raw_puct = (T_puct_raw *)value;
457 raw_puct->exp = exp;
458 raw_puct->sexp = sexp;
459 raw_puct->eppu = eppu;
460 memcpy (raw_puct->currency, currency, 4);
461 break;
462
463 case AOC_CCM_PUCT: /* CCM in Price per Unit and Currency */
464 aoc_calculate_puct (MC_AOC_ROUND_UP(ccm), (T_puct *)value);
465 break;
466
467 case AOC_ACM_PUCT: /* ACM in Price per Unit and Currency */
468 aoc_calculate_puct (MC_AOC_ROUND_UP(acm), (T_puct *)value);
469 break;
470
471 case AOC_ACMMAX_PUCT: /* ACMMax in Price per Unit and Currency */
472 aoc_calculate_puct (MC_AOC_ROUND_UP(acmmax), (T_puct *)value);
473 break;
474 }
475 }
476
477 /*
478 +--------------------------------------------------------------------+
479 | PROJECT: GSM-PS (6147) MODULE: AOC |
480 | STATE : code ROUTINE: aoc_set_values |
481 +--------------------------------------------------------------------+
482
483 PURPOSE : Setting of Advice of charge values.
484 */
485
486 T_ACI_RETURN aoc_set_values (T_ACI_CMD_SRC srcId,
487 UBYTE value_type,
488 void *value,
489 UBYTE *password)
490 {
491 TRACE_FUNCTION ("aoc_set_values()");
492
493 /* Store Password, if available and start writing to the SIM Card. */
494 memcpy (pwd, password, 9);
495 act_src_id = srcId;
496
497 /* AOC not supported in SIM, Check for aoc_state return AT_FAIL */
498 if( aoc_state NEQ AOC_ENABLE )
499 {
500 return( AT_FAIL );
501 }
502
503 switch (value_type)
504 {
505 case AOC_ACM:
506 aoc_update_acm (FIRST_UPDATE, (ULONG)value);
507 break;
508
509 case AOC_ACMMAX:
510 aoc_update_acmmax (FIRST_UPDATE, (ULONG)value);
511 break;
512
513 case AOC_PUCT:
514 aoc_update_puct (FIRST_UPDATE, (T_puct *)value);
515 break;
516 }
517
518 return( AT_EXCT );
519 }
520
521 /*
522 +--------------------------------------------------------------------+
523 | PROJECT: GSM-PS (6147) MODULE: AOC |
524 | STATE : code ROUTINE: aoc_check_moc |
525 +--------------------------------------------------------------------+
526
527 PURPOSE : The function checks whether ACM is greater than ACMMax.
528 In this case only emergency calls are allowed for mobile
529 originated call direction.
530 */
531
532 UBYTE aoc_check_moc (void)
533 {
534 TRACE_FUNCTION ("aoc_check_moc()");
535
536 return aoc_check_acm();
537 }
538
539
540 /*
541 +--------------------------------------------------------------------+
542 | PROJECT: GSM-PS (6147) MODULE: AOC |
543 | STATE : code ROUTINE: aoc_ssc |
544 +--------------------------------------------------------------------+
545
546 PURPOSE : Check SIM service status. The value of service nr is
547 extracted from the SIM service table.
548 */
549
550 UBYTE aoc_ssc (UBYTE nr, UBYTE * serv_table)
551 {
552 TRACE_FUNCTION ("aoc_ssc()");
553
554 if (nr > MAX_SRV_TBL*4)
555 {
556 TRACE_ERROR ("serv_table overflow in pb_ssc()");
557 return NO_ALLOCATED;
558 }
559
560 return ( *(serv_table+(nr-1)/4) >> (((nr-1)&3)*2) & 0x03);
561 }
562
563
564 /*
565 +--------------------------------------------------------------------+
566 | PROJECT: GSM-PS (6147) MODULE: AOC |
567 | STATE : code ROUTINE: aoc_read_acm |
568 +--------------------------------------------------------------------+
569
570 PURPOSE : The function starts reading of the SIM field ACM.
571 */
572
573 void aoc_read_acm (void)
574 {
575 SHORT table_id;
576
577 TRACE_FUNCTION ("aoc_read_acm()");
578
579 table_id = psaSIM_atbNewEntry();
580
581 if(table_id NEQ NO_ENTRY)
582 {
583 simShrdPrm.atb[table_id].accType = ACT_RD_REC;
584 simShrdPrm.atb[table_id].reqDataFld = SIM_ACM;
585 simShrdPrm.atb[table_id].recNr = 1;
586 simShrdPrm.atb[table_id].dataLen = 3;
587 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
588 simShrdPrm.atb[table_id].exchData = sim_data;
589 simShrdPrm.atb[table_id].rplyCB = aoc_read_acm_cb;
590
591 simShrdPrm.aId = table_id;
592 if(psaSIM_AccessSIMData() < 0)
593 {
594 TRACE_EVENT("FATAL ERROR");
595 }
596 }
597 }
598
599 /*
600 +--------------------------------------------------------------------+
601 | PROJECT: GSM-PS (6147) MODULE: AOC |
602 | STATE : code ROUTINE: aoc_read_acm_cb |
603 +--------------------------------------------------------------------+
604
605 PURPOSE : Callback function for reading ACM.
606 */
607
608 void aoc_read_acm_cb(SHORT table_id)
609 {
610 TRACE_FUNCTION ("aoc_read_acm_cb()");
611
612 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
613
614 if (simShrdPrm.atb[table_id].errCode NEQ SIM_NO_ERROR)
615 {
616 /* ACM is not readable, disable set to default values */
617 acm=0L;
618 TRACE_EVENT ("AOC: Card has no ACM field");
619 #ifdef SIM_TOOLKIT
620 if (simShrdPrm.fuRef >= 0)
621 {
622 psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
623 }
624 #endif
625 }
626 else
627 {
628 /* calculate ACM and start reading ACMMax */
629 acm = (sim_data[0]<<16) + (sim_data[1]<<8) + sim_data[2];
630 acm *= 100; /* internal unit is 1/100 */
631 TRACE_EVENT_P1("ACM value = %u", (USHORT)acm);
632 aoc_read_acmmax ();
633 }
634 }
635
636
637 /*
638 +--------------------------------------------------------------------+
639 | PROJECT: GSM-PS (6147) MODULE: AOC |
640 | STATE : code ROUTINE: aoc_read_acmmax |
641 +--------------------------------------------------------------------+
642
643 PURPOSE : The function starts reading of the SIM field ACMMax.
644 */
645
646 void aoc_read_acmmax (void)
647 {
648 SHORT table_id;
649
650 TRACE_FUNCTION ("aoc_read_acmmax()");
651
652 table_id = psaSIM_atbNewEntry();
653
654 if(table_id NEQ NO_ENTRY)
655 {
656 /*
657 * Fill formular for access
658 *
659 * set datafield type = Binary field
660 * set datafield = SIM_ACMMAX
661 * set offset = 0 Bytes
662 * set length = 3 Bytes
663 */
664 simShrdPrm.atb[table_id].accType = ACT_RD_DAT;
665 simShrdPrm.atb[table_id].reqDataFld = SIM_ACMMAX;
666 simShrdPrm.atb[table_id].dataOff = 0;
667 simShrdPrm.atb[table_id].dataLen = 3;
668 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
669 simShrdPrm.atb[table_id].exchData = sim_data;
670 simShrdPrm.atb[table_id].rplyCB = aoc_read_acmmax_cb;
671
672 simShrdPrm.aId = table_id;
673
674 if(psaSIM_AccessSIMData() < 0)
675 {
676 TRACE_EVENT("FATAL ERROR");
677 }
678 }
679 }
680
681 /*
682 +--------------------------------------------------------------------+
683 | PROJECT: GSM-PS (6147) MODULE: AOC |
684 | STATE : code ROUTINE: aoc_read_acmmax_cb |
685 +--------------------------------------------------------------------+
686
687 PURPOSE : Callback function for reading ACMMax.
688 */
689
690 void aoc_read_acmmax_cb(SHORT table_id)
691 {
692 TRACE_FUNCTION ("aoc_read_acmmax_cb()");
693
694 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
695
696 if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
697 {
698 /* calculate ACMMAX and start reading PUCT */
699 acmmax = (sim_data[0]<<16) + (sim_data[1]<<8) + sim_data[2];
700 acmmax *= 100; /* internal unit is 1/100 */
701 TRACE_EVENT_P1("ACMMAX value = %u", (USHORT)acmmax);
702 aoc_read_puct ();
703 }
704 else
705 {
706 /* ACMMAX is not readable, disable set to default values */
707 acmmax=0;
708 TRACE_EVENT ("AOC: Card has no ACMmax field");
709 #ifdef SIM_TOOLKIT
710 if (simShrdPrm.fuRef >= 0)
711 {
712 psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
713 }
714 #endif
715 }
716 }
717
718
719 /*
720 +--------------------------------------------------------------------+
721 | PROJECT: GSM-PS (6147) MODULE: AOC |
722 | STATE : code ROUTINE: aoc_read_puct |
723 +--------------------------------------------------------------------+
724
725 PURPOSE : The function starts reading of the SIM field PUCT.
726 */
727
728 void aoc_read_puct (void)
729 {
730 SHORT table_id;
731
732 TRACE_FUNCTION ("aoc_read_puct()");
733
734 table_id = psaSIM_atbNewEntry();
735 if(table_id NEQ NO_ENTRY)
736 {
737 simShrdPrm.atb[table_id].accType = ACT_RD_DAT;
738 simShrdPrm.atb[table_id].reqDataFld = SIM_PUCT;
739 simShrdPrm.atb[table_id].dataOff = 0;
740 simShrdPrm.atb[table_id].dataLen = 5;
741 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
742 simShrdPrm.atb[table_id].exchData = sim_data;
743 simShrdPrm.atb[table_id].rplyCB = aoc_read_puct_cb;
744
745 simShrdPrm.aId = table_id;
746 if(psaSIM_AccessSIMData() < 0)
747 {
748 TRACE_EVENT("FATAL ERROR");
749 }
750 }
751 }
752
753 /*
754 +--------------------------------------------------------------------+
755 | PROJECT: GSM-PS (6147) MODULE: AOC |
756 | STATE : code ROUTINE: aoc_read_puct_cb |
757 +--------------------------------------------------------------------+
758
759 PURPOSE : Callback function for reading PUCT.
760 */
761
762 void aoc_read_puct_cb(SHORT table_id)
763 {
764 UBYTE index;
765
766 TRACE_FUNCTION ("aoc_read_puct_cb()");
767 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
768
769 if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
770 {
771 /* calculate PUCT */
772 #if defined WIN32
773 TRACE_EVENT_P2("PUCT %x %x",sim_data[3],sim_data[4]);
774 #endif
775
776 currency [0] = sim_data[0];
777 currency [1] = sim_data[1];
778 currency [2] = sim_data[2];
779 currency [3] = 0;
780 eppu = (sim_data[3]<<4 & 0xFF0) + (sim_data[4] & 0x0F);
781 index = sim_data[4]>>4 & 0x0F;
782 if (index > 11) /* only 0 to 11 */
783 index = 11;
784 exp = ppu_values[index][0];
785 sexp = ppu_values[index][1];
786 }
787 else
788 {
789 /* PUCT is not readable, disable set to default values */
790 eppu = exp = sexp = 0;
791 TRACE_EVENT ("AOC: Card has no PUCT field");
792 }
793
794 #ifdef SIM_TOOLKIT
795 if (simShrdPrm.fuRef >= 0)
796 {
797 psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_SUCC_ADD);
798 }
799 #endif
800 }
801
802
803 /*
804 +--------------------------------------------------------------------+
805 | PROJECT: GSM-PS (6147) MODULE: AOC |
806 | STATE : code ROUTINE: aoc_init_calltable |
807 +--------------------------------------------------------------------+
808
809 PURPOSE : Initialisation of the AoC parameters of the call table.
810
811 */
812
813 void aoc_init_calltable (void)
814 {
815 TRACE_FUNCTION ("aoc_init_calltable()");
816
817 /* Initialize AoC parameters and open
818 * the call dependent AoC timer */
819 memset (cc_aoc_table, 0, sizeof (cc_aoc_table));
820
821 /* Initialize AoC Parameter */
822 ccm = 0L;
823 ccm_already_incremented = 0L;
824 acm_increment_flag = 0;
825
826 /* Initialize the Call Timer Variables */
827 cct = 0L;
828 /* act = 0L; */
829 ct_running = 0;
830
831 #ifdef SIM_TOOLKIT
832 simShrdPrm.fuRef = -1;
833 if (!psaSAT_FURegister (aoc_update))
834 {
835 TRACE_EVENT ("FAILED to register the handler aoc_update() for FU");
836 }
837
838 #endif
839 }
840
841 /*
842 +--------------------------------------------------------------------+
843 | PROJECT: GSM-PS (6147) MODULE: AOC |
844 | STATE : code ROUTINE: aoc_timeout |
845 +--------------------------------------------------------------------+
846
847 PURPOSE : A timeout has occured for a timer. The funtion returns
848 TRUE, if it is a call timer or a AoC timer, else FALSE
849 is returned to indicate that the timer has not been
850 processed.
851
852 */
853 UBYTE aoc_timeout (USHORT index)
854 {
855 if (index EQ AOC_CALLTIMER)
856 {
857 /* timeout call timer */
858 aoc_timeout_call_timer ();
859 return TRUE;
860 }
861 else if (index >= AOC_AOCTIMER AND index < AOC_AOCTIMER+MAX_CALL_NR)
862 {
863 /* Check Advice of Charge Timer */
864 aoc_timeout_aoc_timer ((USHORT)(index - AOC_AOCTIMER));
865 return TRUE;
866 }
867 else
868 {
869 /* the timeout is not for AoC */
870 return FALSE;
871 }
872 }
873
874 /*
875 +--------------------------------------------------------------------+
876 | PROJECT: GSM-PS (6147) MODULE : AOC |
877 | STATE : code ROUTINE: aoc_timeout_call_timer |
878 +--------------------------------------------------------------------+
879
880 PURPOSE : the call timer timeout has occured. The CCT and ACT are
881 increased.
882
883 */
884
885 void aoc_timeout_call_timer (void)
886 {
887 int Cid;
888 T_ACI_CMD_SRC idx;
889 UBYTE five_second_have_just_elapsed = FALSE;
890
891 /* TRACE_FUNCTION ("aoc_timeout_call_timer()"); */
892
893 cct++;
894 /* act++; */
895
896 if (acm_increment_flag EQ 1)
897 five_second_have_just_elapsed = TRUE;
898
899 /* Flag to realize 5 second delay for incrementing ACM on the SIM card. */
900 if (acm_increment_flag)
901 acm_increment_flag--;
902
903 /* flush the charge on the SIM, 5 seconds after the last writing,
904 * if there some units to add */
905 if (five_second_have_just_elapsed)
906 aoc_increment_charge (0L, FALSE);
907
908 /* Update the remaining time for running AoC timer */
909 for (Cid=0; Cid<MAX_CALL_NR; Cid++)
910 {
911 if (cc_aoc_table[Cid].aoc_timer_running AND
912 cc_aoc_table[Cid].remaining_time > 0)
913 {
914 vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
915 }
916 }
917
918 for( idx = 0; idx < CMD_SRC_MAX; idx++ )
919 {
920 R_AT( RAT_CTV, idx )( );
921 }
922
923 aoc_set_time_ut_charge ( ACI_NumParmNotPresent, 0L );
924 }
925
926
927 /*
928 +--------------------------------------------------------------------+
929 | PROJECT: GSM-PS (6147) MODULE : AOC |
930 | STATE : code ROUTINE: aoc_timeout_aoc_timer |
931 +--------------------------------------------------------------------+
932
933 PURPOSE : An AoC timer timeout has occured.
934
935 */
936
937 void aoc_timeout_aoc_timer (SHORT Cid)
938 {
939 SHORT dummy_waitId; /* holds call waiting id */
940 T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
941
942 TRACE_FUNCTION ("aoc_timeout_aoc_timer()");
943
944 if ((aoc_check_acm () EQ FALSE) AND
945 (cc_aoc_table[Cid].aoci_active EQ FALSE) AND
946 (cc_aoc_table[Cid].next_unit) ) /* check if the next intervall would charge (time related charge > 0)*/
947 {
948 /* ACM exceeds ACMMax, and call is not free, so disconnect call */
949 TRACE_EVENT ("ACM > ACMMax");
950 cmhCC_ClearCall (Cid,
951 CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
952 src_dummy, AT_CMD_NONE, &dummy_waitId);
953 }
954 else
955 {
956 /* e3 may have changed during the current intervall but recalc is already done */
957 aoc_increment_charge (cc_aoc_table[Cid].next_unit, FALSE);
958 if (cc_aoc_table[Cid].new_data_avail)
959 {
960 /* New Parameter available */
961 /* 4.3.e) bring parameters held in abeyance into operation */
962 if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
963 if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
964 if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
965 if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
966
967 aoc_calculate_charging_parameter_part2 (Cid);
968
969 /* timing has changed? */
970 if (cc_aoc_table[Cid].e_next_bitmap & (E2_CHANGED | E7_CHANGED))
971 {
972 /* reschedule timer */
973 vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
974 vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
975 cc_aoc_table[Cid].first_interval,
976 cc_aoc_table[Cid].next_interval);
977 cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
978 }
979 else
980 /* ask the timer since we could already be ahead */
981 /* cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].next_interval; */
982 vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
983
984 cc_aoc_table[Cid].new_data_avail = FALSE;
985 cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
986 }
987 else
988 {
989 /* re-initialise remaining time counter */
990 /* ask the timer since we could already be ahead */
991 /* cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].next_interval; */
992 vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);
993 }
994
995 /* check if timer had e2=0 and e7>= */
996 if (cc_aoc_table[Cid].next_interval == 0)
997 {
998 cc_aoc_table[Cid].aoc_timer_running = FALSE;
999 /* cc_aoc_table[Cid].aoci_active = FALSE;*/
1000 cc_aoc_table[Cid].remaining_time = 0L;
1001 aoc_set_time_ut_charge ( Cid, ACI_NumParmNotPresent );
1002 }
1003 else
1004 aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
1005 }
1006 }
1007
1008
1009 /*
1010 +--------------------------------------------------------------------+
1011 | PROJECT: GSM-PS (6147) MODULE : AOC |
1012 | STATE : code ROUTINE: aoc_start_aoc_timer |
1013 +--------------------------------------------------------------------+
1014
1015 PURPOSE : AoC is started for the indicated call or
1016 new AoC parameter are received.
1017 */
1018
1019 void aoc_start_newinfo_existingcall (SHORT Cid)
1020 {
1021 UBYTE no_more_timer_running = FALSE;
1022 T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
1023 SHORT dummy_waitId;
1024
1025 TRACE_FUNCTION ("aoc_start_newinfo_existingcall()");
1026
1027 if(!aoc_non_zero_cai (Cid))
1028 {
1029 return;
1030 }
1031
1032 if (cc_aoc_table[Cid].aoc_timer_running EQ FALSE)
1033 {
1034 /* New Parameter available */
1035 /* 4.3.e) bring parameters held in abeyance into operation */
1036 if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
1037 if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
1038 if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
1039 if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
1040
1041 aoc_calculate_charging_parameter_part2 (Cid);
1042
1043 /* vsi_t_status (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid), &cc_aoc_table[Cid].remaining_time);*/
1044
1045 cc_aoc_table[Cid].new_data_avail = FALSE;
1046 cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
1047 no_more_timer_running = TRUE;
1048 }
1049
1050
1051 /* charging information available, else wait for end of interval.*/
1052 if ( (cc_aoc_table[Cid].next_interval EQ 0) AND
1053 ((cc_aoc_table[Cid].first_interval EQ 0) OR (cc_aoc_table[Cid].remaining_time EQ 0)) )
1054 {
1055 /* if CDUR is not actively timing (i.e. due to e2 being zero,
1056 * e7 being zero or the processing of e7 has been completed),
1057 * then a new value of e2 and/or e7 is applied immediately as per a normal call. */
1058 no_more_timer_running = TRUE;
1059 }
1060
1061 /* charging information available, else wait for end of interval. */
1062 if ((aoc_check_acm () EQ TRUE) OR
1063 (cc_aoc_table[Cid].aoci_active EQ TRUE))
1064 {
1065 /* ACM has not exceeded ACMMax then calculate charging parameters and increment inital charge */
1066 aoc_calculate_charging_parameter_part1 (Cid);
1067 aoc_increment_initial_charge (Cid);
1068 cc_aoc_table[Cid].new_data_avail = TRUE;
1069 }
1070 else
1071 {
1072 /*
1073 * ACM has reached ACM max, the call is kept till the next interval elapses
1074 * but if there is no timer running, for a new reception of CAI non zero,
1075 * we behave as on reception of a first CAI for a call, if acm has reached ACM max,
1076 * we disconnect the call.
1077 * "Rec 2.24 : 4.2.2 ACM : If the ACM max is valid and the ACM is equal to or greater
1078 * than the value of ACM max, and an incoming call is received and subsequently
1079 * a non-zero CAI is received for that call, then the call shall be terminated by
1080 * the ME with an appropriate indication given to the user."
1081 */
1082 if (no_more_timer_running)
1083 {
1084 /* if we are here, it means that it's a non-zero CAI, so no need to test it again */
1085 TRACE_EVENT("no more timer running clear call");
1086 cmhCC_ClearCall (Cid,
1087 CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
1088 src_dummy, AT_CMD_NONE, &dummy_waitId);
1089 }
1090 }
1091
1092 if (no_more_timer_running)
1093 {
1094 /* New Parameter available */
1095 aoc_calculate_charging_parameter_part2 (Cid);
1096
1097 cc_aoc_table[Cid].new_data_avail = FALSE;
1098 vsi_t_stop (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid));
1099 vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
1100 cc_aoc_table[Cid].first_interval,
1101 cc_aoc_table[Cid].next_interval);
1102 /* re-initialise remaining time counter for first interval */
1103 cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
1104 }
1105 }
1106
1107 void aoc_start_info_newcall (SHORT Cid)
1108 {
1109 T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
1110 SHORT dummy_waitId;
1111
1112 TRACE_FUNCTION ("aoc_start_info_newcall()");
1113
1114 if( !aoc_non_zero_cai(Cid) )
1115 {
1116 return;
1117 }
1118 /* charging information available */
1119
1120 if( (aoc_check_acm() EQ FALSE) AND
1121 (cc_aoc_table[Cid].aoci_active EQ FALSE) )
1122 {
1123 /* ACM exceeds ACMMax, disconnect call */
1124 TRACE_EVENT("clear call on initial call");
1125 cmhCC_ClearCall (Cid,
1126 CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
1127 src_dummy,
1128 AT_CMD_NONE,
1129 &dummy_waitId);
1130 return;
1131 }
1132
1133 /* ACM has not exceeded ACMMax then calculate charging parameters,
1134 * increment inital charge and start AoC Timer. */
1135 {
1136 /* bring new parameters into operation */
1137
1138 if (cc_aoc_table[Cid].e_next_bitmap & E1_CHANGED) cc_aoc_table[Cid].e1 = cc_aoc_table[Cid].e1_next;
1139 if (cc_aoc_table[Cid].e_next_bitmap & E2_CHANGED) cc_aoc_table[Cid].e2 = cc_aoc_table[Cid].e2_next;
1140 if (cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED) cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
1141 if (cc_aoc_table[Cid].e_next_bitmap & E7_CHANGED) cc_aoc_table[Cid].e7 = cc_aoc_table[Cid].e7_next;
1142
1143 /* cc_aoc_table[Cid].new_data_avail = FALSE;*/
1144 cc_aoc_table[Cid].e_next_bitmap &= ~(E1_CHANGED | E2_CHANGED | E3_CHANGED | E7_CHANGED);
1145 }
1146
1147 aoc_calculate_charging_parameter (Cid);
1148 aoc_increment_initial_charge (Cid);
1149
1150 if(cc_aoc_table[Cid].first_interval)
1151 {
1152 vsi_t_pstart (VSI_CALLER (USHORT)(AOC_AOCTIMER + Cid),
1153 cc_aoc_table[Cid].first_interval,
1154 cc_aoc_table[Cid].next_interval);
1155
1156 cc_aoc_table[Cid].aoc_timer_running = TRUE;
1157 }
1158
1159 cc_aoc_table[Cid].new_data_avail = FALSE;
1160 cc_aoc_table[Cid].remaining_time = cc_aoc_table[Cid].first_interval;
1161
1162 aoc_set_time_ut_charge ( Cid, cc_aoc_table[Cid].remaining_time );
1163 }
1164
1165
1166 /*
1167 +--------------------------------------------------------------------+
1168 | PROJECT: GSM-PS (6147) MODULE : AOC |
1169 | STATE : code ROUTINE: aoc_non_zero_cai |
1170 +--------------------------------------------------------------------+
1171
1172 PURPOSE : Checks whether the Advice of Charge parameter indicate
1173 a free call (parameters are not available or equal zero).
1174 */
1175
1176 UBYTE aoc_non_zero_cai (SHORT Cid)
1177 {
1178 TRACE_FUNCTION ("aoc_non_zero_cai()");
1179
1180 /* AoC = e3 * { e4 + e1*INT(CDUR/(e7,e2)) + e5*INT(SEG/e6) }
1181 * = scaling * { constant + time related + data related}
1182 *
1183 * Ref. GSM 2.24 Section 4 Functional operation in MS */
1184
1185 if ((cc_aoc_table[Cid].e3 EQ 0) OR
1186 ((cc_aoc_table[Cid].e1 EQ 0) AND (cc_aoc_table[Cid].e4 EQ 0) /* AND (cc_aoc_table[Cid].e5 EQ 0) */ ))
1187 /* e5, e6 is currently not supported */
1188 return FALSE;
1189
1190 return TRUE;
1191 }
1192
1193 /*
1194 +--------------------------------------------------------------------+
1195 | PROJECT: GSM-PS (6147) MODULE : AOC |
1196 | STATE : code ROUTINE: aoc_check_acm |
1197 +--------------------------------------------------------------------+
1198
1199 PURPOSE : The function indicates whether ACM exceeds ACMMax.
1200
1201 */
1202
1203 UBYTE aoc_check_acm (void)
1204 {
1205 TRACE_FUNCTION ("aoc_check_acm()");
1206
1207 TRACE_EVENT_P2("ACM=%u ACMMax=%u", acm, acmmax);
1208
1209 if (acmmax NEQ 0)
1210 {
1211 /*
1212 * ACMMax is valid
1213 */
1214 if (acm >= acmmax)
1215 {
1216 causeMod = P_CEER_sim; /* Set the module to sim to report ceer */
1217 causeCeer = P_CEER_ACMMaxReachedOrExceeded; /* Set proprietary cause */
1218 return FALSE; /* ACM exceeds ACMMax */
1219 }
1220 else
1221 {
1222 causeMod = P_CEER_mod; /* Clear module which is set */
1223 causeCeer = P_CEER_NotPresent; /* Clear proprietary cause */
1224 }
1225 }
1226 return TRUE;
1227 }
1228
1229 /*
1230 +--------------------------------------------------------------------+
1231 | PROJECT: GSM-PS (6147) MODULE : AOC |
1232 | STATE : code ROUTINE: aoc_calculate_charging_params_part1 |
1233 +--------------------------------------------------------------------+
1234
1235 PURPOSE : The function calculates an initial rime related charge
1236
1237 */
1238
1239 static void aoc_calculate_charging_parameter_part1 (SHORT Cid)
1240 {
1241 TRACE_FUNCTION ("aoc_calculate_charging_parameter_part1()");
1242
1243 /*
1244 * Calculation for inital charge
1245 */
1246 cc_aoc_table[Cid].first_unit =
1247 ((ULONG)cc_aoc_table[Cid].e3 * (ULONG)cc_aoc_table[Cid].e4) / 10;
1248 }
1249
1250 /*
1251 +--------------------------------------------------------------------+
1252 | PROJECT: GSM-PS (6147) MODULE : AOC |
1253 | STATE : code ROUTINE: aoc_calculate_charging_params_part2 |
1254 +--------------------------------------------------------------------+
1255
1256 PURPOSE : The function calculates the interval length and the
1257 number of units which will be incremented at interval
1258 end.
1259
1260 */
1261
1262 static void aoc_calculate_charging_parameter_part2 (SHORT Cid)
1263 {
1264 TRACE_FUNCTION ("aoc_calculate_charging_parameter_part2()");
1265
1266 /* Calculation of first time interval */
1267 cc_aoc_table[Cid].first_interval = (T_TIME) E_IN_MS(cc_aoc_table[Cid].e7);
1268
1269 /* Calculation of next time interval */
1270 cc_aoc_table[Cid].next_interval = (T_TIME) E_IN_MS(cc_aoc_table[Cid].e2);
1271
1272
1273 /* 4.3.a) E7 is not available or E7 is equal zero then use E2 */
1274 if (cc_aoc_table[Cid].first_interval EQ 0L)
1275 cc_aoc_table[Cid].first_interval = cc_aoc_table[Cid].next_interval;
1276
1277 /*
1278 * Calculation for charge of next units
1279 */
1280 cc_aoc_table[Cid].next_unit =
1281 ((ULONG)cc_aoc_table[Cid].e3 * (ULONG)cc_aoc_table[Cid].e1) / 10;
1282 }
1283
1284 /*
1285 +--------------------------------------------------------------------+
1286 | PROJECT: GSM-PS (6147) MODULE : AOC |
1287 | STATE : code ROUTINE: aoc_calculate_charging_params |
1288 +--------------------------------------------------------------------+
1289
1290 PURPOSE : The function calculates the interval length and the
1291 number of units which will be incremented at interval
1292 end.
1293
1294 */
1295
1296 void aoc_calculate_charging_parameter (SHORT Cid)
1297 {
1298 TRACE_FUNCTION ("aoc_calculate_charging_parameter()");
1299
1300 aoc_calculate_charging_parameter_part1 (Cid);
1301 aoc_calculate_charging_parameter_part2 (Cid);
1302 }
1303
1304 /*
1305 +--------------------------------------------------------------------+
1306 | PROJECT: GSM-PS (6147) MODULE : AOC |
1307 | STATE : code ROUTINE: aoc_increment_initial_charge |
1308 +--------------------------------------------------------------------+
1309
1310 PURPOSE : The function increments the inital charge to CCM and ACM.
1311
1312 */
1313
1314 void aoc_increment_initial_charge (SHORT Cid)
1315 {
1316 TRACE_FUNCTION ("aoc_increment_inital_charge()");
1317
1318 if (cc_aoc_table[Cid].first_unit)
1319 {
1320 /*
1321 * if initial charge is available, charge it and
1322 * inform MMI about it although it has no charge.
1323 */
1324 aoc_increment_charge (cc_aoc_table[Cid].first_unit, FALSE);
1325 cc_aoc_table[Cid].first_unit = 0L;
1326 }
1327 aoc_send_ccm ();
1328 }
1329
1330
1331 /*
1332 +--------------------------------------------------------------------+
1333 | PROJECT: GSM-PS (6147) MODULE : AOC |
1334 | STATE : code ROUTINE: aoc_increment_charge |
1335 +--------------------------------------------------------------------+
1336
1337 PURPOSE : The function increments charge to CCM and ACM. If necessary
1338 the ACM is incremented on the SIM card.
1339
1340 */
1341
1342 void aoc_increment_charge (ULONG charge, UBYTE ever)
1343 {
1344 SHORT table_id;
1345 ULONG acm_for_sim;
1346
1347 TRACE_FUNCTION ("aoc_increment_charge()");
1348
1349 /*
1350 * Both CCM is incremented
1351 */
1352 ccm += charge;
1353
1354 if (ccm > (0xFFFFFF * 100)) /* limit to 0xffffff since datafeld is only 3 bytes long.*/
1355 ccm = (0xFFFFFF * 100);
1356
1357
1358
1359 TRACE_EVENT_P2("NewCCM %u charge %u", ccm, charge);
1360
1361 /*
1362 * the update on the SIM is the difference between the rounded up value of the current CCM
1363 * and the old CCM (already rounded up)
1364 */
1365 acm_for_sim = MC_AOC_ROUND_UP(ccm) - MC_AOC_ROUND_UP(ccm_already_incremented);
1366
1367 if (acm_for_sim)
1368 {
1369 if (acm_increment_flag EQ 0 OR ever)
1370 {
1371 /* sync the calltimer to this SIM-Access */
1372 vsi_t_config (VSI_CALLER AOC_CALLTIMER, TIMER_SET, AOC_THOUSAND_MILLISECONDS );
1373
1374 /*
1375 * Nothing stored in the last five seconds on the SIM card
1376 * and now something to store
1377 */
1378 acm_increment_flag = 5;
1379
1380 ccm_already_incremented += acm_for_sim * 100;
1381
1382 acm += acm_for_sim * 100;
1383
1384 if (acm > (0xFFFFFF * 100))
1385 acm = (0xFFFFFF * 100);
1386
1387 if (limit_reached EQ FALSE)
1388 {
1389 /*
1390 * request table id for SIM SAP access
1391 */
1392 table_id = psaSIM_atbNewEntry();
1393
1394 if(table_id NEQ NO_ENTRY)
1395 {
1396 /*
1397 * Fill formular for access
1398 *
1399 * set datafield type = Binary field
1400 * set datafield = SIM_ACM
1401 * set offset = 0 Bytes
1402 * set length = 3 Bytes
1403 */
1404 simShrdPrm.atb[table_id].accType = ACT_INC_DAT;
1405 simShrdPrm.atb[table_id].reqDataFld = SIM_ACM;
1406 simShrdPrm.atb[table_id].dataOff = 0;
1407 simShrdPrm.atb[table_id].dataLen = 3;
1408 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
1409 simShrdPrm.atb[table_id].exchData = sim_data;
1410 simShrdPrm.atb[table_id].rplyCB = aoc_increment_cb;
1411 simShrdPrm.aId = table_id;
1412 sim_data[0] = (UBYTE)(acm_for_sim >> 16);
1413 sim_data[1] = (UBYTE)(acm_for_sim >> 8);
1414 sim_data[2] = (UBYTE)(acm_for_sim & 0xFF);
1415
1416 TRACE_EVENT_P1("ACM increment = %u", acm_for_sim);
1417
1418 if(psaSIM_AccessSIMData() < 0)
1419 {
1420 TRACE_EVENT("FATAL ERROR");
1421 }
1422 }
1423 }
1424 }
1425 aoc_send_ccm ();
1426 }
1427 }
1428
1429
1430 /*
1431 +--------------------------------------------------------------------+
1432 | PROJECT: GSM-PS (6147) MODULE: AOC |
1433 | STATE : code ROUTINE: aoc_increment_cb |
1434 +--------------------------------------------------------------------+
1435
1436 PURPOSE : Callback function for incrementing ACM.
1437
1438 */
1439
1440 void aoc_increment_cb(SHORT table_id)
1441 {
1442 UBYTE i;
1443 SHORT dummy_waitId; /* holds call waiting id */
1444 T_ACI_CMD_SRC src_dummy = CMD_SRC_NONE;
1445
1446
1447 TRACE_FUNCTION ("aoc_increment_cb()");
1448
1449 switch (simShrdPrm.atb[table_id].errCode)
1450 {
1451 case SIM_NO_ERROR:
1452 break;
1453 case SIM_CAUSE_MAX_INCREASE:
1454 /*
1455 * ACM has reached limit 0xFFFFFF,
1456 * If ACMMAX is zero, ACM shall be cleared
1457 * by MMI. Only an indication is forwarded
1458 * to MMI, else the call is released.
1459 */
1460 if (acmmax EQ 0)
1461 {
1462 limit_reached = TRUE;
1463 R_AT( RAT_CME, simEntStat.entOwn )
1464 ( AT_CMD_CACM, CME_ERR_AcmResetNeeded );
1465 break;
1466 }
1467 /* lint -fallthrough */
1468 default:
1469 /*
1470 * ACM increment is not successfull
1471 */
1472 aoc_state = AOC_DISABLE;
1473
1474 /*
1475 * release all chargeable calls
1476 */
1477 for (i=0;i<MAX_CALL_NR;i++)
1478 {
1479 if (aoc_non_zero_cai(i))
1480 {
1481 cmhCC_ClearCall (i,
1482 CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS, ACI_ORIGINATING_ENTITY, MNCC_CAUSE_ACM_MAX),
1483 src_dummy, AT_CMD_NONE,
1484 &dummy_waitId);
1485 }
1486 }
1487 break;
1488 }
1489 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1490 }
1491
1492 /*
1493 +--------------------------------------------------------------------+
1494 | PROJECT: GSM-PS (6147) MODULE: AOC |
1495 | STATE : code ROUTINE: aoc_calculate_puct |
1496 +--------------------------------------------------------------------+
1497
1498 PURPOSE : Calculate counter in PUCT.
1499
1500 */
1501
1502 void aoc_calculate_puct (ULONG value, T_puct * result)
1503 {
1504 TRACE_FUNCTION ("aoc_calculate_puct()");
1505 #if defined WIN32
1506 {
1507 TRACE_EVENT_P1("EPPU %u",eppu);
1508 TRACE_EVENT_P1("SEXP %u",sexp);
1509 TRACE_EVENT_P1("EXP %u",exp);
1510 TRACE_EVENT_P1("VAL %u",value);
1511 }
1512 #endif
1513 /*
1514 * copy currency
1515 */
1516 memcpy (result->currency, currency, 4);
1517
1518 /*
1519 * Multiply counter value with elementary price per unit
1520 */
1521 value *= eppu;
1522 value *= 100; /* internal calculation is 1/100 unit */
1523
1524 /*
1525 * If sexp is set divide by logarithm of ten, else multiply
1526 */
1527 if (sexp)
1528 value /= exp;
1529 else
1530 value *= exp;
1531
1532 /*
1533 * Create resulting string with two digits after the colon
1534 */
1535 if (value EQ 0)
1536 result->value[0] = '\0';
1537 else
1538 sprintf ((char *) result->value, "%u.%02u", value / 100, value % 100);
1539 }
1540
1541
1542 /*
1543 +--------------------------------------------------------------------+
1544 | PROJECT: GSM-PS (6147) MODULE : AOC |
1545 | STATE : code ROUTINE: aoc_update_acm |
1546 +--------------------------------------------------------------------+
1547
1548 PURPOSE : The function tries to reset the ACM field on the SIM card.
1549
1550 */
1551
1552 void aoc_update_acm (UBYTE operation, ULONG value)
1553 {
1554 SHORT table_id;
1555
1556 TRACE_FUNCTION ("aoc_update_acm()");
1557
1558 /*
1559 * request table id for SIM SAP access
1560 */
1561 table_id = psaSIM_atbNewEntry();
1562 act_upd_op = operation;
1563
1564 if(table_id NEQ NO_ENTRY)
1565 {
1566 switch (operation)
1567 {
1568 case FIRST_UPDATE:
1569 /*
1570 * This is the first access to ACM. It may fail,
1571 * because PIN2 is needed.
1572 */
1573 act_value = 0L;
1574 /*lint -fallthrough*/
1575 case SECOND_UPDATE:
1576 /*
1577 * This is the second access to ACM after PIN entering.
1578 */
1579 simShrdPrm.atb[table_id].accType = ACT_WR_REC;
1580 simShrdPrm.atb[table_id].reqDataFld = SIM_ACM;
1581 simShrdPrm.atb[table_id].dataOff = 0;
1582 simShrdPrm.atb[table_id].dataLen = 3;
1583 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
1584 simShrdPrm.atb[table_id].exchData = sim_data;
1585 simShrdPrm.atb[table_id].rplyCB = aoc_update_acm_cb;
1586 simShrdPrm.aId = table_id;
1587 sim_data[0] = (UBYTE)(act_value >> 16);
1588 sim_data[1] = (UBYTE)(act_value >> 8);
1589 sim_data[2] = (UBYTE)(act_value & 0xFF);
1590
1591 if(psaSIM_AccessSIMData() < 0)
1592 {
1593 TRACE_EVENT("FATAL ERROR");
1594 }
1595 break;
1596 }
1597 }
1598 }
1599
1600 /*
1601 +--------------------------------------------------------------------+
1602 | PROJECT: GSM-PS (6147) MODULE: AOC |
1603 | STATE : code ROUTINE: aoc_update_acm_cb |
1604 +--------------------------------------------------------------------+
1605
1606 PURPOSE : Callback function for updating ACM.
1607
1608 */
1609
1610 void aoc_update_acm_cb(SHORT table_id)
1611 {
1612 T_SIM_SET_PRM * pSIMSetPrm; /* points to MM parameter set */
1613
1614 TRACE_FUNCTION ("aoc_update_acm_cb()");
1615
1616 switch (simShrdPrm.atb[table_id].errCode)
1617 {
1618 case SIM_NO_ERROR:
1619 /*
1620 * No error has occured, read ACM etc. again from SIM Card
1621 */
1622 simEntStat.curCmd = AT_CMD_NONE;
1623 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1624 R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CACM );
1625 aoc_sms ();
1626 break;
1627
1628 case SIM_CAUSE_PIN2_EXPECT:
1629 /*
1630 * An error has occured, maybe PIN2 is needed
1631 */
1632 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1633 if (strlen ((char *) pwd) AND
1634 act_upd_op EQ FIRST_UPDATE)
1635 {
1636 /*
1637 * Password is available and
1638 * it is the first update, then
1639 * try to verify PIN2
1640 */
1641 act_upd_op = VERIFY_PWD;
1642 pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
1643
1644 cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
1645 pSIMSetPrm -> PINType = PHASE_2_PIN_2;
1646 simEntStat.curCmd = AT_CMD_CACM;
1647 simEntStat.entOwn = simShrdPrm.owner = act_src_id;
1648
1649 if ( psaSIM_VerifyPIN() < 0 ) /* verify PIN */
1650 {
1651 TRACE_EVENT( "FATAL RETURN psaSIM in +CACM" );
1652 }
1653 }
1654 else
1655 {
1656 /*
1657 * PIN2 not available or second attempt
1658 */
1659 simEntStat.curCmd = AT_CMD_NONE;
1660 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1661 if (act_upd_op EQ FIRST_UPDATE)
1662 {
1663 R_AT( RAT_CME, simEntStat.entOwn )
1664 ( AT_CMD_CACM, CME_ERR_SimPin2Req );
1665 }
1666 else
1667 {
1668 R_AT( RAT_CME, simEntStat.entOwn )
1669 ( AT_CMD_CACM, CME_ERR_WrongPasswd );
1670 }
1671 }
1672 break;
1673 default:
1674 /*
1675 * Any other error, respective error code is returned
1676 */
1677 simEntStat.curCmd = AT_CMD_NONE;
1678 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1679 R_AT( RAT_CME, simEntStat.entOwn )
1680 (
1681 AT_CMD_CACM,
1682 cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
1683 );
1684 break;
1685 }
1686 }
1687
1688
1689 /*
1690 +--------------------------------------------------------------------+
1691 | PROJECT: GSM-PS (6147) MODULE : AOC |
1692 | STATE : code ROUTINE: aoc_update_acmmax |
1693 +--------------------------------------------------------------------+
1694
1695 PURPOSE : The function tries to set the ACMMAX field on the SIM card.
1696
1697 */
1698
1699 void aoc_update_acmmax (UBYTE operation, ULONG value)
1700 {
1701 SHORT table_id;
1702
1703 TRACE_FUNCTION ("aoc_update_acmmax()");
1704
1705 /*
1706 * request table id for SIM SAP access
1707 */
1708 table_id = psaSIM_atbNewEntry();
1709 act_upd_op = operation;
1710
1711 if(table_id NEQ NO_ENTRY)
1712 {
1713 switch (operation)
1714 {
1715 case FIRST_UPDATE:
1716 /*
1717 * This is the first access to ACMMAX. It may fail,
1718 * because PIN2 is needed.
1719 */
1720 act_value = value;
1721 /*lint -fallthrough*/
1722 case SECOND_UPDATE:
1723 /*
1724 * This is the second access to ACMMAX after PIN entering.
1725 */
1726 simShrdPrm.atb[table_id].accType = ACT_WR_DAT;
1727 simShrdPrm.atb[table_id].reqDataFld = SIM_ACMMAX;
1728 simShrdPrm.atb[table_id].dataOff = 0;
1729 simShrdPrm.atb[table_id].dataLen = 3;
1730 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
1731 simShrdPrm.atb[table_id].exchData = sim_data;
1732 simShrdPrm.atb[table_id].rplyCB = aoc_update_acmmax_cb;
1733 simShrdPrm.aId = table_id;
1734 sim_data[0] = (UBYTE)(act_value >> 16);
1735 sim_data[1] = (UBYTE)(act_value >> 8);
1736 sim_data[2] = (UBYTE)(act_value & 0xFF);
1737
1738 if(psaSIM_AccessSIMData() < 0)
1739 {
1740 TRACE_EVENT("FATAL ERROR");
1741 }
1742 break;
1743 }
1744 }
1745 }
1746
1747 /*
1748 +--------------------------------------------------------------------+
1749 | PROJECT: GSM-PS (6147) MODULE: AOC |
1750 | STATE : code ROUTINE: aoc_update_acmmax_cb |
1751 +--------------------------------------------------------------------+
1752
1753 PURPOSE : Callback function for updating ACMMax.
1754
1755 */
1756
1757 void aoc_update_acmmax_cb(SHORT table_id)
1758 {
1759 T_SIM_SET_PRM * pSIMSetPrm; /* points to MM parameter set */
1760
1761 TRACE_FUNCTION ("aoc_update_acmmax_cb()");
1762
1763 switch (simShrdPrm.atb[table_id].errCode)
1764 {
1765 case SIM_NO_ERROR:
1766 /*
1767 * No error has occured, read ACM etc. again from SIM Card
1768 */
1769 simEntStat.curCmd = AT_CMD_NONE;
1770 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1771 R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CAMM );
1772 aoc_sms ();
1773
1774 aoc_set_time_ut_charge ( ACI_NumParmNotPresent, 0L );
1775 break;
1776 case SIM_CAUSE_PIN2_EXPECT:
1777 /*
1778 * error has occured, maybe PIN2 is needed
1779 */
1780 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1781 if (strlen ((char *) pwd) AND
1782 act_upd_op EQ FIRST_UPDATE)
1783 {
1784 /*
1785 * Password is available and
1786 * it is the first update, then
1787 * try to verify PIN2
1788 */
1789 act_upd_op = VERIFY_PWD;
1790 pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
1791
1792 cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
1793 pSIMSetPrm -> PINType = PHASE_2_PIN_2;
1794 simEntStat.curCmd = AT_CMD_CAMM;
1795 simEntStat.entOwn = simShrdPrm.owner = act_src_id;
1796
1797 if ( psaSIM_VerifyPIN() < 0 ) /* verify PIN */
1798 {
1799 TRACE_EVENT( "FATAL RETURN psaSIM in +CAMM" );
1800 }
1801 }
1802 else
1803 {
1804 /*
1805 * PIN2 not available or second attempt
1806 */
1807 simEntStat.curCmd = AT_CMD_NONE;
1808 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1809 if (act_upd_op EQ FIRST_UPDATE)
1810 {
1811 R_AT( RAT_CME, simEntStat.entOwn )
1812 ( AT_CMD_CAMM, CME_ERR_SimPin2Req );
1813 }
1814 else
1815 {
1816 R_AT( RAT_CME, simEntStat.entOwn )
1817 ( AT_CMD_CAMM, CME_ERR_WrongPasswd );
1818 }
1819 }
1820 break;
1821 default:
1822 /*
1823 * Any other error, respective error code is returned
1824 */
1825 simEntStat.curCmd = AT_CMD_NONE;
1826 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1827 R_AT( RAT_CME, simEntStat.entOwn )
1828 (
1829 AT_CMD_CAMM,
1830 cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
1831 );
1832 break;
1833 }
1834 }
1835
1836 /*
1837 +--------------------------------------------------------------------+
1838 | PROJECT: GSM-PS (6147) MODULE : AOC |
1839 | STATE : code ROUTINE: aoc_update_puct |
1840 +--------------------------------------------------------------------+
1841
1842 PURPOSE : The function tries to modify the PUCT field on the SIM card.
1843
1844 */
1845
1846 void aoc_update_puct (UBYTE operation, T_puct * value)
1847 {
1848 SHORT table_id;
1849
1850 TRACE_FUNCTION ("aoc_update_puct()");
1851
1852 /*
1853 * request table id for SIM SAP access
1854 */
1855 table_id = psaSIM_atbNewEntry();
1856 act_upd_op = operation;
1857
1858 if(table_id NEQ NO_ENTRY)
1859 {
1860 switch (operation)
1861 {
1862 case FIRST_UPDATE:
1863 /*
1864 * This is the first access to PUCT. It may fail,
1865 * because PIN2 is needed.
1866 */
1867 if (aoc_set_puct_values (value) EQ FALSE)
1868 {
1869 R_AT( RAT_CME, simEntStat.entOwn )
1870 ( AT_CMD_CPUC, CME_ERR_OpNotAllow );
1871
1872 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1873 return;
1874 }
1875 /*lint -fallthrough*/
1876 case SECOND_UPDATE:
1877 /*
1878 * This is the second access to PUCT after PIN entering.
1879 */
1880 simShrdPrm.atb[table_id].accType = ACT_WR_DAT;
1881 simShrdPrm.atb[table_id].reqDataFld = SIM_PUCT;
1882 simShrdPrm.atb[table_id].dataOff = 0;
1883 simShrdPrm.atb[table_id].dataLen = 5;
1884 simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
1885 simShrdPrm.atb[table_id].exchData = sim_data;
1886 simShrdPrm.atb[table_id].rplyCB = aoc_update_puct_cb;
1887 simShrdPrm.aId = table_id;
1888 if(psaSIM_AccessSIMData() < 0)
1889 {
1890 TRACE_EVENT("FATAL ERROR");
1891 }
1892 break;
1893 }
1894 }
1895 }
1896
1897 /*
1898 +--------------------------------------------------------------------+
1899 | PROJECT: GSM-PS (6147) MODULE: AOC |
1900 | STATE : code ROUTINE: aoc_update_puct_cb |
1901 +--------------------------------------------------------------------+
1902
1903 PURPOSE : Callback function for updating PUCT.
1904
1905 */
1906
1907 void aoc_update_puct_cb(SHORT table_id)
1908 {
1909 T_SIM_SET_PRM * pSIMSetPrm; /* points to MM parameter set */
1910 UBYTE index;
1911
1912 TRACE_FUNCTION ("aoc_update_puct_cb()");
1913
1914 switch (simShrdPrm.atb[table_id].errCode)
1915 {
1916 case SIM_NO_ERROR:
1917 /*
1918 * No error has occured, read ACM etc. again from SIM Card
1919 */
1920 currency [0] = sim_data[0];
1921 currency [1] = sim_data[1];
1922 currency [2] = sim_data[2];
1923 currency [3] = 0;
1924 eppu = (sim_data[3]<<4 & 0xFF0) + (sim_data[4] & 0x0F);
1925 index = sim_data[4]>>4 & 0x0F;
1926 if (index > 11) /* only 0 to 11 */
1927 index = 11;
1928 exp = ppu_values[index][0];
1929 sexp = ppu_values[index][1];
1930
1931 simEntStat.curCmd = AT_CMD_NONE;
1932 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1933 R_AT( RAT_OK, simEntStat.entOwn) (AT_CMD_CPUC );
1934 aoc_sms ();
1935 break;
1936 case SIM_CAUSE_PIN2_EXPECT:
1937 /*
1938 * error has occured, maybe PIN2 is needed
1939 */
1940 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1941 if (strlen ((char *) pwd) AND
1942 act_upd_op EQ FIRST_UPDATE)
1943 {
1944 /*
1945 * Password is available and
1946 * it is the first update, then
1947 * try to verify PIN2
1948 */
1949 act_upd_op = VERIFY_PWD;
1950 pSIMSetPrm = &simShrdPrm.setPrm[act_src_id];
1951
1952 cmhSIM_FillInPIN ( (char *) pwd, pSIMSetPrm -> curPIN, PIN_LEN);
1953 pSIMSetPrm -> PINType = PHASE_2_PIN_2;
1954 simEntStat.curCmd = AT_CMD_CPUC;
1955 simEntStat.entOwn = simShrdPrm.owner = act_src_id;
1956
1957 if ( psaSIM_VerifyPIN() < 0 ) /* verify PIN */
1958 {
1959 TRACE_EVENT( "FATAL RETURN psaSIM in +CAMM" );
1960 }
1961 }
1962 else
1963 {
1964 /*
1965 * PIN2 not available or second attempt
1966 */
1967 simEntStat.curCmd = AT_CMD_NONE;
1968 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1969 if (act_upd_op EQ FIRST_UPDATE)
1970 {
1971 R_AT( RAT_CME, simEntStat.entOwn )
1972 ( AT_CMD_CPUC, CME_ERR_SimPin2Req );
1973 }
1974 else
1975 {
1976 R_AT( RAT_CME, simEntStat.entOwn )
1977 ( AT_CMD_CPUC, CME_ERR_WrongPasswd );
1978 }
1979 }
1980 break;
1981 default:
1982 /*
1983 * Any other error, respective error code is returned
1984 */
1985 simEntStat.curCmd = AT_CMD_NONE;
1986 simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
1987 R_AT( RAT_CME, simEntStat.entOwn )
1988 (
1989 AT_CMD_CPUC,
1990 cmhSIM_GetCmeFromSim ( simShrdPrm.atb[table_id].errCode )
1991 );
1992 break;
1993 }
1994 }
1995
1996 /*
1997 +--------------------------------------------------------------------+
1998 | PROJECT: GSM-PS (6147) MODULE: AOC |
1999 | STATE : code ROUTINE: aoc_set_puct_values |
2000 +--------------------------------------------------------------------+
2001
2002 PURPOSE : Converts the PUCT values from string to SIM format.
2003 */
2004
2005 UBYTE aoc_set_puct_values(T_puct * puct)
2006 {
2007 UBYTE first_digit = FALSE;
2008 UBYTE colon_found = FALSE;
2009 UBYTE position_dot = 0;
2010 SHORT temp_pos = 0;
2011 SHORT position = 0;
2012 SHORT length = 0;
2013 ULONG eppu = 0L;
2014 ULONG temp_eppu = 0L;
2015 UBYTE i;
2016
2017 TRACE_FUNCTION ("aoc_set_puct_values()");
2018
2019 sim_data[0] = puct->currency [0];
2020 sim_data[1] = puct->currency [1];
2021 sim_data[2] = puct->currency [2];
2022
2023 for (i=0;i<20;i++)
2024 {
2025 if (puct->value[i] EQ '\0')
2026 break;
2027
2028 if (first_digit)
2029 {
2030 /* at least one digit detected */
2031 if (colon_found)
2032 {
2033 /* checking the digits after the colon */
2034 switch (puct->value[i])
2035 {
2036 case '0':
2037 /* zeros after the colon are counted */
2038 temp_eppu = temp_eppu * 10 + (puct->value[i] - '0');
2039 temp_pos++;
2040 break;
2041
2042 default:
2043 /* digits available before the colon */
2044 eppu = (temp_eppu * 10) + (puct->value[i] - '0');
2045 temp_eppu = eppu;
2046 length = length + temp_pos + 1;
2047 temp_pos = 0;
2048 if (position_dot)
2049 {
2050 position = position_dot;
2051 position_dot = 0;
2052 }
2053 break;
2054 }
2055 }
2056 else
2057 {
2058 /* checking the digits before the colon */
2059 switch (puct->value[i])
2060 {
2061 case '0':
2062 /* zeros before the colon are counted */
2063 temp_eppu = temp_eppu * 10 + (puct->value[i] - '0');
2064 temp_pos++;
2065 break;
2066
2067 case '.':
2068 colon_found = TRUE;
2069 position_dot = position + temp_pos;
2070 length += temp_pos;
2071 temp_pos = 0;
2072 break;
2073
2074 default:
2075 /* digits available before the colon */
2076 if (temp_pos)
2077 eppu = (temp_eppu * 10) + (puct->value[i] - '0');
2078 else
2079 eppu = eppu * 10 + (puct->value[i] - '0');
2080 temp_eppu = eppu;
2081 length = length + temp_pos + 1;
2082 position = position + temp_pos + 1;
2083 temp_pos = 0;
2084 break;
2085 }
2086 }
2087 }
2088 else
2089 {
2090 /* no digit found */
2091 if (colon_found)
2092 {
2093 /* searching for the first digit after the colon
2094 * e.g. 0.0034 */
2095 switch (puct->value[i])
2096 {
2097 case '0':
2098 /* count the number of zeros after the colon */
2099 temp_pos++;
2100 break;
2101
2102 default:
2103 /* digits available before the colon */
2104 first_digit = TRUE;
2105 position -= temp_pos;
2106 temp_pos = 0;
2107 temp_eppu = eppu = puct->value[i]-'0';
2108 length++;
2109 break;
2110 }
2111 }
2112 else
2113 {
2114 /* checking the digits before the colon
2115 * e.g 234.56 looking for the 2 */
2116 switch (puct->value[i])
2117 {
2118 case '0':
2119 /* leading zeros are ignored */
2120 break;
2121 case '.':
2122 /* no digits before the colon, e.g. 0.23 */
2123 colon_found = TRUE;
2124 break;
2125 default:
2126 /* digits available before the colon */
2127 first_digit = TRUE;
2128 temp_eppu = eppu = puct->value[i]-'0';
2129 position++;
2130 length++;
2131 break;
2132 }
2133 }
2134 }
2135
2136 if (puct->value[i] EQ 0)
2137 break;
2138 }
2139
2140 #if defined WIN32
2141 {
2142 TRACE_EVENT_P2("PUCT POS=%d LEN=%d", position, length);
2143 TRACE_EVENT_P1("EPPU=%d", eppu);
2144 }
2145 #endif
2146
2147 /*
2148 * check the maximum of EPPU
2149 */
2150 if (eppu > 0xFFF)
2151 return FALSE;
2152
2153 /*
2154 * set the EPPU, SEXP and EXP for the SIM Card
2155 */
2156
2157 sim_data[3] = (UBYTE)(eppu >> 4);
2158 sim_data[4] = (UBYTE)(eppu & 0xF);
2159
2160
2161 /*
2162 * for the case : reset PUCT
2163 */
2164 if (!first_digit)
2165 {
2166 /*
2167 * set the first 4 bits of the fifth bytes to 0 (exp2, exp1, exp0, sexp)
2168 */
2169 sim_data[4] = sim_data[4] & 0x0F;
2170 }
2171 else
2172 {
2173 if (!colon_found)
2174 {
2175 if (temp_pos)
2176 {
2177 sim_data[4] += (temp_pos << 5);
2178 }
2179 else
2180 {
2181 sim_data[4] += ((length - position) << 5);
2182 }
2183 }
2184 else
2185 {
2186 if (position_dot NEQ 0)
2187 sim_data[4] += ((length - position) << 5);
2188 else
2189 sim_data[4] += 0x10 + ((length - position) << 5);
2190 }
2191 }
2192 return TRUE;
2193 }
2194
2195
2196 /*
2197 +--------------------------------------------------------------------+
2198 | PROJECT: GSM-PS (6147) MODULE: AOC |
2199 | STATE : code ROUTINE: aoc_parameter |
2200 +--------------------------------------------------------------------+
2201
2202 PURPOSE : Copies the e-parameters of the facility IE.
2203
2204 */
2205 void aoc_parameter(SHORT Cid, T_FWD_CHG_ADVICE_INV * aoc_para)
2206 {
2207 T_chargingInformation * charge;
2208
2209 TRACE_FUNCTION ("aoc_parameter()");
2210
2211 switch (aoc_para->forwardChargeAdviceArg.ssCode)
2212 {
2213 case(SS_CD_AOCI):
2214 cc_aoc_table[Cid].aoci_active=TRUE;
2215 break;
2216 case(SS_CD_AOCC):
2217 cc_aoc_table[Cid].aoci_active=FALSE;
2218 break;
2219 default:
2220 TRACE_EVENT_P1("UNEXPECTED SS_CODE in FWD_AOC %d, assume AOCC", aoc_para->forwardChargeAdviceArg.ssCode);
2221 cc_aoc_table[Cid].aoci_active=FALSE;
2222 }
2223
2224 charge = &aoc_para->forwardChargeAdviceArg.chargingInformation;
2225
2226 cc_aoc_table[Cid].new_data_avail = TRUE;
2227
2228 if (charge->v_e1)
2229 {
2230 if (cc_aoc_table[Cid].aoc_timer_running)
2231 {
2232 /* E1 is available, 4.3.e) special */
2233 cc_aoc_table[Cid].e1_next = aoc_getEVal(&charge->e1);
2234 cc_aoc_table[Cid].e_next_bitmap |= E1_CHANGED;
2235 TRACE_EVENT_P1("E1 = %u", cc_aoc_table[Cid].e1_next);
2236 }
2237 else
2238 {
2239 cc_aoc_table[Cid].e1 = aoc_getEVal(&charge->e1);
2240 TRACE_EVENT_P1("E1 = %u", cc_aoc_table[Cid].e1);
2241 }
2242
2243 }
2244
2245 if (charge->v_e2)
2246 {
2247 if (cc_aoc_table[Cid].aoc_timer_running)
2248 {
2249 /* E2 is available, 4.3.e) special */
2250 cc_aoc_table[Cid].e2_next = aoc_getEVal(&charge->e2);
2251 cc_aoc_table[Cid].e_next_bitmap |= E2_CHANGED;
2252 TRACE_EVENT_P1("E2 = %u", cc_aoc_table[Cid].e2_next);
2253 }
2254 else
2255 {
2256 cc_aoc_table[Cid].e2 = aoc_getEVal(&charge->e2);
2257 TRACE_EVENT_P1("E2 = %u", cc_aoc_table[Cid].e2);
2258 }
2259 }
2260
2261 if (charge->v_e3)
2262 {
2263 /* Special handling of E3, see AOC08226 */
2264 cc_aoc_table[Cid].e3_next = aoc_getEVal(&charge->e3);
2265 cc_aoc_table[Cid].e_next_bitmap |= E3_CHANGED;
2266 TRACE_EVENT_P1("E3 = %u", cc_aoc_table[Cid].e3_next);
2267 }
2268
2269 if (charge->v_e4)
2270 {
2271 cc_aoc_table[Cid].e4 = aoc_getEVal(&charge->e4);
2272 cc_aoc_table[Cid].e_next_bitmap |= E4_CHANGED;
2273 TRACE_EVENT_P1("E4 = %u", cc_aoc_table[Cid].e4);
2274 }
2275
2276 /* e5 and e6 are not (yet?) supported */
2277 if (charge->v_e5)
2278 {
2279 cc_aoc_table[Cid].e5 = aoc_getEVal(&charge->e5);
2280 TRACE_EVENT_P1("E5 = %u", cc_aoc_table[Cid].e5);
2281 }
2282
2283 if (charge->v_e6)
2284 {
2285 cc_aoc_table[Cid].e6 = aoc_getEVal(&charge->e6);
2286 TRACE_EVENT_P1("E6 = %u", cc_aoc_table[Cid].e6);
2287 }
2288
2289 if (charge->v_e7)
2290 {
2291 if (cc_aoc_table[Cid].aoc_timer_running)
2292 {
2293 /* E7 is available, 4.3.e) special */
2294 cc_aoc_table[Cid].e7_next = aoc_getEVal(&charge->e7);
2295 cc_aoc_table[Cid].e_next_bitmap |= E7_CHANGED;
2296 TRACE_EVENT_P1("E7 = %u", cc_aoc_table[Cid].e7_next);
2297 }
2298 else
2299 {
2300 cc_aoc_table[Cid].e7 = aoc_getEVal(&charge->e7);
2301 TRACE_EVENT_P1("E7 = %u", cc_aoc_table[Cid].e7);
2302 }
2303
2304 }
2305
2306 if(cc_aoc_table[Cid].e_next_bitmap & (E1_CHANGED | E2_CHANGED | E7_CHANGED))
2307 {
2308 /* e3 should be applied to the parameters held in abeyance, see AOC08226 */
2309 }
2310 else
2311 {
2312 /* bring e3 immediately into operation */
2313 cc_aoc_table[Cid].e3 = cc_aoc_table[Cid].e3_next;
2314 }
2315
2316
2317
2318 if(cc_aoc_table[Cid].e_next_bitmap & E3_CHANGED)
2319 {
2320 /* e3 is updated recalc is needed now */
2321 aoc_calculate_charging_parameter_part2( Cid );
2322 }
2323
2324 /*
2325 if(cc_aoc_table[Cid].e_next_bitmap & E4_CHANGED)
2326 {
2327 /* if e4 is updated while charging running, charge amount now */
2328 /* if (cc_aoc_table[Cid].aoc_timer_running EQ TRUE)
2329 {
2330 aoc_calculate_charging_parameter_part1( Cid );
2331 aoc_increment_initial_charge( Cid );
2332 cc_aoc_table[Cid].e_next_bitmap &= ~E4_CHANGED;
2333 }
2334 }
2335 */
2336
2337 }
2338
2339 /*
2340 +--------------------------------------------------------------------+
2341 | PROJECT: GSM-PS (6147) MODULE: AOC |
2342 | STATE : code ROUTINE: aoc_getEVal |
2343 +--------------------------------------------------------------------+
2344
2345 PURPOSE : Assembles e-value out of the facility IE.
2346 */
2347
2348 USHORT aoc_getEVal( void * eBuf )
2349 {
2350 T_e1 *pE = (T_e1*)eBuf;
2351 USHORT val = 0;
2352 UBYTE len;
2353
2354 for( len = 0; len < pE->c_e_val; len++ )
2355 {
2356 val<<= 8;
2357 val += pE->e_val[len];
2358 }
2359
2360 return( val );
2361 }
2362
2363
2364 /*
2365 +--------------------------------------------------------------------+
2366 | PROJECT: GSM-PS (6147) MODULE: AOC |
2367 | STATE : code ROUTINE: aoc_send_ccm |
2368 +--------------------------------------------------------------------+
2369
2370 PURPOSE : The ccm is forwarded if at least one of the calls is
2371 active.
2372 */
2373
2374 void aoc_send_ccm ()
2375 {
2376 ULONG ccm_output;
2377 T_ACI_CMD_SRC idx;
2378
2379 if (qAT_CallActive())
2380 {
2381 /* call back function to notify the MMI */
2382 for( idx = 0; idx < CMD_SRC_MAX; idx++ )
2383 {
2384 /*
2385 * forward ccm in whole units to MMI
2386 */
2387 ccm_output = MC_AOC_ROUND_UP(ccm);
2388
2389 R_AT( RAT_CCCM, idx )( &ccm_output );
2390 }
2391 }
2392 }
2393
2394 /*
2395 +--------------------------------------------------------------------+
2396 | PROJECT: GSM-PS (6147) MODULE: AOC |
2397 | STATE : code ROUTINE: aoc_set_time_ut_charge |
2398 +--------------------------------------------------------------------+
2399
2400 PURPOSE : This function is used to set the period of time until
2401 the next charging occur.
2402 */
2403
2404 void aoc_set_time_ut_charge ( SHORT cId, T_TIME time )
2405 {
2406 UBYTE mode = AOC_CALL_TIMER_ELAPSED; /* indicates the elapsed */
2407 /* timer */
2408 /*
2409 * in case an AoC timer is elapsed the time until
2410 * next charging will be fixed to the new value
2411 */
2412 if ( cId NEQ ACI_NumParmNotPresent )
2413 {
2414 cc_aoc_table[cId].time_ut_charge = time;
2415 mode = AOC_AOC_TIMER_ELAPSED;
2416 }
2417
2418 aoc_calc_expct_charge ( mode );
2419 }
2420
2421 /*
2422 +--------------------------------------------------------------------+
2423 | PROJECT: GSM-PS (6147) MODULE: AOC |
2424 | STATE : code ROUTINE: aoc_calc_expct_charge |
2425 +--------------------------------------------------------------------+
2426
2427 PURPOSE : This function is used to calculate the amount of charge
2428 which is going to be consumed during the period of time
2429 fixed by AOC_MAX_REMAIN_CALL_TIME.
2430 */
2431
2432 void aoc_calc_expct_charge ( UBYTE mode )
2433 {
2434 ULONG expct_charge = 0; /* expected charge */
2435 T_TIME remain_time; /* remaining time until next */
2436 ULONG num_chrg_pts; /* number of charging points */
2437 UBYTE idx; /* used for counting */
2438 BOOL aoc_running = FALSE; /* indicates whether at least */
2439 /* one AoC timer is running */
2440
2441 for ( idx = 0; idx < MAX_CALL_NR; idx++ )
2442 {
2443 if ( cc_aoc_table[idx].aoc_timer_running AND cc_aoc_table[idx].e1 )
2444 {
2445 aoc_running = TRUE;
2446
2447 if ( mode EQ AOC_CALL_TIMER_ELAPSED )
2448 {
2449 #if defined (WIN32)
2450 TRACE_EVENT_P1("time to charge: %d ms",
2451 cc_aoc_table[idx].time_ut_charge - AOC_THOUSAND_MILLISECONDS);
2452 #endif
2453
2454 /* in case the call timer is elapsed the actual
2455 * time until next charging will be calculated */
2456 if (cc_aoc_table[idx].time_ut_charge >= AOC_THOUSAND_MILLISECONDS)
2457 {
2458 cc_aoc_table[idx].time_ut_charge -= AOC_THOUSAND_MILLISECONDS;
2459 }
2460 else
2461 {
2462 /* calculate the expected charging intervals based on the E parameter */
2463 if ( cc_aoc_table[idx].new_data_avail EQ TRUE AND
2464 cc_aoc_table[idx].e_next_bitmap & E7_CHANGED )
2465 {
2466 cc_aoc_table[idx].time_ut_charge = aoc_calc_time_ut_charge ( idx, E7_CHANGED );
2467 }
2468 else if ( cc_aoc_table[idx].e_next_bitmap & E2_CHANGED )
2469 {
2470 cc_aoc_table[idx].time_ut_charge = aoc_calc_time_ut_charge ( idx, E2_CHANGED );
2471 }
2472 else
2473 {
2474 cc_aoc_table[idx].time_ut_charge = ~0L;
2475 }
2476
2477 /* calculate the expected initial charge and
2478 * add to the expected charge */
2479 /* The fixed amount is charged immediately and not somewhen later
2480 if ( cc_aoc_table[idx].new_data_avail EQ TRUE AND
2481 cc_aoc_table[idx].e_bitmap & E4_AVAILABLE )
2482 {
2483 expct_charge += ( ( ULONG ) cc_aoc_table[idx].e3 *
2484 ( ULONG ) cc_aoc_table[idx].e4 ) / 10;
2485 }
2486 */
2487 }
2488 }
2489
2490 /* calculate expected charge for next AOC_MAX_REMAIN_CALL_TIME milliseconds */
2491 num_chrg_pts = 1;
2492
2493 if ( cc_aoc_table[idx].time_ut_charge <= AOC_MAX_REMAIN_CALL_TIME )
2494 {
2495 if (cc_aoc_table[idx].e2)
2496 {
2497 remain_time = AOC_MAX_REMAIN_CALL_TIME -
2498 cc_aoc_table[idx].time_ut_charge;
2499 num_chrg_pts +=
2500 (ULONG)(remain_time / E_IN_MS ( cc_aoc_table[idx].e2 ));
2501 }
2502
2503 expct_charge += ( num_chrg_pts *
2504 ( cc_aoc_table[idx].e1 * cc_aoc_table[idx].e3 ) / 10 );
2505 }
2506 }
2507 }
2508
2509 aoc_calc_acm_wrn_evnt ( expct_charge, aoc_running );
2510 }
2511
2512 /*
2513 +--------------------------------------------------------------------+
2514 | PROJECT: GSM-PS (6147) MODULE: AOC |
2515 | STATE : code ROUTINE: aoc_calc_acm_wrn_evnt |
2516 +--------------------------------------------------------------------+
2517
2518 PURPOSE : In case the remaining credit is low a call timer warning
2519 event is generated.
2520 */
2521
2522 void aoc_calc_acm_wrn_evnt ( ULONG charge, BOOL aoc_running )
2523 {
2524 ULONG credit; /* remaining credit */
2525 ULONG acm_for_sim; /* lack of the actual ACM value */
2526 T_ACI_CCWV_CHRG charging; /* CCWV mode indicated to MMI */
2527
2528 /*
2529 * the update on the SIM is the difference between the rounded up
2530 * value of the current CCM and the old CCM (already rounded up)
2531 */
2532 acm_for_sim = MC_AOC_ROUND_UP(ccm) - MC_AOC_ROUND_UP(ccm_already_incremented);
2533 credit = acmmax - acm - ( acm_for_sim * 100 );
2534
2535 #if defined (WIN32)
2536 {
2537 TRACE_EVENT_P2("AoC charge for next %u ms = %u", AOC_MAX_REMAIN_CALL_TIME, charge );
2538 }
2539 #endif
2540
2541 if ( aoc_running EQ TRUE )
2542 {
2543 if ( charge >= credit )
2544 charging = CCWV_CHRG_Shortage;
2545 else
2546 charging = CCWV_CHRG_Abundance;
2547 }
2548 else
2549 charging = CCWV_CHRG_Termination;
2550
2551 aoc_ntfy_acm_wrn_evnt ( charging );
2552 }
2553
2554 /*
2555 +--------------------------------------------------------------------+
2556 | PROJECT: GSM-PS (6147) MODULE: AOC |
2557 | STATE : code ROUTINE: aoc_ntfy_acm_wrn_evnt |
2558 +--------------------------------------------------------------------+
2559
2560 PURPOSE : Notifies the MMI about the call meter warning event.
2561
2562 */
2563 void aoc_ntfy_acm_wrn_evnt ( T_ACI_CCWV_CHRG charging )
2564 {
2565 T_ACI_CMD_SRC idx;
2566
2567 if ( ccwv_charging NEQ charging )
2568 {
2569 ccwv_charging = charging;
2570
2571 for( idx=0; idx<CMD_SRC_MAX; idx++ )
2572 {
2573 R_AT( RAT_CCWV, idx )( charging );
2574 }
2575 }
2576 }
2577
2578 /*
2579 +--------------------------------------------------------------------+
2580 | PROJECT: GSM-PS (6147) MODULE: AOC |
2581 | STATE : code ROUTINE: aoc_calc_time_ut_charge |
2582 +--------------------------------------------------------------------+
2583
2584 PURPOSE : This function calculates the new time to charge with
2585 respect to the previous value.
2586
2587 */
2588 T_TIME aoc_calc_time_ut_charge ( SHORT cId,
2589 UBYTE e_value_flag )
2590 {
2591 T_TIME new_time = ~0L; /* new time until next charging */
2592 T_TIME e_value; /* interval value */
2593
2594 switch ( e_value_flag )
2595 {
2596 case (E2_CHANGED): e_value = E_IN_MS ( cc_aoc_table[cId].e2 );
2597 break;
2598 case (E7_CHANGED): e_value = E_IN_MS ( cc_aoc_table[cId].e7 );
2599 break;
2600 default : e_value = 0L;
2601 break;
2602 }
2603
2604 if ( e_value <= ( AOC_THOUSAND_MILLISECONDS - cc_aoc_table[cId].time_ut_charge ) )
2605 {
2606 new_time = e_value;
2607 }
2608 else if ( e_value NEQ 0L )
2609 {
2610 new_time = e_value - ( AOC_THOUSAND_MILLISECONDS - cc_aoc_table[cId].time_ut_charge );
2611 }
2612
2613 return new_time;
2614 }
2615