view src/g23m-gprs/grlc/grlc_tmf.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 local functions for service TC of
|             entity GRLC.
+-----------------------------------------------------------------------------
*/

#ifndef GRLC_TMF_C
#define GRLC_TMF_C
#endif

#define ENTITY_GRLC

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

#include <stdio.h>
#include <string.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 air message definitions */
#include "grlc.h"        /* to get the global entity definitions */

#include "grlc_f.h"      /* to get Process GRLC global function definitions */
#include "grlc_tmf.h"    /* to get Service TM global function definitions  */
#include "grlc_tms.h"    /* to get Service TM inter signal definitions  */
#include "grlc_rus.h"    /* to get interface to service RU */
#include "grlc_rds.h"    /* to get interface to service RD */
#include "grlc_gffs.h"
#include "grlc_meass.h"
#include "grlc_tpcs.h"
#include "cl_rlcmac.h"

/*==== CONST ================================================================*/
/*
 * used in tm_compare_prim
 */
#define SAME_RLC_MODE       0
#define DIFFERENT_RLC_MODE  1

#define PRIO_LOWER          0
#define PRIO_SAME           1
#define PRIO_HIGHER         2

#define THROUGHPUT_LOWER    0
#define THROUGHPUT_SAME     1
#define THROUGHPUT_HIGHER   2

#ifdef REL99
#define SAME_PFI            0
#define DIFF_PFI            1
#endif




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

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


/*==== PRIVATE FUNCTIONS ====================================================*/


LOCAL void tm_close_gaps_in_ctrl_blk_seq( UBYTE index );
/*==== PUBLIC FUNCTIONS =====================================================*/



/*
+------------------------------------------------------------------------------
| Function    : tm_access_allowed
+------------------------------------------------------------------------------
| Description : The function tm_access_allowed() this function checks wheather
|               access is allowed or not. The return is TRUE if access
|               is allowed.
|
| Parameters  : radio_prrio - radio priority for current primitive
|
+------------------------------------------------------------------------------
*/
GLOBAL BOOL tm_access_allowed (  UBYTE  radio_prio  )
{
  BOOL result = FALSE;
  TRACE_FUNCTION( "tm_access_allowed" );

  switch(grlc_data->uplink_tbf.ac_class)
  {
    case CGRLC_PCCCH_AC_ALLOWED:
      result = TRUE;
      break;
    case CGRLC_PCCCH_AC_NOT_ALLOWED:
      TRACE_EVENT(" grlc ACCESS NOT ALLOWED PBCCH:");
      break;
    case CGRLC_CCCH_AC_NOT_ALLOWED:
      TRACE_EVENT("grlc ACCESS NOT ALLOWED CCCH");
      break;
    default:
      if ( (radio_prio+3) <= grlc_data->uplink_tbf.ac_class)
        result = TRUE;
      else
        TRACE_EVENT_P2("Radio prio to low : pdu_rp=%d  net_rp=%d",radio_prio,grlc_data->uplink_tbf.ac_class);
      break;
  }


  return(result);
} /* tm_access_allowed() */

/*
+------------------------------------------------------------------------------
| Function    : tm_build_chan_req_des
+------------------------------------------------------------------------------
| Description : The function builds a channel request description. It is called
|               during re-allocation or during uplink allocation on
|               a dowlink TBF.
|
| Parameters  : out_i - Function have to write the channel request description
|                       at this address
|               p_ptr_i - Pointer to primitive which causes the channel request
|                       description
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_build_chan_req_des ( T_chan_req_des * out_i,T_PRIM_QUEUE * p_ptr_i )
{

  UBYTE   next;

  TRACE_FUNCTION( "tm_build_chan_req_des" );

  grlc_data->uplink_tbf.ti  = 0; /* no contention resolution needed */
  out_i->peak_thr_class     = p_ptr_i->prim_ptr->grlc_qos.peak;
  out_i->radio_prio         = p_ptr_i->prim_ptr->radio_prio;

  /*
   * set RLC-Mode and LLC-Mode
   */
  out_i->llc_pdu_type = LLC_NOT_ACK; /* that means not acknowledged */
  if(p_ptr_i->prim_type EQ CGRLC_LLC_PRIM_TYPE_DATA_REQ)
  { /* CGRLC_LLC_PRIM_TYPE_DATA_REQ */
    out_i->rlc_mode = RLC_ACK_MODE;     /* that means RLC mode acknowledged */
  }
  else
  { /* CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ */
    out_i->rlc_mode = RLC_UNACK_MODE;     /* that means RLC mode not acknowledged */
  }

  next = p_ptr_i->next;
  out_i->rlc_octet_cnt = p_ptr_i->prim_ptr->sdu.l_buf/8 +1;
  while (next < PRIM_QUEUE_SIZE_TOTAL)
  {
    out_i->rlc_octet_cnt +=
      grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8 +1;
    next  = grlc_data->prim_queue[next].next;
  }

  if (grlc_data->testmode.mode EQ CGRLC_LOOP)
  {
    out_i->rlc_octet_cnt = 0;
    TRACE_EVENT("open-ended tbf for testmode B requested");
  }
  return;

} /* tm_build_chan_req_des */



/*
+------------------------------------------------------------------------------
| Function    : tm_send_tbf_rel
+------------------------------------------------------------------------------
| Description : The function tm_send_tbf_rel() builds CGRLC_TBF_REL_IND
|               and send it.
|
| Parameters  : TBP-Type - that have to be deleted
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_send_tbf_rel ( T_TBF_TYPE tbf_i )
{
  PALLOC(cgrlc_tbf_rel_ind,CGRLC_TBF_REL_IND);

  TRACE_FUNCTION( "tm_send_tbf_rel" );


  if(grlc_data->uplink_tbf.ti)
    cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_CR_FAILED;
  else if (grlc_data->N3102 EQ 0) /* tbf error with cell reselction*/
    cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_WITH_CELL_RESELECT;
  else
    cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_NORMAL;  /* Find condition for abnormal release */

  grlc_data->uplink_tbf.ti = 0;

  /*
   * indicate if testmode or tbf_type is released
   */

  if((tbf_i NEQ TBF_TYPE_DL)  AND  /* Testmode released only in case of uplink tbf release*/
     (grlc_test_mode_active()))
  {
    if (grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM)
    {
      MFREE(grlc_data->testmode.ptr_test_data);
      grlc_data->testmode.ptr_test_data = NULL;
    }
    grlc_data->testmode.mode = CGRLC_TEST_MODE_RELEASE;
    cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_NORMAL;
  }

#if defined REL99 AND defined TI_PS_FF_TI_PS_FF_TBF_EST_PACCH
  if (tbf_i EQ TBF_TYPE_TP_ACCESS AND
      grlc_data->tm.pacch_prr_pca_sent) /*PRR/PCA sent as POLL (tbf on pacch)*/
  {
    vsi_t_stop(GRLC_handle,T3168);
    cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_UL;
    grlc_data->tm.pacch_prr_pca_sent = FALSE;
    sig_tm_gff_ul_deactivate();
  }
  else
#endif
  if (tbf_i EQ TBF_TYPE_UL)
  {
    cgrlc_tbf_rel_ind->tbf_mode  = CGRLC_TBF_MODE_UL;
    grlc_data->rel_type         |= REL_TYPE_UL;
    sig_tm_gff_ul_deactivate();
  }
  else if (tbf_i EQ TBF_TYPE_DL)
  {
    cgrlc_tbf_rel_ind->tbf_mode  = CGRLC_TBF_MODE_DL;
    grlc_data->rel_type         |= REL_TYPE_DL;
    sig_tm_gff_dl_deactivate();
    cgrlc_tbf_rel_ind->dl_trans_id = grlc_data->downlink_tbf.trans_id;
  }
  else
  {
    cgrlc_tbf_rel_ind->tbf_mode = CGRLC_TBF_MODE_DL_UL;
    grlc_data->rel_type         = REL_TYPE_DL_UL;
    cgrlc_tbf_rel_ind->dl_trans_id = grlc_data->downlink_tbf.trans_id;
    sig_tm_gff_ul_deactivate();
    sig_tm_gff_dl_deactivate();
  }


  /*
   *  \   tbf_i | UL DL CONC
   *    \       |
   *      \     |
   *        \   |
   * tbf_type \ |
   * -----------+-----------
   *     NULL   | x  x   x
   *       UL   | x  -   x
   *       DL   | -  x   x
   *     CONC   | -  -   x
   *
   * x means, that no more TBF is existing
   * - means, that a TBF is still existing
   */

  if( tbf_i               EQ TBF_TYPE_CONC OR
      grlc_data->tbf_type EQ TBF_TYPE_NULL OR
      grlc_data->tbf_type EQ tbf_i            )
  {
    cgrlc_tbf_rel_ind->v_c_value = TRUE;

    meas_grlc_c_get_c_value( &cgrlc_tbf_rel_ind->c_value );
    meas_c_restart( );

  }
  else
  {
    cgrlc_tbf_rel_ind->v_c_value = FALSE;
  }

#if defined (_TARGET_)
  switch(cgrlc_tbf_rel_ind->tbf_mode)
  {
    case CGRLC_TBF_MODE_UL:
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
    case CGRLC_TBF_MODE_2PA:
#endif

      TRACE_EVENT_P4("UL_TBF_REL:nr_of_crc_errors= %ld  ul_call_errors=%ld  dl_call_errors=%ld  rel_type=%d",
                                            grlc_data->nr_of_crc_errors,
                                            grlc_data->ul_call_errors,
                                            grlc_data->dl_call_errors,
                                            grlc_data->rel_type);
      break;
    case CGRLC_TBF_MODE_DL:
      TRACE_EVENT_P4("DL_TBF_REL:nr_of_crc_errors= %ld  ul_call_errors=%ld  dl_call_errors=%ld  rel_type=%d",
                                            grlc_data->nr_of_crc_errors,
                                            grlc_data->ul_call_errors,
                                            grlc_data->dl_call_errors,
                                            grlc_data->rel_type);
      break;
    case CGRLC_TBF_MODE_DL_UL:
      TRACE_EVENT_P4("UL/DL_TBF_REL:nr_of_crc_errors= %ld  ul_call_errors=%ld  dl_call_errors=%ld  rel_type=%d",
                                            grlc_data->nr_of_crc_errors,
                                            grlc_data->ul_call_errors,
                                            grlc_data->dl_call_errors,
                                            grlc_data->rel_type);

      break;
    case CGRLC_TBF_MODE_TMA:
    case CGRLC_TBF_MODE_TMB:
      TRACE_EVENT_P3 ("Testmode TBF_REL:nr_of_crc_errors= %ld  ul_call_errors=%ld  dl_call_errors=%ld",
                                            grlc_data->nr_of_crc_errors,
                                            grlc_data->ul_call_errors,
                                            grlc_data->dl_call_errors);

      break;

  }
  if(grlc_data->ul_call_errors OR grlc_data->dl_call_errors)
    {
      TRACE_EVENT_P6("ul_fn_err=%ld,%ld,%ld//dl_fn_err=%ld,%ld,%ld",
                                                                    grlc_data->ul_fn_errors[0],
                                                                    grlc_data->ul_fn_errors[1],
                                                                    grlc_data->ul_fn_errors[2],
                                                                    grlc_data->dl_fn_errors[0],
                                                                    grlc_data->dl_fn_errors[1],
                                                                    grlc_data->dl_fn_errors[2]);
      grlc_data->ul_call_errors   = 0;
      grlc_data->dl_call_errors   = 0;
    }
    grlc_data->nr_of_crc_errors = 0;
