view src/g23m-gprs/grlc/grlc_f.c @ 268:f2e52cab0a73

abb_inth.c: check all interrupt causes, not just one The original code used if - else if - else if etc constructs, thus the first detected interrupt was the only one handled. However, Iota ITSTATREG is a clear-on-read register, thus if we only handle the first detected interrupt and skip checking the others, then the other interrupts will be lost, if more than one interrupt happened to occur in one ABB interrupt handling cycle - a form of rare race condition. Change the code to check all interrupts that were read in this cycle.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 13 Jun 2021 18:17:53 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  GRLC
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
| Purpose:     This module implements global functions for GRLC
+----------------------------------------------------------------------------- 
*/ 

#ifndef GRLC_F_C
#define GRLC_F_C
#endif

#define ENTITY_GRLC


/*==== INCLUDES =============================================================*/

#include <stdio.h>
#include <string.h>     /* to get definition of memcpy() */ 
#include <math.h>

#include "typedefs.h"   /* to get Condat data types                          */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros                            */
#include "ccdapi.h"     /* to get CCD API                                    */
#include "cnf_grlc.h"    /* to get cnf-definitions                            */
#include "mon_grlc.h"    /* to get mon-definitions                            */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "message.h"    /* to get message describtion                        */
#include "pcm.h"

#include "grlc.h"        /* to get the global entity definitions              */

#include "grlc_f.h"      /* to check own definitions         */
#include "grlc_tmf.h"    /* to get definition of tm_grlc_init()   */
#include "grlc_gfff.h"   /* to get definition of gff_init()  */
#include "grlc_rdf.h"    /* to get definition of rd_init()   */
#include "grlc_ruf.h"    /* to get definition of ru_init()   */
#include "grlc_rus.h"    
#include "grlc_rds.h"    
#include "grlc_tms.h" 
#include "grlc_tpcs.h"
#include "grlc_meass.h"
#include "cl_rlcmac.h"

/*==== CONST ================================================================*/

/*==== DIAGNOSTICS ==========================================================*/

/*==== LOCAL VARS ===========================================================*/

/*==== GLOBAL VARS ===========================================================*/
/*==== LOCAL MACROS =========================================================*/


/*==== FUNCTIONS PROTOTYPES =================================================*/

LOCAL void grlc_encode_dl_acknack   ( UBYTE * ptr_out );

LOCAL void grlc_encode_ul_dummy     ( UBYTE * ptr_out );

LOCAL void grlc_encode_pca          ( UBYTE * ptr_out );
  
LOCAL UBYTE grlc_decode_ul_acknack  ( UBYTE * ptr_blk );

LOCAL UBYTE grlc_ccd_error_handling ( UBYTE entity_i  );

LOCAL USHORT grlc_convert_11bit_2_etsi ( USHORT eleven_bit );

/*==== FUNCTIONS ============================================================*/
/*
+------------------------------------------------------------------------------
| Function    : grlc_encode_dl_acknack
+------------------------------------------------------------------------------
| Description : The function grlc_encode_dl_acknack() encodes the packet downlink
|               ack/nack block without CCD
|
| Parameters  : *ptr_out_i- ptr to the buffer where the air message will be placed
|
|
+------------------------------------------------------------------------------
*/
LOCAL void grlc_encode_dl_acknack ( UBYTE * ptr_out)
{
  MCAST (u_dl_ack,U_GRLC_DL_ACK); /* T_U_GRLC_DL_ACK */

  UBYTE i=0, bit=0,byte,bit_in_byte,j;
  
  TRACE_FUNCTION( "grlc_encode_dl_acknack" );

  /******************* mandatory elements   ****************************/

  /* MESSAGE TYPE 6 bit */
  ptr_out[0]  = u_dl_ack->msg_type << 2;
  bit +=6;
  /* DL TFI 5 bit */
  ptr_out[0] |= (u_dl_ack->dl_tfi >> 3) & 0x03;
  ptr_out[1]  = (u_dl_ack->dl_tfi << 5);
  bit +=5;
  /* ACK NACK DESCRIPTION */
  /* final ack indication 1 bit */
  ptr_out[1] |= (u_dl_ack->ack_nack_des.f_ack_ind << 4);
  bit +=1;
  /* ssn 7 bit */
  ptr_out[1] |= (u_dl_ack->ack_nack_des.ssn >> 3);
  ptr_out[2]  = (u_dl_ack->ack_nack_des.ssn << 5);
  bit +=7;
  for (i=0;i<64; i++)
  {
    byte           = bit / 8; /* byte pos         */
    bit_in_byte    = bit % 8; /* rel bit pos in the current byte */    
    ptr_out[byte] |= u_dl_ack->ack_nack_des.rbb[i] << (7-bit_in_byte);
    bit +=1;
  }
  /* CHANNEL REQUEST DESCRIPTION */
  /* valid flag*/
  byte           = bit / 8; 
  bit_in_byte    = bit % 8;
  ptr_out[byte] |= u_dl_ack->v_chan_req_des << (7-bit_in_byte);
  bit +=1;
  if(u_dl_ack->v_chan_req_des)
  {
    /* peak_thr_class */
    for(i=0;i<4;i++)
    {
      byte           = bit / 8; 
      bit_in_byte    = bit % 8;
      ptr_out[byte] |= (u_dl_ack->chan_req_des.peak_thr_class >> (3-i)) << (7-bit_in_byte);
      bit +=1;
    }     
    /* radio prio */
    for(i=0;i<2;i++)
    {
      byte           = bit / 8; 
      bit_in_byte    = bit % 8;
      ptr_out[byte] |= (u_dl_ack->chan_req_des.radio_prio >> (1-i)) << (7-bit_in_byte);
      bit +=1;
    }
    /* rlc_mode*/
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (u_dl_ack->chan_req_des.rlc_mode) << (7-bit_in_byte);
    bit +=1;
    /* llc pdu type*/
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (u_dl_ack->chan_req_des.llc_pdu_type) << (7-bit_in_byte);
    bit +=1;
    /* rlc_oct_cnt */
    for(i=0;i<16;i++)
    {
      byte           = bit / 8; 
      bit_in_byte    = bit % 8;
      ptr_out[byte] |= (u_dl_ack->chan_req_des.rlc_octet_cnt >> (15-i)) << (7-bit_in_byte);
      bit +=1;
    }
  }
  /* CHANNEL QUALITY REPORT */
  /* c_value */
  for(i=0;i<6;i++)
  {
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (u_dl_ack->chan_qual_rep.c_value >> (5-i)) << (7-bit_in_byte);
    bit +=1;
  }
  /* rxqual */
  for(i=0;i<3;i++)
  {
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (u_dl_ack->chan_qual_rep.rxqual >> (2-i)) << (7-bit_in_byte);
    bit +=1;
  }
  /* signvar */
  for(i=0;i<6;i++)
  {
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (u_dl_ack->chan_qual_rep.signvar >> (5-i)) << (7-bit_in_byte);
    bit +=1;
  }
  /* c_value */
  for(j=0;j<8;j++)
  {
    UBYTE flag,value;

    switch(j)
    {
      case 0:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev0;
        value = u_dl_ack->chan_qual_rep.ilev.ilev0;
        break;
      case 1:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev1;
        value = u_dl_ack->chan_qual_rep.ilev.ilev1;
        break;
      case 2:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev2;
        value = u_dl_ack->chan_qual_rep.ilev.ilev2;
        break;
      case 3:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev3;
        value = u_dl_ack->chan_qual_rep.ilev.ilev3;
        break;
      case 4:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev4;
        value = u_dl_ack->chan_qual_rep.ilev.ilev4;
        break;
      case 5:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev5;
        value = u_dl_ack->chan_qual_rep.ilev.ilev5;
        break;
      case 6:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev6;
        value = u_dl_ack->chan_qual_rep.ilev.ilev6;
        break;
      case 7:
        flag  = u_dl_ack->chan_qual_rep.ilev.v_ilev7;
        value = u_dl_ack->chan_qual_rep.ilev.ilev7;
        break;
      default:
        TRACE_EVENT_P1("no valid j=%d value during grlc_encode_dl_acknack should not appear ",j);
        flag  = 0;
        value = 0;
        break;
    }
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;
    ptr_out[byte] |= (flag) << (7-bit_in_byte);
    bit +=1;
    if(flag) 
    {
      for(i=0;i<4;i++)
      {
        byte           = bit / 8; 
        bit_in_byte    = bit % 8;
        ptr_out[byte] |= (value >> (3-i)) << (7-bit_in_byte);
        bit +=1;
      }
    }
  }

  /* RELEASE 99*/
#ifdef REL99
  byte           = bit / 8; 
  bit_in_byte    = bit % 8;
  ptr_out[byte] |= u_dl_ack->v_release_99_str_u_grlc_dl_ack << (7-bit_in_byte);
  bit +=1;

  if(u_dl_ack->v_release_99_str_u_grlc_dl_ack)
  {
    byte           = bit / 8; 
    bit_in_byte    = bit % 8;

    if(u_dl_ack->release_99_str_u_grlc_dl_ack.v_pfi)
    {
      ptr_out[byte] |= u_dl_ack->release_99_str_u_grlc_dl_ack.v_pfi << (7-bit_in_byte);
      bit +=1;
      for(i=0;i<6;i++)
      {
        byte           = bit / 8; 
        bit_in_byte    = bit % 8;
        ptr_out[byte] |= (u_dl_ack->release_99_str_u_grlc_dl_ack.pfi >> (6-i)) << (7-bit_in_byte);
        bit +=1;
      }

    }
    else
    {
      ptr_out[byte] |= u_dl_ack->release_99_str_u_grlc_dl_ack.v_pfi << (7-bit_in_byte);
      bit +=1;
    }
  }

  bit++;
#endif

  /* SPARE PADDINGS */
  byte           = bit / 8; 
  bit_in_byte    = bit % 8;

  if(bit_in_byte < 7)
  {
    UBYTE mask;

    mask= 0xff >> (bit_in_byte);
    mask &= 0x2B;
    ptr_out[byte] |= mask;
  }
  for(i=byte;i<22;i++)
  {
    byte++;
    ptr_out[byte] = 0x2B;

  }
} /* grlc_encode_dl_acknack() */
  
