view src/gpf3/ccd/ccd.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 c41a534f33c6
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  
|  Modul   : ccd.c
+----------------------------------------------------------------------------- 
|  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 :  Condat Conder Decoder - 
|             Definition of encoding and decoding functions of 
|             air interface messages
+----------------------------------------------------------------------------- 
*/ 

#define CCD_C

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>

#ifdef _MSDOS
  #include <dos.h>
  #include <conio.h>
#endif

/*
 * Standard definitions like UCHAR, ERROR etc.
 */

#include "typedefs.h"
#include "header.h"

/*
 * Types and constants used by CCD
 */
#include "ccd_globs.h"

/*
 * Type definitions for CCD data tables
 */
#include "ccdtable.h"

/*
 * Function prototypes of CCD-CCDDATA interface 
 */
#include "ccddata.h"

/*
 * Error codes and prototypes of exported functions by CCD 
 * (USE_DRIVER EQ undef)
 * For prototypes only look at ccdapi.h.
 */
#undef USE_DRIVER
#include "ccdapi.h"

/*
 * Types and functions for bit access and manipulation
 */
#include "bitfun.h"


/*
 * Prototypes of ccd internal functions
 */
#include "ccd.h"

#if !(defined (CCD_TEST))
#include "vsi.h"
#include "os.h"
#endif

#ifdef SHARED_VSI
  #define VSI_CALLER 0,
#else
  #define VSI_CALLER
#endif

#ifndef RUN_FLASH
/* task_null is used in ccd_signup. It must have the same RUN_... setting. */
static T_CCD_TASK_TABLE task_null;
#endif /* !RUN_FLASH */

//TISH modified for MSIM
#if defined (CCD_TEST) || defined (_TOOLS_) || defined (WIN32)
/* For the DLL and for all simple environment define the task list locally */
/* 10 entries should be more than enough */
#define MAX_ENTITIES 10
T_CCD_TASK_TABLE* ccd_task_list[MAX_ENTITIES];
#else
extern T_CCD_TASK_TABLE* ccd_task_list[];
#endif

#ifndef RUN_FLASH
const T_CCD_VarTabEntry*   mvar;
const T_CCD_SpareTabEntry* spare;
const T_CCD_CalcTabEntry*  calc;
const T_CCD_CompTabEntry*  mcomp;
const T_CCD_ElemTabEntry*  melem;
const T_CCD_CalcIndex*     calcidx;
const T_CCD_ValTabEntry*   mval;
#else
extern const T_CCD_VarTabEntry*   mvar;
extern const T_CCD_SpareTabEntry* spare;
extern const T_CCD_CalcTabEntry*  calc;
extern const T_CCD_CompTabEntry*  mcomp;
extern const T_CCD_ElemTabEntry*  melem;
extern const T_CCD_CalcIndex*     calcidx;
extern const T_CCD_ValTabEntry*   mval;
#endif

#ifndef RUN_FLASH
/*
 * Attention: if one of the following static data shall be used in
 * both, internal as well as external RAM, they must be made global.
 */
static USHORT max_message_id;

/*
 * CCD internal buffer for decoded message
 */
static UBYTE *ccd_decMsgBuffer; 
/*
 * Layer-specific cache for the bitlength of the message-identifier;
 * A value of 0 indicates an empty (undetermined) entry
 */
static UBYTE *mi_length; 

/*
 * CCD internal variables used in each call to code or decode message
 */

static U8 aim_rrc_rcm;
static U8 aim_rrlp;
static U8 aim_sat;

static T_CCD_Globs globs_all;
#endif /* !RUN_FLASH */

/*
 * CCD will call its encoding/decoding functions through a jump table. 
 */
#include "ccd_codingtypes.h"
#ifndef RUN_FLASH
T_FUNC_POINTER  codec[MAX_CODEC_ID+1][2];
#else
extern T_FUNC_POINTER  codec[MAX_CODEC_ID+1][2];
#endif

#ifndef RUN_FLASH
/* initialized is used in ccd_signup. It must have the same RUN_... setting. */
/*
 * Initialising flag
 */
BOOL initialized = FALSE;
#endif /* !RUN_FLASH */

#ifdef SHARED_CCD
  /*
   * If CCD is used in a premptive multithreaded system we need
   * a semaphore to protect the coding and decoding sections.
   */
  #ifndef RUN_FLASH
    T_HANDLE semCCD_Codec, semCCD_Buffer;
  #else
    extern T_HANDLE semCCD_Codec, semCCD_Buffer;
  #endif /* RUN_FLASH */
#endif /* SHARED_CCD */

static U8* mempat;
#define LOWSEGMASK 0xFFFFF000

#ifndef RUN_FLASH
#ifdef DEBUG_CCD
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)                 MODULE  : CCD                 |
| STATE   : code                       ROUTINE : TRACE_CCD           |
+--------------------------------------------------------------------+

  PURPOSE : Error processing of the CCD.

*/

void TRACE_CCD (T_CCD_Globs *globs, char *format, ...)
{
  va_list varpars;
  char trace_buf[256];
  int i=0;

  if (!globs->TraceIt)
    return;

  va_start (varpars, format); /* Initialize variable arguments. */
#if defined CCD_TEST
  /*
   * use vsi_o_trace - prefix the tracestring with [CCD]
   * so the PCO can display it in a CCD window
   */
  strcpy (trace_buf, "~CCD~");
  i = 5; 
#endif /* CCD_TEST */
  vsprintf (trace_buf+i, format, varpars);
  va_end (varpars);              /* Reset variable arguments.   */

#ifdef CCD_TEST
  printf ("\n%s\n", trace_buf);
#else
  vsi_o_ttrace (globs->me, TC_CCD, trace_buf);
#endif /* CCD_TEST */

}
#endif /* !RUN_FLASH */

#endif

/*
 * Stack operations
 */
#define ST_CLEAR(globs) globs->SP=0;globs->StackOvfl=FALSE;

#define ST_OK(globs) (globs->StackOvfl EQ FALSE)

#define ST_CHECK(A, globs) {if (!(globs->StackOvfl) AND globs->SP < MAX_UPN_STACK_SIZE)\
                    {(A);}\
                    else\
                    {globs->StackOvfl = TRUE;}}

#define ST_PUSH(A, globs) ST_CHECK ((globs->Stack[globs->SP++] = (A)), globs)

#define ST_POP(A, globs)  ST_CHECK ((A = globs->Stack[--(globs->SP)]), globs)

#define ST_TOP(A, globs)  ST_CHECK ((A = globs->Stack[globs->SP-1]), globs)

#ifndef RUN_FLASH
/*
 * Attention: if the static function calcUPN shall be used in
 * both, internal as well as external RAM, it must be made global.
 */
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)                 MODULE  : CCD                 |
| STATE   : code                       ROUTINE : calcUPN             |
+--------------------------------------------------------------------+

  PURPOSE : calculates the UPN-term for an element.

