view src/g23m-gprs/llc/llc_uirxf.c @ 222:79cb194284ca

doc/Freerunner-Howto: update for the TCS2/TCS3 hybrid development
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 16 Oct 2016 00:26:26 +0000
parents 219afcfc6250
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  
|  Modul   :  
+----------------------------------------------------------------------------- 
|  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 is part of the entity LLC and implements all 
|             procedures and functions as described in the 
|             SDL-documentation (UIRX-statemachine)
+----------------------------------------------------------------------------- 
*/ 

#ifndef LLC_UIRXF_C
#define LLC_UIRXF_C
#endif

#define ENTITY_LLC

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

#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 "cnf_llc.h"    /* to get cnf-definitions */
#include "mon_llc.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "llc.h"        /* to get the global entity definitions */

#include "llc_uirxf.h"  /* to compare own prototyes */
/*==== CONST ================================================================*/

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

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

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


/*
+------------------------------------------------------------------------------
| Function    : uirx_queue_clean 
+------------------------------------------------------------------------------
| Description : This procedure removes all entries from the UIRX queue
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_queue_clean (void)
{
  T_UIRX_QUEUE** entry = &(llc_data->uirx->queue);
  
  TRACE_FUNCTION( "uirx_queue_clean" );

  while (*entry)
  {
    /*
     * get pointer to next (=first) entry
     */
    T_UIRX_QUEUE* current = *entry;

    /*
     * Free frame, if one is attached to the entry
     */
    if (current->frame != NULL)
    {
      PFREE (current->frame);
    }

    /*
     * remove next entry from the entry (make second to first)
     */
    *entry = current->next;
    
    /*
     * free the removed entry
     */
    MFREE (current);
  }

} /* uirx_queue_clean() */

/*
+------------------------------------------------------------------------------
| Function    : uirx_queue_store
+------------------------------------------------------------------------------
| Description : This procedure stores the primitive to the end of the queue.
|               If the queue is full, an the primitive is freed.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_queue_store (T_LL_UNITDATA_IND *ll_unitdata_ind)
{
  T_UIRX_QUEUE** entry       = &(llc_data->uirx->queue);
  int            num_entries = 0;

  TRACE_FUNCTION( "uirx_queue_store" );

  /*
   * Skip, but count, already for L3 ready waiting entries.
   * If queue is already full, free this primitive.
   */
  while (*entry)
  {
    num_entries++;
    
    if (num_entries >= UIRX_QUEUE_SIZE)
    {
      PFREE (ll_unitdata_ind);
      TRACE_EVENT ("LL_UNITDATA_IND ignored -> UIRX queue is full");
      return;
    }

    entry = &((*entry)->next);
  }

  /*
   * Allocate management memory
   */
  MALLOC( *entry, sizeof(T_UIRX_QUEUE) );

  if (*entry)
  {
    /*
     * Queue primitive
     */
    (*entry)->next   = NULL;
    (*entry)->frame  = ll_unitdata_ind;

  }
  else
  {
    /*
     * Out of memory
     */
    PFREE (ll_unitdata_ind);
    TRACE_ERROR( "Out of memory in uirx_queue_store()" );
  }

} /* uirx_queue_store() */


/*
+------------------------------------------------------------------------------
| Function    : uirx_queue_retrieve
+------------------------------------------------------------------------------
| Description : Retrieve the next frame, if any. 
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL BOOL uirx_queue_retrieve (T_LL_UNITDATA_IND **ll_unitdata_ind)
{
  T_UIRX_QUEUE** entry = &(llc_data->uirx->queue);

  TRACE_FUNCTION( "uirx_queue_retrieve" );

  /*
   * Take the first queue entry, if there is any.
   */
  if (*entry)
  {
    /*
     * Store pointer to the entry
     */
    T_UIRX_QUEUE* current = *entry;

    /*
     * Remove entry from the queue (make second to first)
     */
    *entry = current->next;

    *ll_unitdata_ind = current->frame;
  
    /*
     * Free retrieved management entry
     */
    MFREE (current);

    return TRUE;
  }
  else
  {
    /*
     * Set default return values
     */
    *ll_unitdata_ind = NULL;

    return FALSE;
  }

} /* uirx_queue_retrieve() */

/*
+------------------------------------------------------------------------------
| Function    : uirx_init
+------------------------------------------------------------------------------
| Description : This procedure initialises all necessary variables of
|               ui_frames_rx for all SAPIs.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_init (void)
{
  UBYTE inc;

  TRACE_FUNCTION( "uirx_init" );
  
  /*
   * Initialise every incarnation of UIRX with state TLLI_UNASSIGNED_NOT_READY,
   * except incarnation 0 (= SAPI 1), because we have no flow control for 
   * SAPI 1.
   */
  SWITCH_SERVICE (llc, uirx, 0);
  INIT_STATE (UIRX_0, UIRX_TLLI_UNASSIGNED_READY);

  SWITCH_SERVICE (llc, uirx, 1);
  INIT_STATE (UIRX_1, UIRX_TLLI_UNASSIGNED_NOT_READY);
  
  SWITCH_SERVICE (llc, uirx, 2);
  INIT_STATE (UIRX_2, UIRX_TLLI_UNASSIGNED_NOT_READY);
  
  SWITCH_SERVICE (llc, uirx, 3);
  INIT_STATE (UIRX_3, UIRX_TLLI_UNASSIGNED_NOT_READY);
  
  SWITCH_SERVICE (llc, uirx, 4);
  INIT_STATE (UIRX_4, UIRX_TLLI_UNASSIGNED_NOT_READY);
  
  SWITCH_SERVICE (llc, uirx, 5);
  INIT_STATE (UIRX_5, UIRX_TLLI_UNASSIGNED_NOT_READY);

  /*
   * Initialise the UIRX queue structure
   */
  for (inc = 0; inc < UIRX_NUM_INC; inc++)
  {
    SWITCH_SERVICE (llc, uirx, inc);

    /*
     * Free old used resources (in case of an LLC restart):
     */
    uirx_queue_clean ();
    llc_data->uirx->queue = NULL;
  }

  return;
} /* uirx_init() */