/*
+------------------------------------------------------------------------------
| Function    : grlc_encode_ul_dummy
+------------------------------------------------------------------------------
| Description : The function grlc_encode_ul_dummy() encodes the packet uplink
|               dummy block without CCD
|
| Parameters  : *ptr_out_i- ptr to the buffer where the air message will be placed
|
|
+------------------------------------------------------------------------------
*/
LOCAL void grlc_encode_ul_dummy ( UBYTE * ptr_out)
{ 
  MCAST (ul_dummy,U_GRLC_UL_DUMMY); /* T_U_GRLC_UL_DUMMY */

  UBYTE i;
  
  TRACE_FUNCTION( "grlc_encode_ul_dummy" );

  /******************* mandatory elements   ****************************/

  ptr_out[0]  = ul_dummy->msg_type << 2;
  ptr_out[0] |= (UBYTE) (grlc_data->uplink_tbf.tlli >> 30);                  /* 1100 0000 0000 0000 0000 0000 0000 0000 */
  ptr_out[1]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x3FC00000) >> 22);   /* 0011 1111 1100 0000 0000 0000 0000 0000 */
  ptr_out[2]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x003FC000) >> 14);   /* 0000 0000 0011 1111 1100 0000 0000 0000 */
  ptr_out[3]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x00003FC0) >>  6);   /* 0000 0000 0000 0000 0011 1111 1100 0000 */ 
  ptr_out[4]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x0000003F) <<  2);   /* 0000 0000 0000 0000 0000 0000 0011 1111 */ 
  ptr_out[4] |= 0x01;  /* spare paddings */

  for(i=5;i<22;i++)
    ptr_out[i] = 0x2B;
} /* grlc_encode_ul_dummy() */

/*
+------------------------------------------------------------------------------
| Function    : grlc_encode_pca
+------------------------------------------------------------------------------
| Description : The function grlc_encode_pca() encodes the packet control 
|               acknowledgement block without CCD
|
| Parameters  : *ptr_out_i- ptr to the buffer where the air message will be placed
|
|
+------------------------------------------------------------------------------
*/
LOCAL void grlc_encode_pca ( UBYTE * ptr_out)
{ 
 MCAST(u_ctrl_ack,U_GRLC_CTRL_ACK); /* T_U_GRLC_CTRL_ACK */

  UBYTE i;
  
  TRACE_FUNCTION( "grlc_encode_pca" );

  /******************* mandatory elements   ****************************/

  ptr_out[0]  = u_ctrl_ack->msg_type << 2;
  ptr_out[0] |= (UBYTE) (grlc_data->uplink_tbf.tlli >> 30);                  /* 1100 0000 0000 0000 0000 0000 0000 0000 */
  ptr_out[1]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x3FC00000) >> 22);   /* 0011 1111 1100 0000 0000 0000 0000 0000 */
  ptr_out[2]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x003FC000) >> 14);   /* 0000 0000 0011 1111 1100 0000 0000 0000 */
  ptr_out[3]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x00003FC0) >>  6);   /* 0000 0000 0000 0000 0011 1111 1100 0000 */ 
  ptr_out[4]  = (UBYTE) ((grlc_data->uplink_tbf.tlli & 0x0000003F) <<  2);   /* 0000 0000 0000 0000 0000 0000 0011 1111 */ 
  ptr_out[4] |= u_ctrl_ack->pctrl_ack & 0x03;  

  for(i=5;i<22;i++)
    ptr_out[i] = 0x2B;
} /* grlc_encode_pca() */
/*
+------------------------------------------------------------------------------
| Function    : grlc_decode_ul_acknack
+------------------------------------------------------------------------------
| Description : The function grlc_decode_ul_acknack() decodes the packet uplink
|               ack/nack without CCD
|
| Parameters  : *ptr_blk- ptr to the air message
|
| Return value: returns decode status of air message:ccdOK,ccdWarning,ccdError 
|
+------------------------------------------------------------------------------
*/
LOCAL UBYTE grlc_decode_ul_acknack ( UBYTE *ptr_blk  )
{ 
  MCAST(d_ul_ack,D_GRLC_UL_ACK);/* T_D_GRLC_UL_ACK */
  
  UBYTE i,j,k;
  UBYTE bit_pos;
#ifdef REL99
  UBYTE flag;
#endif
  
  UBYTE result =ccdOK;

  TRACE_FUNCTION( "grlc_decode_ul_acknack" );

  /******************* mandatory elements   ****************************/

  d_ul_ack->msg_type               = (ptr_blk[0] & 0xFC) >> 2 ;
  d_ul_ack->page_mode              = ptr_blk[0] & 0x03; 

  if((ptr_blk[1] & 0xC0)) /* distrubiton part error check */
  {
    TRACE_ERROR("P UL ACK: DISTRUBITION PART ERROR");
    TRACE_EVENT_P2("P UL ACK: DISTRUBITION PART ERROR byte = 0x2%x   res = 0x%2x",ptr_blk[1] ,ptr_blk[1] & 0xC0);
    return ccdError;
  }
  d_ul_ack->ul_tfi                 = (ptr_blk[1] & 0x3E) >> 1;

  if((ptr_blk[1] & 0x01)) /* message escape bit check */
  {
#ifdef REL99
    d_ul_ack->egprs_flag = TRUE;
#endif
    TRACE_ERROR("P UL ACK: MESSAGE ESCAPE ERROR");
    TRACE_EVENT_P2("P UL ACK: MESSAGE ESCAPE ERROR byte = 0x2%x   res = 0x%2x",ptr_blk[1] ,ptr_blk[1] & 0x01);
    return ccdError;
  }

  d_ul_ack->v_gprs_ul_ack_nack_info = TRUE;

  d_ul_ack->gprs_ul_ack_nack_info.chan_coding_cmd        = (ptr_blk[2] & 0xC0) >> 6;

#ifdef _SIMULATION_
  TRACE_EVENT_P2("tfi=%d ch_c_cmd=%d",d_ul_ack->ul_tfi,d_ul_ack->gprs_ul_ack_nack_info.chan_coding_cmd);
#endif /* _SIMULATION_ */
  /******************* Ack/Nack description  ****************************/
  d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.f_ack_ind = (ptr_blk[2] & 0x20) >> 5;                  
  d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.ssn       = (ptr_blk[2] << 2) & 0x7C;
  d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.ssn      |= (ptr_blk[3] >> 6) & 0x03;

  j= 3; /* inital byte of rbb field */
  k= 2; /* inital bit of rbb field  */

  for(i=0; i< 64;i++)
  {
    d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.rbb[i] = (ptr_blk[j] & (0x80>>k)) >> (7-k);
    k++;
    if(k EQ 8)
    {
      k=0;
      j++;
    }
  }
#ifdef _SIMULATION_
  TRACE_EVENT_P2("fai=%d ssn=%d",d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.f_ack_ind,d_ul_ack->gprs_ul_ack_nack_info.ack_nack_des.ssn);
#endif /* _SIMULATION_ */

  bit_pos = 91;          /* abs bit position */

  /******************* contention resolution tlli ***********************/
    
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */

  d_ul_ack->gprs_ul_ack_nack_info.v_cr_tlli = (ptr_blk[j] >> (8-k)) & 0x01; 

  bit_pos++;

  if(d_ul_ack->gprs_ul_ack_nack_info.v_cr_tlli)
  {
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.l_cr_tlli = 32;
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.o_cr_tlli = 3;        
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.b_cr_tlli[0] = ptr_blk[j];
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.b_cr_tlli[1] = ptr_blk[j+1];
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.b_cr_tlli[2] = ptr_blk[j+2];
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.b_cr_tlli[3] = ptr_blk[j+3];
    d_ul_ack->gprs_ul_ack_nack_info.cr_tlli.b_cr_tlli[4] = ptr_blk[j+4];
    bit_pos+=32;
  }

#ifdef REL99
  /******************* packet timing advance ****************************/
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */
  flag    = (ptr_blk[j] >> (8-k)) & 0x01; 
  bit_pos++;
  if(flag)
  {
  }
  /******************* power control params ****************************/
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */
  flag    = (ptr_blk[j] >> (8-k)) & 0x01; 
  bit_pos++;
  if(flag)
  {
  }
  /*******************     Extension bits   ****************************/
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */
  flag    = (ptr_blk[j] >> (8-k)) & 0x01; 
  bit_pos++;
  if(flag)
  {
  }
  /*******************     Fixed Alloc      ****************************/
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */
  flag    = (ptr_blk[j] >> (8-k)) & 0x01; 
  bit_pos++;
  if(flag)
  {
  }
  /*******************     R99 FLAG           ****************************/
  j                       = bit_pos / 8; /* byte pos         */
  k                       = bit_pos % 8; /* rel bit pos      */
  bit_pos++;
  d_ul_ack->gprs_ul_ack_nack_info.v_release_99_str_d_ul_ack    = (ptr_blk[j] >> (8-k)) & 0x01; 
  /*******************     Extended PTA      ****************************/
  j       = bit_pos / 8; /* byte pos         */
  k       = bit_pos % 8; /* rel bit pos      */
  flag    = (ptr_blk[j] >> (8-k)) & 0x01; 
  bit_pos++;
  if(flag)
  {
  }
  /**********************************************************************/
  j                    = bit_pos / 8; /* byte pos         */
  k                    = bit_pos % 8; /* rel bit pos      */
  d_ul_ack->gprs_ul_ack_nack_info.release_99_str_d_ul_ack.tbf_est    = (ptr_blk[j] >> (8-k)) & 0x01; 

#endif

  return(result);

} /* grlc_decode_ul_acknack() */

