FreeCalypso > hg > freecalypso-sw
view gsm-fw/ccd/ccd.c @ 843:7666dd5df2bc
gsm-fw: libgdi.a added to the link with CONFIG_INCLUDE_PS
gtamodem-gsm build almost passes, now only CST is missing
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Sat, 25 Apr 2015 19:49:37 +0000 |
parents | 970d6199f2c5 |
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 */