/*
+------------------------------------------------------------------------------
| Function    : uirx_init_sapi
+------------------------------------------------------------------------------
| Description : This procedure initialises all necessary variables of
|               ui_frames_rx for the given SAPI.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_init_sapi (void)
{ 
  TRACE_FUNCTION( "uirx_init_sapi" );
  
  /*
   * <R.LLC.TLLI_ASS.A.007>, <R.LLC.TLLI_ASS.A.009>
   */
  llc_data->sapi->vur = 0;

  llc_data->uirx->last_32_frames_bitfield = 0L;

  return;
} /* uirx_init_sapi() */



/*
+------------------------------------------------------------------------------
| Function    : uirx_store_nu
+------------------------------------------------------------------------------
| Description : This procedure stores the given n(u) in a list of the last 32 
|               received n(u)s concerning the given SAPI. Therefore the 
|               variable v(ur) is passed to the procedure, which contains 
|               the current value of the unacknowledged receive sequence 
|               number.
|
| Parameters  : nu  - N(U), must be in the range vur-32 <= nu < vur
|               vur - V(UR)
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_store_nu (T_FRAME_NUM nu, T_FRAME_NUM vur)
{ 
  USHORT            diff;


  TRACE_FUNCTION( "uirx_store_nu" );
  
  /*
   * Set the bit for the received N(U) in last_32_frames_bitfield. The 
   * relative bit position referring to V(UR) has already been stored 
   * in diff.
   */
  diff = (vur + (MAX_SEQUENCE_NUMBER+1) - nu - 1) % (MAX_SEQUENCE_NUMBER+1);

  llc_data->uirx->last_32_frames_bitfield |= (0x00000001L) << diff;

  return;
} /* uirx_store_nu() */



/*
+------------------------------------------------------------------------------
| Function    : uirx_check_nu
+------------------------------------------------------------------------------
| Description : This procedure checks if the given n(u) has already been 
|               received for the current SAPI within the last 32 frames (see 
|               procedure store_nu).
|
| Parameters  : nu    - N(U), must be in the range vur-32 <= nu < vur
|               vur   - V(UR)
|
| Returns     : TRUE  - if frame was already received.
|               FALSE - else
+------------------------------------------------------------------------------
*/
GLOBAL BOOL uirx_check_nu (T_FRAME_NUM nu, T_FRAME_NUM vur)
{ 
  USHORT diff;


  TRACE_FUNCTION( "uirx_check_nu" );
  
  /*
   * The difference (modulo counted) between V(UR) and N(U) is 
   * calculated as follows:
   * - add 512 (maximum sequence number + 1) to V(UR), in case V(UR)
   *   is smaller than N(U)
   * - subtract N(U)
   * - subtract 1 because V(UR) is not contained within 
   *   last_32_frames_bitfield and thus the bit shift must be one less
   * - afterwards apply modulo 512 to get back into the range of 
   *   sequence numbers, because we added this value initially to
   *   V(UR)
   */
  diff = (vur + (MAX_SEQUENCE_NUMBER+1) - nu - 1) % (MAX_SEQUENCE_NUMBER + 1);

  /*
   * Check if the corresponding bit of N(U) in last_32_frames_bitfield is 
   * set. The bit is stored in last_32_frames_bitfield relative to V(UR).
   */
  return ((llc_data->uirx->last_32_frames_bitfield & (0x00000001L << diff)) != 0L);
} /* uirx_check_nu() */


/*
+------------------------------------------------------------------------------
| Function    : uirx_set_new_vur
+------------------------------------------------------------------------------
| Description : This procedure handles setting vur to a new value. The modulo
|               operation and the handling of the last_32_frames_bitfield
|               is done here.
|
| Parameters  : new_vur - V(UR), must be in range V(UR) < new_vur < V(UR)-32
|
+------------------------------------------------------------------------------
*/
GLOBAL void uirx_set_new_vur (T_FRAME_NUM new_vur)
{ 
  USHORT diff;


  TRACE_FUNCTION( "uirx_set_new_vur" );

  new_vur %= (MAX_SEQUENCE_NUMBER+1);
  
  /*
   * The difference (modulo counted) between V(UR) and the new_vur is 
   * calculated as follows:
   * - add 512 (maximum sequence number + 1) to new_vur
   * - subtract V(UR)
   * - afterwards apply modulo 512 to get back into the range of 
   *   sequence numbers, because we added this value initially
   */
  diff = (new_vur + (MAX_SEQUENCE_NUMBER+1) - llc_data->sapi->vur) 
           % (MAX_SEQUENCE_NUMBER+1);

  /*
   * Now move the bitfield indicating the last 32 frames numbers. If the diff
   * from current to new_vur is to large, the bitfild is automaticly cleard
   * by shifting all bits out.
   */
  llc_data->uirx->last_32_frames_bitfield <<= diff;

  /*
   * Increase oc if necessary. If new_vur is a higher value, no overflow
   * encountered. If new_vur is lower, an retransmission could be possible
   * or we have had an overflow. But this function will not be called in 
   * case of a retransmission!
   */
  if ( new_vur < llc_data->sapi->vur )
  {
    llc_data->sapi->oc_ui_rx += (MAX_SEQUENCE_NUMBER+1);
  }

  /*
   * Set net V(UR) value
   */
  llc_data->sapi->vur = new_vur;

} /* uirx_set_new_vur() */