view src/g23m-fad/ra/ra_tra.c @ 683:81394dcdf4d3

uartfax.c: OM-style wakeup interrupt implemented for Tango
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 26 Jun 2020 03:06:16 +0000
parents 90eb61ecd093
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GSM-F&D (8411)
|  Modul   :  RA_TRA
+-----------------------------------------------------------------------------
|  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 Modul defines the functions for the transparent data model
|             for the component RA of the mobile station
+-----------------------------------------------------------------------------
*/

#ifndef RA_TRA_C
#define RA_TRA_C
#endif

#define ENTITY_RA

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

#include "typedefs.h"
#include "vsi.h"
#include "macdef.h"
#include "pconst.cdg"
#include "custom.h"
#include "gsm.h"
#include "cnf_ra.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "ccdapi.h"
#include "ra.h"

/*==== CONST ======================================================*/
/*==== TYPES ======================================================*/
/*==== VARIABLES ==================================================*/
/*==== FUNCTIONS ==================================================*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_init                 |
+--------------------------------------------------------------------+

  PURPOSE : initialize the transparent mode data
*/

GLOBAL void tra_init (UBYTE tra_rate)
{
  T_TRA *dtra = ra_data->tra;

  TRACE_FUNCTION("tra_init()");

  dtra->ul_data_pending    = FALSE;
  dtra->ul_signals_pending = FALSE;
  dtra->ul_break_pending   = FALSE;

  dtra->break_pos = 0;
  dtra->break_len = 0;
  dtra->overspeed = 0;
  dtra->ul_status = 0;
  dtra->ul_sa     = 0;
  dtra->ul_sb     = 0;
  dtra->ul_x      = 0;

  dtra->dl_sa.pos   = ST_SA;  /* DSR */
  dtra->dl_sa.last  = 0xFF;
  dtra->dl_sa.timer = 0L;

#ifdef _SIMULATION_  /* according to GSM-TS07.01 */

  dtra->dl_sa.delay_OFF_ON = 0L;
  dtra->dl_sa.delay_ON_OFF = 0L;

#else /* to avoid spurious data at the beginning of the call */

  dtra->dl_sa.delay_OFF_ON = 5000L;
  dtra->dl_sa.delay_ON_OFF = 1000L;

#endif

  dtra->dl_sb.pos          = ST_SB;  /* DCD */
  dtra->dl_sb.last         = 0xFF;
  dtra->dl_sb.timer        = 0L;
  dtra->dl_sb.delay_OFF_ON =  200L;
  dtra->dl_sb.delay_ON_OFF = 5000L;

  dtra->dl_x.pos           = ST_X;   /* CTS */
  dtra->dl_x.last          = 0xFF;
  dtra->dl_x.timer         = 0L;
  dtra->dl_x.delay_OFF_ON  = 1000L;
  dtra->dl_x.delay_ON_OFF  = 1000L;

  ra_data->ra_data_ind.status = ST_SA + ST_SB + ST_X;

  ra_data->ra_data_ind.fr_type    = FR_TRANS;
  ra_data->ra_data_ind.sdu.o_buf  = 0;
  ra_data->ra_data_ind.sdu.l_buf  = 0;

  ra_data->ra_ready_ind[0].req_frames = 0; /* used, if not all data sent yet */
  dtra->ready_ind_idx = 1;

  switch (tra_rate)
  {
  case TRA_FULLRATE_14400:
    ra_data->ra_ready_ind[1].req_frames = RAU_DATA_14400;
    break;
  case TRA_FULLRATE_4800:
    ra_data->ra_ready_ind[1].req_frames = RAU_DATA_4800;
    break;
  case TRA_HALFRATE_4800:
  case TRA_FULLRATE_2400:
    ra_data->ra_ready_ind[1].req_frames = RAU_DATA_2400;
    break;
  case TRA_HALFRATE_2400:
    ra_data->ra_ready_ind[1].req_frames = RAU_DATA_1200;
    break;
  default:
    ra_data->ra_ready_ind[1].req_frames = RAU_DATA_9600;
    break;
  }

  cl_set_frame_desc_0(&dtra->ul_frame_desc, NULL, 0);

  hCommMMI = vsi_c_open ( VSI_CALLER ACI_NAME );
  hCommTRA = vsi_c_open ( VSI_CALLER TRA_NAME );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_idle                 |
+--------------------------------------------------------------------+

  PURPOSE : IDLE processing fpr uplink and downlink transparent mode


*/

GLOBAL void tra_idle(void)
{
  TRACE_FUNCTION("tra_idle()");
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_ul_null              |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void tra_ul_null(void)
{
  TRACE_FUNCTION("tra_ul_null()");

  if (ra_data->activated)
  {
    /*
     * setup the communication parameters
     */
    shm_set_dsp_value (conf_b_itc, V_ITC_DATA);
    shm_set_dsp_value (test_b_t_dl_debug, 0);

    switch (ra_data->nsb)
    {
      case 1:
        shm_set_dsp_value (conf_b_nsb, V_NSB_ONE_STOP);
        break;

      case 2:
        shm_set_dsp_value (conf_b_nsb, V_NSB_TWO_STOP);
        break;

      default:
        break;
    }

    switch (ra_data->ndb)
    {
      case 7:
        shm_set_dsp_value (conf_b_ndb, V_NDMSK_B_7_DBITS);
        break;

      case 8:
        shm_set_dsp_value (conf_b_ndb, V_NDMSK_B_8_DBITS);
        break;

      default:
        break;
    }

    switch (ra_data->user_rate)
    {
      case URA_300:
        shm_set_dsp_value (conf_b_ur, V_UR_300);
        break;

      case URA_1200:
        shm_set_dsp_value (conf_b_ur, V_UR_1200);
        break;

      case URA_2400:
        shm_set_dsp_value (conf_b_ur, V_UR_2400);
        break;

      case URA_4800:
        shm_set_dsp_value (conf_b_ur, V_UR_4800);
        break;

      case URA_9600:
        /* hack for 14400: */
        if (ra_data->tra_rate EQ TRA_FULLRATE_14400)
        {
          shm_set_dsp_value (conf_b_ur, V_UR_14400);
        }
        else
        {
          shm_set_dsp_value (conf_b_ur, V_UR_9600);
        }
        break;

      case URA_1200_75:
        shm_set_dsp_value (conf_b_ur, V_UR_1200_75);
        break;

      case URA_14400:
        shm_set_dsp_value (conf_b_ur, V_UR_14400);
        break;

      default:
        break;
    }

    shm_set_dsp_value (conf_b_ce, V_CE_TRANSP);

    switch (ra_data->tra_rate)
    {
      case TRA_FULLRATE_14400:
      case TRA_FULLRATE_9600:
      case TRA_FULLRATE_4800:
      case TRA_FULLRATE_2400:
        shm_set_dsp_value (conf_b_ct, V_CT_FR);
        ra_data->cycle_time = 20;
        break;

      case TRA_HALFRATE_4800:
      case TRA_HALFRATE_2400:
        shm_set_dsp_value (conf_b_ct, V_CT_HR);
        ra_data->cycle_time = 40;
        break;

      default:
        break;
    }

    /*
     * set uplink buffer empty to empty values and no break
     */
    shm_set_dsp_value (rau_byte_cnt,  2);
    shm_set_dsp_value (rau_break_len, 0);
    shm_set_dsp_value (rau_break_pos, 0);

    /*
     * start initialisation process in F&D L1
     */
    shm_set_dsp_value (act_b_init,   1);
    shm_set_dsp_value (act_b_syncul, 1);
    shm_set_dsp_value (act_b_syncdl, 1);

    INIT_STATE (KER, TRA_INIT_L1);

#ifdef HO_WORKAROUND /* tra_ul_null */
    _act_d_ra_conf = *ra_data->shm.shm_addr[d_ra_conf];
    TRACE_EVENT("d_ra_conf saved");
#endif

  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_ul_init_l1           |
+--------------------------------------------------------------------+

  PURPOSE :


*/

GLOBAL void tra_ul_init_l1(void)
{
  TRACE_FUNCTION("tra_ul_init_l1()");

  if (shm_get_dsp_value (act_b_init) EQ 0)
  {
    /*
     * L1 F&D initialzed
     * start ul/dl synchronisation
     */

    SET_STATE (KER, TRA_SYNCH_TCH_START);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_sync_tch_start    |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void tra_dl_sync_tch_start(void)
{
  TRACE_FUNCTION("tra_dl_sync_tch_start()");

  if (shm_get_dsp_value (statd_b_syncdet) EQ 1)
  {
    /*
     * Start a pseudo timer with 500 ms.
     * The value is decremented by cycle_time
     * each time the L1 calls the dll_data_ul function.
     */
    TRACE_EVENT("SYNC_TIMER: start");
    ra_data->sync_timer = 500L;
    shm_set_dsp_value (rad_byte_cnt,  2);
    SET_STATE (KER, TRA_SYNCH_TCH_FOUND);
  }
}

LOCAL void set_ul_status(T_TRA *tra)
{
shm_set_dsp_value (statu_b_sa, tra->ul_sa);
shm_set_dsp_value (statu_b_sb, tra->ul_sb);
shm_set_dsp_value (statu_b_x,  tra->ul_x);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_ul_sync_tch_found    |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void tra_ul_sync_tch_found(void)
{
  TRACE_FUNCTION("tra_ul_sync_tch_found()");

  if (TimeOut(&ra_data->sync_timer) NEQ TRUE)
    return;

  /*
   * timeout of the sync timer - reset the sync-detection flags
   */
  TRACE_EVENT("SYNC_TIMER: time out");

  shm_set_dsp_value (act_b_syncul,  0);
  shm_set_dsp_value (act_b_syncdl,  0);

  if (ra_data->tra_rate NEQ TRA_FULLRATE_14400)
  {
    ra_data->sync_timer = 10000L;         /* 10 secs timeout */
    SET_STATE (KER, TRA_WAIT_SYNC_LOST);
  }
  else
  {
    SET_STATE (KER, TRA_DATA_TRANS_PRE1);

#ifdef HO_WORKAROUND /* tra_ul_sync_tch_found */
  if (*ra_data->shm.shm_addr[d_ra_conf] NEQ _act_d_ra_conf)
  {
    *ra_data->shm.shm_addr[d_ra_conf] = _act_d_ra_conf; /* tra_dl_data_trans */
    TRACE_EVENT("HO_REFRESH tra_ul_sync_tch_found");
  }
#endif

  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_wait_sync_lost    |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void tra_dl_wait_sync_lost(void)
{
  BOOL timeout;

  TRACE_FUNCTION("tra_dl_wait_sync_lost()");

  timeout = TimeOut(&ra_data->sync_timer);

  if (timeout EQ TRUE)
  {
    TRACE_EVENT("SYNC_TIMER: statd_b_syncdet remains HIGH");
  }

  if (shm_get_dsp_value (statd_b_syncdet) EQ 0 OR timeout EQ TRUE)
  {
    /*
     * sync detection finished -> enter the data transmission state
     * send ra_activate_cnf -> ACI
     */
    SET_STATE (KER, TRA_DATA_TRANS_PRE1);
    set_ul_status(ra_data->tra);

#ifdef HO_WORKAROUND /* tra_dl_wait_sync_lost */
  if (*ra_data->shm.shm_addr[d_ra_conf] NEQ _act_d_ra_conf)
  {
    *ra_data->shm.shm_addr[d_ra_conf] = _act_d_ra_conf; /* tra_dl_data_trans */
    TRACE_EVENT("HO_REFRESH tra_dl_wait_sync_lost");
  }
#endif

  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_ul_data_trans        |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void tra_ul_data_trans(void)
{
  T_TRA *dtra = ra_data->tra;

  TRACE_FUNCTION("tra_ul_data_trans()");

  if (dtra->ul_signals_pending)
  {
    /*
     * handle sa, sb, x signals
     */
    set_ul_status(dtra);

    shm_set_dsp_value (act_b_ovspul, dtra->overspeed);
  }

  if (dtra->ul_data_pending)
  {
    USHORT offs, new_offs;

    offs = shm_get_dsp_value (rau_byte_cnt);

    if (offs > 0)
    {
      offs -= 2;

      if (dtra->ul_break_pending)
      {
        shm_set_dsp_value (rau_break_pos, dtra->break_pos);
        shm_set_dsp_value (rau_break_len, dtra->break_len);
      }
      else
      {
        shm_set_dsp_value (rau_break_pos, 0);
        shm_set_dsp_value (rau_break_len, 0);
      }

      new_offs = shm_set_dsp_buffer(&dtra->ul_frame_desc,
                                     ra_data->shm.shm_addr[adr_rau_data]+wof_rau_data,
                                     offs,
                                     (USHORT)(ra_data->ra_ready_ind[1].req_frames - offs));
      if (new_offs NEQ offs)
      {
        shm_set_dsp_value (rau_byte_cnt, (USHORT)(new_offs+2));
      }

      if (dtra->ul_frame_desc.Len[0] EQ 0)
      {
        dtra->ul_data_pending = FALSE;
        dtra->ready_ind_idx = 1;
      }
      else
      {
        dtra->ul_frame_desc.Adr[0] += (new_offs-offs);
      }
    }
  }
  if (!dtra->ul_data_pending OR dtra->ul_signals_pending)
  {
    if (dtra->ul_signals_pending AND !dtra->ul_data_pending)
    {
      dtra->ready_ind_idx = 1;
    }
    if (dtra->data_req_rec) /* send only if RA_DATA_REQ received */
    {
      l1i_ra_ready_ind(hCommTRA, dtra->ready_ind_idx);
      dtra->data_req_rec = FALSE;
      dtra->ready_ind_idx = 0;
      dtra->ul_signals_pending = FALSE;
    }
  }
}

LOCAL UBYTE check_status_bit(T_STATUS_BIT *status)
{
  if (status->last NEQ status->current)
  {
    status->last = status->current;

    if (status->current) /* current status bit is OFF */
    {
      if (status->delay_ON_OFF)
      {
        status->timer = status->delay_ON_OFF; /* start ON to OFF timer */
        return 2+1;
      }
      else
      {
        ra_data->ra_data_ind.status |= status->pos; /* status bit OFF */
        return 4+1;
      }
    }
    else /* current status bit is ON */
    {
      if (status->delay_OFF_ON)
      {
        status->timer = status->delay_OFF_ON; /* start OFF to ON timer */
        return 2+0;
      }
      else
      {
        ra_data->ra_data_ind.status &= ~status->pos; /* status bit ON */
        return 4+0;
      }
    }
  }
  else /* status->last EQ status->current */
  {
    if (TimeOut(&status->timer) EQ TRUE)
    {
      if (status->current) /* current status bit is OFF */
      {
        ra_data->ra_data_ind.status |= status->pos; /* filtered status bit OFF */
        return 4+1;
      }
      else
      {
        ra_data->ra_data_ind.status &= ~status->pos; /* filtered status bit ON */
        return 4+0;
      }
    }
  }
  return 0;
}

LOCAL BOOL get_dl_status_bits(void)
{
  T_TRA *dtra = ra_data->tra;
  BOOL dl_status_changed = FALSE;
  UBYTE ret;

  /*** status bit SA ***/

  dtra->dl_sa.current = (UBYTE)shm_get_dsp_value(statd_b_sa);
  ret = check_status_bit(&dtra->dl_sa);
  if (ret > 3)
    dl_status_changed = TRUE;

#ifdef TRACE_RA_TRA_STATUS
  switch (ret)
  {
  case 2: TRACE_EVENT("SA bit timer started 1 -> 0"); break;
  case 3: TRACE_EVENT("SA bit timer started 0 -> 1"); break;
  case 4: TRACE_EVENT("CT107-DSR=ON"); break;
  case 5: TRACE_EVENT("CT107-DSR=OFF"); break;
  }
#endif

  if (!(ra_data->ra_data_ind.status & ST_SA)) /* DSR EQ ON */
  {
    /*** perform filtering of status bit SB ***/

    dtra->dl_sb.current = (UBYTE)shm_get_dsp_value(statd_b_sb);
    ret = check_status_bit(&dtra->dl_sb);
    if (ret > 3)
      dl_status_changed = TRUE;

#ifdef TRACE_RA_TRA_STATUS
    switch (ret)
    {
    case 2: TRACE_EVENT("SB bit timer started 1 -> 0"); break;
    case 3: TRACE_EVENT("SB bit timer started 0 -> 1"); break;
    case 4: TRACE_EVENT("CT109-DCD=ON"); break;
    case 5: TRACE_EVENT("CT109-DCD=OFF"); break;
    }
#endif

    /*** perform filtering of status bit X ***/

    dtra->dl_x.current = (UBYTE)shm_get_dsp_value(statd_b_x);
    ret = check_status_bit(&dtra->dl_x);
    if (ret > 3)
      dl_status_changed = TRUE;

#ifdef TRACE_RA_TRA_STATUS
    switch (ret)
    {
    case 2: TRACE_EVENT("X bit timer started 1 -> 0"); break;
    case 3: TRACE_EVENT("X bit timer started 0 -> 1"); break;
    case 4: TRACE_EVENT("CT106-CTS=ON"); break;
    case 5: TRACE_EVENT("CT106-CTS=OFF"); break;
    }
#endif

  }
  else if (dl_status_changed EQ TRUE) /* DSR EQ OFF */
  {
    ra_data->ra_data_ind.status |= ST_SB + ST_X;
    dtra->dl_sb.last = 0xFF;
    dtra->dl_x.last  = 0xFF;

#ifdef TRACE_RA_TRA_STATUS
    TRACE_EVENT("CT106-CTS=OFF");
    TRACE_EVENT("CT109-DCD=OFF");
#endif
  }

  /*
   * overwrite the downlink CTS bit;
   * allows UART the reception of escape sequence always;
   * no matter what the current call state may be
  ra_data->ra_data_ind.status &= ~ST_X;
   */
  return dl_status_changed;
}

LOCAL U8 get_frame_descriptor(U8 bytes_to_read)
{
  T_TRA *dtra = ra_data->tra;

#ifdef _SIMULATION_
  dtra->dl_pFD = cl_ribu_get_new_frame_desc(ra_data->dl_ribu);
#else
  dtra->dl_pFD = tra_get_next_FrameDesc();
#endif


  if (NULL EQ dtra->dl_pFD)
  {
    /*Race condition where there is a data from L1 and call is released parallely*/
    TRACE_EVENT("Call is Released when data arrived or Ribu write index is invalid");

    /*return as if no data is read from L1.*/
    return 0;
  }


  if (bytes_to_read)
  {
    dtra->dl_pFD->len = MAX_TRANS_BUFFER;
    return (shm_get_dsp_buffer_new(ra_data->shm.shm_addr[adr_rad_data]+wof_rad_data, bytes_to_read, dtra->dl_pFD));
  }
  else
  {
    dtra->dl_pFD->len = 0;
    return 0;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_wait_for_connect  |
+--------------------------------------------------------------------+

  PURPOSE : wait for all filtered status bits set to 0
*/

GLOBAL void tra_dl_wait_for_connect(void)
{
  TRACE_FUNCTION("tra_dl_wait_for_connect()");

#ifdef HO_WORKAROUND /* tra_dl_wait_for_connect */
  if (*ra_data->shm.shm_addr[d_ra_conf] NEQ _act_d_ra_conf)
  {
    *ra_data->shm.shm_addr[d_ra_conf] = _act_d_ra_conf; /* tra_dl_data_trans */
    TRACE_EVENT("HO_REFRESH tra_dl_data_trans");
  }
#endif

  get_dl_status_bits();
  if ((UBYTE)(ra_data->ra_data_ind.status AND (ST_SA + ST_SB + ST_X)) EQ 0)
  {
    l1i_ra_activate_cnf();
    SET_STATE (KER, TRA_DATA_TRANS_PRE2);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_wait_for_uart     |
+--------------------------------------------------------------------+

  PURPOSE : wait for DTI connection to UART
*/

GLOBAL void tra_dl_wait_for_uart(void)
{
  TRACE_FUNCTION("tra_dl_wait_for_uart()");

  get_dl_status_bits();
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_got_uart          |
+--------------------------------------------------------------------+

  PURPOSE : send the current downlink status bits to UART
*/

GLOBAL void tra_dl_got_uart(void)
{
  TRACE_FUNCTION("tra_dl_got_uart()");

  get_dl_status_bits();
  get_frame_descriptor(0);
  l1i_ra_data_ind(hCommTRA);
  SET_STATE (KER, TRA_DATA_TRANS);
}

LOCAL void get_dl_bytes(UBYTE bytes_to_read)
{
  T_TRA *dtra = ra_data->tra;

  UBYTE bytes_read;

  bytes_read = get_frame_descriptor(bytes_to_read);
  shm_set_dsp_value (rad_byte_cnt, 2); /* confirm read operation */

  if ( bytes_read EQ 0 ){
    /*We couldn't read the data, in get_frame_descriptor() there is a possibiliy
     we get NULL frame description (race condition) hence no data is read. In this case we should not 
     access dtra->dl_pFD pointer and as well donot indicate ra_data_ind, hence return.
    */
    return;
  }


  if (ra_data->ra_data_ind.status & ST_SA OR ra_data->ra_data_ind.status & ST_SB)
  {
    /*
    DSR is OFF OR DCD is OFF
    */
    dtra->dl_pFD->len = 0;
#ifdef TRACE_RA_TRA_DATA
    TRACE_EVENT_P1("DATA_IND - len=0:%c", *dtra->dl_pFD->buf);
#endif
  }
  else
  {
    dtra->dl_pFD->len = bytes_read;
#ifdef TRACE_RA_TRA_DATA
    TRACE_EVENT_P2("DATA_IND - len=%d:%c", bytes_read, *dtra->dl_pFD->buf);
#endif
  }
  l1i_ra_data_ind(hCommTRA);
}

LOCAL BOOL dl_break_detected(BOOL *dl_status_changed, UBYTE *bytes_to_read)  /* BREAK handling */
{
  T_TRA *dtra = ra_data->tra;

  UBYTE brklen;
  UBYTE brkpos;
  UBYTE bytes_read;

  if ((brklen = (UBYTE)shm_get_dsp_value(rad_break_len)) > 0)
  {
    TRACE_EVENT_P1("RA_BREAK_IND-brklen=%d", brklen);

    /*** handling of 0xff break over multiple frames not implemented yet ***/

    if ((brkpos = (UBYTE)shm_get_dsp_value(rad_break_pos)) > 0)
    {
      TRACE_EVENT_P1("brkpos=%d", brkpos);
      /*
       * If the position > 0 read out the data until the break occurs.
       */
      if (*bytes_to_read > 0)
      {
        TRACE_EVENT_P1("bytes_to_read=%d", *bytes_to_read);

        bytes_read = get_frame_descriptor(brkpos);
        bytes_to_read -= bytes_read;
        dtra->dl_pFD->len = bytes_read;

        TRACE_EVENT ("DATA_IND -  break handling");
        dtra->dl_pFD->len = 0;
        l1i_ra_data_ind(hCommTRA);
      }
    }

    shm_set_dsp_value (rad_byte_cnt, 2); /* confirm read operation */

#ifdef HO_WORKAROUND /* tra_dl_data_trans - "BREAK" */

    /*
    enforce new DSR status bit filtering time
    */
    dtra->dl_sa.delay_OFF_ON = 1000L;
    dtra->dl_sa.delay_ON_OFF = 0L;

    dtra->dl_sa.last = 0xFF;
    dtra->dl_sb.last = 0xFF;
    dtra->dl_x.last  = 0xFF;

    ra_data->ra_data_ind.status = ST_SA + ST_SB + ST_X;

    *dl_status_changed = TRUE;

#else

    dtra->ra_break_ind.break_len = brklen;
    l1i_ra_break_ind();

#endif

    if (*dl_status_changed EQ TRUE)
    {
      get_frame_descriptor(0);
      l1i_ra_data_ind(hCommTRA);
    }

    return TRUE;
  } /* brklen > 0 */

  return FALSE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : RA_TRA                   |
| STATE   : code                  ROUTINE : tra_dl_data_trans        |
+--------------------------------------------------------------------+

  PURPOSE :
*/

GLOBAL void tra_dl_data_trans(void)
{
  UBYTE bytes_to_read;
  BOOL dl_status_changed;

  TRACE_FUNCTION("tra_dl_data_trans()");

#ifdef HO_WORKAROUND /* tra_dl_data_trans */
  if (*ra_data->shm.shm_addr[d_ra_conf] NEQ _act_d_ra_conf)
  {
    *ra_data->shm.shm_addr[d_ra_conf] = _act_d_ra_conf; /* tra_dl_data_trans */
    TRACE_EVENT("HO_REFRESH tra_dl_data_trans");
  }
#endif

  dl_status_changed = get_dl_status_bits();

  /*** read out the received downlink data ***/

  bytes_to_read = shm_get_dsp_value (rad_byte_cnt);

  if (bytes_to_read > 0)
  {
    bytes_to_read -= 2; /* ignore header */

    if (dl_break_detected(&dl_status_changed, &bytes_to_read))
      return;

    if (bytes_to_read > 0 AND bytes_to_read <= MAX_TRANS_BUFFER)
    {
      get_dl_bytes(bytes_to_read);
    }
    else  /* NO bytes_to_read */
    {
      if (dl_status_changed EQ TRUE)
      {
        get_frame_descriptor(0);
        l1i_ra_data_ind(hCommTRA);
      }
    }
  }
  else /* NO bytes_to_read -- will never happen */
  {
    if (dl_status_changed EQ TRUE)
    {
      get_frame_descriptor(0);
      l1i_ra_data_ind(hCommTRA);
    }
  }
}