#endif /* defined (_TARGET_) */

  PSEND(hCommGRR,cgrlc_tbf_rel_ind);

} /* tm_send_tbf_rel() */



/*
+------------------------------------------------------------------------------
| Function    : tm_abort_tbf
+------------------------------------------------------------------------------
| Description : The function tm_abort_tbf() stops a TBF.
|
| Parameters  : tbf_i - TBF type to abort
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_abort_tbf ( T_TBF_TYPE tbf_i )
{
 /*SZML-TC/056*/

  TRACE_FUNCTION( "tm_abort_tbf" );

  switch( tbf_i )
  {
    case TBF_TYPE_NULL:
      TRACE_EVENT("NULL TBF active: check if tbf starting time is running");
      /*SZML-TC/093*/
      break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
    case TBF_TYPE_TP_ACCESS:
      tm_send_tbf_rel(tbf_i);
      tm_deactivate_tbf(tbf_i);
      break;
#endif
    case TBF_TYPE_UL:
      tm_send_tbf_rel(tbf_i);
      sig_tm_ru_abrel(1, FALSE);
      tm_deactivate_tbf(tbf_i);
      break;
    case TBF_TYPE_DL:
      tm_send_tbf_rel(tbf_i);
      sig_tm_rd_abrel(1,FALSE);
      tm_deactivate_tbf(tbf_i);
      break;
    case TBF_TYPE_CONC:
      tm_send_tbf_rel(tbf_i);
      sig_tm_ru_abrel(1, FALSE);
      sig_tm_rd_abrel(1,FALSE);
      tm_deactivate_tbf(tbf_i);
      break;
    default:
      TRACE_ERROR ( "tm_abort_tbf: TBF type is invalid" );
      break;
  }
} /* tm_abort_tbf() */



/*
+------------------------------------------------------------------------------
| Function    : tm_ini_realloc
+------------------------------------------------------------------------------
| Description : The function tm_ini_realloc() do all action that are necessary
|               to start a Resource Re-Allocation Procedure.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_ini_realloc ( UBYTE start_of_new_tbf_i )
{
  TRACE_FUNCTION( "tm_ini_realloc" );
  grlc_data->tm.start_of_new_tbf = start_of_new_tbf_i ;

 /*SZML-TC/058*/

} /* tm_ini_realloc() */



/*
+------------------------------------------------------------------------------
| Function    : tm_build_res_req
+------------------------------------------------------------------------------
| Description : The function tm_build_res_req() builds Packet Resource Request.
|
| Parameters  : reason_i   - the reason for building that packet resouce
|                            reallocation
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_build_res_req (T_U_GRLC_RESOURCE_REQ *ptr2res_req,
                              T_REASON_BUILD    reason_i)
{
  TRACE_FUNCTION( "tm_build_res_req" );


  memset(ptr2res_req,0,sizeof(T_U_GRLC_RESOURCE_REQ) );


  /* processing of messsage type */
  ptr2res_req->msg_type =  U_GRLC_RESOURCE_REQ_c;

  /* processing of change mark */

  if( grlc_data->tm.change_mark EQ NOT_SET )
  {
    ptr2res_req->v_ma_ch_mark = 0;
  }
  else
  {
    ptr2res_req->v_ma_ch_mark = 1;
    ptr2res_req->ma_ch_mark   = grlc_data->tm.change_mark;
  }

  if(reason_i EQ R_FIX_RE_ALLOC)
  {
    /* 1 - processing of ACCESS_TYPE */
    ptr2res_req->v_access_type     = 0;

    /* 2 - processing of global TFI and TLLI */
    ptr2res_req->flag              = 0;
    ptr2res_req->v_glob_tfi        = 1;
    ptr2res_req->glob_tfi.flag     = 0;
    ptr2res_req->glob_tfi.v_ul_tfi = 1;
    ptr2res_req->glob_tfi.ul_tfi   = grlc_data->ul_tfi;

    /* 3 - processing of radio access capabilities */
    ptr2res_req->v_ra_cap          = FALSE;

    /* 4 - processing of channel request description */
    tm_build_chan_req_des(&ptr2res_req->chan_req_des,
                          &grlc_data->prim_queue[grlc_data->prim_start_tbf]);
  }
  else if(reason_i EQ R_RE_ALLOC)
  {
    /* 1 - processing of ACCESS_TYPE */
    ptr2res_req->v_access_type = 0;

    /* 2 - processing of global TFI and TLLI */
    ptr2res_req->flag          = 1;
    ptr2res_req->v_glob_tfi    = 0;
    ptr2res_req->v_tlli_value  = 1;

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

    /* 3 - processing of radio access capabilities */
    ptr2res_req->v_ra_cap = FALSE;

    /* 4 - processing of channel request description */
    tm_build_chan_req_des(&ptr2res_req->chan_req_des,
                          &grlc_data->prim_queue[grlc_data->tm.start_of_new_tbf]);
  }
  else if(reason_i EQ R_BUILD_2PHASE_ACCESS)
  {
    /* 1 - processing of ACCESS_TYPE */
    ptr2res_req->v_access_type = 1;
    ptr2res_req->access_type   = TWO_PHASE;

    /* 2 - processing of global TFI and TLLI */
    ptr2res_req->flag          = 1;
    ptr2res_req->v_glob_tfi    = 0;
    ptr2res_req->v_tlli_value  = 1;

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

    /* 3 - processing of radio access capabilities */
    if( rr_csf_get_radio_access_capability( &ptr2res_req->ra_cap ) EQ 0 )
    {
      ptr2res_req->v_ra_cap = TRUE;
    }
    else
    {
      ptr2res_req->v_ra_cap = FALSE;

      TRACE_ERROR( "tm_build_res_req: radio access capabilities invalid" );
    }

    /* 4 - processing of channel request description */
    tm_build_chan_req_des((T_chan_req_des *)(&ptr2res_req->chan_req_des),
                          &grlc_data->prim_queue[grlc_data->prim_start_tbf] );
  }

  /* 5 - processing of signal variance */
  ptr2res_req->signvar   = meas_sv_get_value( );
  ptr2res_req->v_signvar = TRUE;

  /* 6 - processing of relative interference levels */
  meas_int_get_rel_i_level( &ptr2res_req->ilev );

  /* 7 - processing of C value */
  ptr2res_req->c_value = meas_grlc_c_get_value( );

#ifdef REL99
  ptr2res_req->v_release_99_str_grlc_prr              = TRUE;

  /* Workaround to avoid definition of EGPRS measurements info
   * in grr.aim file. This will reduce the size of ccddata.lib
   */
  ptr2res_req->release_99_str_grlc_prr.flag           = 0;
  ptr2res_req->release_99_str_grlc_prr.flag2          = 0;

  /* Flag PFI, shall only include if PFI and BSS R99 */
  if (grlc_data->nw_rel AND grlc_data->pfi_support)
  {
    ptr2res_req->release_99_str_grlc_prr.v_pfi = 1;

    if ( reason_i EQ R_RE_ALLOC )
    {
      ptr2res_req->release_99_str_grlc_prr.pfi =
        grlc_data->prim_queue[grlc_data->tm.start_of_new_tbf].prim_ptr->pkt_flow_id[0];
    }
    else
    {
      ptr2res_req->release_99_str_grlc_prr.pfi = grlc_data->pfi_value;
    }
  }
  else
  {
    ptr2res_req->release_99_str_grlc_prr.v_pfi = 0;
  }

  ptr2res_req->release_99_str_grlc_prr.add_ms_rac     = 0;
  ptr2res_req->release_99_str_grlc_prr.retrans_of_prr = 0;
#endif


} /* tm_build_res_req() */










/*
+------------------------------------------------------------------------------
| Function    : tm_init_prim
+------------------------------------------------------------------------------
| Description : The function tm_init_prim() initializes the primitive queue.

| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_init_prim ( void )
{
  UBYTE  i;
  TRACE_FUNCTION( "tm_init_prim" );


  /* LLC PRIM QUEUE*/
  for (i=0;i<PRIM_QUEUE_SIZE;i++)
  {
    /*
     *   set next to the following entry
     */
    grlc_data->prim_queue[i].next = i+1;

    /*
     *  and initialize the not used primitive entry
     */
    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;
  }


  /*
   * last free entry points to 0xff
   */
  grlc_data->prim_queue[PRIM_QUEUE_SIZE-1].next = 0xff;

  /*
   *   index 0 is the first free entry
   */
  grlc_data->prim_start_free = 0;

  /*
   * becauce there are no primitives in the tbf prim_start_tbf points to 0xff
   */
  grlc_data->prim_start_tbf = 0xff;

  /*
   * init because there are no primitives there is also no user data
   */
  grlc_data->prim_user_data = 0;


  /* init gmm prim queue*/

  for (i=PRIM_QUEUE_SIZE; i<(PRIM_QUEUE_SIZE_TOTAL);i++)
  {
    grlc_data->prim_queue[i].next = i+1;

    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->gmm_procedure_is_running = FALSE;
  grlc_data->prim_queue[PRIM_QUEUE_SIZE_TOTAL-1].next = 0xff;



} /* tm_init_prim() */




/*
+------------------------------------------------------------------------------
| Function    : tm_start_access
+------------------------------------------------------------------------------
| Description : The function tm_start_access() prepares the TC data structure
|               for a packet access procedure.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_start_access ( void )
{
  USHORT rlc_octetts;

  TRACE_FUNCTION( "tm_start_access" );

  /*
   *  mark that first packet access in process
   */

  grlc_data->tm.n_res_req  = 0;

#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
  grlc_data->tm.pacch_prr_pca_sent = FALSE;
