diff src/g23m-fad/l2r/l2r_dnf.c @ 174:90eb61ecd093

src/g23m-fad: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 12 Oct 2016 05:40:46 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-fad/l2r/l2r_dnf.c	Wed Oct 12 05:40:46 2016 +0000
@@ -0,0 +1,1042 @@
+/* 
++----------------------------------------------------------------------------- 
+|  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);
+    }
+  }
+}
+