view src/g23m-fad/l2r/l2r_dnf.c @ 287:3dee79757ae4

UI fw: load handheld audio mode on boot We have now reached the point where use of audio mode config files should be considered mandatory. In ACI usage we can tell users that they need to perform an AT@AUL of some appropriate audio mode, but in UI-enabled fw we really need to have the firmware load audio modes on its own, so that correct audio config gets established when the handset or development board runs on its own, without a connected host computer. Once have FC Venus with both main and headset audio channels and headset plug insertion detection, our fw will need to automatically load the handheld mode or the headset mode depending on the plug insertion state. For now we load only the handheld mode, which has been tuned for FC-HDS4 on FC Luna.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 13 Nov 2021 03:20:57 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  CSD (8411)
|  Modul   :  L2r_dnf.c
+----------------------------------------------------------------------------- 
|  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 procedures and functions for
|             the component L2R of the base station
+----------------------------------------------------------------------------- 
*/ 

#ifndef L2R_DNF_C
#define L2R_DNF_C
#endif

#define ENTITY_L2R

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

#include <string.h>
#include "typedefs.h"
#include "pconst.cdg"
#include "vsi.h"
#include "macdef.h"
#include "custom.h"
#include "gsm.h"
#include "cus_l2r.h"
#include "cnf_l2r.h"
#include "mon_l2r.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "dti.h"      /* functionality of the dti library */

#include "cl_ribu.h"
#include "l2r.h"

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

/*==== TYPES =======================================================*/

/*==== VAR EXPORT ==================================================*/

/*==== VAR LOCAL ===================================================*/

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

/*
+------------------------------------------------------------------------------
|  Function    : dn_init
+------------------------------------------------------------------------------
|  Description : initialise the l2r data for the downlink process
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_init(T_DN *ddn)
{
  TRACE_FUNCTION ("dn_init()");

  ddn->FlowCtrlUsed = FALSE;
  ddn->DnFlow = FL_INACTIVE;
  ddn->UpFlow = FL_INACTIVE;
#ifdef L2R_TRACE_FLOW
  ddn->LastSentFlow = FL_INVALID;
#endif
  ddn->FlowThresh = MAX_DPRIM_RIBU_SIZE / 2;
  ddn->LastState = 0 << SO_SA_BIT | 0 << SO_SB_BIT;

  ddn->RiBu.idx.depth = MAX_DPRIM_RIBU_SIZE;
  INIT_STATE (DN_LL, IW_IDLE);
  INIT_STATE (DN_UL, IW_IDLE);
  INIT_STATE (DN, DN_DISCONNECTED);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_check_flow
+------------------------------------------------------------------------------
|  Description : checks flow control staus
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_check_flow(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_check_flow()");

  if (!ddn->FlowCtrlUsed)
  {
    return;
  }

  if (ddn->RiBu.idx.filled >= ddn->FlowThresh)
  {
    switch (ddn->DnFlow)
    {
    case FL_ACTIVE:
      return;

    case FL_INACTIVE:
      ddn->DnFlow = FL_ACTIVE;
      break;
    }
  }
  else
  {
    switch (ddn->DnFlow)
    {
    case FL_ACTIVE:
      ddn->DnFlow = FL_INACTIVE;
      break;

    case FL_INACTIVE:
      return;
    }
  }
  sig_dn_up_flow (ddn->DnFlow);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_next_frame
+------------------------------------------------------------------------------
|  Description : Local function, which is used by up_copy_data_from_l2r 
|                to advance to the next frame in the primitive.
|                The variable primDesc of the calling function is updated.
|
|  Parameters  : primDesc   -
|
|  Return      : 1  -
|                0  -
+------------------------------------------------------------------------------
*/

LOCAL UBYTE dn_next_frame(T_P_DPRIM_DESCRIPTOR *primDesc)
{
  T_DN *ddn = &l2r_data->dn;

#ifdef _SIMULATION_
  TRACE_FUNCTION ("dn_next_frame()");
#endif

  (*primDesc)->index++; /* next frame */

  if ((*primDesc)->index >= (*primDesc)->nFr)
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("next primitive");
#endif
    cl_ribu_read_index(&ddn->RiBu.idx); /* point to next primitive */

    if (!ddn->RiBu.idx.filled) /* no primitive is ready */
    {
#ifdef _SIMULATION_
      TRACE_EVENT ("no primitive is ready");
#endif
      return (0);
    }

    *primDesc = ddn->RiBu._primDesc[ddn->RiBu.idx.ri]; /* point to next primitive descriptor */
    (*primDesc)->index = 0;
  }
  return (1);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_copy_data_from_l2r