#endif


  grlc_data->tm.n_acc_req_procedures++;

  if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)
  {
    grlc_data->uplink_tbf.prio
         = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->radio_prio;
    /*  save prio for packet access request building     */
    rlc_octetts =
       grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8 +1;
#ifdef REL99
    if (grlc_data->pfi_support)
    {
      /* pfi will take 1 byte*/
      grlc_data->uplink_tbf.nr_blocks = ( rlc_octetts / 15 ) + 1;
      grlc_data->pfi_value =
        grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->pkt_flow_id[0];
    }
    else
#endif
    { /* last "+1" we need complete bytes/octetts   */
      grlc_data->uplink_tbf.nr_blocks = ( rlc_octetts / 16 ) + 1;
    }

    /*TRACE_EVENT_P1("tm_start_access: nr_block:  %d", grlc_data->uplink_tbf.nr_blocks);*/
    /* 16 because 23(CS_1 length) -3(blockheader) -4(TLLI) = 16 octetts   */
    /* last "+1" we need complete blocks                                  */
    if(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type EQ CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ )
    {
      grlc_data->uplink_tbf.rlc_mode = CGRLC_RLC_MODE_UACK;
      grlc_data->uplink_tbf.ti = 0;  /*  mark that contention resolution is not requested    */
    }
    else
    {
      grlc_data->uplink_tbf.rlc_mode = CGRLC_RLC_MODE_ACK;
      grlc_data->uplink_tbf.ti = 1;     /*  mark that contention resulution is not yet done    */
    }
    /*
     *  estimate access_type
     */
    if(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type EQ CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ )
    {
      grlc_data->uplink_tbf.access_type = CGRLC_AT_TWO_PHASE;
    }
    else if(grlc_data->uplink_tbf.access_type EQ CGRLC_AT_CELL_UPDATE)
    {
      TRACE_EVENT("CU WILL BE PERFORMED");
    }
    else
    {
      switch(grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause)
      {
        case GRLC_DTACS_DEF:
          if(grlc_data->uplink_tbf.nr_blocks <= 8)
          {
            grlc_data->uplink_tbf.access_type = CGRLC_AT_SHORT_ACCESS;
          }
          else
          {
            grlc_data->uplink_tbf.access_type = CGRLC_AT_ONE_PHASE;
          }
          break;

        case GRLC_DTACS_PAGE_RESPONSE:
          grlc_data->uplink_tbf.access_type = CGRLC_AT_PAGE_RESPONSE;
          break;

        case GRLC_DTACS_MOBILITY_MANAGEMENT:
          grlc_data->uplink_tbf.access_type = CGRLC_AT_MM_PROCEDURE;
          break;
        case GRLC_DTACS_EMPTY_FRAME:
        case GRLC_DTACS_CELL_NOTIFI_NULL_FRAME:
          grlc_data->uplink_tbf.access_type = CGRLC_AT_CELL_UPDATE;
          TRACE_EVENT("EMPTY FRAME for CU, but not requested by GMM");
          break;

        default:
          grlc_data->uplink_tbf.access_type = CGRLC_AT_NULL;
          break;
      }
    }
  }
  else
  {
    TRACE_ERROR("NO PRIM IN QUEUE in tm_start_access");
  }


} /* tm_start_access() */



/*
+------------------------------------------------------------------------------
| Function    : tm_data_req
+------------------------------------------------------------------------------
| Description : The function tm_data_req() starts the process of queueing
|               a primitive received from LLC
|
| Parameters  : prime_tpye_i - primitiven type (PRIME_TYPE_UNITDATA or
|                                                     PRIME_TYPE_DATA)
|               ptr2prim_i   - address of the primitive to handle
|
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_data_req ( T_PRIM_TYPE prim_tpye_i,
                          T_GRLC_DATA_REQ * ptr2prim_i)
{
  UBYTE free_entry_count , position , new_prim ;
  T_COMPARE_PRIM compare_result  = C_PRIM_CONTINUE;
  BOOL new_qos = FALSE;

  TRACE_FUNCTION( "tm_data_req" );


  /*
   *  get the index of next free prim queue entry
   */
  free_entry_count = tm_prim_queue_get_free_count();

  if (free_entry_count)
  {
    /* get first free entry from free list */
    new_prim  = grlc_prim_get_first (&grlc_data->prim_start_free);

#ifdef REL99
    /*SM currenlty give 0xFF , in case network does not assign PFI */
    if (ptr2prim_i->pkt_flow_id[0] EQ 0xFF)
    {
      ptr2prim_i->pkt_flow_id[0] = 0;
    }
#endif

    grlc_data->prim_queue[new_prim ].prim_type = prim_tpye_i;
    grlc_data->prim_queue[new_prim ].prim_ptr = ptr2prim_i;

    position  = grlc_data->prim_start_tbf;

    do
    {
      if(position  < PRIM_QUEUE_SIZE_TOTAL) /*  this "if" make sure only valid llc_pdu
                                                 are used in comparision */
      {

        compare_result  = tm_compare_prim(new_prim ,position ,&new_qos);

        /*
         * position for new prim is found !
         */
        if(compare_result  NEQ C_PRIM_CONTINUE) break;

        position  = grlc_data->prim_queue[position ].next;

      }
      else
      { /* first prim in queue */
        compare_result  = C_PRIM_NEW_TBF;
        break;
      }

    } while (1);


    switch( compare_result  )
    {
      case C_PRIM_NEW_TBF:
        grlc_data->prim_queue[new_prim ].start_new_tbf = 1;
        break;
      case C_PRIM_REALLOC_START:
        {
          T_U_GRLC_RESOURCE_REQ resource_req;/*lint !e813*/

          tm_ini_realloc(new_prim);
          tm_build_res_req( &resource_req,
                            R_RE_ALLOC );
		  tm_store_ctrl_blk( CGRLC_BLK_OWNER_TM, ( void* )&resource_req );
          if (grlc_data->prim_queue[position].next NEQ 0xff)/*sec 8.1.1.1.2 para 10*/
          { 
            grlc_data->prim_queue[grlc_data->prim_queue[position].next].re_allocation = 1;
          }
       }
        break;
      case C_PRIM_REALLOC_SHORT:
        {
          T_U_GRLC_RESOURCE_REQ resource_req; /*lint !e813*/

          tm_ini_realloc(new_prim);
          tm_build_res_req( &resource_req,
                            R_FIX_RE_ALLOC );
          tm_store_ctrl_blk( CGRLC_BLK_OWNER_TM, ( void* )&resource_req );
        }
        break;

      case C_PRIM_REALLOC_MARK:
        grlc_data->prim_queue[new_prim ].re_allocation = 1;
        break;
      case C_PRIM_RLC_MODE_CHANGE:  /*sec 8.1.1.1.2 para 5*/
        grlc_data->prim_queue[new_prim].start_new_tbf = 1;
        grlc_data->prim_queue[grlc_data->prim_queue[position].next].start_new_tbf = 1;
        break;

    }


    if(position < PRIM_QUEUE_SIZE_TOTAL)
    {
      position  = grlc_data->prim_queue[position].next;
    }
    /*This new QOS is for lower priority */
    if ( (position EQ  0xff) AND (new_qos EQ TRUE))
    {
      grlc_data->prim_queue[new_prim].re_allocation = 1;/*8.1.1.1.2 para 10*/
      TRACE_EVENT_P2("reallocation set for llc pdu = %d ,priority =%d",new_prim,ptr2prim_i->radio_prio);
    }

    grlc_prim_put(&grlc_data->prim_start_tbf,new_prim ,position );

    /*
     * update amount of buffered user data
     */
    grlc_data->prim_user_data += BYTELEN(ptr2prim_i->sdu.l_buf);

    /*
     * and check if the queue is now full
     */
    free_entry_count--;

    if( (free_entry_count == 0) || (grlc_data->prim_user_data > grlc_data->tm.max_grlc_user_data ) )
    {
      grlc_data->tm.send_grlc_ready_ind = PRIM_QUEUE_FULL;
    }
  }
  else
  {
    TRACE_ERROR("Data-Request, but prim_queue full");
    /*
     * This is an error of LLC.
     * Therefore here is no special handling of this case
     */
    PFREE(ptr2prim_i);

  }

} /* tm_data_req() */



/*
+------------------------------------------------------------------------------
| Function    : tm_grlc_init
+------------------------------------------------------------------------------
| Description : The function tm_grlc_init() initialize the TC data structure.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_grlc_init ( void )
{
  UBYTE i;

  TRACE_FUNCTION( "tm_grlc_init" );

  /*
   *  set some values
   */
  grlc_data->tm.disable_class         = CGRLC_DISABLE_CLASS_CR;
  grlc_data->tbf_type                 = TBF_TYPE_NULL;
  grlc_data->rel_type                 = REL_TYPE_NULL;
  grlc_data->tm.start_of_new_tbf      = 0xff;
  grlc_data->tm.send_grlc_ready_ind   = SEND_A_GRLC_READY_IND;


  grlc_data->tm.n_acc_req_procedures  = 0;
  grlc_data->tm.n_res_req             = 0;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
  grlc_data->tm.pacch_prr_pca_sent    = FALSE;
#endif


  /* initialize the relevant data for uplink control block */
  grlc_data->tm.ul_ctrl_blk.seq[0]    = MAX_CTRL_BLK_NUM;

  for( i = 0; i < MAX_CTRL_BLK_NUM; i++ )
  {
    grlc_data->tm.ul_ctrl_blk.blk[i].state = BLK_STATE_NONE;
    grlc_data->tm.ul_ctrl_blk.blk[i].owner = CGRLC_BLK_OWNER_NONE;
  }

  /*
   * Initialise service name (uses define SERVICE_NAME_* in GRLC.H);
   */

  INIT_STATE(TM,TM_ACCESS_DISABLED);
  /*
   *  initialize primitive queue
   */
  tm_init_prim();


} /* tm_grlc_init() */




/*
+------------------------------------------------------------------------------
| Function    : tm_prim_queue_get_free_count
+------------------------------------------------------------------------------
| Description : This function returns the number of free
|               entries in the primitive queue.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE tm_prim_queue_get_free_count ( void )
{
  UBYTE i = grlc_data->prim_start_free;
  UBYTE result = 0,j;

  TRACE_FUNCTION( "tm_prim_queue_get_free_count" );


  for(j=0;j<PRIM_QUEUE_SIZE_TOTAL;j++)
  {
    if (i NEQ 0xff)
    {
      result++;
      i = grlc_data->prim_queue[i].next;
    }
    else
    {
      break;
    }
  }
  if((grlc_data->grlc_data_req_cnt + result NEQ PRIM_QUEUE_SIZE )AND
     !grlc_data->gmm_procedure_is_running)
  {
    TRACE_EVENT_P4("PST=%d PSF=%d PDU=%d FREE_CNT=%d: tm_prim_queue_get_free_count CHECK it"
                                                           ,grlc_data->prim_start_tbf
                                                           ,grlc_data->prim_start_free
                                                           ,grlc_data->grlc_data_req_cnt
                                                           ,result);
  }

  return(result);

} /* tm_prim_queue_get_free_count() */