/*
+------------------------------------------------------------------------------
| Function    : grlc_ccd_error_handling
+------------------------------------------------------------------------------
| Description : The function grlc_ccd_error_handling() ...
|
| Parameters  : entity_i - the CCD was called for this entity
|
+------------------------------------------------------------------------------
*/
LOCAL UBYTE grlc_ccd_error_handling ( UBYTE entity_i  )
{ 
  UBYTE result = DELETE_MESSAGE;
  USHORT parlist [MAX_ERR_PAR];
  UBYTE first_error; 

  TRACE_FUNCTION( "grlc_ccd_error_handling" );


  memset (parlist, 0, sizeof (parlist));
  
  first_error = ccd_getFirstError (entity_i, parlist);
  
  switch (first_error)
  {
    
  case ERR_PATTERN_MISMATCH:      /* A spare pattern does not match with  */
    /* the specified content                */
    /* Error params[0] = bitposition        */
    {
      MCAST(ptr,D_GRLC_UL_ACK);
      result = ptr->msg_type;
    }
    break;
    
  default:
    /* SZML-GLBL/010 */
    TRACE_ERROR( "Ctrl-Message will be deleted" );
    break;
  }
  
  return(result);

} /* grlc_ccd_error_handling() */


/*==== PUBLIC FUNCTIONS =====================================================*/


/*
+------------------------------------------------------------------------------
| Function    : grlc_buffer2ulong
+------------------------------------------------------------------------------
| Description : The function grlc_buffer2ulong() copy a 32-Bit-Buffer in a ULONG
|               variable
|               
|               SZML-GLBL/002
|
| Parameters  : ptmsi - pointer to buffer that contains the 32bit for the ULONG 
|
+------------------------------------------------------------------------------
*/
GLOBAL ULONG grlc_buffer2ulong ( BUF_cr_tlli *tlli)
{
  ULONG ul;
 
  UBYTE l, dummy; 
  USHORT i, ii;
  UBYTE off1, off2;
  
  TRACE_FUNCTION( "grlc_buffer2ulong "); 
  
  ul= 0;
  
  l = (UBYTE)tlli->l_cr_tlli;
  
  off1 = tlli->o_cr_tlli / 8;
  off2 = tlli->o_cr_tlli % 8;
  
  dummy = 0;
  dummy = tlli->b_cr_tlli[off1] << off2;
  
  if(l <= (8-off2))
  {
    dummy = dummy >> (8-l);
    ul |= dummy;
    return ul;
  }
  dummy = dummy >> off2;
  ul |= dummy;
  l -= (8-off2);
  
  do
  {
    off1++;
    
    if(l < 8)
    {
      dummy = tlli->b_cr_tlli[off1] >> (8-l);
      ii = 1;
      ul = ul << l;
      for(i=0; i< l; i++)
      {
        ul = ul | (dummy & ii);
        ii *= 2;
      }
      return ul;  
    }
    else
    {
      ul = ul << 8;
      ul |= tlli->b_cr_tlli[off1];
      l -= 8;
      if(l EQ 0)
        return ul;
    }
  }
  while(TRUE);
}



/*
+------------------------------------------------------------------------------
| Function    : grlc_delete_prim
+------------------------------------------------------------------------------
| Description : The function grlc_delete_prim() deletes the primitive that is   
|               pointed by the grlc_data->prim_start_tbf and sets the 
|               grlc_data->prim_start_tbf to the next entry in the tbf list.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_delete_prim ( void )
{ 
  TRACE_FUNCTION( "grlc_delete_prim" );

  /*
   * access type is reseted 
   */
  grlc_data->uplink_tbf.access_type = CGRLC_AT_NULL;

  if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)
  {
    UBYTE i;  

    /* 
     * get first entry from tbf list 
     */
    i = grlc_prim_get_first (&grlc_data->prim_start_tbf);


    if(i >= PRIM_QUEUE_SIZE)
    {
      TRACE_EVENT_P5("delete prim VOR i=%d  ps=%d, pf=%d,sps=%d,spf=%d",
                                                      i,
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);
    }

    /*
     *   estimate new user data amount in queue
     */
    grlc_data->prim_user_data -= BYTELEN(grlc_data->prim_queue[i].prim_ptr->sdu.l_buf); 

    /* 
     * free primitive before reset old primitive entry
     */    
    PFREE ( grlc_data->prim_queue[i].prim_ptr );

    /* 
     * reset old primitive 
     */
    grlc_data->prim_queue[i].prim_ptr = NULL;
    grlc_data->prim_queue[i].prim_type = CGRLC_LLC_PRIM_TYPE_NULL;
    grlc_data->prim_queue[i].cv_status = FALSE;  
    grlc_data->prim_queue[i].rlc_status = FALSE;
    grlc_data->prim_queue[i].re_allocation = FALSE;
    grlc_data->prim_queue[i].start_new_tbf = FALSE;
    grlc_data->prim_queue[i].last_bsn = 0xff;
    grlc_data->prim_queue[i].previous = 0xff;

    /* 
     * put new entry at the end of free list 
     */

    if(i < PRIM_QUEUE_SIZE)
    {
      grlc_prim_put(&grlc_data->prim_start_free,i,END_OF_LIST);
    }
    else  if(grlc_data->gmm_procedure_is_running)
    {
     grlc_prim_put(&grlc_data->prim_start_free,i,END_OF_LIST);
     TRACE_EVENT_P5("delete prim %d AFTER PST=%d, PSF=%d,spst=%d,spsf=%d",
                                                      i,
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);
    }

    /*
     * update LLC flow control state
     */
    if ((grlc_data->tm.send_grlc_ready_ind EQ PRIM_QUEUE_FULL) AND            /* PRIM QUEUE IS FULL */
         (
        (!grlc_data->gmm_procedure_is_running AND (i < PRIM_QUEUE_SIZE))  OR  /* LLC QUEUE IS ACTIVE, PDU FROM LLC QUEUE DELETED */
        (grlc_data->gmm_procedure_is_running AND !(i < PRIM_QUEUE_SIZE))))    /* GMM QUEUE IS ACTIVE, PDU FROM GMM QUEUE DELETED */
    {
      TRACE_EVENT_P3("Flow control activated gmm_q=%d,i=%d,ready=%d",grlc_data->gmm_procedure_is_running,i,grlc_data->tm.send_grlc_ready_ind);
      grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;
    }

    grlc_data->grlc_data_req_cnt--;
  }
  else
  {
    TRACE_EVENT_P3("PST=%d PSF=%d PDU=%d: grlc_delete_prim"
                                                           ,grlc_data->prim_start_tbf
                                                           ,grlc_data->prim_start_free
                                                           ,grlc_data->grlc_data_req_cnt);
    return; 
  }


} /* grlc_delete_prim() */






  
/*
+------------------------------------------------------------------------------
| Function    : grlc_calc_new_poll_pos
+------------------------------------------------------------------------------
| Description : The function grlc_calc_new_poll_pos() calculates the fn of the 
|               new poll position
|
| Parameters  : fn_i    - framenumber
|               rrbp_i  - relative position
|
+------------------------------------------------------------------------------
*/
GLOBAL ULONG grlc_calc_new_poll_pos ( ULONG fn_i, UBYTE rrbp_i )
{ 
  ULONG result=0;
  TRACE_FUNCTION( "grlc_calc_new_poll_pos" );

  switch( rrbp_i )
  {
  case 0:
    result = (fn_i+13);
    break;
  case 1:
    if((fn_i+18)%13)
      result = (fn_i+17);
    else
      result = (fn_i+18);
    break;
  case 2:
    if(((fn_i+21)%13) EQ 8)
      result = (fn_i+21);
    else
      result = (fn_i+22);
    break;
  case 3:
    result = (fn_i+26);
    break;
  default:
    TRACE_ERROR( "unexpected rrbp  value" );
    break;
  } /* switch (rrbp_i) */
  result = result % 0x297000; 

  return result;

} /* grlc_calc_new_poll_pos() */




/*
+------------------------------------------------------------------------------
| Function    : grlc_get_new_poll_index
+------------------------------------------------------------------------------
| Description : The function grlc_get_new_poll_index()
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
LOCAL UBYTE grlc_get_new_poll_index ( UBYTE * ptr_list_start_i )
{ 
  UBYTE result;
  TRACE_FUNCTION( "grlc_get_new_poll_index" );

  result = *ptr_list_start_i;                                                   
  /* set to new first entry */
  if (result NEQ 0xFF)
  {    
    *ptr_list_start_i = grlc_data->next_poll_array[*ptr_list_start_i].next;
    /* remove first entry from list  */
    grlc_data->next_poll_array[result].next = 0xff;    
  }
  else
  {
    TRACE_EVENT ("Poll array is full");
  }

  return(result);

} /* grlc_get_new_poll_index() */