*/
LOCAL BOOL calcUPN  (ULONG        op,
                     ULONG        num_ops,
                     ULONG       *result,
                     T_CCD_Globs *globs)
{
  BOOL   opError;
  ULONG  op1=0,op2=0;

  opError = FALSE;
  
#ifdef DEBUG_CCD
  TRACE_CCD (globs, "Calculation of UPN-term ");
#endif

  while (num_ops-- AND !opError AND ST_OK(globs))
  {
    switch (calc[op].operation)
    {
      case '+':
        /*
         * get the upper two elements from the stack, add them
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 + op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '+' causes invalid calculation");
#endif
        break;
      case '-':
        /*
         * get the upper two elements from the stack, subtract them
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 - op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '-' causes invalid calculation");
#endif
        break;
      case '*':
        /*
         * get the upper two elements from the stack, multiply them
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 * op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '*' causes invalid calculation");
#endif
        break;
      case '/':
        /*
         * get the upper two elements from the stack, divide them
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          if (!op2)
          {
            ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, 
                        (USHORT) (globs->bitpos), (USHORT) -1);
          }
          else
          {
            ST_POP(op1, globs);
            ST_PUSH ((op1 / op2), globs);
          }
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '/' causes invalid calculation");
#endif
        break;
      case '&':
        /*
         * get the upper two elements from the stack, perform a
         * binary AND
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 & op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '&' causes invalid calculation");
#endif
        break;
      case '|':
        /*
         * get the upper two elements from the stack, perform a
         * binary OR
         * and push the result on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 | op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '|' causes invalid calculation");
#endif
        break;
      case 'A':
        /*
         * get the upper two elements from the stack, perform a
         * logical AND
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 AND op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'AND' causes invalid calculation");
#endif
        break;
      case 'O':
        /*
         * get the upper two elements from the stack, perform a
         * logical OR
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 OR op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'OR' causes invalid calculation");
#endif
        break;
      case 'X':
        /*
         * get the upper two elements from the stack, perform a
         * logical XOR
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ( ((op1 AND !op2) OR (!op1 AND op2)) , globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'XOR' causes invalid calculation");
#endif
        break;
      case '=':
        /*
         * get the upper two elements from the stack, look if they
         * are equal
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 EQ op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '=' causes invalid calculation");
#endif
        break;
      case '#':
        /*
         * get the upper two elements from the stack, look if they
         * are different
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 NEQ op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '#' causes invalid calculation");
#endif
        break;
      case '>':
        /*
         * get the upper two elements from the stack, look if
         * op1 > op2
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 > op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '>' causes invalid calculation");
#endif
        break;
      case '<':
        /*
         * get the upper two elements from the stack, look if
         * op1 < op2
         * and push a TRUE or FALSE on the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op2, globs);
          ST_POP(op1, globs);
          ST_PUSH ((op1 < op2), globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '<' causes invalid calculation");
#endif
        break;
      case 'P':
        /*
         * push a constant on the stack
         */
        ST_PUSH (calc[op].operand, globs);
#ifdef DEBUG_CCD
        if (globs->StackOvfl == TRUE)
          TRACE_CCD (globs, "Constant can't be pused on UPN stack");
#endif
        break;
      case ':':
        /*
         * duplicate the upper element on the stack
         */
        if (globs->SP >= 1)
        {
          ST_TOP (op1, globs);
          ST_PUSH (op1, globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "No UPN stack element to duplicate");
#endif
        break;
      case 'R':
        /*
         * push the content of a C-structure variable on the stack
         */
      {
        /* if no register available some compilers may react with 
           a warning like this: identifier p not bound to register
        */
        UBYTE *p;
        ULONG           value;

        /*
         * normaly we have to check if the element is a VAR
         * and not an array/substructure.
         * - but this must be done by ccdgen
         */

        /*
         * setup the read pointer to the element in the C-structure
         */
        p = globs->pstruct + melem[(USHORT) calc[op].operand].structOffs;

        /*
         * Get the element table entry from the element to read.
         * if the element of the condition is conditional too
         * then look for the valid flag of this element.
         * if the element is not valid,
         * we dont need to check the contents of it
         */
        if (melem[(USHORT) calc[op].operand].optional)
        {
          if (*(UBYTE *) p EQ FALSE)
          {
            ST_PUSH (0L, globs);
            break;
          }
          else
            p++;
        }

        /*
         * read the contents of the element
         */
        switch (mvar[melem[(USHORT) calc[op].operand].elemRef].cType)
        {
          case 'B':
            value = (ULONG) * p;
            break;
          case 'S':
            value = (ULONG) * (USHORT *) p;
            break;
          case 'L':
            value = *(ULONG *) p;
            break;
          default:
            value = 0L;
        }
        ST_PUSH (value, globs);
        break;
      }
      case 'S':
        /*
         * get the upper element from the stack an
         * set the position of the bitstream pointer to this
         * value
         */
        if (globs->SP >= 1)
        {
          ST_POP(op1, globs);
#ifdef DEBUG_CCD
          TRACE_CCD (globs, "SETBITPOS %d (byte %d.%d)",
                     (USHORT) op1, (USHORT) (op1 / 8), (USHORT) (op1 % 8));
#endif
          bf_setBitpos ((USHORT) op1, globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'SETBITPOS' causes invalid calculation");
#endif
        break;
      case 'G':
        /*
         * push the position of the bitstream pointer on the
         * stack
         */
        ST_PUSH ((ULONG) globs->bitpos, globs);
#ifdef DEBUG_CCD
        TRACE_CCD (globs, "GETBITPOS %d (byte %d.%d)", 
                   (USHORT) globs->bitpos, globs->bytepos, globs->byteoffs);
#endif
        break;
      case '^':
        /*
         * swap the upper two elements of the stack
         */
        if (globs->SP >= 2)
        {
          ST_POP(op1, globs);
          ST_POP(op2, globs);
          ST_PUSH(op1, globs);
          ST_PUSH(op2, globs);
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter '^' causes invalid calculation");
#endif
        break;
      case 'K':
        /*
         * Keep a value in the KEEP register.
         */
        if (globs->SP >= 1)
        {
          ST_POP(op1, globs);
          globs->KeepReg[calc[op].operand] = op1;
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'KEEP' causes invalid calculation");
#endif
        break;
      case 'L':
        /*
         * Copy the L part of a TLV element from the KEEP register to the UPN stack.
         */          
        ST_PUSH(globs->KeepReg[0]*8, globs);
#ifdef DEBUG_CCD
        if (globs->StackOvfl == TRUE)
          TRACE_CCD (globs, "Control parameter 'LTAKE' causes invalid calculation");
#endif
        break;
      case 'T':
        /*
         * Take a value from the KEEP register and push it on the UPN stack.
         */          
        ST_PUSH(globs->KeepReg[calc[op].operand], globs);
#ifdef DEBUG_CCD
        if (globs->StackOvfl == TRUE)
          TRACE_CCD (globs, "Control parameter 'TAKE' causes invalid calculation");
#endif
        break;
      case 'C':
        /*
         * Compare the value on the UPN stack with the one stored in the KEEP register.
         * Push the higher value in the KEEP register.
         */
        if (globs->SP >= 1)
        {          
          ST_POP(op1, globs);
          if ((globs->KeepReg[calc[op].operand]) < op1)
          {
            globs->KeepReg[calc[op].operand] = op1;
          }
        }
#ifdef DEBUG_CCD
        else
          TRACE_CCD (globs, "Control parameter 'MAX' causes invalid calculation");
#endif
        break;
      case 'Z':
        /*
         *  Used to mark presence of an address information part error label
         */          
        globs->errLabel = ERR_ADDR_INFO_PART;
          break;
      case 'D':
        /*
         *  Used to mark presence of a distribution part error label
         */          
        globs->errLabel = ERR_DISTRIB_PART;
          break;
      case 'N':
        /*
         *  Used to mark presence of a non distribution part error label
         */          
        globs->errLabel = ERR_NON_DISTRIB_PART;
          break;
      case 'M':
        /*
         *  Used to mark presence of a message escape error label
         */          
        globs->errLabel = ERR_MESSAGE_ESCAPE;
          break;
      case 'I':
        /*
         *  Used to mark presence of an ignore error label
         */          
        globs->errLabel = ERR_IGNORE;
          break;
      case 'l':
        /*
         * Take a value from the CCD STO register and push it on the UPN stack.
         */
        opError = ccd_getStore (globs, calc[op].operand, &op1);
        if (!opError)
        {
          ST_PUSH(op1, globs);
#ifdef DEBUG_CCD
          TRACE_CCD (globs, "Push CCD STORE register [%d] value to UPN stack",
                     calc[op].operand);
        }
        else
        {
          TRACE_CCD (globs, "Reading from CCD STORE register [%d] impossible",
                     calc[op].operand);
#endif
        }
        break;
      case 's':
        /*
         * Store a value in the CCD STO register.
         */
        if (globs->SP >= 1)
        {
          ST_POP(op1, globs);
          opError =  ccd_writeStore (globs, calc[op].operand, op1);
#ifdef DEBUG_CCD
          TRACE_CCD (globs, "Store value in CCD STO register [%d]",
                     calc[op].operand);
        }
        else
        {
          TRACE_CCD (globs, "Control parameter 'STORE' causes invalid calculation");
#endif
        }
        break;
 
      default:
        opError = TRUE;
        break;
    }
    op++;
  }

  if (!opError AND ST_OK(globs))
  {
    if (result NEQ (ULONG *) NULL)
      ST_POP (*result, globs);
    return (ST_OK(globs));
  }
  else
  {
#ifdef DEBUG_CCD
    if(opError)
      TRACE_CCD (globs, "Calculation of UPN-term failed ");
    else
      TRACE_CCD (globs, "Calculation of UPN-term failed due to stack overflow");
#endif
    return FALSE;
  }
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)                 MODULE  : CCD                 |
| STATE   : code                       ROUTINE : ccd_conditionOK     |
+--------------------------------------------------------------------+

  PURPOSE : Check if the conditions for an element are true.
            The elemRef references an element entry from the elem tab.
            The function returns TRUE if the defined
            conditions are TRUE.

*/

BOOL ccd_conditionOK (const ULONG e_ref, T_CCD_Globs *globs)
{
  ULONG result, cond_calc_ref, num_cond_calcs, cix_ref;

  cix_ref = melem[e_ref].calcIdxRef;
  num_cond_calcs = calcidx[cix_ref].numCondCalcs;
  cond_calc_ref  = calcidx[cix_ref].condCalcRef;


  if (! calcUPN (cond_calc_ref,
                 num_cond_calcs,
                 &result,
                 globs))
    return FALSE;

  return (result EQ TRUE);
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)                 MODULE  : CCD                 |
| STATE   : code                       ROUTINE : ccd_calculateRep    |
+--------------------------------------------------------------------+

  PURPOSE : For a given element (referenced by elemRef) calculate the
            repeat value.

*/

BOOL ccd_calculateRep  (const ULONG  e_ref,
                              ULONG *repeat,
                              ULONG *max_repeat,
                              T_CCD_Globs *globs)
{
  ULONG cix_ref, result;
  ULONG remaining_repeats=0;
  ULONG rep_calc_ref, num_rep_calcs;

  BOOL   is_variable;

  cix_ref = melem[e_ref].calcIdxRef;
  num_rep_calcs = calcidx[cix_ref].numRepCalcs;
  rep_calc_ref  = calcidx[cix_ref].repCalcRef;

  *max_repeat  = (ULONG) melem[e_ref].maxRepeat;

  if (num_rep_calcs EQ 0)
  {
    if (melem[e_ref].repType EQ 'i')
    {
      switch (melem[e_ref].elemType)
      {
        case 'S':
          remaining_repeats = (ULONG)((globs->maxBitpos-globs->bitpos)
                           / spare[melem[e_ref].elemRef].bSize);
          break;
        case 'F': /* Code transparent pointer to base type */
        case 'R': /* Pointer to base type */
        case 'V':
          remaining_repeats = (ULONG)((globs->maxBitpos-globs->bitpos)
                           / mvar[melem[e_ref].elemRef].bSize);
          break;
        case 'D': /* Code transparent pointer to composition */
        case 'P': /* Pointer to composition */
        case 'C':
          /* for repeated compositions the remaining repeats
             are set to the max repeats because of the unknown
             size of one composition */
          remaining_repeats = (ULONG) melem[e_ref].maxRepeat;
          break;
        default:
          ccd_setError (globs, ERR_INVALID_CALC, BREAK, (USHORT) -1);
          break;
      }

      *repeat   = MINIMUM (*max_repeat, remaining_repeats);
      is_variable = TRUE;
    }
    else
    {
      if (melem[e_ref].repType EQ 'b')
      {
        remaining_repeats = (ULONG)(globs->maxBitpos-globs->bitpos);
        *repeat   = MINIMUM (*max_repeat, remaining_repeats);
      }
      else
      {
        *repeat     =  MINIMUM (*max_repeat,
                                (ULONG) calcidx[cix_ref].repCalcRef);
        if (*repeat < (ULONG) calcidx[cix_ref].repCalcRef) 
          ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, 
                           (USHORT) e_ref, globs->pstruct + globs->pstructOffs);
      }
      is_variable = FALSE;
    }
  }
  else
  {
    is_variable = FALSE;
    if (! calcUPN (rep_calc_ref,
                   num_rep_calcs,
                   &result,
                   globs))
    {
      *repeat = *max_repeat = 0;

      ccd_setError (globs, ERR_INVALID_CALC, BREAK, (USHORT) -1);
    }
    else
    {
      if ((melem[e_ref].repType != 'b') && (melem[e_ref].repType != 's'))
      {
        is_variable = TRUE;
      }
      if (melem[e_ref].repType EQ 'i')
      {
        switch (melem[e_ref].elemType)
        {
          case 'S':
            remaining_repeats = (ULONG)((globs->maxBitpos-globs->bitpos)
                             / spare[melem[e_ref].elemRef].bSize);
            break;
          case 'F': /* Code transparent pointer to base type */
          case 'R': /* Pointer to base type */
          case 'V':
            remaining_repeats = (ULONG)((globs->maxBitpos-globs->bitpos)
                             / mvar[melem[e_ref].elemRef].bSize);
            break;
          default:
            ccd_setError (globs, ERR_INVALID_CALC, BREAK, (USHORT) -1);
            break;
        }
        *repeat = MINIMUM (result, remaining_repeats);
      }
      else
      {
        *repeat = MINIMUM (result, *max_repeat);
        if (*repeat < result) 
          ccd_recordFault (globs, ERR_MAX_REPEAT, CONTINUE, 
                           (USHORT) e_ref, globs->pstruct + globs->pstructOffs);
      }
    }
  }
  return (is_variable);
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_performOperations |
+--------------------------------------------------------------------+

  PURPOSE : Perform the operation for an element. This operations
            are executed before an element is encoded or decoded.
            The Operations work with the UPN-Stack.

*/

void ccd_performOperations (ULONG        num_of_ops,
                            ULONG        op_def_ref,
                            T_CCD_Globs *globs)
{
  if (! calcUPN (op_def_ref,
                 num_of_ops,
                 NULL,
                 globs))
    ccd_setError (globs, ERR_INVALID_CALC, BREAK, (USHORT) -1);
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
 * Attention: if the static function ccd_isOptional shall be used in
 * both, internal as well as external RAM, it must be made global.
 */
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_isOptional        |
+--------------------------------------------------------------------+

  PURPOSE : Checks if a given element is optional. If the element is
            not optional and is a composition,
            a recursive call is performed in order to check
            if the composition contains only optional elements.
            In this case the whole composition is optional.

            In case of components concatenated with a CSN1 coding 
            rules the meaning of the word <optional> differs from the 
            traditional TI tool chain conventions. So far some coding 
            types (like tagged types, e.g. GSM3_TV) characterise 
            optional elements inherently. The value of their valid 
            flag indicates the presence or absence of such an element.
            Components concatenated with a CSN1 coding type cause 
            these valid flags in the C header structure too. If you 
            find a bit in the received message stream indicating 
            optional values not included in the message (e. g. a 
            CSN1_S1 element is represented by ??, CCD will set the 
            valid flag to zero. But the whole element represented by 
            the flag is present; only the value is absent! Therefor 
            the valid flag in the C structure is not an indication of 
            an element’s absence.
*/

LOCAL BOOL ccd_isOptional (ULONG e_ref, T_CCD_Globs *globs)
{
  ULONG  cix_ref;
  
  switch (melem[e_ref].codingType)
  {
  case CCDTYPE_CSN1_S1: /* Fall through. */
  case CCDTYPE_CSN1_S0:
  case CCDTYPE_CSN1_SHL:
  
    cix_ref = melem[e_ref].calcIdxRef;
    /*
     * If this element is conditional, check the condition.
     */
    if (calcidx[cix_ref].numCondCalcs NEQ 0
    AND ! ccd_conditionOK (e_ref, globs))
      return TRUE;
      
    if (melem[e_ref].repType == 'i' AND 
        calcidx[melem[e_ref].calcIdxRef].repCalcRef == 0)
      return TRUE;
    else 
      return FALSE;
//    break;
//    PATCH FROM M18
   case CCDTYPE_CSN1_CONCAT:
      return TRUE;

  default:
    break;
  }
  
  if (! melem[e_ref].optional)
  {
    /*
     * if the element is an array with an interval [0..x]
     * it can be handled like an optional element
     */
    if ( ! (melem[e_ref].repType EQ 'i'
        AND calcidx[melem[e_ref].calcIdxRef].repCalcRef EQ 0))
    {
      /*
       * if the element is not optional but it is a composition
       * we check recursive if the composition consists only of
       * optional elements
       */
      if (melem[e_ref].elemType EQ 'C' OR
	      melem[e_ref].elemType EQ 'D' OR
	      melem[e_ref].elemType EQ 'P')
      {
        ULONG el, lel, c_ref;
        
        c_ref = melem[e_ref].elemRef;

        el = (ULONG) mcomp[c_ref].componentRef;
        lel = el + mcomp[c_ref].numOfComponents;
   
        while (el < lel)
        {
          if (! ccd_isOptional (el, globs))
            return FALSE;
          el++;
        }
      }
      else
        return FALSE;
    }
  }
  return TRUE; 
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_decodeComposition |
+--------------------------------------------------------------------+

  PURPOSE : decodes the bitstream to a C-Structure.The decoding
            rules contains the element definitions for the
            elements of this message.
            This function may called recursivly because of a
            substructured element definition.
*/

void ccd_decodeComposition (const ULONG c_ref, T_CCD_Globs *globs)
{
  /*
   * index in table melem
   */
  ULONG  e_ref;       /* element reference */
  ULONG  l_ref;       /* reference to the last element of a component */
  SHORT  codecRet;
  BOOL   ExtendedGroupActive = FALSE;
  BOOL   GroupExtended       = FALSE;
  BOOL   MoreData;
  BOOL   SetPosExpected = FALSE;
  int    i;
  ULONG  act_err_label;

#ifdef DEBUG_CCD
  #ifndef CCD_SYMBOLS
  TRACE_CCD (globs, "ccd_decodeComposition()");
  #else
  TRACE_CCD (globs, "ccd_decodeComposition(): Composition = %s",
               mcomp[c_ref].name);
  #endif
#endif

  act_err_label = (ULONG) globs->errLabel;
  globs->ccd_recurs_level++;

  /*
   * setup the index in the melem table for this composition.
   * If this function is called for the first time
   * (ccd_recurs_level == 1) the elem-table entry for the msg_type
   * was skipped.
   */

  l_ref = mcomp[c_ref].componentRef
           + mcomp[c_ref].numOfComponents;

  e_ref  = mcomp[c_ref].componentRef
           + ((globs->ccd_recurs_level EQ 1) ? 1 : 0);

  /*
   * decode all elements
   */
  while (e_ref < l_ref)
  {
#ifdef ERR_TRC_STK_CCD
    /* save the value for tracing in error case */
    globs->error_stack[globs->ccd_recurs_level] = (USHORT) e_ref;
#endif /* ERR_TRC_STK_CCD */

    if (melem[e_ref].extGroup != ' ' && GroupExtended && !ExtendedGroupActive)
    {
      /*
       * the last read extension bit signals an
       * extension of the group but there are no
       * more elements defined for this group.
       * This indicates a protocol extension, that must be
       * skipped by ccd.
       */

      do
      {
        /*
         * read the ext-bit to determine the extension
         * of this group
         */
        GroupExtended = (bf_readBit (globs) EQ 0);
        /*
         * skip to next octett
         */
#ifdef DEBUG_CCD
        TRACE_CCD (globs, "skipping 7 bits");
#endif
        bf_incBitpos (7, globs);
      } while (GroupExtended);
    }

    /*
     * check if the bitstream has ended
     */
    if (bf_endOfBitstream(globs) AND !globs->TagPending)
    {
        ULONG  cix_ref, num_prolog_steps;
        
        cix_ref = melem[e_ref].calcIdxRef;
        num_prolog_steps = calcidx[cix_ref].numPrologSteps;
        
      /* End of the bit stream is not reached if a call to bf_setBitpos()
       * is expected for the next element of the current substructure. 
       * An instructive example is an empty "mob_id"
       */
      if (num_prolog_steps)
      {
        ULONG prolog_step_ref = calcidx[cix_ref].prologStepRef;
        
        i = (int) (prolog_step_ref + num_prolog_steps);
        
        while (i >= (int) prolog_step_ref)
        {
          if (calc[i].operation == 'S')
          {
            SetPosExpected = TRUE;
            break;
          }
          i--;
        }
      }

     if (SetPosExpected EQ FALSE)
     {
       /*
        * no more bits to decode.
        * If at least one mandatory element is to decode
        * generate an error.
        */

        while (e_ref < l_ref)
        {
          if (! ccd_isOptional (e_ref, globs))
            ccd_setError (globs, ERR_MAND_ELEM_MISS, BREAK, (USHORT) -1);

          e_ref++;
        }
        /* after the while loop the recursion level will be decremented. */
        break;
      }
    }

    /*
     * look for extension group processing
     */
    if (melem[e_ref].extGroup NEQ ' ')
    {
      /*
       * extended group symbol found
       */
      switch (melem[e_ref].extGroup)
      {
        case '+':
          /*
           * start of an extended group
           */
          ExtendedGroupActive = TRUE;
          /*
           * read the extension bit to determine the extension
           * of this group
           */
          GroupExtended = (bf_readBit (globs) EQ 0);
          /*
           * use the jump-table for selecting the decode function
           */
          codecRet =
            codec[melem[e_ref].codingType][DECODE_FUN](c_ref,
                                                         (USHORT)e_ref, globs);
          if (codecRet NEQ 0x7f)
          {
            /*
             * set the e_ref to the next or the same element
             */
            e_ref += codecRet;
          }
          break;

        case '-':
          /*
           * end of one extension,
           * decode first and the read the extension bit.
           */
          /*
           * use the jump-table for selecting the decode function
           */
          codecRet =
            codec[melem[e_ref].codingType][DECODE_FUN](c_ref,
                                                         (USHORT)e_ref, globs);
          if (codecRet NEQ 0x7f)
          {
            /*
             * set the e_ref to the next or the same element
             */
            e_ref += codecRet;
          }

          /*
           * look if the previously readed extension bit
           * alows an extension of this group
           */
          if (!GroupExtended)
          {

            ExtendedGroupActive = FALSE;
            /*
             * overread the following elements in the group
             */
            /*
             * search the last element of the extended group
             */
            while (e_ref < l_ref
            AND melem[e_ref].extGroup NEQ '*')
            {
#ifdef DEBUG_CCD
#ifdef CCD_SYMBOLS
              if (melem[e_ref].elemType EQ 'V')
                TRACE_CCD (globs, "Skipping ext-group element %s",
                           ccddata_get_alias((USHORT) e_ref, 1));
              else if (melem[e_ref].elemType EQ 'C')
                TRACE_CCD (globs, "Skipping ext-group element %s",
                           mcomp[melem[e_ref].elemRef].name);
              else
                TRACE_CCD (globs, "Skipping ext-group spare");
#else
              TRACE_CCD (globs, "Skipping ext-group element %c-%d",
                         melem[e_ref].elemType,
                         e_ref);

#endif
#endif
              e_ref++;
            }
            /*
             * skip the last element
             */
            e_ref++;
          }
          else
          {
            /*
             * read the extension bit to determine if the group
             * extension holds on
             */
            GroupExtended = (bf_readBit (globs) EQ 0);
          }
          break;

        case '*':
          if (!ExtendedGroupActive)
          {
            /*
             * this is a single element extended group
             * often used for later extension of the protocol
             */
            /*
             * read the extension bit to determine if a group
             * extension is present
             */
            GroupExtended = (bf_readBit (globs) EQ 0);
          }
          ExtendedGroupActive = FALSE;

          /*
           * use the jump-table for selecting the decode function
           */
          codecRet =
            codec[melem[e_ref].codingType][DECODE_FUN](c_ref, e_ref, globs);
          if (codecRet NEQ 0x7f)
          {
            /*
             * set the e_ref to the next or the same element
             */
            e_ref += codecRet;
          }
          break;

        case '!': /* Moredata bit */
        case '#':
          if ((MoreData = bf_readBit (globs)) EQ 1)
          {
            /*
             * moredata-bit is set to 1
             * process this element.
             */

            /*
             * use the jump-table for selecting the decode function
             */
            codecRet =
              codec[melem[e_ref].codingType][DECODE_FUN](c_ref, e_ref, globs);

            if (melem[e_ref].extGroup EQ '#')
            {
              /*
               * if more data are signaled with an additional
               * bit but there are no
               * more elements defined for this group.
               * This indicates a protocol extension, that must be
               * skipped by ccd.
               */

              do
              {
                /*
                 * read the ext-bit to determine the extension
                 * of this group
                 */
                GroupExtended = (bf_readBit (globs) EQ 1);
                /*
                 * skip to next octett
                 */
          #ifdef DEBUG_CCD
                TRACE_CCD (globs, "skipping 7 bits");
          #endif
                bf_incBitpos (7, globs);
              } while (!bf_endOfBitstream(globs) AND GroupExtended);

            }

            if (codecRet NEQ 0x7f)
            {
              /*
               * set the elemRef to the next or the same element(USHORT)
               */
              e_ref += codecRet;
            }
          }

          if (!MoreData)
          {
            /*
             * more data bit is cleared,
             * overread the following elements in the group
             * search the last element of the extended group
             */
            while (e_ref < l_ref
            AND melem[e_ref].extGroup NEQ '#')
            {
#ifdef DEBUG_CCD
#ifdef CCD_SYMBOLS
              if (melem[e_ref].elemType EQ 'V')
                TRACE_CCD (globs, "Skipping ext-group element %s",
                           ccddata_get_alias((USHORT) e_ref, 1));
              else if (melem[e_ref].elemType EQ 'C')
                TRACE_CCD (globs, "Skipping ext-group element %s",
                           mcomp[melem[e_ref].elemRef].name);
              else
                TRACE_CCD (globs, "Skipping ext-group spare");
#else
              TRACE_CCD (globs, "Skipping ext-group element %c-%d",
                         melem[e_ref].elemType,
                         e_ref);

#endif
#endif
              e_ref++;
            }

            /*
             * skip the last element of the moredata group
             */
            e_ref++;
          }
          break;
        default:
          ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, 
                        (USHORT) (globs->bitpos), (USHORT) -1);
          break;
      }
    }
    else
    {
      /*
       * no processing action for an extended group
       */

      /*
       * use the jump-table for selecting the decode function
       */
      codecRet =
        codec[melem[e_ref].codingType][DECODE_FUN](c_ref, e_ref, globs);
      if (codecRet NEQ 0x7f)
      {
        /*
         * set the e_ref to the next or the same element
         */
        e_ref += codecRet;
      }
    }
  }

  /* Reset indicator of exhaustion in the IEI table*/
  for (i = 0; globs->iei_ctx[globs->ccd_recurs_level].iei_table[i].valid== TRUE; i++)
  {
    globs->iei_ctx[globs->ccd_recurs_level].iei_table[i].exhausted = FALSE;
    globs->iei_ctx[globs->ccd_recurs_level].iei_table[i].act_amount = 0;

  }

  globs->iei_ctx[globs->ccd_recurs_level].countSkipped = 0;
  globs->ccd_recurs_level--;
  globs->errLabel  = (U8) act_err_label;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
 * Attention: if this static function shall be used in
 * both, internal as well as external RAM, it must be made global.
 */
static void SkipExtensionOctets (ULONG *e_ref, ULONG l_ref)
{
  /* The extended group is terminated. Skip over its IEs. */
  while (*e_ref < l_ref && melem[*e_ref].extGroup != '*')
    (*e_ref)++;
  if (*e_ref < l_ref)
    (*e_ref)++;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
 * Attention: if this static function shall be used in
 * both, internal as well as external RAM, it must be made global.
 */
LOCAL BOOL CheckBP_RecodeXB (ULONG ExtBitPos1, ULONG ExtBitPos2, 
                             ULONG ExtBitPos3, T_CCD_Globs *globs)
{
  /* Absence due to validity flag, condition or a ccdWarning. */
  if (ExtBitPos3 == globs->bitpos )
  {
    globs->bitpos --;    
    if (ExtBitPos1 NEQ ExtBitPos2)
      bf_recodeBit ((USHORT) ExtBitPos1, 1, globs);
    return FALSE;
  }
  return TRUE;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_encodeComposition |
+--------------------------------------------------------------------+

  PURPOSE : codes the content of a C-Structure into a bitstream.
            This function may be called recursivly if an IE in the
            structure is itself a structured IE.

            For extended octet groups the following rules apply.
            
            Any IE within an extension octet is characterised by its 
            extGroup which is one of the following:
            
            
            '+'    octet begins with this IE.
            ' '    octet continues with this IE or a new octet begins.
            '-'    octet ends with this IE.
            '*'    octet group ends with this IE.
            
            An octet may begin with '+', '-', ' ' or '*'.
            An octet beginning with '-' or '*' is made of only one IE (7 bits).
            A group made of one octet has only one IE with '*'.
            If '+' is present, next IEs ending with '*' or '-' are present too.
            If the beginning IE  with ' ' is not IE

            Examples of extended group configurations.
             _ _      _ _ _ 
            | | |    | | | |
            |+|*|    |+| |*|  one octet
            |_|_|    |_|_|_|

             _ _ _ _      _ _ _      _ _ _ _ 
            | | | | |    | | | |    | | | | |
            |+|-| |*|    |+|-|*|    |+| |-|*|  two octets
            |_|_|_|_|    |_|_|_|    |_|_|_|_|


             _ _ _ _ _ _ _ _ _ _ 
            | | | | | | | | | | |
            |+| | |-| |-| |-| |*|   four octets
            |_|_|_|_|_|_|_|_|_|_|
            
            Also groups after groups are possible.
             _ _ _ _ _ _ _ _ _
            | | | | | | | | | |
            |+| |-| |*|+|*|*|*|
            |_|_|_|_|_|_|_|_|_|
            
            The status of encoding is given as follows:

            ExtendedGroupActive is set to 1 if '+' is present in the encoding.
            ExtendedGroupActive is changed from 1 to 0 when encoding '*'.
            ExtendedGroupActive is set to 0 if an octet beginning with ' ' is
            not present.
            OpenNewOctet is set to 1 after encoding an IE with '-'.
            ExtBitPos1 is set to the globs->bitpos when writing extension bit:
            1) for '+' or 
            2) for ' ' after '-'

            Extension bit is set to 0 if a further octet is encoded for
            the group. If an octet is the last one within a group, the 
            extension bit is set to 1.

            While processing the first IE of an octet (e.g. for '+'),
            if the IE is absent, CCD will skip over all IEs up to the
            ending '*'.
            When processing IEs with ' ' and for ExtendedGroupActive=1 the valid
            flag is set to 1 in order to compensate probable mistakes in PS.

*/

void ccd_encodeComposition (const ULONG c_ref, T_CCD_Globs *globs)
{
  ULONG  e_ref;
  ULONG  l_ref;
  BOOL   ExtendedGroupActive = FALSE, OpenNewOctet = FALSE;
  ULONG  ext_bit_pos1=0, ext_bit_pos2=0, ext_bit_pos3=0, more_data_bit_pos=0;
  int    ext_bit_pending=0;
  UBYTE  codecRet;


#ifdef DEBUG_CCD
  #ifndef CCD_SYMBOLS
    TRACE_CCD (globs, "ccd_encodeComposition()");
  #else
    TRACE_CCD (globs, "ccd_encodeComposition(): Composition = %s",
               mcomp[c_ref].name);
    #endif
#endif

  globs->ccd_recurs_level++;

  /*
   * setup the index in the melem table for this composition.
   * If this function is called for the first time
   * (ccd_recurs_level == 1) the elem-table entry for the msg_type
   * was skipped.
   */

  l_ref = (USHORT)(mcomp[c_ref].componentRef
           + mcomp[c_ref].numOfComponents);

  e_ref  = (USHORT)(mcomp[c_ref].componentRef
           + ((globs->ccd_recurs_level EQ 1) ? 1 : 0));

  /*
   * code all elements
   */
  while (e_ref < l_ref)
  {
#ifdef ERR_TRC_STK_CCD
    /* 
     * Save the value for tracing in error case.
     */
    globs->error_stack[globs->ccd_recurs_level] = (USHORT) e_ref;
#endif /* ERR_TRC_STK_CCD */

    /*
     * look for extension group processing
     */
    if (melem[e_ref].extGroup NEQ ' ')
    {
      /*
       * extended group symbol found
       */
      switch (melem[e_ref].extGroup)
      {
        case '+':

          /*
           * remember the position of the extension bit
           * because we maybe have to recode it.
           */
          ext_bit_pos1 = ext_bit_pos2 = (ULONG) globs->bitpos;


          /*
           * write the extension bit. It may overwritten
           * later. (ext=0 -> group extended)
           */
          bf_writeBit (0, globs);
          ext_bit_pos3 = (USHORT) globs->bitpos;

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
          /* Use the jump-table for selecting encode function. */
          codecRet = (UBYTE)
            codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);

          /* Absence due to validity flag, conditions or a ccdWarning. */
          if (!CheckBP_RecodeXB (ext_bit_pos1, ext_bit_pos2, ext_bit_pos3, globs))
          {
            ExtendedGroupActive = FALSE;
            SkipExtensionOctets (&e_ref, l_ref);
            continue;
          }
          /* Start of an extended group */
          else
          {
            OpenNewOctet = FALSE;
          }

          ExtendedGroupActive = TRUE;
          ext_bit_pending = 1;

          if (codecRet NEQ 0x7f)
          {
            /* Set the elemRef to the next or the same element. */
            e_ref += codecRet;
          }
          break;

        /* End of one extension octet. */
        case '-':
          /* IE must be present if the previous one was not with '-'. */
          if (OpenNewOctet == FALSE)
          {
#ifdef DEBUG_CCD
            if (globs->pstruct [melem[e_ref].structOffs] != TRUE)
            {
              TRACE_CCD (globs, "Wrong value for valid flag!\n...changed to 1 for ccdID=%d",
                         e_ref);
            }
#endif
            /* IE has to be present. Don't trust PS code. */
            globs->pstruct [melem[e_ref].structOffs] = TRUE;
          }
          ext_bit_pos3 = (USHORT) globs->bitpos;

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
          /* Use the jump-table for selecting encode function. */
          codecRet = (UBYTE)
            codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);

          if (OpenNewOctet == TRUE)
          {
            /* Absence due to validity flag, conditions or a ccdWarning. */
            if (!CheckBP_RecodeXB (ext_bit_pos1, ext_bit_pos2, ext_bit_pos3, globs))
            {
              ExtendedGroupActive = FALSE;
              SkipExtensionOctets (&e_ref, l_ref);
              continue;
            }
          }
          
          if (codecRet NEQ 0x7f)
          {
          /* Set the elemRef to the next or the same element. */
            e_ref += codecRet;
          }

          /* IE with '-' belongs to the first octet. */
          if (ext_bit_pending EQ 1)
          {
            ext_bit_pending++;
          }
          /*
           * At least one octet has been encoded for the current group.
           * Swap the stored positions of the extension bits.
           */
          else
          {
            ext_bit_pos1 = ext_bit_pos2;
          }

          /*
           * Store the position of the extension bit
           * because we maybe have to recode it.
           */
          ext_bit_pos2 = (ULONG) globs->bitpos;
          /*
           * write the extension bit. It may overwritten
           * later. (ext=0 -> group extended)
           */
          bf_writeBit (0, globs);
          OpenNewOctet = TRUE;

          break;

        case '*':
          if (!ExtendedGroupActive)
          {
            /*
             * This is a single element extended group, often
             * used for later extension of the protocol
             * Write '1' in extension bit since group is not extended yet.
             */
            bf_writeBit (1, globs);
            ext_bit_pos3 = (USHORT) globs->bitpos;

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
            /* Use the jump-table for selecting encode function. */
            codecRet = (UBYTE)
              codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);
            /* Absence due to the valid flag or a ccdWarning. */
            if (ext_bit_pos3 == globs->bitpos)
            {
              globs->bitpos --;
            }

            if (codecRet NEQ 0x7f)
            {
              /* Set the elemRef to the next or the same element. */
              e_ref += codecRet;
            }
          }
          else
          {
            ExtendedGroupActive = FALSE;
            /* IE must be present if the previous one was not with '-'. */
            if (OpenNewOctet == FALSE)
            {
#ifdef DEBUG_CCD
              if (globs->pstruct [melem[e_ref].structOffs] != TRUE)
              {
                TRACE_CCD (globs, "Wrong value for valid flag!\n...changed to 1 for ccdID=%d",
                           e_ref);
              }
#endif
              /* IE has to be present. Don't trust PS code. */
              globs->pstruct [melem[e_ref].structOffs] = TRUE;
            }

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
             /* Use the jump-table for selecting the encode function. */
            codecRet = (UBYTE)
              codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);
            ext_bit_pos3 = (USHORT) globs->bitpos;

            if (codecRet NEQ 0x7f)
            {
              /* Set the elemRef to the next or the same element. */
              e_ref += codecRet;
            }

            if ((ext_bit_pos3-1) NEQ ext_bit_pos2)
            {
              /*
               * if the writepointer (ext_bit_pos3) have incremented
               * since the first extension bit (NEQ ext_bit_pos1)
               * at least one element of this group is valid
               * and written into the bitstream.
               */
              /*
               * the extended group is terminated,
               * so we have to switch the previously written
               * extBit from 0 to 1
               */
              bf_recodeBit ((USHORT) ext_bit_pos2, 1, globs);
            }
            else
            {
              /*
               * break of an extended group, no element are coded
               * since the last extension bit.
               */
              /*
               * the extended group is terminated,
               * so we have to switch the previously written
               * extBit from 0 to 1
               */
              if (ext_bit_pos1 NEQ ext_bit_pos2)
              {
                bf_recodeBit ((USHORT) ext_bit_pos1, 1, globs);
              }
              /*
               * delete the written ext-bit because the extended
               * group ended.
               */
              bf_setBitpos ((USHORT) ext_bit_pos2, globs);
            }
          }
          break;
        case '!':
        case '#':
          more_data_bit_pos = (ULONG) globs->bitpos;
          bf_writeBit (1, globs);

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
          /*
           * use the jump-table for selecting the encode function
           */
          codecRet = (UBYTE)
            codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);
          if (codecRet NEQ 0x7f)
          {
            if (more_data_bit_pos+1 EQ globs->bitpos)
            {
              /*
               * rewrite the written moredata bit to 0
               */
              bf_setBitpos (more_data_bit_pos, globs);
              bf_writeBit (0, globs);
              /*
               * no coding performed -> extension group ended
               * We skip all elements in this group
               */
              while (melem[e_ref].extGroup EQ '!')
                e_ref++;

              if (melem[e_ref].extGroup EQ '#')
                e_ref++;
            }
            else
            {
              if (melem[e_ref].extGroup EQ '#')
              {
                /*
                 * code a zero bit for the last element
                 */
                bf_writeBit (0, globs);
              }
              e_ref++;
            }
          }
          break;
        default:
          ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, 
                      (USHORT) (globs->bitpos), (USHORT) -1);
        break;
      }
    }
    else
    {
      if (ExtendedGroupActive)
      {
        ext_bit_pos3 = (USHORT) globs->bitpos;

        /* IE in the middle part of an ext-octet. */
        if (OpenNewOctet == FALSE)
        {
#ifdef DEBUG_CCD
          if (globs->pstruct [melem[e_ref].structOffs] != TRUE)
          {
            TRACE_CCD (globs, "Wrong value for valid flag!\n...changed to 1 for ccdID=%d",
                       e_ref);
          }
#endif
          globs->pstruct [melem[e_ref].structOffs] = TRUE;
        }
      }

#if defined(_TOOLS_)
      if (ccd_patch (globs, 0))
        codecRet = 1;
      else
#endif /* _TOOLS_ */
      /* Use the jump-table for selecting encode function. */
      codecRet = (UBYTE)
        codec[melem[e_ref].codingType][ENCODE_FUN](c_ref, e_ref, globs);

      /* The following is only meant for IEs after an IE with '-'. */
      if (ExtendedGroupActive)
      {
        if (OpenNewOctet == TRUE)
        {
          /* Absence due to validity flag, conditions or a ccdWarning. */
          if (!CheckBP_RecodeXB (ext_bit_pos1, ext_bit_pos2, ext_bit_pos3, globs))
          {
            ExtendedGroupActive = FALSE;
            SkipExtensionOctets (&e_ref, l_ref);
            continue;
          }
          /* Start of an extension octet */
          else
          {
            OpenNewOctet = FALSE;
          }
        }
      }

      if (codecRet NEQ 0x7f)
      {
        /* Set the elemRef to the next or the same element. */
        e_ref += codecRet;
      }
    }
  }

  globs->ccd_recurs_level--;
}
#endif /* !RUN_FLASH */

/* ---------------------------------------------------------------- */
/* GLOBAL FUNCTIONS                                                 */
/* ---------------------------------------------------------------- */

#ifndef RUN_FLASH
/*
+------------------------------------------------------------------------------
|  Function     :  ccd_check_pointer
+------------------------------------------------------------------------------
|  Description  :  This function checks the validity of a pointer
|
|  Parameters   :  ptr - the pointer
|
|  Return       :  ccdOK if pointer valid, otherwise ccdError
+------------------------------------------------------------------------------
*/
int ccd_check_pointer (U8* ptr)
{
  if (!ptr || ptr == mempat
#ifdef WIN32
      /* For windows: check also if ptr is too small */
      || !(ptr && LOWSEGMASK)
#endif
     )
  {
    return ccdError;
  }
  return ccdOK;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_begin             |
+--------------------------------------------------------------------+


  PARAMETERS:  none

  PURPOSE:     Returns the address of the CCD buffer for decoded
               messages and locks it until ccd_end() is called

*/

UBYTE* CCDDATA_PREF(ccd_begin) (void)
{
#ifdef SHARED_CCD
  /*
   * if the CCD is used in a premptive multithreaded system
   * we must lock this critical section
   */
  vsi_s_get (VSI_CALLER semCCD_Buffer);
#endif

#ifdef DEBUG_CCD
{
  #ifndef _TMS470
  T_CCD_Globs globs;
  globs.me = 0;
  globs.TraceIt = 1;
  TRACE_CCD (&globs, "CCD Begin");
  #endif
}
#endif
  return ccd_decMsgBuffer;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_end               |
+--------------------------------------------------------------------+


  PARAMETERS:  none

  PURPOSE:     Unlocks the CCD buffer for decoded
               messages

*/

void CCDDATA_PREF(ccd_end) (void)
{
#ifdef SHARED_CCD
  /*
   * if the CCD is used in a premptive multithreaded system
   * we must unlock this critical section of accessing the
   * decoded message buffer
   */
  vsi_s_release (VSI_CALLER semCCD_Buffer);
#endif
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_GetGlobVars       |
+--------------------------------------------------------------------+


  PARAMETERS:  

  PURPOSE:     Determines which set of global variables to use
               and locks the CCD buffer (semaphore) if necessary.

*/
T_CCD_Globs* ccd_GetGlobVars (T_CCD_ERR_LIST_HEAD** eentry, T_CCD_STORE_LIST** stoentry)
{
  T_CCD_TASK_TABLE* tentry;
#ifndef SHARED_CCD
  int me = 0;
#else
  T_HANDLE me;
  me = vsi_e_handle (0, NULL);
  if (me == VSI_ERROR)
    me = 0;
#endif /* !SHARED_CCD */

  tentry = ccd_task_list[me];
  tentry->ccd_globs->me = me;
  *eentry = tentry->ccd_err_list;
  *stoentry = tentry->ccd_store;
#ifdef SHARED_CCD
  if (tentry->ccd_globs == &globs_all)
  {
    /*
     * if the CCD is used in a premptive multithreaded system
     * we must lock this critical section
     */
    vsi_s_get (VSI_CALLER semCCD_Codec);
  }
#endif /* SHARED_CCD */
  return tentry->ccd_globs;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_FreeGlobVars      |
+--------------------------------------------------------------------+


  PARAMETERS:  none

  PURPOSE:     Unlocks the CCD buffer for decoded messages 
               if the entity is not GRR and if 
               the CCD is used in a premptive multithreaded system.

*/
void ccd_FreeGlobVars (T_CCD_Globs* globs)
{
#ifdef SHARED_CCD
  if (globs == &globs_all)
  {   
    vsi_s_release (VSI_CALLER semCCD_Codec);
  }
#endif /* SHARED_CCD */
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
#ifdef DEBUG_CCD
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_dump_msg          |
+--------------------------------------------------------------------+

  PARAMETERS:  U16 l_buf
                - Number of bits in the encoded message or IE.

               U16 o_buf
                - Offset of the bitstream buffer in bits.

               U8 *buf
                - Bitstream buffer of the encoded message or IE.

               T_CCD_Globs globs
                - Pointer to global variables

  PURPOSE:     Dump contents of air interface message - for debugging

*/
void ccd_dump_msg (U16 l_buf, U16 o_buf, U8 *buf, T_CCD_Globs *globs)
{

  if (!globs->TraceIt)
    return;
  else
  {
    int  i, j, buflen;
    char s[64], c[4];

    buflen = (l_buf + o_buf + 7) >> 3;
    TRACE_CCD (globs, "-------------------------------------------------");
    TRACE_CCD (globs, " CCD: Decode Message");
    TRACE_CCD (globs, " Before DECODING: lbuf= %d, obuf= %d", l_buf, o_buf);
    TRACE_CCD (globs, " Hex dump of message to be decoded:");

    s[0] = '\0';
    for (i = o_buf>>3; i < buflen; i+=16)
    {
      for (j = 0; j < 16; j++)
      {
	if ((i+j) < buflen)
	{
	  sprintf(c, " %02x", buf[i+j]);
	  strcat (s, c);
	}
      }
      TRACE_CCD (globs, "%s", s);
      s[0] = '\0';
    }
  }
}
#endif /* DEBUG_CCD */
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_common_decode_init|
+--------------------------------------------------------------------+

  PARAMETERS:  

  PURPOSE:     Perform common CCD initialization before message decode.

*/
void ccd_common_decode_init(U16 l_buf, U16 o_buf, U8 *buf, T_CCD_Globs *globs)
{
#if defined (DEBUG_CCD)
  /* to avoid the vsprintf if the traces won't appear anyhow */
  ULONG mask;
  if (vsi_gettracemask (globs->me, globs->me, &mask) != VSI_ERROR)
  {
    globs->TraceIt = mask & TC_CCD;
  }
#endif

  /*
   * no call to setjmp() done. So ccd_Error performs no longjmp in
   * case of an error
   */
  globs->jmp_mark_set = FALSE;

  /* setup the bitbuffer */
  globs->bitbuf = buf;
  globs->bitpos = 0;

  /* cleanup the read-caches */
  globs->lastbytepos16 = globs->lastbytepos32 = 0xffff;

  /* setup the bitoffset */
  globs->bitoffs = o_buf;

  
  bf_incBitpos (o_buf, globs);

  /*
   * calclate the max bitpos to read
   */
  globs->buflen = l_buf + o_buf;
  globs->maxBitpos = globs->buflen;
  globs->msgLen = globs->buflen;
  globs->errLabel = 0;
  globs->continue_array = TRUE;
  globs->SeekTLVExt = TRUE;

  globs->ccd_recurs_level = 0;
  globs->CCD_Error = ccdOK;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
 * Attention: if this static function shall be used in
 * both, internal as well as external RAM, it must be made global.
 */
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : SeekForGSMExtensions  |
+--------------------------------------------------------------------+

  PURPOSE:     Check if there are elements left in the air message
               without being decoded. Assume that the next IE has the
               type T, TV or a TLV. Seek for Comprehension Required
               extensions.
               1) Rules to distinguish between the types:
               handling of unknown IEs (GSM 04.07, section 11.2.4)
               "Bit 8 of the IEI octet is set to "1" indicates a TV 
               formatted type 1 standard IE or a T formatted type 2 
               IEs, and to "0" indicates a TLV formatted type 4 IE. 
               Hence, a 1 valued bit 8 indicates that the whole IE is 
               one octet long, and a 0 valued bit 8 indicates that the
               following octet is a length octet.
               1) Rules to read the length:
               For TLV4 encode L in one byte.
               For TLV5 and ASN.1 encode in one byte or more. Use
               0x81, 0x82 etc in the first byte to say L is encoded
               in one, two etc bytes.
               For ASN.1 BER type use 0x80 in the first byte and
               two otets of 0 bits after the encoded IE.
               For all the three types it is possible to encode L
               in only one byte.
               TLV6 is not supported. TLV6 is not a GSM standard 
               type. It has been defined in g23net software.
*/
static void SeekForGSMExtensions (U8 entity, T_CCD_Globs *globs)
{
  U8 *MsgBuf = (U8*)globs->bitbuf;
  U16 BP = globs->bytepos;
  U16 OctNr = (globs->buflen+7) >> 3;
  U16 errPos = 0;
  U8 errTag = 0xFF;
  U8 errCode;

#ifdef DEBUG_CCD
  TRACE_CCD( globs, "SeekForGSMExtensions...");
#endif
  while (BP < OctNr)
  {
    U8 T = MsgBuf[BP];
    BOOL tlv5 = FALSE;

    /* Expecting a CCDTYPE_GSM5_TLV type we get an unknown tag with MSB set.
     * Expecting other types than CCDTYPE_GSM5_TLV we get an unknown tag with
     * comprehension required bits (5, 6, 7 and 8 of IEI according to GSM0407)
     * are set to zero.
     */
    tlv5 = (aim_sat == entity);
    if ( (tlv5 && ((T & 0x80) == 0x80))
        ||
         (!tlv5 && ((T & 0xf0) == 0)) )
    {
      errTag = T;
      errPos = BP*8;
      errCode = ERR_COMPREH_REQUIRED;
      /* Report error. Do not analyse the rest. */
      break;
    }
    else
    {
      errTag = T;
      errPos = BP*8;
      errCode = ERR_IE_NOT_EXPECTED;
    }

    /* The type is TLV or ASN.1. */
    if ((T & 0x80) NEQ 0x80)
    { 
      /* BP points to the first L byte */
      U16 L = MsgBuf[++BP]; 
      switch (L)
      {
        /* End Of Content (ASN.1 BER) */
        case 0x80:
          do
          {
            BP++;
          } while ((*(U16*)&MsgBuf[BP]) != 0 && BP < OctNr);
          BP++;
          L = 0;
          break;

        /* Length encoding in two bytes */
        case 0x81:
          L = MsgBuf[++BP];
          break;

        /* Length encoding in three bytes */
        case 0x82:
          L = (MsgBuf[++BP]) << 8;
          L |= MsgBuf[++BP];
          break;

        /* Length encoding in one byte. */
        default:
          break;
      }

      /* Skip over the bytes. */
      while (L > 0 && BP < OctNr)
      {
        --L;
        ++BP;
      } 

    } /* if TLV */
    /* else: The type is T or TV. Skip one byte (see next step). */

    /* 
     * BP points to the last byte of the skipped IE, 
     * move to the next IE.
     */
    BP++;
  }/* while bytes left unread */

  /* Report the summary of the found erros. */
  if (errTag != 0xFF)
  {
    ccd_setError (globs, errCode,
      (U8)((errCode == ERR_COMPREH_REQUIRED) ? BREAK : CONTINUE),
                  errTag,
                  errPos,
                  (USHORT) -1);
  }
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_decodeMsg         |
+--------------------------------------------------------------------+


  PARAMETERS:  UBYTE      entity
                - specifies the calling entity of CCD. The Constants
                  for each valid entity is defined in MCONST.CDG

               UBYTE      direction
                - specifies wether the message goes UPLINK or DOWNLINK.
                  This is nessesary because there are same PDU-Type
                  codes for different messages.

	              T_MSGBUF * mBuf
                - specifies the bitstream buffer of the message. The
                  struct contains the l_buf and the o_buf elements.
                  These elements specifies the length and offset in bits
                  of the bitstream in the T_MSGBUF component buf.

               UBYTE    * mStruct
                - reference to the C-Structure of the decoded message.
                  The type may differ so the Pointer is always typed as
                  UBYTE* and must be casted after decoding. If this parameter
                  is NULL CCD uses his internal buffer wich must be
                  protected via ccd_begin() in a multithread environment.

               UBYTE      mId
                - specifies the PDU-Type of the bitstream. If this
                  parameter is not equal 0xff the CCD does not decode
                  the pdu-type from the bitstream to decide wich decoding
                  rules to select. Normaly this param is set to 0xff.

  PURPOSE:     decodes a bitstream, containing a valid TETRA-Message
               of the Air-Interface to a corresponding C-Structure.

*/

BYTE CCDDATA_PREF(ccd_decodeMsg) (UBYTE         entity,
                                  UBYTE         direction,
                                  T_MSGBUF     *mBuf,
                                  UBYTE        *mStruct,
                                  UBYTE         mId)
{
  UBYTE theMsgId;
  USHORT mcompRef;
  int    jmp_ret;
  T_CCD_Globs *globs;
  T_CCD_ERR_LIST_HEAD* eentry;
  T_CCD_STORE_LIST* stoentry;

    globs = ccd_GetGlobVars (&eentry, &stoentry);

    /*
     * setup the structure-buffer
     *
     * if the parameter of the decoded message buffer address is NULL
     * we use the internal one
     */
    globs->pstruct = (mStruct EQ NULL) ? ccd_decMsgBuffer : mStruct;
    globs->pstructOffs = 0;

    ccd_common_decode_init(mBuf->l_buf, mBuf->o_buf, mBuf->buf, globs);
    ccd_err_reset (eentry);
    globs->errLabel = 0;
    globs->continue_array = TRUE;

  #ifdef DEBUG_CCD
    ccd_dump_msg(mBuf->l_buf, mBuf->o_buf, mBuf->buf, globs);
  #endif

    if (mId NEQ 0xff AND mId NEQ 0xfe)
      globs->pstruct[0] = theMsgId = mId;
    else
    {
      /* Read the message identifier */
      globs->pstruct[0] = bf_decodeByteNumber ((ULONG) mi_length[entity], globs);
      theMsgId = globs->pstruct[0];
    }

    /* Get entry in mmtx table for this message */
    mcompRef = ccddata_get_mmtx(entity,theMsgId,direction);

    /* Check the message identifier */
    if (theMsgId > max_message_id OR mcompRef EQ NO_REF)
    {
  #ifdef ERR_TRC_STK_CCD
      globs->ccd_recurs_level = 255;
  #endif /* ERR_TRC_STK_CCD */
      ccd_setError (globs, ERR_INVALID_MID, BREAK,
		    (USHORT) theMsgId, (USHORT) -1);
      ccd_FreeGlobVars (globs);
      ccd_err_free (eentry);
      return (BYTE)globs->CCD_Error;
    }
  #ifdef ERR_TRC_STK_CCD
    /* save the value for tracing in error case */
    globs->error_stack[0] = mcompRef;
  #endif /* ERR_TRC_STK_CCD */

  #ifdef DEBUG_CCD
  #ifdef CCD_SYMBOLS
    TRACE_CCD (globs, "CCD decode: Message = %s",
    mcomp[mcompRef].name);
  #else
    TRACE_CCD (globs, "CCD decode: MessageId = %x", theMsgId);
  #endif
  #endif

  /* 
   * Clean up the entite C-structure before decoding.
   * Do not overwrite the MsgId (1. Byte)
   */
  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "CCD Cleaning struct %ld bytes",
	       mcomp[mcompRef].cSize-1);
  #endif
  memset ((UBYTE *) &globs->pstruct[1], 0,
    (size_t)(mcomp[mcompRef].cSize - 1));

    /*
     * clear the UPN stack
     */
    ST_CLEAR(globs);
    memset ((ULONG *) &(globs->KeepReg[0]), 0, MAX_KEEP_REG_SIZE);

    /*
     * inform the GSM-CODEC about the begin of a new message
     */
    cdc_GSM_start (globs);

    jmp_ret = setjmp (globs->jmp_mark);

    if (jmp_ret EQ 0)
    {
      globs->jmp_mark_set = TRUE;
      ccd_decodeComposition ((ULONG) mcompRef, globs);

      /*
       * The coding rules and the data tables must be able to lead CCD to
       * understand the bit buffer, element by element. If for some reason
       * the bit pointer points to a place after the message limit, the
       * encoding action is not trustworthy. Nevertheless CCD reports a
       * WARNING and not error.
       * In development phase it is helpful to detect such cases.
       * Otherwise the caller can supposedly still use the message.
       */
      if (globs->bitpos > globs->buflen)
      {
        ccd_recordFault (globs, ERR_MSG_LEN, CONTINUE, mcompRef, NULL);
      }
      /*
       * Seek for GSM extensions with types T, TV and TLV.
       * (GRR, RCM/RRC and RRLP assume other extension mechanisms.)
       * Check only at octet border.
       */
      else if ((globs->SeekTLVExt) && !globs->byteoffs)
      {
        SeekForGSMExtensions (entity, globs);
      }
  }


  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "CCD-ERROR = %d", globs->CCD_Error);
    TRACE_CCD (globs, "-------------------------------------------------");
  #endif /* DEBUG_CCD */

    ccd_FreeGlobVars (globs);
    ccd_err_free (eentry);

    return (BYTE) globs->CCD_Error;
  }  /* end ccd_decodeMsg () */
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
  /*
  +--------------------------------------------------------------------+
  | PROJECT : CCD (6144)               MODULE  : CCD                   |
  | STATE   : code                     ROUTINE : ccd_decodeMsgPtr      |
  +--------------------------------------------------------------------+


    PARAMETERS:  U8      entity
		  - specifies the calling entity of CCD. The Constants
		    for each valid entity is defined in MCONST.CDG

		 U8      direction
		  - specifies wether the message goes UPLINK or DOWNLINK.
		    This is nessesary because there are same PDU-Type
		    codes for different messages.

		       U16 l_buf
		  - Lenght of the bitstrem to be decoded.

							   U16 o_buf
		  - specifies the bitstream buffer of the message. The
		    struct contains the l_buf and the o_buf elements.
		    These elements specifies the length and offset in bits
		    of the bitstream in the T_MSGBUF component buf.

							   U8 *buf
		  - specifies the bitstream buffer of the message. 

		 U8 ** mStructPtr
		  -	points to the pointer on the C-structure of the 
		    decoded message. The buffer containing this message 
		    structure will be allocated by CCD. After decoding 
		    the first element in the message C-structure contains 
		    the message (PDU) type as a UBYTE.

		 U8  mId
		  - specifies the PDU-Type of the bitstream. If this
		    parameter is not equal 0xff the CCD does not decode
		    the pdu-type from the bitstream to decide wich decoding
		    rules to select. Normaly this param is set to 0xff.

    PURPOSE:     Like ccd_decodeMsg, this function decodes a bitstream
		 containing a valid TETRA-Message from the Air-Interface
		 to a corresponding C-Structure, only this function
		 allows the use of pointer types in the C-structure.

  */
  #if defined DYNAMIC_ARRAYS || defined _TOOLS_
S8 CCDDATA_PREF(ccd_decodeMsgPtr) (U8   entity,
		       U8   direction,
		       U16  l_buf,
		       U16  o_buf,
		       U8*  buf,
		       U8** mStructPtr,
		       U8   mId)
{
  /*
   * Make a dummy for the DLLs, even if DYNAMIC_ARRAYS is not defined to
   * keep the ccd.def unique
   */
  #ifndef DYNAMIC_ARRAYS
    return -1;
}
  #else /* DYNAMIC_ARRAYS */
    UBYTE  theMsgId;
    int    jmp_ret;
    U32    msgsize;
    USHORT mcompRef;
    T_CCD_Globs *globs;
    T_CCD_ERR_LIST_HEAD* eentry;
    T_CCD_STORE_LIST* stoentry;

    globs = ccd_GetGlobVars (&eentry, &stoentry);
    ccd_common_decode_init(l_buf, o_buf, buf, globs);
    ccd_err_reset (eentry);
    globs->errLabel = 0;
    globs->continue_array = TRUE;
    globs->alloc_head = *mStructPtr = NULL;

  #ifdef DEBUG_CCD
    TRACE_CCD( globs, "======================================================");
    TRACE_CCD( globs, "ccd_decodeMsgPtr: Decoding message with pointer types.");
    ccd_dump_msg(l_buf, o_buf, buf, globs);
  #endif

	    /* Read the message identifier. */
    if (mId NEQ 0xff AND mId NEQ 0xfe)
      theMsgId = mId;
    else
      theMsgId = bf_decodeByteNumber ((ULONG) mi_length[entity], globs);

    /* Get the entry in mmtx table for this message */
    mcompRef = ccddata_get_mmtx (entity,theMsgId,direction);
     
    /* Check the validity of the message identifier */
    if (theMsgId > max_message_id OR mcompRef EQ NO_REF)
    {
  #ifdef ERR_TRC_STK_CCD
      globs->ccd_recurs_level = 255;
  #endif /* ERR_TRC_STK_CCD */
      ccd_setError (globs, ERR_INVALID_MID, BREAK, (USHORT) theMsgId, (USHORT) -1);
      ccd_FreeGlobVars (globs);
      ccd_err_free (eentry);
      return (BYTE) globs->CCD_Error;
    }

  #ifdef ERR_TRC_STK_CCD
    /* save the value for tracing in error case */
    globs->error_stack[0] = mcompRef;
  #endif /* ERR_TRC_STK_CCD */

  #ifdef DEBUG_CCD
  #ifdef CCD_SYMBOLS
    TRACE_CCD (globs, "CCD decode: Message = %s",
    mcomp[mcompRef].name);
  #else
    TRACE_CCD (globs, "CCD decode: MessageId = %x", theMsgId);
  #endif
  #endif

    /*
     * Setup the structure-buffer.
     * Make a first simple estimation of much memory to allocate.
     * It is twice as much as the air interface message, rounded up 
     * to the nearest kilobyte boundary.
     */
    msgsize = mcomp[mcompRef].cSize;
    
  #ifdef DEBUG_CCD
    TRACE_CCD( globs, "Allocating %ld bytes for msg.", msgsize);
  #endif
    
    globs->alloc_head = (U8 *) DRP_ALLOC(msgsize, DP_NO_FRAME_GUESS);

    if (globs->alloc_head == NULL)
    {
      ccd_setError (globs, ERR_NO_MEM, BREAK, (USHORT) theMsgId, (USHORT) -1);
      ccd_FreeGlobVars (globs);
      ccd_err_free (eentry);
      return (BYTE) globs->CCD_Error;
    }
    *mStructPtr = globs->alloc_head;
    globs->pstruct = globs->alloc_head;
    globs->pstructOffs = 0;

    /*Write the MSG ID in the buffer*/
    globs->pstruct[0] = theMsgId;

    /* 
     * Clean up the entite C-structure before decoding.
     * Do not overwrite the MsgId (1. Byte)
     */
  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "CCD Cleaning struct %ld bytes", mcomp[mcompRef].cSize);
  #endif
  memset ((U8 *)globs->pstruct, 0, (size_t)(msgsize));

    /* 
     * Write the message identifier into the C-structure.
     */
    globs->pstruct[0] = theMsgId;

    /*
     * clear the UPN stack
     */
    ST_CLEAR(globs);
    memset ((ULONG *) &(globs->KeepReg[0]), 0, MAX_KEEP_REG_SIZE);

    /*
     * inform the GSM-CODEC about the begin of a new message
     */
    cdc_GSM_start (globs);

    jmp_ret = setjmp (globs->jmp_mark);

    if (jmp_ret EQ 0)
    {
      globs->jmp_mark_set = TRUE;
      ccd_decodeComposition ((ULONG) mcompRef, globs);
      if (globs->byteoffs NEQ 0)
      {
       bf_incBitpos (8-globs->byteoffs, globs);
  
        /* There are more bits to be decoded than ccddata expects.
         * The additional bits may belong to unknown non-critical extensions.
         */
        if (globs->bitpos > globs->buflen)
        {
         ccd_recordFault (globs, ERR_UNEXPECT_PAD, CONTINUE, mcompRef, NULL);
        }
        /*
         * Seek for GSM extensions with types T, TV and TLV.
         * (GRR, RCM/RRC and RRLP assume other extension mechanisms.)
         * Check only at octet border.
         */
        else if ((entity != aim_rrc_rcm) 
                && (entity != aim_rrlp)
                && (globs->SeekTLVExt)
                && !globs->byteoffs)
        {
          SeekForGSMExtensions (entity, globs);
        }
      }
      else
      {
        if (globs->bitpos > globs->buflen)
        {
         ccd_recordFault (globs, ERR_MSG_LEN, CONTINUE, mcompRef, NULL);
        }
        /*
         * Seek for GSM extensions with types T, TV and TLV.
         * (GRR, RCM/RRC and RRLP assume other extension mechanisms.)
         * Check only at octet border.
         */
        else if ((entity != aim_rrc_rcm) 
                && (entity != aim_rrlp)
                && (globs->SeekTLVExt)
                && !globs->byteoffs)
        {
          SeekForGSMExtensions (entity, globs);
        }
      }
    }

  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "CCD-ERROR = %d", globs->CCD_Error);
    TRACE_CCD (globs, "-----------------------------------------------------");
  #endif /* DEBUG_CCD */

    ccd_FreeGlobVars (globs);
    ccd_err_free (eentry);

    return (BYTE) globs->CCD_Error;
}  /* end ccd_decodeMsgPtr () */
  #endif /* !DYNAMIC_ARRAYS */
  #endif /* DYNAMIC_ARRAYS || _TOOLS_ */
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
  /*
  +--------------------------------------------------------------------+
  | PROJECT : CCD (6144)               MODULE  : CCD                   |
  | STATE   : code                     ROUTINE : ccd_codeMsgPtr        |
  +--------------------------------------------------------------------+

   PARAMETERS:   UBYTE      entity
		  - specifies the calling entity of CCD. The Constants
		    for each valid entity is defined in MCONST.CDG

		 UBYTE      direction
		  - specifies wether the message goes UPLINK or DOWNLINK.
		    This is nessesary because there are same PDU-Type
		    codes for different messages.

		 T_MSGBUF * mBuf
		  - specifies the bitstream buffer of the message. The
		    struct contains the l_buf and the o_buf elements.
		    These elements specifies the length and offset in bits
		    of the bitstream in the T_MSGBUF component buf.
		    The o_buf component must be specified by the caller,
		    the l_buf component is calculated by CCD.

		 UBYTE    * mStruct
		  - reference to the C-Structure containing the
		    C-Representation of the decoded message.
		    The type should be casted to UBYTE*. If this parameter
		    is NULL CCD uses his internal buffer wich must be
		    protected via ccd_begin() in a multithread environment.

		 UBYTE      mId
		  - specifies the PDU-Type of the bitstream. If this
		    parameter is not equal 0xff the CCD does not read
		    the pdu-type from the structure component pt
		    to decide wich decoding rules to select.
		    Normaly this param is set to 0xff.

   PURPOSE:      encodes a C-Structure containing the C-Representation of
		 a valid Air-interface message to a bitstream.

  */

S8 CCDDATA_PREF(ccd_codeMsgPtr)(U8   entity,
		    U8   direction,
		    U16* l_buf,
		    U16  o_buf,
		    U8   *buf,
		    U8*  mStruct,
		    U8   mId)
{
    UBYTE  theMsgId;
    int    jmp_ret;
    USHORT maxBytes, mcompRef;
    T_CCD_Globs *globs;
    T_CCD_ERR_LIST_HEAD* eentry;
    T_CCD_STORE_LIST* stoentry;
    
    globs = ccd_GetGlobVars (&eentry, &stoentry);
    ccd_err_reset (eentry);

  #if defined (DEBUG_CCD)
    {
      /* to avoid the vsprintf if the traces won't appear anyhow */
      ULONG mask;
      if (vsi_gettracemask (globs->me, globs->me, &mask) != VSI_ERROR)
      {
	globs->TraceIt = mask & TC_CCD;
      }
    }
  #endif

    /*
     * Set a sign that no call to setjmp() is done. So ccd_setError 
     * performs no longjmp in case of an error.
     */
    globs->jmp_mark_set = FALSE;

    /* Setup the bitbuffer. */
    globs->bitbuf = buf;
    globs->bitpos = 0;

    /* and the structure-buffer */
    globs->pstruct = (mStruct EQ NULL) ? ccd_decMsgBuffer : mStruct;
    globs->pstructOffs = 0;

    /* Cleanup the read-caches. */
    globs->lastbytepos16 = globs->lastbytepos32 = 0xffff;

    /* Setup the bitoffset. */
    globs->bitoffs = o_buf;

    
    bf_incBitpos (o_buf, globs);

    globs->bitbuf[globs->bytepos] = 0;

    globs->ccd_recurs_level = 0;

    globs->CCD_Error = ccdOK;

    globs->continue_array = TRUE;

    if (mId NEQ 0xff AND mId NEQ 0xfe)
      theMsgId = mId;
    else
    {
      theMsgId = globs->pstruct[0];
    }

    mcompRef = ccddata_get_mmtx(entity,theMsgId,direction);
    /* Check the validity of the given message identifier. */
    if (theMsgId > max_message_id OR mcompRef EQ NO_REF)
    {
  #ifdef ERR_TRC_STK_CCD
      globs->ccd_recurs_level = 255;
  #endif /* ERR_TRC_STK_CCD */
      ccd_setError (globs, ERR_INVALID_MID, BREAK, (USHORT) theMsgId, (USHORT) -1);
      ccd_FreeGlobVars (globs);
      ccd_err_free (eentry);
      return (BYTE) globs->CCD_Error;
    }

  #ifdef ERR_TRC_STK_CCD
    /* save the value for tracing in error case */
    globs->error_stack[0] = mcompRef;
  #endif /* ERR_TRC_STK_CCD */

  maxBytes = (*l_buf + 7)>>3;
  globs->msgLen = *l_buf;

  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "-------------------------------------------------");
    TRACE_CCD (globs, "CCD: Code Message");
    TRACE_CCD (globs, "Cleaning %d bits (%d bytes) of the bitstream",
      mcomp[mcompRef].bSize, maxBytes);
  #endif

    /* 
     * Clean up the bit buffer for the encoded message before encoding.
     */
    memset ((U8 *) &buf[(o_buf>>3)], 0, (size_t) maxBytes);
    /* Store the length of ereased buffer to support error handling. */
    globs->buflen = *l_buf;

    if (mId EQ 0xff)
    {
      /* Write the message identifier. */
      bf_writeBits ((U32)mi_length[entity], globs);
    }

  #ifdef DEBUG_CCD
  #ifdef CCD_SYMBOLS
    TRACE_CCD (globs, "CCD encode: Message = %s", mcomp[mcompRef].name);
  #else
    TRACE_CCD (globs, "CCD encode: MessageId = %x", theMsgId);
  #endif
  #endif

    /*
     * Clear the UPN stack.
     */
    ST_CLEAR(globs);
    memset ((ULONG *) &(globs->KeepReg[0]), 0, MAX_KEEP_REG_SIZE);

    /*
     * Inform the GSM-CODEC about the begin of a new message.
     */
    cdc_GSM_start (globs);

    jmp_ret = setjmp (globs->jmp_mark);

    if (jmp_ret EQ 0)
    {
      /*
       * no call to setjmp() done. So ccd_Error performs no longjmp in
       * case of an error
       */
      globs->jmp_mark_set = TRUE;
      ccd_encodeComposition ((ULONG) mcompRef, globs);
      if (globs->bitpos > o_buf + *l_buf)
      {
	ccd_setError (globs, ERR_BUFFER_OF, CONTINUE, (USHORT) -1);
      }
      bf_writePadBits (globs);
    }

    *l_buf = (USHORT) globs->bitpos - (USHORT) o_buf;

  #ifdef DEBUG_CCD
  {
    int i, j, buflen;
    char s[64], c[4];  

    buflen = (*l_buf + o_buf + 7) >> 3;

    TRACE_CCD (globs, "-------------------------------------------------");
    TRACE_CCD (globs, " After ENCODING: lbuf= %d, obuf= %d", *l_buf, o_buf);
    TRACE_CCD (globs, " Hex dump of encoded message:"); 

    s[0] = '\0';
    for (i = o_buf >> 3; i < buflen; i+=16)
    {
      for (j = 0; j < 16; j++)
      {
	if ((i+j) < buflen)
	{
	  sprintf(c, " %02x", buf[i+j]);
	  strcat (s, c);
	}
      }
      TRACE_CCD (globs, "%s", s);
      s[0] = '\0';
    }
  }
  #endif

  #ifdef DEBUG_CCD
    TRACE_CCD (globs, "CCD-ERROR = %d", globs->CCD_Error);
    TRACE_CCD (globs, "-------------------------------------------------");
  #endif

    ccd_FreeGlobVars (globs);
    ccd_err_free (eentry);

    return (BYTE)globs->CCD_Error;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
  /*
  +--------------------------------------------------------------------+
  | PROJECT : CCD (6144)               MODULE  : CCD                   |
  | STATE   : code                     ROUTINE : ccd_codeMsg           |
  +--------------------------------------------------------------------+

   PARAMETERS:   UBYTE      entity
		  - specifies the calling entity of CCD. The Constants
		    for each valid entity is defined in MCONST.CDG

		 UBYTE      direction
		  - specifies wether the message goes UPLINK or DOWNLINK.
		    This is nessesary because there are same PDU-Type
		    codes for different messages.

		 T_MSGBUF * mBuf
		  - specifies the bitstream buffer of the message. The
		    struct contains the l_buf and the o_buf elements.
		    These elements specifies the length and offset in bits
		    of the bitstream in the T_MSGBUF component buf.
		    The o_buf component must be specified by the caller,
		    the l_buf component is calculated by CCD.

		 UBYTE    * mStruct
		  - reference to the C-Structure containing the
		    C-Representation of the decoded message.
		    The type should be casted to UBYTE*. If this parameter
		    is NULL CCD uses his internal buffer wich must be
		    protected via ccd_begin() in a multithread environment.

		 UBYTE      mId
		  - specifies the PDU-Type of the bitstream. If this
		    parameter is not equal 0xff the CCD does not read
		    the pdu-type from the structure component pt
		    to decide wich decoding rules to select.
		    Normaly this param is set to 0xff.

   PURPOSE:      encodes a C-Structure containing the C-Representation of
		 a valid Air-interface message to a bitstream.

  */

BYTE CCDDATA_PREF(ccd_codeMsg) (UBYTE  entity,
		    UBYTE         direction,
		    T_MSGBUF     *mBuf,
		    UBYTE        *mStruct,
		    UBYTE         mId)
{
  return CCDDATA_PREF(ccd_codeMsgPtr) (entity, direction, &mBuf->l_buf,
      mBuf->o_buf, mBuf->buf, mStruct, mId);
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+------------------------------------------------------------------------------
|  Function    : ccd_init_ccddata
+------------------------------------------------------------------------------
|  Description : Initialize local tables.
|
|  Parameters  : -
|
|  Return      : ccdOK, ccdWarning, or ccdError depending on the success.
+------------------------------------------------------------------------------
*/
ULONG CCDDATA_PREF(ccd_init_ccddata) (void)
{
  const T_CCD_CompTabEntry *msg;
  USHORT                    mcompRef;  
  UBYTE                     ret, entity, num_of_entities;
  USHORT                    messageId;
#ifdef DEBUG_CCD
  T_CCD_Globs *globs = &globs_all;
#endif

  aim_rrc_rcm = (U8)ccddata_get_ccdent ("UMTS_AS_ASN1_MSG");
  aim_rrlp    = (U8)ccddata_get_ccdent ("RRLP_ASN1_MSG");
  aim_sat     = (U8)ccddata_get_ccdent ("SAT");

  mcomp = ccddata_get_mcomp (0);
  mvar = ccddata_get_mvar (0);
  mval = ccddata_get_mval (0);
  melem = ccddata_get_melem (0);
  spare = ccddata_get_spare (0);
  calc = ccddata_get_calc (0);
  calcidx = ccddata_get_calcidx (0);

  mi_length = ccddata_get_mi_length();
  ccd_decMsgBuffer = ALIGN_BUF(ccddata_get_decmsgbuffer());
  max_message_id = (USHORT) ccddata_get_max_message_id();

#ifdef CCD_SYMBOLS
  if (!ccddata_mccd_symbols())
  {
#ifdef CCD_TEST
    printf ("CCD_SYMBOLS is not set in ccddata\n");
#else     /* CCD_TEST */
    vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
                  "CCD_SYMBOLS is not set in ccddata" );
#endif    /* CCD_TEST */
  }

#else     /* CCD_SYMBOLS */
  if (ccddata_mccd_symbols())
  {
#ifdef CCD_TEST
    printf ("Undefine CCD_SYMBOLS in ccddata\n");
#else     /* CCD_TEST */
    vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
                  "Undefine CCD_SYMBOLS in ccddata" );
#endif    /* CCD_TEST */
  }
#endif    /* CCD_SYMBOLS */

#ifdef DEBUG_CCD
  /* Only for TRACE_CCD call in ccd_init. */
  globs->me = 0;
  globs->TraceIt = 1;
#endif /* DEBUG_CCD */

  num_of_entities = (UBYTE) ccddata_get_num_of_entities();
  for (entity = 0; entity < num_of_entities; entity++)
  {
    /*
     * Point to the first defined Message, to get the length
     * of the message identifier
     */
    msg = NULL;
    messageId = 0;
    while (msg EQ NULL AND messageId <= max_message_id)
    {
      /* 
       * If there is no UPLINK-decoding, try the DOWNLINK.
       */
      if ((mcompRef = ccddata_get_mmtx(entity, messageId, UPLINK)) NEQ NO_REF)
        msg = (T_CCD_CompTabEntry *) &mcomp[mcompRef];
      else
        if ((mcompRef = ccddata_get_mmtx(entity, messageId, DOWNLINK)) NEQ NO_REF)
          msg = (T_CCD_CompTabEntry *) &mcomp[mcompRef];
        else
          messageId++;
    }
    if (msg NEQ NULL
    AND melem[msg->componentRef].elemType EQ 'V'
    AND melem[msg->componentRef].elemRef NEQ NO_REF)
    {
      /*
       * if there is a message for this layer - get the length
       * of the first element (msg_type or pdu_type)
       */
      mi_length[entity] =(UBYTE) (mvar[melem[msg->componentRef].elemRef].bSize); 
    }
    else
      mi_length[entity] = 0;

#ifdef DEBUG_CCD
  TRACE_CCD (globs, "MI-LEN [ENTITY %d] = %d", entity, mi_length[entity]);
#endif
  }

  /*
   * Register all needed coding/decoding functions in the jump table.
   */
  ret = cdc_init (codec);
    
  if (ret EQ ccdError)
    return ccdError;

#ifdef DEBUG_CCD
  if (ret EQ ccdWarning)
  {
    TRACE_CCD (globs, "CCD: Mismatch between CCD and CCDDATA. Check the codec list.");//return ccdWarning;
  }
#endif

  return ccdOK;
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+------------------------------------------------------------------------------
|  Function     :  ccd_signup
+------------------------------------------------------------------------------
|  Description  :  This function sets up the local CCD data for the calling
|                  entity.
|
|  Parameters   :  ccd_reg - set if called by ccd_register, not set if called
|                            by ccd_init
|                  decmsgbuf_size - further enhancement: size of the entity's
|                                   decoded msg buffer size
|
|  Return       :  ccdErr or ccdOK depending on the success
+------------------------------------------------------------------------------
*/

static int ccd_signup (int ccd_reg, int decmsgbuf_size)
{
#ifndef _TOOLS_
    UBYTE                     ret;
#endif
  #ifdef SHARED_CCD
    T_HANDLE me;
  #else
    int me = 0;
  #endif
  T_CCD_TASK_TABLE* tentry;

#ifdef SHARED_CCD
  me = vsi_e_handle (0, NULL);
  if (me == VSI_ERROR)
  {
    me = 0;
    tentry = ccd_task_list[0] = &task_null;
    task_null.ccd_globs = &globs_all;
#ifdef DEBUG_CCD
    TRACE_CCD (&globs_all, "Ccd initialization: task could not be identified. Try to continue with a non reentrant init");
#endif
  }
  else
  {
    if (!ccd_task_list[me])
    {
      ccd_task_list[me] = D_ALLOC (sizeof (T_CCD_TASK_TABLE));
      if (!ccd_task_list[me])
      {
        vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
                  "Could not allocate memory for ccd task table entry" );
      }
      else
      {
        ccd_task_list[me]->ccd_globs = NULL;
        ccd_task_list[me]->ccd_err_list = NULL;
        ccd_task_list[me]->ccd_store = NULL;
      }
    }
    tentry = ccd_task_list[me];
    tentry->decmsgbuf = NULL;
    if (ccd_reg)
    {
      if (!tentry->ccd_globs)
      {
        if (decmsgbuf_size != CCD_REENTRANT)
        {
#ifdef DEBUG_CCD
          TRACE_CCD (tentry->ccd_globs, "Ccd_register (task %d): ignore %d for parameter decmsgbuf_size. Make non reentrant ccd_init instead.", me, decmsgbuf_size);
#endif
          tentry->ccd_globs = &globs_all;
        }
        else
        {
          tentry->ccd_globs = D_ALLOC (sizeof(T_CCD_Globs));
          if (!tentry->ccd_globs)
          {
            vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
                      "Could not allocate memory for ccd_globs" );
          }
        }
      }
    }
    else
    {
      tentry->ccd_globs = &globs_all;
    }
  }
#else   /* SHARED_CCD */
  tentry = ccd_task_list[0] = &task_null;
  task_null.ccd_globs = &globs_all;
#endif

  tentry->ccd_globs->me = me;
  if (ccd_err_init (&tentry->ccd_err_list))
  {
  #ifdef CCD_TEST
    printf ("Cannot initialize error list: out of memory\n");
  #else   /* CCD_TEST */
    vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
	  "Cannot initialize error list: out of memory" );
  #endif  /* CCD_TEST */
    return ccdError;
  }

  if (ccd_store_init (&tentry->ccd_store))
  {
#ifdef CCD_TEST
    printf ("Cannot initialize store register: out of memory\n");
#else   /* CCD_TEST */
    vsi_o_assert( VSI_CALLER OS_SYST_ERR, __FILE__, __LINE__,
	  "Cannot initialize store register: out of memory" );
#endif  /* CCD_TEST */
    return ccdError;
  }

  if (!initialized)
  {
#ifdef SHARED_CCD
   /*
   * if the CCD is used in a premptive multithreaded system
   * we must create a semaphore for the coding and decoding
   */
    semCCD_Codec  = vsi_s_open (VSI_CALLER "CCD_COD",1);
    semCCD_Buffer = vsi_s_open (VSI_CALLER "CCD_BUF",1);

#endif     /* SHARED_CCD */
  
#ifndef _TOOLS_
    ret = (UBYTE)ccd_init_ccddata ();
    if (ret != ccdOK)
    return  ret;

#endif /* !_TOOLS_ */
    initialized = TRUE;
    /* save memory init pattern */
    mempat = (U8*) CCDDATA_PREF(ccd_get_numFaults ());
  }
  return ccdOK;
}

