view src/g23m-gprs/grlc/grlc_rds.c @ 274:fa22012c4a39

CST: remove AT%Nxxxx old AEC control This crude method of enabling and configuring AEC is not compatible with L1_NEW_AEC, and even for the old AEC it did not support every possible combination. It is time for this hack to go. The new and proper way of enabling and configuring AEC is via RiViera Audio Service audio mode facility, either audio mode files or full access write, most directly accessible via fc-tmsh auw 12 for free experimentation.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 29 Jul 2021 18:57:36 +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 signal handler functions for service
|             RD of entity GRLC.
+----------------------------------------------------------------------------- 
*/ 

#ifndef GRLC_RDS_C
#define GRLC_RDS_C
#endif

#define ENTITY_GRLC

/*==== INCLUDES =============================================================*/
#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"
#include "grlc.h"        /* to get the global entity definitions */
#include "grlc_rdf.h"
#include "grlc_tms.h"
#include "grlc_f.h"
#include "grlc_meass.h"

/*==== CONST ================================================================*/
const T_TIME T3192_Values[8] = {500, 1000, 1500, 1, 80, 120, 160, 200};

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

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

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



/*
+------------------------------------------------------------------------------
| Function    : sig_tm_rd_assign
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_TM_RD_ASSIGN
|
| Parameters  : dummy - description of parameter dummy
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_tm_rd_assign ( void ) 
{ 
  TRACE_ISIG( "sig_tm_rd_assign" );
  
  switch( GET_STATE( RD ) )
  {
    case RD_WAIT_FOR_STARTING_TIME_ACK:
    case RD_WAIT_FOR_STARTING_TIME_UACK:
      TRACE_EVENT_P3("DL reassignment during starting time :%ld: dl_tfi=%d, st_dl_tfi=%d"
                                                                ,grlc_data->dl_tbf_start_time
                                                                ,grlc_data->dl_tfi
                                                                ,grlc_data->start_fn_dl_tfi);


      /*lint -fallthrough*/

    case RD_NULL:            
      rd_tbf_init();
      if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK)
      {
        SET_STATE(RD,RD_WAIT_FOR_STARTING_TIME_ACK);
      }
      else
      {
        SET_STATE(RD,RD_WAIT_FOR_STARTING_TIME_UACK);
      }    
      grlc_data->dl_index = 1;
      grlc_data->tbf_ctrl[grlc_data->dl_index].tbf_type    = TBF_TYPE_DL;
      grlc_data->tbf_ctrl[grlc_data->dl_index].tfi         = grlc_data->dl_tfi;
      grlc_data->tbf_ctrl[grlc_data->dl_index].pdu_cnt     = 0;
      grlc_data->tbf_ctrl[grlc_data->dl_index].rlc_oct_cnt = 0;
      grlc_data->tbf_ctrl[grlc_data->dl_index].cnt_ts      = 0;
      grlc_data->tbf_ctrl[grlc_data->dl_index].ack_cnt     = 0;
      grlc_data->tbf_ctrl[grlc_data->dl_index].fbi         = 0;
      grlc_data->tbf_ctrl[grlc_data->dl_index].ret_bsn     = 0;

      grlc_data->rd.ack_ctrl.cnt_meas_rpt                 = ACK_CNT_MEAS_RPT_FIRST;
      grlc_data->rd.ack_ctrl.cnt_other                    = ACK_CNT_NORMAL;
      break;
    case RD_ACK:
    case RD_UACK:
      vsi_t_stop(GRLC_handle,T3190); 
      vsi_t_start(GRLC_handle,T3190,T3190_VALUE);
      grlc_data->rd.next_tbf_params   = grlc_data->downlink_tbf;
      grlc_data->rd.v_next_tbf_params = TRUE;
      TRACE_EVENT_P3("dl tbf reassignment with tfi %d, nts=%d tbf_st_time=%ld"
                                              ,grlc_data->dl_tfi
                                              ,grlc_data->downlink_tbf.nts
                                              ,grlc_data->dl_tbf_start_time);
      break;
    default:
      TRACE_ERROR( "SIG_TM_RD_ASSIGN unexpected" );
      {
        TRACE_EVENT_P2("DL ASS: state=%d  t3192=%d "
                                                                        ,grlc_data->rd.state
                                                                        ,grlc_data->downlink_tbf.t3192_val );
      }
      break;
  }
} /* sig_tm_rd_assign() */



