FreeCalypso > hg > fc-magnetite
diff src/g23m-gprs/grr/grr_csf.c @ 183:219afcfc6250
src/g23m-gprs: initial import from TCS3.2/LoCosto
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 13 Oct 2016 04:24:13 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gprs/grr/grr_csf.c Thu Oct 13 04:24:13 2016 +0000 @@ -0,0 +1,6089 @@ +/* ++----------------------------------------------------------------------------- +| Project : GPRS (8441) +| Modul : GRR ++----------------------------------------------------------------------------- +| 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 implements local functions for service CS of +| entity GRR. ++----------------------------------------------------------------------------- +*/ + +#ifndef GRR_CSF_C +#define GRR_CSF_C +#endif + +#define ENTITY_GRR + +/*==== INCLUDES =============================================================*/ + +#include <stdio.h> +#include <string.h> +#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 "ccdapi.h" /* to get CCD API */ +#include "cnf_grr.h" /* to get cnf-definitions */ +#include "mon_grr.h" /* to get mon-definitions */ +#include "prim.h" /* to get the definitions of used SAP and directions */ +#include "message.h" +#include "grr.h" /* to get the global entity definitions */ +#include "grr_f.h" +#include "grr_ctrls.h" +#include "grr_meass.h" +#include "grr_csf.h" +#include "grr_em.h" /*for Engineering mode*/ + + +/*==== CONST ================================================================*/ +#if defined (REL99) AND defined (TI_PS_FF_EMR) +/* + * Bitmasks + */ +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#endif + +T_NC_DATA* nc_data = NULL; /* pointer to neighbour cell data */ + +const SHORT p_res_off[32] = { -52, /* 0 -> -52 dB */ + -48, /* 1 -> -48 dB */ + -44, /* 2 -> -44 dB */ + -40, /* 3 -> -40 dB */ + -36, /* 4 -> -36 dB */ + -32, /* 5 -> -32 dB */ + -28, /* 6 -> -28 dB */ + -24, /* 7 -> -24 dB */ + -20, /* 8 -> -20 dB */ + -16, /* 9 -> -16 dB */ + -12, /* 10 -> -12 dB */ + -10, /* 11 -> -10 dB */ + - 8, /* 12 -> - 8 dB */ + - 6, /* 13 -> - 6 dB */ + - 4, /* 14 -> - 4 dB */ + - 2, /* 15 -> - 2 dB */ + 0, /* 16 -> 0 dB */ + 2, /* 17 -> 2 dB */ + 4, /* 18 -> 4 dB */ + 6, /* 19 -> 6 dB */ + 8, /* 20 -> 8 dB */ + 10, /* 21 -> 10 dB */ + 12, /* 22 -> 12 dB */ + 16, /* 23 -> 16 dB */ + 20, /* 24 -> 20 dB */ + 24, /* 25 -> 24 dB */ + 28, /* 26 -> 28 dB */ + 32, /* 27 -> 32 dB */ + 36, /* 28 -> 36 dB */ + 40, /* 29 -> 40 dB */ + 44, /* 30 -> 44 dB */ + 48 /* 31 -> 48 dB */ +}; + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +/* +PURPOSE : checks whether the network colour code (ncc) is member + of the ncc permitted field. +*/ +LOCAL const UBYTE ncc_bit_mask[8] = +{ + BIT_0, BIT_1, BIT_2, BIT_3, + BIT_4, BIT_5, BIT_6, BIT_7 +}; +#endif + +#define NC_MODE_LEN 1 +#define NC_RXLEV_SCELL_LEN 6 +#define NC_IF_SCELL_LEN 6 +#define NC_NUM_OF_MEAS_LEN 3 +#define NC_FREQ_N_LEN 6 +#define NC_BSIC_N_LEN 6 +#define NC_RXLEV_N_LEN 6 + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +#define BA_USED_LEN 1 +#define BA_USED_3G_LEN 1 +#define PSI3_CM_LEN 2 +#define PMO_USED_LEN 1 +#endif + +#define GET_NC_RPT_PRD(x) ((0x01<<(x))*480) /* multiple of 480 ms */ + +#define CS_PERIOD_1_SEC 217 /* 1 second defined by */ + /* multiplies of TDMA frames */ +#define MAX_SYNC_FAILED_CNT 3 + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +#define INRANGE(min, x, max) ((unsigned)(x-min) <= (max-min)) +#endif + +#ifdef _TARGET_ + +#define MIN_RXLEV_FOR_SIX_STRGST 4 /* minimum RXLEV value of neighbour cells */ + /* which shall be considered for cell */ + /* re-selection decision */ +#endif /* #ifdef _TARGET_ */ + +#define RXLEV_ACRCY 1000 +#define RXLEV_MAX_NBR ((T_RXLEV_DATA_NBR)(~((T_RXLEV_DATA_NBR)0))) +#define RXLEV_AVG_INVALID 0xFF + +#ifdef TI_PS_FF_QUAD_BAND_SUPPORT +#define CHECK_DUAL_BANDS (std EQ STD_DUAL OR std EQ STD_DUAL_EGSM OR \ + std EQ STD_DUAL_US OR std EQ STD_850_1800 OR \ + std EQ STD_900_1900 OR std EQ STD_850_900_1800 OR \ + std EQ STD_850_900_1900) +#endif + +/*==== GLOBAL VARS ===========================================================*/ + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +EXTERN BOOL use_ba_gprs; +#endif + +/*==== LOCAL VARS ===========================================================*/ + +/*==== PRIVATE FUNCTIONS ====================================================*/ + +LOCAL void cs_trace_nc_mval_lst ( void ); +LOCAL void cs_init_nc_mval ( T_NC_MVAL *mval ); +LOCAL void cs_reorg_nc_mval_lst ( void ); + + +LOCAL BOOL cs_build_meas_rpt ( T_U_MEAS_REPORT *u_meas_report ); + +LOCAL BOOL cs_process_serving_cell_data + ( UBYTE *rxlev_scell, UBYTE *v_i_scell, + UBYTE *i_scell, UBYTE *used_bits, + BOOL *rsc_avail, BOOL *isc_avail ); + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +LOCAL void cs_build_enh_sorted_strng_arfcn_list + (T_ENH_STRNG_ARFCN_LIST *f_bin ); +/* +LOCAL UBYTE cs_sort_arfcns_into_bins + ( T_ENH_STRNG_ARFCN_LIST *p_s_bin, + T_ENH_STRNG_ARFCN_LIST *p_m_bin, + T_ENH_STRNG_ARFCN_LIST *p_r_bin);*/ +LOCAL UBYTE cs_sort_arfcns_into_bins + ( T_ENH_STRNG_ARFCN_LIST *p_s_bin, + T_ENH_STRNG_ARFCN_LIST *p_r_bin); +LOCAL void cs_sort_store_in_desc_order_rxlev + ( T_ENH_STRNG_ARFCN_LIST *p_bin, + T_ENH_STRNG_ARFCN_LIST *p_f_bin); +LOCAL BOOL cs_build_enh_meas_rpt( T_U_ENHNC_MEAS_REPORT *u_enh_meas_report ); + +LOCAL BOOL cs_fill_nc_enh_meas_results + (T_nc_meas_rep_enh *nc_meas_rep_enh); +LOCAL void cs_form_enh_cell_list (void ); +LOCAL void cs_form_ba_bcch_enh_cell_list + (void ); +LOCAL void cs_nc_sort_and_update_emr_info + (void ); +LOCAL void cs_nc_sort_cells_into_bins + (T_ENH_BIN *p_sbin,T_ENH_BIN *p_mbin, + T_ENH_BIN *p_rbin ); +LOCAL void cs_nc_sort_and_store_meas_results + (T_ENH_BIN *p_bin, UBYTE nbr_rpt ); +LOCAL void cs_nc_update_rest_bin + (T_ENH_BIN *p_rbin, + T_ENH_BIN *p_bin, UBYTE nbr_rpt ); +LOCAL UBYTE cs_get_band_index_for_emr + (USHORT arfcn); +LOCAL UBYTE cs_nc_scale_rxlev (void); +#endif + +LOCAL void cs_build_nc_freq_list + ( T_SC_DATABASE *db ); +LOCAL void cs_find_strongest_with_status + ( UBYTE *count, + UBYTE *index, + UBYTE select_status, + UBYTE maximum, + UBYTE limitation ); +LOCAL void cs_consider_multiband + ( UBYTE *count, + UBYTE *index, + UBYTE select_status, + UBYTE maximum ); +LOCAL BOOL cs_update_strongest ( UBYTE cnt_strgst, + UBYTE cnt_candid, + UBYTE *index, + ULONG fn_offset ); +LOCAL void cs_start_t3158 ( T_TIME time ); +LOCAL void cs_set_cnt_nc_six ( UBYTE strgst, + UBYTE candid ); +LOCAL T_TIME cs_get_nc_rpt_prd_idle + ( void ); + +LOCAL void cs_copy_rxlev_from_avg( UBYTE rxlev_avg, + T_CELL *cell ); +LOCAL void cs_reuse_old_cell_rxlev (void); +#if defined (REL99) AND defined (TI_PS_FF_EMR) +LOCAL void cs_build_ba_bcch_nc_freq_list (); +#endif + +/* ++------------------------------------------------------------------------------ +| Function : cs_set_cnt_nc_six ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_set_cnt_nc_six ( UBYTE strgst, UBYTE candid ) +{ + TRACE_FUNCTION( "cs_set_cnt_nc_six" ); + +#if defined FF_EOTD + grr_data->db.cnt_nc_six.strgst = MINIMUM( CS_MAX_STRONG_CARRIER_CR, strgst ); +#else /* #if defined FF_EOTD */ + grr_data->db.cnt_nc_six.strgst = strgst; +#endif /* #if defined FF_EOTD */ + + grr_data->db.cnt_nc_six.candid = candid; + +} /* cs_set_cnt_nc_six() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_meas_rpt ++------------------------------------------------------------------------------ +| Description : This function ... +| +| Parameters : u_meas_report - Pointer to measurement report +| ++------------------------------------------------------------------------------ +*/ +LOCAL BOOL cs_build_meas_rpt ( T_U_MEAS_REPORT *u_meas_report ) +{ + T_NC_ORDER nc_ord = cs_get_network_ctrl_order( TRUE ); + BOOL pbcch_present = grr_is_pbcch_present( ); + UBYTE used_bits; + /* bits currently used for the measurement report */ + UBYTE next_meas_bits = 0; + /* bits used for the next element of the */ + /* measurement result list */ + BOOL is_first_instance; + + T_CS_MEAS_DATA *nmeas = &grr_data->cs_meas; + T_nc_meas_rep *ncmeas_rep = &u_meas_report->nc_meas_rep; + T_nc_meas_s1 *p_mrpt; + T_ncell_info *ncell; + T_NC_MVAL *mval; + UBYTE return_value; + BOOL rsc_avail = FALSE; + BOOL isc_avail = FALSE; +#if defined (REL99) AND defined (TI_PS_FF_EMR) + UBYTE psi3_cm = grr_get_psi3_cm(); +#endif + TRACE_FUNCTION( "cs_build_meas_rpt" ); + + /* process message type */ + used_bits = PMR_MSG_TYPE_LEN; + u_meas_report->msg_type = U_MEAS_REPORT_c; + + /* process TLLI */ + used_bits += PMR_TLLI_LEN; + grr_set_buf_tlli( &u_meas_report->tlli_value, grr_get_tlli( ) ); + + /* process PSI5 change mark */ + used_bits += PMR_FLAG_LEN; + + if( pbcch_present EQ FALSE OR + grr_data->db.nc_ref_lst.param EQ &psc_db->nc_ms.ncmeas.param ) + { + u_meas_report->v_psi5_cm = FALSE; + } + else if( grr_data->db.nc_ref_lst.param EQ &psc_db->nc_cw.param ) + { + used_bits += PMR_PSI5_CHNGE_MRK_LEN; + + u_meas_report->v_psi5_cm = TRUE; + u_meas_report->psi5_cm = psc_db->psi5_params.psi5_change_mark; + } + else + { + TRACE_ERROR( "cs_build_meas_rpt no valid data set" ); + return( FALSE ); + } + + /* process flags */ + used_bits += PMR_FLAG_LEN; + u_meas_report->flag = 0; + u_meas_report->v_nc_meas_rep = TRUE; + u_meas_report->v_xmeas_rep = FALSE; + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + /*if(psc_db->network_rel NEQ BSS_NW_REL_97)*/ + { + used_bits += PMR_FLAG_LEN; + u_meas_report->v_release_99_str_pmr = TRUE; + + used_bits += PMR_FLAG_LEN; + u_meas_report->release_99_str_pmr.v_meas_rep_3g_str = FALSE; + + used_bits += PMR_FLAG_LEN; + u_meas_report->release_99_str_pmr.v_ba_psi3_str = TRUE; + + used_bits += PMO_IND_USED_LEN; + u_meas_report->release_99_str_pmr.ba_psi3_str.pmo_ind_used = psc_db->nc_ms.pmo_ind; + + /* 1 bit for u_meas_report->ba_psi3_str.flag */ + used_bits += PMR_FLAG_LEN; + + /* process BA used, PSI3 change mark and PMO used */ + if( pbcch_present EQ FALSE ) + { + TRACE_EVENT_P1("pbcch_present %d", pbcch_present); + u_meas_report->release_99_str_pmr.ba_psi3_str.flag = FALSE; + + u_meas_report->release_99_str_pmr.ba_psi3_str.v_ba_ind_used = TRUE; + u_meas_report->release_99_str_pmr.ba_psi3_str.v_ba_ind_used_3g = TRUE; + + used_bits += PMR_BA_IND_USED_LEN; + u_meas_report->release_99_str_pmr.ba_psi3_str.ba_ind_used = psc_db->ba_ind; + + /* Add 1 bit for ba_ind_used_3g */ + u_meas_report->release_99_str_pmr.ba_psi3_str.ba_ind_used_3g = 0; + used_bits += PMR_BA_IND_USED_LEN; + } + else + { + u_meas_report->release_99_str_pmr.ba_psi3_str.flag = TRUE; + + u_meas_report->release_99_str_pmr.ba_psi3_str.v_psi3_cm = TRUE; + + used_bits += PMR_PSI3_CHNGE_MRK_LEN; + u_meas_report->release_99_str_pmr.ba_psi3_str.psi3_cm = psi3_cm; + } + } +#endif + + /* process NC mode */ + used_bits += NC_MODE_LEN; + + switch( nc_ord ) + { + case NC_NC1: ncmeas_rep->nc_mode = NCMODE_NC1; break; + case NC_NC2: ncmeas_rep->nc_mode = NCMODE_NC2; break; + + default: TRACE_ERROR( "cs_build_meas_rpt no valid NC mode" ); return( FALSE ); + } + + /* process serving cell data - rxlev and ilev */ + + return_value = + cs_process_serving_cell_data(&ncmeas_rep->rxlev_scell, + &ncmeas_rep->v_i_scell, + &ncmeas_rep->i_scell, &used_bits, + &rsc_avail, &isc_avail); + if((return_value EQ FALSE) AND (rsc_avail EQ FALSE)) + return(FALSE); + + + /* process NC measurement results */ + used_bits += NC_NUM_OF_MEAS_LEN; + ncmeas_rep->num_nc_meas = 0; + ncmeas_rep->c_nc_meas_s1 = 0; + is_first_instance = nmeas->pmr_snd_ref EQ 0 ? TRUE : FALSE; + + do + { + /* calculate estimated length of next measurement result */ + if( nmeas->pmr_snd_ref >= grr_data->db.cnt_nc_six.candid ) + { + mval = NULL; + ncell = NULL; + } + else + { + mval = &grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[nmeas->pmr_snd_ref].idx]; + + next_meas_bits = NC_FREQ_N_LEN + NC_RXLEV_N_LEN + PMR_FLAG_LEN; + + if( mval->sync_info.sync.status EQ STAT_SYNC_OK ) + { + UBYTE ncell_idx = 0; + + ncell = grr_get_ncell_info( mval->arfcn, mval->sync_info.bsic ); + + while( ncell_idx < grr_data->db.nc_ref_lst.number AND + ncell EQ NULL ) + { + ncell = grr_data->db.nc_ref_lst.info[ncell_idx]; + + if( ncell->arfcn NEQ mval->arfcn OR + NC_GET_TYPE( ncell->info_src ) NEQ INFO_TYPE_BA_BCCH ) + { + ncell = NULL; + } + + ncell_idx++; + } + + if( ncell NEQ NULL ) + { + next_meas_bits = NC_FREQ_N_LEN + NC_RXLEV_N_LEN + PMR_FLAG_LEN; + + if( NC_GET_TYPE( ncell->info_src ) EQ INFO_TYPE_BA_BCCH ) + { + next_meas_bits += NC_BSIC_N_LEN; + } + } + } + else + { + ncell = NULL; + } + } + + if( ncell NEQ NULL AND mval NEQ NULL) + { + if( BIT_UL_CTRL_BLOCK_CONTENTS - used_bits >= next_meas_bits ) + { + /* copy next measurement result to measurement report */ + + ncmeas_rep->num_nc_meas++; + ncmeas_rep->c_nc_meas_s1++; + used_bits += next_meas_bits; + p_mrpt = &ncmeas_rep->nc_meas_s1[ncmeas_rep->c_nc_meas_s1 - 1]; + + p_mrpt->freq_n = ncell->index; + p_mrpt->rxlev_n = mval->rxlev_avg; + + if( NC_GET_TYPE( ncell->info_src ) EQ INFO_TYPE_BA_BCCH ) + { + p_mrpt->bsic = mval->sync_info.bsic; + p_mrpt->v_bsic = TRUE; + } + else + { + p_mrpt->v_bsic = FALSE; + } + + nmeas->pmr_snd_ref++; + } + else + { + mval = NULL; + } + } + else + { + nmeas->pmr_snd_ref++; + } + + } + while( mval NEQ NULL ); + + return( is_first_instance OR ncmeas_rep->num_nc_meas ); + + +} /* cs_build_meas_rpt() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_is_meas_reporting ++------------------------------------------------------------------------------ +| Description : This function ... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL UBYTE cs_is_meas_reporting ( void ) +{ + T_NC_ORDER ctrl_order = cs_get_network_ctrl_order( TRUE ); + + TRACE_FUNCTION( "cs_is_meas_reporting" ); + + return( ctrl_order EQ NC_NC1 OR ctrl_order EQ NC_NC2 ); + +} /* cs_is_meas_reporting() */ + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +/* ++------------------------------------------------------------------------------ +| Function : cs_is_enh_meas_reporting ++------------------------------------------------------------------------------ +| Description : This function is used to check whether enhanced measurement +| reporting is to be done. +| +| Parameters : returns TRUE if ENH reporting is to be done +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_is_enh_meas_reporting ( void ) +{ + BOOL return_value = FALSE; + + TRACE_FUNCTION( "cs_is_enh_meas_reporting" ); + + if ( cs_is_meas_reporting() AND + (grr_data->db.nc_ref_lst.enh_param->rept_type EQ REPORT_TYPE_ENH_REP) ) + { + return_value = TRUE; + } + + return( return_value ); +} /* cs_is_enh_meas_reporting() */ +#endif + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_nc_freq_list ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : db - pointer to serving cell database +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_build_nc_freq_list ( T_SC_DATABASE *db ) +{ + UBYTE i, j, k; /* used for counting */ + UBYTE act_idx; /* index of actual processed reference list entry */ + BOOL is_removed; + BOOL is_overwritten; + + T_ncell_info *info_ref_lst; + T_ncell_info *info_prev = ( db->nc_cw.list.number EQ 0 ? + NULL : + &db->nc_cw.list.info[db->nc_cw.list.number-1] ); + T_ncell_info *info_curr; + T_INFO_SRC info_src = 0; + + TRACE_FUNCTION( "cs_build_nc_freq_list" ); + + /* + * add neighbour cell information of BA(GPRS) to reference list + * in case they are not removed + */ + for( i = 0; i < db->nc_cw.list.number; i++ ) + { + /* + * looking for entry with correct index, + * they are no longer sorted with increasing number + */ + k = 0; + + while( k < db->nc_cw.list.number AND i NEQ db->nc_cw.list.info[k].index ) + { + k++; + } + + if( db->nc_cw.list.info[k].arfcn EQ psc_db->pbcch.bcch.arfcn ) + { + /* remove the serving cell from the neighbour cell reference list */ + is_removed = TRUE; + } + else + { + for( j = 0, is_removed = FALSE; + j < db->nc_ms.rfreq.number AND is_removed EQ FALSE; + j++ ) + { + if( db->nc_cw.list.info[k].index EQ db->nc_ms.rfreq.idx[j] ) + { + is_removed = TRUE; + } + } + } + + if( is_removed EQ FALSE ) + { + if( !( db->nc_cw.list.info[k].v_cr_par EQ FALSE AND + NC_GET_TYPE( db->nc_cw.list.info[k].info_src ) NEQ INFO_TYPE_BA_BCCH AND + cs_get_network_ctrl_order( TRUE ) NEQ NC_NC2 ) + AND + !( db->nc_cw.list.info[k].cr_par.cell_ba ) ) + { + grr_data->db.nc_ref_lst.info[grr_data->db.nc_ref_lst.number] = + &db->nc_cw.list.info[k]; + grr_data->db.nc_ref_lst.number++; + } + else + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P2( "cs_build_nc_freq_list 1: not added to NC_REF_LST %d %d", + db->nc_cw.list.info[k].arfcn, db->nc_cw.list.info[k].bsic ); + } + +#endif /* #if !defined (NTRACE) */ + + } + } + else + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P2( "cs_build_nc_freq_list 2: not added to NC_REF_LST %d %d", + db->nc_cw.list.info[k].arfcn, db->nc_cw.list.info[k].bsic ); + } + +#endif /* #if !defined (NTRACE) */ + + + } + } + + /* + * add/overwrite neighbour cell information to/of reference list + */ + i = 0; + + while( ( info_curr = grr_get_next_bigger_ncell_param + ( &db->nc_ms.ncmeas.list, info_src ) ) NEQ NULL ) + { + j = 0; + is_overwritten = FALSE; + + while( j < grr_data->db.nc_ref_lst.number AND is_overwritten EQ FALSE ) + { + info_ref_lst = grr_data->db.nc_ref_lst.info[j]; + + if( NC_GET_TYPE( info_ref_lst->info_src ) NEQ INFO_TYPE_BA_BCCH AND + info_ref_lst->v_cr_par EQ TRUE AND + info_curr->v_cr_par EQ TRUE AND + info_ref_lst->bsic EQ info_curr->bsic AND + info_ref_lst->arfcn EQ info_curr->arfcn ) + { + is_overwritten = TRUE; + } + else + { + j++; + } + } + + /* + * calculate the index of the reference list entry + * which shall be used for further processing + */ + if( is_overwritten EQ FALSE ) + { + if( grr_data->db.nc_ref_lst.number < MAX_NR_OF_NCELL ) + { + act_idx = grr_data->db.nc_ref_lst.number; + } + else + { + TRACE_ERROR( "cs_build_nc_freq_list: reference list full" ); + return; + } + } + else + { + act_idx = j; + } + + + if( + !( info_curr->v_cr_par EQ FALSE AND + NC_GET_TYPE( info_curr->info_src ) NEQ INFO_TYPE_BA_BCCH AND + cs_get_network_ctrl_order( TRUE ) NEQ NC_NC2 ) + AND + !( info_curr->cr_par.cell_ba ) + AND + ( info_curr->arfcn NEQ psc_db->pbcch.bcch.arfcn ) + ) + { + /* + * add/overwrite reference list entry + */ + grr_data->db.nc_ref_lst.info[act_idx] = info_curr; + grr_data->db.nc_ref_lst.number++; + + /* process cell selection parameter */ + grr_restore_cs_param + ( info_curr, info_prev, (UBYTE)( db->nc_cw.list.number + i ) ); + + + if( info_curr->v_cr_par EQ TRUE ) + { + info_prev = info_curr; + } + } + else + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P2( "cs_build_nc_freq_list 3: not added to NC_REF_LST %d %d", + info_curr->arfcn, info_curr->bsic ); + } + +#endif /* #if !defined (NTRACE) */ + + info_curr->index = db->nc_cw.list.number + i; + } + + info_src = info_curr->info_src; + + i++; + } + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + UBYTE read; + USHORT crp_s; + ULONG crp[4]; + T_ncell_info *info; + + crp[0] = ( ( ULONG )psc_db->pbcch.bcch.arfcn << 16 ); + crp[0] |= ( ( ULONG )psc_db->pbcch.bcch.bsic << 8 ); + crp[0] |= ( ULONG )psc_db->scell_par.cell_ba; + + crp[1] = ( ( ULONG )psc_db->scell_par.exc_acc << 24 ); + crp[1] |= ( ( ULONG )psc_db->scell_par.cr_par_1.cr_pow_par.gprs_rxlev_access_min << 16 ); + crp[1] |= ( ( ULONG )psc_db->scell_par.cr_par_1.cr_pow_par.gprs_ms_txpwr_max_cch << 8 ); + + if( psc_db->scell_par.cr_par_1.v_hcs_par ) + { + crp[1] |= ( ULONG )psc_db->scell_par.cr_par_1.hcs_par.gprs_prio_class; + crp_s = ( ( USHORT )psc_db->scell_par.cr_par_1.hcs_par.gprs_hcs_thr << 8 ); + } + else + { + crp[1] |= ( ULONG )0xFF; + crp_s = ( ( USHORT )0xFF << 8 ); + } + + crp_s |= ( ULONG )psc_db->scell_par.multi_band_rep; + + TRACE_EVENT_P3( "SCELL %08X%08X%04X", crp[0], crp[1], crp_s ); + + for( read = 0; read < grr_data->db.nc_ref_lst.number; read++ ) + { + info = grr_data->db.nc_ref_lst.info[read]; + + crp[0] = ( ( ULONG )info->arfcn << 16 ); + crp[0] |= ( ( ULONG )info->bsic << 8 ); + + if( info->v_cr_par ) + { + crp[0] |= ( ULONG )info->cr_par.cell_ba; + + crp[1] = ( ( ULONG )info->cr_par.exc_acc << 24 ); + crp[1] |= ( ( ULONG )info->cr_par.same_ra_scell << 16 ); + crp[1] |= ( ( ULONG )info->cr_par.cr_par_1.cr_pow_par.gprs_rxlev_access_min << 8 ); + crp[1] |= ( ULONG )info->cr_par.cr_par_1.cr_pow_par.gprs_ms_txpwr_max_cch; + + crp[2] = ( ( ULONG )info->cr_par.cr_offset.gprs_temp_offset << 24 ); + crp[2] |= ( ( ULONG )info->cr_par.cr_offset.gprs_penalty_time << 16 ); + crp[2] |= ( ( ULONG )info->cr_par.gprs_resel_off << 8 ); + + if( grr_data->db.nc_ref_lst.info[read]->cr_par.cr_par_1.v_hcs_par ) + { + crp[2] |= ( ULONG )info->cr_par.cr_par_1.hcs_par.gprs_prio_class; + crp[3] = ( ( ULONG )info->cr_par.cr_par_1.hcs_par.gprs_hcs_thr << 24 ); + } + else + { + crp[2] |= ( ULONG )0xFF; + crp[3] = ( ( ULONG )0xFF << 24 ); + } + + if( info->cr_par.v_si13_pbcch ) + { + if( info->cr_par.si13_pbcch.v_si13_location ) + { + crp[3] |= ( ( ULONG )info->cr_par.si13_pbcch.si13_location << 16 ); + crp[3] |= ( ( ULONG )0xFF << 8 ); + crp[3] |= ( ULONG )0xFF; + } + else + { + crp[3] |= ( ( ULONG )0xFF << 16 ); + crp[3] |= ( ( ULONG )info->cr_par.si13_pbcch.pbcch_location << 8 ); + crp[3] |= ( ULONG )info->cr_par.si13_pbcch.psi1_repeat_period; + } + } + else + { + crp[3] |= ( ULONG )0xFFFFFF; + } + } + else + { + crp[1] |= ( ULONG )0xFF; + crp[2] = ( ULONG )0xFFFFFFFF; + crp[3] = ( ULONG )0xFFFFFFFF; + } + + TRACE_EVENT_P5( "NC_REF_LST[%d] %08X%08X%08X%08X", + read, crp[0], crp[1], crp[2], crp[3] ); + } + } + +#endif /* #if !defined (NTRACE) */ + +}/* cs_build_nc_freq_list */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_reorg_nc_mval_lst ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_reorg_nc_mval_lst ( void ) +{ + BOOL scell_restored = FALSE; + UBYTE mval_idx; + UBYTE nc_idx; + T_NC_MVAL *nc_mval; + T_ncell_info *ncell_info; + + TRACE_FUNCTION( "cs_reorg_nc_mval_lst" ); + + for( mval_idx = 0; mval_idx < MAX_NR_OF_NC_MVAL; mval_idx++ ) + { + /* + * check whether measured values can be reused + */ + + nc_mval = &grr_data->db.nc_mval_list.nc_mval[mval_idx]; + + if( nc_mval->status NEQ NC_MVAL_STAT_NONE ) + { + /* + * only used entries shall be considered + */ + + if( psc_db->pbcch.bcch.arfcn EQ nc_mval->arfcn AND + psc_db->pbcch.bcch.arfcn NEQ RRGRR_INVALID_ARFCN ) + { + /* + * remove the measured values from the serving cell, + * this cell will not be used for cell re-selection + */ + cs_init_nc_mval( nc_mval ); + } + else + { + ncell_info = grr_get_ncell_info( nc_mval->arfcn, RRGRR_INVALID_BSIC ); + + if( ncell_info EQ NULL ) + { + /* + * cell is not on the neighbor cell list, + * keep the measured values until RR informs GRR, + * but do not use them + */ + nc_mval->status = NC_MVAL_STAT_PENDING; + nc_mval->rla_p.stat = CS_RLA_P_NOT_AVAIL; + } + else + { + /* + * cell is on the neighbor cell list, + * re-activate the measured values + */ + nc_mval->status = NC_MVAL_STAT_ASSIGNED; + } + + if( grr_data->db.old_scell.arfcn EQ nc_mval->arfcn AND + grr_data->db.old_scell.arfcn NEQ RRGRR_INVALID_ARFCN ) + { + /* + * in case the old serving cell is on the measured values list, + * keep the results for further use + */ + scell_restored = TRUE; + + nc_mval->sync_info.bsic = grr_data->db.old_scell.bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + } + } + } + } + + for( nc_idx = 0; nc_idx < grr_data->db.nc_ref_lst.number; nc_idx++ ) + { + nc_mval = grr_get_nc_mval( grr_data->db.nc_ref_lst.info[nc_idx]->arfcn, + RRGRR_INVALID_BSIC, &mval_idx ); + + if( nc_mval EQ NULL ) + { + nc_mval = + grr_get_nc_mval( RRGRR_INVALID_ARFCN, RRGRR_INVALID_BSIC, &mval_idx ); + + if( nc_mval NEQ NULL ) + { + nc_mval->status = NC_MVAL_STAT_ASSIGNED; + nc_mval->arfcn = grr_data->db.nc_ref_lst.info[nc_idx]->arfcn; + + if( grr_data->db.old_scell.arfcn EQ nc_mval->arfcn AND + grr_data->db.old_scell.arfcn NEQ RRGRR_INVALID_ARFCN ) + { + scell_restored = TRUE; + + nc_mval->sync_info.bsic = grr_data->db.old_scell.bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + + TRACE_EVENT_P2( "cs_reorg_nc_mval_lst: old SCELL on new NCELL list (1) %d %d", + grr_data->db.nc_ref_lst.info[nc_idx]->arfcn, + grr_data->db.nc_ref_lst.info[nc_idx]->bsic ); + } + } + else + { + TRACE_EVENT_P1( "cs_reorg_nc_mval_lst: nc_mval EQ NULL (1) %d", + RRGRR_INVALID_ARFCN ); + } + } + else + { + if( grr_data->db.old_scell.arfcn EQ nc_mval->arfcn AND + grr_data->db.old_scell.arfcn NEQ RRGRR_INVALID_ARFCN ) + { + scell_restored = TRUE; + + nc_mval->status = NC_MVAL_STAT_ASSIGNED; + nc_mval->sync_info.bsic = grr_data->db.old_scell.bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + + TRACE_EVENT_P2( "cs_reorg_nc_mval_lst: old SCELL on new NCELL list (2) %d %d", + grr_data->db.nc_ref_lst.info[nc_idx]->arfcn, + grr_data->db.nc_ref_lst.info[nc_idx]->bsic ); + } + } + } + + if( scell_restored EQ FALSE AND + grr_data->db.old_scell.arfcn NEQ RRGRR_INVALID_ARFCN ) + { + nc_mval = + grr_get_nc_mval( RRGRR_INVALID_ARFCN, RRGRR_INVALID_BSIC, &mval_idx ); + + if( nc_mval NEQ NULL ) + { + nc_mval->status = NC_MVAL_STAT_PENDING; + nc_mval->arfcn = grr_data->db.old_scell.arfcn; + nc_mval->sync_info.bsic = grr_data->db.old_scell.bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + } + else + { + TRACE_EVENT_P1( "cs_reorg_nc_mval_lst: nc_mval EQ NULL (2) %d", + RRGRR_INVALID_ARFCN ); + } + } + + grr_data->cs.is_mval_initialized = FALSE; + + cs_trace_nc_mval_lst( ); + +}/* cs_reorg_nc_mval_lst */ + +/*==== PUBLIC FUNCTIONS =====================================================*/ +/* ++------------------------------------------------------------------------------ +| Function : cs_grr_init ++------------------------------------------------------------------------------ +| Description : The function cs_grr_init() .... name change becauce there is a +| function in cs_init in TIL. +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_grr_init ( void ) +{ + TRACE_FUNCTION( "cs_grr_init" ); + + grr_data->cs.gmm_state = STANDBY_STATE; + grr_data->cs.last_cr = 0; + grr_data->cs.reselect_cause = CS_RESELECT_CAUSE_CS_NORMAL; + grr_data->cs.is_mval_initialized = FALSE; + grr_data->cs.nc_sync_rep_pd = 0; + +#if !defined (NTRACE) + + grr_data->cs.v_crp_trace = FALSE; + +#endif /* #if !defined (NTRACE) */ + + grr_init_ncmeas_extd_struct( &psc_db->nc_ms, FALSE ); + cs_init_nc_ref_list( &grr_data->db.nc_ref_lst ); + cs_init_nc_mval_lst( ); + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + /* Initialize Enhanced Measurement parameters and list */ + grr_init_enh_param(&psc_db->enh_ms, TRUE); + grr_init_enh_cell_list(); +#endif + + grr_data->cs_meas.pmr_snd_ref = 0; + grr_data->cs_meas.packet_mode = PACKET_MODE_NULL; + + nc_data = &grr_data->nc_data; + + cs_reset_all_cell_results( ); + + grr_data->cs.list_id = 0; + grr_data->cs.stop_req = FALSE; + + nc_data->c_cell = 0; + + grr_data->cs.cr_meas_mode = CS_CRMM_BA_GPRS; + grr_data->cs.cr_meas_update = FALSE; + grr_data->cs.last_assignment_id = 0; + + + INIT_STATE( CS_MEAS, CS_MEAS_NULL ); + INIT_STATE( CS, CS_NULL ); +} /* cs_grr_init() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_process_cc_order ++------------------------------------------------------------------------------ +| Description : The function cs_process_cc_order() .... +| +| Parameters : d_cell_chan_order - Pointer to packet cell change order message +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_process_cc_order ( T_nc_meas_par *nc_meas_par, + UBYTE v_nc_freq_list, + T_nc_freq_list *nc_freq_list +#if defined (REL99) AND defined (TI_PS_FF_EMR) + , UBYTE v_enh_meas_param_pcco, + T_enh_meas_param_pcco *enh_meas_param_pcco +#endif + ) +{ + TRACE_FUNCTION( "cs_process_cc_order" ); + + grr_init_ncmeas_extd_struct( &pcr_db->nc_ms, FALSE ); + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + /* Initialize Enhanced Measurement parameters */ + grr_init_enh_param(&pcr_db->enh_ms, TRUE); +#endif + + /* + * process the NC measurement parameter + * + * only one instance of PCCO, store data in final location + */ + grr_prcs_nc_param_struct ( &pcr_db->nc_ms.ncmeas.param, + nc_meas_par, + 0 ); + + /* For PCCO the paramater obtained in PCCO should be applied immediately + Sec 5.6.1 Spec 4.60 */ + grr_data->db.nc_ref_lst.param = &pcr_db->nc_ms.ncmeas.param; + + /* + * process NC_FREQUENCY_LIST + * + * only one instance of PCCO, store data in final location + */ + grr_prcs_nc_freq_list ( &pcr_db->nc_ms.ncmeas.list, + &pcr_db->nc_ms.rfreq, + v_nc_freq_list, + nc_freq_list, + INFO_TYPE_PCCO, + 0 ); + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + /* + * process the ENH measurement parameter + * + * only one instance of PCCO, store data in final location + */ + if(v_enh_meas_param_pcco) + { + grr_prcs_enh_param_pcco ( pcr_db, enh_meas_param_pcco ); + } +#endif + +} /* cs_process_cc_order() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_calc_cr_criterion ++------------------------------------------------------------------------------ +| Description : The function cs_calc_cr_criterion() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_calc_cr_criterion ( T_CR_CRITERIONS *cr_crit, + USHORT arfcn, + T_rla_p *rla_p, + T_CR_PAR_1 *cr_par_1 ) +{ + T_MS_PWR_CAP mspc; + SHORT A, B; + + TRACE_FUNCTION( "cs_calc_cr_criterion" ); + + /* C1 = A - MAX(B,0) */ + /* A = RLA_P - GPRS_RXLEV_ACCESS_MIN */ + /* B = GPRS_MS_TXPWR_MAX_CCH - P */ + /* P = max MS RF output power */ + + /* C31 = RLA_P(s) - HCS_THR(s) (serving cell) */ + /* C31 = RLA_P(n) - HCS_THR(n) - TO(n)*L(n) (neighbour cell) */ + /* TO(n) = GPRS_TEMPORARY_OFFSET(n) * H( GPRS_PENALTY_TIME(N) - T(n) ) */ + /* L(n) = 0 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* 1 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + + /* C32(s) = C1(s) */ + /* C32(n) = C1(n) + GPRS_RESELECT OFFSET(n) - TO(n)*(1-L(n)) */ + /* TO(n) = GPRS_TEMPORARY_OFFSET(n) * H( GPRS_PENALTY_TIME(N) - T(n) ) */ + /* L(n) = 0 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* 1 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* H(n) = 0 for x < 0 */ + /* 1 for x >= 0 */ + /* T(n) = ????? */ + + grr_get_ms_pwr_cap( arfcn, grr_data->meas.pwr_offset, &mspc ); + + /* + * calculate cell re-selection criteria acc. GSM05.08, + * chapter 10.1.2 for the serving/neighbour cell + */ + + /* intermediate results for serving/neighbour cell */ + A = (SHORT)rla_p->lev - (SHORT)cr_par_1->cr_pow_par.gprs_rxlev_access_min; + B = mspc.p_control[cr_par_1->cr_pow_par.gprs_ms_txpwr_max_cch] - mspc.p[mspc.ms_power]; + + /* path loss criterion for serving/neighbour cell */ + cr_crit->c1 = A - MAXIMUM( B, 0 ); + + /* signal threshold criterion for serving/neighbour cell */ + cr_crit->c31 = ( SHORT )rla_p->lev; + + if( cr_par_1->v_hcs_par ) + { + cr_crit->c31 -= ( 2 * cr_par_1->hcs_par.gprs_hcs_thr ); + } + + /* cell ranking criterion for serving/neighbour cell */ + cr_crit->c32 = cr_crit->c1; + +} /* cs_calc_cr_criterion() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_calc_params ++------------------------------------------------------------------------------ +| Description : The function cs_calc_params() .... +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_calc_params ( void ) +{ + BOOL prio_cr = FALSE; + UBYTE h; + UBYTE i, prios, prion, strgst = 0xFF; + T_ncell_info *ncell_info; + T_NC_MVAL *nc_mval; + + TRACE_FUNCTION( "cs_calc_params" ); + + /* C1 = A - MAX(B,0) */ + /* A = RLA_P - GPRS_RXLEV_ACCESS_MIN */ + /* B = GPRS_MS_TXPWR_MAX_CCH - P */ + /* P = max MS RF output power */ + + /* C31 = RLA_P(s) - HCS_THR(s) (serving cell) */ + /* C31 = RLA_P(n) - HCS_THR(n) - TO(n)*L(n) (neighbour cell) */ + /* TO(n) = GPRS_TEMPORARY_OFFSET(n) * H( GPRS_PENALTY_TIME(N) - T(n) ) */ + /* L(n) = 0 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* 1 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + + /* C32(s) = C1(s) */ + /* C32(n) = C1(n) + GPRS_RESELECT OFFSET(n) - TO(n)*(1-L(n)) */ + /* TO(n) = GPRS_TEMPORARY_OFFSET(n) * H( GPRS_PENALTY_TIME(N) - T(n) ) */ + /* L(n) = 0 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* 1 if PRIORITY_CLASS(n) = PRIORITY_CLASS(s) */ + /* H(n) = 0 for x < 0 */ + /* 1 for x >= 0 */ + /* T(n) = ????? */ + + cs_calc_cr_criterion( &grr_data->db.scell_info.cr_crit, + psc_db->pbcch.bcch.arfcn, + &grr_data->db.scell_info.rla_p, + &psc_db->scell_par.cr_par_1 ); + + /* priority class for serving cell */ + prios = ( psc_db->scell_par.cr_par_1.v_hcs_par ) ? + psc_db->scell_par.cr_par_1.hcs_par.gprs_prio_class : 0; + + /* + * calculate cell re-selection criteria acc. GSM05.08, + * chapter 10.1.2 for the neighbour cells + */ + for( i = 0; i < grr_data->db.cnt_nc_six.strgst; i++ ) + { + h = FALSE; + nc_mval = &grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx]; + + if( nc_mval->sync_info.sync.status EQ STAT_SYNC_OK ) + { + ncell_info = + grr_get_ncell_info( nc_mval->arfcn, nc_mval->sync_info.bsic ); + + if( ncell_info NEQ NULL ) + { + cs_calc_cr_criterion( &grr_data->db.nc_six_strgst[i].cr_crit, + ncell_info->arfcn, + &nc_mval->rla_p, + &ncell_info->cr_par.cr_par_1 ); + + /* cell ranking criterion for neighbour cell, add GPRS_RESELECT_OFFSET */ + + /* + * if the parameter C32_QUAL is set, positive GPRS_RESELECT_OFFSET values + * shall only be applied to the neighbour cell with the highest RLA_P value + * of those cells for which C32 is compared. + * + * calculation part 1 + */ + if( psc_db->gen_cell_par.c32_qual EQ FALSE OR + p_res_off[ncell_info->cr_par.gprs_resel_off] < 0 ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c32 += + p_res_off[ncell_info->cr_par.gprs_resel_off]; + } + + /* priority class of neighbour cell */ + prion = ( ncell_info->cr_par.cr_par_1.v_hcs_par ) ? + ncell_info->cr_par.cr_par_1.hcs_par.gprs_prio_class : 0; + + /* check whether GPRS_TEMPORARY_OFFSET shall be considered */ + if( (ULONG)( ( ncell_info->cr_par.cr_offset.gprs_penalty_time + 1 ) * + 10 * CS_PERIOD_1_SEC ) > grr_data->db.nc_six_strgst[i].avail_time ) + { + h = TRUE; + } + + /* + * cell ranking and signal threshold criterion for neighbour cell, + * subtract GPRS_TEMPORARY_OFFSET + */ + if( h ) + { + SHORT *criterion; + + if( prios NEQ prion ) + { + criterion = &grr_data->db.nc_six_strgst[i].cr_crit.c31; + } + else + { + criterion = &grr_data->db.nc_six_strgst[i].cr_crit.c32; + } + + if( ncell_info->cr_par.cr_offset.gprs_temp_offset EQ + GPRS_TEMPORARY_OFFSET_INFINITY ) + { + *criterion = CS_SMALLEST_SHORT_VALUE; + } + else + { + *criterion -= 10 * ncell_info->cr_par.cr_offset.gprs_temp_offset; + } + } + + /* + * cell ranking and signal threshold criterion for neighbour cell, + * subtract RA_RESELECT_HYSTERESIS and/or GPRS_CELL_RESELECT_HYSTERESIS + */ + if( !ncell_info->cr_par.same_ra_scell ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c32 -= + 2 * psc_db->gen_cell_par.ra_re_hyst; + } + else if( grr_data->cs.gmm_state NEQ STANDBY_STATE ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c32 -= + 2 * psc_db->gen_cell_par.gprs_c_hyst; + + if( psc_db->gen_cell_par.c31_hyst ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c31 -= + 2 * psc_db->gen_cell_par.gprs_c_hyst; + } + } + + /* + * in case a cell re-selection occured within the + * previous 15 seconds, subtract 5 dB + */ + if(grr_t_status( T15_SEC_CC ) > 0) + { + grr_data->db.nc_six_strgst[i].cr_crit.c32 -= 5; + } + } + else + { + grr_data->db.nc_six_strgst[i].cr_crit.c1 = -2; + grr_data->db.nc_six_strgst[i].cr_crit.c31 = -2; + grr_data->db.nc_six_strgst[i].cr_crit.c32 = -2; + } + } + else + { + grr_data->db.nc_six_strgst[i].cr_crit.c1 = -1; + grr_data->db.nc_six_strgst[i].cr_crit.c31 = -1; + grr_data->db.nc_six_strgst[i].cr_crit.c32 = -1; + } + } + + /* + * calculate the correct neighbour cell for adding positive + * GPRS_RESELECT_OFFSET values to C32 in case C32_QUAL is set + */ + if( psc_db->gen_cell_par.c32_qual EQ TRUE ) + { + /* + * check whether priorized cell re-selection should be performed + */ + for( i = 0; i < grr_data->db.cnt_nc_six.strgst; i++ ) + { + if( grr_data->db.nc_six_strgst[i].cr_crit.c31 >= 0 ) + { + prio_cr = TRUE; + } + } + + if( grr_data->db.scell_info.cr_crit.c31 >= 0 ) + { + prio_cr = TRUE; + } + + /* find out the strongest neighbour cell */ + for( i = 0; i < grr_data->db.cnt_nc_six.strgst; i++ ) + { + if( ( prio_cr AND grr_data->db.nc_six_strgst[i].cr_crit.c31 >= 0 ) OR + ( !prio_cr ) ) + { + if( strgst EQ 0xFF OR + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].rla_p.lev > + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[strgst].idx].rla_p.lev ) + { + strgst = i; + } + } + } + + if( strgst NEQ 0xFF ) + { + nc_mval = &grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[strgst].idx]; + + if( nc_mval->sync_info.sync.status EQ STAT_SYNC_OK ) + { + ncell_info = + grr_get_ncell_info( nc_mval->arfcn, nc_mval->sync_info.bsic ); + + if( ncell_info NEQ NULL ) + { + /* + * if the parameter C32_QUAL is set, positive GPRS_RESELECT_OFFSET values + * shall only be applied to the neighbour cell with the highest RLA_P value + * of those cells for which C32 is compared. + * + * calculation part 2 + */ + + if( p_res_off[ncell_info->cr_par.gprs_resel_off] > 0 ) + { + grr_data->db.nc_six_strgst[strgst].cr_crit.c32 += + p_res_off[ncell_info->cr_par.gprs_resel_off]; + } + } + } + } + } + + /* + * perform some tracing + */ + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + /* trace the C1 criterion */ + for( i = grr_data->db.cnt_nc_six.strgst; i < CS_MAX_STRONG_CARRIER; i++ ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c1 = 0; + } + + TRACE_EVENT_P7 + ( + "C1 : %6d %6d %6d %6d %6d %6d %6d", + grr_data->db.scell_info.cr_crit.c1, + grr_data->db.nc_six_strgst[0].cr_crit.c1, + grr_data->db.nc_six_strgst[1].cr_crit.c1, + grr_data->db.nc_six_strgst[2].cr_crit.c1, + grr_data->db.nc_six_strgst[3].cr_crit.c1, + grr_data->db.nc_six_strgst[4].cr_crit.c1, + grr_data->db.nc_six_strgst[5].cr_crit.c1 + ); + + /* trace the C31 criterion */ + for( i = grr_data->db.cnt_nc_six.strgst; i < CS_MAX_STRONG_CARRIER; i++ ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c31 = 0; + } + + TRACE_EVENT_P7 + ( + "C31 : %6d %6d %6d %6d %6d %6d %6d", + + grr_data->db.scell_info.cr_crit.c31, + grr_data->db.nc_six_strgst[0].cr_crit.c31, + grr_data->db.nc_six_strgst[1].cr_crit.c31, + grr_data->db.nc_six_strgst[2].cr_crit.c31, + grr_data->db.nc_six_strgst[3].cr_crit.c31, + grr_data->db.nc_six_strgst[4].cr_crit.c31, + grr_data->db.nc_six_strgst[5].cr_crit.c31 + ); + + /* trace the C32 criterion */ + for( i = grr_data->db.cnt_nc_six.strgst; i < CS_MAX_STRONG_CARRIER; i++ ) + { + grr_data->db.nc_six_strgst[i].cr_crit.c32 = 0; + } + + TRACE_EVENT_P7 + ( + "C32 : %6d %6d %6d %6d %6d %6d %6d", + grr_data->db.scell_info.cr_crit.c32, + grr_data->db.nc_six_strgst[0].cr_crit.c32, + grr_data->db.nc_six_strgst[1].cr_crit.c32, + grr_data->db.nc_six_strgst[2].cr_crit.c32, + grr_data->db.nc_six_strgst[3].cr_crit.c32, + grr_data->db.nc_six_strgst[4].cr_crit.c32, + grr_data->db.nc_six_strgst[5].cr_crit.c32 + ); + } + +#endif /* #if !defined (NTRACE) */ + +} /* cs_calc_params() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_store_meas_values ++------------------------------------------------------------------------------ +| Description : The function cs_store_meas_values() saves the received +| rla_p values in the grr database +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_store_meas_values ( void ) +{ + UBYTE i, j; /* used for counting */ + + USHORT arfcn; + + T_rla_p rla_p; + + TRACE_FUNCTION( "cs_store_meas_values" ); + + /* + * store the first value as serving cell + */ + grr_data->db.scell_info.rla_p.stat = + cs_get_rla_p( &nc_data->cell[0].rla_p_data, + &grr_data->db.scell_info.rla_p.lev ); + + if( grr_data->db.scell_info.rla_p.stat NEQ CS_RLA_P_NOT_AVAIL ) + { +#ifdef FF_PS_RSSI + RX_SetValue( grr_data->db.scell_info.rla_p.lev, + RX_QUAL_UNAVAILABLE, + psc_db->scell_par.cr_par_1.cr_pow_par.gprs_rxlev_access_min); +#else + RX_SetValue( grr_data->db.scell_info.rla_p.lev ); +#endif + } + + /* + * store the next values as neighbour cells + */ + for( j = 1; j < nc_data->c_cell; j++ ) + { + i = 0; +#if defined (REL99) AND defined (TI_PS_FF_EMR) + arfcn = nc_data->cell[j].arfcn; +#else + arfcn = grr_l1_arfcn_to_g23( nc_data->cell[j].arfcn ); +#endif + rla_p.stat = cs_get_rla_p( &nc_data->cell[j].rla_p_data, &rla_p.lev ); + + while( i < MAX_NR_OF_NC_MVAL AND + grr_data->db.nc_mval_list.nc_mval[i].arfcn NEQ arfcn ) + + { + i++; + } + + if( i < MAX_NR_OF_NC_MVAL ) + { + grr_data->db.nc_mval_list.nc_mval[i].rla_p = rla_p; + } + } +} /* cs_store_meas_values() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_store_rxlev_values ++------------------------------------------------------------------------------ +| Description : The function cs_store_rxlev_values() +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_store_rxlev_values ( void ) +{ + UBYTE i, j; /* used for counting */ + + USHORT arfcn; + + TRACE_FUNCTION( "cs_store_rxlev_values" ); + + /* + * store the first value as serving cell + */ + grr_data->db.scell_info.rxlev_avg = + cs_get_rxlev_avg( &nc_data->cell[0].rxlev_data ); + + /* + * store the next values as neighbour cells + */ + for( j = 1; j < nc_data->c_cell; j++ ) + { + i = 0; +#if defined (REL99) AND defined (TI_PS_FF_EMR) + arfcn = nc_data->cell[j].arfcn; +#else + arfcn = grr_l1_arfcn_to_g23( nc_data->cell[j].arfcn ); +#endif + + while( i < MAX_NR_OF_NC_MVAL AND + grr_data->db.nc_mval_list.nc_mval[i].arfcn NEQ arfcn ) + + { + i++; + } + + if( i < MAX_NR_OF_NC_MVAL ) + { + grr_data->db.nc_mval_list.nc_mval[i].rxlev_avg = + cs_get_rxlev_avg( &nc_data->cell[j].rxlev_data ); + } + } +} /* cs_store_rxlev_values() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_find_strongest ++------------------------------------------------------------------------------ +| Description : The function cs_find_strongest() finds out the six strongest +| neighbour cells and stores their indices in an array. +| +| Parameters : cnt_strgst - number of strongest carriers +| cnt_candid - number of strongest plus candidate carriers +| index - index of carriers +| status - status of carriers +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_find_strongest ( ULONG fn_offset ) +{ + UBYTE cnt_strgst; + UBYTE cnt_candid; + UBYTE index[CS_MAX_STRONG_CARRIER]; + + UBYTE max_nc_excl_sc_band = 0; /* maximum number of reported neighbour */ + /* cells that should be not in the band */ + /* of the serving cell */ + + TRACE_FUNCTION( "cs_find_strongest" ); + +#ifdef TI_PS_FF_QUAD_BAND_SUPPORT + if( CHECK_DUAL_BANDS EQ TRUE) +#else + if( std EQ STD_DUAL OR std EQ STD_DUAL_EGSM OR std EQ STD_DUAL_US ) +#endif + { + switch( psc_db->scell_par.multi_band_rep ) + { + case GRR_MULTIBAND_REPORTING_1: max_nc_excl_sc_band = 1; break; + case GRR_MULTIBAND_REPORTING_2: max_nc_excl_sc_band = 2; break; + case GRR_MULTIBAND_REPORTING_3: max_nc_excl_sc_band = 3; break; + default : max_nc_excl_sc_band = 0; break; + } + } + + /* + * look for strongest neighbour cells with a valid RLA_P value, + * these are used for cell re-selection only + */ + cnt_strgst = 0; + + cs_consider_multiband + ( &cnt_strgst, index, CS_RLA_P_VALID, max_nc_excl_sc_band ); + + /* + * look for strongest neighbour cells with a RLA_P which is not valid + * but available and add them to the remaining storage areas in the list + * of strongest neighbour cells, these are used for checking the BSIC + * in advance, these cells may become a valid RLA_P value soon + */ + cnt_candid = cnt_strgst; + + if( cnt_candid < CS_MAX_STRONG_CARRIER ) + { + cs_consider_multiband + ( &cnt_candid, index, CS_RLA_P_NOT_VALID, max_nc_excl_sc_band ); + } + + return(cs_update_strongest( cnt_strgst, cnt_candid, index, fn_offset )); +} /* cs_find_strongest() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_consider_multiband ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_consider_multiband ( UBYTE *count, + UBYTE *index, + UBYTE select_status, + UBYTE maximum ) +{ + TRACE_FUNCTION( "cs_consider_multiband" ); + + if( maximum NEQ 0 ) + { + /* + * A maximum of zero means that normal reporting of the six strongest + * cell irrespective of the band used should be performed. + * + * A maximum greater zero means that multi band reporting should be + * performed, so the MS shall report the strongest cells in each of the + * frequency bands in the BA list, excluding the frequency band of the + * serving cell. The remaining positions shall be used for reporting of + * the cells in the band of the serving cell. + */ + cs_find_strongest_with_status + ( count, index, select_status, maximum, CS_EXCLUDE_SC_BAND ); + + cs_find_strongest_with_status + ( count, index, select_status, + (UBYTE)( CS_MAX_STRONG_CARRIER - maximum ), CS_ONLY_SC_BAND ); + } + + if( *count < CS_MAX_STRONG_CARRIER ) + { + cs_find_strongest_with_status + ( count, index, select_status, + (UBYTE)( CS_MAX_STRONG_CARRIER - *count ), CS_NO_BAND_LIMITATION ); + } +} /* cs_consider_multiband() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_find_strongest_with_status ++------------------------------------------------------------------------------ +| Description : The function cs_find_strongest_with_status() finds out the +| six strongest neighbour cells with a specific status and +| stores their indices in an array. +| +| Parameters : count - number of strongest carriers +| index - index of carriers +| status - status of carriers +| select_status - status which should be used for selection +| +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_find_strongest_with_status ( UBYTE *count, + UBYTE *index, + UBYTE select_status, + UBYTE maximum, + UBYTE limitation ) +{ + UBYTE strgst_idx; /* used for counting */ + UBYTE mval_idx; /* used for counting */ + UBYTE k; /* used for counting */ + BOOL cells_left = TRUE; /* indicates whether there are more cells */ + /* which may belong to the strongest */ + SHORT max_rla_p; /* next maximum RLA_P value */ + UBYTE idx_next_max; /* index of the cell with the next max. */ + /* RLA_P value */ + BOOL one_of_six_flag; /* indicates whether a cell already */ + /* belongs to the strongest */ + BOOL limit; /* indicator for limitation precedence */ + BOOL scell_is_high_band; /* serving cell is in DCS or PCS band */ + BOOL ncell_is_high_band; /* neighbour cell is in DCS or PCS band */ + UBYTE max_found_cell = MINIMUM( *count + maximum, CS_MAX_STRONG_CARRIER ); + /* maximum number of strongest neighbour */ + /* cells that should be found after */ + /* leaving this function */ + USHORT low_channel; + USHORT high_channel; + + T_NC_MVAL *nc_mval; + + TRACE_FUNCTION( "cs_find_strongest_with_status" ); + +#ifdef TI_PS_FF_QUAD_BAND_SUPPORT + if( std EQ STD_DUAL_US OR std EQ STD_900_1900 OR + std EQ STD_850_900_1900 ) +#else + if( std EQ STD_DUAL_US ) +#endif + { + low_channel = LOW_CHANNEL_1900; + high_channel = HIGH_CHANNEL_1900; + } + else + { + low_channel = LOW_CHANNEL_1800; + high_channel = HIGH_CHANNEL_1800; + } + + for( strgst_idx = *count; + strgst_idx < max_found_cell AND cells_left; + strgst_idx++ ) + { + max_rla_p = -1; + idx_next_max = 0xFF; + + for( mval_idx = 0; mval_idx < MAX_NR_OF_NC_MVAL; mval_idx++ ) + { + nc_mval = &grr_data->db.nc_mval_list.nc_mval[mval_idx]; + + if( nc_mval->status EQ NC_MVAL_STAT_ASSIGNED ) + { + one_of_six_flag = FALSE; + + for( k = 0; k < *count AND one_of_six_flag EQ FALSE; k++ ) + { + if( mval_idx EQ index[k] ) + { + one_of_six_flag = TRUE; + } + } + + if( one_of_six_flag EQ FALSE AND + nc_mval->rla_p.stat EQ select_status AND + +#ifdef _TARGET_ + nc_mval->rla_p.lev >= MIN_RXLEV_FOR_SIX_STRGST AND +#endif /* #ifdef _TARGET_ */ + + nc_mval->rla_p.lev > max_rla_p ) + { + switch( limitation ) + { + default: + TRACE_ASSERT( limitation EQ CS_NO_BAND_LIMITATION OR + limitation EQ CS_EXCLUDE_SC_BAND OR + limitation EQ CS_ONLY_SC_BAND ); + + /*lint -fallthrough*/ + + /* + * fallthrough statement inserted to pass lint process, + * error 644: (Warning -- limit may not have been initialized) + */ + + case( CS_NO_BAND_LIMITATION ): + limit = FALSE; + break; + + case( CS_EXCLUDE_SC_BAND ): + scell_is_high_band = + ( psc_db->pbcch.bcch.arfcn >= low_channel AND + psc_db->pbcch.bcch.arfcn <= high_channel ); + + ncell_is_high_band = + ( nc_mval->arfcn >= low_channel AND + nc_mval->arfcn <= high_channel ); + + limit = ( scell_is_high_band EQ ncell_is_high_band ); + break; + + case( CS_ONLY_SC_BAND ): + scell_is_high_band = + ( psc_db->pbcch.bcch.arfcn >= low_channel AND + psc_db->pbcch.bcch.arfcn <= high_channel ); + + ncell_is_high_band = + ( nc_mval->arfcn >= low_channel AND + nc_mval->arfcn <= high_channel ); + + limit = ( scell_is_high_band NEQ ncell_is_high_band ); + break; + } + + /* + * limitation may take precedence, + * do not consider neighbour cell in case + */ + if( limit EQ FALSE ) + { + max_rla_p = nc_mval->rla_p.lev; + idx_next_max = mval_idx; + } + } + } + } + + if( idx_next_max EQ 0xFF ) + { + cells_left = FALSE; + } + else + { + index[strgst_idx] = idx_next_max; + + (*count)++; + } + } +} /* cs_find_strongest_with_status() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_update_strongest ++------------------------------------------------------------------------------ +| Description : The function cs_update_strongest() updates the list of the +| strongest neighbour cells stored in the database. +| +| Parameters : cnt_strgst - number of strongest carriers +| cnt_candid - number of strongest plus candidate carriers +| index - index of carriers +| status - status of carriers +| fn_offset - frame number offset +| ++------------------------------------------------------------------------------ +*/ +LOCAL BOOL cs_update_strongest ( UBYTE cnt_strgst, + UBYTE cnt_candid, + UBYTE *index, + ULONG fn_offset ) +{ + UBYTE i, j; /* used for counting */ + ULONG avail_time[CS_MAX_STRONG_CARRIER]; + /* used to store the times when a cell becomes first */ + /* a cell of the strongest carriers for a possible */ + /* rearrangment of the list of the strongest carriers */ + + T_NC_SIX_STRGST *six_strgst; + T_NC_SIX_STRGST *six_candid; + + BOOL has_changed = ( grr_data->db.cnt_nc_six.candid NEQ cnt_candid ); + + + TRACE_FUNCTION( "cs_update_strongest" ); + + memset( avail_time, 0, sizeof( avail_time ) ); + + for( i = 0; i < cnt_candid; i++ ) + { + /* + * check whether cell is already inserted in list of strongest carrier + */ + six_strgst = NULL; + six_candid = NULL; + j = 0; + + while( j < grr_data->db.cnt_nc_six.candid AND + six_strgst EQ NULL AND + six_candid EQ NULL ) + { + six_candid = &grr_data->db.nc_six_strgst[j]; + + if( index[i] EQ six_candid->idx ) + { + if( j < grr_data->db.cnt_nc_six.strgst ) + { + six_strgst = six_candid; + } + } + else + { + six_candid = NULL; + + j++; + } + } + + + if( six_strgst NEQ NULL ) + { + if( six_strgst->avail_time <= + ( GPRS_PENALTY_TIME_MAX + 1 ) * 10 * CS_PERIOD_1_SEC ) + { + /* + * the time how long the cell is already inserted + * is stored up to a limited period + */ + avail_time[i] = six_strgst->avail_time + fn_offset; + } + else + { + avail_time[i] = six_strgst->avail_time; + } + } + else + { + if( six_candid EQ NULL ) + { + has_changed = TRUE; + } + + if( grr_data->db.old_scell.arfcn EQ + grr_data->db.nc_mval_list.nc_mval[index[i]].arfcn AND + grr_data->db.old_scell.bsic EQ + grr_data->db.nc_mval_list.nc_mval[index[i]].sync_info.bsic ) + { + /* for the old serving cell timer T shall always set to status expired */ + avail_time[i] = + ( ( GPRS_PENALTY_TIME_MAX + 1 ) * 10 * CS_PERIOD_1_SEC ) + 1; + } + + } + } + + for( i = 0; i < cnt_candid; i++ ) + { + grr_data->db.nc_six_strgst[i].idx = index[i]; + grr_data->db.nc_six_strgst[i].avail_time = avail_time[i]; + + /* + * every time a new list of strongest carriers is build-up + * the parameter mode should be set to CS_MODE_IDLE. + */ + grr_data->db.nc_six_strgst[i].mode = CS_MODE_IDLE; + } + + cs_set_cnt_nc_six( cnt_strgst, cnt_candid ); + + /* + * perform some tracing + */ + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + /* trace the ARFCN */ + { + USHORT arfcn[CS_MAX_STRONG_CARRIER]; + + memset( arfcn, RRGRR_INVALID_ARFCN, sizeof( arfcn ) ); + + for( i = 0; i < grr_data->db.cnt_nc_six.candid; i++ ) + { + arfcn[i] = + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].arfcn; + } + + TRACE_EVENT_P7 + ( + "ARFCN: %6d %6d %6d %6d %6d %6d %6d", + psc_db->pbcch.bcch.arfcn, + arfcn[0], arfcn[1], arfcn[2], arfcn[3], arfcn[4], arfcn[5] + ); + } + + /* trace the BSIC */ + { + USHORT bsic[CS_MAX_STRONG_CARRIER]; + + memset( bsic, RRGRR_INVALID_BSIC, sizeof( bsic ) ); + + for( i = 0; i < grr_data->db.cnt_nc_six.candid; i++ ) + { + bsic[i] = + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].sync_info.bsic; + } + + TRACE_EVENT_P7 + ( + "BSIC : %6d %6d %6d %6d %6d %6d %6d", + psc_db->pbcch.bcch.bsic, + bsic[0], bsic[1], bsic[2], bsic[3], bsic[4], bsic[5] + ); + } + + /* trace the RLA_P */ + { + UBYTE rla_p[CS_MAX_STRONG_CARRIER]; + UBYTE rxlev_avg[CS_MAX_STRONG_CARRIER]; + + memset( rla_p, 0, sizeof( rla_p ) ); + memset( rxlev_avg, 0, sizeof( rxlev_avg ) ); + + for( i = 0; i < grr_data->db.cnt_nc_six.candid; i++ ) + { + rla_p[i] = + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].rla_p.lev; + + + rxlev_avg[i] = + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].rxlev_avg; + + } + + TRACE_EVENT_P7 + ( + "RLA_P: %6d %6d %6d %6d %6d %6d %6d", + grr_data->db.scell_info.rla_p.lev, + rla_p[0], rla_p[1], rla_p[2], rla_p[3], rla_p[4], rla_p[5] + ); + + TRACE_EVENT_P7 + ( + "RXLEV_AVG: %6d %6d %6d %6d %6d %6d %6d", + grr_data->db.scell_info.rxlev_avg, + rxlev_avg[0], rxlev_avg[1], rxlev_avg[2], rxlev_avg[3], rxlev_avg[4], rxlev_avg[5] + ); + + } + + /* trace the synchronisation status */ + { + UBYTE sync_stat[CS_MAX_STRONG_CARRIER]; + + memset( sync_stat, 0xFF, sizeof( sync_stat ) ); + + for( i = 0; i < grr_data->db.cnt_nc_six.candid; i++ ) + { + sync_stat[i] = + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].sync_info.sync.status; + } + + TRACE_EVENT_P6 + ( + "SYNC : %6d %6d %6d %6d %6d %6d", + sync_stat[0], sync_stat[1], sync_stat[2], + sync_stat[3], sync_stat[4], sync_stat[5] + ); + } + } + +#endif /* #if !defined (NTRACE) */ + + return( has_changed ); + +} /* cs_update_strongest() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_compare_bsic ++------------------------------------------------------------------------------ +| Description : The function cs_compare_bsic() compares the indicated BSIC +| with the stored BSICs +| +| Parameters : rrgrr_check_bsic_ind - pointer to primitive +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_compare_bsic ( T_RRGRR_NCELL_SYNC_IND *rrgrr_check_bsic_ind ) +{ + UBYTE i = 0; + UBYTE j; + UBYTE nc_mval_idx; + T_NC_MVAL *nc_mval; + + + TRACE_FUNCTION( "cs_compare_bsic" ); + + + + while( i < RRGRR_MAX_RSLT_NCELL_SYNC_IND AND + rrgrr_check_bsic_ind->sync_result[i].arfcn NEQ RRGRR_INVALID_ARFCN ) + { + if( ( nc_mval = grr_get_nc_mval( rrgrr_check_bsic_ind->sync_result[i].arfcn, + RRGRR_INVALID_BSIC, &nc_mval_idx ) ) NEQ NULL ) + { + switch( rrgrr_check_bsic_ind->sync_result[i].sb_flag ) + { + case( SB_FOUND ): + nc_mval->sync_info.bsic = rrgrr_check_bsic_ind->sync_result[i].bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + break; + + case( NO_SB_FOUND ): + nc_mval->sync_info.bsic = RRGRR_INVALID_BSIC; + + if( nc_mval->sync_info.sync.sync_failed_cnt EQ MAX_SYNC_FAILED_CNT ) + { + nc_mval->sync_info.sync.status = STAT_SYNC_NONE; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + + j=0; + while( j < grr_data->nc_data.c_cell AND + grr_data->nc_data.cell[j].arfcn NEQ + nc_mval->arfcn ) + { + j++; + } + + if( j < grr_data->nc_data.c_cell ) + { + cs_reset_meas_result( &grr_data->nc_data.cell[j] ); + } + + } + else + { + nc_mval->sync_info.sync.status = STAT_SYNC_FAILED; + nc_mval->sync_info.sync.sync_failed_cnt += 1; + } + break; + + case( SB_UNKNOWN ): + if( nc_mval->status EQ NC_MVAL_STAT_PENDING ) + { + cs_init_nc_mval( nc_mval ); + } + else + { + nc_mval->sync_info.bsic = RRGRR_INVALID_BSIC; + nc_mval->sync_info.sync.status = STAT_SYNC_NONE; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + } + break; + } + } + + if( nc_mval EQ NULL ) + { + if( ( nc_mval = grr_get_nc_mval( RRGRR_INVALID_ARFCN, + RRGRR_INVALID_BSIC, + &nc_mval_idx ) ) NEQ NULL ) + { + switch( rrgrr_check_bsic_ind->sync_result[i].sb_flag ) + { + case( SB_FOUND ): + nc_mval->status = NC_MVAL_STAT_PENDING; + nc_mval->arfcn = rrgrr_check_bsic_ind->sync_result[i].arfcn; + nc_mval->sync_info.bsic = rrgrr_check_bsic_ind->sync_result[i].bsic; + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + + grr_data->cs.is_mval_initialized = FALSE; + break; + + case( NO_SB_FOUND ): + nc_mval->status = NC_MVAL_STAT_PENDING; + nc_mval->arfcn = rrgrr_check_bsic_ind->sync_result[i].arfcn; + nc_mval->sync_info.bsic = RRGRR_INVALID_BSIC; + nc_mval->sync_info.sync.status = STAT_SYNC_FAILED; + nc_mval->sync_info.sync.sync_failed_cnt = 0; + + grr_data->cs.is_mval_initialized = FALSE; + break; + + case( SB_UNKNOWN ): + TRACE_EVENT_P1( "cs_compare_bsic: SB_UNKNOWN for %d which is not on measured values list, e.g. after GRR suspension", + rrgrr_check_bsic_ind->sync_result[i].arfcn ); + break; + } + } + else + { + TRACE_EVENT_P1( "cs_compare_bsic: no free entry for measured values found %d", + rrgrr_check_bsic_ind->sync_result[i].arfcn ); + } + } + +#ifdef _SIMULATION_ + + TRACE_EVENT_P3( "BSIC: %d %d %d", + rrgrr_check_bsic_ind->sync_result[i].arfcn, + rrgrr_check_bsic_ind->sync_result[i].sb_flag, + rrgrr_check_bsic_ind->sync_result[i].bsic ); + +#endif /* #ifdef _SIMULATION_ */ + + i++; + } + + cs_trace_nc_mval_lst( ); + +} /* cs_compare_bsic() */ + + + + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_best_cell ++------------------------------------------------------------------------------ +| Description : The function cs_get_best_cell() checks the start of +| cell reselection. +| Is a criterion fulfilled for cell reselction, then reading of +| best neighbourcell is started. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_get_best_cell ( T_NC_SIX_STRGST **nc, T_scell_info **sc ) +{ + UBYTE strgst_idx; + UBYTE i; + T_NC_SIX_STRGST *next_cell; + BOOL c31_bc; /* best neighbour cell priorized */ + BOOL c31_nc; /* next neighbour cell priorized */ + BOOL c31_sc; /* serving cell priorized */ + T_ncell_info *ncell_best; /* best neighbour cell */ + T_ncell_info *ncell_next; /* next neighbour cell */ + T_NC_MVAL *mval_best; /* measured values for best neighbour cell */ + T_NC_MVAL *mval_next; /* measured values for next neighbour cell */ + + TRACE_FUNCTION( "cs_get_best_cell" ); + + /* + * start cell reselection if: + * + * 1. C1 for the serving cell falls below zero: C1 < 0 + * + * 2. A non-serving cell is evaluated to be better than the serving cell. + * + * a) The best cell is the cell with the highest value of C32 among those + * cells that have the highest PRIOROTY_CLASS among those that fulfill + * the criterion C31 >= 0. + * + * Interpretation: If C31 is fulfilled, take cells with highest + * priority and then select the cell with highest + * C32 value. + * + * b) The best cell is the cell with the highest value of C32 among all + * cells if no cell fulfill the criterion C31 >= 0. + * + * Interpretation: If C31 is not fulfilled, take the cell with the + * highest C32 value. + * + * NOTE: When selecting a neighbour cell to be the new serving cell, + * C1 criterion of that cell shall be taken into account. + */ + + /* + * set default results + */ + *sc = NULL; + *nc = NULL; + mval_best = NULL; + strgst_idx = 0xFF; + + if( grr_data->cs.is_upd_ncell_stat_needed ) + { + TRACE_EVENT( "cs_get_best_cell: is_upd_ncell_stat_needed EQ TRUE" ); + + return; + } + + if( + ( + grr_data->db.scell_info.rla_p.stat NEQ CS_RLA_P_VALID + ) + OR + ( + grr_data->db.scell_info.rla_p.stat EQ CS_RLA_P_VALID AND + grr_data->db.scell_info.cr_crit.c1 >= 0 AND + grr_data->db.scell_info.cell_barred EQ FALSE + ) + ) + { + *sc = &grr_data->db.scell_info; + } + + /* + * search the best neighbour cell, + * this cell should not be used for a cell re-selection attempt before + */ + for( i = 0; + i < grr_data->db.cnt_nc_six.strgst AND *nc EQ NULL; + i++ ) + { + *nc = &grr_data->db.nc_six_strgst[i]; + mval_best = &grr_data->db.nc_mval_list.nc_mval[(*nc)->idx]; + strgst_idx = i; + + if( (*nc)->mode NEQ CS_MODE_IDLE OR + mval_best->sync_info.sync.status NEQ STAT_SYNC_OK OR + (*nc)->cr_crit.c1 < 0 ) + { + *nc = NULL; + mval_best = NULL; + strgst_idx = 0xFF; + } + } + + /* + * if no best neighbour cell was found inform the caller + */ + if( *nc EQ NULL OR mval_best EQ NULL ) + { + return; + } + + ncell_best = + grr_get_ncell_info( mval_best->arfcn, mval_best->sync_info.bsic ); + + if( ncell_best EQ NULL ) + { + TRACE_EVENT( "cs_get_best_cell: ncell_best EQ NULL" ); + *nc = NULL; + strgst_idx = 0xFF; + + return; + } + + /* + * check whether best neighbour cell is priorized + */ + c31_bc = ( (*nc)->cr_crit.c31 >= 0 AND + ncell_best->cr_par.cr_par_1.v_hcs_par EQ TRUE ); + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P4( "cs_get_best_cell: ncell_best %d %d %d %d", + mval_best->arfcn, + mval_best->sync_info.bsic, + c31_bc, + ncell_best->cr_par.cr_par_1.hcs_par.gprs_prio_class ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * look for a better neighbour cell + */ + for( i = 0; i < grr_data->db.cnt_nc_six.strgst; i++ ) + { + next_cell = &grr_data->db.nc_six_strgst[i]; + mval_next = &grr_data->db.nc_mval_list.nc_mval[next_cell->idx]; + + if( next_cell->mode EQ CS_MODE_IDLE AND + next_cell NEQ *nc AND + mval_next->sync_info.sync.status EQ STAT_SYNC_OK AND + next_cell->cr_crit.c1 >= 0 ) + { + ncell_next = + grr_get_ncell_info( mval_next->arfcn, mval_next->sync_info.bsic ); + + if( ncell_next EQ NULL ) + { + TRACE_EVENT( "cs_get_best_cell: ncell_next EQ NULL" ); + + *nc = NULL; + strgst_idx = 0xFF; + + return; + } + + /* + * check whether next neighbour cell is priorized + */ + c31_nc = ( next_cell->cr_crit.c31 >= 0 AND + ncell_next->cr_par.cr_par_1.v_hcs_par EQ TRUE ); + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P4( "cs_get_best_cell: ncell_next %d %d %d %d", + mval_next->arfcn, + mval_next->sync_info.bsic, + c31_nc, + ncell_next->cr_par.cr_par_1.hcs_par.gprs_prio_class ); + } + +#endif /* #if !defined (NTRACE) */ + + if( c31_bc AND + c31_nc AND + ( + ( ncell_next->cr_par.cr_par_1.hcs_par.gprs_prio_class EQ + ncell_best->cr_par.cr_par_1.hcs_par.gprs_prio_class AND + next_cell->cr_crit.c32 > (*nc)->cr_crit.c32 ) + OR + ( ncell_next->cr_par.cr_par_1.hcs_par.gprs_prio_class > + ncell_best->cr_par.cr_par_1.hcs_par.gprs_prio_class ) + ) + ) + { + /* + * priorized cell reselection must be done + */ + *nc = next_cell; + ncell_best = ncell_next; + strgst_idx = i; + } + else if ( !c31_bc ) + { + /* + * check whether next neighbour cell is priorized + */ + if( c31_nc ) + { + /* + * first priorized cell found + */ + c31_bc = TRUE; + *nc = next_cell; + ncell_best = ncell_next; + strgst_idx = i; + } + else if ( next_cell->cr_crit.c32 > (*nc)->cr_crit.c32 ) + { + /* + * until now, no priorized cell found + */ + *nc = next_cell; + ncell_best = ncell_next; + strgst_idx = i; + } + } + } + } + + /* + * check whether serving cell is priorized + */ + c31_sc = ( grr_data->db.scell_info.cr_crit.c31 >= 0 AND + psc_db->scell_par.cr_par_1.v_hcs_par EQ TRUE ); + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P3( "cs_get_best_cell: scell %d %d %d", + *sc, c31_sc, + psc_db->scell_par.cr_par_1.hcs_par.gprs_prio_class ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * check whether cell reselection must be done + */ + if( + ( + *sc EQ NULL + ) + OR + ( + c31_bc AND + c31_sc AND + ( + ( ncell_best->cr_par.cr_par_1.hcs_par.gprs_prio_class EQ + psc_db->scell_par.cr_par_1.hcs_par.gprs_prio_class AND + (*nc)->cr_crit.c32 > grr_data->db.scell_info.cr_crit.c32 ) + OR + ( ncell_best->cr_par.cr_par_1.hcs_par.gprs_prio_class > + psc_db->scell_par.cr_par_1.hcs_par.gprs_prio_class ) + ) + ) + OR + ( + !c31_bc AND + !c31_sc AND + (*nc)->cr_crit.c32 > grr_data->db.scell_info.cr_crit.c32 + ) + OR + ( + c31_bc AND + !c31_sc + ) + ) + { + *sc = NULL; + } + else + { + *nc = NULL; + strgst_idx = 0xFF; + } + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT_P3( "cs_get_best_cell: strong/candid %d %d %d", + grr_data->db.cnt_nc_six.strgst, + grr_data->db.cnt_nc_six.candid, + strgst_idx ); + } + +#endif /* #if !defined (NTRACE) */ + +} /* cs_get_best_cell() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_network_ctrl_order ++------------------------------------------------------------------------------ +| Description : The NETWORK_CONTROL_ORDER values NC1 and NC2 shall only apply +| in Ready state. In Standby state, the MS shall always use +| normal MS control independent of the ordered NC mode. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL T_NC_ORDER cs_get_network_ctrl_order ( BOOL consider_gmm_state ) +{ + T_NC_ORDER ctrl_order = NC_NC0; + + TRACE_FUNCTION( "cs_get_network_ctrl_order" ); + + if( grr_data->nc2_on ) + { + if( + ( + ( + consider_gmm_state EQ TRUE AND + grr_data->cs.gmm_state EQ READY_STATE + ) + OR + ( + consider_gmm_state EQ FALSE + ) + ) + AND + ( + grr_data->db.nc_ref_lst.param NEQ NULL + ) + ) + { + ctrl_order = grr_data->db.nc_ref_lst.param->ctrl_order; + } + } + +#ifdef _SIMULATION_ + + TRACE_EVENT_P2( "NETWORK_CONTROL_ORDER: %d, GMM_STATE: %d", + grr_data->db.nc_ref_lst.param EQ NULL ? + ctrl_order : grr_data->db.nc_ref_lst.param->ctrl_order, + grr_data->cs.gmm_state ); + +#endif /* #ifdef _SIMULATION_ */ + + return( ctrl_order ); + +} /* cs_get_network_ctrl_order() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_reset_nc_change_mark ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_reset_nc_change_mark ( T_SC_DATABASE *db ) +{ + TRACE_FUNCTION( "cs_reset_nc_change_mark" ); + + db->nc_cw.list.chng_mrk.curr = 0; + db->nc_cw.list.chng_mrk.prev = 0; + db->nc_cw.param.chng_mrk.curr = 0; + db->nc_cw.param.chng_mrk.prev = 0; + db->nc_ms.ncmeas.list.chng_mrk.curr = 0; + db->nc_ms.ncmeas.list.chng_mrk.prev = 0; + db->nc_ms.ncmeas.param.chng_mrk.curr = 0; + db->nc_ms.ncmeas.param.chng_mrk.prev = 0; + +} /* cs_reset_nc_change_mark() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_cr_meas_mode ++------------------------------------------------------------------------------ +| Description : The function cs_get_cr_meas_mode() returns the cell +| re-selection measurement mode used in context of TBF +| establishment. +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL UBYTE cs_get_cr_meas_mode ( void ) +{ + TRACE_FUNCTION( "cs_get_cr_meas_mode" ); + + return( grr_is_pbcch_present() ? CS_CRMM_BA_GPRS : CS_CRMM_BA_BCCH ); +} /* cs_get_cr_meas_mode() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_send_cr_meas_req ++------------------------------------------------------------------------------ +| Description : The function cs_send_cr_meas_req() sends the cell reselection +| measurement request to L1 (MPHP_CR_MEAS_REQ) +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_send_cr_meas_req ( UBYTE del_meas_rslt ) +{ + BOOL is_pbcch_present = grr_is_pbcch_present( ); + UBYTE i, j,number_of_frequencies; + BOOL is_existing; + BOOL v_cs_par[MAX_NR_OF_NCELL]; + T_NC_ORDER nc_ord = cs_get_network_ctrl_order( TRUE ); + T_NC_REF_LIST *nc_list = &grr_data->db.nc_ref_lst; + + TRACE_FUNCTION( "cs_send_cr_meas_req" ); + + { + /* + * first value represents the arfcn of the serving cell + */ +#if defined (REL99) AND defined (TI_PS_FF_EMR) + grr_data->nc_data.cell[0].arfcn = psc_db->pbcch.bcch.arfcn; +#else + grr_data->nc_data.cell[0].arfcn = grr_g23_arfcn_to_l1( psc_db->pbcch.bcch.arfcn ); +#endif + number_of_frequencies = 1; + + memset( v_cs_par, ( is_pbcch_present ? FALSE : TRUE ), sizeof( v_cs_par ) ); + + for( i = 0; i < nc_list->number; i++ ) + { + if( is_pbcch_present ) + { + v_cs_par[i] |= nc_list->info[i]->v_cr_par; + } + + for( j = i + 1, is_existing = FALSE; + j < nc_list->number AND is_existing EQ FALSE; + j++ ) + { + if( nc_list->info[j]->arfcn EQ nc_list->info[i]->arfcn ) + { + is_existing = TRUE; + + if( is_pbcch_present ) + { + v_cs_par[j] |= nc_list->info[i]->v_cr_par; + } + } + } + + if( !is_existing AND + ( nc_ord EQ NC_NC2 OR ( nc_ord NEQ NC_NC2 AND v_cs_par[i] ) ) ) + { +#if defined (REL99) AND defined (TI_PS_FF_EMR) + grr_data->nc_data.cell[number_of_frequencies].arfcn = nc_list->info[i]->arfcn; +#else + grr_data->nc_data.cell[number_of_frequencies].arfcn = + grr_g23_arfcn_to_l1( nc_list->info[i]->arfcn ); +#endif + number_of_frequencies++; + } + } + + if( del_meas_rslt EQ CS_DELETE_MEAS_RSLT ) + { + cs_reuse_old_cell_rxlev( ); + } + grr_data->nc_data.c_cell = number_of_frequencies; + cs_req_cr_meas( ); + } +} /* cs_send_cr_meas_req() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_send_cr_meas_stop_req ++------------------------------------------------------------------------------ +| Description : The function cs_send_cr_meas_stop_req() sends the cell +| reselection measurement stop request to L1 +| (MPHP_CR_MEAS_STOP_REQ) +| +| Parameters : dummy - description of parameter dummy +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_send_cr_meas_stop_req ( void ) +{ + TRACE_FUNCTION( "cs_send_cr_meas_stop_req" ); + + + grr_data->nc_data.c_cell = 0; + grr_data->cs.cr_meas_mode = cs_get_cr_meas_mode( ); + cs_stop_cr_meas( ); + +} /* cs_send_cr_meas_stop_req() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_send_update_ba_req ++------------------------------------------------------------------------------ +| Description : The function cs_send_update_ba_req() updates the BA(BCCH) list +| by passing the lists of added and removed frequencies. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_send_update_ba_req ( T_SC_DATABASE *db ) +{ + UBYTE i, j; /* used for counting */ + BOOL is_found; + T_add_freq_list *afreq; + T_ncell_info *ncinfo; + T_NC_ORDER ctrl_order = cs_get_network_ctrl_order( FALSE ); + + TRACE_FUNCTION( "cs_send_update_ba_req" ); + + { + PALLOC( rrgrr_upd_ba_req, RRGRR_UPDATE_BA_REQ ); + + /* process cell type */ + rrgrr_upd_ba_req->cell_type = SYNC_SCELL; + + /* process NC mode */ + switch( ctrl_order ) + { + case NC_NC2: rrgrr_upd_ba_req->nc_mode = NC2_USED; break; + case NC_RESET: rrgrr_upd_ba_req->nc_mode = NC_RESET; break; + default : rrgrr_upd_ba_req->nc_mode = NC2_NOT_USED; break; + } + + /* process list of removed frequencies */ + if( db->nc_ms.rfreq.number > RRGRR_BA_LIST_SIZE ) + { + TRACE_ERROR ( "Number of removed frequencies > RRGRR_BA_LIST_SIZE" ); + } + + i = 0; + while( i < db->nc_ms.rfreq.number AND i < RRGRR_BA_LIST_SIZE ) + { + j = 0; + is_found = FALSE; + while( j < db->nc_cw.list.number AND is_found EQ FALSE ) + { + if( db->nc_cw.list.info[j].index EQ db->nc_ms.rfreq.idx[i] ) + { + is_found = TRUE; + } + else + { + j++; + } + } + + if( is_found EQ TRUE ) + { + rrgrr_upd_ba_req->rm_freq_list[i].arfcn = db->nc_cw.list.info[j].arfcn; + rrgrr_upd_ba_req->rm_freq_list[i].bsic = db->nc_cw.list.info[j].bsic; + } + else + { + TRACE_ERROR( "Removed frequency cannot be found in nc_cw structure" ); + } + + i++; + } + + if( i < RRGRR_BA_LIST_SIZE ) + { + rrgrr_upd_ba_req->rm_freq_list[i].arfcn = RRGRR_INVALID_ARFCN; + rrgrr_upd_ba_req->rm_freq_list[i].bsic = RRGRR_INVALID_BSIC; + } + +#ifdef _SIMULATION_ + + i++; + while( i < RRGRR_BA_LIST_SIZE ) + { + rrgrr_upd_ba_req->rm_freq_list[i].arfcn = RRGRR_INVALID_ARFCN; + rrgrr_upd_ba_req->rm_freq_list[i].bsic = RRGRR_INVALID_BSIC; + i++; + } + +#endif /* #ifdef _SIMULATION_ */ + + /* process list of added frequencies */ + if( db->nc_ms.ncmeas.list.number > RRGRR_BA_LIST_SIZE ) + { + TRACE_ERROR ( "Number of added frequencies > RRGRR_BA_LIST_SIZE" ); + } + + i = 0; + while( i < db->nc_ms.ncmeas.list.number AND i < RRGRR_BA_LIST_SIZE ) + { + afreq = &rrgrr_upd_ba_req->add_freq_list[i]; + ncinfo = &db->nc_ms.ncmeas.list.info[i]; + + afreq->arfcn = ncinfo->arfcn; + afreq->bsic = ncinfo->bsic; + + if( ncinfo->v_cr_par EQ TRUE ) + { + afreq->v_cr_par = TRUE; + + afreq->cr_par.cell_bar_access_2 = ncinfo->cr_par.cell_ba; + afreq->cr_par.exc_acc = ncinfo->cr_par.exc_acc; + afreq->cr_par.same_ra_as_serving_cell = ncinfo->cr_par.same_ra_scell; + afreq->cr_par.gprs_rxlev_access_min = ncinfo->cr_par.cr_par_1.cr_pow_par.gprs_rxlev_access_min; + afreq->cr_par.gprs_ms_txpwr_max_cch = ncinfo->cr_par.cr_par_1.cr_pow_par.gprs_ms_txpwr_max_cch; + afreq->cr_par.gprs_temporary_offset = ncinfo->cr_par.cr_offset.gprs_temp_offset; + afreq->cr_par.gprs_penalty_time = ncinfo->cr_par.cr_offset.gprs_penalty_time; + afreq->cr_par.gprs_reselect_offset = ncinfo->cr_par.gprs_resel_off; + afreq->cr_par.priority_class = ncinfo->cr_par.cr_par_1.hcs_par.gprs_prio_class; + afreq->cr_par.hcs_thr = ncinfo->cr_par.cr_par_1.hcs_par.gprs_hcs_thr; + afreq->cr_par.si13_location = SI13_LOC_INVALID; + afreq->cr_par.pbcch_location = PBCCH_LOC_INVALID; + afreq->cr_par.psi1_repeat_period = PSI1_RPT_PRD_INVALID; + + if( ncinfo->cr_par.v_si13_pbcch ) + { + if( ncinfo->cr_par.si13_pbcch.v_si13_location ) + { + afreq->cr_par.si13_location = ncinfo->cr_par.si13_pbcch.si13_location; + } + else + { + afreq->cr_par.pbcch_location = ncinfo->cr_par.si13_pbcch.pbcch_location; + afreq->cr_par.psi1_repeat_period = ncinfo->cr_par.si13_pbcch.psi1_repeat_period - 1; + } + } + } + else + { + afreq->v_cr_par = FALSE; + } + + i++; + } + + if( i < RRGRR_BA_LIST_SIZE ) + { + rrgrr_upd_ba_req->add_freq_list[i].arfcn = RRGRR_INVALID_ARFCN; + rrgrr_upd_ba_req->add_freq_list[i].bsic = RRGRR_INVALID_BSIC; + } + +#ifdef _SIMULATION_ + + i++; + while( i < RRGRR_BA_LIST_SIZE ) + { + rrgrr_upd_ba_req->add_freq_list[i].arfcn = RRGRR_INVALID_ARFCN; + rrgrr_upd_ba_req->add_freq_list[i].bsic = RRGRR_INVALID_BSIC; + i++; + } + +#endif /* #ifdef _SIMULATION_ */ + + PSEND( hCommRR, rrgrr_upd_ba_req ); + } +} /* cs_send_update_ba_req() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_send_meas_rep_req ++------------------------------------------------------------------------------ +| Description : The function cs_send_meas_rep_req() updates RR with cause +| NC_START_MEAS or NC_REPORT_MEAS or NC_STOP_MEAS. +| +| Parameters : NC_START_MEAS - start the measurement +| NC_REPORT_MEAS - report the measurement +| NC_STOP_MEAS - stop the measurement +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_send_meas_rep_req ( UBYTE cause ) +{ + TRACE_FUNCTION( "cs_send_meas_rep_req" ); + + { + PALLOC( rrgrr_meas_rep_req, RRGRR_MEAS_REP_REQ ); + + rrgrr_meas_rep_req->meas_cause = grr_data->cs_meas.nc_meas_cause = cause; + + PSEND( hCommRR, rrgrr_meas_rep_req ); + } +} /* cs_send_meas_rep_req() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_store_meas_rep_cnf ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_store_meas_rep_cnf ( T_RRGRR_MEAS_REP_CNF *rrgrr_meas_rep_cnf ) +{ + UBYTE i; /* used for counting */ + UBYTE mval_idx; + T_NC_MVAL *mval; + + TRACE_FUNCTION( "cs_store_meas_rep_cnf" ); + + /* + * store the first value as serving cell + */ + grr_data->db.scell_info.rxlev_avg = rrgrr_meas_rep_cnf->meas_res[0].rxlev; + + /* + * store the next values as neighbour cells + */ + cs_init_nc_mval_lst( ); + + for( i = 1; + i < RRGRR_MEAS_REP_LIST_SIZE AND + rrgrr_meas_rep_cnf->meas_res[i].arfcn NEQ RRGRR_INVALID_ARFCN; + i++ ) + { + mval = grr_get_nc_mval( RRGRR_INVALID_ARFCN, RRGRR_INVALID_BSIC, &mval_idx ); + + if( mval NEQ NULL ) + { + mval->status = NC_MVAL_STAT_ASSIGNED; + mval->arfcn = rrgrr_meas_rep_cnf->meas_res[i].arfcn; + mval->rla_p.stat = CS_RLA_P_VALID; + mval->rla_p.lev = + mval->rxlev_avg = rrgrr_meas_rep_cnf->meas_res[i].rxlev; + mval->sync_info.bsic = rrgrr_meas_rep_cnf->meas_res[i].bsic; + mval->sync_info.sync.status = STAT_SYNC_OK; + + grr_data->cs.is_mval_initialized = FALSE; + } + else + { + TRACE_EVENT_P2( "No free entry for measured value found: %d %d", + rrgrr_meas_rep_cnf->meas_res[i].arfcn, + rrgrr_meas_rep_cnf->meas_res[i].bsic ); + } + } +} /* cs_store_meas_rep_cnf() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_strongest ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_build_strongest ( void ) +{ + UBYTE i; + UBYTE count = 0; + UBYTE index[CS_MAX_STRONG_CARRIER]; + + TRACE_FUNCTION( "cs_build_strongest" ); + + cs_find_strongest_with_status + ( &count, index, CS_RLA_P_VALID, + (UBYTE)( CS_MAX_STRONG_CARRIER - count ), CS_NO_BAND_LIMITATION ); + + for( i = 0; i < count; i++ ) + { + grr_data->db.nc_six_strgst[i].idx = index[i]; + } + + cs_set_cnt_nc_six( count, count ); + +} /* cs_build_strongest() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_send_meas_rpt ++------------------------------------------------------------------------------ +| Description : This function ... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_send_meas_rpt ( BOOL perform_init ) +{ + BOOL rpt_snd; + T_U_MEAS_REPORT meas_rpt; + + TRACE_FUNCTION( "cs_send_meas_rpt" ); + + if( perform_init EQ TRUE ) + { + grr_data->cs_meas.pmr_snd_ref = 0; + } + + memset(&meas_rpt, 0, sizeof(T_U_MEAS_REPORT)); + + rpt_snd = cs_build_meas_rpt( &meas_rpt ); + + if( rpt_snd EQ TRUE ) + { + sig_cs_ctrl_meas_report( &meas_rpt ); + } + + return( rpt_snd ); +} /* cs_send_meas_rpt() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_start_t_reselect ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_start_t_reselect ( void ) +{ + TRACE_FUNCTION( "cs_start_t_reselect" ); + + if( grr_t_status( T_RESELECT ) EQ 0 ) + { + vsi_t_start( GRR_handle, T_RESELECT, T_RESELECT_VALUE ); + + TRACE_EVENT( "Timer T_RESELECT started" ); + } +} /* cs_start_t_reselect() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_stop_t_reselect ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_stop_t_reselect ( void ) +{ + TRACE_FUNCTION( "cs_stop_t_reselect" ); + + if( grr_t_status( T_RESELECT ) NEQ 0 ) + { + vsi_t_stop( GRR_handle, T_RESELECT ); + + TRACE_EVENT( "Timer T_RESELECT stopped" ); + } +} /* cs_stop_t_reselect() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_process_t3158 ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_process_t3158 ( void ) +{ + T_TIME reporting_period; + T_TIME time_to_go; + BOOL tmr_3158_rng_le_rp = FALSE; + + TRACE_FUNCTION( "cs_process_t3158" ); + + if( cs_is_meas_reporting( ) ) + /* Implies NC measurement conditions are satisfied. May mean Enhanced + measurement conditions are also satisfied */ + { + switch( grr_data->cs_meas.packet_mode ) + { + case( PACKET_MODE_PIM ): + case( PACKET_MODE_PAM ): + reporting_period = cs_get_nc_rpt_prd_idle( ); + break; + + case( PACKET_MODE_PTM ): + /* + * In packet transfer mode, the reporting period is indicated in + * NC_REPORTING_PERIOD_T. + */ + reporting_period = + GET_NC_RPT_PRD( grr_data->db.nc_ref_lst.param->rep_per_t ); + break; + + default: + if( GET_STATE( CS ) EQ CS_CR_NETWORK ) + { + /* + * In case timer T3158 expires during processing of Packet Cell Change + * Order, the timer should be re-started and not stopped at all. + */ + reporting_period = cs_get_nc_rpt_prd_idle( ); + } + else + { + reporting_period = 0; + } + break; + } + + time_to_go = grr_t_status( T3158 ); + + if( time_to_go > 0 ) + { + if( time_to_go > reporting_period ) + { + cs_stop_t3158( ); + + if( grr_is_pbcch_present( ) EQ FALSE AND + grr_data->cs_meas.nc_meas_cause NEQ NC_STOP_MEAS ) + { + cs_send_meas_rep_req ( NC_STOP_MEAS ); + } + } + else + { + tmr_3158_rng_le_rp = TRUE; + } + } + + if( reporting_period NEQ 0 ) + { + if( tmr_3158_rng_le_rp EQ FALSE ) + { + cs_reset_all_rxlev_results( ); + cs_start_t3158( reporting_period ); + /* + * Start rx_lev averaging when NC=1 or NC=2 in ALR + */ + if( grr_is_pbcch_present( ) EQ FALSE AND + grr_data->cs_meas.nc_meas_cause EQ NC_STOP_MEAS ) + { + cs_send_meas_rep_req ( NC_START_MEAS ) ; + } + } + } + else + { + cs_reset_all_rxlev_results( ); + } + } + else + { + cs_reset_all_rxlev_results( ); + cs_stop_t3158( ); + /* + * Stop rx_lev averaging when NC=1 or NC=2 in ALR + */ + if( grr_is_pbcch_present( ) EQ FALSE AND + grr_data->cs_meas.nc_meas_cause NEQ NC_STOP_MEAS ) + { + cs_send_meas_rep_req ( NC_STOP_MEAS ); + } + } +} /* cs_process_t3158() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_start_t3158 ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_start_t3158 ( T_TIME time ) +{ + TRACE_FUNCTION( "cs_start_t3158" ); + + vsi_t_start( GRR_handle, T3158, time ); + + TRACE_EVENT_P1( "T3158: %d", time ); + +} /* cs_start_t3158() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_stop_t3158 ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_stop_t3158 ( void ) +{ + TRACE_FUNCTION( "cs_stop_t3158" ); + + if( grr_t_status( T3158 ) > 0 ) + { + vsi_t_stop( GRR_handle, T3158 ); + + TRACE_EVENT( "T3158 stopped" ); + } +} /* cs_stop_t3158() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_cancel_meas_report ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_cancel_meas_report ( void ) +{ + TRACE_FUNCTION( "cs_cancel_meas_report" ); + + switch( GET_STATE( CS_MEAS ) ) + { + case CS_MEAS_REP_REQ: + SET_STATE( CS_MEAS, CS_NULL ); + break; + case CS_MEAS_PMR_SENDING: + sig_cs_ctrl_cancel_meas_report( ); + break; + default: + /* do nothing */ + break; + } +} /* cs_cancel_meas_report() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_nc_ref_list ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : db - pointer to serving cell database +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_build_nc_ref_list ( T_SC_DATABASE *db, BOOL is_dsf ) +{ + TRACE_FUNCTION( "cs_build_nc_ref_list" ); + + cs_init_nc_ref_list( &grr_data->db.nc_ref_lst ); + + if( + grr_data->cs.gmm_state EQ READY_STATE AND + is_dsf EQ FALSE AND + ( + db->nc_ms.ncmeas.param.ctrl_order EQ NC_NC0 OR + db->nc_ms.ncmeas.param.ctrl_order EQ NC_NC1 OR + db->nc_ms.ncmeas.param.ctrl_order EQ NC_NC2 + ) + ) + { + grr_data->db.nc_ref_lst.param = &db->nc_ms.ncmeas.param; + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + grr_data->db.nc_ref_lst.enh_param = &db->enh_ms; +#endif + } + else if( db->nc_cw.param.ctrl_order EQ NC_NC0 OR + db->nc_cw.param.ctrl_order EQ NC_NC1 OR + db->nc_cw.param.ctrl_order EQ NC_NC2 ) + { + grr_data->db.nc_ref_lst.param = &db->nc_cw.param; + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + grr_data->db.nc_ref_lst.enh_param = &db->enh_cw; +#endif + } + + cs_build_nc_freq_list( db ); + cs_reorg_nc_mval_lst( ); + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + if( !grr_is_pbcch_present() AND + grr_data->db.nc_ref_lst.enh_param->rept_type EQ REPORT_TYPE_ENH_REP) + { + cs_init_ba_bcch_nc_ref_list(); + cs_build_ba_bcch_nc_freq_list(); + } +#endif + +}/* cs_build_nc_ref_list */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_init_nc_ref_list ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : list - pointer to NC measurement pointer list +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_init_nc_ref_list ( T_NC_REF_LIST *list ) +{ + TRACE_FUNCTION( "cs_init_nc_ref_list" ); + + list->number = 0; + list->param = NULL; + +#if defined (REL99) AND defined (TI_PS_FF_EMR) + list->enh_param = NULL; +#endif + +}/* cs_init_nc_ref_list */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_init_nc_mval_lst ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_init_nc_mval_lst ( void ) +{ + UBYTE i; + + TRACE_FUNCTION( "cs_init_nc_mval_lst" ); + + if( grr_data->cs.is_mval_initialized EQ FALSE ) + { + for( i = 0; i < MAX_NR_OF_NC_MVAL; i++ ) + { + cs_init_nc_mval( &grr_data->db.nc_mval_list.nc_mval[i] ); + } + + grr_data->cs.is_mval_initialized = TRUE; + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "cs_init_nc_mval_lst: now initialized" ); + } + +#endif /* #if !defined (NTRACE) */ + + } + else + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "cs_init_nc_mval_lst: already initialized" ); + } + +#endif /* #if !defined (NTRACE) */ + + } +}/* cs_init_nc_mval_lst */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_init_nc_mval ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : mval - pointer to NC measured value +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_init_nc_mval ( T_NC_MVAL *mval ) +{ + TRACE_FUNCTION( "cs_init_nc_mval" ); + + mval->arfcn = RRGRR_INVALID_ARFCN; + mval->sync_info.bsic = RRGRR_INVALID_BSIC; + mval->sync_info.sync.status = STAT_SYNC_NONE; + mval->sync_info.sync.sync_failed_cnt = 0; + mval->rla_p.stat = CS_RLA_P_NOT_AVAIL; + mval->rxlev_avg = RXLEV_AVG_INVALID; + mval->status = NC_MVAL_STAT_NONE; +}/* cs_init_nc_mval */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_update_bsic ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_update_bsic ( void ) +{ + UBYTE i +#if defined (REL99) AND defined (TI_PS_FF_EMR) + ,j, k +#endif + ; + /* used for counting */ +#if defined (TI_PS_FF_RTD) AND defined (REL99) + UBYTE i_max,rtd_index,rtd_count; +#else + UBYTE i_max; +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + + + TRACE_FUNCTION( "cs_update_bsic" ); + + i = 0; + i_max = MINIMUM( grr_data->db.cnt_nc_six.candid, CS_MAX_STRONG_CARRIER ); + i_max = MINIMUM( i_max, RRGRR_MAX_ARFCN_NCELL_SYNC_REQ ); + + if( i_max NEQ 0 ) + { + PALLOC( rrgrr_check_bsic_req, RRGRR_NCELL_SYNC_REQ ); + + while( i < i_max ) + { +#if defined (TI_PS_FF_RTD) AND defined (REL99) + rrgrr_check_bsic_req->ncell_sync_list[i].arfcn = grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].arfcn; +#else + rrgrr_check_bsic_req->arfcn[i] = grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[i].idx].arfcn; +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + + + i++; + } +#if defined (REL99) AND defined (TI_PS_FF_EMR) + /* Extend the ARFCN list only if ENH reporting is requested */ + if(cs_is_enh_meas_reporting()) + { + T_ENH_STRNG_ARFCN_LIST f_bin;/* Stores the ARFCN-RXLEV pair in descending + order of RXLEV */ + BOOL found; /* Will be set, if ARFCN in f_bin is found in NC_MVAL */ + + memset(&f_bin, 0, sizeof(T_ENH_STRNG_ARFCN_LIST)); + + /* Form a ARFCN-RXLEV pair list in descending order of RXLEV */ + cs_build_enh_sorted_strng_arfcn_list(&f_bin); + + /* Fill the NCELL_SYNC_REQ with ARFCNs from the above list. This list + will be filled without disturbing the six strongest cells for + cell reselection or PMR. The request for SYNC is now done for a + max of 12 cells with 1st few cells upto a max of six for cell + reselection and the remaining will be filled with ARFCNs from + the ENH list in the order of serving band, multiband and the rest + contains the excess from the above bands, each group containing + cells in descending order of RXLEV */ + j = 0; + while(i_max < RRGRR_MAX_ARFCN_NCELL_SYNC_REQ AND j < f_bin.num) + { + found = FALSE; + for(k = 0; k < grr_data->db.cnt_nc_six.candid; k++) + { + if(f_bin.meas[j].arfcn EQ + grr_data->db.nc_mval_list.nc_mval[grr_data->db.nc_six_strgst[k].idx].arfcn) + { + found = TRUE; + break; + } + } + + if(!found) + { +#if defined (TI_PS_FF_RTD) AND defined (REL99) + rrgrr_check_bsic_req->ncell_sync_list[i_max].arfcn = f_bin.meas[j].arfcn; +#else + rrgrr_check_bsic_req->arfcn[i_max] = f_bin.meas[j].arfcn; +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + + i_max++; + } + j++; + } + } + + if( i_max < RRGRR_MAX_ARFCN_NCELL_SYNC_REQ ) + { +#if defined (TI_PS_FF_RTD) AND defined (REL99) + rrgrr_check_bsic_req->ncell_sync_list[i_max].arfcn = RRGRR_INVALID_ARFCN; +#else + rrgrr_check_bsic_req->arfcn[i_max] = RRGRR_INVALID_ARFCN; +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + } /*if*/ +#if defined (TI_PS_FF_RTD) AND defined (REL99) + i=0; + while (i < i_max) + { + j = 0; + rtd_count = 0; + /*More than 3 RTD values is not acceptable */ + while( j < grr_data->db.nc_ref_lst.number AND rtd_count < MAX_NUM_OF_RTD_VALUES ) + { + /* Check the NC ARFCN in the BA-list to get the index of that ARFCN in BA-list*/ + if(rrgrr_check_bsic_req->ncell_sync_list[i].arfcn EQ (grr_data->db.nc_ref_lst.info[j])->arfcn) + { + /* Pickup the right RTD value for that ARFCN */ + rtd_index = (grr_data->db.nc_ref_lst.info[j])->index; + /*Maximum number of ncell is 32 if it exceeds then store RTD_NOT_AVAILABLE for that ARFCN*/ + if(rtd_index < MAX_NR_OF_NCELL AND psc_db->rtd[rtd_index] NEQ RTD_NOT_AVAILABLE ) + { + rrgrr_check_bsic_req->ncell_sync_list[i].v_rtd = 1; + rrgrr_check_bsic_req->ncell_sync_list[i].rtd[rtd_count] = psc_db->rtd[rtd_index]; + rtd_count++; + }/*if*/ + } /*if*/ + j++; + } /*while*/ + rrgrr_check_bsic_req->ncell_sync_list[i].c_rtd = rtd_count; + i++; + } /*while*/ +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + + +#ifdef _SIMULATION_ + + i_max = i_max + 1; + while( i_max < RRGRR_MAX_ARFCN_NCELL_SYNC_REQ ) + { +#if defined (TI_PS_FF_RTD) AND defined (REL99) + rrgrr_check_bsic_req->ncell_sync_list[i_max].arfcn = RRGRR_INVALID_ARFCN; +#else + rrgrr_check_bsic_req->arfcn[i_max] = RRGRR_INVALID_ARFCN; +#endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ + + i_max++; + } +#endif +#else + + if( i < RRGRR_MAX_ARFCN_NCELL_SYNC_REQ ) + { + rrgrr_check_bsic_req->arfcn[i] = RRGRR_INVALID_ARFCN; + } + +#ifdef _SIMULATION_ + + i = i + 1; + while( i < RRGRR_MAX_ARFCN_NCELL_SYNC_REQ ) + { + rrgrr_check_bsic_req->arfcn[i] = RRGRR_INVALID_ARFCN; + i++; + } + +#endif /* #ifdef _SIMULATION_ */ + +#endif /* REL99 AND TI_PS_FF_EMR */ + + rrgrr_check_bsic_req->sync_type = SYNC_INITIAL; + PSEND( hCommRR, rrgrr_check_bsic_req ); + } +}/* cs_update_bsic */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_find_candidate ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_find_candidate ( void ) +{ + BOOL is_new_candidate = FALSE; + T_scell_info *sc; + + TRACE_FUNCTION( "cs_find_candidate" ); + + if( grr_data->cs.reselect_cause EQ CS_RESELECT_CAUSE_CTRL_ABNORMAL AND + psc_db->gen_cell_par.rab_acc_re EQ GRR_RA_RETRY_DISABLED ) + { + grr_data->db.cr_cell = NULL; + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "no candidate found, RA retry bit for abnormal cell re-selection not set" ); + } + +#endif /* #if !defined (NTRACE) */ + + } + else if( grr_data->cs.reselect_cause EQ CS_RESELECT_CAUSE_CTRL_SCELL ) + { + if( cs_create_cr_cell( psc_db->pbcch.bcch.arfcn, + psc_db->pbcch.bcch.bsic ) NEQ NULL ) + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "serving cell found as candidate" ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * the cell re-selection process will be started + */ + is_new_candidate = TRUE; + } + } + else + { + cs_get_best_cell( &grr_data->db.cr_cell, &sc ); + + if( grr_data->db.cr_cell NEQ NULL ) + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "candidate found" ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * the cell re-selection process will be started + */ + is_new_candidate = TRUE; + } + else if( sc NEQ NULL ) + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "no candidate found, serving cell good" ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * the serving cell becomes good again or is still good + */ + cs_stop_t_reselect( ); + } + else + { + +#if !defined (NTRACE) + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + TRACE_EVENT( "no candidate found, serving cell bad" ); + } + +#endif /* #if !defined (NTRACE) */ + + /* + * the serving cell becomes bad but + * no suitable neighbour cell is available + */ + cs_start_t_reselect( ); + } + } + + return( is_new_candidate ); +}/* cs_find_candidate */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_cr_decision ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_cr_decision ( T_CRDM mode ) +{ + T_NC_ORDER ctrl_order; + BOOL cr_initiated = FALSE; + + TRACE_FUNCTION( "cs_cr_decision" ); + + switch( mode ) + { + case( CRDM_T_RESELECT ): + sig_cs_ctrl_no_more_candidate( grr_data->cs.reselect_cause ); + + cr_initiated = TRUE; + break; + + case( CRDM_CR_CTRL ): + ctrl_order = cs_get_network_ctrl_order( TRUE ); + + if( ctrl_order EQ NC_NC0 OR + ctrl_order EQ NC_NC1 OR + grr_data->cs.reselect_cause EQ CS_RESELECT_CAUSE_CTRL_SCELL OR + ( grr_data->cs.reselect_cause EQ CS_RESELECT_CAUSE_CTRL_DL_SIG_FAIL AND + ctrl_order EQ NC_NC2 ) ) + { + /* + * Only in case the NETWORK_CONTROL_ORDER is either equal to + * NC0 or NC1 the MS shall perform automomous cell re-selection + */ + + if( cs_find_candidate( ) ) + { + sig_cs_ctrl_new_candidate( grr_data->cs.reselect_cause ); + } + else + { + sig_cs_ctrl_no_more_candidate( grr_data->cs.reselect_cause ); + } + } + else + { + sig_cs_ctrl_no_more_candidate( grr_data->cs.reselect_cause ); + } + + cr_initiated = TRUE; + break; + + case( CRDM_CR_INITIAL ): + ctrl_order = cs_get_network_ctrl_order( TRUE ); + + if( ctrl_order EQ NC_NC0 OR ctrl_order EQ NC_NC1 ) + { + /* + * Only in case the NETWORK_CONTROL_ORDER is either equal to + * NC0 or NC1 the MS shall perform automomous cell re-selection + */ + + grr_data->db.cr_cell = NULL; + + cs_calc_params( ); + + if( cs_find_candidate( ) ) + { + sig_cs_ctrl_new_candidate( grr_data->cs.reselect_cause ); + + cr_initiated = TRUE; + } + } + break; + + case( CRDM_CR_CONT ): + if( cs_find_candidate( ) ) + { + sig_cs_ctrl_new_candidate( grr_data->cs.reselect_cause ); + } + else + { + sig_cs_ctrl_no_more_candidate( grr_data->cs.reselect_cause ); + } + + cr_initiated = TRUE; + break; + + default: + TRACE_ASSERT( mode EQ CRDM_T_RESELECT OR + mode EQ CRDM_CR_CTRL OR + mode EQ CRDM_CR_INITIAL OR + mode EQ CRDM_CR_CONT ); + break; + } + + if( cr_initiated EQ TRUE ) + { + TRACE_EVENT_P2( "cs_cr_decision: mode %d, reselect_cause %d", + mode, grr_data->cs.reselect_cause ); + } + + return( cr_initiated ); + +}/* cs_cr_decision */ + + + + + +/* ++------------------------------------------------------------------------------ +| Function : cs_trace_nc_mval_lst ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_trace_nc_mval_lst ( void ) +{ + +#if !defined (NTRACE) + + UBYTE read, write; + USHORT arfcn[8]; + UBYTE bsic[8]; + T_NC_MVAL_STATUS status[8]; + T_RXLEV_AVG rxlev_avg[8]; + UBYTE rla_p_lev[8]; + UBYTE rla_p_stat[8]; + + + TRACE_FUNCTION( "cs_trace_nc_mval_lst" ); + + if( grr_data->cs.v_crp_trace EQ TRUE ) + { + memset( arfcn, 0xFF, sizeof( arfcn ) ); + memset( bsic, 0xFF, sizeof( bsic ) ); + memset( status, 0xFF, sizeof( status ) ); + memset( rxlev_avg, 0xFF, sizeof( rxlev_avg ) ); + memset( rla_p_lev, 0xFF, sizeof( rla_p_lev ) ); + memset( rla_p_stat, 0xFF, sizeof( rla_p_stat ) ); + + write = 0; + + for( read = 0; read < MAX_NR_OF_NC_MVAL; read++ ) + { + if( grr_data->db.nc_mval_list.nc_mval[read].status NEQ NC_MVAL_STAT_NONE ) + { + arfcn[write] = grr_data->db.nc_mval_list.nc_mval[read].arfcn; + bsic[write] = grr_data->db.nc_mval_list.nc_mval[read].sync_info.bsic; + status[write] = grr_data->db.nc_mval_list.nc_mval[read].status; + rla_p_lev [write] = grr_data->db.nc_mval_list.nc_mval[read].rla_p.lev; + rla_p_stat [write] = grr_data->db.nc_mval_list.nc_mval[read].rla_p.stat; + rxlev_avg [write] = grr_data->db.nc_mval_list.nc_mval[read].rxlev_avg; + + write++; + } + + if( write EQ 8 ) + { + TRACE_EVENT_P8 + ( "NC_MVAL_LIST ARFCN: %5d %5d %5d %5d %5d %5d %5d %5d", + arfcn[0], arfcn[1], arfcn[2], arfcn[3], + arfcn[4], arfcn[5], arfcn[6], arfcn[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST BSIC: %5d %5d %5d %5d %5d %5d %5d %5d", + bsic[0], bsic[1], bsic[2], bsic[3], + bsic[4], bsic[5], bsic[6], bsic[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST STATUS: %5d %5d %5d %5d %5d %5d %5d %5d", + status[0], status[1], status[2], status[3], + status[4], status[5], status[6], status[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST T_RXLEV_AVG: %5d %5d %5d %5d %5d %5d %5d %5d", + rxlev_avg[0], rxlev_avg[1], rxlev_avg[2], rxlev_avg[3], + rxlev_avg[4], rxlev_avg[5], rxlev_avg[6], rxlev_avg[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST rla_p.stat: %5d %5d %5d %5d %5d %5d %5d %5d", + rla_p_stat[0], rla_p_stat[1], rla_p_stat[2], rla_p_stat[3], + rla_p_stat[4], rla_p_stat[5], rla_p_stat[6], rla_p_stat[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST rla_p.lev: %5d %5d %5d %5d %5d %5d %5d %5d", + rla_p_lev[0], rla_p_lev[1], rla_p_lev[2], rla_p_lev[3], + rla_p_lev[4], rla_p_lev[5], rla_p_lev[6], rla_p_lev[7] ); + + memset( arfcn, 0xFF, sizeof( arfcn ) ); + memset( bsic, 0xFF, sizeof( bsic ) ); + memset( status, 0xFF, sizeof( status ) ); + memset( rxlev_avg, 0xFF, sizeof( rxlev_avg ) ); + memset( rla_p_lev, 0xFF, sizeof( rla_p_lev ) ); + memset( rla_p_stat, 0xFF, sizeof( rla_p_stat ) ); + + write = 0; + } + } + + if( write NEQ 0 ) + { + TRACE_EVENT_P8 + ( "NC_MVAL_LIST ARFCN: %5d %5d %5d %5d %5d %5d %5d %5d", + arfcn[0], arfcn[1], arfcn[2], arfcn[3], + arfcn[4], arfcn[5], arfcn[6], arfcn[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST BSIC: %5d %5d %5d %5d %5d %5d %5d %5d", + bsic[0], bsic[1], bsic[2], bsic[3], + bsic[4], bsic[5], bsic[6], bsic[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST STATUS: %5d %5d %5d %5d %5d %5d %5d %5d", + status[0], status[1], status[2], status[3], + status[4], status[5], status[6], status[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST T_RXLEV_AVG: %5d %5d %5d %5d %5d %5d %5d %5d", + rxlev_avg[0], rxlev_avg[1], rxlev_avg[2], rxlev_avg[3], + rxlev_avg[4], rxlev_avg[5], rxlev_avg[6], rxlev_avg[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST rla_p.stat: %5d %5d %5d %5d %5d %5d %5d %5d", + rla_p_stat[0], rla_p_stat[1], rla_p_stat[2], rla_p_stat[3], + rla_p_stat[4], rla_p_stat[5], rla_p_stat[6], rla_p_stat[7] ); + + TRACE_EVENT_P8 + ( "NC_MVAL_LIST rla_p.lev: %5d %5d %5d %5d %5d %5d %5d %5d", + rla_p_lev[0], rla_p_lev[1], rla_p_lev[2], rla_p_lev[3], + rla_p_lev[4], rla_p_lev[5], rla_p_lev[6], rla_p_lev[7] ); + } + } + +#endif /* #if !defined (NTRACE) */ + +} /* cs_trace_nc_mval_lst( ) */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_stop_cr_meas ++------------------------------------------------------------------------------ +| Description : The function cs_stop_cr_meas () .... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_stop_cr_meas( void ) +{ + TRACE_FUNCTION( "cs_stop_cr_meas" ); + + switch( grr_data->cs.cr_meas_mode ) + { + case( CS_CRMM_BA_GPRS ): + if( grr_data->cs.stop_req EQ FALSE ) + { + PALLOC( mphp_cr_meas_stop_req, MPHP_CR_MEAS_STOP_REQ ); + +#if 0 + + /* + * the timing for the MPHP_CR_MEAS_STOP_CON is not correct on + * layer 1 side, so we are no longer consider the confirmation + */ + + grr_data->cs.stop_req = TRUE; + +#endif /* #if 0 */ + + PSEND( hCommL1, mphp_cr_meas_stop_req ); + } + break; + case( CS_CRMM_BA_BCCH ): + grr_data->cs.cr_meas_update = FALSE; + break; + } +} /* cs_stop_cr_meas() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_req_cr_meas ++------------------------------------------------------------------------------ +| Description : The function cs_req_cr_meas () .... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_req_cr_meas ( void ) +{ + TRACE_FUNCTION( "cs_req_cr_meas" ); + + if( nc_data->c_cell NEQ 0 ) + { + if( grr_data->cs_meas.packet_mode NEQ PACKET_MODE_PTM ) + { + PALLOC( mphp_cr_meas_req, MPHP_CR_MEAS_REQ ); + + cs_fill_cr_meas_req( mphp_cr_meas_req, grr_data->cs.list_id ); + + grr_data->cs.list_id++; + + PSEND( hCommL1, mphp_cr_meas_req ); + } + else + { + PALLOC( mphp_tcr_meas_req, MPHP_TCR_MEAS_REQ ); + + grr_data->cs.last_assignment_id++; + grr_data->cs.cr_meas_update = TRUE; + + cs_fill_cr_meas_req( (T_MPHP_CR_MEAS_REQ*)mphp_tcr_meas_req, + grr_data->cs.last_assignment_id ); + + PSEND( hCommL1, mphp_tcr_meas_req ); + } + + grr_data->cs.stop_req = FALSE; + } +} /* cs_req_cr_meas() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_fill_cr_meas_req ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : prim - Pointer to primitive buffer +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_fill_cr_meas_req ( T_MPHP_CR_MEAS_REQ *prim, UBYTE id ) +{ + UBYTE i; /* used for counting */ + + TRACE_FUNCTION( "cs_fill_cr_meas_req" ); + + prim->nb_carrier = nc_data->c_cell; + prim->list_id = id; + + for( i = 0; i < nc_data->c_cell; i++ ) + { +#if defined (REL99) AND defined (TI_PS_FF_EMR) + prim->carrier_list[i] = grr_g23_arfcn_to_l1(nc_data->cell[i].arfcn); +#else + prim->carrier_list[i] = nc_data->cell[i].arfcn; +#endif + } + +#ifdef _SIMULATION_ + + for( i = nc_data->c_cell; i < MPHP_NUMC_BA_GPRS_SC; i++ ) + { + prim->carrier_list[i] = 0xFFFF; + } + +#endif /* #ifdef _SIMULATION_ */ + +} /* cs_fill_cr_meas_req() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_reset_all_cell_results ++------------------------------------------------------------------------------ +| Description : The function cs_reset_all_cell_results() .... +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_reset_all_cell_results ( void ) +{ + UBYTE i; /* used for counting */ + + TRACE_FUNCTION( "cs_reset_all_cell_results" ); + + for( i = 0; i < MPHP_NUMC_BA_GPRS_SC; i++ ) + { + cs_reset_meas_result( &nc_data->cell[i] ); + } +} /* cs_reset_all_cell_results () */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_reset_all_rxlev_results ++------------------------------------------------------------------------------ +| Description : The function cs_reset_all_rxlev_results() .... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_reset_all_rxlev_results ( void ) +{ + UBYTE i; /* used for counting */ + + TRACE_FUNCTION( "cs_reset_all_rxlev_results" ); + + for( i = 0; i < MPHP_NUMC_BA_GPRS_SC; i++ ) + { + nc_data->cell[i].rxlev_data.acc = 0; + nc_data->cell[i].rxlev_data.nbr = 0; + } +} /* cs_reset_all_rxlev_results () */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_reset_meas_result ++------------------------------------------------------------------------------ +| Description : The function cs_reset_meas_result() .... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_reset_meas_result ( T_CELL *cell ) +{ + T_RLA_P_DATA *rla_p_data = &cell->rla_p_data; + T_RXLEV_DATA *rxlev_data = &cell->rxlev_data; + + UBYTE i; /* used for counting */ + + TRACE_FUNCTION( "cs_reset_meas_result" ); + TRACE_EVENT_P2( "cs_reset_meas_result arfcn =%ld LOI=%ld",cell->arfcn,rla_p_data->loi ); + + rla_p_data->loi = CS_IDX_NOT_USED; + rla_p_data->ovrflw = FALSE; + + for( i = 0; i < CS_MAX_MEAS_RSLT; i++ ) + { + rla_p_data->meas[i].cnt = 0; + rla_p_data->meas[i].acc = 0; + rla_p_data->meas[i].rpt_prd = 0; + } + + rxlev_data->acc = 0; + rxlev_data->nbr = 0; +} /* cs_reset_meas_result () */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_fill_meas_rslt ++------------------------------------------------------------------------------ +| Description : ... +| +| Parameters : ... +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_fill_meas_rslt ( T_MPHP_CR_MEAS_IND *mphp_cr_meas_ind, + T_MPHP_TCR_MEAS_IND *mphp_tcr_meas_ind ) +{ + T_RLA_P_DATA *rla_p_data; + T_RXLEV_DATA *rxlev_data; + + T_RXLEV_DATA_NBR del_nbr; + + UBYTE i; + UBYTE index = 0; + BOOL ovrflw = FALSE; + + UBYTE cnt; + SHORT acc; + USHORT rpt_prd; + + TRACE_FUNCTION( "cs_fill_meas_rslt" ); + + if( mphp_cr_meas_ind NEQ NULL ) + { + rpt_prd = mphp_cr_meas_ind->reporting_period; + } + else + { + rpt_prd = CS_RPT_PRD_PTM; + } + + /* + * Process all data relevant for RLA_P derivation + */ + + for( i = 0; i < nc_data->c_cell; i++ ) + { + rla_p_data = &nc_data->cell[i].rla_p_data; + rxlev_data = &nc_data->cell[i].rxlev_data; + + if( mphp_cr_meas_ind NEQ NULL ) + { + cnt = 1; + if((signed char)mphp_cr_meas_ind->p_ncell_meas[i].rxlev <0) + { + acc = 0; + } + else + { + acc = (signed char)mphp_cr_meas_ind->p_ncell_meas[i].rxlev; + } + } + else + { + cnt = mphp_tcr_meas_ind->acc_nbr[i]; + if((SHORT)mphp_tcr_meas_ind->acc_level[i] <0) + { + acc = 0; + } + else + { + acc = mphp_tcr_meas_ind->acc_level[i]; + } + } + + if( rla_p_data->loi NEQ CS_IDX_NOT_USED ) + { + if( rla_p_data->loi EQ CS_MAX_MEAS_RSLT - 1 ) + { + ovrflw = TRUE; + } + else + { + index = rla_p_data->loi + 1; + } + } + + if( cnt EQ 0 ) + { + if( rla_p_data->meas[index].cnt EQ 0 ) + { + rla_p_data->meas[index].rpt_prd += rpt_prd; + } + else + { + rla_p_data->meas[index].cnt = 0; + rla_p_data->meas[index].acc = 0; + rla_p_data->meas[index].rpt_prd = rpt_prd; + } + } + else + { + rla_p_data->meas[index].cnt = cnt; + rla_p_data->meas[index].acc = acc; + rla_p_data->meas[index].rpt_prd = rpt_prd; + + rla_p_data->loi = index; + + /* if an overflow once occured it will be forever */ + if( rla_p_data->ovrflw EQ FALSE ) + { + rla_p_data->ovrflw = ovrflw; + } + } + + /* + * Process all data relevant for average RXLEV derivation + */ + + if( cnt NEQ 0 ) + { + if( rxlev_data->nbr > RXLEV_MAX_NBR - cnt ) + { + del_nbr = cnt - ( RXLEV_MAX_NBR - rxlev_data->nbr ); + rxlev_data->acc -= del_nbr * ( rxlev_data->acc / rxlev_data->nbr ); + rxlev_data->nbr -= del_nbr; + } + + rxlev_data->acc += ( acc * RXLEV_ACRCY ); + rxlev_data->nbr += cnt; + } + } +} /* cs_fill_meas_rslt() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_rla_p ++------------------------------------------------------------------------------ +| Description : The function cs_get_rla_p() .... +| +| Parameters : rla_p_data - pointer to RLA_P raw data +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_get_rla_p( T_RLA_P_DATA *rla_p_data, UBYTE *rla_p ) +{ + BOOL s_avg; /* status of average RXLEV value */ + LONG avg; /* average RXLEV value used for cell re-selection */ + LONG cnt = 0; /* number of accumulated measurement samples */ + LONG acc = 0; /* accumulated receive level values */ + ULONG run_avg_prd = 0; /* running average period */ + UBYTE c_meas = 0; /* number of measurements */ + UBYTE index = rla_p_data->loi; + /* index to actual used measurement result */ + BOOL v_meas_left = rla_p_data->loi NEQ CS_IDX_NOT_USED; + /* indicates whether more measurement results */ + /* are not yet considered */ + + TRACE_FUNCTION( "cs_get_rla_p" ); + + while( + ( + c_meas < CS_MIN_RLA_P_SAMPLES OR + run_avg_prd < CS_MIN_RUN_AVG_PRD + ) + AND + ( + v_meas_left EQ TRUE + ) + ) + { + /* + * check whether valid measurement results are available + */ + if( rla_p_data->meas[index].cnt NEQ 0 AND + c_meas < CS_MAX_MEAS_RSLT ) + { + c_meas++; + + /* + * accumulate individual measurement results + */ + run_avg_prd += rla_p_data->meas[index].rpt_prd; + cnt += rla_p_data->meas[index].cnt; + acc += rla_p_data->meas[index].acc; + + /* determine the next index to be used for RLA_P calculation */ + if( index EQ 0 ) + { + if( rla_p_data->ovrflw EQ TRUE ) + { + index = CS_MAX_MEAS_RSLT - 1; + } + else + { + v_meas_left= FALSE; + } + } + else + { + index--; + } + + + } + else + { + v_meas_left = FALSE; + } + } + + /* + * calculate status of RLA_P + */ + if( cnt EQ 0 ) + { + s_avg = CS_RLA_P_NOT_AVAIL; + } + else if( + ( + c_meas < CS_MIN_RLA_P_SAMPLES + ) + OR + ( + run_avg_prd < CS_MIN_RUN_AVG_PRD + AND + c_meas < CS_MAX_MEAS_RSLT + ) + ) + { + s_avg = CS_RLA_P_NOT_VALID; + } + else + { + s_avg = CS_RLA_P_VALID; + } + + if( cnt > 0 ) + { + /* + * calculate RLA_P + */ + avg = acc / cnt; + + + /* + * clip RLA_P to values between 0 and 63 + */ + if( (signed char)( avg ) < CGRLC_RXLEV_MIN ) + { + avg = CGRLC_RXLEV_MIN; + } + else if ( (signed char)( avg ) > CGRLC_RXLEV_MAX ) + { + avg = CGRLC_RXLEV_MAX; + } + } + else + { + avg = CGRLC_RXLEV_NONE; + } + + + *rla_p = (UBYTE)avg; + + return( s_avg ); + +} /* cs_get_rla_p () */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_rxlev_avg ++------------------------------------------------------------------------------ +| Description : The function cs_get_rxlev_avg() .... +| +| Parameters : rxlev_data - pointer to RXLEV raw data +| ++------------------------------------------------------------------------------ +*/ +GLOBAL T_RXLEV_AVG cs_get_rxlev_avg( T_RXLEV_DATA *rxlev_data ) +{ + T_RXLEV_AVG rxlev_avg; + + TRACE_FUNCTION( "cs_get_rxlev_avg" ); + + + if( rxlev_data->nbr EQ 0 ) + { + rxlev_avg = RXLEV_AVG_INVALID; + } + else + { + rxlev_avg = + ( T_RXLEV_AVG )( rxlev_data->acc / ( rxlev_data->nbr * RXLEV_ACRCY ) ); + } + + TRACE_EVENT_P2("1_cs_get_rxlev_avg: nbr=%ld rx_avg=%ld",rxlev_data->nbr,rxlev_avg); + + return( rxlev_avg ); +} /* cs_get_rxlev_avg () */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_tcr_meas_ind_to_pl ++------------------------------------------------------------------------------ +| Description : The function cs_tcr_meas_ind_to_pl () forwards the cell +| re-selection measurement results catched during packet transfer +| mode to ALR. +| +| Parameters : prim - pointer to primitive payload +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_tcr_meas_ind_to_pl ( T_MPHP_TCR_MEAS_IND * prim ) +{ + UBYTE i; /* used for counting */ + + TRACE_FUNCTION( "cs_tcr_meas_ind_to_pl" ); + + { + PALLOC( tb_meas_ind, TB_MEAS_IND ); + + for( i = 0; i < TB_BA_LIST_SIZE; i++ ) + { + if(( grr_data->cs.cr_meas_update EQ TRUE) AND + (nc_data->cell[i].arfcn NEQ 0)) + { + if(nc_data->cell[i].arfcn NEQ 0) + { + tb_meas_ind->tb_meas_result[i].arfcn = grr_g23_arfcn_to_l1(nc_data->cell[i].arfcn); + } + else + { + tb_meas_ind->tb_meas_result[i].arfcn = TB_INVALID_ARFCN; + } + } + else + { + tb_meas_ind->tb_meas_result[i].arfcn = TB_INVALID_ARFCN; + } + + tb_meas_ind->tb_meas_result[i].rxlev = prim->acc_level[i]; + tb_meas_ind->tb_meas_result[i].num_meas = prim->acc_nbr[i]; + } + + PSEND( hCommPL, tb_meas_ind ); + } +} /* cs_tcr_meas_ind_to_pl() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_create_cr_cell ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL T_NC_MVAL* cs_create_cr_cell ( USHORT arfcn, UBYTE bsic ) +{ + T_NC_MVAL *nc_mval; + UBYTE nc_mval_idx; + + TRACE_FUNCTION( "cs_create_cr_cell" ); + + /* if the new selected cell is not found in the neighbour cell list */ + nc_mval = grr_get_nc_mval( RRGRR_INVALID_ARFCN, RRGRR_INVALID_BSIC, &nc_mval_idx ); + + if( nc_mval NEQ NULL ) + { + nc_mval->arfcn = arfcn; + nc_mval->sync_info.bsic = bsic; + + /* + * The function cs_create_cr_cell is only called in case of processing a + * packet cell change order. If the packet cell change order has been + * received on a cell without PBCCH, GRR should forward the RRGRR_CR_REQ + * with parameter CR_NEW in all cases. This is forced by setting the + * synchronisation status to STAT_SYNC_OK. + */ + if( grr_is_pbcch_present( ) ) + { + TRACE_EVENT( "cs_create_cr_cell: cell not part of neighbour cell list" ); + + nc_mval->sync_info.sync.status = STAT_SYNC_NONE; + } + else + { + nc_mval->sync_info.sync.status = STAT_SYNC_OK; + } + + grr_data->db.cr_cell = &grr_data->db.nc_nw_slctd.strgst; + grr_data->db.cr_cell->idx = nc_mval_idx; + grr_data->db.cr_cell->mode = CS_MODE_IDLE; + grr_data->db.cr_cell->avail_time = 0; + } + + return( nc_mval ); + +} /* cs_create_cr_cell() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_nc_rpt_prd_idle ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL T_TIME cs_get_nc_rpt_prd_idle ( void ) +{ + T_TIME reporting_period; + ULONG small_int_multi; /* smallest integer multiple of DRX period */ + ULONG drx_period; /* DRX period in milliseconds */ + + TRACE_FUNCTION( "cs_get_nc_rpt_prd_idle" ); + + reporting_period = GET_NC_RPT_PRD( grr_data->db.nc_ref_lst.param->rep_per_i ); + drx_period = meas_im_get_drx_period_seconds( ); + drx_period = M_ROUND_UP( drx_period, DRX_NORM_FACTOR ); + + /* + * In packet idle mode, the reporting period is NC_REPORTING_PERIOD_I + * rounded off to the nearest smaller integer multiple of DRX period + * if NC_REPORTING_PERIOD_I is greater than DRX period, else, the + * reporting period is DRX period. + */ + if( drx_period NEQ NO_PAGING ) + { + if( reporting_period > drx_period ) + { + small_int_multi = reporting_period / drx_period; + reporting_period = drx_period * small_int_multi; + } + else + { + reporting_period = drx_period; + } + } + + return( reporting_period ); + +} /* cs_get_nc_rpt_prd_idle() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_reset_meas_rep_params ++------------------------------------------------------------------------------ +| Description : This function will reset measurement reporting parameters +| +| Parameters : db - pointer to serving cell database +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_reset_meas_rep_params ( T_SC_DATABASE *db ) +{ + TRACE_FUNCTION( "cs_reset_meas_rep_params" ); + + db->nc_ms.ncmeas.param.ctrl_order = NC_RESET; + db->nc_ms.ncmeas.param.rep_per_i = 0; + db->nc_ms.ncmeas.param.rep_per_t = 0; + +} /* cs_reset_meas_rep_params() */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_check_nc_sync_timer ++------------------------------------------------------------------------------ +| Description : Handles the nc sync timer of 10 sec in case of PIM_PBCCH and +| PTM_PBCCH +| +| Parameters : reporting_period +| ++------------------------------------------------------------------------------ +*/ + + +GLOBAL void cs_check_nc_sync_timer(USHORT reporting_pd) +{ + if(!grr_data->db.cnt_nc_six.candid) return; + grr_data->cs.nc_sync_rep_pd += reporting_pd; + + + if(grr_data->cs.nc_sync_rep_pd >= CS_NCSYNC_RPT_PRD_PIM) + { + PALLOC( rrgrr_check_bsic_req, RRGRR_NCELL_SYNC_REQ ); + rrgrr_check_bsic_req->sync_type = SYNC_RECONFIRM; + PSEND( hCommRR, rrgrr_check_bsic_req ); + /*subtracting nc_sync_rep_pd from CS_NCSYNC_RPT_PRD_PIM wil provide take care + of periodicity of non-uniform reporting_period values*/ + TRACE_EVENT_P1("GRR_NC_SYNC:EXPIRY: nc_sync_rep_pd=%d", grr_data->cs.nc_sync_rep_pd); + grr_data->cs.nc_sync_rep_pd -= CS_NCSYNC_RPT_PRD_PIM; + } + return; + +} + +/* ++------------------------------------------------------------------------------ +| Function : cs_process_serving_cell_data ++------------------------------------------------------------------------------ +| Description : This function is used to fill rxlev and interference measurements +| of the serving cell +| +| Parameters : rxlev, iscell +| ++------------------------------------------------------------------------------ +*/ +LOCAL BOOL cs_process_serving_cell_data ( UBYTE *rxlev_scell, UBYTE *v_i_scell, + UBYTE *i_scell, UBYTE *used_bits, + BOOL *rsc_avail, BOOL *isc_avail ) + +{ + TRACE_FUNCTION( "cs_process_serving_cell_data" ); + + *used_bits += NC_RXLEV_SCELL_LEN; + + if( grr_data->db.scell_info.rxlev_avg EQ RXLEV_AVG_INVALID ) + { + TRACE_ERROR( "cs_build_xxx_meas_rpt no RXLEV of serving cell" ); + return( FALSE ); + } + else + { + *rsc_avail = TRUE; + *rxlev_scell = grr_data->db.scell_info.rxlev_avg; + } + + /* process interference measurement of serving cell */ + *used_bits += PMR_FLAG_LEN; + *v_i_scell = FALSE; + + if( grr_is_pbcch_present( ) EQ TRUE AND + psc_db->paging_group.kc NEQ 0 AND + grr_data->cs_meas.packet_mode EQ PACKET_MODE_PIM ) + { + T_p_frequency_par freq_par; + + if( grr_get_pccch_freq_par + ( ( UBYTE )( grr_imsi_mod( ) % psc_db->paging_group.kc ), + &freq_par.p_chan_sel, &freq_par.p_freq_list ) ) + { + T_MEAS_IM_CARRIER ma; + UBYTE written_bits; + T_ilev_abs i_level; + + meas_im_set_carrier( &ma, &freq_par ); + + written_bits = meas_im_get_abs_i_level( &ma, &i_level ); + + if( written_bits > CGRLC_MAX_TIMESLOTS * PMR_FLAG_LEN ) + { + *v_i_scell = TRUE; + *used_bits += NC_IF_SCELL_LEN; + + if ( i_level.v_ilevabs0 EQ TRUE ) + { + *i_scell = i_level.ilevabs0; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs1 EQ TRUE ) + { + *i_scell = i_level.ilevabs1; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs2 EQ TRUE ) + { + *i_scell = i_level.ilevabs2; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs3 EQ TRUE ) + { + *i_scell = i_level.ilevabs3; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs4 EQ TRUE ) + { + *i_scell = i_level.ilevabs4; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs5 EQ TRUE ) + { + *i_scell = i_level.ilevabs5; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs6 EQ TRUE ) + { + *i_scell = i_level.ilevabs6; + *isc_avail = TRUE; + } + else if( i_level.v_ilevabs7 EQ TRUE ) + { + *i_scell = i_level.ilevabs7; + *isc_avail = TRUE; + } + else + { + TRACE_ERROR( "cs_process_serving_cell_data corrupted I_LEVEL data" ); + return( FALSE ); + } + } + } + } + return(TRUE); +}/* cs_process_serving_cell_data */ + +#if defined (REL99) AND defined (TI_PS_FF_EMR) +/* ++------------------------------------------------------------------------------ +| Function : cs_send_enh_meas_rpt ++------------------------------------------------------------------------------ +| Description : This function is used to send enh meas report to the network +| +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +GLOBAL BOOL cs_send_enh_meas_rpt (void) +{ + T_U_ENHNC_MEAS_REPORT enh_meas_rpt; + BOOL rpt_send; + + TRACE_FUNCTION( "cs_send_enh_meas_rpt" ); + + if(grr_is_pbcch_present()) + { + cs_form_enh_cell_list(); + } + else + { + cs_form_ba_bcch_enh_cell_list(); + } + + cs_nc_sort_and_update_emr_info(); + + memset (&enh_meas_rpt, 0, sizeof(T_U_ENHNC_MEAS_REPORT)); + + rpt_send = cs_build_enh_meas_rpt(&enh_meas_rpt); + + if( rpt_send EQ TRUE ) + { + sig_cs_ctrl_enh_meas_report(&enh_meas_rpt); + } + + return(rpt_send); + +} /* cs_send_enh_meas_rpt() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_form_enh_cell_list ++------------------------------------------------------------------------------ +| Description : This function is used to form enhanced cell list from BA list +| (nc_ref_lst) and Measured values list(nc_mval_list) +| +| +| Parameters : Nil +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_form_enh_cell_list(void) +{ + UBYTE i = 0, n = 0, j; + UBYTE nc_ref_index_arfcn, nc_ref_index_bsic; + + TRACE_FUNCTION( "cs_form_enh_cell_list" ); + + memset((grr_data->db.enh_cell_list), 0xFF, sizeof(T_ENH_CELL_LIST)*MAX_NR_OF_NCELL); + + grr_data->db.cnt_enh_cell_list = 0; + + /* Check one entry of Measured values list against all entries of BA list */ + while(i < MAX_NR_OF_NC_MVAL AND n < MAX_NR_OF_NCELL) + { + if( (grr_data->db.nc_mval_list.nc_mval[i].status EQ NC_MVAL_STAT_ASSIGNED) + AND + (grr_data->db.nc_mval_list.nc_mval[i].arfcn NEQ RRGRR_INVALID_ARFCN) + AND + (grr_data->db.nc_mval_list.nc_mval[i].sync_info.sync.status EQ + STAT_SYNC_OK) + AND + (grr_data->db.nc_mval_list.nc_mval[i].rla_p.stat EQ CS_RLA_P_VALID) ) + { + nc_ref_index_arfcn = NOT_SET; /* Will be set the 1st time ARFCN matches + in the BA list */ + nc_ref_index_bsic = NOT_SET; /* Will be set the 1st time ARFCN-BSIC pair + matches in the BA list */ + + /* Comparison with BA list */ + for (j = 0; j < grr_data->db.nc_ref_lst.number; j++) + { + if(grr_data->db.nc_mval_list.nc_mval[i].arfcn EQ + grr_data->db.nc_ref_lst.info[j]->arfcn) + { + if(nc_ref_index_arfcn EQ NOT_SET) + { + /* ARFCN matched for the 1st time in BA list */ + nc_ref_index_arfcn = j; + } + + /* In case the same cell (ARFCN+BSIC) or the same ARFCN without BSIC + occur more than once in the resulting GSM Neighbour Cell list, + each occurrence shall be assigned an index but only the cell with + the highest index shall be used for cell re-selection and referred + to in measurement reports. */ + if(grr_data->db.nc_ref_lst.info[j]->index > + grr_data->db.nc_ref_lst.info[nc_ref_index_arfcn]->index) + { + nc_ref_index_arfcn = j; + } + + if(grr_data->db.nc_mval_list.nc_mval[i].sync_info.bsic EQ + grr_data->db.nc_ref_lst.info[j]->bsic) + { + nc_ref_index_bsic = nc_ref_index_arfcn; + } + } + } + + /* Store ARFCN, BSIC, RLA_P and RXLEV, if ARFCN and/or BSIC matches */ + if(nc_ref_index_arfcn NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].arfcn = + grr_data->db.nc_mval_list.nc_mval[i].arfcn; + + grr_data->db.enh_cell_list[n].bsic.bsic = + grr_data->db.nc_mval_list.nc_mval[i].sync_info.bsic; + + grr_data->db.enh_cell_list[n].rla_p = + grr_data->db.nc_mval_list.nc_mval[i].rla_p.lev; + + grr_data->db.enh_cell_list[n].rxlev_avg = + grr_data->db.nc_mval_list.nc_mval[i].rxlev_avg; + } + + /* Store in the enhanced cell list as Valid and Invalid BSICs */ + if (nc_ref_index_bsic NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].index = + grr_data->db.nc_ref_lst.info[nc_ref_index_bsic]->index; + + grr_data->db.enh_cell_list[n].rept_prio = + grr_data->db.nc_ref_lst.enh_param->gprs_rept_prio_desc. + rept_prio[grr_data->db.nc_ref_lst.info[nc_ref_index_bsic]->index]; + + grr_data->db.enh_cell_list[n++].bsic.status = BSIC_VALID; + } + else if(nc_ref_index_arfcn NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].index = + grr_data->db.nc_ref_lst.info[nc_ref_index_arfcn]->index; + /* Set the reporting priority to high for invalid BSICs and allowed + NCC part. Refer Section 8.4.8.1 of 3GPP TS 05.08 V8.15.0 (2002-06) */ + grr_data->db.enh_cell_list[n].rept_prio = HIGH_PRIO; + grr_data->db.enh_cell_list[n++].bsic.status = BSIC_INVALID; + } + } + i++; + } + grr_data->db.cnt_enh_cell_list = n; +}/* cs_form_enh_cell_list */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_form_ba_bcch_enh_cell_list ++------------------------------------------------------------------------------ +| Description : This function is used to form enhanced cell list from BA list +| (nc_ref_lst) and Measured values list(nc_mval_list) +| +| +| Parameters : Nil +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_form_ba_bcch_enh_cell_list(void) +{ + UBYTE i = 0, n = 0, j; + UBYTE nc_ref_index_arfcn, nc_ref_index_bsic; + + TRACE_FUNCTION( "cs_form_ba_bcch_enh_cell_list" ); + + memset((grr_data->db.enh_cell_list), 0xFF, sizeof(T_ENH_CELL_LIST)*MAX_NR_OF_NCELL); + + grr_data->db.cnt_enh_cell_list = 0; + + /* Check one entry of Measured values list against all entries of BA list */ + while(i < MAX_NR_OF_NC_MVAL AND n < MAX_NR_OF_NCELL) + { + if( (grr_data->db.nc_mval_list.nc_mval[i].status EQ NC_MVAL_STAT_ASSIGNED) + AND + (grr_data->db.nc_mval_list.nc_mval[i].arfcn NEQ RRGRR_INVALID_ARFCN) + AND + (grr_data->db.nc_mval_list.nc_mval[i].sync_info.sync.status EQ + STAT_SYNC_OK) + AND + (grr_data->db.nc_mval_list.nc_mval[i].rla_p.stat EQ CS_RLA_P_VALID) ) + { + nc_ref_index_arfcn = NOT_SET; /* Will be set the 1st time ARFCN matches + in the BA list */ + nc_ref_index_bsic = NOT_SET; /* Will be set the 1st time ARFCN-BSIC pair + matches in the BA list */ + + /* Comparison with BA list */ + for (j = 0; j < grr_data->db.ba_bcch_nc_ref_lst.number; j++) + { + if(grr_data->db.nc_mval_list.nc_mval[i].arfcn EQ + grr_data->db.ba_bcch_nc_ref_lst.info[j]->arfcn) + { + if(nc_ref_index_arfcn EQ NOT_SET) + { + /* ARFCN matched for the 1st time in BA list */ + nc_ref_index_arfcn = j; + } + + /* In case the same cell (ARFCN+BSIC) or the same ARFCN without BSIC + occur more than once in the resulting GSM Neighbour Cell list, + each occurrence shall be assigned an index but only the cell with + the highest index shall be used for cell re-selection and referred + to in measurement reports. */ + if(grr_data->db.ba_bcch_nc_ref_lst.info[j]->index > + grr_data->db.ba_bcch_nc_ref_lst.info[nc_ref_index_arfcn]->index) + { + nc_ref_index_arfcn = j; + } + + if(grr_data->db.nc_mval_list.nc_mval[i].sync_info.bsic EQ + grr_data->db.ba_bcch_nc_ref_lst.info[j]->bsic) + { + nc_ref_index_bsic = nc_ref_index_arfcn; + } + } + } + + /* Store ARFCN, BSIC, RLA_P AND RXLEV, if ARFCN and/or BSIC matches */ + if(nc_ref_index_arfcn NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].arfcn = + grr_data->db.nc_mval_list.nc_mval[i].arfcn; + + grr_data->db.enh_cell_list[n].bsic.bsic = + grr_data->db.nc_mval_list.nc_mval[i].sync_info.bsic; + + grr_data->db.enh_cell_list[n].rla_p = + grr_data->db.nc_mval_list.nc_mval[i].rla_p.lev; + + grr_data->db.enh_cell_list[n].rxlev_avg = + grr_data->db.nc_mval_list.nc_mval[i].rxlev_avg; + } + + /* Store in the enhanced cell list as Valid and Invalid BSICs */ + if (nc_ref_index_bsic NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].index = + grr_data->db.ba_bcch_nc_ref_lst.info[nc_ref_index_bsic]->index; + + grr_data->db.enh_cell_list[n].rept_prio = + grr_data->db.nc_ref_lst.enh_param->gprs_rept_prio_desc. + rept_prio[grr_data->db.ba_bcch_nc_ref_lst.info[nc_ref_index_bsic]->index]; + + grr_data->db.enh_cell_list[n++].bsic.status = BSIC_VALID; + } + else if(nc_ref_index_arfcn NEQ NOT_SET) + { + grr_data->db.enh_cell_list[n].index = + grr_data->db.ba_bcch_nc_ref_lst.info[nc_ref_index_arfcn]->index; + /* Set the reporting priority to high for invalid BSICs and allowed + NCC part. Refer Section 8.4.8.1 of 3GPP TS 05.08 V8.15.0 (2002-06) */ + grr_data->db.enh_cell_list[n].rept_prio = HIGH_PRIO; + grr_data->db.enh_cell_list[n++].bsic.status = BSIC_INVALID; + } + } + i++; + } + grr_data->db.cnt_enh_cell_list = n; +}/* cs_form_ba_bcch_enh_cell_list */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_nc_sort_and_update_emr_info ++------------------------------------------------------------------------------ +| Description : The purpose of this function is to handle all the specific +| requirements for EMR - sorting according to priority as given +| in 5.08 V8.16.0, sec.8.4.8.1, and scaling of rxlev values. +| +| +| Parameters : Nil +| ++------------------------------------------------------------------------------ +*/ + +LOCAL void cs_nc_sort_and_update_emr_info(void) +{ + T_ENH_BIN sc_bin; + T_ENH_BIN mband_bin[5]; /* 0 - 900, 1 - 1800, 2 - 400, 3 - 1900, 4 - 850*/ + T_ENH_BIN rest_bin; + UBYTE i; + UBYTE temp; + T_GRR_ENH_PARA *p_enh = grr_data->db.nc_ref_lst.enh_param; + T_ENH_CELL_LIST *enh_cell_list = &(grr_data->db.enh_cell_list[0]); + BOOL include_cell = FALSE; + grr_data->db.sorted_enh_cell_list.num_valid = 0; + + TRACE_FUNCTION( "cs_nc_sort_and_update_emr_info" ); + + /* Flush off the old sorted ENH cell list before forming a new one */ + memset(&grr_data->db.sorted_enh_cell_list,0,sizeof(T_ENH_BIN)); + + /* Step 1: Sort cells into different bins - serving cell band bin, + non-serving cell band bin, and the rest which can contain invalid BSIC + cells */ + cs_nc_sort_cells_into_bins(&sc_bin, mband_bin, &rest_bin); + + /* Step 2: Fill the cells from each bin, after sorting in descending order + of RXLEV, in the order of : sc_bin, mband_bin and rest_bin. + Further number of cells from sc_bin and mband_bin is restricted by SERVING_BAND + and MULTIBAND reporting parameters */ + if ( (sc_bin.num_valid > 0) AND (p_enh->servingband_rep > 0) ) + { + cs_nc_sort_and_store_meas_results(&sc_bin, p_enh->servingband_rep); + if (sc_bin.num_valid > p_enh->servingband_rep) + { + cs_nc_update_rest_bin(&rest_bin, &sc_bin, p_enh->servingband_rep); + } + } + + /* Fill cells from multi band after sorting*/ + for ( i = 0; i < MAX_NUM_BANDS AND + grr_data->db.sorted_enh_cell_list.num_valid + < grr_data->db.cnt_enh_cell_list; i++) + { + if ( (mband_bin[i].num_valid > 0) AND (p_enh->multiband_rep > 0) ) + { + cs_nc_sort_and_store_meas_results(&mband_bin[i], p_enh->multiband_rep); + if (mband_bin[i].num_valid > p_enh->multiband_rep) + { + cs_nc_update_rest_bin(&rest_bin, &mband_bin[i], p_enh->multiband_rep ); + } + } + } + + /* Now sort cells in the rest bin which may contain both valid and + invalid BSIC cells. Here we use the reporting offset along with measured RXLEV, + for sorting. According to 5.08, sec.8.4.8.1 we need to find those cells whose sum of + RXLEV and xxx_reporting_offset is maximum. This can be acheived by sorting the cells + in the order of their rxlevm, where rxlevm = rxlev + offset */ + if ( (rest_bin.num_valid > 0) AND (grr_data->db.sorted_enh_cell_list.num_valid + < grr_data->db.cnt_enh_cell_list) ) + { + UBYTE j; + UBYTE max_rxlevm; + UBYTE band; + UBYTE rxlevm; + UBYTE k; + T_ncell_info *ncell; + + for (i = 0; i < rest_bin.num_valid; i++) + { + band = cs_get_band_index_for_emr (enh_cell_list[rest_bin.enh_index[i]].arfcn); + max_rxlevm = enh_cell_list[rest_bin.enh_index[i]].rla_p + + (p_enh->enh_rep_data[band].rep_offset * 6); + k = i; + for ( j = i+1; j < rest_bin.num_valid ; j++ ) + { + band = cs_get_band_index_for_emr (enh_cell_list[rest_bin.enh_index[j]].arfcn); + rxlevm = enh_cell_list[rest_bin.enh_index[j]].rla_p + + (p_enh->enh_rep_data[band].rep_offset * 6) ; + if ( rxlevm > max_rxlevm ) + { + k = j; + max_rxlevm = rxlevm; + } + } + include_cell = TRUE; + /* When reduced reporting is enabled we have to report low priority cell + once in 4 reporting periods. The RXLEV then should be average of previous + two periods */ + if ( (enh_cell_list[rest_bin.enh_index[k]].rept_prio EQ NORMAL_PRIO) AND + (p_enh->rep_rate EQ REPORTING_RATE_REDUCED) ) + { + /* ncell cannot be NULL since the loop will be entered only for a + valid BSIC */ + ncell = grr_get_ncell_info(enh_cell_list[rest_bin.enh_index[k]].arfcn, + enh_cell_list[rest_bin.enh_index[k]].bsic.bsic); + + /* For every 4th time, we include this cell in the report */ + if ( (ncell->rep_count & (0x03)) EQ 0 ) + { + /* For those cells that are not reported in every measurement report, + the MS shall average the measurements of the current and the previous + reporting period (i.e. over two reporting periods). */ + enh_cell_list[rest_bin.enh_index[k]].rxlev_avg = + (enh_cell_list[rest_bin.enh_index[k]].rxlev_avg + ncell->last_rxlev) >> 1; + /* division by 2 */ + } + else + { + ncell->last_rxlev = enh_cell_list[rest_bin.enh_index[k]].rxlev_avg; + include_cell = FALSE; + } + /* modulo 4 addition */ + ncell->rep_count = (ncell->rep_count + 1) & 0x03; + } + + if (include_cell EQ TRUE) + { + grr_data->db.sorted_enh_cell_list. + enh_index[grr_data->db.sorted_enh_cell_list.num_valid] = + rest_bin.enh_index[k]; + grr_data->db.sorted_enh_cell_list.num_valid++; + } + + if(k NEQ i) + { + temp = rest_bin.enh_index[k]; + rest_bin.enh_index[k] = rest_bin.enh_index[i]; + rest_bin.enh_index[i] = temp; + } + } + } + /* This leaves us with final step in neighbour cell measurement reporting - scaling.*/ + grr_data->db.pemr_params.scale_used = cs_nc_scale_rxlev (); +}/* cs_nc_sort_and_update_emr_info */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_nc_sort_cells_into_bins ++------------------------------------------------------------------------------ +| Description : The purpose of this function is to sort the cells into various +| bins. This is the first step in handling reporting priority +| as given in 5.08 sec.8.4.8.1 +| +| +| Parameters : Pointers to the three bins +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_nc_sort_cells_into_bins(T_ENH_BIN *p_sbin,T_ENH_BIN *p_mbin, + T_ENH_BIN *p_rbin) +{ + UBYTE i, j; + UBYTE band; + UBYTE sc_band; + UBYTE rth; + T_ENH_CELL_LIST *enh_cell_list = &(grr_data->db.enh_cell_list[0]); + T_GRR_ENH_PARA *p_enh = grr_data->db.nc_ref_lst.enh_param; + + TRACE_FUNCTION( "cs_nc_sort_cells_into_bins" ); + + memset(p_sbin, 0xFF, sizeof(T_ENH_BIN)); + p_sbin->num_valid = 0; + + memset(p_rbin, 0xFF, sizeof(T_ENH_BIN)); + p_rbin->num_valid = 0; + + for( i = 0; i < MAX_NUM_BANDS; i++) + { + memset(&p_mbin[i], 0xFF, sizeof(T_ENH_BIN)); + p_mbin[i].num_valid = 0; + } + + sc_band = cs_get_band_index_for_emr (psc_db->pbcch.bcch.arfcn); + + for ( j = 0; j < grr_data->db.cnt_enh_cell_list; j++ ) + { + if(enh_cell_list[j].bsic.status EQ BSIC_VALID) /* Valid BSIC */ + { + /*Find the band of this arfcn*/ + band = cs_get_band_index_for_emr(enh_cell_list[j].arfcn); + rth = p_enh->enh_rep_data[band].rep_threshold; + if (band EQ sc_band ) + { + /* Apply the threshold criteria for this band*/ + if ( rth NEQ REP_THRESHOLD_INF ) + { + if((rth EQ REP_THRESHOLD_DEF) OR + (enh_cell_list[j].rla_p >= (rth * 6))) + { + p_sbin->enh_index[p_sbin->num_valid++] = j; + } + else + { + p_rbin->enh_index[p_rbin->num_valid++] = j; + } + } /*otherwise report-never*/ + } /* otherwise cell in non-serving band*/ + else + { + /* Apply the threshold criteria for this band*/ + if ( rth NEQ REP_THRESHOLD_INF ) + { + if((rth EQ REP_THRESHOLD_DEF) OR + (enh_cell_list[j].rla_p >= (rth * 6))) + { + p_mbin[band].enh_index[p_mbin[band].num_valid++] = j; + } + else + { + p_rbin->enh_index[p_rbin->num_valid++] = j; + } + } /*otherwise report never*/ + } + } + else /* If there's no cell with the given BSIC, then it falls under Invalid + BSIC category */ + { + /* check whether Invalid BSIC reporting is enabled or not and NCC part is + permitted or not */ + if ( (p_enh->inv_bsic_enabled EQ TRUE) AND + ((BOOL)((UBYTE)(p_enh->ncc_permitted & + ncc_bit_mask[(enh_cell_list[j].bsic.bsic & BSIC_NCC_MASK) >> 3])) NEQ 0) ) + { + /* put it in rest bin */ + p_rbin->enh_index[p_rbin->num_valid++] = j; + } + } /* if enh_cell_list.index */ + } /* end of for */ +}/* cs_nc_sort_cells_into_bins */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_get_band_index_for_emr ++------------------------------------------------------------------------------ +| Description : This is implementation specific function. This is used to +| get index into emr reporting data (reporting threshold and +| offset) array, which is band specific. +| +| +| Parameters : ARFCN +| ++------------------------------------------------------------------------------ +*/ + +LOCAL UBYTE cs_get_band_index_for_emr (USHORT arfcn) +{ + + TRACE_FUNCTION( "cs_get_band_index_for_emr" ); + + if ( INRANGE(LOW_CHANNEL_900, arfcn, HIGH_CHANNEL_900) ) + { + return 0; + } + else if ( INRANGE(LOW_CHANNEL_1800, arfcn, HIGH_CHANNEL_1800)) + { + return 1; + } + else if (INRANGE(LOW_CHANNEL_1900, arfcn, HIGH_CHANNEL_1900)) + { + return 3; + } + else if ( INRANGE(LOW_CHANNEL_850, arfcn, HIGH_CHANNEL_850)) + { + return 4; + } + else + { + return 2; + } +}/* cs_get_band_index_for_emr */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_nc_sort_and_store_meas_results ++------------------------------------------------------------------------------ +| Description : This function sorts the cells collected in each bin, in +| descending order of RXLEV +| +| +| Parameters : Pointer to bin, Number of cells to be reported +| ++------------------------------------------------------------------------------ +*/ + +LOCAL void cs_nc_sort_and_store_meas_results(T_ENH_BIN *p_bin, UBYTE nbr_rpt) +{ + UBYTE i; + UBYTE j; + UBYTE max_rxlev; + UBYTE k; + UBYTE temp; + T_ENH_CELL_LIST *enh_cell_list = &(grr_data->db.enh_cell_list[0]); + + TRACE_FUNCTION( "cs_nc_sort_and_store_meas_results" ); + + for (i = 0; (i < p_bin->num_valid AND nbr_rpt > 0); i++,nbr_rpt--) + { + max_rxlev = enh_cell_list[p_bin->enh_index[i]].rla_p; + + k = i; + + for ( j = i+1; j < p_bin->num_valid ; j++ ) + { + if ( enh_cell_list[p_bin->enh_index[j]].rla_p > max_rxlev ) + { + + k = j; + + max_rxlev = enh_cell_list[p_bin->enh_index[j]].rla_p; + } + } + + grr_data->db.sorted_enh_cell_list. + enh_index[grr_data->db.sorted_enh_cell_list.num_valid] = + p_bin->enh_index[k]; + grr_data->db.sorted_enh_cell_list.num_valid++; + + if(k NEQ i) + { + temp = p_bin->enh_index[k]; + p_bin->enh_index[k] = p_bin->enh_index[i]; + p_bin->enh_index[i] = temp; + } + + } +}/* cs_nc_sort_and_store_meas_results */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_nc_update_rest_bin ++------------------------------------------------------------------------------ +| Description : This function updates the rest bin by appending the left out +| cells in the other bins. These may also have to be reported +| along with the cells in rest bin. +| +| +| Parameters : Pointers to the rest and a bin, Number of cells to be reported +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_nc_update_rest_bin(T_ENH_BIN *p_rbin, T_ENH_BIN *p_bin, + UBYTE nbr_rpt) +{ + UBYTE i, count; + + TRACE_FUNCTION( "cs_nc_update_rest_bin" ); + + count = p_bin->num_valid - nbr_rpt; + + for ( i = 0; i < count; i++) + { + p_rbin->enh_index[p_rbin->num_valid++] = p_bin->enh_index[nbr_rpt++]; + p_bin->num_valid--; + } + +}/* cs_nc_update_rest_bin */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_nc_scale_rxlev ++------------------------------------------------------------------------------ +| Description : This function performs the scaling of RXLEV. +| +| +| Parameters : Nil +| ++------------------------------------------------------------------------------ +*/ +LOCAL UBYTE cs_nc_scale_rxlev (void) +{ + UBYTE i; + UBYTE no_of_cells = grr_data->db.cnt_enh_cell_list; + UBYTE scale; + T_ENH_CELL_LIST *enh_cell_list = &(grr_data->db.enh_cell_list[0]); + UBYTE scale_order = grr_data->db.nc_ref_lst.enh_param->scale_order; + + TRACE_FUNCTION( "cs_nc_scale_rxlev" ); + + /*If scaling is automatic, then we find the scaling as below: + If the maximum RXLEV is greater than 63 (MAX_RXLEV), then we add 10dB + and check whether it falls into the range after scaling*/ + /* Note: The assumption is L1 reports values in the following way - + if actual value of rxlev (x) is between y and y+1 dBm, then the reported value + is 110+x rounded off to next integer. */ + if ( scale_order EQ SCALE_AUTO ) + { + UBYTE max = 0; + + if( grr_data->db.scell_info.rxlev_avg NEQ RXLEV_AVG_INVALID ) + { + max = grr_data->db.scell_info.rxlev_avg; + } + + for ( i = 0; i < no_of_cells ; i++ ) + { + if (enh_cell_list[i].rxlev_avg > max ) + { + max = enh_cell_list[i].rxlev_avg; + } + } + + if ( max > 63 ) + { + /* If the max value is greater than 63, we scale by 10 so that + rxlev values of maximum cells will come into range(0 - 63) */ + scale = 10; + } + else + { + scale = 0; + } + } + else + { + scale = scale_order * 10; + } + + /* Apply the scale to the values to be reported for SCELL and NCELLs */ + + if( grr_data->db.scell_info.rxlev_avg NEQ RXLEV_AVG_INVALID ) + { + grr_data->db.scell_info.rxlev_avg -= scale; + } + + for ( i = 0; i < no_of_cells ; i++ ) + { + if (enh_cell_list[i].rxlev_avg > scale) + { + enh_cell_list[i].rxlev_avg -= scale; + } + else + { + enh_cell_list[i].rxlev_avg = 0; + } + + if (enh_cell_list[i].rxlev_avg > 63) + { + enh_cell_list[i].rxlev_avg = 63; + } + } + return (scale/10); +}/* cs_nc_scale_rxlev */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_enh_meas_rpt ++------------------------------------------------------------------------------ +| Description : This function is used to build PEMR +| +| Parameters : u_enh_meas_report - Pointer to ENH measurement report +| ++------------------------------------------------------------------------------ +*/ +LOCAL BOOL cs_build_enh_meas_rpt ( T_U_ENHNC_MEAS_REPORT *u_enh_meas_report ) +{ + T_NC_ORDER nc_ord = cs_get_network_ctrl_order( TRUE ); + /*UBYTE size_avail = MSG_SIZE_PEMR - MAND_SIZE_PEMR;*/ + BOOL pbcch_present = grr_is_pbcch_present( ); + UBYTE psi3_cm = grr_get_psi3_cm(); + T_nc_meas_rep_enh *nc_meas_rep_enh = &(u_enh_meas_report->nc_meas_rep_enh); + UBYTE used_bits = 0; /* for formality sake only, not used here */ + UBYTE rxlev_scell; + UBYTE v_i_scell; + UBYTE i_scell; + BOOL rsc_avail = FALSE; + BOOL isc_avail = FALSE; + + TRACE_FUNCTION( "cs_build_enh_meas_rpt" ); + + /* process message type */ + u_enh_meas_report->msg_type = U_ENHNC_MEAS_REPORT_c; + + /* process TLLI */ + grr_set_buf_tlli( &u_enh_meas_report->tlli_value, grr_get_tlli( ) ); + + /* Process NC Measurements */ + + /* process NC mode */ + switch( nc_ord ) + { + case NC_NC1: nc_meas_rep_enh->nc_mode = NCMODE_NC1; break; + case NC_NC2: nc_meas_rep_enh->nc_mode = NCMODE_NC2; break; + + default: + TRACE_ERROR( "cs_build_enh_meas_rpt no valid NC mode" ); + return( FALSE ); + } + + /* process BA used, PSI3 change mark and PMO used */ + if( pbcch_present EQ FALSE ) + { + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.flag = FALSE; + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.v_ba_ind_used = TRUE; + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.v_ba_ind_used_3g = TRUE; + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.ba_ind_used = + psc_db->ba_ind; + } + else + { + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.flag = TRUE; + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.v_psi3_cm = TRUE; + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.psi3_cm = psi3_cm; + } + + u_enh_meas_report->nc_meas_rep_enh.ba_psi3_str.pmo_ind_used = + psc_db->nc_ms.pmo_ind; + + /* process serving cell data - rxlev and ilev */ + cs_process_serving_cell_data(&rxlev_scell, &v_i_scell, &i_scell, &used_bits, + &rsc_avail, &isc_avail); + + if((rsc_avail EQ TRUE) AND (isc_avail EQ FALSE)) + { + /* Only RXLEV of SCELL avalable. ILEV of SCELL not available */ + nc_meas_rep_enh->v_serv_cell_data = TRUE; + nc_meas_rep_enh->serv_cell_data.v_i_scell = FALSE; + nc_meas_rep_enh->serv_cell_data.rxlev_scell = rxlev_scell; + } + else if(rsc_avail EQ FALSE) + { + /* RXLEV of SCELL not avalable. Hence SCELL info is not reported */ + nc_meas_rep_enh->v_serv_cell_data = FALSE; + } + else if((rsc_avail EQ TRUE) AND (isc_avail EQ TRUE)) + { + /* Both RXLEV and ILEV of SCELL available and reported */ + nc_meas_rep_enh->v_serv_cell_data = TRUE; + nc_meas_rep_enh->serv_cell_data.v_i_scell = TRUE; + nc_meas_rep_enh->serv_cell_data.rxlev_scell = rxlev_scell; + nc_meas_rep_enh->serv_cell_data.i_scell = i_scell; + } + + /* process NC measurement results */ + if(cs_fill_nc_enh_meas_results(nc_meas_rep_enh) EQ FALSE) + { + nc_meas_rep_enh->v_nc_rep_quan = FALSE; + } + + /* process BSIC_SEEN and SCALE */ + if(nc_meas_rep_enh->c_rep_invalid_bsic_info NEQ 0) + { + nc_meas_rep_enh->bsic_seen = TRUE; + } + else + { + nc_meas_rep_enh->bsic_seen = FALSE; + } + + nc_meas_rep_enh->scale = grr_data->db.pemr_params.scale_used; + + return(TRUE); + +} /* cs_build_enh_meas_rpt() */ + + +/* ++------------------------------------------------------------------------------ +| Function : cs_fill_nc_meas_results ++------------------------------------------------------------------------------ +| Description : This function is used to fill ENH measurements of neighbour +| cells in the PEMR message +| +| +| Parameters : Pointer to ENH meas parameters struct +| ++------------------------------------------------------------------------------ +*/ + +LOCAL BOOL cs_fill_nc_enh_meas_results(T_nc_meas_rep_enh *nc_meas_rep_enh) +{ + UBYTE size_avail = MSG_SIZE_PEMR - MAND_SIZE_PEMR; + UBYTE i; + UBYTE highest_index = 0; + T_ENH_CELL_LIST *enh_cell_list = &(grr_data->db.enh_cell_list[0]); + T_ENH_BIN *sorted_list = &grr_data->db.sorted_enh_cell_list; + UBYTE index_0 = 1; + + nc_meas_rep_enh->nc_rep_quan.c_reporting_quantity_bmp = 0; + nc_meas_rep_enh->c_rep_invalid_bsic_info = 0; + + + TRACE_FUNCTION( "cs_fill_nc_meas_results" ); + + /*lint -e{437} Passing struct '' to ellipsis */ + TRACE_EVENT_P1("dump=%x",grr_data->db.enh_cell_list[0]); + + if(grr_data->db.sorted_enh_cell_list.num_valid EQ 0) + { + return(FALSE); + } + + nc_meas_rep_enh->v_nc_rep_quan = TRUE; + + for(i = 0; i < sorted_list->num_valid; i++) + { + if(enh_cell_list[sorted_list->enh_index[i]].bsic.status EQ BSIC_VALID) + { + /*Fill it in valid BSIC bit map reporting, enh_cell_list[i]->index + corresponds to the bit in the report. Find whether size permits */ + TRACE_EVENT_P2("I%x = %x",i,enh_cell_list[sorted_list->enh_index[i]].index); + nc_meas_rep_enh->nc_rep_quan. + reporting_quantity_bmp[enh_cell_list[sorted_list->enh_index[i]].index]. + v_reporting_quantity = TRUE; + nc_meas_rep_enh->nc_rep_quan. + reporting_quantity_bmp[enh_cell_list[sorted_list->enh_index[i]].index]. + reporting_quantity = enh_cell_list[sorted_list->enh_index[i]].rxlev_avg; + + size_avail = size_avail - index_0; + index_0 = 0; + + if ( enh_cell_list[sorted_list->enh_index[i]].index > highest_index ) + { + /* When the place where the RXLEV has to be filled requires + additional bits in bit map, then we have to account for + these single bits and additional 6 bits for RXLEV */ + if ( size_avail >= (enh_cell_list[sorted_list->enh_index[i]].index + - highest_index) + NC_RXLEV_N_LEN ) + { + /* This means we require atleast enh_cell_list[i]->index - + highest_index+6 bits in bit map to include this rxlev */ + /* 6 bits for RXLEV itself */ + size_avail = size_avail - + (enh_cell_list[sorted_list->enh_index[i]].index - highest_index + + NC_RXLEV_N_LEN); + highest_index = enh_cell_list[sorted_list->enh_index[i]].index; + nc_meas_rep_enh->nc_rep_quan. + c_reporting_quantity_bmp = + enh_cell_list[sorted_list->enh_index[i]].index + 1; /* counter is index+1 */ + continue; + } + else if (size_avail >= NC_RXLEV_N_LEN) + { + continue; + } + else + break; /* No more filling possible */ + } + else if (size_avail >= NC_RXLEV_N_LEN) + { + size_avail -= NC_RXLEV_N_LEN; /* size for bit map is already accounted for*/ + nc_meas_rep_enh->nc_rep_quan. + c_reporting_quantity_bmp = highest_index +1; + continue; + } + else + { + break; /*no more inclusion of results is possible*/ + } + } + else + { + /* fill in invalid BSIC list since cell is not present in the neighbour cell + list. Here the index that needs to be filled is index of the ARFCN in BA(list)*/ + if ( size_avail > NC_INVBSIC_PEMR ) + { + nc_meas_rep_enh->v_rep_invalid_bsic_info = TRUE; + nc_meas_rep_enh->rep_invalid_bsic_info + [nc_meas_rep_enh->c_rep_invalid_bsic_info].bcch_freq_ncell + = enh_cell_list[sorted_list->enh_index[i]].index; + nc_meas_rep_enh->rep_invalid_bsic_info + [nc_meas_rep_enh->c_rep_invalid_bsic_info].bsic + = enh_cell_list[sorted_list->enh_index[i]].bsic.bsic; + nc_meas_rep_enh->rep_invalid_bsic_info + [nc_meas_rep_enh->c_rep_invalid_bsic_info].rxlev_ncell + = enh_cell_list[sorted_list->enh_index[i]].rxlev_avg; + nc_meas_rep_enh->c_rep_invalid_bsic_info++; + size_avail -= NC_INVBSIC_PEMR; + } + } + } + + return(TRUE); + +}/* cs_fill_nc_enh_meas_results */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_enh_sorted_strng_arfcn_list ++------------------------------------------------------------------------------ +| Description : The purpose of this function is to sort the cells into various +| bins and in desc order of RXLEV in each of the bin. The ARFCNs +| in the sorted bin are finally sent to RR for decoding purpose +| +| +| Parameters : Pointers to the final sorted bin for storage +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_build_enh_sorted_strng_arfcn_list(T_ENH_STRNG_ARFCN_LIST *f_bin) +{ + T_ENH_STRNG_ARFCN_LIST s_bin, r_bin; + + UBYTE total_arfcns; + + f_bin->num = 0; + + TRACE_FUNCTION( "cs_build_enh_sorted_strng_arfcn_list" ); + + /* Sort ARFCNs into Serving, Non-serving or the Rest*/ + total_arfcns = cs_sort_arfcns_into_bins(&s_bin, &r_bin); + + /* Sort the ARFCNs in desc order of RXLEV and store them in the final bin */ + if(total_arfcns NEQ 0) + { + cs_sort_store_in_desc_order_rxlev(&s_bin, f_bin); + cs_sort_store_in_desc_order_rxlev(&r_bin, f_bin); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : cs_sort_arfcns_into_bins ++------------------------------------------------------------------------------ +| Description : The purpose of this function is to sort the ARFCNs into various +| bins. +| +| +| Parameters : Pointers to the the bins +| ++------------------------------------------------------------------------------ +*/ +LOCAL UBYTE cs_sort_arfcns_into_bins(T_ENH_STRNG_ARFCN_LIST *p_s_bin, + T_ENH_STRNG_ARFCN_LIST *p_r_bin) +{ + UBYTE i; + UBYTE band, sc_band; + UBYTE total_cells = 0; + + p_s_bin->num = 0; + p_r_bin->num = 0; + + TRACE_FUNCTION( "cs_sort_arfcns_into_bins" ); + + sc_band = cs_get_band_index_for_emr (psc_db->pbcch.bcch.arfcn); + + /* Check the ARFCNs in the NC_MVAL and store them in Serving or + Rest bins according to their bands */ + i = 0; + while( (i < MAX_NR_OF_NC_MVAL) AND (total_cells <= MAX_NR_OF_NCELL) ) + { + if( (grr_data->db.nc_mval_list.nc_mval[i].arfcn NEQ RRGRR_INVALID_ARFCN) + AND (grr_data->db.nc_mval_list.nc_mval[i].status EQ NC_MVAL_STAT_ASSIGNED) ) + { + band = cs_get_band_index_for_emr(grr_data->db.nc_mval_list.nc_mval[i].arfcn); + if (band EQ sc_band) + { + p_s_bin->meas[p_s_bin->num].arfcn = + grr_data->db.nc_mval_list.nc_mval[i].arfcn; + p_s_bin->meas[p_s_bin->num].rxlev = + grr_data->db.nc_mval_list.nc_mval[i].rla_p.lev; + p_s_bin->num++; + + } + else /* Process the non-serving bands */ + { + p_r_bin->meas[p_r_bin->num].arfcn = + grr_data->db.nc_mval_list.nc_mval[i].arfcn; + p_r_bin->meas[p_r_bin->num].rxlev = + grr_data->db.nc_mval_list.nc_mval[i].rla_p.lev; + p_r_bin->num++; + } + total_cells = p_s_bin->num + p_r_bin->num; + } + i++; + } /* end of while */ + return(total_cells); +}/* cs_sort_arfcns_into_bins */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_sort_in_desc_order_rxlev ++------------------------------------------------------------------------------ +| Description : This function sorts the cells collected in each bin, in +| descending order of RXLEV. It will be stored in the final bin +| as and when sorted. +| +| +| Parameters : Pointer to serving or multiband bin, Pointer to final bin +| ++------------------------------------------------------------------------------ +*/ + +LOCAL void cs_sort_store_in_desc_order_rxlev(T_ENH_STRNG_ARFCN_LIST *p_bin, + T_ENH_STRNG_ARFCN_LIST *p_f_bin) +{ + UBYTE i; + UBYTE j; + UBYTE max_rxlev; + UBYTE k; + T_MEAS temp; + + TRACE_FUNCTION( "cs_sort_store_in_desc_order_rxlev" ); + + for (i = 0; i < p_bin->num; i++) + { + max_rxlev = p_bin->meas[i].rxlev; + k = i; + for ( j = i + 1; j < p_bin->num; j++ ) + { + if ( p_bin->meas[j].rxlev > max_rxlev ) + { + k = j; + max_rxlev = p_bin->meas[j].rxlev; + } + } + + /* Store the ARFCN-RXLEV pair in the final bin in desc order of RXLEV */ + p_f_bin->meas[p_f_bin->num++] = p_bin->meas[k]; + + if(k NEQ i) + { + temp = p_bin->meas[k]; + p_bin->meas[k] = p_bin->meas[i]; + p_bin->meas[i] = temp; + } + } +}/* cs_sort_store_in_desc_order_rxlev */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_init_ba_bcch_nc_ref_list ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : list - pointer to NC measurement pointer list +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void cs_init_ba_bcch_nc_ref_list () +{ + TRACE_FUNCTION( "cs_init_ba_bcch_nc_ref_list" ); + + grr_data->db.ba_bcch_nc_ref_lst.number = 0; + +}/* cs_init_ba_bcch_nc_ref_list */ + +/* ++------------------------------------------------------------------------------ +| Function : cs_build_ba_bcch_nc_freq_list ++------------------------------------------------------------------------------ +| Description : +| +| Parameters : db - pointer to serving cell database +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_build_ba_bcch_nc_freq_list () +{ + UBYTE i; + + TRACE_FUNCTION( "cs_build_ba_bcch_nc_freq_list" ); + + /* + * add neighbour cell information of SI2 and PMO to reference list + */ + for( i = 0; i < psc_db->nc_ba_bcch_cw.number; i++ ) + { + grr_data->db.ba_bcch_nc_ref_lst.info[i] = &psc_db->nc_ba_bcch_cw.info[i]; + grr_data->db.ba_bcch_nc_ref_lst.number++; + } + + if(use_ba_gprs EQ FALSE) + { + UBYTE number = psc_db->nc_ba_bcch_cw.number; + for(i = 0; i < psc_db->nc_ms.ncmeas.list.number; i++) + { + grr_data->db.ba_bcch_nc_ref_lst.info[number] = + &psc_db->nc_ms.ncmeas.list.info[i]; + grr_data->db.ba_bcch_nc_ref_lst.info[number]->index = number; + grr_data->db.ba_bcch_nc_ref_lst.number++; + number++; + } + } +} + +#endif +/* ++------------------------------------------------------------------------------ +| Function : cs_copy_rxlev_from_avg ++------------------------------------------------------------------------------ +| Description : The function cs_copy_rxlev_from_avg() helps to retain the old +| rxlev data obtained for the neighbour cells before the cell +| change. +| Parameters : Index of the nc_data->cell,nc_mval->rxlev_avg +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_copy_rxlev_from_avg(UBYTE rxlev_avg,T_CELL *cell) +{ +#define INITIAL_ACC_MEAS 4 + UBYTE i; /* used for counting */ + T_RLA_P_DATA *rla_p_data = &cell->rla_p_data; + T_RXLEV_DATA *rxlev_data = &cell->rxlev_data; + + TRACE_FUNCTION( "cs_copy_rxlev_from_avg" ); + TRACE_EVENT_P3( "cs_copy_rxlev_from_avg arfcn=%ld LOI=%ld rxlev_avg=%ld", cell->arfcn,rla_p_data->loi,rxlev_avg); + + rla_p_data->loi = INITIAL_ACC_MEAS - 1 ; + rla_p_data->ovrflw = FALSE; + + for( i = 0; i < INITIAL_ACC_MEAS; i++ ) + { + rla_p_data->meas[i].cnt = 1; + rla_p_data->meas[i].acc = (USHORT)rxlev_avg; + rla_p_data->meas[i].rpt_prd = 208; + } + + rxlev_data->acc = rxlev_avg*INITIAL_ACC_MEAS*RXLEV_ACRCY; + rxlev_data->nbr = INITIAL_ACC_MEAS; +} +/* ++------------------------------------------------------------------------------ +| Function : cs_reuse_old_cell_rxlev ++------------------------------------------------------------------------------ +| Description : The function cs_reuse_old_cell_rxlev() helps to reuse rxlev data +| obtained for the neighbour cells in the old cell before the cell +| change. +| Parameters : void +| ++------------------------------------------------------------------------------ +*/ +LOCAL void cs_reuse_old_cell_rxlev() +{ + T_NC_MVAL *nc_mval; + UBYTE i,found,mval_idx ; + UBYTE mval_index=0; + + TRACE_FUNCTION( "cs_reuse_old_cell_rxlev" ); + TRACE_EVENT( "cs_reuse_old_cell_rxlev" ); + + for( i = 0; i < MPHP_NUMC_BA_GPRS_SC; i++ ) + { +#if 0 + mval_index = 0; + nc_mval = grr_get_nc_mval( nc_data->cell[i].arfcn, RRGRR_INVALID_BSIC, &mval_index ); + if(nc_mval NEQ 0) + { + if(nc_mval->rla_p.stat EQ CS_RLA_P_VALID) + { + cs_copy_rxlev_from_avg( (UBYTE)nc_mval->rxlev_avg,&nc_data->cell[i] ); + } + else + { + cs_reset_meas_result( &nc_data->cell[i] ); + } + } + else + { + cs_reset_meas_result( &nc_data->cell[i] ); + } +#else + found=0; + for( mval_idx = 0; mval_idx < MAX_NR_OF_NC_MVAL; mval_idx++ ) + { + nc_mval = &grr_data->db.nc_mval_list.nc_mval[mval_idx]; + if((UBYTE)nc_mval->rxlev_avg EQ 0xFF AND + nc_mval->rla_p.stat EQ CS_RLA_P_VALID) + { + TRACE_EVENT_P4("PATCH: arfcn=%ld avg_lev=%ld rla_p_lev=%ld stat=%ld " + ,nc_mval->arfcn,nc_mval->rxlev_avg,nc_mval->rla_p.lev,nc_mval->rla_p.stat); + } + if( + (nc_mval->arfcn EQ nc_data->cell[i].arfcn) + AND + (nc_mval->rla_p.stat EQ CS_RLA_P_VALID) + AND + ((UBYTE)nc_mval->rxlev_avg NEQ 0xFF) + ) + { + cs_copy_rxlev_from_avg( (UBYTE)nc_mval->rxlev_avg,&nc_data->cell[i] ); + found=1; + } + } + if(!found) + cs_reset_meas_result( &nc_data->cell[i] ); +#endif + } +} + + + + + + +