view src/aci2/aci/aci_util.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 93999a60b835
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-PS (6147)
|  Modul   :  ACI_UTIL
+----------------------------------------------------------------------------- 
|  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 utility functions for the AT
|             command interpreter.
+----------------------------------------------------------------------------- 
*/ 



#ifndef ACI_UTIL_C
#define ACI_UTIL_C
#endif

#include "aci_all.h"

#include "aci_cmh.h"
#include "ati_cmd.h"

#include "aci_cmd.h"

#ifdef FAX_AND_DATA
#include "aci_fd.h"
#endif    /* of #ifdef FAX_AND_DATA */

#include "psa.h"
#include "psa_sms.h"
#include "phb.h"
#include "cmh.h"
#include "cmh_sms.h"

#if defined (FF_ATI) || defined (FF_BAT)
#include "aci_mem.h"
#include "aci_lst.h"
#include "aci_io.h"
#include "ksd.h"
#include "cmh_ss.h"
#include "psa_ss.h"
#endif
#ifdef FF_ATI
#include "ati_int.h"
#endif
#ifdef FF_BAT
#include "aci_bat_cb.h"
#endif



#ifdef GPRS
#include "gaci_cmh.h"
#endif /* GPRS */

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

#define CSCS_CHSET_Chars  256

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

/*==== EXPORT =====================================================*/
/* This fucntion cuts the pathname from the file
   used by ACI_ASSERT makro*/
GLOBAL char * getFileName(char * file)
{
  char *cursor = file;
  do {
    #ifdef _SIMULATION_
    if(*cursor EQ '\\') { file = cursor+1;}
    #else
    if(*cursor EQ '/') { file = cursor+1;}
    #endif
    cursor++;
  } while(*cursor NEQ '\0');
  return file;
}


LOCAL USHORT utl_ucs2FromGsm ( UBYTE*           in,
                              USHORT           inLen,
                              UBYTE*           out,
                              USHORT           maxOutLen,
                              USHORT*          outLen,
                              T_ACI_GSM_ALPHA  gsm,
                              T_ACI_CSCS_ALPHA alphabet );

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

GLOBAL const UBYTE chset [CSCS_CHSET_Tables][CSCS_CHSET_Chars] =
{
/*
 *-------------------------------------------------------------------
 * Conversion table: IRA -> internal GSM
 *-------------------------------------------------------------------
 */
/* 0x00 */  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */    0x00, 0x00, 0x8A, 0x00, 0x00, 0x8D, 0x00, 0x00,
/* 0x10 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x18 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */    0xA0, 0xA1, 0xA2, 0xA3, 0x82, 0xA5, 0xA6, 0xA7,
/* 0x28 */    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
/* 0x30 */    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
/* 0x38 */    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
/* 0x40 */    0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
/* 0x48 */    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
/* 0x50 */    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
/* 0x58 */    0xD8, 0xD9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x91/*00*/,
/* 0x60 */    0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
/* 0x68 */    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
/* 0x70 */    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
/* 0x78 */    0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x80 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x88 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x90 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x98 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },

/*
 *-------------------------------------------------------------------
 * Conversion table: PC Danish/Norwegian -> internal GSM
 *-------------------------------------------------------------------
 */
/* 0x00 */  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */    0x00, 0x00, 0x8A, 0x00, 0x00, 0x8D, 0x00, 0x00,
/* 0x10 */    0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x00,
/* 0x18 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */    0xA0, 0xA1, 0xA2, 0xA3, 0x82, 0xA5, 0xA6, 0xA7,
/* 0x28 */    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
/* 0x30 */    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
/* 0x38 */    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
/* 0x40 */    0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
/* 0x48 */    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
/* 0x50 */    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
/* 0x58 */    0xD8, 0xD9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x91/*00*/,
/* 0x60 */    0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
/* 0x68 */    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
/* 0x70 */    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
/* 0x78 */    0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x80 */    0x89, 0xFE, 0x85, 0xE1, 0xFB, 0xFF, 0x8F, 0x89,
/* 0x88 */    0xE5, 0xE5, 0x84, 0xE9, 0xE9, 0x87, 0xDB, 0x8E,
/* 0x90 */    0x9F/*C5*/, 0x9D, 0x9C, 0xEF, 0xFC, 0x88, 0xF5/*E5*/, 0x86,
/* 0x98 */    0xF9/*E9*/, 0xDC, 0xDE, 0x8C, 0x81, 0x8B, 0x00, 0x00,
/* 0xA0 */    0xE1, 0xE9, 0xEF, 0xF5, 0xFD, 0xDD, 0x00, 0x00,
/* 0xA8 */    0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
/* 0xB0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE0 */    0x00, 0x9E, 0x93, 0x00, 0x98, 0x00, 0x00, 0x00,
/* 0xE8 */    0x92, 0x99, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },

/*
 *-------------------------------------------------------------------
 * Conversion table: ISO 8859 Latin 1 -> internal GSM
 *-------------------------------------------------------------------
 */
/* 0x00 */  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */    0x00, 0x00, 0x8A, 0x00, 0x00, 0x8D, 0x00, 0x00,
/* 0x10 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x18 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */    0xA0, 0xA1, 0xA2, 0xA3, 0x82, 0xA5, 0xA6, 0xA7,
/* 0x28 */    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
/* 0x30 */    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
/* 0x38 */    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
/* 0x40 */    0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
/* 0x48 */    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
/* 0x50 */    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
/* 0x58 */    0xD8, 0xD9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x91/*00*/,
/* 0x60 */    0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
/* 0x68 */    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
/* 0x70 */    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
/* 0x78 */    0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x80 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x88 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x90 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x98 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA0 */    0x00, 0xC0, 0x00, 0x81, 0xA4, 0x83, 0x00, 0xDF,
/* 0xA8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
/* 0xC0 */    0xC1, 0xC1, 0xC1, 0xC1, 0xDB, 0x8E, 0x9C, 0x89,
/* 0xC8 */    0xC5, 0x9F/*C5*/, 0xC5, 0xC5, 0xC9, 0xC9, 0xC9, 0xC9,
/* 0xD0 */    0x00, 0xDD, 0xCF, 0xCF, 0xCF, 0xCF, 0xDC, 0x00,
/* 0xD8 */    0x8B, 0xD5, 0xD5, 0xD5, 0xDE, 0xD9, 0x00, 0x9E,
/* 0xE0 */    0xFF, 0xE1, 0xE1, 0xE1, 0xFB, 0x8F, 0x9D, 0x89,
/* 0xE8 */    0x84, 0x85, 0xE5, 0xE5, 0x87, 0xE9, 0xE9, 0xE9,
/* 0xF0 */    0x00, 0xFD, 0x88, 0xEF, 0xEF, 0xEF, 0xFC, 0x00,
/* 0xF8 */    0x8C, 0x86, 0xF5, 0xF5, 0xFE, 0xF9, 0x00, 0xF9 },

/*
 *-------------------------------------------------------------------
 * Conversion table: PC Code Page 437 -> internal GSM
 *-------------------------------------------------------------------
 */
/* 0x00 */  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */    0x00, 0x00, 0x8A, 0x00, 0x00, 0x8D, 0x00, 0x00,
/* 0x10 */    0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x00,
/* 0x18 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */    0xA0, 0xA1, 0xA2, 0xA3, 0x82, 0xA5, 0xA6, 0xA7,
/* 0x28 */    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
/* 0x30 */    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
/* 0x38 */    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
/* 0x40 */    0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
/* 0x48 */    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
/* 0x50 */    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
/* 0x58 */    0xD8, 0xD9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x91/*00*/,
/* 0x60 */    0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
/* 0x68 */    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
/* 0x70 */    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
/* 0x78 */    0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x80 */    0x89, 0xFE, 0x85, 0xE1, 0xFB, 0xFF, 0x8F, 0x89,
/* 0x88 */    0xE5, 0xE5, 0x84, 0xE9, 0xE9, 0x87, 0xDB, 0x8E,
/* 0x90 */    0x9F/*C5*/, 0x9D, 0x9C, 0xEF, 0xFC, 0x88, 0xF5/*E5*/, 0x86,
/* 0x98 */    0xF9/*E9*/, 0xDC, 0xDE, 0x00, 0x81, 0x83, 0x00, 0x00,
/* 0xA0 */    0xE1, 0xE9, 0xEF, 0xF5, 0xFD, 0xDD, 0x00, 0x00,
/* 0xA8 */    0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
/* 0xB0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE0 */    0x00, 0x9E, 0x93, 0x00, 0x98, 0x00, 0x00, 0x00,
/* 0xE8 */    0x92, 0x99, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },

/*
 *-------------------------------------------------------------------
 * Conversion table: GSM -> internal GSM
 *-------------------------------------------------------------------
 */