/*
+------------------------------------------------------------------------------
| Function    : sig_tm_rd_abrel
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_TM_RD_ABREL
|
| Parameters  : dummy - description of parameter dummy
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_tm_rd_abrel ( ULONG fn, BOOL poll) 
{ 
  TRACE_ISIG( "sig_tm_rd_abrel" );
  
  switch( GET_STATE( RD ) )
  {
    case RD_ACK:
    case RD_REL_ACK:
    case RD_UACK:
    case RD_REL_UACK:
    case RD_NET_REL:    
    case RD_WAIT_FOR_STARTING_TIME_ACK:
    case RD_WAIT_FOR_STARTING_TIME_UACK:
      vsi_t_stop(GRLC_handle,T3190);
      vsi_t_stop(GRLC_handle,T3192);
	    
      rd_free_desc_list_partions();
      rd_free_database_partions();

      grlc_data->tbf_ctrl[grlc_data->dl_index].vs_vr  = grlc_data->rd.vr;
      grlc_data->tbf_ctrl[grlc_data->dl_index].va_vq  = grlc_data->rd.vq;
      grlc_trace_tbf_par ( grlc_data->dl_index );
       
      if(!poll)
      {
        /*
         * abnormal release: abort TBF
         */
        SET_STATE(RD,RD_NULL);          
      }
      else
      {
        SET_STATE(RD,RD_NET_REL);
        grlc_data->rd.fn_p_tbf_rel = fn;
        TRACE_EVENT_P2("p. tbf rel c_fn=%ld poll_fn=%d",fn,grlc_data->rd.fn_p_tbf_rel);
      }
      break;
    default:
      TRACE_ERROR( "SIG_TM_RD_ABREL unexpected" );
      break;
  }
} /* sig_tm_rd_abrel() */

/*
+------------------------------------------------------------------------------
| Function    : sig_tm_rd_ul_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_TM_RD_UL_REQ
|
| Parameters  : dummy - description of parameter dummy
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_tm_rd_ul_req ( void) 
{ 
  TRACE_ISIG( "sig_tm_rd_ul_req" );
  
  switch( GET_STATE( RD ) )
  {
    case RD_ACK:
    case RD_REL_ACK:
    case RD_UACK:
    case RD_REL_UACK:
    case RD_WAIT_FOR_STARTING_TIME_ACK:
    case RD_WAIT_FOR_STARTING_TIME_UACK:
      grlc_data->rd.channel_req = TRUE;      
      break;
    default:
      TRACE_ERROR( "SIG_TM_RD_UL_REQ unexpected" );
      break;
  }
} /* sig_tm_rd_ul_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_tm_rd_ul_req_stop
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_TM_RD_UL_REQ_STOP: No packet
|               channel description shall be sent in packet downlink ack/nack,
|               because a valid packet uplink assignment is received
|
| Parameters  : dummy - description of parameter dummy
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_tm_rd_ul_req_stop ( void) 
{ 
  TRACE_ISIG( "sig_tm_rd_ul_req_stop" );
  /*
   * do it in every state
   */  
  grlc_data->rd.channel_req = FALSE;

} /* sig_tm_rd_ul_req_stop() */

/*
+------------------------------------------------------------------------------
| Function    : sig_tm_rd_nor_rel
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_TM_RD_NOR_REL
|
| Parameters  : dummy - description of parameter dummy
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_tm_rd_nor_rel ( void) 
{ 
  TRACE_ISIG( "sig_tm_rd_nor_rel" );
  
  switch( GET_STATE( RD ) )
  {
    case RD_NULL:
    case RD_ACK:
    case RD_REL_ACK:
    case RD_UACK:
    case RD_REL_UACK:
    case RD_NET_REL:  
    case RD_WAIT_FOR_STARTING_TIME_ACK:
    case RD_WAIT_FOR_STARTING_TIME_UACK:
      SET_STATE(RD,RD_NULL);
      vsi_t_stop(GRLC_handle,T3190);
      vsi_t_stop(GRLC_handle,T3192);	  
      grlc_data->tbf_ctrl[grlc_data->dl_index].vs_vr  = grlc_data->rd.vr;
      grlc_data->tbf_ctrl[grlc_data->dl_index].va_vq  = grlc_data->rd.vq; 
      grlc_trace_tbf_par ( grlc_data->dl_index );
      break;
    default:
      TRACE_ERROR( "SIG_TM_RD_NOR_REL unexpected" );
      break;
  }
} /* sig_tm_rd_nor_rel() */