/*
+------------------------------------------------------------------------------
| Function    : grlc_save_poll_pos
+------------------------------------------------------------------------------
| Description : The function grlc_save_poll_pos() 
|
| Parameters  : fn_i        - framenumber  
|               tn_i        - timeslot number
|               rrbp_i      - fn of the poll block|               
|               poll_type_i - kind of dl data
|               pctrl_ack_i - packet control ack value, needed fo p ctr ack msg
|               
|               
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_save_poll_pos ( ULONG fn_i, USHORT tn_i, UBYTE rrbp_i, UBYTE poll_type_i,UBYTE pctrl_ack_i)
{
  ULONG new_poll_pos;
  UBYTE i, next, help_index;

  TRACE_FUNCTION( "grlc_save_poll_pos" );

  if( tn_i >= POLL_TYPE_ARRAY_SIZE )
  {
    TRACE_EVENT_P5( "grlc_save_poll_pos: fn = %d, tn = %d, rrbp = %d, poll_type = %d, pctrl_ack = %d",
                    fn_i, tn_i, rrbp_i, poll_type_i, pctrl_ack_i );

    return;
  }

  if(0xFF NEQ rrbp_i)
  {
    new_poll_pos = grlc_calc_new_poll_pos(fn_i, rrbp_i);
  }
  else
  {
    new_poll_pos = fn_i;
  }

  /*TRACE_EVENT_P6("SAVE BEF: fn_i= %ld,rrbp=%ld,new_poll_pos=%ld, poll_type=%d,ps=%d ps_fn=%ld",
                                                fn_i,
                                                rrbp_i,
                                                new_poll_pos,
                                                poll_type_i,
                                                grlc_data->poll_start_tbf,
                                                grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn);

  */
  /* delete the poll position when it is older than 26 frames */
  while( grlc_data->poll_start_tbf NEQ 0xFF  AND 
         grlc_check_dist(new_poll_pos, 
                         grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn, 26) EQ FALSE)
  {
    /* move the expired poll position to the list of unused entries */
    TRACE_EVENT_P1("Remove expired poll at pst=%d",grlc_data->poll_start_tbf);
    help_index                                  = grlc_data->poll_start_tbf;
    grlc_data->poll_start_tbf                   = grlc_data->next_poll_array[help_index].next;
    grlc_data->next_poll_array[help_index].next = grlc_data->poll_start_free;
    grlc_data->poll_start_free                  = help_index;
    
    /* clear the poll position */
    grlc_data->next_poll_array[help_index].fn  = 0xFFFFFFFF;
    grlc_data->next_poll_array[help_index].cnt = 0;
    
    for( i = 0; i < POLL_TYPE_ARRAY_SIZE; i++ )
    {
      grlc_data->next_poll_array[help_index].poll_type[i] = CGRLC_POLL_NONE;      
    }
  }
  
  next       = 0xFF;
  help_index = grlc_data->poll_start_tbf;


  /*
   * find the position of the new fn
   */
  
  while( help_index NEQ 0xFF )
  {
    if( grlc_data->next_poll_array[help_index].fn EQ new_poll_pos )
    {
      next       = help_index;
      help_index = 0xFF;
    }
    else if( grlc_check_dist( new_poll_pos, grlc_data->next_poll_array[help_index].fn, 26 ) )
    {
      next       = help_index;
      help_index = grlc_data->next_poll_array[help_index].next;
    }
    else
    {
      help_index = 0xFF;
    }
  }

  /*
   * new_poll_pos is present in the poll array
   */
  if( next                                            NEQ 0xFF         AND
      grlc_data->next_poll_array[next].fn              EQ  new_poll_pos AND 
      grlc_data->next_poll_array[next].poll_type[tn_i] EQ  CGRLC_POLL_NONE        ) 
  {  
     /*
      * no collision 
      */
     grlc_data->next_poll_array[next].poll_type[tn_i] = poll_type_i;
     grlc_data->next_poll_array[next].cnt++;
     grlc_data->next_poll_array[next].ctrl_ack        = pctrl_ack_i;
  }
  else if( next                               NEQ 0xFF         AND
           grlc_data->next_poll_array[next].fn EQ  new_poll_pos     )

  { 
    /*
     * collision detected, if both pos were received with data blocks, the sent 
     * RLC/MAC block otherwise send packet control ack.
     */
    if ((poll_type_i NEQ CGRLC_POLL_DATA) 
         OR
        (grlc_data->next_poll_array[next].poll_type[tn_i] NEQ CGRLC_POLL_DATA))
    {
       grlc_data->next_poll_array[next].poll_type[tn_i] = CGRLC_POLL_COLLISION;
       TRACE_EVENT("collision detected: pca will sent");
    }
    else
    {
      TRACE_EVENT("collision detected: rlc/mac will be sent");
    }
    if(pctrl_ack_i NEQ 3)
      grlc_data->next_poll_array[next].ctrl_ack        = pctrl_ack_i;
  }
  else
  { 
    /*
     * fn does not exist in the poll list, included in poll list
     *
     * get new free index from the free list 
     */
    i = grlc_get_new_poll_index(&(grlc_data->poll_start_free));    
    if( i EQ 0xFF ) 
    { 
      TRACE_EVENT ("Poll array is full"); /*This should not happen */
      return;   
    }

    grlc_data->next_poll_array[i].cnt             = 1;
    grlc_data->next_poll_array[i].fn              = new_poll_pos;
    grlc_data->next_poll_array[i].poll_type[tn_i] = poll_type_i; 
    grlc_data->next_poll_array[i].ctrl_ack        = pctrl_ack_i;

    if( next EQ 0xFF )
    { 
      /* 
       * first entry in poll array 
       */
      grlc_data->next_poll_array[i].next    = grlc_data->poll_start_tbf;
      grlc_data->poll_start_tbf             = i;
    }
    else if( next < NEXT_POLL_ARRAY_SIZE )
    {
      /*
       * include in description list, is not first element 
       */
      grlc_data->next_poll_array[i].next            = grlc_data->next_poll_array[next].next;
      grlc_data->next_poll_array[next].next         = i;
    }
    else
    {
      TRACE_ASSERT( next < NEXT_POLL_ARRAY_SIZE );
    }
  }


  /*TRACE_EVENT_P6("SAVE AFTER: fn_i= %ld,rrbp=%ld,new_poll_pos=%ld, poll_type=%d,ps=%d ps_fn=%ld",
                                                fn_i,
                                                rrbp_i,
                                                new_poll_pos,
                                                poll_type_i,
                                                grlc_data->poll_start_tbf,
                                                grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn);
   */

} /* grlc_save_poll_pos() */






/*
+------------------------------------------------------------------------------
| Function    : grlc_encode_ctrl
+------------------------------------------------------------------------------
| Description : The function grlc_encode_ctrl() build a T_SDU buffer that 
|               contains the encode Ctrl Block ready to transmit. 
|
| Parameters  : ULONG ptr_in_i - ptr to the input structure
|               ULONG ptr_out_i - ptr to begin of output buffer
|               UBYTE r_bit_i - value of r_bit
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_encode_ctrl ( UBYTE * ptr_in_i, 
                              T_MSGBUF * ptr_out_i, 
                              UBYTE r_bit_i)
{ 
  TRACE_FUNCTION( "grlc_encode_ctrl" );

  ptr_out_i->buf[0] = 0x40 | r_bit_i;
  ptr_out_i->o_buf  = BIT_UL_CTRL_BLOCK_MAC_HEADER;
  ptr_out_i->l_buf  = BIT_UL_CTRL_BLOCK_CONTENTS;


  if(!grlc_data->grlc_wo_ccd)
  {
    ccd_codeMsg ( CCDENT_GRLC, 
                  UPLINK,
                  ptr_out_i,
                  ptr_in_i, 
                  NOT_PRESENT_8BIT);
  }
  else
  {
    switch(ptr_in_i[0]) /* msg_type */
    {
      case U_GRLC_UL_DUMMY_c:
        grlc_encode_ul_dummy(&ptr_out_i->buf[1]);
        break;
      case U_GRLC_CTRL_ACK_c:
        grlc_encode_pca(&ptr_out_i->buf[1]);
        break;
      case U_GRLC_DL_ACK_c:
        memset(&ptr_out_i->buf[1],0,22); /*lint !e419*/
        grlc_encode_dl_acknack(&ptr_out_i->buf[1]);
      break;
      default:
        ccd_codeMsg ( CCDENT_GRLC, 
                      UPLINK,
                      ptr_out_i,
                      ptr_in_i, 
                      NOT_PRESENT_8BIT);
        break;
    }
  }
  ptr_out_i->l_buf += ptr_out_i->o_buf;
  ptr_out_i->o_buf  = 0;

} /* grlc_encode_ctrl() */


/*
+------------------------------------------------------------------------------
| Function    : grlc_init
+------------------------------------------------------------------------------
| Description : The function grlc_init initializes the entity GRLC
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_init ( void )
{ 
  TRACE_FUNCTION( "grlc_init" );
  
  /* initialize all GRLC data */
  grlc_data = &grlc_data_base;
  memset( grlc_data, 0, sizeof( T_GRLC_DATA ) );

  grlc_data->grlc_data_req_cnt = 0;
  grlc_data->testmode.mode     = CGRLC_NO_TEST_MODE;

  grlc_data->meas.sq_restart = TRUE;
  
  /* 
   * call of service init functions 
   */
  tm_grlc_init();
  rd_init();
  ru_init();
  meas_grlc_init();
  tpc_grlc_init();
  gff_init();

  ccd_register(CCD_REENTRANT);  

#ifdef _SIMULATION_
  /* 
   * to make sure that the structure definitions of T_GRLC_DATA_REQ and 
   * T_GRLC_UNITDATA_REQ have the same layout.
   */
  {
    T_GRLC_DATA_REQ * ptr_grlc_data_req = (T_GRLC_DATA_REQ *)_decodedMsg;
    T_GRLC_UNITDATA_REQ * ptr_grlc_unitdata_req = (T_GRLC_UNITDATA_REQ *)_decodedMsg;

    if( &(ptr_grlc_data_req->grlc_qos)   NEQ &(ptr_grlc_unitdata_req->grlc_qos) AND
        &(ptr_grlc_data_req->radio_prio) NEQ &(ptr_grlc_unitdata_req->radio_prio) AND
        &(ptr_grlc_data_req->sdu)        NEQ &(ptr_grlc_unitdata_req->sdu) AND
        &(ptr_grlc_data_req->tlli)       NEQ &(ptr_grlc_unitdata_req->tlli) )
    {
      /*
       * In this case the primitive handling will not work correctly!!!
       */
      TRACE_ERROR("Fatal ERROR: T_GRLC_UNITDATA_REQ and T_GRLC_DATA_REQ are not equal!!");
    }
  } /* _SIMULATION_ */