/*
+------------------------------------------------------------------------------
| Function    : tm_compare_prim
+------------------------------------------------------------------------------
| Description : The function tm_compare_prim() check wheather the pdu have to
|               set at tis position or not. They function also estimate
|               how to set this primitive (with new TBF, immediately
|               re-allocation or re-allocation at next PDU-boundary)
|
| Parameters  : new_prim_i - index of the new-primitive entry in prim_queue[]
|               position_i - index of the preceding entry of the possible
|                            position of the new primitive
+------------------------------------------------------------------------------
*/
GLOBAL T_COMPARE_PRIM tm_compare_prim ( UBYTE new_prim_i,
                                        UBYTE position_i,
                                        BOOL *new_qos)
{
  BOOL rlc_mode;
  UBYTE new_prio       = PRIO_HIGHER;
  UBYTE new_throughput = THROUGHPUT_HIGHER;
#ifdef REL99
  UBYTE new_pfi = SAME_PFI;
#endif
  UBYTE pre_prim_index, post_prim_index, new_prim_index;
  T_GRLC_UNITDATA_REQ * pre_prim_ptr, * new_prim_ptr, * post_prim_ptr;
  T_COMPARE_PRIM result;

  TRACE_FUNCTION( "tm_compare_prim" );


  /*
   *  set all variables
   */

  pre_prim_index =  position_i;
  post_prim_index = grlc_data->prim_queue[position_i].next;
  new_prim_index = new_prim_i;


  /*
   * GRLC_UNITDATA_REQ and T_GRLC_UNITDATA_REQ have the same layout!!
   */
  pre_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[pre_prim_index].prim_ptr;
  post_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[post_prim_index].prim_ptr;
  new_prim_ptr = (T_GRLC_UNITDATA_REQ *) grlc_data->prim_queue[new_prim_index].prim_ptr;



  if(post_prim_index NEQ 0xff)
  {
#ifdef REL99
    if (grlc_data->pfi_support AND
        (post_prim_ptr->pkt_flow_id[0] NEQ new_prim_ptr->pkt_flow_id[0])
       )
    {
      new_pfi = DIFF_PFI;
    }
#endif

    /*
     * last position in queue; the values at position 0xff in the prim_queue are invalid
     * therefore they are here not set
     */
    if(post_prim_ptr->radio_prio < new_prim_ptr->radio_prio )
    {
      new_prio = PRIO_LOWER;
    }
    else if(post_prim_ptr->radio_prio EQ new_prim_ptr->radio_prio )
    {
      new_prio = PRIO_SAME;
    }

    if(post_prim_ptr->grlc_qos.peak > new_prim_ptr->grlc_qos.peak )
    {
      new_throughput = THROUGHPUT_LOWER;
    }
    else if(post_prim_ptr->grlc_qos.peak EQ new_prim_ptr->grlc_qos.peak )
    {
      new_throughput = THROUGHPUT_SAME;
    }
  }

/*  TRACE_EVENT_P2("np=%d np=%d",new_prio,new_throughput);*/


  /*
   * evalute - wheather the primitive have to put at this position or not
   * compare with "following primitive"
   */


  if(post_prim_index EQ 0xff)
  { /*
     * because this is the last entry in prim_queue this
     * primitive have to put at this position
     */
    result = C_PRIM_PUT;
  }
  else
  {
    if (grlc_data->prim_queue[post_prim_index].rlc_status)
    { /*
       * it is forbidden to change position of
       * primitives already in transmission
       */
      result = C_PRIM_CONTINUE;
    }
    else if (grlc_data->prim_queue[post_prim_index].cv_status)
    {/*
      * it is forbidden to change position of primitives
      * included in countdown procedure
      */
      result = C_PRIM_CONTINUE;
    }
#ifdef REL99
    else if (new_pfi EQ DIFF_PFI)
    {
      result = C_PRIM_PUT;
    }
#endif
    else if ( new_prio EQ PRIO_HIGHER)
    {
      result = C_PRIM_PUT;
    }
    else if ( (new_prio EQ PRIO_SAME) AND (new_throughput EQ THROUGHPUT_HIGHER) )
    {
      result = C_PRIM_PUT;
    }
    else
    {
      result = C_PRIM_CONTINUE;
    }
  }

  /*
   * evalute - type of "put"
   * compare with "preceding primitive"
   */


  /*TRACE_EVENT_P3("np=%d np=%d result=%d",new_prio,new_throughput,result);*/


  if(result EQ C_PRIM_PUT)
  {

    /*
     * set variables
     */


    if(pre_prim_ptr->radio_prio < new_prim_ptr->radio_prio )
    {
      new_prio = PRIO_LOWER;
      *new_qos = TRUE;
    }
    else if(pre_prim_ptr->radio_prio EQ new_prim_ptr->radio_prio )
    {
      new_prio = PRIO_SAME;
    }
    else
    {
      new_prio = PRIO_HIGHER;
    }

    if(pre_prim_ptr->grlc_qos.peak > new_prim_ptr->grlc_qos.peak )
    {
      new_throughput = THROUGHPUT_LOWER;
    }
    else if(pre_prim_ptr->grlc_qos.peak EQ new_prim_ptr->grlc_qos.peak )
    {
      new_throughput = THROUGHPUT_SAME;
    }
    else
    {
      new_throughput = THROUGHPUT_HIGHER;
    }

#ifdef REL99
    if (grlc_data->pfi_support AND
        (pre_prim_ptr->pkt_flow_id[0] NEQ new_prim_ptr->pkt_flow_id[0])
       )
    {
      new_pfi = DIFF_PFI;
    }
    else
    {
      new_pfi = SAME_PFI;
    }
#endif

    if (  grlc_data->prim_queue[pre_prim_index].prim_type EQ
      grlc_data->prim_queue[new_prim_index].prim_type)
    {
      rlc_mode = SAME_RLC_MODE;
    }
    else
    {
      rlc_mode = DIFFERENT_RLC_MODE;
    }





    /*
     * evalution
     */


   /* TRACE_EVENT_P4("result=%d,rlc_mode=%d,prio=%d,peak=%d",result,rlc_mode,new_prio,new_throughput);*/

    if(rlc_mode EQ DIFFERENT_RLC_MODE)
    {

      if (new_prio EQ PRIO_HIGHER AND post_prim_index NEQ 0xFF)
      {
        result = C_PRIM_RLC_MODE_CHANGE;
      }
      else
      {
        result = C_PRIM_NEW_TBF;
      }
    }
    else if (grlc_data->prim_queue[pre_prim_index].cv_status)
    { /*
       * if count-down-procedure has started for this pdu,
       * re-allocation is forbitten
       */
      result = C_PRIM_NEW_TBF;
    }
#ifdef REL99
    else if ( grlc_data->pfi_support                           AND
              grlc_data->prim_queue[pre_prim_index].rlc_status AND
              new_pfi EQ DIFF_PFI
            )
    {
        result = C_PRIM_REALLOC_START;
        TRACE_EVENT_P3("C_PRIM_REALLOC_START: npfi = %d, rlc_st = %d pre_prim_i=%d"
                                                       ,new_prim_ptr->pkt_flow_id[0]
                                                       ,grlc_data->prim_queue[pre_prim_index].rlc_status
                                                       ,pre_prim_index);

    }
#endif
    else if( (grlc_data->prim_queue[pre_prim_index].rlc_status) AND
              ((new_prio EQ PRIO_HIGHER ) OR
               ((new_throughput EQ THROUGHPUT_HIGHER ) AND (new_prio EQ PRIO_SAME ))
              )
            )
    { /*
       * C_PRIM_REALLOC_START only if the "pre-pdu"
       * is in transmission
       */
      TRACE_EVENT_P4("C_PRIM_REALLOC_START: ntp=%d np=%d rlc_st=%d  pre_prim_i=%d"
                                                            ,new_throughput
                                                            ,new_prio
                                                            ,grlc_data->prim_queue[pre_prim_index].rlc_status
                                                            ,pre_prim_index);
      result = C_PRIM_REALLOC_START;
    }
    else if(
              (new_prio EQ PRIO_LOWER ) OR
               ((new_throughput EQ THROUGHPUT_LOWER ) AND (new_prio EQ PRIO_SAME ))
           )

		{
        result = C_PRIM_REALLOC_MARK;
        TRACE_EVENT_P4("C_PRIM_REALLOC_MARK: ntp=%d np=%d rlc_st=%d  pre_prim_i=%d"
                                                            ,new_throughput
                                                            ,new_prio
                                                            ,grlc_data->prim_queue[pre_prim_index].rlc_status
                                                            ,pre_prim_index);
    }
    else if (grlc_data->uplink_tbf.ac_class >= CGRLC_PCCCH_AC_NOT_ALLOWED   AND  /* if pbcch is present */
             grlc_data->uplink_tbf.access_type EQ CGRLC_AT_SHORT_ACCESS     AND  /* last acess type */
             grlc_data->tbf_type NEQ TBF_TYPE_DL)                                /* not required if acess is over existing downlink tbf*/
    {
			/* if prevoious access type is short access, ms should send packet resource request*/
        result = C_PRIM_REALLOC_SHORT;
        grlc_data->uplink_tbf.access_type = CGRLC_AT_ONE_PHASE;
	      TRACE_EVENT_P4("C_PRIM_REALLOC_SHORT: ntp=%d np=%d rlc_st=%d  pre_prim_i=%d"
                                                            ,new_throughput
                                                            ,new_prio
                                                            ,grlc_data->prim_queue[pre_prim_index].rlc_status
                                                            ,pre_prim_index);

    }
  }

 /* TRACE_EVENT_P4("np=%d np=%d  rlc_mode=%d result=%d",new_prio,new_throughput,rlc_mode,result);*/


  return(result);

} /* tm_compare_prim() */



/*
+------------------------------------------------------------------------------
| Function    : tm_send_grlc_ready_ind
+------------------------------------------------------------------------------
| Description : This function sends the GRLC_READY_IND
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
LOCAL void tm_send_grlc_ready_ind ( void )
{
  if(grlc_data->gmm_procedure_is_running)
  {
    PALLOC(grlc_suspend_ready_ind, GRLC_SUSPEND_READY_IND);
    PSEND(hCommLLC, grlc_suspend_ready_ind);
  }
  else
  {
    PALLOC(grlc_ready_ind, GRLC_READY_IND);
    PSEND(hCommLLC, grlc_ready_ind);
  }
} /* tm_send_grlc_ready_ind() */