/*
+------------------------------------------------------------------------------
| Function    : sig_gff_rd_mac_ready_ind
+------------------------------------------------------------------------------
| Description : Handles the Signal sig_gff_rd_mac_ready_ind
|
| Parameters  : *mac_dl_ready_ind - Ptr to primitive MAC_READY_IND
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_gff_rd_mac_ready_ind ( T_MAC_READY_IND * mac_dl_ready_ind)
{
  UBYTE   *ptr_block=NULL;
  ULONG   delta_fn;
   
  TRACE_ISIG( "sig_gff_rd_mac_ready_ind" );


  grlc_data->tbf_ctrl[grlc_data->dl_index].end_fn = mac_dl_ready_ind->fn;  

  grlc_handle_poll_pos (mac_dl_ready_ind->fn);
  delta_fn = rd_calc_delta_fn(mac_dl_ready_ind->fn);

  switch( GET_STATE( RD ) )
  {
    case RD_WAIT_FOR_STARTING_TIME_ACK:
    case RD_WAIT_FOR_STARTING_TIME_UACK:       
      if(!grlc_check_if_tbf_start_is_elapsed ( grlc_data->dl_tbf_start_time, mac_dl_ready_ind->fn))
      {
        TRACE_EVENT_P2("WAIT FOR DL STARTING TIME, UL IS RUNNING st=%ld fn=%ld",grlc_data->dl_tbf_start_time
                                                                              ,mac_dl_ready_ind->fn);
        grlc_send_rem_poll_pos (mac_dl_ready_ind->fn);
        return;
      }
      if(grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_ACK)
      {
        SET_STATE(RD,RD_ACK);
      }
      else
      {
        SET_STATE(RD,RD_UACK);
      } 
      grlc_data->tbf_ctrl[grlc_data->dl_index].start_fn    = mac_dl_ready_ind->fn;
      
      TRACE_EVENT_P6("DL first call at fn = %ld (%ld) with tfi=%d, dl_mask=%x tbf_st_time=%ld ta=%d",
                                        mac_dl_ready_ind->fn,
                                        mac_dl_ready_ind->fn%42432,
                                        grlc_data->dl_tfi,
                                        grlc_data->dl_tn_mask,
                                        grlc_data->dl_tbf_start_time,
                                        grlc_data->ta_value);
      rd_cgrlc_st_time_ind();
      vsi_t_start(GRLC_handle,T3190,T3190_VALUE);

      /*lint -fallthrough*/

    case RD_ACK:
    case RD_REL_ACK:
    case RD_UACK:
    case RD_REL_UACK:
      if(grlc_data->rd.v_next_tbf_params AND
          grlc_check_if_tbf_start_is_elapsed ( grlc_data->dl_tbf_start_time, mac_dl_ready_ind->fn))
      {
        grlc_data->rd.v_next_tbf_params = FALSE;
        rd_cgrlc_st_time_ind();
        vsi_t_start(GRLC_handle,T3190,T3190_VALUE);
      }
      if(grlc_data->rd.ch_req_in_ack_prog AND mac_dl_ready_ind->last_poll_resp)
      {
        grlc_data->rd.channel_req = TRUE;
      }
      else if(grlc_data->rd.ch_req_in_ack_prog)
      {
        sig_rd_tm_ul_req_cnf();
        grlc_data->rd.ch_req_in_ack_prog = FALSE;
      }

      
      if(grlc_data->rd.release_tbf)  
      {
        /*
         * Packet downlink ack/nack with final ack bit set to 1 was programmed
         */
        grlc_data->rd.release_tbf = FALSE;
        if(mac_dl_ready_ind->last_poll_resp EQ 0)
        {
          /*
           * Transmission from L1 confirmed
           */
          grlc_data->rd.cnt_sent_f_ack++;
        }

      }

       
      if( grlc_data->rd.f_ack_ind AND
          (grlc_data->rd.fn_p_tbf_rel NEQ 0xFFFFFFFF)  AND
          grlc_check_if_tbf_start_is_elapsed ( grlc_data->rd.fn_p_tbf_rel, mac_dl_ready_ind->fn))
      {
        /*
         * no addtional final downlink ack with fbi requested by the network
         * T3192 can be started
         */

        vsi_t_stop(GRLC_handle,T3190);

        if(grlc_data->rd.cnt_sent_f_ack)
        { 
          /*
           * it is only a retransmission of the final dl ack. 
           * Therefore t3192 is restarted, no offset is needed
           */
          vsi_t_start(GRLC_handle,T3192, T3192_Values[grlc_data->downlink_tbf.t3192_val]); 
          TRACE_EVENT_P3("T3192 started:  rel_fn=%ld fn=%ld T3192=%d",grlc_data->rd.fn_p_tbf_rel,mac_dl_ready_ind->fn,grlc_data->downlink_tbf.t3192_val);
        }
        else
        {
          /*
           * the first final dl ack is not retransmitted, therefore retransmission is required.
           * start t3190 and wait for new poll position
           */ 
          vsi_t_start(GRLC_handle,T3190,T3190_VALUE);
          TRACE_EVENT_P1("NO DL REL: ret needed T3190 is running %d",grlc_data->rd.cnt_sent_f_ack);
        }  
        grlc_data->rd.fn_p_tbf_rel = 0xFFFFFFFF;
      }


      if( (delta_fn EQ 4) 
           OR 
          (delta_fn EQ 5))                   
      {
        UBYTE  i=0;
        UBYTE  index;
        while(grlc_data->next_poll_array[grlc_data->poll_start_tbf].cnt 
              AND 
              (i<8))
        {
          if(grlc_data->next_poll_array[grlc_data->poll_start_tbf].poll_type[i] EQ CGRLC_POLL_DATA)
          {
           /* 
            * poll positon in next frame present, 
            * counter for for poll postions in one frame 
            */
            if( grlc_data->rd.channel_req                                OR /* uplink request */
                grlc_data->rd.next_poll_block EQ NEXT_POLL_BLOCK_DL_DATA OR /* last poll block was not ack nack */
                grlc_data->rd.f_ack_ind                                  OR /* final ack indicator */
                !tm_is_ctrl_blk_rdy
                   ( grlc_data->rd.ack_ctrl.cnt_meas_rpt, 
                     grlc_data->rd.ack_ctrl.cnt_other     ) )               /* no ctrl message */
            { 
              if ( !((grlc_data->rd.rlc_mode EQ CGRLC_RLC_MODE_UACK) AND grlc_data->rd.f_ack_ind) )
              {
                /* 
                 * sent downlink ack/nack 
                 */
                 ptr_block = rd_set_acknack();
                 sig_rd_meas_qual_rpt_sent( );
                 grlc_data->tbf_ctrl[grlc_data->dl_index].ack_cnt++;

                 if( grlc_data->rd.ack_ctrl.cnt_meas_rpt > 0 )
                   grlc_data->rd.ack_ctrl.cnt_meas_rpt--;
                 
                 if( grlc_data->rd.ack_ctrl.cnt_other > 0 )
                   grlc_data->rd.ack_ctrl.cnt_other--;

                 grlc_send_normal_burst(ptr_block, NULL, i);
              }
              else
              {
                /*
                 * unacknowledged mode, send packet control acknowledgment
                 */
                if(grlc_data->burst_type EQ CGRLC_BURST_TYPE_NB)
                {
                   ptr_block = grlc_set_packet_ctrl_ack();
                   grlc_send_normal_burst(ptr_block, NULL, i);
                }
                else
                {
                   /* send access burst. */
                   grlc_send_access_burst(i);
                }
              }
              grlc_data->rd.next_poll_block = NEXT_POLL_BLOCK_CTRL;
              if(grlc_data->rd.f_ack_ind)
              {
                grlc_data->rd.release_tbf = TRUE;
              }
            }
            else
            { 
              /* 
               * sent control block 
               */
              ptr_block = tm_get_ctrl_blk( &index, TRUE );
              grlc_send_normal_burst(NULL, ptr_block, i);
              grlc_data->rd.next_poll_block = NEXT_POLL_BLOCK_DL_DATA;
              
              if( grlc_data->rd.ack_ctrl.cnt_meas_rpt EQ 0 )
                grlc_data->rd.ack_ctrl.cnt_meas_rpt = ACK_CNT_NORMAL;
                 
              if( grlc_data->rd.ack_ctrl.cnt_other EQ 0 )
                grlc_data->rd.ack_ctrl.cnt_other = ACK_CNT_NORMAL;
            }
          }
          i++;
        }
      }
      grlc_send_rem_poll_pos(mac_dl_ready_ind->fn);
      break;
    case RD_NET_REL:       
      /* 
       * send packet control acknowledgement and abort TBF
       */
      grlc_send_rem_poll_pos(mac_dl_ready_ind->fn);
      if(grlc_data->rd.release_tbf)
      {
        SET_STATE(RD,RD_NULL);
        grlc_data->rd.release_tbf = FALSE;                
        TRACE_EVENT_P2("poll sent after packet tbf release(DL): current_fn=%ld rel_fn=%ld",
                                        mac_dl_ready_ind->fn,
                                        grlc_data->rd.fn_p_tbf_rel);
        sig_rd_tm_end_of_tbf(FALSE);
      }
      if(grlc_check_if_tbf_start_is_elapsed ( grlc_data->rd.fn_p_tbf_rel, mac_dl_ready_ind->fn))
      {
        grlc_data->rd.release_tbf = TRUE;
        TRACE_EVENT_P2("wait for poll confirm after packet tbf release(DL) current_fn=%ld rel_fn=%ld",
                                        mac_dl_ready_ind->fn,
                                        grlc_data->rd.fn_p_tbf_rel);
      }
	  break;
    default:
      TRACE_ERROR( "SIG_GFF_RD_MAC_READY_IND unexpected" );
      break;
  }
} /* sig_gff_rd_mac_ready_ind() */