#endif

  grlc_data->t3164_to_cnt           = 0;
  grlc_data->ul_tfi_changed         = FALSE;
  grlc_data->uplink_tbf.access_type = CGRLC_AT_NULL; /* NO CELL UPDATE NEED */
  grlc_data->grlc_wo_ccd            = 0;             /* as default ccd used for air message handling */

  /*
   * Ready Timer state initialization 
   */
#ifdef FF_GRLC_4_TWO_2_ONE
  grlc_data->ready_timer.handling   = READY_TIMER_HANDLING_ENABLED;
#else
  grlc_data->ready_timer.handling   = READY_TIMER_HANDLING_DISABLED;
#endif

  grlc_data->ready_timer.state      = STANDBY_STATE; 
  grlc_data->ready_timer.value      = CGRLC_T3314_DEFAULT;

} /* grlc_init() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_prim_put
+------------------------------------------------------------------------------
| Description : The function grlc_prim_put() put a Element (object_i) behind 
|               pos_i in the prim_queue.
|
| Parameters  : list_start_i  - address of the list should be manipulted  
|               object_i      - index of element that should be added to the list
|               pos_i         - index of the position behind that the object 
|                               should be added 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_prim_put(UBYTE * list_start_i, UBYTE object_i, UBYTE pos_i)
{ 
  TRACE_FUNCTION( "grlc_prim_put" );

  if(* list_start_i EQ 0xff)
  { /* no elements in the list */
    * list_start_i = object_i;
  }
  else
  { /* elements in the list */
    UBYTE i = * list_start_i;
    UBYTE j;
    BOOL put= FALSE;
    
    /* 
     * SZML-GLBL/004
     */
    for(j=0;j<PRIM_QUEUE_SIZE_TOTAL;j++)
    {
      if (grlc_data->prim_queue[i].next NEQ pos_i)
      {
        i = grlc_data->prim_queue[i].next;
      }
      else
      {
        /* 
         * put new object at pos_i of queue 
         */
        put = TRUE;
        grlc_data->prim_queue[object_i].next = grlc_data->prim_queue[i].next;
        grlc_data->prim_queue[i].next = object_i;
        break;
      }
    }
    if(!put)
      TRACE_EVENT_P3("PST=%d PSF=%d PDU=%d: grlc_prim_put failed"
                                                           ,grlc_data->prim_start_tbf
                                                           ,grlc_data->prim_start_free
                                                           ,grlc_data->grlc_data_req_cnt);

  }
} /* grlc_prim_put() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_prim_get_first
+------------------------------------------------------------------------------
| Description : The function grlc_prim_get_first() removes the first element
|               and returns the index of the first element.
|
| Parameters  : list_start_i - address of the list that should be used
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE grlc_prim_get_first(UBYTE * list_start_i)
{ 
  UBYTE result;
  TRACE_FUNCTION( "grlc_prim_get_first" );

  result = *list_start_i;
                                                    
  /* 
   * set to new first entry 
   */
  *list_start_i = grlc_data->prim_queue[*list_start_i].next;

  /*
   * remove first entry from list 
   */
  grlc_data->prim_queue[result].next = 0xff;  

  return(result);

} /* grlc_prim_get_first() */


/*
+------------------------------------------------------------------------------
| Function    : grlc_set_packet_ctrl_ack
+------------------------------------------------------------------------------
| Description : The function grlc_set_packet_ctrl_ack() |
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE * grlc_set_packet_ctrl_ack(void)
{ 
  MCAST(u_ctrl_ack,U_GRLC_CTRL_ACK);
  UBYTE * result;
  TRACE_FUNCTION( "grlc_set_packet_ctrl_ack" );

  u_ctrl_ack->msg_type  = U_GRLC_CTRL_ACK_c;

  grlc_set_buf_tlli( &u_ctrl_ack->tlli_value, grlc_data->uplink_tbf.tlli );

  if(grlc_data->poll_start_tbf NEQ 0xFF)
    u_ctrl_ack->pctrl_ack = grlc_data->next_poll_array[grlc_data->poll_start_tbf].ctrl_ack;
  else /* response to IA poll */
    u_ctrl_ack->pctrl_ack = 3; 

  result                = _decodedMsg;

  return(result);

} /* grlc_set_packet_ctrl_ack() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_send_access_burst
+------------------------------------------------------------------------------
| Description : The function grlc_send_access_burst() sents the poll as 
|               four access burst type
|
| Parameters  : tn_i : timeslot where the access burst shall send
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_send_access_burst(UBYTE tn_i)
{ 
  TRACE_FUNCTION( "grlc_send_access_burst" );

  

  if(grlc_data->poll_start_tbf NEQ 0xFF)
  {
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt--;
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].poll_type[tn_i] = CGRLC_POLL_NONE;
    grlc_data->next_poll_fn = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn;
  }
  grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].tn = tn_i;
  if(grlc_data->ab_type EQ CGRLC_AB_11_BIT)
  {
    /*11 bit access burst*/
    USHORT elevenBit = 0x07E4+grlc_data->next_poll_array[grlc_data->poll_start_tbf].ctrl_ack;
    grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].block_status = 8;
    grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block[0]  = grlc_convert_11bit_2_etsi(elevenBit);
    /*
    TRACE_EVENT_P2("PCA AB_11_BIT sent fn_i= %ld PRACH11: %d"
                                              ,grlc_data->next_poll_fn
                                              ,grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block[0]);
    */
  }
  else
  {
    /*8 bit access burst*/
    grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].block_status = 7;
    grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block[0]  = (0x7C+grlc_data->next_poll_array[grlc_data->poll_start_tbf].ctrl_ack);
    /*
    TRACE_EVENT_P1 ("PCA 8 bit access burst sent fn_i= %ld ",grlc_data->next_poll_fn);      
    */
  }
    
#ifdef _SIMULATION_
  {
    PALLOC(mac_poll_req,MAC_POLL_REQ);
    memset(mac_poll_req,0,
           sizeof(T_MAC_POLL_REQ));
    memcpy(&(mac_poll_req->ul_poll_resp),
           &(grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index]),
             sizeof(T_ul_poll_resp));
    PSEND(hCommL1,mac_poll_req);          
  }
#else  /* #ifdef _SIMULATION_ */
  {
    TRACE_MEMORY_PRIM ( hCommGRLC, hCommL1, MAC_POLL_REQ,
                        &grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index],
                        sizeof(T_ul_poll_resp) );
  }
#endif /* #ifdef _SIMULATION_ */

  TRACE_BINDUMP
    ( hCommGRLC, TC_USER4, 
      cl_rlcmac_get_msg_name( U_MSG_TYPE_CHANNEL_REQ_c, RLC_MAC_ROUTE_UL ),
      grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block,
      RLC_MAC_MAX_LEN_CHANNEL_REQ ); /*lint !e569*/

  grlc_data->ul_poll_pos_index++;
  /* 
   * next poll block invalid
   */
  grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].block_status = 0;    


} /* grlc_send_access_burst() */

/*
+------------------------------------------------------------------------------
| Function    : grlc_send_normal_burst
+------------------------------------------------------------------------------
| Description : The function grlc_send_normal_burst() sents the poll as 
|               normal burst type
|
| Parameters  : ptr_block_i : ptr to the ctrl message
| Parameters  : tn_i        : timeslot where the access burst shall send
| Parameters  : r_bit_i     : r bit needed for the mac header
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_send_normal_burst
                        (UBYTE * struct_data, UBYTE * encoded_data, UBYTE tn_i)
{
  
  TRACE_FUNCTION( "grlc_send_normal_burst" );

  if( (grlc_data->poll_start_tbf NEQ 0xFF)  AND
      (grlc_data->ta_value       EQ 0xFF) )
  {
    TRACE_EVENT_P2("No TA VALUE IN GRLC --> NB POLL NOT SENT  ta=%d poll_st_tbf=%d"
                                                                ,grlc_data->ta_value
                                                                ,grlc_data->poll_start_tbf);

    TRACE_ERROR("No TA VALUE IN GRLC --> NB POLL NOT SENT");

    grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt--;
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].poll_type[tn_i] = CGRLC_POLL_NONE;
    return;
  }

  /*
   * either encoded data or structured data are passed by reference
   */


  if( struct_data NEQ NULL )
  {
    grlc_encode_ul_ctrl_block( ( UBYTE* )grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block, struct_data );
  }
  else if( encoded_data NEQ NULL )
  {
    memcpy( ( UBYTE* )grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block, 
            encoded_data,
            BYTE_UL_CTRL_BLOCK );
  }
  else
  {
    TRACE_ERROR( "grlc_send_normal_burst: no data available" );
  }

  grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].tn = tn_i;
  grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].block_status = 3;

  if(grlc_data->poll_start_tbf NEQ 0xFF)
  {
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt--;
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].poll_type[tn_i] = CGRLC_POLL_NONE;
    grlc_data->next_poll_fn = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn;
  }
  
#ifdef _SIMULATION_
  {
    PALLOC(mac_poll_req,MAC_POLL_REQ);
    memset(mac_poll_req,0,
           sizeof(T_MAC_POLL_REQ));
    memcpy(&(mac_poll_req->ul_poll_resp),
           &(grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index]),
             sizeof(T_ul_poll_resp));
    PSEND(hCommL1,mac_poll_req);          
  }
#else  /* #ifdef _SIMULATION_ */
  {
    TRACE_MEMORY_PRIM ( hCommGRLC, hCommL1, MAC_POLL_REQ,
                        &grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index],
                        sizeof(T_ul_poll_resp) );
  }