/*
+------------------------------------------------------------------------------
| Function    : tm_handle_grlc_ready_ind
+------------------------------------------------------------------------------
| Description : This function handles the sending of the GRLC_READY_IND. Call
|               to this function in any of the following cases:
|
|               - a GRLC_DATA_REQ was received
|               - a GRLC_UNITDATA_REQ was received
|               - a queued prim is deleted
|               - the TM state is changed from TM_ACCESS_DISABLED or
|                 TM_ACCESS_PREPARED to another
|
| Parameters  : none
+------------------------------------------------------------------------------
*/
GLOBAL void tm_handle_grlc_ready_ind ( void )
{
  UBYTE state = GET_STATE( TM );

  TRACE_FUNCTION( "tm_handle_grlc_ready_ind" );

  if( state EQ TM_ACCESS_DISABLED OR
      state EQ TM_ACCESS_PREPARED    )
  {
    TRACE_EVENT("TM_ACCESS_DISABLED/TM_ACCESS_PREPARED no ready ind");
    return;
  }

  switch (grlc_data->tm.send_grlc_ready_ind)
  {
    case SEND_A_GRLC_READY_IND:
      tm_send_grlc_ready_ind();
      grlc_data->tm.send_grlc_ready_ind = WAIT_FOR_LLC_DATA_REQ;
      break;

    case PRIM_QUEUE_FULL:
      /*
       * Check if we have now enough space
       */
      TRACE_EVENT_P3("PRIM_QUEUE_FULL  prim_start_tbf=%d prim_start_free=%ld user_data=%ld",
                                      grlc_data->prim_start_tbf,
                                      grlc_data->prim_start_free,
                                      grlc_data->prim_user_data);
      if ( (tm_prim_queue_get_free_count() > 0)            AND
           (grlc_data->prim_user_data <= grlc_data->tm.max_grlc_user_data)   )
      {
        TRACE_EVENT("NOT PRIM_QUEUE_FULL !!!");
        tm_send_grlc_ready_ind();
        grlc_data->tm.send_grlc_ready_ind = WAIT_FOR_LLC_DATA_REQ;
      }
      break;

    case WAIT_FOR_LLC_DATA_REQ:
      /* NO BREAK */
    default:
      /* Nothing to do */
      break;
  }

} /* tm_handle_grlc_ready_ind() */



/*
+------------------------------------------------------------------------------
| Function    : tm_handle_error_ra
+------------------------------------------------------------------------------
| Description : The function tm_handle_error_ra() handles actions related
|               to errors that leads to randam access procedure
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_handle_error_ra ( void )
{
  TRACE_FUNCTION( "tm_handle_error_ra" );


  /*
   * - called in case of contention resulution failed in RU
   * - t3168 expires contention resulution failed in 2P-Access
   * - If the mobile station has been assigned more PDCHs than it supports according
   *  to its MS multislot class, the mobile station shall reinitiate the packet access
   *  procedure unless it has already been repeated 4 times. In that
   *  case, TBF failure has occurred.
   */


  /*
   *  Kill TBF if running
   */

  TRACE_EVENT_P3("ERROR_RA: nacc: %d prim_start_tbf:%d   t3164_cnt=%d"
                                                            ,grlc_data->tm.n_acc_req_procedures
                                                            ,grlc_data->prim_start_tbf
                                                            ,grlc_data->t3164_to_cnt);

  if(grlc_data->tbf_type NEQ CGRLC_TBF_MODE_NULL)
  {
    SET_STATE(TM,TM_WAIT_4_PIM);
  }
  else
  {
    SET_STATE(TM,TM_PIM);
    sig_tm_ru_reset_poll_array();	
  }

  tm_abort_tbf(grlc_data->tbf_type);
  grlc_data->tm.n_res_req = 0; /* reset counter of resource requests during access */

  if (grlc_data->N3102 EQ 0)
  {
  }
  else if((grlc_data->tm.n_acc_req_procedures < 5) AND
     (grlc_data->t3164_to_cnt < 4))
  {
  }
  else
  {
    grlc_data->t3164_to_cnt            = 0;
    grlc_data->tm.n_acc_req_procedures = 0;
    tm_cgrlc_status_ind(CGRLC_TBF_ESTABLISHMENT_FAILURE);
    grlc_delete_prim();
    tm_handle_grlc_ready_ind();
  }



} /* tm_handle_error_ra() */

/*
+------------------------------------------------------------------------------
| Function    : tm_activate_tbf
+------------------------------------------------------------------------------
| Description : The function tm_activate_tbf() set the assigned TBF
|               into the data structures
|
| Parameters  : tbf_type_i - type of TBF to deactivate
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_activate_tbf ( T_TBF_TYPE tbf_type_i )
{
  TRACE_FUNCTION( "tm_activate_tbf" );

  /*
   *  Reset of n_acc_req_procedures because of the fact that number of
   *  access procedures during pacet access procedures must not considered in
   *  a error with random access occured during running TBF.
   */
 /* grlc_data->tm.n_acc_req_procedures = 0;*/

  switch( tbf_type_i )
  {
  case TBF_TYPE_UL:
    switch( grlc_data->tbf_type )
    {
    case TBF_TYPE_DL:
      grlc_data->tbf_type = TBF_TYPE_CONC;
      break;
    case TBF_TYPE_NULL:
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
    case TBF_TYPE_TP_ACCESS:
#endif
      grlc_data->tbf_type = TBF_TYPE_UL;
      break;
    default:
      break;
    }
    break;
  case TBF_TYPE_DL:
    switch( grlc_data->tbf_type )
    {
    case TBF_TYPE_UL:
      grlc_data->tbf_type = TBF_TYPE_CONC;
      break;
    case TBF_TYPE_NULL:
      grlc_data->tbf_type = TBF_TYPE_DL;
      break;
    default:
      break;
    }
    break;
  case TBF_TYPE_CONC:
    switch( grlc_data->tbf_type )
    {
    case TBF_TYPE_UL:
    case TBF_TYPE_DL:
    case TBF_TYPE_CONC:
      grlc_data->tbf_type = TBF_TYPE_CONC;
      break;
    default:
      {
        TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type");
      }
      break;
    }
    break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
   case TBF_TYPE_TP_ACCESS:
     switch( grlc_data->tbf_type )
     {
       case TBF_TYPE_NULL:
         grlc_data->tbf_type = TBF_TYPE_TP_ACCESS;
         break;
       default:
         {
           TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type");
         }
         break;
     }
     break;
#endif
  default:
      {
        TRACE_ERROR("FATAL ERROR: tm_activate_tbf called with wrong tbf_type");
      }
      break;
  } /* switch (tbf_type_i) */


} /* tm_activate_tbf() */


/*
+------------------------------------------------------------------------------
| Function    : tm_deactivate_tbf
+------------------------------------------------------------------------------
| Description : The function tm_deactivate_tbf() removes a TBF logical from TM
|               end estimates how to continue.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_deactivate_tbf ( T_TBF_TYPE tbf_i )
{
  TRACE_FUNCTION( "tm_deactivate_tbf" );

  switch( grlc_data->tbf_type )
  {

  case TBF_TYPE_CONC:
    switch( tbf_i )
    {
    case TBF_TYPE_UL:
      grlc_data->tbf_type = TBF_TYPE_DL;
      break;
    case TBF_TYPE_DL:
      grlc_data->tbf_type = TBF_TYPE_UL;
      break;
    case TBF_TYPE_CONC:
      grlc_data->tbf_type = TBF_TYPE_NULL;
      break;
    }
    break;



  case TBF_TYPE_DL:
  case TBF_TYPE_UL:
    if(grlc_data->tbf_type EQ tbf_i)
    {
      grlc_data->tbf_type = TBF_TYPE_NULL;
    }
    else
    {
      TRACE_ERROR("requested release tbf type does not exist");
      TRACE_EVENT_P2("SNH:  requested release tbf type does not exist tbf_i =%d tbf_ty=%d",tbf_i,grlc_data->tbf_type);
    }
    break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
  case TBF_TYPE_TP_ACCESS:
    grlc_data->tbf_type = TBF_TYPE_NULL;
    break;
#endif
  default:
    break;
  }

} /* tm_deactivate_tbf() */






/*
+------------------------------------------------------------------------------
| Function    : tm_delete_prim_queue
+------------------------------------------------------------------------------
| Description : delete all pdus in the queue
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_delete_prim_queue( void)
{
  TRACE_FUNCTION( "tm_delete_prim_queue" );

  do
  {
    grlc_delete_prim();

  } while( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) AND
           !grlc_data->prim_queue[grlc_data->prim_start_tbf].start_new_tbf );

  tm_handle_grlc_ready_ind();

} /* tm_delete_prim_queue */





/*
+------------------------------------------------------------------------------
| Function    : tm_queue_test_mode_prim()
+------------------------------------------------------------------------------
| Description : The function puts a number of primitives
|               in the primitive queue
|
| Parameters  : pdu_num_i  - number of primitives to queue
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_queue_test_mode_prim( UBYTE pdu_num_i )
{
  UBYTE i = 0;
  TRACE_FUNCTION( "tm_queue_test_mode_prim" );


  for (i=0; i<pdu_num_i; i++)
  {
    PALLOC_SDU(grlc_unitdata_req,GRLC_UNITDATA_REQ,(195*8));
    grlc_unitdata_req->sapi = GRLC_SAPI_TEST_MODE;
    grlc_unitdata_req->tlli = grlc_data->uplink_tbf.tlli;
    memset(&grlc_unitdata_req->grlc_qos,0,sizeof(T_GRLC_grlc_qos));
    grlc_unitdata_req->radio_prio=2;
    grlc_unitdata_req->sdu.l_buf= 195*8;
    grlc_unitdata_req->sdu.o_buf=0;
    memset(grlc_unitdata_req->sdu.buf,0x0f,195);             /*lint !e419*/
    PSEND(hCommGRLC,grlc_unitdata_req);
  }

} /* tm_queue_test_mode_prim */



/*
+------------------------------------------------------------------------------
| Function    : tm_close_gaps_in_ctrl_blk_seq
+------------------------------------------------------------------------------
| Description : The function tm_close_gaps_in_ctrl_blk_seq reorders the queue
|               holding the order which is used to identify the next control
|               block to sent.
|
| Parameters  : index - at this index the reordering starts
|
+------------------------------------------------------------------------------
*/
LOCAL void tm_close_gaps_in_ctrl_blk_seq ( UBYTE index )
{
  TRACE_FUNCTION( "tm_close_gaps_in_ctrl_blk_seq" );

  while( index                               <   MAX_CTRL_BLK_NUM AND
         grlc_data->tm.ul_ctrl_blk.seq[index] NEQ MAX_CTRL_BLK_NUM     )
  {
    grlc_data->tm.ul_ctrl_blk.seq[index-1] = grlc_data->tm.ul_ctrl_blk.seq[index];

    index++;
  }

  grlc_data->tm.ul_ctrl_blk.seq[index-1] = MAX_CTRL_BLK_NUM;

} /* tm_close_gaps_in_ctrl_blk_seq() */

