view src/g23m-gprs/grlc/grlc_rds.c @ 75:8697f358f505

backlight rework: Condat light driver accepts levels The present change is another intermediate step on the path toward new FreeCalypso backlight handling. At this intermediate step the Condat light driver accepts 0-255 backlight levels driven by MFW, and puts them out on PWL on Luna development boards. At the same time on C139 it is now possible to turn on the display backlight with or without the keypad bl - the lsb of the 0-255 backlight level controls the keypad bl. MFW presently drives only 0 and 255 backlight levels, thus there is no visible behavioral change yet - but the plan for subsequent stages of this backlight rework is to add a dimmed backlight state (no keypad bl on C139) during active calls.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 24 Oct 2020 20:44:04 +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;
  }
}