#endif /* #ifdef _SIMULATION_ */

  {
    UBYTE* ul_block = ( UBYTE* )grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].ul_block;

    TRACE_BINDUMP( hCommGRLC, TC_USER4,
                   cl_rlcmac_get_msg_name
                     ( ( UBYTE )( ul_block[1] >> 2 ), RLC_MAC_ROUTE_UL ),
                   ul_block, MAX_L2_FRAME_SIZE ); /*lint !e569*/
  }

  grlc_data->ul_poll_pos_index++;
  /* 
   * next poll block invalid
   */
  grlc_data->ul_poll_resp[grlc_data->ul_poll_pos_index].block_status = 0;    

  /*
  TRACE_EVENT_P1 ("Normal burst sent at fn_i= %ld ",grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn);
  */
} /* grlc_send_normal_burst() */

/*
+------------------------------------------------------------------------------
| Function    : grlc_del_sent_poll
+------------------------------------------------------------------------------
| Description : The function grlc_del_sent_poll() deletes the poll pos which was 
|               sent to L1
|
| Parameters  

|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_del_sent_poll(void )
{ 
  UBYTE     help_index;
  UBYTE     next_index;

  TRACE_FUNCTION( "grlc_del_sent_poll" );
   
  
  if( grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt EQ 0 )
  {
    help_index = grlc_data->poll_start_tbf;
    grlc_data->poll_start_tbf = grlc_data->next_poll_array[grlc_data->poll_start_tbf].next;
    next_index = grlc_data->poll_start_free; 
    while(grlc_data->next_poll_array[next_index].next NEQ 0xFF)
    {
       next_index = grlc_data->next_poll_array[next_index].next;
    }
    grlc_data->next_poll_array[next_index].next = help_index;
    grlc_data->next_poll_array[help_index].next = 0xFF;
  }



} /* grlc_del_sent_poll() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_decode_tbf_start_rel
|------------------------------------------------------------------------------
| Description : The function grlc_decode_tbf_start_rel() translates the TBF- 
|               Starting-Time-Relative into full frame number. Therefore the 
|               received frame number is needed in start_fn !! 
|
| Parameters  : rel_pos - number in blocks added to current framenuber
|
+------------------------------------------------------------------------------
*/
GLOBAL ULONG grlc_decode_tbf_start_rel(ULONG start_fn, USHORT rel_pos)
{ 
  ULONG result;

  TRACE_FUNCTION( "grlc_decode_tbf_start_rel" );
  
  result = 4+4*rel_pos + start_fn + rel_pos/3;
  
  if ((12 EQ (result%13))  OR
       (7 EQ (result%13))  OR
       (3 EQ (result%13)))
  {
    result += 1;  
  }
  if(FN_MAX <= result)
  {
    result %= FN_MAX;
  }

  return result;
}  /* grlc_decode_tbf_start_rel */



/*
+------------------------------------------------------------------------------
| Function    : grlc_get_sdu_len_and_used_ts
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : * sdu_len - len of the current sdu in progress
|               * used_ul_resources - used uplink resources in fixed alloc mode
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_get_sdu_len_and_used_ts (  T_RLC_VALUES * values  )
{ 
  TRACE_FUNCTION( "grlc_get_sdu_len_and_used_ts" );
   
  switch( GET_STATE( RU ) )
  {
    case RU_NULL:
      values->sdu_len = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8;
      values->cnt_ts  = 0;
      break;
    default:
      values->sdu_len = grlc_data->ru.sdu_len;
      values->cnt_ts  = grlc_data->ru.cnt_ts;          
      break;
  }
 /* grlc_get_sdu_len_and_used_ts() */
}



/*
+------------------------------------------------------------------------------
| Function    : grlc_check_dist
+------------------------------------------------------------------------------
| Description : The function grlc_check_dist() checks if high_i is bigger/equal 
|               than low_i(modulo calculation). 
|               The return value is true, if high_i is equal to low_i or 
|               bigger than low_i.
| Parameters  : high_i - expected high value
|               low_i  - expected low value
|               dist_i - max. allowed distance between high_i and low_i
+------------------------------------------------------------------------------
*/
GLOBAL BOOL grlc_check_dist ( ULONG high_i, ULONG low_i, ULONG dist_i)
{
  BOOL  result = FALSE;
  ULONG  real_dist;

  TRACE_FUNCTION( "grlc_check_dist" );
    
  if (high_i >= low_i)
    real_dist = high_i - low_i;
  else
    real_dist = high_i + (FN_MAX-low_i);

  if (real_dist <= dist_i )
  {
     result = TRUE;
  }
  return result;
} /* grlc_check_dist() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_handle_poll_pos
+------------------------------------------------------------------------------
| Description : The function grlc_handle_poll_pos()  
|                
| Parameters  : -
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_handle_poll_pos (ULONG current_fn)
{
  UBYTE     help_index;
  UBYTE     next_index;
  TRACE_FUNCTION( "grlc_handle_poll_pos" );
  
  while ( (grlc_data->poll_start_tbf NEQ 0xFF) AND
          (grlc_check_dist(current_fn,grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn,26)) AND 
          (current_fn NEQ grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn))
  {
    TRACE_EVENT_P4("current_fn= %ld  missed poll_fn=%ld  ps_tbf=%d  cnt=%d",
                                  current_fn,
                                  grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn,
                                  grlc_data->poll_start_tbf,
                                  grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt);
    /*
     * delete elememnt from tbf_list if all pollType = POLL_NONE, and add to free list
     */
    grlc_data->missed_poll_fn = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn;
    grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt = 0;
    help_index = grlc_data->poll_start_tbf;
    grlc_data->poll_start_tbf = grlc_data->next_poll_array[grlc_data->poll_start_tbf].next;
    next_index = grlc_data->poll_start_free;
    while(grlc_data->next_poll_array[next_index].next NEQ 0xFF)
    {
       next_index = grlc_data->next_poll_array[next_index].next;
    }
    grlc_data->next_poll_array[next_index].next = help_index;
    grlc_data->next_poll_array[help_index  ].next = 0xFF;
    TRACE_ERROR( "Poll Position missed" );
  }
} /* grlc_handle_poll_pos() */


/*
+------------------------------------------------------------------------------
| Function    : grlc_send_rem_poll_pos
+------------------------------------------------------------------------------
| Description : The function grlc_send_rem_poll_pos()  
|                
| Parameters  : -
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_send_rem_poll_pos (ULONG current_fn)
{ 
  ULONG delta_fn = 0;
  UBYTE *ptr_block=NULL;

  
  TRACE_FUNCTION( "grlc_send_rem_poll_pos" );

  if (grlc_data->poll_start_tbf EQ 0xFF)
    return;



#ifdef _TARGET_      
  delta_fn = grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn;
  if(current_fn EQ FN_MAX-5)
    delta_fn += 5;
  else
    delta_fn -= current_fn;
#endif

#ifdef _SIMULATION_
  if(current_fn EQ grlc_data->next_poll_array[grlc_data->poll_start_tbf].fn)        
    delta_fn    = 4;      
  else      
    delta_fn    = 0;      
#endif

  
  if( (delta_fn EQ 4) OR 
      (delta_fn EQ 5) )
  {
    UBYTE tn=0;
    UBYTE index;
    while(grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt
           AND (tn < 8))
    {
      switch(grlc_data->next_poll_array[grlc_data->poll_start_tbf].poll_type[tn])
      {
         case CGRLC_POLL_CTRL:
         case CGRLC_POLL_UACK:
         case CGRLC_POLL_COLLISION:
           if(grlc_data->burst_type EQ CGRLC_BURST_TYPE_NB)
           {
             ptr_block = grlc_set_packet_ctrl_ack();
             grlc_send_normal_burst(ptr_block, NULL, tn);
           }
           else
             grlc_send_access_burst(tn);
           break;
         case CGRLC_POLL_RES_AB:
           grlc_send_access_burst(tn);
           break;
         case CGRLC_POLL_RES_NB:
           ptr_block = grlc_set_packet_ctrl_ack();
           grlc_send_normal_burst(ptr_block, NULL, tn);
           break;
         case CGRLC_POLL_DATA:
           if( grlc_data->tbf_type EQ TBF_TYPE_UL )
           {
             /*
              * no downlink active , send ctrl block or pca 
              */
             if( tm_get_num_ctrl_blck( ) NEQ 0 )
             {
               ptr_block = tm_get_ctrl_blk( &index, TRUE );
               grlc_send_normal_burst(NULL, ptr_block, tn);
               grlc_data->rd.next_poll_block = NEXT_POLL_BLOCK_DL_DATA;
             }
             else if(grlc_data->burst_type EQ CGRLC_BURST_TYPE_NB)
             {
               ptr_block = grlc_set_packet_ctrl_ack();
               grlc_send_normal_burst(ptr_block, NULL, tn);
             }
             else
               grlc_send_access_burst(tn);
           }
           break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
         case CGRLC_POLL_RE_ASS: /* TBF re assignment on PACCH */
    
            if(grlc_data->burst_type EQ CGRLC_BURST_TYPE_NB)
            {
               T_U_GRLC_RESOURCE_REQ resource_req;
              
               tm_build_res_req( &resource_req,R_BUILD_2PHASE_ACCESS);
               grlc_send_normal_burst((UBYTE *)&resource_req, NULL, tn);
            }
            else /* PCA CTRL ACK 00 */
            {
               grlc_data->next_poll_array[grlc_data->poll_start_tbf].ctrl_ack = 0;
               grlc_send_access_burst(tn);
            }

           break;
#endif
      }
      tn++;
    }
    grlc_del_sent_poll();
  }  
}/* grlc_send_rem_poll_pos() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_test_mode_active
+------------------------------------------------------------------------------
| Description : This functions returns 0 if the GPRS test mode is not activated. 
|               Otherwise a value greater then 0. 
|               
| Parameters  : no parameters
|
+------------------------------------------------------------------------------
*/