/*
+------------------------------------------------------------------------------
| Function    : tm_store_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL BOOL tm_store_ctrl_blk ( T_BLK_OWNER blk_owner, void *blk_struct )
{
  UBYTE       i;                 /* used for counting                  */
  BOOL        result    = FALSE; /* indicates whether control block is */
                                 /* stored successfully or not         */
  T_BLK_INDEX blk_index;         /* index to the control block buffer  */

  TRACE_FUNCTION( "tm_store_ctrl_msg" );

  /*
   * we have to find a free buffer for the control block which is
   * indicated by the index to the control block buffer
   */
  blk_index = MAX_CTRL_BLK_NUM;

  switch( blk_owner )
  {
    case( CGRLC_BLK_OWNER_CTRL ):
      if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_CTRL].state EQ BLK_STATE_NONE )
      {
        blk_index = BLK_INDEX_CTRL;
      }
      break;

    case( CGRLC_BLK_OWNER_CS ):
      if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_CS].state EQ BLK_STATE_NONE )
      {
        blk_index = BLK_INDEX_CS;
      }
      break;

    case( CGRLC_BLK_OWNER_TM ):
      if( grlc_data->tm.ul_ctrl_blk.blk[BLK_INDEX_TM].state EQ BLK_STATE_NONE )
      {
        blk_index = BLK_INDEX_TM;
      }
      break;

    case( CGRLC_BLK_OWNER_MEAS ):

      blk_index = BLK_INDEX_MEAS;

      while( blk_index                                     <   MAX_CTRL_BLK_NUM AND
             grlc_data->tm.ul_ctrl_blk.blk[blk_index].state NEQ BLK_STATE_NONE       )
      {
        blk_index++;
      }
      break;

    default:
      /* do nothing */
      break;
  }

  /*
   * check whether the control block buffer is free,
   */
  if( blk_index < MAX_CTRL_BLK_NUM )
  {
    /*
     * check the queue holding the order which is used to identify the next
     * control block to send
     */
    i = 0;

    while( i                               <   MAX_CTRL_BLK_NUM AND
           grlc_data->tm.ul_ctrl_blk.seq[i] NEQ MAX_CTRL_BLK_NUM     )
    {
      i++;
    }

    /*
     * check whether there is a free entry in the order queue,
     * in case the check fails, there is something wrong with the concept
     */
    if( i < MAX_CTRL_BLK_NUM )
    {
      /*
       * store the control block data and state in the queues
       */
      if(blk_owner EQ CGRLC_BLK_OWNER_TM)
      {
        grlc_encode_ul_ctrl_block
        ( ( UBYTE* )&grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0],
          ( UBYTE* )blk_struct );
      }
      else
      {
        /*
         * encoded control message received by higher layers
         */
        memcpy(( UBYTE* )&grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0],( UBYTE* )blk_struct,BYTE_UL_CTRL_BLOCK);
      }

      grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_ALLOCATED;
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = blk_owner;
      grlc_data->tm.ul_ctrl_blk.seq[i]               = blk_index;

      if( i < MAX_CTRL_BLK_NUM - 1 )
      {
        grlc_data->tm.ul_ctrl_blk.seq[i+1] = MAX_CTRL_BLK_NUM;
      }

      result = TRUE;
    }
    else
    {
      TRACE_ERROR( "tm_store_ctrl_blk: no free entry in queue found" );
    }
  }

  if( result EQ FALSE )
  {
    if( blk_owner EQ CGRLC_BLK_OWNER_MEAS )
    {
      TRACE_EVENT( "tm_store_ctrl_blk: no table entry allocated" );
    }
    else
    {
      TRACE_ERROR( "tm_store_ctrl_blk: no table entry allocated" );
    }
  }

  return( result );

} /* tm_store_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cancel_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL BOOL tm_cancel_ctrl_blk ( T_BLK_OWNER blk_owner )
{
  BOOL  result     = FALSE;
  UBYTE i         = 0;
  UBYTE blk_index = grlc_data->tm.ul_ctrl_blk.seq[i];

  TRACE_FUNCTION( "tm_cancel_ctrl_blk" );


  while( blk_index NEQ MAX_CTRL_BLK_NUM AND
         result    EQ  FALSE                )
  {
    if( grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner EQ blk_owner           AND
        grlc_data->tm.ul_ctrl_blk.blk[blk_index].state EQ BLK_STATE_ALLOCATED     )
    {
      /*
       * mark the entry in the queue as free
       */
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_NONE;
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = CGRLC_BLK_OWNER_NONE;

      tm_close_gaps_in_ctrl_blk_seq( (UBYTE)( i + 1 ) );

      result = TRUE;
    }

    i++;
    if( i < MAX_CTRL_BLK_NUM )
    {
      blk_index = grlc_data->tm.ul_ctrl_blk.seq[i];
    }
    else
    {
      blk_index = MAX_CTRL_BLK_NUM;
    }
  }

  if( result EQ FALSE )
  {
    TRACE_EVENT( "tm_cancel_ctrl_blk: no block found" );
  }

  return( result );

} /* tm_cancel_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_set_start_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE* tm_set_start_ctrl_blk ( UBYTE *index )
{
  UBYTE       i         = 0;
  T_BLK_INDEX blk_index = MAX_CTRL_BLK_NUM;

  TRACE_FUNCTION( "tm_set_start_ctrl_blk" );

  while( i                               <   MAX_CTRL_BLK_NUM AND
         grlc_data->tm.ul_ctrl_blk.seq[i] NEQ MAX_CTRL_BLK_NUM AND
         blk_index                       EQ  MAX_CTRL_BLK_NUM     )
  {
    blk_index = grlc_data->tm.ul_ctrl_blk.seq[i];

    if( grlc_data->tm.ul_ctrl_blk.blk[blk_index].state EQ BLK_STATE_ALLOCATED )
    {
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_SENT_REQ;

      /*
       * the control block was encoded without having correct information
       * about the value of the R bit. So we have to set the correct value now.
       */
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].data[0] = 0x40 | grlc_data->r_bit;
    }
    else
    {
      blk_index = MAX_CTRL_BLK_NUM;
    }

    i++;
  }

  *index = blk_index;

  return( blk_index EQ MAX_CTRL_BLK_NUM ?
                         NULL : grlc_data->tm.ul_ctrl_blk.blk[blk_index].data );

} /* tm_set_start_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_set_stop_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL T_BLK_INDEX tm_set_stop_ctrl_blk
        ( BOOL is_tx_success, T_BLK_OWNER srch_owner, T_BLK_INDEX start_index )
{
  T_BLK_INDEX blk_index = grlc_data->tm.ul_ctrl_blk.seq[start_index];
  T_BLK_INDEX nxt_index;

  TRACE_FUNCTION( "tm_set_stop_ctrl_blk" );

  if( blk_index < MAX_CTRL_BLK_NUM )
  {
    T_BLK_OWNER blk_owner = grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner;

    if( srch_owner EQ CGRLC_BLK_OWNER_NONE OR
        srch_owner EQ blk_owner         )
    {
      /*
       * mark the entry in the queue as free
       */
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].state = BLK_STATE_NONE;
      grlc_data->tm.ul_ctrl_blk.blk[blk_index].owner = CGRLC_BLK_OWNER_NONE;

      tm_close_gaps_in_ctrl_blk_seq( 1 );

      nxt_index = start_index;
    }
    else
    {
      nxt_index = start_index + 1;
    }
  }
  else
  {
    nxt_index = MAX_CTRL_BLK_NUM;
  }

  return( nxt_index );

} /* tm_set_stop_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_set_stop_tm_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_set_stop_tm_ctrl_blk ( void )
{
  T_BLK_INDEX start_index = 0;

  TRACE_FUNCTION( "tm_set_stop_tm_ctrl_blk" );

  while
  (
    ( start_index = tm_set_stop_ctrl_blk( FALSE, CGRLC_BLK_OWNER_TM, start_index ) )
                                                           NEQ MAX_CTRL_BLK_NUM
                                                           ){};
} /* tm_set_stop_tm_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_set_stop_all_ctrl_blk
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_set_stop_all_ctrl_blk ( void )
{
  T_BLK_INDEX start_index = 0;

  TRACE_FUNCTION( "tm_set_stop_all_ctrl_blk" );

  while
  (
    ( start_index = tm_set_stop_ctrl_blk( FALSE,
                                          CGRLC_BLK_OWNER_NONE,
                                          start_index ) ) NEQ MAX_CTRL_BLK_NUM
                                          ){};
} /* tm_set_stop_all_ctrl_blk() */

/*
+------------------------------------------------------------------------------
| Function    : tm_get_gmm_prim_queue
+------------------------------------------------------------------------------
| Description : The function tm_get_gmm_prim_queue () ....
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_get_gmm_prim_queue ( void )
{
  UBYTE i;
  TRACE_FUNCTION( "tm_get_gmm_prim_queue " );



  /* init gmm prim queue*/
  TRACE_EVENT_P4("GET GMM QUEUE: BEFORE ps=%d, pf=%d,sps=%d,spf=%d",
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);

  /*
   * Delte all GMM primitives in current llc queue, which are on the top.
   */
  while((grlc_data->prim_start_tbf >= PRIM_QUEUE_SIZE) AND
        (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL))
  {
    grlc_delete_prim();
  }

  grlc_data->gmm_procedure_is_running = TRUE;

  if(grlc_data->prim_start_free EQ 0xFF)
  {
    TRACE_ERROR("PRIM_QUEUE FULL: RAU MAY BE SENT, NEXT DATA PRIM WILL BE DELETED ");
  }

  for (i=PRIM_QUEUE_SIZE; i<(PRIM_QUEUE_SIZE_TOTAL);i++)
  {
    grlc_data->prim_queue[i].next = i+1;

    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[PRIM_QUEUE_SIZE_TOTAL-1].next = 0xff;

  grlc_data->save_prim_start_tbf  = grlc_data->prim_start_tbf;
  grlc_data->save_prim_start_free = grlc_data->prim_start_free;

  grlc_data->prim_start_tbf  = 0xFF;
  grlc_data->prim_start_free = PRIM_QUEUE_SIZE;
  grlc_data->prim_user_data  = 0;
  grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;

  TRACE_EVENT_P4("GET GMM QUEUE: AFTER ps=%d, pf=%d,sps=%d,spf=%d",
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);


} /* tm_get_gmm_prim_queue  */

/*
+------------------------------------------------------------------------------
| Function    : tm_get_llc_prim_queue
+------------------------------------------------------------------------------
| Description : The function tm_get_llc_prim_queue () ....
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_get_llc_prim_queue ( void )
{
  UBYTE i;

  TRACE_FUNCTION( "tm_get_llc_prim_queue " );


  TRACE_EVENT_P4("GET LLC QUEUE: BEFORE ps=%d, pf=%d,sps=%d,spf=%d",
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);


  if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)
  {
    /*finish gmm data and than resume with llc data*/
   i = grlc_data->prim_start_tbf;
    while(grlc_data->prim_queue[i].next NEQ 0xFF)
    {
      i = grlc_data->prim_queue[i].next;
    }
    grlc_data->prim_queue[i].next          = grlc_data->save_prim_start_tbf;
    grlc_data->prim_queue[i].start_new_tbf = TRUE;
  }
  else
  {
    grlc_data->prim_start_tbf  = grlc_data->save_prim_start_tbf;
  }
  grlc_data->prim_start_free = grlc_data->save_prim_start_free;
  grlc_data->gmm_procedure_is_running = FALSE;
  grlc_data->prim_user_data = 0;
  i = grlc_data->prim_start_tbf;
  while(i NEQ 0xFF)
  {
    grlc_data->prim_user_data += BYTELEN(grlc_data->prim_queue[i].prim_ptr->sdu.l_buf);
    i = grlc_data->prim_queue[i].next;
  }


  TRACE_EVENT_P4("GET LLC QUEUE: AFTER ps=%d, pf=%d,sps=%d,spf=%d",
                                                      grlc_data->prim_start_tbf,
                                                      grlc_data->prim_start_free,
                                                      grlc_data->save_prim_start_tbf,
                                                      grlc_data->save_prim_start_free);




} /* tm_get_llc_prim_queue  */