+------------------------------------------------------------------------------
|  Description : Copies data from l2r into ring buffer.
||               Moreover the return value of the calling function
|                bytesCopied are set

|  Parameters  : buf          -
|                len          -
|                sa           -
|                sb           -
|                flow         -
|                bytesCopied  -
|
|  Return      : -
+------------------------------------------------------------------------------
*/

LOCAL U16 dn_copy_data_from_l2r(U8 *buf, U16 len, U8 *sa, U8 *sb, U8 *flow)
{
  T_DN *ddn = &l2r_data->dn;

  T_P_DPRIM_DESCRIPTOR primDesc;
  T_P_L2R_FRAME frame;
  
  register T_P_UBYTE pFrame;
  register T_P_UBYTE pBuf;
  register T_P_UBYTE pStat;
  
  USHORT bytesToCopy;
  USHORT blocklen;
  UBYTE frameCount;
  UBYTE statOct;

#ifdef _SIMULATION_
  TRACE_EVENT ("dn_copy_data_from_l2r()");
#endif

  ddn->ReportMrgFlow = FALSE;

  if (!ddn->RiBu.idx.filled) /* don't copy into buffer if no primitive is ready */
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("no primitive ready");
#endif
    switch (ddn->MrgFlow)
    {
    case FL_ACTIVE:
      *flow = DTI_FLOW_OFF;
      break;
    case FL_INACTIVE:
      *flow = DTI_FLOW_ON;
      break;
    }
    *sa = GET_SO_SA_BIT(ddn->LastState);
    *sb = GET_SO_SB_BIT(ddn->LastState);
    return 0;
  }

  if (ddn->ULFlow EQ FL_ACTIVE)
  {
    len = 0; /* upper layer has raised flow control; don't send data */
  }

  bytesToCopy = len;
  primDesc = ddn->RiBu._primDesc[ddn->RiBu.idx.ri]; /* point to current primitive descriptor */

  if (primDesc->nFr EQ 0) /* skip empty primitive */
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("empty primitive");
#endif
    switch (ddn->MrgFlow)
    {
    case FL_ACTIVE:
      *flow = DTI_FLOW_OFF;
      break;
    case FL_INACTIVE:
      *flow = DTI_FLOW_ON;
      break;
    }
    *sa = GET_SO_SA_BIT(ddn->LastState);
    *sb = GET_SO_SB_BIT(ddn->LastState);
    return 0;
  }

#ifdef _TARGET_
  if (primDesc->prim->data_size > DATA_SIZE_SHORT)
  {
    frameCount = 1;
  }
  else
  {
    frameCount = 2;
  }
#else
  {
    frameCount = 100;
  }