/* 0x00 */  { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
/* 0x08 */    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
/* 0x10 */    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
/* 0x18 */    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
/* 0x20 */    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
/* 0x28 */    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
/* 0x30 */    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
/* 0x38 */    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
/* 0x40 */    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
/* 0x48 */    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
/* 0x50 */    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
/* 0x58 */    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
/* 0x60 */    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
/* 0x68 */    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
/* 0x70 */    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
/* 0x78 */    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
/* 0x80 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x88 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x90 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x98 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xA8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xB8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xC8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xD8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xE8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF0 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0xF8 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};


/*
 *-------------------------------------------------------------------
 * Conversion table: ASCII <-> internal GSM
 * ( needed for the conversion of UCS2 <-> internal GSM )
 *-------------------------------------------------------------------
 */
/* GSM alphabet characters unknown in the ASCII table have been 
   replaced by <SP> characters */
LOCAL const UBYTE gsmToAsciiTable[128] =
{   
    /*n =     0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
/* 0x0n */   64,163, 36,165,232,233,249,236,242,199, 10,216,248, 13,197,229,
/* 0x1n */  128, 95,129,130,131,132,133,134,135,136,137, 32,198,230,223,201,
/* 0x2n */   32, 33, 34, 35,164, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
/* 0x3n */   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
/* 0x4n */  161, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
/* 0x5n */   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,196,214,209,220,167,
/* 0x6n */  191, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
/* 0x7n */  112,113,114,115,116,117,118,119,120,121,122,228,246,241,252,224
};

LOCAL const UBYTE  hexVal[] = {"0123456789ABCDEF"};

/*
static const unsigned char
gsm_2_ascii_table[128] = 
{
  0x40, 0x9C, 0x24, 0x9D, 0x8A, 0x82, 0x97, 0x8D, 0x95, 0x80, 0x0A, 0x02, 0x07, 0x0D, 0x8F, 0x86,
  0x04, 0x5F, 0xE8, 0xE2, 0xEF, 0xEA, 0xE3, 0x05, 0xE6, 0xE9, 0xF0, 0x20, 0x92, 0x91, 0xE1, 0x90, 
  0x20, 0x21, 0x22, 0x23, 0x01, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
  0xAD, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x8E, 0x99, 0xA5, 0x9A, 0x06,
  0xA8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x84, 0x94, 0xA4, 0x81, 0x85
};
*/

/*==== FUNCTIONS ==================================================*/
#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : strupper                     |
+-------------------------------------------------------------------+

  PURPOSE : Converts all characters from 'a' to 'z' to capital
            characters from 'A' to 'Z'.
*/
GLOBAL char* strupper ( char* s )
{
  USHORT i = 0;

  while ( s NEQ 0 AND s[i] NEQ '\0')
  {
    if ( s[i] >= 0x61 AND s[i] <= 0x7a )

      s[i] = s[i] - 0x20;

    i++;
  }

  return s;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_chsetToGsm               |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the character set used within the AT command interpreter
            to the SIM GSM character set.
*/
GLOBAL void utl_chsetToSim ( UBYTE*          in,
                             USHORT          inLen,
                             UBYTE*          out,
                             USHORT*         outLen,
                             T_ACI_GSM_ALPHA gsm )
{
  UBYTE  cvtdVal;
  USHORT outIdx   = 0;
  USHORT inIdx;
  UBYTE  corr     = ( gsm EQ GSM_ALPHA_Int ? 0xFF : 0x7F );
  T_ACI_CSCS_CHSET cscsChset;
  UBYTE  srcId = srcId_cb;

  cscsChset = ati_user_output_cfg[srcId].cscsChset;
  
  if ( cscsChset EQ CSCS_CHSET_Hex )
  {
    utl_hexToGsm ( in, inLen, out, outLen, gsm, CSCS_ALPHA_8_Bit );
  }
  else if ( cscsChset EQ CSCS_CHSET_Ucs2 )
  {
    /* If the user chooses UCS2, then the best mode of coding should be 
     * used to store the characters in the SIM */
    utl_ucs2ToSim(in, inLen, out, outLen, gsm, CSCS_ALPHA_8_Bit);
  }
  else
  {
    for ( inIdx = 0; inIdx < inLen; inIdx++ )
    {
      cvtdVal = chset[cscsChset][( UBYTE ) in[inIdx]];

      if ( cvtdVal NEQ 0x00 )
      {
        out[outIdx] = ( CHAR ) cvtdVal & corr;
        outIdx++;
      }
    }

    if ( gsm EQ GSM_ALPHA_Int )
      out[outIdx] = '\0';

    *outLen = outIdx;
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_codeUcs2                 |
+-------------------------------------------------------------------+

  PURPOSE : This function finds optimal coding format to store the 
            UCS2 character string in the phone book.
*/
GLOBAL void utl_ucs2ToSim( UBYTE*          in,
                           USHORT          inLen,
                           UBYTE*          out,
                           USHORT*         outLen,
                           T_ACI_GSM_ALPHA gsm,
                           T_ACI_CSCS_ALPHA alphabet)
{
  int    i;
  BOOL   flag = TRUE;
  USHORT ucs2_len = inLen/4;
  UBYTE  hexOut[MAX_ALPHA_LEN * 4];
  USHORT hexOutLen = 0;

  /* Convert the hex character string to actual hex values */
  hexOutLen = utl_HexStrToBin(in, inLen, hexOut, (MAX_ALPHA_LEN * 4));

  /* Initial check is done for GSM or ASCII only characters */
  for(i = 0; i < (hexOutLen/2); i++)
  {
    if(( hexOut[i*2] NEQ 0x00 ))
    {
      flag = FALSE;
      break;
    }
  }
  if (flag EQ TRUE)
  {
    utl_ConvUcs2ToGSM(hexOut, hexOutLen, out, outLen, gsm, alphabet);
    if (*outLen)
      return;
  }

  /* If possible UCS2 character string is coded in 0x81 format which
     uses a one byte base pointer */
  utl_Ucs2InFormat1 (hexOut, hexOutLen, out, outLen);
  if (*outLen)
    return;

  /* If possible UCS2 character string is coded in 0x82 format which
     uses two byte base pointer */
  utl_Ucs2InFormat2 (hexOut, hexOutLen, out, outLen);
  if (*outLen)
    return;

  /* If none of the above work, UCS2 character string is coded in 0x80 */
  *out = 0x80;
  utl_hexToGsm ( in, inLen, out + 1, outLen, gsm, CSCS_ALPHA_8_Bit );
  (*outLen)++;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_ConvUcs2ToGSM            |
+-------------------------------------------------------------------+

  PURPOSE : This function converts UCS2 charecter string consisting of 
            only ASCII charecters to default GSM values.
*/
GLOBAL void utl_ConvUcs2ToGSM ( UBYTE*           in,
                                USHORT           inLen,
                                UBYTE*           out,
                                USHORT*          outLen,
                                T_ACI_GSM_ALPHA  gsm,
                                T_ACI_CSCS_ALPHA alphabet )
{
  int i, j;
  BOOL   flag;
  UBYTE  val = 0x00;
  USHORT len;
  UBYTE  tmpOut;
  USHORT outIdx = 0;

  len = inLen/2;
  for (i = 0;i < len; i++)
  {
    tmpOut = in[(i*2) + 1];    
    /* convert the hexadecimal ASCII value to GSM, if the value is
     * not convertible then we exit */
    if ( tmpOut EQ ( gsmToAsciiTable[tmpOut])) /* ASCII and GSM are identical */
    {
      val = tmpOut;
    }
    else /* find match in the table and copy index of match */
    {
      flag = FALSE;
      for (j=0; j<128; j++)
      {
        if (tmpOut EQ gsmToAsciiTable[j])
        {
          val = (UBYTE)j;
          flag = TRUE;
          break;
        }
      }
      if (!flag)
      {
        *outLen = 0;
        return;
      }
    }      
    
    /* if necessary, cut the GSM value to 7bit */
    if ( alphabet EQ CSCS_ALPHA_7_Bit AND !( val & 0x80 ) )
    {
      if ( gsm EQ GSM_ALPHA_Int )
      {
        out[outIdx++] = val | 0x80; 
      }
      else
      {
        out[outIdx++] = val;
      }
    }
    else
    {
      out[outIdx++] = val;
    }
  }
      
  if ( gsm EQ GSM_ALPHA_Int )
  {
    out[outIdx] = '\0';
  }

  /* set the outlength */
  *outLen = outIdx;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_Ucs2InFormat1            |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the UCS2 character string in the 
            0x81 coding scheme for UCS2.
            Octet 1: 0x81
            Octet 2: Num of Characters
            Octet 3: Bits 15 to 8 of Base pointer
            Octet 4 onwards: Characters
*/
GLOBAL void utl_Ucs2InFormat1( UBYTE*           in,
                               USHORT           inLen,
                               UBYTE*           out,
                               USHORT*          outLen)
{
  int i, j;
  UBYTE  base_ptr = 0x00;
  UBYTE  temp_ptr;
  USHORT len = inLen/2;
  USHORT tmp_base;
  USHORT tmp;
  USHORT outIdx = 0;
  

  /* We first check if the UCS2 string can be coded 
   * using a single base pointer */
  for (i = 0; i < len; i++)
  {
    if (in[i*2])
    {
      if ((in[i*2] & 0x80))
      {
        *outLen = 0;
        return;
      }
      temp_ptr = in[i*2] & 0x7f;
      temp_ptr <<= 1;
      temp_ptr |= ((in[(i*2)+1] & 0x80) >> 7);
      
      if (base_ptr)
      {
        if (temp_ptr NEQ base_ptr)
        {
          *outLen = 0;
          return;           
        }
      } else
      {
        base_ptr = temp_ptr;
      }
    }
  }


  /* Characters are coded using the base pointer below */
  /* For details, see GSM 11.11 Annex B (normative) */
  out[0] = 0x81;
  if (len < PHB_MAX_TAG_LEN - 3)
  {
    out[1] = (UBYTE)len;
  } else
  {
    out[1] = PHB_MAX_TAG_LEN - 3;
  }
  out[2]   = base_ptr;
  tmp_base = 0;
  tmp_base = base_ptr << 7;
  outIdx   = 3;

  len = out[1];
  for (i = 0; i < len; i++)
  {
    if (in[i*2])
    {
      tmp  = 0;
      tmp  = in[i*2] << 8;
      tmp |= in[(i*2)+1];
      out[outIdx++] = (tmp - tmp_base) | 0x80;
    } else 
    {
      for (j=0; j<128; j++)
      {
        if (in[(i*2)+1] EQ gsmToAsciiTable[j])
        {
          out[outIdx++] = (UBYTE)j;
          break;
        }
      }

   /* If the charecter cannot be found in ASCII table exit */
   if (j EQ 128)
   {
     *outLen = 0;
     return ;
   }

    }
  }

  *outLen = outIdx;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_Ucs2InFormat2            |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the UCS2 character string in the 
            0x82 coding scheme for UCS2.
            Octet 1: 0x82
            Octet 2: Number of characters
            Octet 3 and Octet 4: 2 byte base pointer
            Octet 5 onwards: Characters 
            
*/
GLOBAL void utl_Ucs2InFormat2( UBYTE*           in,
                               USHORT           inLen,
                               UBYTE*           out,
                               USHORT*          outLen)
{
  int i, j;
  USHORT len = inLen/2;
  USHORT lowest_ch  = 0;
  USHORT highest_ch = 0;
  USHORT tmp;
  USHORT outIdx = 0;
  

  /* We first check if the UCS2 string can be coded 
   * using a smallest char as the base pointer */
  for (i = 0; i < len; i++)
  {
    if (in[i*2])
    {
      tmp  = 0;
      tmp  = in[i*2] << 8;
      tmp |= in[(i*2)+1];

      if (lowest_ch EQ 0 OR tmp < lowest_ch)
        lowest_ch = tmp;

      if (tmp > highest_ch)
        highest_ch = tmp;
    }
  }

  /* To use lowest char can be used as the base pointer, the distance
   * between the lowest and highest char must not be more then 128 */
  if ((highest_ch - lowest_ch) > 0x80)
  {
    *outLen = 0;
    return;
  }

  /* Characters are coded using the base pointer below */
  /* For details, see GSM 11.11 Annex B (normative) */
  out[0] = 0x82;
  if (len < PHB_MAX_TAG_LEN - 4)
  {
    out[1] = (UBYTE)len;
  } else
  {
    out[1] = PHB_MAX_TAG_LEN - 4;
  }
  out[2] = (lowest_ch & 0xff00) >> 8;
  out[3] = (lowest_ch & 0x00ff);  
  outIdx   = 4;

  len = out[1];
  for (i = 0; i < len; i++)
  {
    if (in[i*2])
    {
      tmp  = 0;
      tmp  = in[i*2] << 8;
      tmp |= in[(i*2)+1];
      out[outIdx++] = (tmp - lowest_ch) | 0x80;
    } else 
    {
      for (j=0; j<128; j++)
      {
        if (in[(i*2)+1] EQ gsmToAsciiTable[j])
        {
          out[outIdx++] = (UBYTE)j;
          break;
        }
      }

    /* If the charecter cannot be found in ASCII table exit */
     if (j EQ 128)
     {
      *outLen = 0;
      return ;
     }
    }
  }

  *outLen = outIdx;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_chsetToGsm               |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the character set used within the AT command interpreter
            to the ACI internal GSM character set.
*/
GLOBAL void utl_chsetToGsm ( UBYTE*          in,
                             USHORT          inLen,
                             UBYTE*          out,
                             USHORT*         outLen,
                             T_ACI_GSM_ALPHA gsm )
{
  UBYTE  cvtdVal;
  USHORT outIdx   = 0;
  USHORT inIdx;
  UBYTE  corr     = ( gsm EQ GSM_ALPHA_Int ? 0xFF : 0x7F );
  T_ACI_CSCS_CHSET cscsChset;
  UBYTE  srcId = srcId_cb;

  cscsChset = ati_user_output_cfg[srcId].cscsChset;

  if ( ati_user_output_cfg[srcId].cscsChset EQ CSCS_CHSET_Hex )
  {
    utl_hexToGsm ( in, inLen, out, outLen, gsm, CSCS_ALPHA_8_Bit );
  }
  else if ( cscsChset EQ CSCS_CHSET_Ucs2 )
  {
    utl_ucs2ToGsm ( in, inLen, out, outLen, gsm, CSCS_ALPHA_8_Bit );
  }
  else
  {
    for ( inIdx = 0; inIdx < inLen; inIdx++ )
    {
      cvtdVal = chset[cscsChset][( UBYTE ) in[inIdx]];

      if ( cvtdVal NEQ 0x00 )
      {
        out[outIdx] = ( CHAR ) cvtdVal & corr;
        outIdx++;
      }
    }

    if ( gsm EQ GSM_ALPHA_Int )
      out[outIdx] = '\0';

    *outLen = outIdx;
  }
}
#endif


#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_hexFromAlpha             |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the SIM with UCS2 form 0x81 or 0x82 to 16 Bit hex values.
            see GSM 11.11 Annex B Coding of Alpha fields in the SIM for UCS2
            UCS2 form 0x81:
             - octet 1 = 0x81
             - octet 2 = length
             - octet 3 = Bits 15 to 8 of the base pointer to a half page in the UCS2 code space
                         0hhh hhhh h000 0000 , with h = bits of the half page base pointer
                        16... .... .... ...1

            UCS2 form 0x82:
             - octet 1 = 0x81
             - octet 2 = length
             - octet 3 = upper 8 Bit of 16 Bit base pointer to a half page in the UCS2 code space
             - octet 4 = lower 8 Bit of 16 Bit base pointer to a half page in the UCS2 code space           
*/
GLOBAL void utl_hexFromUCS2  ( UBYTE  *in, 
                              UBYTE  *out, 
                              USHORT  maxOutlen, 
                              USHORT *outlen)
{
  USHORT outIdx = 0;
  USHORT base_pointer;
  USHORT length = in[1];
  USHORT tmp;

  if (*in EQ 0x81)
  {
    base_pointer = in[2] << 7;
    in += 3;
  }
  else /* if (*in EQ 0x82) */
  {
    base_pointer = in[2]<<8 | in[3];
    in += 4;
  }
  
  while ( length-- AND outIdx < maxOutlen-2)
  {  
    if (*in & 0x80)
    {
      tmp  = base_pointer + (*in & 0x7F); 
    }
    else
    {
      tmp  = 0x0000 + gsmToAsciiTable[*in];
    }
    out[outIdx++] = hexVal[(tmp >> 12) & 0x0F ];
    out[outIdx++] = hexVal[(tmp >>  8) & 0x0F ];
    out[outIdx++] = hexVal[(tmp >>  4) & 0x0F ];
    out[outIdx++] = hexVal[(tmp      ) & 0x0F ];

    in++;
  }

  out[outIdx] = '\0';
  *outlen = outIdx;
}
#endif


#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_chsetFromGsm             |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the SIM format to the character set
            used within the AT command interpreter.
*/
GLOBAL void utl_chsetFromSim ( UBYTE*          in,
                               USHORT          inLen,
                               UBYTE*          out,
                               USHORT          maxOutLen,
                               USHORT*         outLen,
                               T_ACI_GSM_ALPHA gsm )
{
  T_ACI_CSCS_CHSET cscsChset;
  UBYTE srcId = srcId_cb;

  cscsChset = ati_user_output_cfg[srcId].cscsChset;

  if ( cscsChset EQ CSCS_CHSET_Ucs2 AND
        (( *in EQ 0x80 ) OR ( *in EQ 0x81 ) OR ( *in EQ 0x82 )) )
  {
    /* UCS2 with form 0x81 or 0x82 as HEX string */
    if (( *in EQ 0x81 ) OR ( *in EQ 0x82 ))
    {
      utl_hexFromUCS2 ( in, out, maxOutLen, outLen);
      return;
    }
    
    /* UCS2 form 0x80 as HEX string */
    utl_hexFromGsm ( in + 1, (USHORT)( inLen - 1 ), out, maxOutLen, outLen,
                     gsm, CSCS_ALPHA_8_Bit );
  } 
  else 
  {
    utl_chsetFromGsm ( in, inLen, out, maxOutLen, outLen, gsm );
  }
}
#endif /* #ifdef FF_ATI */

#if defined(FF_ATI) || defined(FF_BAT)
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_chsetFromGsm             |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the ACI internal GSM character set to the character set
            used within the AT command interpreter.
*/

GLOBAL USHORT utl_chsetFromGsm(
  UBYTE*            in,
  USHORT            inLen,
  UBYTE*            out,
  USHORT            maxOutLen,
  USHORT*           outLen,
  T_ACI_GSM_ALPHA   gsm)
{
  USHORT outIdx = 0;
  USHORT inIdx  = 0;
  USHORT actLen = ( gsm EQ GSM_ALPHA_Int ?
                        ( USHORT ) strlen ( ( CHAR* ) in ) : inLen );
  UBYTE  corr   = ( gsm EQ GSM_ALPHA_Int ? 0x00 : 0x80 );
  T_ACI_CSCS_CHSET cscsChset;
  UBYTE  srcId = srcId_cb;
  USHORT tblIdx;

  cscsChset = ati_user_output_cfg[srcId].cscsChset;

  if ( cscsChset EQ CSCS_CHSET_Hex )
  {
    return utl_hexFromGsm ( in, inLen, out, maxOutLen, outLen, gsm, CSCS_ALPHA_8_Bit );
  }
  else if ( cscsChset EQ CSCS_CHSET_Ucs2 )
  {
    return utl_ucs2FromGsm ( in, inLen, out, maxOutLen, outLen, gsm, CSCS_ALPHA_8_Bit );
  }
  else
  {
    while ( inIdx < actLen AND outIdx < maxOutLen - 1 )
    {
      tblIdx = 0;

      while ( tblIdx <= 0xFF                                      AND
              chset[cscsChset][tblIdx] NEQ (( UBYTE )in[inIdx] | corr ))
        tblIdx++;

      if ( tblIdx <= 0xFF )
      {
        out[outIdx] = ( UBYTE )tblIdx;
        outIdx++;
      }

      inIdx++;
    }

    out[outIdx] = '\0';
    *outLen     = outIdx;

    return inIdx;
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_sprints                  |
+-------------------------------------------------------------------+

  PURPOSE : This function writes a not null terminated string to a
            buffer.
*/
GLOBAL USHORT sprints ( CHAR* buf, CHAR* arg, USHORT len )
{
  buf[0] = '\"';

  memcpy ( &buf[1], arg, len );

  buf[len + 1] = '\"';
  buf[len + 2] = '\0';

  return (len + 2);
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_sprintq                  |
+-------------------------------------------------------------------+

  PURPOSE : This function writes a not null terminated string to a
            buffer.
*/
GLOBAL USHORT sprintq ( CHAR* buf, CHAR* arg, USHORT len )
{
  memcpy ( &buf[0], arg, len );

  buf[len] = '\0';

  return (len);
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_hexToIntGsm              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the "HEX" character set to the ACI internal GSM
            character set.
*/
GLOBAL void utl_hexToGsm ( UBYTE*           in,
                           USHORT           inLen,
                           UBYTE*           out,
                           USHORT*          outLen,
                           T_ACI_GSM_ALPHA  gsm,
                           T_ACI_CSCS_ALPHA alphabet )
{
  SHORT  val    = 0;
  UBYTE  digit;
  USHORT inIdx  = 0;
  USHORT outIdx = 0;
  SHORT  base   = 0x10;

  while ( inIdx < inLen )
  {
    if ( in[inIdx] >= 0x30 AND in[inIdx] <= 0x39 )        /* '0' ... '9' */
    {
      digit = in[inIdx] - 0x30;                           /* ->0 ... 9  */
    }
    else if ( in[inIdx] >= 0x61 AND in[inIdx] <= 0x66 )   /* 'a' ... 'f' */
    {
      digit = in[inIdx] - 0x61 + 0x0A;                    /* ->0x0a...0x0f */
    }
    else if ( in[inIdx] >= 0x41 AND in[inIdx] <= 0x46 )   /* 'A' ... 'F' */
    {
      digit = in[inIdx] - 0x41 + 0x0A;                    /* ->0x0a...0x0f */
    }
    else
    {
      digit = 0xFF;
    }

    if ( digit NEQ 0xFF )  /* skip invalid digit */
    {
      if ( base EQ 0x10 )
      {
        val = digit << 4;
      }
      else
      {
        val |= digit;

        if ( alphabet EQ CSCS_ALPHA_7_Bit AND !( val & 0x80 ) )
        {
          if ( gsm EQ GSM_ALPHA_Int )
          {
            out[outIdx++] = ( CHAR ) val | 0x80;
          }
          else
          {
            out[outIdx++] = ( CHAR ) val;
          }
        }
        else if ( alphabet NEQ CSCS_ALPHA_7_Bit )
        {
          out[outIdx++] = ( CHAR ) val;
        }
      }

      base ^= 0x10;
    }

    inIdx++;
  }

  if ( gsm EQ GSM_ALPHA_Int )
    out[outIdx] = '\0';

  *outLen = outIdx;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_ucs2ToGsm              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the "UCS2" character set to the ACI internal GSM
            character set.
*/
GLOBAL void utl_ucs2ToGsm ( UBYTE*           in,
                           USHORT           inLen,
                           UBYTE*           out,
                           USHORT*          outLen,
                           T_ACI_GSM_ALPHA  gsm,
                           T_ACI_CSCS_ALPHA alphabet )
{
  int i, j;
  UBYTE val;
  USHORT len;
  UBYTE tmpIn[2];  /* store temporary two chars (HEX conversion) */
  UBYTE tmpInIdx;  /* holds a temporary index for two chars (HEX conversion)*/
  UBYTE digit;     /* holds a digit (HEX conversion) */
  SHORT tmpVal;    /* hold a temporary value (HEX conversion) */
  UBYTE tmpOut; /* the HEX output (HEX conversion) */ 
  SHORT  base   = 0x10;
  USHORT outIdx = 0;
  UBYTE tmpInLen = 2; 
  
  /* TRACE_FUNCTION(" utl_ucs2ToGsm() "); */
  
  len = inLen/4;
  
  for (i=0;i<len;i++)
  {
    /* check if this is a UCS2 character in 00xy format */
    if ( ( in[i*4] EQ '0' ) AND ( in[i*4+1] EQ '0' )  ) 
    {
      /* convert the next two character to HEX */
      tmpIn[0] = in[i*4+2];
      tmpIn[1] = in[i*4+3];

      tmpVal = tmpOut = val = 0;
      
      /* convert the two characters into the real hexadecimal ASCII value */
      for( tmpInIdx=0; tmpInIdx<2; tmpInIdx++ )
      {
        if ( tmpIn[tmpInIdx] >= '0' AND tmpIn[tmpInIdx] <= '9' )
        {
          digit = tmpIn[tmpInIdx] - '0';
        }
        else if ( tmpIn[tmpInIdx] >= 'a' AND tmpIn[tmpInIdx] <= 'f' )
        {
          digit = tmpIn[tmpInIdx] - 'a' + 0x0A;
        }
        else if ( tmpIn[tmpInIdx] >= 'A' AND tmpIn[tmpInIdx] <= 'F' )
        {
          digit = tmpIn[tmpInIdx] - 'A' + 0x0A;
        }
        else
        {
          digit = 0xFF;
        }
        
        if ( digit NEQ 0xFF )
        {
          if ( base EQ 0x10 )
          {
            tmpVal = digit * 0x10;
          }
          else
          {
            tmpVal += digit;
            tmpOut = (UBYTE) tmpVal;
          }
          
          base ^= 0x10;
        }
      }      
      
      /* convert the hexadecimal ASCII value to GSM */
      if (!(tmpOut & 0x80))  
      {
        if ( tmpOut EQ ( gsmToAsciiTable[tmpOut])) /* ASCII and GSM are identical */
        {
          val = tmpOut;
        }
        else /* find match in the table and copy index of match */
        {
          for (j=0; j<128; j++)
          {
            if (tmpOut EQ gsmToAsciiTable[j])
            {
              val = (UBYTE)j;
              break;
            }
          }
        }      
      }
      else /* find match in the table and copy index of match */
      {
        for (j=0; j<128; j++)
        {
          if (tmpOut EQ gsmToAsciiTable[j])
          {
            val = (UBYTE)j;
            break;
          }
        }
      }
      
      /* if necessary, cut the GSM value to 7bit */
      if ( alphabet EQ CSCS_ALPHA_7_Bit AND !( val & 0x80 ) )
      {
        if ( gsm EQ GSM_ALPHA_Int )
        {
          out[outIdx++] = val | 0x80; 
        }
        else
        {
          out[outIdx++] = val;
        }
      }
      else
      {
        out[outIdx++] = val;
      }
    }
    
    else  /* unknown char, skip it */
    {
      /* TRACE_EVENT("UCS2 MISMATCH: Unknown UCS2 entry, character skipped!"); */
      /* out[outIdx++] = '?'; */
    }
  }
  
  if ( gsm EQ GSM_ALPHA_Int )
  {
    out[outIdx] = '\0';
  }
  
  /* set the outlength */
  *outLen = outIdx;
  
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_hexFromGsm               |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the ACI internal GSM character set to the "HEX"
            character set.
*/
GLOBAL USHORT utl_hexFromGsm ( UBYTE*           in,
                             USHORT           inLen,
                             UBYTE*           out,
                             USHORT           maxOutLen,
                             USHORT*          outLen,
                             T_ACI_GSM_ALPHA  gsm,
                             T_ACI_CSCS_ALPHA alphabet )
{
  USHORT inIdx  = 0;
  USHORT outIdx = 0;

  while ( inIdx < inLen AND outIdx < maxOutLen - 2 )
  {
      if ( alphabet NEQ CSCS_ALPHA_7_Bit OR
         ( gsm EQ GSM_ALPHA_Def AND !( in[inIdx] & 0x80 ) )  OR
         ( gsm EQ GSM_ALPHA_Int AND  ( in[inIdx] & 0x80 ) ) )
    {
      out[outIdx++] = hexVal[ in[inIdx] >> 4    ];
      out[outIdx++] = hexVal[ in[inIdx] &  0x0F ];
    }

    inIdx++;
  }

  out[outIdx] = '\0';
  *outLen     = outIdx;
  
  return inIdx;
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_ucs2FromGsm              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the ACI internal GSM character set to the "UCS2"
            character set.
*/
LOCAL USHORT utl_ucs2FromGsm (UBYTE*           in,
                              USHORT           inLen,
                              UBYTE*           out,
                              USHORT           maxOutLen,
                              USHORT*          outLen,
                              T_ACI_GSM_ALPHA  gsm,
                              T_ACI_CSCS_ALPHA alphabet )
{
  USHORT inIdx  = 0;
  USHORT outIdx = 0;

  while ( inIdx < inLen AND outIdx < maxOutLen - 4 )
  {
    if ( alphabet NEQ CSCS_ALPHA_7_Bit OR
       ( gsm EQ GSM_ALPHA_Def AND !( in[inIdx] & 0x80 ) )     OR
       ( gsm EQ GSM_ALPHA_Int AND  ( in[inIdx] & 0x80 ) ) )
    {
      /* Insert two leading Os, convert GSM to ASCII and print out as HEX  */
      out[outIdx++] = '0';
      out[outIdx++] = '0';
      out[outIdx++] = hexVal[ gsmToAsciiTable[in[inIdx]] >> 4    ];
      out[outIdx++] = hexVal[ gsmToAsciiTable[in[inIdx]] &  0x0F ];
    }

    inIdx++;
  }

  out[outIdx] = '\0';
  *outLen     = outIdx;
  
  return inIdx;

}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_smDtaToTe                |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the SM data in the format
            specified in Rec. GSM 07.05, message data parameter
            <data>, to the format used by the AT Command Interface.
*/
GLOBAL void utl_smDtaToTe ( UBYTE*  in,
                            USHORT  inLen,
                            UBYTE*  out,
                            USHORT  maxOutLen,
                            USHORT* outLen,
                            UBYTE   fo,
                            UBYTE   dcs )
{
  UBYTE alphabet = cmhSMS_getAlphabetPp ( dcs );

  if ( alphabet EQ CSCS_ALPHA_7_Bit AND
       (fo & TP_UDHI_MASK) EQ TP_UDHI_WITHOUT_HEADER )
  {
    utl_chsetFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def );
  }
  else if ( alphabet NEQ CSCS_ALPHA_7_Bit OR
            (fo & TP_UDHI_MASK) EQ TP_UDHI_WITH_HEADER )
  {
    utl_hexFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def, 
                     CSCS_ALPHA_8_Bit );
  }
  else
  {
    *outLen = MINIMUM ( inLen, maxOutLen - 1 );
    memcpy ( out, in,  *outLen );
    out[*outLen] = '\0';
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_smDtaFromTe              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the SM data in the format used
            by the AT Command Interface to the format specified in
            Rec. GSM 07.05, message data parameter <data>.
*/
GLOBAL void utl_smDtaFromTe ( UBYTE*  in,
                              USHORT  inLen,
                              UBYTE*  out,
                              USHORT* outLen,
                              UBYTE   fo,
                              UBYTE   dcs )
{
  UBYTE alphabet = cmhSMS_getAlphabetPp ( dcs );

  if ( alphabet EQ CSCS_ALPHA_7_Bit                AND
       ( fo & TP_UDHI_MASK ) EQ TP_UDHI_WITHOUT_HEADER )
  {
    utl_chsetToGsm ( in, inLen, out, outLen, GSM_ALPHA_Def );
  }
  else if ( alphabet NEQ CSCS_ALPHA_7_Bit             OR
            ( fo & TP_UDHI_MASK ) EQ TP_UDHI_WITH_HEADER )
  {
    utl_hexToGsm ( in, inLen, out, outLen, GSM_ALPHA_Def, alphabet );
  }
  else
  {
    memcpy ( out, in, inLen );
    *outLen = inLen;
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_ussdDtaFromTe            |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the USSD data in the format used
            by the AT Command Interface to the format specified in
            Rec. GSM 07.07.
*/
GLOBAL void utl_ussdDtaFromTe ( UBYTE*  in,
                                USHORT  inLen,
                                UBYTE*  out,
                                USHORT* outLen,
                                UBYTE   dcs )
{
  UBYTE alphabet = cmhSMS_getAlphabetCb ( dcs );

  if ( alphabet EQ CSCS_ALPHA_7_Bit )
  {
    utl_chsetToGsm ( in, inLen, out, outLen, GSM_ALPHA_Def );
  }
  else
  {
    utl_hexToGsm ( in, inLen, out, outLen, GSM_ALPHA_Def, alphabet );
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_ussdDtaToTe              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the USSD data in the format
            specified in Rec. GSM 07.07 to the format used
            by the AT Command Interface.
*/

GLOBAL USHORT utl_ussdDtaToTe ( UBYTE*  in,
                              USHORT  inLen,
                              UBYTE*  out,
                              USHORT  maxOutLen,
                              USHORT* outLen,
                              UBYTE   dcs )
{
  UBYTE alphabet = cmhSMS_getAlphabetCb ( dcs );

  if ( alphabet EQ CSCS_ALPHA_7_Bit )
  {
    return utl_chsetFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def );
  }
  else
  {
    return utl_hexFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def, alphabet );
  }
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_cbmDtaToTe               |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the CBM data in the format
            specified in Rec. GSM 07.05, message data parameter
            <data>, to the format used by the AT Command Interface.
*/
GLOBAL void utl_cbmDtaToTe ( UBYTE*  in,
                             USHORT  inLen,
                             UBYTE*  out,
                             USHORT  maxOutLen,
                             USHORT* outLen,
                             UBYTE   fo,
                             UBYTE   dcs )
{
  UBYTE alphabet = cmhSMS_getAlphabetCb ( dcs );

  if ( alphabet EQ CSCS_ALPHA_7_Bit                AND
       ( fo & TP_UDHI_MASK ) EQ TP_UDHI_WITHOUT_HEADER )
  {
    utl_chsetFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def );
  }
  else if ( alphabet NEQ CSCS_ALPHA_7_Bit             OR
            ( fo & TP_UDHI_MASK ) EQ TP_UDHI_WITH_HEADER )
  {
    utl_hexFromGsm ( in, inLen, out, maxOutLen, outLen, GSM_ALPHA_Def, alphabet );
  }
  else
  {
    *outLen = MINIMUM ( inLen, maxOutLen );
    memcpy ( out, in, *outLen );
  }
}
#endif

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_cvtGsmIra                |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the characters of a string from
            the ACI internal GSM character set to the IRA character
            set or vice versa.
*/
GLOBAL BOOL utl_cvtGsmIra ( UBYTE*         in,
                            USHORT         inLen,
                            UBYTE*         out,
                            USHORT         outLen,
                            T_ACI_CSCS_DIR dir )
{
  USHORT inIdx  = 0;
  USHORT outIdx = 0;
  USHORT tblIdx;
  UBYTE  cvtdVal;

  TRACE_FUNCTION("utl_cvtGsmIra()");


  if ( inLen > outLen )
  {
    return ( FALSE );
  }

  if ( dir EQ CSCS_DIR_GsmToIra )
  {
    while ( inIdx < inLen )
    {
      tblIdx = 0;

      while ( tblIdx <= 0xFF                                             AND
              chset[CSCS_CHSET_Ira][tblIdx] NEQ (( UBYTE )in[inIdx] | 0x80 ))
        tblIdx++;

      if ( tblIdx <= 0xFF )
      {
        out[outIdx] = ( UBYTE )tblIdx;
        outIdx++;
      }
      else
      {
        return ( FALSE );
      }

      inIdx++;
    }
  }
  else if ( dir EQ CSCS_DIR_IraToGsm )
  {
    for ( inIdx = 0; inIdx < inLen; inIdx++ )
    {
      cvtdVal = chset[CSCS_CHSET_Ira][( UBYTE ) in[inIdx]];

      if ( cvtdVal NEQ 0x00 )
      {
        out[outIdx] = ( CHAR ) cvtdVal & 0x7F;
        outIdx++;
      }
      else
      {
        return ( FALSE );
      }
    }

  }
  else
  {
    return ( FALSE );
  }

  return ( TRUE );
}


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_binToHex                 |
+-------------------------------------------------------------------+

  PURPOSE : This function converts a binary string of bytes with a
            given length into an null terminated ASCII string
            representation.
*/
GLOBAL void utl_binToHex (UBYTE*         in,
                          SHORT          inLen,
                          CHAR*          out )
{
  SHORT idx = 0;
  UBYTE hNib;
  UBYTE lNib;

  while( idx < inLen )
  {
    hNib = (in[idx]&0xF0)>>4;

    if( hNib > 9 ) *out = (hNib-10)+0x41;
    else           *out = hNib + 0x30;

    out++;

    lNib = in[idx]&0x0F;

    if( lNib > 9 ) *out = (lNib-10)+0x41;
    else           *out = lNib + 0x30;

    out++;
    idx++;
  }
  *out = 0x0;
}


#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM              MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : utl_HexStrToBin              |
+-------------------------------------------------------------------+

  PURPOSE : This function converts a null terminated string of HEX
            values in a binary buffer.
            RETURN: byte count.
*/
GLOBAL USHORT utl_HexStrToBin (UBYTE         *in,
                               USHORT         inLen,
                               UBYTE         *out,
                               USHORT         outLen)
{
  USHORT inIdx = 0;
  USHORT outIdx = 0;
  UBYTE value;
  BOOL  hNib = TRUE;

  while ((inIdx < inLen) AND (outIdx < outLen))
  {
    if ((in[inIdx] >= 0x30) AND (in[inIdx] <= 0x39))
    {
      value = in[inIdx] - 0x30;
    }
    else if ((in[inIdx] >= 0x61) AND (in[inIdx] <= 0x66))
    {
      value = in[inIdx] - 0x61 + 0x0A;
    }
    else if ((in[inIdx] >= 0x41) AND (in[inIdx] <= 0x46))
    {
      value = in[inIdx] - 0x41 + 0x0A;
    }
    else
    {
      return (0);
    }

    if (hNib)
    {
      out[outIdx] = (value << 0x04) & 0xF0;
      hNib = FALSE;
    }
    else
    {
      out[outIdx] |= value & 0x0F;
      hNib = TRUE;
      outIdx++;
    }
    inIdx++;
  }

  return (outIdx);
}
#endif

#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : trace_cmd_line               |
+-------------------------------------------------------------------+

  PURPOSE : This function trace the command line and check
            this string for % character
*/

GLOBAL void trace_cmd_line (char *prefix, char *output, UBYTE srcId, USHORT output_len)
{
  char trcBuf[80];
  int dst_i;

  dst_i = sprintf (trcBuf, "%s(Src %d)[lth %d]", (prefix) ? prefix : "", srcId, output_len);

  strncpy(&trcBuf[dst_i], output, 79-dst_i);
  trcBuf[79] = '\0';

  if (trcBuf[76])
  {
    trcBuf[76] = trcBuf[77] = trcBuf[78] = '.';  /* add trailing "..." if string is >=76 */
  }

  /* Send the trace if either EVENT or CLASS8 is turned on */
  TRACE_USER_CLASS_P1(TC_EVENT|TC_USER8, "%s",trcBuf);
}
#endif


#ifdef FF_ATI
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : ACI_UTIL                     |
| STATE   : code             ROUTINE : trace_cmd_state              |
+-------------------------------------------------------------------+

  PURPOSE : This function trace the command line state
*/

GLOBAL void trace_cmd_state (UBYTE            srcId, 
                             T_ATI_CMD_STATE  old_state, 
                             T_ATI_CMD_STATE  new_state)
{
  char trcBuf[50];

  if (old_state EQ new_state)
  {
    return;
  }

  sprintf (trcBuf, "(Src %d) cmd_state: ", srcId );

  switch (old_state)
  {
    case (CMD_IDLE):
      strcat (trcBuf, "CMD_IDLE -> ");
      break;
    case (CMD_TYPING):
      strcat (trcBuf, "CMD_TYPING -> ");
      break;
    case (CMD_RUNNING):
      strcat (trcBuf, "CMD_RUNNING -> ");
      break;
    default:
      strcat (trcBuf, "CMD_UNKNOWN ! ");
  }
  
  switch (new_state)
  {
    case (CMD_IDLE):
      strcat (trcBuf, "CMD_IDLE");
      break;
    case (CMD_TYPING):
      strcat (trcBuf, "CMD_TYPING");
      break;
    case (CMD_RUNNING):
      strcat (trcBuf, "CMD_RUNNING");
      break;
    default:
      strcat (trcBuf, "CMD_UNKNOWN !");
  }

  TRACE_EVENT_P1("%s",trcBuf);
}
#endif

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_CMD            |
| STATE   : code                        ROUTINE : toa_merge          |
+--------------------------------------------------------------------+

  PURPOSE : builds type of address octet from TOA structure

*/

GLOBAL UBYTE toa_merge (T_ACI_TOA type)
{

return   ((type.ton << 4) & 0xF0) 
       | ( type.npi       & 0x0F)
       | 0x80;
}



#ifdef GPRS
/*
  +-----------------------------------------------------------------------------
  | Function    : utl_create_pco
  +-----------------------------------------------------------------------------
  | Description : The function create_pco() creates protocol configuration
  |               options needed to activate a PDPcontext.
  |
  | Parameters  : buffer      - buffer to write the PCOs
  |               length      - on call: buffer size; on return: written bytes
  |               content     - mask to specify the PCO content
  |               config_prot - used configuration protocol (currently PPP)
  |               auth_prot   - authentication protocol (currently PAP)
  |               user_name   - string with the user name
  |               password    - string with the password
  |               dns1        - requested primary DNS address
  |               dns2        - requested secondary DNS address
  |
  | Return      :  0 - operation successful
  |               -1 - operation fails
  |
  +-----------------------------------------------------------------------------
*/
GLOBAL int utl_create_pco (UBYTE*  buffer,
                           USHORT* length,
                           ULONG   content,
                           UBYTE   config_prot,
                           USHORT  auth_prot,
                           UBYTE*  user_name,
                           UBYTE*  password,
                           ULONG   dns1,
                           ULONG   dns2)
{
  USHORT  size;
  USHORT  temp_len;
  USHORT  len_user;
  USHORT  len_pwd;
  USHORT  written;
  UBYTE*  pos;
  UBYTE*  len_pos1;
  UBYTE*  len_pos2;

  TRACE_FUNCTION( "create_pco" );

  /*
   * store buffer size
   */
  size = *length;
  /*
   * initialize values
   */
  *length = 0;
  written = 0;
  pos     = buffer;
  /*
   * calculate if requested content is writeable
   */
  temp_len = 1;
  if(content & ACI_PCO_CONTENTMASK_AUTH)
  {
    len_user = strlen((char*)user_name);
    len_pwd  = strlen((char*)password);
    temp_len+= ACI_PCO_PAP_OVERHEAD + len_user + len_pwd;
  }
  if((content & ACI_PCO_CONTENTMASK_DNS1) ||
     (content & ACI_PCO_CONTENTMASK_DNS2))
  {
    temp_len+= ACI_PCO_IPCP_OVERHEAD;
    if(content & ACI_PCO_CONTENTMASK_DNS1)
      temp_len+= ACI_PCO_IPCP_LENGTH_DNS1;
    if(content & ACI_PCO_CONTENTMASK_DNS2)
      temp_len+= ACI_PCO_IPCP_LENGTH_DNS2;
  }
  TRACE_EVENT_P2("temp_len=%d size=%d", temp_len, size);
  if(temp_len > size)
  {
    /*
     * content is to long
     */
    return -1;
  }
  /*
   * set configuration protocol identifier
   */
  *pos = 0x80 | config_prot;
  pos++;
  written++;

  /*
   * authentication
   */
  if(content & ACI_PCO_CONTENTMASK_AUTH)
  {
    /*
     * set authentication protocol
     */
    *pos = (UBYTE)((auth_prot >> 8) & 0x00ff);
    pos++;
    written++;
    *pos = (UBYTE)(auth_prot        & 0x00ff);
    pos++;
    written++;
    /*
     * store first length position
     */
    len_pos1 = pos;
    pos++;
    written++;
    /*
     * Code field
     */
    *pos = ACI_PCO_PAP_AUTH_REQ;
    pos++;
    written++;
    /*
     * Identifier field (just some value)
     */
    *pos = 0x01;
    pos++;
    written++;
    /*
     * Length field (store length position)
     */
    *pos = 0x00;
    pos++;
    written++;
    len_pos2 = pos;
    pos++;
    written++;
    /*
     * User Name Length field
     */
    *pos = (UBYTE)(/*lint -e(644) */len_user & 0x00ff);
    pos++;
    written++;
    /*
     * User Name field
     */
    memcpy(pos, user_name, len_user);
    pos    += len_user;
    written+= len_user;
    /*
     * Password Length field
     */
    *pos = (UBYTE)(/*lint -e(644) */len_pwd & 0x00ff);  
    pos++;
    written++;
    /*
     * Password field
     */
    memcpy(pos, password, len_pwd);
    pos    += len_pwd;
    written+= len_pwd;
    /*
     * fill length fields
     */
    *len_pos1 = (UBYTE)(pos - len_pos1 - 1);
    *len_pos2 = *len_pos1;
  }
  /*
   * DNS addresses
   */
  if((content & ACI_PCO_CONTENTMASK_DNS1) ||
     (content & ACI_PCO_CONTENTMASK_DNS2))
  {
    /*
     * set IPCP protocol
     */
    *pos = ACI_PCO_IPCP_PROT_MSB;
    pos++;
    written++;
    *pos = ACI_PCO_IPCP_PROT_LSB;
    pos++;
    written++;
    /*
     * store first length position
     */
    len_pos1 = pos;
    pos++;
    written++;
    /*
     * Code field
     */
    *pos = ACI_PCO_IPCP_CONF_REQ;
    pos++;
    written++;
    /*
     * Identifier field (just some value)
     */
    *pos = 0x01;
    pos++;
    written++;
    /*
     * Length field (store length position)
     */
    *pos = 0x00;
    pos++;
    written++;
    len_pos2 = pos;
    pos++;
    written++;
    /*
     * primary DNS address
     */
    if(content & ACI_PCO_CONTENTMASK_DNS1)
    {
      /*
       * Type field
       */
      *pos = ACI_PCO_IPCP_TYPE_DNS1;
      pos++;
      written++;
      /*
       * Length field
       */
      *pos = ACI_PCO_IPCP_LENGTH_DNS1;
      pos++;
      written++;
      /*
       * primary DNS address
       */
      *pos = (UBYTE)((dns1 >> 24) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)((dns1 >> 16) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)((dns1 >>  8) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)(dns1         & 0x000000ff);
      pos++;
      written++;
    }
    /*
     * secondary DNS address
     */
    if(content & ACI_PCO_CONTENTMASK_DNS2)
    {
      /*
       * Type field
       */
      *pos = ACI_PCO_IPCP_TYPE_DNS2;
      pos++;
      written++;
      /*
       * Length field
       */
      *pos = ACI_PCO_IPCP_LENGTH_DNS2;
      pos++;
      written++;
      /*
       * primary DNS address
       */
      *pos = (UBYTE)((dns2 >> 24) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)((dns2 >> 16) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)((dns2 >>  8) & 0x000000ff);
      pos++;
      written++;
      *pos = (UBYTE)(dns2         & 0x000000ff);
      pos++;
      written++;
    }
    /*
     * fill length fields
     */
    *len_pos1 = (UBYTE)(pos - len_pos1 - 1);
    *len_pos2 = *len_pos1;
  }
  /*
   * pass written bytes to caller
   */
  *length = written;
  /*
   * return result
   */
  return 0;
} /* utl_create_pco() */



/*
  +-----------------------------------------------------------------------------
  | Function    : utl_analyze_pco
  +-----------------------------------------------------------------------------
  | Description : The function analyze_pco() analyzes the response protocol
  |               configuration from the network
  |
  | Parameters  : buffer  - buffer with the response PCOs
  |               length  - length of PCOs
  |               dns1    - returns primary DNS address
  |               dns2    - returns secondary DNS address
  |               gateway - returns Gateway address
  |
  | Return      :  0 - operation successful
  |               -1 - operation fails
  |
  +-----------------------------------------------------------------------------
*/
GLOBAL int utl_analyze_pco (UBYTE* buffer,
                            USHORT length,
                            ULONG* dns1,
                            ULONG* dns2,
                            ULONG* gateway)
{
  UBYTE*  pos;
  USHORT  pos_len;
  USHORT  packet_len;
  USHORT  start_pos;
  USHORT  dist_to_next;
  UBYTE   type_len;

  TRACE_FUNCTION( "utl_analyze_pco" );

  /*
   * initialize values
   */
  pos      = buffer;
  pos_len  = 0;
  *dns1    = 0;
  *dns2    = 0;
  *gateway = 0;
  /*
   * check configuration protocol
   */
  if( (length <= pos_len) ||
      !(*pos & 0x80) )
  {
    return -1;
  }

#if 0
  /* Table 10.5.154/3GPP TS 24.008 states:
       "All other values are interpreded as PPP in this version of the protocol.
     so the next check should not be performed
   */
  if((*pos & 0x07) NEQ ACI_PCO_CONFIG_PROT_PPP)
  {
    /*
     * configuration protocol is not PPP
     */
    return 0;
  }
#endif

  pos++;
  pos_len++;
  
  /*
   * search for IPCP packet
   */
  while(length > (pos_len + ACI_PCO_IPCP_OVERHEAD))
  {
    /*
     * initialize distance to next packet
     */
    dist_to_next = *(pos + 2) + 3;
    /*
     * check for IPCP packet
     */
    if((*pos       EQ ACI_PCO_IPCP_PROT_MSB) &&
       (*(pos + 1) EQ ACI_PCO_IPCP_PROT_LSB))
    {
      /*
       * check for correct length field
       */
      pos         += 2;
      pos_len     += 2;
      dist_to_next-= 2;
      packet_len   = *(pos + 3);
      packet_len   = packet_len << 8;
      packet_len  += *(pos + 4);
      if((packet_len EQ *pos) &&
         (length > (pos_len + packet_len)))
      {
        pos++;
        pos_len++;
        dist_to_next--;
        /*
         * check of code field
         */
        start_pos = pos_len;
        switch(*pos)
        {
          case ACI_PCO_IPCP_CONF_REQ:
            /*
             * search for Gateway address
             */
            pos    += 4;
            pos_len+= 4;
            while((pos_len + 1 - start_pos) < packet_len)
            {
              type_len = *(pos + 1);
              if((*pos     EQ ACI_PCO_IPCP_TYPE_IP) &&
                 (type_len EQ ACI_PCO_IPCP_LENGTH_IP) &&
                 ((pos_len +
                   ACI_PCO_IPCP_LENGTH_IP -
                   start_pos) <= packet_len))
              {
                *gateway = *(pos + 2);
                *gateway = ((*gateway) << 8);
                *gateway+= *(pos + 3);
                *gateway = ((*gateway) << 8);
                *gateway+= *(pos + 4);
                *gateway = ((*gateway) << 8);
                *gateway+= *(pos + 5);
              }
              pos    += type_len;
              pos_len+= type_len;
            }
            if((pos_len - start_pos) <= packet_len)
            {
              dist_to_next = packet_len + start_pos - pos_len;
            }
            else
            {
              dist_to_next = 0;
              pos         -= (pos_len - start_pos - packet_len);
              pos_len     -= (pos_len - start_pos - packet_len);
            }
            break;

          case ACI_PCO_IPCP_CONF_ACK:
          case ACI_PCO_IPCP_CONF_NAK:
            /*
             * search for DNS addresses
             */
            pos    += 4;
            pos_len+= 4;
            while((pos_len + 1 - start_pos) < packet_len)
            {
              type_len = *(pos + 1);
              if((*pos     EQ ACI_PCO_IPCP_TYPE_DNS1) &&
                 (type_len EQ ACI_PCO_IPCP_LENGTH_DNS1) &&
                 ((pos_len +
                   ACI_PCO_IPCP_LENGTH_DNS1 -
                   start_pos) <= packet_len))
              {
                *dns1 = *(pos + 2);
                *dns1 = ((*dns1) << 8);
                *dns1+= *(pos + 3);
                *dns1 = ((*dns1) << 8);
                *dns1+= *(pos + 4);
                *dns1 = ((*dns1) << 8);
                *dns1+= *(pos + 5);
              }
              else if((*pos     EQ ACI_PCO_IPCP_TYPE_DNS2) &&
                      (type_len EQ ACI_PCO_IPCP_LENGTH_DNS2) &&
                      ((pos_len +
                        ACI_PCO_IPCP_LENGTH_DNS2 -
                        start_pos) <= packet_len))
              {
                *dns2 = *(pos + 2);
                *dns2 = ((*dns2) << 8);
                *dns2+= *(pos + 3);
                *dns2 = ((*dns2) << 8);
                *dns2+= *(pos + 4);
                *dns2 = ((*dns2) << 8);
                *dns2+= *(pos + 5);
              }
              pos    += type_len;
              pos_len+= type_len;
            }
            if((pos_len - start_pos) <= packet_len)
            {
              dist_to_next = packet_len + start_pos - pos_len;
            }
            else
            {
              dist_to_next = 0;
              pos         -= (pos_len - start_pos - packet_len);
              pos_len     -= (pos_len - start_pos - packet_len);
            }
            break;
        }
      }
    }
    /*
     * go to next packet
     */
    pos_len+= dist_to_next;
    pos    += dist_to_next;
  }
  /*
   * return
   */
  return 0;
} /* utl_analyze_pco() */




GLOBAL int utl_strcasecmp (const char *s1, const char *s2)
{
  char c1, c2;
  int i;

  int len1 = (s1 == NULL) ? 0 : strlen(s1);
  int len2 = (s2 == NULL) ? 0 : strlen(s2);

  if (len1 > len2) 
  {
    return (1);
  }
  if(len1 < len2) 
  {
    return (-1);
  }
  for (i = 0; i < len1; i++)
  {
    c1 = s1[i];
    c2 = s2[i];
    if (c1 == c2)
    {
      continue ;
    }
    if (c1 >= 'a' AND c1 <= 'z')
    {
      c1 = c1 - ('a'-'A');
    }
    if (c2 >= 'a' AND c2 <= 'z')
    {
      c2 = c2 - ('a'-'A');
    }
    if (c1 != c2)
    {
      return (1);
    }
  }
  return (0);
}


#endif /* GPRS */



#if defined (FF_ATI) || defined (FF_BAT)

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : ACI_UTIL                 |
| STATE   : code                  ROUTINE : rci_display_USSD         |
+--------------------------------------------------------------------+

  PURPOSE : used by rCI_PlusCUSD and utl_cb_percentKSIR
*/
GLOBAL void rci_display_USSD (UBYTE            srcId,
                              T_ACI_CUSD_MOD   mode,
                              UBYTE            *ussd_str,
                              UBYTE            ussd_len,
                              BOOL             cvtStr,
                              SHORT            dcs )
{
  SHORT  pos = 0;
  USHORT chunksize;
  USHORT lenCvtdStr;
  CHAR sa[80];


  TRACE_FUNCTION("rci_display_USSD()");

  pos = sprintf(sa,"+CUSD: ");

  if (mode NEQ CUSD_MOD_NotPresent)
  {
    pos += sprintf(sa+pos,"%d,",mode);
  }
  else
    pos += sprintf(sa+pos,",");

  if(ussd_str NEQ NULL)
  {
    pos += sprintf(sa+pos,"\"");    /* beginning double quote */
    while (ussd_len)
    {
      if( cvtStr EQ CONVERT_STRING )
      {
        chunksize = utl_ussdDtaToTe( ussd_str,
                         (USHORT)ussd_len,
                         (UBYTE*)(sa + pos),
                         sizeof(sa)-pos,
                         &lenCvtdStr,
                         (UBYTE)dcs );

        pos += lenCvtdStr;
      }
      else
      {
        /*
        *   How much space do we have left in the output array?
        */
        chunksize=(sizeof(sa)-pos)-1;

        if (ussd_len<chunksize)
        {
          /*
          *   Remaining data fits within the output array.
          */
          chunksize=ussd_len;
        }
        else if (chunksize>3)
        {
          /*
          *   If the remaining data will not fit in the output
          *   array, and we have more than 3 bytes available (which
          *   we will), make sure that the amount of data output
          *   divides by 4. This is so we don't split UCS2 characters
          *   between two lines of output.
          */
          chunksize &= ~0x3;
        }

        memcpy(sa+pos,ussd_str,chunksize);
        
        pos += chunksize;

        sa[pos]=0;
      }
      ussd_len-=chunksize;
      ussd_str+=chunksize;

      if (ussd_len OR (sizeof(sa)-pos) < 10)
      {
#ifdef _SIMULATION_
        io_sendMessage(srcId, sa, ATI_NORMAL_OUTPUT);   /* append CR+LF only for testcase */
#else
        io_sendMessage(srcId, sa, ATI_ECHO_OUTPUT);     /* normal output a chunk */
#endif
        pos=0;
        memset(sa, 0, 80);
      }
    }

    pos+=sprintf(sa+pos,"\",");   /* ending double quote */

    if (dcs EQ ACI_NumParmNotPresent)
    {
      /* see 07.07: default is 0 */
      dcs = 0;
    }

    pos+=sprintf(sa+pos,"%d",dcs);
  }
  
  ci_remTrailCom(sa, pos);
  io_sendMessage(srcId, sa, ATI_NORMAL_OUTPUT);
}

/*
 ****************************************************************
 */
LOCAL void utl_cvtCLIRStat ( UBYTE clirOpt,
                             UBYTE ssSt,
                             T_ACI_CLIR_STAT *clirStat )
{
  if ( clirOpt EQ KSD_CO_NOT_VALID )
  {
    /* SS Status of class - T_ACI_KSD_ST */
    if ( ssSt EQ KSD_ST_NOT_VALID )
      *clirStat = CLIR_STAT_Unknown;
    else if ( ssSt & SSS_P )
      *clirStat = CLIR_STAT_Permanent;
    else
      *clirStat = CLIR_STAT_NotProv;
  }
  else
  {
    switch ( clirOpt )
    {
      case( CLIR_OPT_PERMANENT ):
        *clirStat = CLIR_STAT_Permanent;
        break;

      case( CLIR_OPT_TEMPORARY ):
        *clirStat = CLIR_STAT_RestrictTemp;
        break;

      case( CLIR_OPT_ALLOWED ):
        *clirStat = CLIR_STAT_AllowTemp;
        break;

      default:
        *clirStat = CLIR_STAT_Unknown;
        break;
    }
  }
}

/*
 ****************************************************************
 */
LOCAL  void utl_cb_ccbs( UBYTE srcId, T_ACI_KSIR * ksStat )
{
  T_ACI_CCBS_SET *CCBS_Setting = NULL;

  T_ACI_CCBS_STAT status;
  T_basicService basicServ;
  int i;
  T_CC_FEAT *ccbs_features;

  TRACE_FUNCTION("utl_cb_ccbs()");

  /* SS Status of CCBS */
  if (ksStat->ir.rKSCC.ssSt EQ KSD_ST_NOT_VALID)
    status = CCBS_STAT_NotPresent;
  else if (!(ksStat->ir.rKSCC.ssSt & SSS_P))
    status = CCBS_STAT_NotProvisioned;
  else if (ksStat->ir.rKSCC.ssSt & SSS_A)
    status = CCBS_STAT_Active;
  else
    status = CCBS_STAT_Provisioned;

  ACI_MALLOC(CCBS_Setting, sizeof(T_ACI_CCBS_SET));

  /* CCBS_Setting infos */
  if (!ksStat->ir.rKSCC.c_ccFeatLst)
  {
    TRACE_EVENT("KSD_CMD_CCBS: no feature list");

    if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
    {
      rCI_PercentCCBS(CCBS_IND_IrgtResult,
                      status,
                      CCBS_Setting,
                      TRUE);
    }
#ifdef FF_BAT
    else /* CMD_MODE_BAT */
    {
      rBAT_PercentCCBS(CCBS_IND_IrgtResult,
                       status,
                       CCBS_Setting,
                       TRUE);
   }
#endif
    return;
  }

  for (i=0; i<ksStat->ir.rKSCC.c_ccFeatLst; i++)
  {
    ccbs_features = ksStat->ir.rKSCC.ccFeatLst + i;

    memcpy( CCBS_Setting->number, ccbs_features->num, MAX_B_SUBSCR_NUM_LEN);
    memcpy( CCBS_Setting->subaddr, ccbs_features->sub, MAX_SUBADDR_LEN);

    CCBS_Setting->type.npi   = ccbs_features->npi NEQ 0xFF 
                               ? (T_ACI_TOA_NPI)ccbs_features->npi 
                               : NPI_NotPresent;
    CCBS_Setting->type.ton   = ccbs_features->ton NEQ 0xFF 
                               ? (T_ACI_TOA_TON)ccbs_features->ton 
                               : TON_NotPresent;
    CCBS_Setting->satype.tos = ccbs_features->tos NEQ 0xFF 
                               ? (T_ACI_TOS_TOS)ccbs_features->tos 
                               : TOS_NotPresent;
    CCBS_Setting->satype.oe  = ccbs_features->oe NEQ 0xFF 
                               ? (T_ACI_TOS_OE)ccbs_features->oe 
                               : OE_NotPresent;

    if( ccbs_features->bsTp EQ BS_TELE_SRV )
    {
      basicServ.v_teleservice = TRUE;
      basicServ.v_bearerService = FALSE;
      basicServ.teleservice = ccbs_features->bsCd;
    }
    else /* if( p_servType EQ BS_BEAR_SRV ) */
    {
      basicServ.v_bearerService = TRUE;
      basicServ.v_teleservice = FALSE;
      basicServ.bearerService = ccbs_features->bsCd;
    }
    
    CCBS_Setting->class_type = cmhSS_GetClass( &basicServ );

    CCBS_Setting->idx = ccbs_features->idx NEQ 0xFF 
                        ? ccbs_features->idx 
                        : ACI_NumParmNotPresent;
    
    CCBS_Setting->alrtPtn = ALPT_NotPresent;
    
    if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
    {
      rCI_PercentCCBS(CCBS_IND_IrgtResult,
                      status,
                      CCBS_Setting,
                      TRUE);
    }
#ifdef FF_BAT
    else /* CMD_MODE_BAT */
    {
      rBAT_PercentCCBS(CCBS_IND_IrgtResult,
                      status,
                      CCBS_Setting,
                      TRUE);
    }
#endif
  }

  ACI_MFREE( CCBS_Setting );
}

/*
 ****************************************************************
 */
LOCAL void utl_cb_callwaiting( UBYTE srcId, T_ACI_KSIR *ksStat )
{
  T_ACI_CLSSTAT   classStat;
  UBYTE           idx;
  T_ACI_TOA       type;

  TRACE_FUNCTION("utl_cb_callwaiting()");

  if ( ksStat->ir.rKSCW.opCd NEQ KSD_OP_IRGT )
    return;

  /* SS Status of class - T_ACI_KSD_ST */
  if ( ksStat->ir.rKSCW.ssSt EQ KSD_ST_NOT_VALID )
  {
    classStat.status = STATUS_NotPresent;
  }
  else if ( ksStat->ir.rKSCW.ssSt & KSD_ST_A )
  {
    classStat.status = STATUS_Active;
  }
  else
  {
    classStat.status = STATUS_NotActive;
  }

  /* init parameter type: */
  type.npi = NPI_NotPresent;
  type.ton = TON_NotPresent;

  for( idx = 0; idx < ksStat->ir.rKSCW.c_cwBSGLst; idx++ )
  {
    /* type of class */
    classStat.class_type = cmhSS_GetClassType(ksStat->ir.rKSCW.cwBSGLst[idx].bsTp,
                                              ksStat->ir.rKSCW.cwBSGLst[idx].bsCd);
    if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
    {
    }
    else /* CMD_MODE_BAT */
    {
    }
    
    rCI_PlusCCWA(&classStat,"\0", &type, PRES_NOT_PRES, CLASS_NotPresent, NULL);
  }
}

/*
 ****************************************************************
 */
LOCAL  void utl_cb_lineidentification( UBYTE srcId, T_ACI_KSIR * ksStat )
{
  T_ACI_CLIP_STAT clipStat;
  T_ACI_CLIR_MOD  clirMode;
  T_ACI_CLIR_STAT clirStat;
  T_ACI_COLP_STAT colpStat;
  T_ACI_COLR_STAT colrStat;

  TRACE_FUNCTION("utl_cb_lineidentification()");

  if ( ksStat->ir.rKSCL.opCd NEQ KSD_OP_IRGT )
    return;

  switch ( ksStat->ir.rKSCL.ssCd )
  {
    case KSD_SS_CLIP:
     {
      /* SS Status of class - T_ACI_KSD_ST */
      if ( ksStat->ir.rKSCL.ssSt EQ KSD_ST_NOT_VALID )
        clipStat = CLIP_STAT_Unknown;
      else if ( ksStat->ir.rKSCL.ssSt & SSS_P )
        clipStat = CLIP_STAT_Prov;
      else
        clipStat = CLIP_STAT_NotProv;

      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        rCI_PlusCLIP ( clipStat, NULL, NULL, PRES_NOT_PRES, NULL, NULL, NULL );
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        rBAT_PlusCLIP ( clipStat, NULL, NULL, PRES_NOT_PRES, NULL, NULL, NULL );
      }
#endif
      break;
    }
    case KSD_SS_CLIR:
    {
      clirMode = ksStat->ir.rKSCL.mode;
      utl_cvtCLIRStat(ksStat->ir.rKSCL.clirOpt,
                      ksStat->ir.rKSCL.ssSt,
                      &clirStat);
      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        rCI_PlusCLIR (clirMode, clirStat);
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        rBAT_PlusCLIR (clirMode, clirStat);
      }
#endif
      break;
    } 
    case KSD_SS_COLP:
    {
      /* SS Status of class - T_ACI_KSD_ST */
      if ( ksStat->ir.rKSCL.ssSt EQ KSD_ST_NOT_VALID )
        colpStat = COLP_STAT_Unknown;
      else if ( ksStat->ir.rKSCL.ssSt & SSS_P )
        colpStat = COLP_STAT_Prov;
      else
        colpStat = COLP_STAT_NotProv;

      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        rCI_PlusCOLP ( colpStat, NULL, NULL, NULL, NULL, NULL );
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        rBAT_PlusCOLP ( colpStat, NULL, NULL, NULL, NULL, NULL );
      }
#endif
      break;
    } 
    case KSD_SS_COLR:
    {
      /* SS Status of class - T_ACI_KSD_ST */
      if ( ksStat->ir.rKSCL.ssSt EQ KSD_ST_NOT_VALID )
        colrStat = COLR_STAT_Unknown;
      else if ( ksStat->ir.rKSCL.ssSt & SSS_P )
        colrStat = COLR_STAT_Prov;
      else
        colrStat = COLR_STAT_NotProv;
      
      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        rCI_PercentCOLR(colrStat);
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        rBAT_PercentCOLR(colrStat);
      } 
#endif
      break;
    }
  }
}

/*
 ****************************************************************
 */
LOCAL  void utl_cb_callforwarding( UBYTE srcId, T_ACI_KSIR * ksStat )
{
  T_ACI_CCFC_SET  ccfcSetting;
  UBYTE           idx;

  TRACE_FUNCTION("utl_cb_callforwarding()");

  if ( ksStat->ir.rKSCF.opCd NEQ KSD_OP_IRGT )
    return;

  for( idx = 0; idx < ksStat->ir.rKSCF.c_cfFeatLst; idx++ )
  {
    /* SS Status of class - T_ACI_KSD_ST */
    if ( ksStat->ir.rKSCF.cfFeatLst[idx].ssSt EQ KSD_ST_NOT_VALID )
      ccfcSetting.clsstat.status = STATUS_NotPresent;
    else if ( ksStat->ir.rKSCF.cfFeatLst[idx].ssSt & SSS_A )
      ccfcSetting.clsstat.status = STATUS_Active;
    else
      ccfcSetting.clsstat.status = STATUS_NotActive;
    /* type of class */
    if ( ksStat->ir.rKSCF.cfFeatLst[idx].bsTp EQ KSD_BS_TP_None
     AND ksStat->ir.rKSCF.cfFeatLst[idx].bsCd EQ KSD_BS_TeleBearerUnknown)
    {
      if (ccfcSetting.clsstat.status EQ STATUS_NotPresent)
        ccfcSetting.clsstat.class_type = CLASS_None;
      else
        ccfcSetting.clsstat.class_type = CLASS_VceDatFax;
    }
    else
      ccfcSetting.clsstat.class_type = cmhSS_GetClassType(ksStat->ir.rKSCF.cfFeatLst[idx].bsTp,
                                                           ksStat->ir.rKSCF.cfFeatLst[idx].bsCd);
    /* number */
    strcpy(ccfcSetting.number, (char *)ksStat->ir.rKSCF.cfFeatLst[idx].num);
    if ( !strlen ( ccfcSetting.number ))
    {
      ccfcSetting.type.npi   = NPI_NotPresent;
      ccfcSetting.type.ton   = TON_NotPresent;
      ccfcSetting.subaddr[0] = 0x0;
      ccfcSetting.satype.tos = TOS_NotPresent;
      ccfcSetting.satype.oe  = OE_NotPresent;
      ccfcSetting.time       = ACI_NumParmNotPresent;
    }
    else
    {
      T_CF_FEAT *cfFeat = &ksStat->ir.rKSCF.cfFeatLst[idx];
      /* toa */
      ccfcSetting.type.ton = cfFeat->ton NEQ 0xFF 
                             ? (T_ACI_TOA_TON)cfFeat->ton 
                             : TON_NotPresent;
      ccfcSetting.type.npi = cfFeat->npi NEQ 0xFF 
                             ? (T_ACI_TOA_NPI)cfFeat->npi 
                             : NPI_NotPresent;
      /* subaddr */
      strcpy(ccfcSetting.subaddr, (char *)ksStat->ir.rKSCF.cfFeatLst[idx].sub);
      /* tos */
      ccfcSetting.satype.tos = cfFeat->tos NEQ 0xFF
                               ? (T_ACI_TOS_TOS)cfFeat->tos
                               : TOS_NotPresent;
      ccfcSetting.satype.oe  = cfFeat->oe NEQ 0xFF 
                               ? (T_ACI_TOS_OE)cfFeat->oe 
                               : OE_NotPresent;
      /* time */
      ccfcSetting.time       = cfFeat->time NEQ 0xFF 
                               ? cfFeat->time 
                               : ACI_NumParmNotPresent;
    }
    if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
    {
      rCI_PlusCCFC (&ccfcSetting);
    }
#ifdef FF_BAT
    else
    {
      rBAT_PlusCCFC (&ccfcSetting);
    }
#endif
  }
}

/*
 ****************************************************************
 */
LOCAL  void utl_cb_callbarring( UBYTE srcId, T_ACI_KSIR * ksStat )
{
  T_ACI_CLSSTAT   classStat;
  UBYTE           idx;

  TRACE_FUNCTION("utl_cb_callbarring()");

  if (ksStat->ir.rKSCB.opCd NEQ KSD_OP_IRGT)
  {
    return;
  }
  for (idx = 0; idx < ksStat->ir.rKSCB.c_cbInfoLst; idx++)
  {
    /* type of class */
    classStat.class_type = cmhSS_GetCbClassType(ksStat->ir.rKSCB.cbInfoLst[idx].bsTp,
                                                 ksStat->ir.rKSCB.cbInfoLst[idx].bsCd);

    /* SS Status of class */
    if (classStat.class_type EQ CLASS_VceDatFaxSms 
     OR classStat.class_type EQ CLASS_None)
    {
      classStat.status = STATUS_NotActive;
    }
    else
    {
      classStat.status = STATUS_Active;
    }
    if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
    {
      rCI_PlusCLCK(&classStat);
    }
#ifdef FF_BAT
    else /* CMD_MODE_BAT */
    {
      rBAT_PlusCLCK(&classStat);
    }
#endif
  }
}

/*
 ****************************************************************
 */
LOCAL  void utl_cb_imei( UBYTE srcId, T_ACI_KSIR * ksStat )
{
  TRACE_FUNCTION("utl_cb_imei()");

  sprintf ( g_sa,
            "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
            (ksStat->ir.rKSIMEI.tac1 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.tac1 & 0x0F,

            (ksStat->ir.rKSIMEI.tac2 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.tac2 & 0x0F,

            (ksStat->ir.rKSIMEI.tac3 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.tac3 & 0x0F,

            (ksStat->ir.rKSIMEI.fac  >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.fac  & 0x0F,

            (ksStat->ir.rKSIMEI.snr1 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.snr1 & 0x0F,

            (ksStat->ir.rKSIMEI.snr2 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.snr2 & 0x0F,

            (ksStat->ir.rKSIMEI.snr3 >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.snr3 & 0x0F,

             ksStat->ir.rKSIMEI.cd,
            (ksStat->ir.rKSIMEI.svn  >> 4) & 0x0F,
             ksStat->ir.rKSIMEI.svn  & 0x0F );

  io_sendMessage ( srcId, g_sa, ATI_NORMAL_OUTPUT );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_UTIL           |
| STATE   : code                        ROUTINE :                    |
+--------------------------------------------------------------------+

  PURPOSE : handles PercentKSIR call back

*/
GLOBAL void utl_cb_percentKSIR (U8 srcId, T_ACI_KSIR *ksStat)
{
  T_ACI_USSD_DATA  ussd;

  TRACE_FUNCTION("utl_cb_percentKSIR()");
  
  switch (ksStat->ksdCmd)
  {
    case (KSD_CMD_IMEI):
      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        utl_cb_imei(srcId, ksStat);
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        rBAT_PercentIMEI(&(ksStat->ir.rKSIMEI));
      }
#endif
      break;

    case (KSD_CMD_CB):
      utl_cb_callbarring(srcId, ksStat);
      break;

    case (KSD_CMD_CF):
      utl_cb_callforwarding(srcId, ksStat);
      break;

    case (KSD_CMD_CL):
      utl_cb_lineidentification(srcId, ksStat);
      break;

    case (KSD_CMD_CW):
      utl_cb_callwaiting(srcId, ksStat);
      break;

    case (KSD_CMD_PWD):
      /* no specific answer to +CPWD which is the corresponding AT cmd */
      break;

    case (KSD_CMD_UBLK):
      /* no specific answer to +CPIN which is the corresponding AT cmd */
      break;

    case (KSD_CMD_USSD):
      if (aci_cmd_src_mode_get(srcId) EQ CMD_MODE_ATI)
      {
        rci_display_USSD(srcId,
                         ksStat->ir.rKSUS.mode,
                         (UBYTE *)ksStat->ir.rKSUS.ussd,
                         ksStat->ir.rKSUS.len,
                         FALSE, /* means DO NOT CONVERT STRING */
                         ksStat->ir.rKSUS.dcs);
      }
#ifdef FF_BAT
      else /* CMD_MODE_BAT */
      {
        ussd.len = ksStat->ir.rKSUS.len;
        memcpy (ussd.data, (UBYTE *)ksStat->ir.rKSUS.ussd, ussd.len);
        rBAT_PlusCUSD(ksStat->ir.rKSUS.mode, &ussd, ksStat->ir.rKSUS.dcs);
      }
#endif
      break;

    case (KSD_CMD_CCBS):
      utl_cb_ccbs(srcId, ksStat);
      break;
  }

}
#endif /* defined (FF_ATI) || defined (FF_BAT) */