view src/gpf/ccd/ccd.c @ 247:12b20090b46a

ETM: add phone-on command to FCBM
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 09 May 2021 21:04:52 +0000
parents 4e78acac3d88
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 */