#endif

  frame   = (*primDesc->dadr)[primDesc->index];   /* dn_copy_data_from_l2r: point to current l2r frame in primitive */
  pBuf    = buf;                                  /* point to destination buffer */
  pFrame  = &((*frame)[primDesc->offset]);
  pStat   = &((*frame)[primDesc->off_status]);

  if (pFrame EQ pStat)
  {
    /* current byte is status octet */
    ddn->LastState = *pFrame & SO_STATUS_BITS_MASK;
  }

  /* merge flow control conditions */

  switch (ddn->MrgFlow)
  {
  case FL_ACTIVE:
    *flow = DTI_FLOW_OFF;
    break;
  case FL_INACTIVE:
    *flow = DTI_FLOW_ON;
    break;
  }

  *sa = GET_SO_SA_BIT(ddn->LastState);
  *sb = GET_SO_SB_BIT(ddn->LastState);

  /************************************************************************************
   * loop until either
   *   -  no more data are available or
   *   -  status in L2R frame changes or
   *   -  buffer for data is full
   ************************************************************************************/

  for (;;)
  {
    blocklen = pStat - pFrame;

    if (blocklen EQ 0)
    {
      /*
       * current byte is status octet;
       * only in the first pass of the loop, there may be no status octet
       */

      /*****************************
       *  evaluate status bits
       *****************************/
      statOct = *pFrame;
      if (ddn->LastState NEQ (statOct & SO_STATUS_BITS_MASK))
      {
        /*
         *  Status has changed.
         *  We have to stop,
         *  since only one state can be transmitted to the upper layer.
         */
        primDesc->offset = primDesc->off_status = pFrame - (T_P_UBYTE)frame;

#ifdef _SIMULATION_
        TRACE_EVENT ("return because of status change");
#endif
        return len - bytesToCopy;
      }

      pFrame++;

      /************************************
       *  evaluate address bits
       ************************************/
      
      statOct &= SO_ADR_MASK;
      
      switch (statOct)
      {
      case SO_BREAK_ACK:
      case SO_BREAK_REQ:
      case SO_END_EMPTY:
        /*
         * no more data in this frame
         */
        if (dn_next_frame(&primDesc) EQ 0) /* no more data available */
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;

#ifdef _SIMULATION_
          TRACE_EVENT ("return because no more data available");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }

        frameCount--;

        if (frameCount EQ 0)
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;
#ifdef _SIMULATION_
          TRACE_EVENT ("return because number of frames reached");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
        
        frame  = (*primDesc->dadr)[primDesc->index]; /* dn_copy_data_from_l2r */
        pFrame = (T_P_UBYTE)frame;
        pStat  = (T_P_UBYTE)frame;
        continue;  /* continue with next frame */

      case SO_END_FULL:
        pStat = &((*frame)[primDesc->prim->data_size]);
        blocklen = pStat - pFrame;
        break;

      case SO_TWO_OCTET:
        blocklen = *pFrame++ & SO_ADR_MASK_TWO_OCT;
        pStat = pFrame + blocklen;
        break;

      default:
        blocklen = statOct;
        pStat = pFrame + blocklen;
        break;
      }
    }

    if (bytesToCopy < blocklen)
    {
      /***************************************
       *  There is not enough space in the
       *  buffer to copy the complete block
       ***************************************/

      T_P_UBYTE pEnd = pFrame + bytesToCopy; /* save end mark */

      while (pFrame < pEnd)
      {
        *pBuf++ = *pFrame++;
      }

      if (pFrame >= &((*frame)[primDesc->prim->data_size]))
      {
        /*
         * end of frame reached 
         * actually this case can never occur, 
         * since bytesToCopy < blocklen
        */
        dn_next_frame(&primDesc);
        primDesc->offset = 0;
        primDesc->off_status = 0;
      }
      else
      {
        primDesc->offset = pFrame - (T_P_UBYTE)frame;
        primDesc->off_status = pStat  - (T_P_UBYTE)frame;
      }

#ifdef _SIMULATION_
      TRACE_EVENT ("return because buffer is full");
#endif
      return len; /* this much data could be copied */
    
    }
    else /* bytesToCopy >= blocklen */
    {
      /***************************************
       *  Copy the complete block
       ***************************************/
      
      bytesToCopy -= blocklen;

      while (pFrame < pStat)
      {
        *pBuf++ = *pFrame++;
      }

      if (pFrame >= &((*frame)[primDesc->prim->data_size])) /* end of frame reached */
      {
        if (dn_next_frame(&primDesc) EQ 0) /* no more data available */
        {
#ifdef _SIMULATION_
          TRACE_EVENT ("return because no more data available");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
      
        frameCount--;

        if (frameCount EQ 0)
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;

#ifdef _SIMULATION_
          TRACE_EVENT ("return because number of frames reached");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
        
        frame  = (*primDesc->dadr)[primDesc->index]; /* dn_copy_data_from_l2r */
        pFrame = (T_P_UBYTE)frame;
        pStat  = (T_P_UBYTE)frame;
      }
      
      if (bytesToCopy EQ 0)
      {
        primDesc->offset = pFrame - (T_P_UBYTE)frame;
        primDesc->off_status = pStat - (T_P_UBYTE)frame;

#ifdef _SIMULATION_
        TRACE_EVENT ("return because all data are copied");
#endif
        return len; /* this much data could be copied */
      }

    } /* bytesToCopy >= blocklen */
  } /* for (;;) */
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_send_data_ind
+------------------------------------------------------------------------------
|  Description : This procedure copies data from the downlink ring buffer 
|                into a DTI_DATA_IND primitive
|                and sends this primitive to the relay entity.
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_send_data_ind(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_send_data_ind()");

  if (ddn->DtiConnected EQ FALSE)
  {
    TRACE_EVENT("DTI not connected, but dn_send_data_ind() called");
    return;
  }

  {
  USHORT len = L2R_FRAMES_PER_PRIM_MAX * (RLP_FRAME_SIZE_SHORT - HT_LEN - 1);
  UBYTE sa;
  UBYTE sb;
  UBYTE flow;
  T_desc2* desc;

  PALLOC (dti_data_ind, DTI2_DATA_IND);

  MALLOC (desc, (USHORT)(sizeof(T_desc2) - 1 + len));
  desc->len  = dn_copy_data_from_l2r ((U8*)&desc->buffer[0], len, &sa, &sb, &flow);
  desc->size = desc->len;
  desc->offset = 0;
  desc->next = 0;

  dti_data_ind->desc_list2.first = (ULONG)desc;
  dti_data_ind->desc_list2.list_len = desc->len;
  
  dti_data_ind->parameters.st_lines.st_line_sa    = sa;
  dti_data_ind->parameters.st_lines.st_line_sb    = sb;
  dti_data_ind->parameters.st_lines.st_flow       = flow;
  dti_data_ind->parameters.st_lines.st_break_len  = DTI_BREAK_OFF;
  dti_data_ind->parameters.p_id                   = DTI_PID_UOS;
  dti_data_ind->link_id                           = ddn->link_id;

#ifdef L2R_TRACE_FLOW
  if (ddn->LastSentFlow NEQ dti_data_ind->parameters.st_lines.st_flow)
  {
    switch (dti_data_ind->parameters.st_lines.st_flow)
    {
    case FL_ACTIVE:
      TRACE_EVENT("DTI downlink: FL_ACTIVE");
      break;

    case FL_INACTIVE:
      TRACE_EVENT("DTI downlink: FL_INACTIVE");
      break;
    }
    ddn->LastSentFlow = dti_data_ind->parameters.st_lines.st_flow;
  }
#endif

  dti_send_data (
    l2r_hDTI,
    L2R_DTI_UP_DEF_INSTANCE,
    L2R_DTI_UP_INTERFACE,
    L2R_DTI_UP_CHANNEL,
    dti_data_ind
    );        
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_scan_break_req
+------------------------------------------------------------------------------
|  Description : This procedure scans a rlp_data_ind primitive for L2R BREAK
|                status octets. It returnes the index of the frame following
|                the last BREAK status octet in the primitive.
|                Moreover the total number of frames in the primitive 
|                as well as the status bits of the last BREAK are returned.
|                In addition the x bit of the last status octet is returned.
|                It is important to search the last BREAK in the primitive,
|                because the data following a break signal
|                are used in the case of no data compression.
|
|  Parameters  : data_ind -
|                found
|                index
|                frames
|                emptyfr
|                sa
|                sb
|                flow_brk
|                flow_gen
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_scan_break_req
            (
              T_P_RLP_DATA_IND  data_ind,
              BOOL             *found,
              T_PRIM_INDEX     *index,
              T_PRIM_INDEX     *frames,
              T_PRIM_INDEX     *emptyfr,
              T_BIT            *sa,
              T_BIT            *sb,
              T_FLOW           *flow_brk,
              T_FLOW           *flow_gen
            )

{
  T_PRIM_INDEX ind;
  UBYTE off;
  UBYTE statOct;
  UBYTE brkStatOct = (UBYTE)(0 << SO_SA_BIT | 0 << SO_SB_BIT | 0 << SO_X_BIT);
  UBYTE genStatOct = (UBYTE)(0 << SO_SA_BIT | 0 << SO_SB_BIT | 0 << SO_X_BIT);

  T_P_L2R_FRAME frame;

  TRACE_FUNCTION ("dn_scan_break_req()");

  *found   = FALSE;
  *frames  = data_ind->sdu.l_buf / (8 * data_ind->data_size + HT_LEN);
  *emptyfr = 0;

  frame = (T_P_L2R_FRAME)(data_ind->sdu.buf + (data_ind->sdu.o_buf>>3) + HEADER_LEN);
  off = 0;
  ind = 0;

  while (ind < *frames)
  {
    statOct = (*frame)[off];

    switch (statOct & SO_ADR_MASK)
    {
    case SO_BREAK_REQ:
      *found  = TRUE;
      *index  = ind + 1;
      brkStatOct = statOct;
      genStatOct = statOct;
      ind++;
      frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
      off = 0;
      break;

    case SO_END_EMPTY:
      if (off EQ 0)
      {
        (*emptyfr)++;
      }
      /* fall through!!! */

    case SO_BREAK_ACK:
    case SO_END_FULL:
      genStatOct = statOct;
      ind++;
      frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
      off = 0;
      break;

    case SO_TWO_OCTET:
      genStatOct = statOct;
      off += ((*frame)[off] & SO_ADR_MASK_TWO_OCT) + 2;
      if (off >= data_ind->data_size)
      {
        ind++;
        frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
        off = 0;
      }
      break;

    default:
      genStatOct = statOct;
      off += (statOct & SO_ADR_MASK) + 1;
      if (off >= data_ind->data_size)
      {
        ind++;
        frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
        off = 0;
      }
      break;
    }
  }

  if (*found)
  {
    *sa    = GET_SO_SA_BIT(brkStatOct);
    *sb    = GET_SO_SB_BIT(brkStatOct);
  }
  else
  {
    *sa    = GET_SO_SA_BIT(genStatOct);
    *sb    = GET_SO_SB_BIT(genStatOct);
  }

  if (l2r_data->dn.FlowCtrlUsed)
  {
    if (GET_SO_X_BIT (brkStatOct) EQ 0)
    {
      *flow_brk = FL_INACTIVE;
    }
    else
    {
      *flow_brk = FL_ACTIVE;
    }
    
    if (GET_SO_X_BIT (genStatOct) EQ 0)
    {
      *flow_gen = FL_INACTIVE;
    }
    else
    {
      *flow_gen = FL_ACTIVE;
    }
  }
  else
  {
    *flow_brk = FL_INACTIVE;
    *flow_gen = FL_INACTIVE;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_free_prim
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : primDesc -
|
|
|  Return      :
+------------------------------------------------------------------------------
*/

LOCAL void dn_free_prim(T_P_DPRIM_DESCRIPTOR primDesc)
{
  TRACE_FUNCTION ("dn_free_prim()");

  if (primDesc->prim NEQ NULL)
  {
    PFREE (primDesc->prim);
    primDesc->prim = NULL;
    primDesc->nFr = 0;
    primDesc->index = 0;
    primDesc->offset = 0;
    primDesc->off_status = 0;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_free_all_prims
+------------------------------------------------------------------------------
|  Description : frees all primititives
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_free_all_prims(void)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_DESC_RIBU_INDEX n;

  TRACE_FUNCTION ("dn_free_all_prims()");

  for (n = 0; n < ddn->RiBu.idx.depth; n++)
  {
    dn_free_prim (ddn->RiBu._primDesc[n]);
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_free_prims
+------------------------------------------------------------------------------
|  Description : frees all primitive if r
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_cond_free_prims(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_cond_free_prims()");

  while (ddn->RiBu.free NEQ ddn->RiBu.idx.ri)
  {
    dn_free_prim (ddn->RiBu._primDesc[ddn->RiBu.free]);

    ddn->RiBu.free++;
    if (ddn->RiBu.free EQ ddn->RiBu.idx.depth)
    {
      ddn->RiBu.free = 0;
    }
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_store_prim
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : data_ind -
|                index    -
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_store_prim(T_P_RLP_DATA_IND data_ind, T_PRIM_INDEX index)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_INDEX m;
  T_P_DPRIM_DESCRIPTOR primDesc;

  T_PRIM_INDEX frames = data_ind->sdu.l_buf / (8 * data_ind->data_size + HT_LEN);
  UBYTE *pos = data_ind->sdu.buf + (data_ind->sdu.o_buf>>3) + HEADER_LEN;

  TRACE_FUNCTION ("dn_store_prim()");

  primDesc = ddn->RiBu._primDesc[cl_ribu_write_index(&ddn->RiBu.idx)];

  primDesc->prim = data_ind;
  primDesc->index = index;    /* if BREAK then not equal 0 */
  primDesc->offset = 0;
  primDesc->off_status = 0;
  primDesc->nFr = frames;

  for (m = 0; m < frames; m++)
  {
    (*primDesc->dadr)[m] = (T_P_L2R_FRAME)(pos + m * (data_ind->data_size + HT_LEN));
  }

  dn_check_flow();

  if (GET_STATE (DN_UL) EQ IW_WAIT AND ddn->ULFlow EQ FL_INACTIVE AND
      ddn->DtiConnected) /*jk: data send only when DTI connected*/
  {
    dn_send_data_ind();
    SET_STATE (DN_UL, IW_IDLE);
  }
}

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

  PURPOSE :

*/

GLOBAL void dn_init_ribu(void)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_DESC_RIBU_INDEX n;
  T_PRIM_INDEX m;

  TRACE_FUNCTION ("dn_init_ribu()");

  cl_ribu_init(&ddn->RiBu.idx, ddn->RiBu.idx.depth);
  ddn->RiBu.free = 0;

  for (n = 0; n < ddn->RiBu.idx.depth; n++)
  {
    ddn->RiBu._primDesc[n]      = &(ddn->PrimDesc[n]);
    ddn->PrimDesc[n].nFr        = 0;
    ddn->PrimDesc[n].dadr       = (T_P_ADR_VECTOR)&(ddn->AdrVec[n]); /* dn_init_ribu */
    ddn->PrimDesc[n].index      = 0;
    ddn->PrimDesc[n].offset     = 0;
    ddn->PrimDesc[n].off_status = 0;
    ddn->PrimDesc[n].prim       = NULL;

    for (m = 0; m < L2R_FRAMES_PER_PRIM_MAX; m++)
    {
      ddn->AdrVec[n][m] = NULL;
    }
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_req_data
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_cond_req_data(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_cond_req_data()");

  /* ring buffer full? */

  if ((ddn->RiBu.idx.wi + 1) % ddn->RiBu.idx.depth EQ ddn->RiBu.free)
  {
    SET_STATE (DN_LL, IW_IDLE);
  }
  else
  {
    PALLOC (rlp_getdata_req, RLP_GETDATA_REQ);
    PSENDX (RLP, rlp_getdata_req);
    SET_STATE (DN_LL, IW_WAIT);
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_store_status
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : flow -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_store_status(T_FLOW flow)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_store_status()");

  if (flow EQ ddn->LLFlow)
  {
    return;
  }

  ddn->LLFlow = flow;
  dn_merge_flow();
  sig_dn_up_ll_flow(ddn->LLFlow);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_merge_flow
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_merge_flow(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_merge_flow()");

  if (ddn->FlowCtrlUsed AND (ddn->UpFlow EQ FL_ACTIVE OR ddn->LLFlow EQ FL_ACTIVE)     )
  {
    if (ddn->MrgFlow EQ FL_INACTIVE)
    {
      ddn->ReportMrgFlow = TRUE;
      /*
      TRACE_EVENT("DN: Merged flow set active");
      */
    }
    ddn->MrgFlow = FL_ACTIVE;
  }
  else
  {
    if (ddn->MrgFlow EQ FL_ACTIVE)
    {
      ddn->ReportMrgFlow = TRUE;
      /*
      TRACE_EVENT("DN: Merged flow set inactive");
      */
    }
    ddn->MrgFlow = FL_INACTIVE;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_report_status
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

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

  if (l2r_data->dn.ReportMrgFlow AND GET_STATE (DN_UL) EQ IW_WAIT)
  {
    if (l2r_data->dn.DtiConnected) /*jk: data send only when DTI connected*/
    {
      dn_send_data_ind();
      SET_STATE (DN_UL, IW_IDLE);
    }
  }
}