/*
+------------------------------------------------------------------------------
| Function    : tm_ul_tbf_ind
+------------------------------------------------------------------------------
| Description : The function tm_ul_tbf_ind () ....
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_ul_tbf_ind ( void )
{
  TRACE_FUNCTION( "tm_ul_tbf_ind " );



  switch(grlc_data->tbf_type)
  {
    case TBF_TYPE_NULL:
      if( grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL )
      {
        PALLOC(cgrlc_ul_tbf_ind,CGRLC_UL_TBF_IND); /*T_CGRLC_UL_TBF_IND*/

        tm_start_access();

        cgrlc_ul_tbf_ind->access_type    = grlc_data->uplink_tbf.access_type;
        cgrlc_ul_tbf_ind->ra_prio        = grlc_data->uplink_tbf.prio;
        cgrlc_ul_tbf_ind->nr_blocks      = grlc_data->uplink_tbf.nr_blocks;
        cgrlc_ul_tbf_ind->llc_prim_type  = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_type;
        cgrlc_ul_tbf_ind->rlc_oct_cnt    = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->sdu.l_buf/8 +1;
        cgrlc_ul_tbf_ind->peak           = grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->grlc_qos.peak;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
        cgrlc_ul_tbf_ind->tbf_est_pacch  = FALSE;
#endif

        SET_STATE( TM, TM_PAM );
        PSEND(hCommGRR,cgrlc_ul_tbf_ind);
      }
      else
      {
        /*
         * inform higher layers that no tbf is requested
         */
        PALLOC(cgrlc_ul_tbf_ind,CGRLC_UL_TBF_IND); /*T_CGRLC_UL_TBF_IND*/
        cgrlc_ul_tbf_ind->access_type     = CGRLC_AT_NULL;
        cgrlc_ul_tbf_ind->ra_prio         = 0xEE;
        cgrlc_ul_tbf_ind->nr_blocks       = 0xEE;
        cgrlc_ul_tbf_ind->llc_prim_type   = 0xEE;
        cgrlc_ul_tbf_ind->peak            = 0xEE;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
        cgrlc_ul_tbf_ind->tbf_est_pacch  = FALSE;
#endif


        PSEND(hCommGRR,cgrlc_ul_tbf_ind);
        /*
         * delete control message queue
         */
        tm_set_stop_all_ctrl_blk();
      }
      tm_handle_grlc_ready_ind( );
    break;
    case TBF_TYPE_DL:
      if( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL) AND (!grlc_data->tm.n_res_req))
      {
        tm_start_access();
        tm_build_chan_req_des(&grlc_data->chan_req_des,
                               &grlc_data->prim_queue[grlc_data->prim_start_tbf]);
        sig_tm_rd_ul_req();
        grlc_data->tm.n_res_req++;
      }
      break;
    case TBF_TYPE_CONC:
    case TBF_TYPE_UL:
      break;
    default:
      TRACE_ERROR("unknown tbf type during uplink access");
      break;
  }
} /* tm_ul_tbf_ind  */












/*
+------------------------------------------------------------------------------
| Function    : tm_tfi_handling
+------------------------------------------------------------------------------
| Description : The function tm_tfi_handling () handles modified tfi´s in
|               case of starting time
|
| Parameters  : start_fn_present: indicates if a starting time is present
|               tbf_type : type of the current tbf
|               ul_tfi   : new assignend uplink tfi
|               dl_tfi   : new assignend downlink tfi
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_tfi_handling  (ULONG tbf_start,UBYTE tbf_type, UBYTE ul_tfi, UBYTE dl_tfi)
{

  TRACE_FUNCTION( "tm_tfi_handling " );


  /*TRACE_EVENT_P6("TFI CHANGE: =tbf_type = %d\n fn= %ld \n new_Utfi=%d old_Utfi=%d \n new_Dtfi=%d old_Dtfi=%d"
                                     ,tbf_type
                                     ,tbf_start
                                     ,ul_tfi
                                     ,grlc_data->ul_tfi
                                     ,dl_tfi
                                     ,grlc_data->dl_tfi);

  */
  switch( tbf_type )
  {
    case CGRLC_TBF_MODE_UL:
      if((tbf_start NEQ CGRLC_STARTING_TIME_NOT_PRESENT)  AND  (ul_tfi NEQ grlc_data->ul_tfi)) /*lint !e650*/
      {
        if(grlc_data->tfi_change  EQ TFI_CHANGE_NULL)
          grlc_data->tfi_change = TFI_CHANGE_UL;
        else if(grlc_data->tfi_change  EQ TFI_CHANGE_DL)
          grlc_data->tfi_change = TFI_CHANGE_ALL;
        grlc_data->start_fn_ul_tfi = ul_tfi;
        grlc_data->ul_tbf_start_time = tbf_start;
        TRACE_EVENT_P3("GRLC UL TFI CHANGE AFTER ST. TIME = %ld new_tfi=%d old_tfi=%d"
                                     ,tbf_start
                                     ,ul_tfi
                                     ,grlc_data->ul_tfi);
      }
      else
      {
        if(grlc_data->tfi_change  EQ TFI_CHANGE_UL)
          grlc_data->tfi_change = TFI_CHANGE_NULL;
        else if(grlc_data->tfi_change  EQ TFI_CHANGE_ALL)
          grlc_data->tfi_change = TFI_CHANGE_DL;
        grlc_data->ul_tfi          = ul_tfi;
        grlc_data->start_fn_ul_tfi = 0xFF;
        grlc_data->ul_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
      }
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
      sig_tm_gff_ul_activate(GFF_ACTIVE);
#else
      sig_tm_gff_ul_activate();
#endif
      break;
    case CGRLC_TBF_MODE_DL:
      if((tbf_start NEQ CGRLC_STARTING_TIME_NOT_PRESENT) AND  (dl_tfi NEQ grlc_data->dl_tfi)) /*lint !e650*/
      {
        if(grlc_data->tfi_change  EQ TFI_CHANGE_NULL)
          grlc_data->tfi_change = TFI_CHANGE_DL;
        else if(grlc_data->tfi_change  EQ TFI_CHANGE_UL)
          grlc_data->tfi_change = TFI_CHANGE_ALL;
        grlc_data->start_fn_dl_tfi = dl_tfi;
        grlc_data->dl_tbf_start_time = tbf_start;
        TRACE_EVENT_P3("GRLC DL TFI CHANGE AFTER ST. TIME =%ld new_tfi=%d old_tfi=%d"
                                     ,tbf_start
                                     ,dl_tfi
                                     ,grlc_data->dl_tfi);
      }
      else
      {
        if(grlc_data->tfi_change  EQ TFI_CHANGE_DL)
          grlc_data->tfi_change = TFI_CHANGE_NULL;
        else if(grlc_data->tfi_change  EQ TFI_CHANGE_ALL)
          grlc_data->tfi_change = TFI_CHANGE_UL;
        grlc_data->dl_tfi = dl_tfi;
        grlc_data->start_fn_dl_tfi = 0xFF;
        grlc_data->dl_tbf_start_time = CGRLC_STARTING_TIME_NOT_PRESENT;
      }
      sig_tm_gff_dl_activate();
      break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
    case CGRLC_TBF_MODE_2PA:
      sig_tm_gff_ul_activate(GFF_TWO_PHASE);
      break;
#endif

  }


  /*TRACE_EVENT_P1("TFI_CHANGE = %d",grlc_data->tfi_change );*/

} /* tm_tfi_handling () */



/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_status_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive CGRLC_STATUS_IND
|
| Parameters  : cause - status cause, gmm is informed
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_status_ind ( UBYTE cause )
{
  PALLOC(cgrlc_status_ind,CGRLC_STATUS_IND);

  TRACE_FUNCTION( "tm_cgrlc_status_ind" );

  cgrlc_status_ind->failure = cause;
  PSEND(hCommGMM,cgrlc_status_ind);

  TRACE_EVENT_P1("error cause = %ld",cause);


}/* tm_cgrlc_status_ind*/

/*
+------------------------------------------------------------------------------
| Function    : tm_handle_polling_bit
+------------------------------------------------------------------------------
| Description : Handles the the polling in the immediate assignment (uplink or
|               downlink)
|
| Parameters  : st_fn - starting time
|               tn    - timeslot
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_handle_polling_bit ( ULONG st_fn, UBYTE tn )
{

  TRACE_FUNCTION( "tm_handle_polling_bit" );



  grlc_data->next_poll_fn       = st_fn;
  grlc_data->ul_poll_pos_index  = 0;
  if(grlc_data->burst_type EQ 0)
  {
    grlc_send_access_burst( tn );
  }
  else
  {
    grlc_send_normal_burst(grlc_set_packet_ctrl_ack(), NULL, tn);
  }



}/* tm_handle_polling_bit */