GLOBAL UBYTE grlc_test_mode_active ()
{
  if(grlc_data->testmode.mode NEQ CGRLC_NO_TEST_MODE)
    return TRUE;
  else
    return FALSE;

}/* grlc_test_mode_active*/


/*
+------------------------------------------------------------------------------
| Function    : grlc_prbs
+------------------------------------------------------------------------------
| Description : 
|               This function generates a pseodo random bis sequence. 
|               The implementation is related to CCITT O.151 Okt. 92 chapter 2.1  .
|               
|               This functions generates the next length_i bytes of a 32767-bit 
|               pseudo-random test sequence if action_i is set to COMPUTE_DATA
|               and writes the data at address ptr_i.
|            
|               The function stores the position where it stops to calculate.
|               In case of action_i EQ INITIALIZE the function erase his history.
|               On its next call the function continues with its intial values
|               
| Parameters  : UBYTE action_i (INITIALIZE or COMPUTE_DATA)
|               and only
|               UBYTE length_i (number of data bytes which shall callculated and copied)
|               UBYTE * out_i  (location where this dada have to be placed, only valid)  
|
+------------------------------------------------------------------------------
*/

GLOBAL void grlc_prbs(UBYTE action_i, UBYTE length_i, UBYTE * ptr_i)
{
  TRACE_FUNCTION( "grlc_prbs" );

  switch(action_i)
  {
  case INITIALIZE:

#define FEED_BACK_MASK 0x6000    
    /* 
     * 14th and 15 stage will be feeded back 
     */


    /*
     * Initialize the prbs generation
     *
     * This value is the value of the shift register 8 cycles 
     * before shift register value 0x7fff
     */
    grlc_data->testmode.prbs_shift_reg = 0x55ff;
    break;
  case COMPUTE_DATA:
    {
      /*
       * get prbs computing values
       */
      USHORT i,reg = grlc_data->testmode.prbs_shift_reg;

      UBYTE  * out_ptr = ptr_i;

      for(i=0; i < (8 * length_i); i++)
      {
        /*
         * write a byte in output if neccessary
         */
        if(i % 8 EQ 0) 
        { 
          *out_ptr++ = (UBYTE)(0x00ff&reg);
        }
        
        
        {
          USHORT temp = reg & FEED_BACK_MASK;
          /*
           *  shift the register and but new data in
           */
          reg = reg << 1;
          if ( (temp EQ FEED_BACK_MASK) OR (temp EQ 0) )
          {
            /* 
             * put a "0" in 
             */;
          }
          else
          {
            /* 
             * put a "1" in
             */
            reg +=1;       
          }
        }   /* for(i=0; i < (8 * length_i); i++) */
      }      
      /*
       * store prbs computing values
       */
      grlc_data->testmode.prbs_shift_reg = reg;
    }
    break;

  default:
    break;
  }
  
  return;

}/*grlc_prbs*/
  







/*
+------------------------------------------------------------------------------
| Function    : grlc_trace_tbf_par
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_trace_tbf_par ( UBYTE tbf_index )
{ 
  TRACE_FUNCTION( "grlc_trace_tbf_par" );
 
  TRACE_EVENT_P9("tbf_type=%d;start_fn=%ld (%ld);end_fn=%ld(%ld);rlc_oct_cnt=%d; pdu_cnt=%ld;vs_vr=%d;va_vq=%d ",
                                                    grlc_data->tbf_ctrl[tbf_index].tbf_type,
                                                    grlc_data->tbf_ctrl[tbf_index].start_fn,
                                                    grlc_data->tbf_ctrl[tbf_index].start_fn%42432,
                                                    grlc_data->tbf_ctrl[tbf_index].end_fn,
                                                    grlc_data->tbf_ctrl[tbf_index].end_fn%42432,
                                                    grlc_data->tbf_ctrl[tbf_index].rlc_oct_cnt,
                                                    grlc_data->tbf_ctrl[tbf_index].pdu_cnt,
                                                    grlc_data->tbf_ctrl[tbf_index].vs_vr,
                                                    grlc_data->tbf_ctrl[tbf_index].va_vq);

  TRACE_EVENT_P9("cnt_ts=%d;ack_cnt=%d;fbi=%d;ret_bsn=%d;N_ACC=%d,tlli=%lx rem_ul_data=%d,PST=%d,PSF=%d",                                  
                                                    grlc_data->tbf_ctrl[tbf_index].cnt_ts,
                                                    grlc_data->tbf_ctrl[tbf_index].ack_cnt,
                                                    grlc_data->tbf_ctrl[tbf_index].fbi,
                                                    grlc_data->tbf_ctrl[tbf_index].ret_bsn,
                                                    grlc_data->tm.n_acc_req_procedures,
                                                    grlc_data->uplink_tbf.tlli,
                                                    grlc_data->grlc_data_req_cnt,
                                                    grlc_data->prim_start_tbf,
                                                    grlc_data->prim_start_free);

} /* grlc_trace_tbf_par */




/*
+------------------------------------------------------------------------------
| Function    : grlc_set_buf_tlli
+------------------------------------------------------------------------------
| Description : The function grlc_set_buf_tlli() fills the TLLI buffer.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_set_buf_tlli ( BUF_tlli_value *buf_tlli_o, ULONG tlli_i )
{
  TRACE_FUNCTION( "grlc_set_buf_tlli" );

  grlc_set_tlli( &buf_tlli_o->l_tlli_value, 
                &buf_tlli_o->o_tlli_value,
                &buf_tlli_o->b_tlli_value[0],
                tlli_i );

} /* grlc_set_buf_tlli */


/*
+------------------------------------------------------------------------------
| Function    : grlc_set_tlli
+------------------------------------------------------------------------------
| Description : The function grlc_set_tlli() fills the TLLI buffer.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_set_tlli
                ( USHORT *l_tlli, USHORT *o_tlli, UBYTE *b_tlli, ULONG tlli )
{
  TRACE_FUNCTION( "grlc_set_tlli" );

  *l_tlli   = 32;
  *o_tlli   = 0;
  
  b_tlli[0] = (UBYTE)((tlli >> 24) & 0x000000ff);
  b_tlli[1] = (UBYTE)((tlli >> 16) & 0x000000ff);
  b_tlli[2] = (UBYTE)((tlli >> 8 ) & 0x000000ff);
  b_tlli[3] = (UBYTE)((tlli      ) & 0x000000ff);

  /* unused byte must be set to 0x00, otherwise CCD has some problems */
  b_tlli[4] = 0;

} /* grlc_set_tlli */


/*
+------------------------------------------------------------------------------
| Function    : grlc_encode_ul_ctrl_block
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_encode_ul_ctrl_block ( UBYTE *ul_ctrl_block, 
                                       UBYTE *ul_ctrl_data )
{
  T_CTRLBUF enc_block;

  TRACE_FUNCTION( "grlc_encode_ul_ctrl_block" );

  grlc_encode_ctrl( ul_ctrl_data, ( T_MSGBUF* )&enc_block , grlc_data->r_bit );
  memcpy( ul_ctrl_block, enc_block.buf, BYTELEN( enc_block.l_buf ) );    

} /* grlc_encode_ul_ctrl_block */






/*
+------------------------------------------------------------------------------
| Function    : grlc_check_if_tbf_start_is_elapsed
+------------------------------------------------------------------------------
| Description : The function grlc_check_if_tbf_start_is_elapsed() checks if 
|               tbf starting time is elapsed or not, modulo calculation is 
|               needed
| Parameters  : start_fn    - tbf starting time
|               current_fn  - current frame number
+------------------------------------------------------------------------------
*/
GLOBAL BOOL grlc_check_if_tbf_start_is_elapsed ( ULONG start_fn, ULONG current_fn)
{
  BOOL  result = FALSE;
  ULONG d1;
  /* ULONG d2; */
  /* FN_MAX=0x297000 == 2715648 ==125463 seconds(4.62ms per frame)
   * the starting time is within  current_fn-10808 and current_fn+31623
   * modulo operation must be taken in account
   */
  TRACE_FUNCTION( "grlc_check_if_tbf_start_is_elapsed" );

  /*
   * handle maximum distance for tbf starting time
   */

  if(start_fn EQ CGRLC_STARTING_TIME_NOT_PRESENT)  /*lint !e650*/
  {
    result =TRUE;
    return result;
  }
  d1 = 10808;
  /* d2 = 31623; */
  if( (start_fn <= current_fn)     AND
      ((current_fn-start_fn) <= d1))
  {
    result = TRUE;
    /*TRACE_EVENT_P2(" case 1: st time elapsed st_fn=%ld  c_fn=%ld",start_fn,current_fn);*/
  }
  else if((start_fn >= current_fn) AND
          (FN_MAX-start_fn+current_fn) <= d1)
  {
    result = TRUE;
   /* TRACE_EVENT_P2("case 2: st time elapsed st_fn=%ld  c_fn=%ld",start_fn,current_fn);*/
  }
/*  else
  {
    TRACE_EVENT_P2("case 3: WAIT FOR ST TIME st_fn=%ld  c_fn=%ld",start_fn,current_fn);
  }
*/    

  return result;
} /* grlc_check_if_tbf_start_is_elapsed() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_decode_grlc
+------------------------------------------------------------------------------
| Description : The function grlc_decode_grlc() calls the function ccd_decodeMsg.
|               After the call the decoded Message is in _decodeCtrlMsg.
|
| Parameters  : msg_ptr_i - pointer to buffer that should be decoded
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE grlc_decode_grlc (T_MSGBUF  *  msg_ptr_i)
{ 
  UBYTE result;
  UBYTE msg_type = msg_ptr_i->buf[0] >> 2;;

  TRACE_FUNCTION( "grlc_decode_grlc" );

  /*
   * Offset must be zero, else code to get msg_type is illegal
   */
  TRACE_ASSERT (msg_ptr_i->o_buf==0);



  switch (msg_type)
  {
    case D_UL_ACK:
      if(!grlc_data->grlc_wo_ccd)
      {
        result = ccd_decodeMsg (CCDENT_GRLC, DOWNLINK, msg_ptr_i, _decodedMsg, NOT_PRESENT_8BIT);
      }
      else
      {
        result = grlc_decode_ul_acknack(msg_ptr_i->buf);
      }
      break;
    default:
      TRACE_ERROR(" not Packet ul ack decoded: should nor happen ");
      result = DELETE_MESSAGE;
      break;
  }


  if ( result EQ ccdError )
  {
    return grlc_ccd_error_handling( CCDENT_GRLC );
  }

  return msg_type;

} /* grlc_decode_grlc() */



