diff comlib/cl_list.c @ 0:75a11d740a02

initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 09 Jun 2016 00:02:41 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/comlib/cl_list.c	Thu Jun 09 00:02:41 2016 +0000
@@ -0,0 +1,653 @@
+/*
++-----------------------------------------------------------------------------
+|  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 module defines the functions for the List
+|             processing functions used in components RR/PL of the mobile station.
++-----------------------------------------------------------------------------
+*/
+
+#ifndef CL_LIST_C
+#define CL_LIST_C
+
+#include "config.h"
+#include "fixedconf.h"
+
+#define ENTITY_RR
+#define ENTITY_PL
+
+/*==== INCLUDES ===================================================*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>   
+#include "typedefs.h"
+#include "message.h"
+#include "vsi.h"
+#include "gsm.h"
+#include "prim.h"
+#include "cl_list.h"
+
+/*==== CONST ======================================================*/
+#ifdef TI_PS_FF_QUAD_BAND_SUPPORT
+#define INRANGE(min, x, max)  ((unsigned)(x-min) <= (max-min))
+#endif
+
+/*==== VARIABLES ==================================================*/
+LOCAL const BYTE ByteBitMask[]= {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x1};
+
+/*==== EXPORT =====================================================*/
+
+/*==== PRIVATE FUNCTIONS ==========================================*/
+LOCAL UBYTE srv_is_not_in_list (USHORT * channels,
+                                USHORT   new_channel,
+                                USHORT   size);
+
+
+/*==== PUBLIC FUNCTIONS ===========================================*/
+/*
+ * List processing Functions
+ *
+ * RR uses a lot of channel lists. They are organized internally as bitmaps.
+ * In the following a set of functions is defined for access to this lists:
+ *
+ * srv_set_channel
+ * srv_unset_channel
+ * srv_get_channel
+ * srv_create_list
+ * srv_clear_list
+ * srv_copy_list
+ * srv_compare_list
+ * srv_merge_list
+ * srv_is_empty_list
+ * srv_create_chan_mob_alloc
+ *
+ * The size of the internal channel lists depends on the supported frequency
+ * band:
+ *
+ * STD=1 (STD_900)         GSM 900
+ * STD=2 (STD_EGSM)        E-GSM
+ * STD=3 (STD_1900)        PCS 1900
+ * STD=4 (STD_1800)        DCS 1800
+ * STD=5 (STD_DUAL)        GSM 900 / DCS 1800 DUALBAND
+ * STD=6 (STD_DUAL_EGSM)   GSM 900 / E-GSM / DCS 1800 DUALBAND
+ * STD=7 (STD_850)         GSM 850
+ * STD=8 (STD_DUAL_US)     GSM 850 / PCS 1900 DUALBAND
+ *
+ * We use a compressed bit array to store the list of channels.
+ * Dependent on the configured or found frequency bands the bit array
+ * needs several numbers of bytes. For the representation of the individual
+ * bits in the array we need the function scr_channel_bit(), setBit(),
+ * resetBit() and getBit().
+ *
+ */
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : setBit					 |
++--------------------------------------------------------------------+
+
+  PURPOSE : sets bit.
+
+*/
+
+LOCAL void setBit (UBYTE* bitstream, unsigned bitindex)
+{
+  bitstream[bitindex >> 3] |= ByteBitMask[bitindex & 7];
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : resetBit					 |
++--------------------------------------------------------------------+
+
+  PURPOSE : Resets bit.
+
+*/
+
+LOCAL void resetBit (UBYTE* bitstream, unsigned bitindex)
+{
+  bitstream[bitindex >> 3] &= ~ByteBitMask[bitindex & 7];
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : getBit					 |
++--------------------------------------------------------------------+
+
+  PURPOSE : Gets bit.
+
+*/
+
+
+LOCAL BYTE getBit (UBYTE* bitstream, unsigned bitindex)
+{
+  unsigned ByteIdx = bitindex >> 3;
+
+  if (bitstream[ByteIdx])
+    return (bitstream[ByteIdx] & ByteBitMask[bitindex & 7]) ? 1 : 0;
+  else
+    return 0;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : scr_channel_bit            |
++--------------------------------------------------------------------+
+
+  PURPOSE : calculate bit position in the bitstream for a given
+            channel and execute function dependent on mode.
+
+*/
+
+GLOBAL UBYTE scr_channel_bit(T_LIST * list, int channel, int mode)
+{
+  int     bitposition = -1;
+  UBYTE   ret = 0;
+
+  /*
+   * a more efficient way of range checking for ARM
+   * (according to application note 34, ARM DAI 0034A, January 1998)
+   *
+   * For the following code:
+   * if (channel >= low_channel AND channel <= high_channel)
+   *   bitposition = ...;
+   *
+   * exist the faster way to implemented this:
+   * if ((unsigned)(channel - low_channel) <= (high_channel - low_channel)
+   *   bitposition = ...;
+   *
+   * Future versions of the compiler will perform this optimization
+   * automatically.
+   *
+   * We use the follwing macro:
+   * #define  INRANGE(min, x, max)  ((unsigned)(x-min) <= (max-min))
+   */
+  if(channel EQ CHANNEL_0)
+    channel = CHANNEL_0_INTERNAL;
+
+  bitposition = BITOFFSET_LIST - channel;
+      /*if (channel EQ CHANNEL_0)
+        bitposition = (USHORT)(BITOFFSET_DUAL_EGSM_B - CHANNEL_0_INTERNAL);
+      else if (INRANGE(LOW_CHANNEL_900,channel,HIGH_CHANNEL_900))
+        bitposition = (USHORT)(BITOFFSET_DUAL_EGSM_A - channel);
+      else if (INRANGE(LOW_CHANNEL_EGSM,channel,HIGH_CHANNEL_EGSM))
+        bitposition = (USHORT)(BITOFFSET_DUAL_EGSM_B - channel);
+      else if (INRANGE(LOW_CHANNEL_1800,channel,HIGH_CHANNEL_1800))
+        bitposition = (USHORT)(BITOFFSET_DUAL_EGSM_C - channel);
+      if (INRANGE(LOW_CHANNEL_850,channel,HIGH_CHANNEL_850))
+        bitposition = (USHORT)(BITOFFSET_DUAL_US_A - channel);
+      else if (INRANGE(LOW_CHANNEL_1900,channel,HIGH_CHANNEL_1900))
+        bitposition = (USHORT)(BITOFFSET_DUAL_US_B - channel);
+*/
+  if (bitposition >=0)
+  {
+    switch (mode)
+    {
+      case SET_CHANNEL_BIT:
+        setBit (list->channels, bitposition);
+        break;
+      case RESET_CHANNEL_BIT:
+        resetBit (list->channels, bitposition);
+        break;
+      case GET_CHANNEL_BIT:
+        ret = getBit (list->channels, bitposition);
+        break;
+      case CHECK_CHANNEL:
+        ret = 1;
+        break;
+    }
+  }
+  return ret;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_create_list            |
++--------------------------------------------------------------------+
+
+  PURPOSE : Creates a frequency list in USHORT format from the
+            bit list. USHORT format means an array of USHORTs
+            followed by NOT_PRESENT_16BIT (0xFFFF), except for the
+            case when all elements of the array are used, i.e. the
+            array's space is fully occupied.
+            In this function the channels are just converted between
+            the formats, any semantic errors are not checked here, ie.
+            if the MS is 1800-only and the list contains a 900 channel
+            this will be converted even if this leads to an error.
+            This has to be handled by the caller.
+
+            Parameters:
+                list          - [in]  is the input list.
+                channel_array - [out] converted list.
+                size          - [in]  defines the maximum number of channels
+                                      in the list.
+                zero_at_start - [in]  specifies where the CHANNEL_0 should be
+                                      put:
+                                       TRUE  - at the start of the list
+                                       FALSE - at the end of the list
+                start_index   - [in] specifies a index into the channel_array.
+                                     new channels are added at the positions
+                                     following and including the index:
+                                      channel_array[start_index] to
+                                       channel_array[size-1]
+
+                                     If the start_index is not equal zero it is
+                                     also checked if the new channel is already
+                                     in the channel_array list (from
+                                      channel_array[0] to
+                                       channel_array[start_index-1])
+
+                                     If the start_index is equal zero the
+                                     above check is not performed.
+
+            Return Value:
+                number of elements added + start_index
+
+*/
+
+GLOBAL int srv_create_list (T_LIST * list, USHORT * channel_array, USHORT size,
+                            UBYTE zero_at_start, USHORT start_index)
+{
+  int           BitOffset, Idx;
+  unsigned int  ByteValue, BitMask, LeftMask;
+  int           i = start_index;
+  UBYTE         *pch;
+  USHORT        *parray = &channel_array[start_index];
+
+  pch = &list->channels[T_LIST_MAX_SIZE-1];
+  for(Idx = T_LIST_MAX_SIZE-1; Idx >= 0 AND i < size; Idx--, pch--)
+  {
+    /*
+     * check and add all channels
+     */
+    if ((ByteValue = *pch) NEQ 0)
+    {
+      /* byte contains set bits */
+
+      /* check single bits */
+      for (BitOffset=7, BitMask=0x01, LeftMask=0xfe;
+           BitOffset>=0;
+           BitOffset--, BitMask<<=1, LeftMask<<=1)
+      {
+        if (ByteValue & BitMask)
+        {
+          *parray = BITOFFSET_LIST - (BitOffset+(Idx<<3));
+          if(!start_index OR
+             srv_is_not_in_list (channel_array, *parray, start_index))
+          {
+            /* if the check is ok, ie:
+             * always add channel, or the channel has not yet existed
+             * in the list, then advance the pointer and add the
+             * next channel on next position
+             * if the check fails the pointer is not advanced and
+             * the channel will not be added and the next channel
+             * will overwrite the current channel.
+             */
+            parray++;
+
+            /* check if list is full */
+            if (++i >= size)
+              break;
+          }
+          /* check if any bits are left */
+          if ((ByteValue & LeftMask) EQ 0)
+            break;
+        }
+      } /* for all bits in byte */
+    } /* if Byte NEQ 0 */
+  } /* for all Bytes in List */
+
+
+  /*
+   * If CHANNEL_0 is included in the list
+   * it has to be changed from CHANNEL_0_INTERNAL to CHANNEL_0
+   * and then the zero_at_start flag is handled.
+   *
+   * If CHANNEL_0 is in the list it is always
+   * at the end of the list.
+   */
+  if(i NEQ start_index AND
+     *(parray-1) EQ CHANNEL_0_INTERNAL)
+  {
+    *(parray-1) = CHANNEL_0;
+
+    if(zero_at_start AND (i > 1))
+    {
+      memmove(&channel_array[1], &channel_array[0], (int)sizeof(channel_array[0])*(i-1));
+      channel_array[0] = CHANNEL_0;
+    }
+  }
+
+  /*
+   * add the end identifier to the output list
+   */
+  if (i<size)
+  {
+    *parray = NOT_PRESENT_16BIT;
+  }
+
+  return i;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_is_not_in_list         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Checks if the given channel number is a member of the given
+            list.
+
+            Parameters:
+            channels    - contains the existing output list.
+            new_channel - is the channel number which shall be checked.
+            size        - indicates the length of the list.
+
+*/
+
+static UBYTE srv_is_not_in_list (USHORT * channels,
+                                 USHORT   new_channel,
+                                 USHORT   size)
+{
+  USHORT   i;
+
+  /*
+   * for all members of the list
+   */
+  for (i=0;i<size;i++)
+  {
+    /*
+     * The end of the list is reached
+     * that means the new channel is not inside.
+     */
+    if (channels[i] EQ NOT_PRESENT_16BIT)
+      return TRUE;
+
+    /*
+     * the channel is inside
+     */
+    if (channels[i] EQ new_channel)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_clear_list             |
++--------------------------------------------------------------------+
+
+  PURPOSE : Clears a list by clearing all bits.
+
+*/
+
+GLOBAL void srv_clear_list (T_LIST * list)
+{
+  /*
+   * simple algorithm: clear the whole list.
+   */
+  memset (list, 0, sizeof (T_LIST));
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_copy_list              |
++--------------------------------------------------------------------+
+
+  PURPOSE : Copies a list.
+
+*/
+
+GLOBAL void srv_copy_list (T_LIST * target_list, T_LIST * source_list,
+                           UBYTE    size)
+{
+  memcpy (target_list, source_list, size);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_compare_list           |
++--------------------------------------------------------------------+
+
+  PURPOSE : Compares two lists.
+
+*/
+
+GLOBAL UBYTE srv_compare_list (T_LIST * list1, T_LIST * list2)
+{
+  return (memcmp (list1, list2, sizeof (T_LIST)) EQ 0);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_merge_list             |
++--------------------------------------------------------------------+
+
+  PURPOSE : Merges two lists. Both lists are bitmaps. So the merge
+            is done by a bitwise OR.
+
+*/
+
+GLOBAL void srv_merge_list (T_LIST * target_list, T_LIST * list)
+{
+  USHORT i;
+
+  /*
+   * The maximum list size is T_LIST_MAX_SIZE Bytes for the dualband extended
+   * frequency standard.
+   */
+
+  for (i=0;i<T_LIST_MAX_SIZE;i++)
+    target_list->channels[i] |= list->channels[i];
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_unmask_list            |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine resets those bits in destination list that are set in
+            the source list.
+            Refer Cell Selection Improvements-LLD section:4.1.1.3.11    
+*/
+
+GLOBAL void srv_unmask_list(T_LIST *target,T_LIST *source)
+{  
+   UBYTE count=0;
+   for (count=0;count<T_LIST_MAX_SIZE; count++)
+   {
+      target->channels[count] &= ~source->channels[count];
+   }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_trace_freq_in_list     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine traces the frequencies in the list
+            CSI-LLD section:4.1.1.3.11    
+*/
+
+GLOBAL void srv_trace_freq_in_list(T_LIST *list)
+{ 
+  U16 i;
+ 
+  for(i=CHANNEL_0;i<CHANNEL_0_INTERNAL;i++)
+  {
+    if(srv_get_channel (list, i))
+    {
+      TRACE_EVENT_P1("arfcn=%u",i);
+    }
+  } 
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_count_list             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine returns the count of the number of channels 
+            set in the List
+            CSI-LLD section:4.1.1.3.11    
+*/
+
+GLOBAL U16 srv_count_list(T_LIST *list)
+{ 
+  U16 i;
+  U16 sum = 0;
+ 
+  for(i=CHANNEL_0;i<CHANNEL_0_INTERNAL;i++)
+  {
+    if(srv_get_channel (list, i))
+    {
+      sum++;
+    }
+  }
+
+  return sum; 
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_is_list_set            |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine checks if any channel in the list is set
+            CSI-LLD section:4.1.1.3.11    
+*/
+
+GLOBAL BOOL srv_is_list_set(T_LIST *list)
+{ 
+  U8 i;
+ 
+  for(i=0;i<T_LIST_MAX_SIZE;i++)
+  {
+    if(list->channels[i])
+    {
+       return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : RR_SRV                     |
+| STATE   : code                ROUTINE : srv_get_region_from_std    |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine derived "region" from "std" 
+            CSI-LLD section:4.1.1.3.11    
+*/
+GLOBAL U8 srv_get_region_from_std(U8 std)
+{
+#ifdef TI_PS_FF_QUAD_BAND_SUPPORT
+  U8 region = BOTH_REGIONS;
+#else
+  U8 region = EUROPEAN_REGION;
+#endif
+
+  switch(std)
+  {
+    case STD_850:
+    case STD_1900:
+    case STD_DUAL_US:
+      region = AMERICAN_REGION;
+      break;
+#ifdef TI_PS_FF_QUAD_BAND_SUPPORT
+    case STD_900:
+    case STD_1800:
+    case STD_DUAL:
+    case STD_DUAL_EGSM:
+      region = EUROPEAN_REGION;
+      break;
+    default:
+      TRACE_EVENT_P1 ("srv_get_region_from_std: wrong std %x", std);
+      TRACE_ERROR ("srv_get_region_from_std: wrong std");
+      break;
+#endif
+  }
+
+  return region;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)     MODULE  : RR_SRV                       |
+| STATE   : code              ROUTINE : srv_get_region_from_std_arfcn|
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine derived "region" from "std" and "ARFCN"
+*/
+#ifdef TI_PS_FF_QUAD_BAND_SUPPORT
+GLOBAL U8 srv_get_region_from_std_arfcn(U8 std, U16 arfcn)
+{
+  U8 region = EUROPEAN_REGION;
+
+  switch(std)
+  {
+    case STD_850_1800:
+    case STD_850_900_1800:
+      if (INRANGE(LOW_CHANNEL_850,arfcn,HIGH_CHANNEL_850))
+        region = AMERICAN_REGION;
+      else
+        region = EUROPEAN_REGION;
+      break;
+
+    case STD_900_1900:
+      if (INRANGE(LOW_CHANNEL_1900,arfcn,HIGH_CHANNEL_1900))
+        region = AMERICAN_REGION;
+      else
+        region = EUROPEAN_REGION;
+      break;
+
+    case STD_850_900_1900:
+      if (INRANGE(LOW_CHANNEL_1900,arfcn,HIGH_CHANNEL_1900) OR 
+          INRANGE(LOW_CHANNEL_850,arfcn,HIGH_CHANNEL_850))
+        region = AMERICAN_REGION;
+      else
+        region = EUROPEAN_REGION;
+      break;
+    default:
+      TRACE_EVENT_P1 ("srv_get_region_from_std_arfcn: wrong std %x", std);
+      TRACE_ERROR ("srv_get_region_from_std_arfcn: wrong std");
+      break;
+  }
+
+  return region;
+}
+#endif
+
+#endif /* !CL_LIST_C */
+