/*
+------------------------------------------------------------------------------
| Function    : sig_gff_rd_data
+------------------------------------------------------------------------------
| Description : Handles the SIGNAL sig_gff_rd_data
|
| Parameters  : fn - current frame number
|               tn - current timeslot number
|               block_status - current block_status
|               sp           - sp bit of mac header.
|               bsn          - bsn number
|               fbi          - fbi bit
|               e_bit        - e bit
|               ptr_dl_block - pointer to the dl data block
+------------------------------------------------------------------------------
*/
GLOBAL void sig_gff_rd_data (ULONG fn, UBYTE tn, USHORT block_status,UBYTE rrbp,UBYTE sp,UBYTE bsn,UBYTE fbi,UBYTE e_bit, UBYTE * ptr_dl_block) 
{
  UBYTE bsn_l;
  UBYTE diff;
  BOOL  InRange;
  BOOL  li_correct;
  T_CODING_SCHEME old_cs_type;


  TRACE_FUNCTION( "sig_gff_rd_data" );

  
  grlc_data->tbf_ctrl[grlc_data->dl_index].cnt_ts++;


  /*
   * TESTMODE B
   */
  if (grlc_data->testmode.mode EQ CGRLC_LOOP)
  {
   /* 
    * If the downlink TBF is established on more than one timeslot, the MS shall transmit in 
    * the second uplink timeslot (if present) RLC/MAC blocks received on the second downlink 
    * timeslot, and shall transmit in the third uplink timeslot (if present) RLC/MAC blocks 
    * received in the third downlink timeslot and so on.
    */
    if (grlc_data->downlink_tbf.nts > 1)
    {
      if (tn - grlc_data->testmode.dl_ts_offset)
      {
        grlc_data->testmode.rec_data[1].block_status = block_status;
        grlc_data->testmode.rec_data[1].e_bit        = e_bit;
        memcpy(grlc_data->testmode.rec_data[1].payload,ptr_dl_block,50);
      }
      else
      {
        grlc_data->testmode.rec_data[0].block_status = block_status;
        grlc_data->testmode.rec_data[0].e_bit        = e_bit;
        memcpy(grlc_data->testmode.rec_data[0].payload,ptr_dl_block,50);
      }
    }
    else
    {
      grlc_data->testmode.rec_data[0].block_status = block_status;
      grlc_data->testmode.rec_data[0].e_bit        = e_bit;
      memcpy(grlc_data->testmode.rec_data[0].payload,ptr_dl_block,50);
    }

    grlc_data->rd.f_ack_ind = rd_check_fbi(fbi,sp,fn,rrbp);

    vsi_t_stop(GRLC_handle,T3190);
    vsi_t_start(GRLC_handle,T3190,T3190_VALUE);

    TRACE_EVENT_P6("DL DATA in testmode B at fn=%ld: bsn =%d, bs=%d,e_bit=%d, fbi=%d sp=%d "
                            ,fn
                            ,bsn
                            ,block_status
                            ,grlc_data->testmode.rec_data[0].e_bit
                            ,fbi
                            ,sp);
    return;
  }




/******************************************************************************************/
#if defined (_SIMULATION_)
  TRACE_EVENT_P1("DL DATA bsn= %d",bsn);
#endif /* defined (_SIMULATION_) */


  if(grlc_data->rd.vq NEQ grlc_data->rd.vr)
  {
    TRACE_EVENT_P5("wait for neg acked blocks :bsn=%d  vr=%d vq=%d  fbi=%d fn=%ld",
                                                            bsn,
                                                            grlc_data->rd.vr,
                                                            grlc_data->rd.vq,
                                                            fbi,
                                                            fn);
  }
/******************************************************************************************/
  old_cs_type = grlc_data->rd.cs_type;
  switch( GET_STATE( RD ) )
  {    
    case RD_WAIT_FOR_STARTING_TIME_ACK:
      SET_STATE(RD,RD_ACK);    

      /*lint -fallthrough*/

    case RD_ACK     :
      vsi_t_stop(GRLC_handle,T3190); 
      vsi_t_start(GRLC_handle,T3190,T3190_VALUE);
      bsn_l   = bsn;
      InRange = rd_check_window_size(bsn_l);


      if( !InRange  OR (grlc_data->rd.vn[bsn_l & WIN_MOD] EQ VN_RECEIVED))
      {
        grlc_data->tbf_ctrl[grlc_data->dl_index].ret_bsn++;
        
        if( fbi                      AND 
            !grlc_data->rd.f_ack_ind AND
           ((bsn_l+1) & 0x7F) EQ grlc_data->rd.vr)
        { /* WORKAROUND FOR NORTEL, fbi bit is modified , only possible for last bsn*/ 
          
          grlc_data->rd.f_ack_ind=rd_check_fbi(fbi,sp,fn,rrbp);

          TRACE_EVENT_P8("fbi modification in ret bsn=%d,vr=%d,vq=%d,sp=%d,fbi=%d,e=%d ptr[0]=%x,ptr[1]=%x",
                                                                    bsn_l,
                                                                    grlc_data->rd.vr,
                                                                    grlc_data->rd.vq,
                                                                    sp,
                                                                    fbi,
                                                                    e_bit,
                                                                    ptr_dl_block[0],
                                                                    ptr_dl_block[1]);

        }
        
        return;
      }
      grlc_data->rd.rlc_data_len = rd_calc_rlc_data_len(block_status);
      li_correct                = rd_read_li_m_of_block(ptr_dl_block,
                                                        e_bit);
      if((old_cs_type NEQ grlc_data->rd.cs_type) AND
         (old_cs_type NEQ CS_ZERO))
      {
        TRACE_EVENT_P3("DL CS TYPE CHANGED from %d to %d, bsn=%d",old_cs_type,grlc_data->rd.cs_type,bsn_l);
      }
      
      if(!li_correct)
      {
        grlc_data->rd.vn[bsn_l & WIN_MOD] = VN_INVALID;
        TRACE_ERROR( "LI field is longer than RLC data block" );
        return;
      }
     
      /* 
       * compute receive parameter
       */
      rd_comp_rec_par(bsn_l); 

      rd_save_block( bsn_l, &(ptr_dl_block[grlc_data->rd.li_cnt]),
                              fbi );

#if defined (_SIMULATION_)
  TRACE_EVENT_P1("first_ptr= %ld",grlc_data->rd.data_array[bsn_l & WIN_MOD].first);
#endif /* defined (_SIMULATION_) */

      diff = (grlc_data->rd.vq - bsn_l) & 0x7F;
      while( ( diff <= WIN_SIZE)          AND
             (grlc_data->rd.vq NEQ bsn_l) AND 
             (grlc_data->rd.vn[bsn_l & WIN_MOD] EQ VN_RECEIVED )  )
      {
        rd_send_grlc_data_ind(bsn_l);		
        bsn_l = (bsn_l+1)  & 0x7F;
        diff  = (grlc_data->rd.vq - bsn_l) & 0x7F;
      }       
      
      grlc_data->rd.f_ack_ind = rd_check_fbi(fbi,sp,fn,rrbp);
      
      break;
    case RD_REL_ACK :    
      /*
       * all blocks are received, after sending p. dl ack nack timer t3192 will be restarted
       */
      grlc_data->tbf_ctrl[grlc_data->dl_index].ret_bsn++;

      if(grlc_data->rd.f_ack_ind AND sp)
      { /* 
         * will be restarted at sending the dl ack nack: secure, in case of gaps.
         * The value could be zero, therfore a offset is needed
         */ 
        vsi_t_stop(GRLC_handle,T3192); 
        grlc_data->rd.fn_p_tbf_rel = grlc_decode_tbf_start_rel(fn,(USHORT)(rrbp+3));
        TRACE_EVENT_P3("FINAL DL ACK RETR REQIURED t3192=%d rel_fn=%ld c_fn=%ld ",grlc_data->downlink_tbf.t3192_val,grlc_data->rd.fn_p_tbf_rel,fn);
      }
 /*     TRACE_EVENT_P7("BLOCK DISCARDED WAIT FOR TBF RELEASE f_ack=%d bsn=%d sp=%d rrbp=%d vr=%d vq=%d t3192=%d"
                                                               ,grlc_data->rd.f_ack_ind
                                                               ,bsn
                                                               ,sp
                                                               ,rrbp
                                                               ,grlc_data->rd.vr
                                                               ,grlc_data->rd.vq
                                                               ,grlc_data->downlink_tbf.t3192_val);
  */
      break;    
    case RD_WAIT_FOR_STARTING_TIME_UACK:
      SET_STATE(RD,RD_UACK);

      /*lint -fallthrough*/

    case RD_UACK:
      /*
       * After receiving each block the timer T3190 should be restarted. 
       */
      vsi_t_stop(GRLC_handle,T3190); 
      vsi_t_start(GRLC_handle,T3190,T3190_VALUE);

      if(!rd_check_window_size(bsn))
      {
        TRACE_EVENT_P3("UACK bsn outside window: bsn=%d vr=%d vq=%d",bsn,grlc_data->rd.vr,grlc_data->rd.vq);
        return;
      }
      
      grlc_data->rd.rlc_data_len  = rd_calc_rlc_data_len(block_status);
      li_correct                 = rd_read_li_m_of_block(ptr_dl_block, e_bit);
      if(!li_correct)
      {
        TRACE_ERROR( "LI field is longer than RLC data block" );
        return;
      }
     
      /* 
       * compute receive parameter 
       */
      rd_comp_rec_par(bsn); 
      rd_save_block( bsn, &(ptr_dl_block[grlc_data->rd.li_cnt]), fbi );
      if(!grlc_data->rd.inSequence)
        rd_fill_blocks(bsn);

      rd_send_grlc_data_ind(bsn);
      
      grlc_data->rd.f_ack_ind = rd_check_fbi(fbi,sp,fn,rrbp);

      break;
    case RD_REL_UACK:

      if(fbi AND sp)
      {
        vsi_t_stop(GRLC_handle,T3192); 
        grlc_data->rd.fn_p_tbf_rel = grlc_decode_tbf_start_rel(fn,(USHORT)(rrbp+3));
        TRACE_EVENT_P4("data in REL_UACK restart t3192:  bsn=%d   t3192=%d fn=%ld rel_fn=%ld"
                                                               ,bsn
                                                               ,grlc_data->downlink_tbf.t3192_val
                                                               ,fn
                                                               ,grlc_data->rd.fn_p_tbf_rel);

      }
      break;
    default:
      TRACE_ERROR( "SIG_GFF_RD_DATA unexpected" );
      break;
  }

} /* sig_gff_rd_data() */

/*
+------------------------------------------------------------------------------
| Function    : sig_ru_rd_get_downlink_release_state
+------------------------------------------------------------------------------
| Description : This function returns true if RD is in release state( if
|               fbi=1 is received in dowonlink data block. 
|
| Parameters  : release_state 
+------------------------------------------------------------------------------
*/
GLOBAL void sig_ru_rd_get_downlink_release_state( BOOL *release_started)
{
  *release_started = FALSE ;

  if( (GET_STATE( RD ) EQ RD_REL_ACK ) OR
      (GET_STATE( RD ) EQ RD_REL_UACK ) )
  {
     *release_started = TRUE;
  }
  else if(GET_STATE( RD ) EQ RD_NULL )
  {
     TRACE_ERROR("ERROR:sig_ru_rd_get_downlink_release_state called in RD NULL state");
     *release_started = TRUE;
  }
}