BYTE CCDDATA_PREF(ccd_init) (void)
{
  return (BYTE) ccd_signup (0, 0);
}

/*
+------------------------------------------------------------------------------
|  Function     :  ccd_register
+------------------------------------------------------------------------------
|  Description  :  This function sets up the local CCD data for the calling
|                  entity.
|                  Entities calling this function with a parameter 0 will
|                  get an own set of CCD local data, i.e., they don't have to
|                  synchronize with other entities to use CCD.     
|
|  Parameters   :  decmsgbuf_size - further enhancement: size of the entity's
|                                   decoded msg buffer size
|
|  Return       :  ccdErr or ccdOK depending on the success
+------------------------------------------------------------------------------
*/

int ccd_register (int decmsgbuf_size)
{
  return ccd_signup (1, decmsgbuf_size);
}
#endif /* !RUN_FLASH */

#ifndef RUN_FLASH
/*
+--------------------------------------------------------------------+
| PROJECT : CCD (6144)               MODULE  : CCD                   |
| STATE   : code                     ROUTINE : ccd_exit              |
+--------------------------------------------------------------------+

 PURPOSE:  performs a shutdown of CCD.

*/

int CCDDATA_PREF(ccd_exit) (void)
{
#ifdef SHARED_CCD
  T_CCD_TASK_TABLE* tentry;
  T_HANDLE me = vsi_e_handle (0, NULL);
  if (me == VSI_ERROR)
    return ccdError;
  tentry = ccd_task_list[me]; 
  if (tentry->ccd_globs && (tentry->ccd_globs != &globs_all))
  {
    D_FREE (tentry->ccd_globs);
    tentry->ccd_globs = 0;
  }
  ccd_store_exit();
  ccd_err_exit (); 
  D_FREE (ccd_task_list[me]);
  ccd_task_list[me] = NULL;
#else
  ccd_store_exit();
  ccd_err_exit (); 
#endif /* SHARED_CCD */
  return ccdOK;
}
#endif /* !RUN_FLASH */