/*
+------------------------------------------------------------------------------
| Function    : tm_store_fa_bitmap
+------------------------------------------------------------------------------
| Description : This function stores the allocation bitmap in
|               case of fixed allocation
|
| Parameters  : ptr2_fix_alloc - ptr to the fixed allocation struct
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_store_fa_bitmap (T_CGRLC_fix_alloc_struct * ptr2_fix_alloc)
{
  UBYTE i,j;
  USHORT ul_res_sum = 0;
  T_FA_ALLOC  * ptr_fa_ctrl;

  TRACE_FUNCTION( "tm_store_fa_bitmap" );


  /*
   * calculate uplink resources allocation
   */

  for(i=0;i<ptr2_fix_alloc->bitmap_len;i++)
  {
    if(ptr2_fix_alloc->bitmap_array[i])
    {
      UBYTE mask = 0x80;

      for(j=0; j<=7; j++)
      {
        if(ptr2_fix_alloc->bitmap_array[i] & mask)
          ul_res_sum++;
        mask>>=1;
      }
    }
  }


  /*
   * set fa_ctrl
   */
  if(grlc_data->uplink_tbf.fa_manag.fa_type EQ FA_NO_CURRENT)
  {
    grlc_data->uplink_tbf.fa_manag.fa_type = FA_NO_NEXT;
    ptr_fa_ctrl                            = &grlc_data->uplink_tbf.fa_manag.current_alloc;
    ptr_fa_ctrl->alloc_start_fn            = grlc_data->ul_tbf_start_time;
    ptr_fa_ctrl->alloc_end_fn              = ptr2_fix_alloc->end_fn;
  }
  else
  {
    grlc_data->uplink_tbf.fa_manag.fa_type = FA_BITMAP;
    ptr_fa_ctrl                            = &grlc_data->uplink_tbf.fa_manag.next_alloc;
    ptr_fa_ctrl->alloc_start_fn            = grlc_data->ul_tbf_start_time;

    /*
     * check conflict of end of current alloc and start of next alloc
     */
    if( grlc_check_dist(grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn,
        grlc_data->uplink_tbf.fa_manag.next_alloc.alloc_start_fn,10000))
    {
      ULONG delta_fn;
      UBYTE idle_frames;
      UBYTE iden_radio_blocks;
      UBYTE ts_delet;

      delta_fn          = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn -
                           grlc_data->uplink_tbf.fa_manag.next_alloc.alloc_start_fn;
      idle_frames       = (UBYTE)((delta_fn / 52) *4  + delta_fn % 4);
      iden_radio_blocks = (UBYTE)((delta_fn - idle_frames) / 4 + 1);

      /*
       * remove shared allocation from current allocation
       */
      ts_delet = 0;
      for(i=0;i<iden_radio_blocks;i++)
      {
        UBYTE pos;
        pos = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len - i;

        /*
         * calculate number of timeslots for current frame and delete them from resources
         */
        if(grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[pos])
        {
          UBYTE mask = 0x80;

          for(j=0; j<=7; j++)
          {
            if(ptr2_fix_alloc->bitmap_array[i] & mask)
              ts_delet++;
            mask>>=1;
          }
        }
        grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[pos] = 0;
      }
      grlc_data->uplink_tbf.fa_manag.current_alloc.ul_res_sum -= ts_delet;
      grlc_data->uplink_tbf.fa_manag.ul_res_sum -= ts_delet;
      grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len -= iden_radio_blocks;
      grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn =
          grlc_data->uplink_tbf.fa_manag.current_alloc.alloc_end_fn - delta_fn;
    }
  }
  grlc_data->uplink_tbf.fa_manag.ul_res_sum += ul_res_sum;
  ptr_fa_ctrl->ul_res_sum                    = ul_res_sum;
  /*
   * store end of fixed allocation
   */
  ptr_fa_ctrl->alloc_end_fn              = ptr2_fix_alloc->end_fn;


  tm_handle_final_alloc (ptr2_fix_alloc->final_alloc);

} /* tm_store_fa_bitmap() */


/*
+------------------------------------------------------------------------------
| Function    : tm_handle_final_alloc
+------------------------------------------------------------------------------
| Description : This function handles the final allocation bit.
|
| Parameters  :   -
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_handle_final_alloc (UBYTE final_allocation)
{
  UBYTE  next;
  T_RLC_VALUES  rlc_val;
  USHORT rlc_data_size=0;

  TRACE_FUNCTION( "tm_handle_final_alloc" );

  switch(grlc_data->uplink_tbf.cs_type)
  {
    case CS_1:
      rlc_data_size = 20;
      break;
    case CS_2:
      rlc_data_size = 30;
      break;
    case CS_3:
      rlc_data_size = 36;
      break;
    case CS_4:
      rlc_data_size = 50;
      break;
    default:
      break;
  }
  if(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL AND
     grlc_data->prim_queue[grlc_data->prim_start_tbf].rlc_status EQ FALSE )
  {
    next = grlc_data->prim_queue[grlc_data->prim_start_tbf].next;
  }
  else
  {
    next = grlc_data->prim_start_tbf;
    TRACE_EVENT_P3("PST=%d PSF=%d PDU=%d: tm_handle_final_alloc"
                                                           ,grlc_data->prim_start_tbf
                                                           ,grlc_data->prim_start_free
                                                           ,grlc_data->grlc_data_req_cnt);

  }
  grlc_get_sdu_len_and_used_ts( &rlc_val);
  grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt = rlc_val.sdu_len;
  grlc_data->uplink_tbf.fa_manag.ul_res_used = rlc_val.cnt_ts;
  grlc_data->uplink_tbf.fa_manag.ul_res_remain =
       grlc_data->uplink_tbf.fa_manag.ul_res_sum -  grlc_data->uplink_tbf.fa_manag.ul_res_used;
  grlc_data->uplink_tbf.fa_manag.tbf_oct_cap_remain = grlc_data->uplink_tbf.fa_manag.ul_res_remain * rlc_data_size;

  if(final_allocation)
  {
    /*
     * last allocation of the tbf, it must end at the end of tbf.
     * check if more data is in prim queue than available uplink resources.
     * NO: nothing to do
     * YES: reorganize prim queue(set start_new_tbf) and inform RU
     */


    while((grlc_data->prim_queue[next].start_new_tbf EQ 0) AND
          (next NEQ 0xFF) )
    {
      if(grlc_data->uplink_tbf.fa_manag.tbf_oct_cap_remain <
        (grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt + grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8 + 1))
      {
        /*
         * find the end of the tbf.
         */
        grlc_data->prim_queue[next].start_new_tbf = 1;
        sig_tm_ru_queue_status();
        return;
      }
      grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt   += grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8;
      grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt++; /* for pdu boundaries */
      next                        = grlc_data->prim_queue[next].next;
    }
  }
  else
  {
    /*
     * not the last allocation
     */
    while((grlc_data->prim_queue[next].start_new_tbf EQ 0) AND
          (next NEQ 0xFF) )
    {
      grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt   += grlc_data->prim_queue[next].prim_ptr->sdu.l_buf/8;
      grlc_data->uplink_tbf.fa_manag.tbf_oct_cnt++; /* for pdu boundaries */
      next                        = grlc_data->prim_queue[next].next;
    }
  }


} /* tm_handle_final_alloc() */


/*
+------------------------------------------------------------------------------
| Function    : tm_set_fa_bitmap
+------------------------------------------------------------------------------
| Description : sets fixed allocation bitmap for requested allocation after
|               receiving a repeat allocation with ts_override
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL USHORT tm_set_fa_bitmap( UBYTE ts_mask, T_FA_ALLOC* ptr_alloc)
{
  UBYTE  i,j;
  USHORT  tx_slots;
  TRACE_FUNCTION( "tm_set_fa_bitmap" );

  if (ts_mask)
  {
    /*
     * add new time slots to current allocation
     */
    tx_slots = 0;
    for(i=0;i<grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_len;i++)
    {
      ptr_alloc->alloc.bitmap_array[i] = grlc_data->uplink_tbf.fa_manag.current_alloc.alloc.bitmap_array[i] | ts_mask;

      if(ptr_alloc->alloc.bitmap_array[i])
      {
        UBYTE mask = 0x80;

        for(j=0; j<=7; j++)
        {
          if(ptr_alloc->alloc.bitmap_array[i] & mask)
            tx_slots++;
          mask>>=1;
        }
      }


    }
  }
  else
  {
    /*
     * no new timeslot allocated
     */
    tx_slots = grlc_data->uplink_tbf.fa_manag.current_alloc.ul_res_sum;
  }
  return (tx_slots);

} /* tm_set_fa_bitmap() */

/*
+------------------------------------------------------------------------------
| Function    : tm_handle_test_mode_cnf
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_handle_test_mode_cnf ( BOOL v_test_mode_cnf )
{
  TRACE_FUNCTION( "tm_handle_test_mode_cnf" );

  if( v_test_mode_cnf EQ TRUE )
  {
    PALLOC( cgrlc_test_mode_cnf, CGRLC_TEST_MODE_CNF );

    grlc_data->testmode.mode = CGRLC_NO_TEST_MODE;

    PSEND( hCommGMM, cgrlc_test_mode_cnf );

    tm_delete_prim_queue();
    /*inform grr that testmode is finished*/
    {
      PALLOC(cgrlc_test_mode_ind,CGRLC_TEST_MODE_IND); /*T_CGRLC_TEST_MODE_IND*/
      cgrlc_test_mode_ind->test_mode_flag = CGRLC_NO_TEST_MODE;
      PSEND(hCommGRR,cgrlc_test_mode_ind);
    }

  }
} /* tm_handle_test_mode_cnf() */

/*
+------------------------------------------------------------------------------
| Function    : tm_prcs_pwr_ctrl
+------------------------------------------------------------------------------
| Description :
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_prcs_pwr_ctrl ( T_CGRLC_pwr_ctrl *pwr_ctrl )
{
  TRACE_FUNCTION( "tm_prcs_pwr_ctrl" );

  if( pwr_ctrl->v_pwr_ctrl_param )
  {
    tpc_set_pwr_ctrl_param( &pwr_ctrl->pwr_ctrl_param );
  }

  if( pwr_ctrl->v_glbl_pwr_ctrl_param )
  {
    tpc_set_glbl_pwr_ctrl_param( &pwr_ctrl->glbl_pwr_ctrl_param );
  }

  if( pwr_ctrl->v_freq_param )
  {
    grlc_data->tm.freq_param = pwr_ctrl->freq_param;
  }

  if( pwr_ctrl->v_c_value )
  {
    meas_grlc_c_set_c_value( &pwr_ctrl->c_value );
  }

  sig_tm_tpc_update_pch( );

  {
    PALLOC( pwr_ctrl_cnf, CGRLC_PWR_CTRL_CNF );
    PSEND( hCommGRR, pwr_ctrl_cnf );
  }
} /* tm_prcs_pwr_ctrl() */


#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
GLOBAL void tm_send_msg_directly_to_l1_queue (UBYTE * unencoded_msg)
{

  TRACE_FUNCTION( "tm_send_msg_directly_to_l1_queue" );

  /* Call function that formats ARAC message  */

  memset(&grlc_data->ru.ul_data[0],
      0,
      sizeof(T_ul_data));

  grlc_data->ru.ul_data[0].block_status = 2;
  grlc_encode_ul_ctrl_block(( UBYTE* ) grlc_data->ru.ul_data[0].ul_block,
  ( UBYTE* )unencoded_msg );

#ifdef _SIMULATION_
  {
    PALLOC(mac_data_req,MAC_DATA_REQ);
    memset(&(mac_data_req->ul_data),
          0,
          sizeof(T_ul_data));
    memcpy(&(mac_data_req->ul_data),
          &(grlc_data->ru.ul_data[0]),
          sizeof(T_ul_data));
    PSEND(hCommL1,mac_data_req);
  }
#else
  /* No need to copy again */
#endif   /* ! _SIMULATION_ */

  grlc_data->ru.ul_data[1].block_status = 0;
  return;

}


GLOBAL void tm_send_prr_2p_ptm ( void )
{
  T_U_GRLC_RESOURCE_REQ resource_req;

  TRACE_FUNCTION( "tm_send_prr_2p_ptm" );

  tm_build_res_req( &resource_req, R_BUILD_2PHASE_ACCESS);

  tm_send_msg_directly_to_l1_queue((UBYTE *)&resource_req);

  return;

}
#endif