/*
+------------------------------------------------------------------------------
| Function    : grlc_activate_tfi
+------------------------------------------------------------------------------
| Description : 
|              grlc_activate_tfi modifies tfi´s if tbf starting time is reached
|
|              
| Parameters  : fn_i is the current framenuber in tbf mode
|
+------------------------------------------------------------------------------
*/          

GLOBAL void grlc_activate_tfi (ULONG fn_i)
{

  TRACE_FUNCTION( "grlc_activate_tfi" );


  /* 1. check if starting time is reached */
  switch(grlc_data->tfi_change)
  {
    case TFI_CHANGE_UL:
      if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->ul_tbf_start_time, ((fn_i+5)%FN_MAX)))
      {
        grlc_data->tfi_change      = TFI_CHANGE_NULL;
        grlc_data->ul_tfi          = grlc_data->start_fn_ul_tfi;
        grlc_data->start_fn_ul_tfi = 0xFF;        
        TRACE_EVENT_P2("UL TFI CHANGE St reached st_fn=%ld c_fn=%ld",grlc_data->ul_tbf_start_time,fn_i );
        grlc_data->ul_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
        grlc_data->tbf_ctrl[grlc_data->ul_index].tfi = grlc_data->ul_tfi;
        grlc_data->ul_tfi_changed  = TRUE;
      }
      break;
    case TFI_CHANGE_DL:
      if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->dl_tbf_start_time, fn_i))
      {
        grlc_data->tfi_change      = TFI_CHANGE_NULL;
        grlc_data->dl_tfi          = grlc_data->start_fn_dl_tfi;
        grlc_data->start_fn_dl_tfi = 0xFF;
        TRACE_EVENT_P2("DL TFI CHANGE St reached st_fn=%ld c_fn=%ld",grlc_data->dl_tbf_start_time,fn_i );
        grlc_data->dl_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
        grlc_data->tbf_ctrl[grlc_data->dl_index].tfi = grlc_data->dl_tfi;
      }
      break;
    case TFI_CHANGE_ALL:
      if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->ul_tbf_start_time, ((fn_i+5)%FN_MAX)))
      {
        grlc_data->tfi_change      = TFI_CHANGE_DL;
        grlc_data->ul_tfi          = grlc_data->start_fn_ul_tfi;
        grlc_data->start_fn_ul_tfi = 0xFF;
        TRACE_EVENT_P2("UL TFI CHANGE(ALL) St reached st_fn=%ld c_fn=%ld",grlc_data->ul_tbf_start_time,fn_i );
        grlc_data->ul_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
        grlc_data->tbf_ctrl[grlc_data->ul_index].tfi = grlc_data->ul_tfi;
        grlc_data->tbf_ctrl[grlc_data->dl_index].tfi = grlc_data->dl_tfi;
        grlc_data->ul_tfi_changed  = TRUE;
      }
      if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->dl_tbf_start_time, fn_i))
      {
        if (grlc_data->tfi_change EQ TFI_CHANGE_DL)
          grlc_data->tfi_change      = TFI_CHANGE_NULL;
        else
          grlc_data->tfi_change      = TFI_CHANGE_UL;
        grlc_data->dl_tfi          = grlc_data->start_fn_dl_tfi;
        grlc_data->start_fn_dl_tfi = 0xFF;
        TRACE_EVENT_P2("DL TFI CHANGE(ALL) St reached st_fn=%ld c_fn=%ld",grlc_data->dl_tbf_start_time,fn_i );
        grlc_data->dl_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
      }
      break;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : grlc_t_status
+------------------------------------------------------------------------------
| Description : This function returns the remaining time in milliseconds.
|               A value of 0L is returned in case the timer is not existing or
|               not running.
|
| Parameters  : t_index : timer index
|
+------------------------------------------------------------------------------
*/
GLOBAL T_TIME grlc_t_status( USHORT t_index )
{
  T_TIME t_time = 0L;
  
  TRACE_FUNCTION( "grlc_t_status" );

  vsi_t_status( GRLC_handle, t_index, &t_time );

  return( t_time );
} /* grlc_t_status */ 

/*
+------------------------------------------------------------------------------
| Function    : grlc_enter_standby_state
+------------------------------------------------------------------------------
| Description : This function is called in case the STANDBY state should be
|               entered.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_enter_standby_state ( void )
{
  TRACE_FUNCTION( "grlc_enter_standby_state" );

  if( grlc_data->ready_timer.handling EQ READY_TIMER_HANDLING_ENABLED )
  {
    if( grlc_data->ready_timer.state EQ READY_STATE )
    {
      /* The ready_timer.state is set to STANDBY_STATE just in case we are not already in this state.
         The CGRLC_STANDBY_STATE_IND primitives are sent if we move from READY_STATE to STANDBY_STATE only.  
      */
      if( grlc_data->ready_timer.value NEQ CGRLC_DEACTIVATED )
      {
        /* If the timer T3314 expires while we are in READY_STATE but the timer is deactivated then
           the transition to STANDBY_STATE will never occur
        */
        /* If the primitive CGRLC_FORCE_TO_STANDBY_REQ is received when we are in Ready State but
           the timer is deactivated then the transition to STANDBY_STATE will never occur
        */
        grlc_data->ready_timer.state = STANDBY_STATE;
        vsi_t_stop( GRLC_handle, T3314 );

        {
          PALLOC(cgrlc_standby_state_ind,CGRLC_STANDBY_STATE_IND); /* T_CGRLC_STANDBY_STATE_IND sent to GMM */
          PSEND(hCommGMM,cgrlc_standby_state_ind);
        }

        {
          PALLOC(cgrlc_standby_state_ind,CGRLC_STANDBY_STATE_IND); /* T_CGRLC_STANDBY_STATE_IND sent to GRR */
          PSEND(hCommGRR,cgrlc_standby_state_ind);
        }
      }
      else
      {
        TRACE_EVENT( "grlc_enter_standby_state: MS enters STANDBY state while T3314 is deactivated" );
      }
    }
    else
    {
      TRACE_EVENT( "grlc_enter_standby_state: MS is already in STANDBY state" );
    }
  }
} /* grlc_enter_standby_state */ 

/*
+------------------------------------------------------------------------------
| Function    : grlc_enter_ready_state
+------------------------------------------------------------------------------
| Description : This function is called in case the READY state should be
|               entered.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void grlc_enter_ready_state ( void )
{
  TRACE_FUNCTION( "grlc_enter_ready_state" );

  if (grlc_data->ready_timer.state EQ STANDBY_STATE)
  {
    /* The ready_timer.state is set to READY_STATE just in case we are not already in this state.
       The CGRLC_READY_STATE_IND primitives are sent only if we move from STANDBY_STATE to READY_STATE */

    /* If we receive the primitive CGRLC_READY_TIMER_CONFIG_REQ with timer value CGRLC_DEACTIVATED when 
       we are in CGRLC_STANDBY, the state will immediately switch to READY and the CGRLC_READY_STATE_IND
       primitives will be sent */
    grlc_data->ready_timer.state = READY_STATE;      

    {
      PALLOC(cgrlc_ready_state_ind,CGRLC_READY_STATE_IND); /* T_CGRLC_READY_STATE_IND  sent to GMM */
      PSEND(hCommGMM,cgrlc_ready_state_ind);
    }

    {
      PALLOC(cgrlc_ready_state_ind,CGRLC_READY_STATE_IND); /* T_CGRLC_READY_STATE_IND  sent to GRR */
      PSEND(hCommGRR,cgrlc_ready_state_ind);
    }
  }
  else
  {
    TRACE_EVENT( "grlc_enter_ready_state: MS is already in READY state" );
  }
} /* grlc_enter_ready_state */ 
/*
+------------------------------------------------------------------------------
| Function    : grlc_convert_11bit_2_etsi
+------------------------------------------------------------------------------
| Description : Converts the 11 bit access burst value into ETSI format
|
| Parameters  : In:  eleven bit value
|               Out: converted eleven bit
|
+------------------------------------------------------------------------------
*/
LOCAL USHORT grlc_convert_11bit_2_etsi ( USHORT eleven_bit )
{
  USHORT etsi11bit;
  USHORT dummy1 = 0, dummy2 = 0;

  TRACE_FUNCTION( "grlc_convert_11bit_2_etsi" );

  /*
   *  11 Bit access burst
   * b: bit
   * b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0
   * should be sent to the network -according 04.60 and 0404- in the
   * following 16-bit format:
   * 0 0 0 0 0 b2 b1 b0 b10 b9 b8 b7 b6 b5 b4 b3
   */

  /*
   * get b2 b1 b0
   */
  dummy1 = 0x0007 & eleven_bit;

  /*
   * shift it 8 bits to left
   */
  dummy1 = ( dummy1 << 8 );

  /*
   * get b10 b9 b8 b7 b6 b5 b4 b3
   */
  dummy2 = 0xFFF8 & eleven_bit;

  /*
   * shift it 3 bits to right
   */
  dummy2 = ( dummy2 >> 3 );

  /*
   * compose dummy1 and dummy2 to the target 16-bit format
   */
  etsi11bit = dummy1 | dummy2;
  
  return etsi11bit;

} /* grlc_convert_11bit_2_etsi() */