FreeCalypso > hg > fc-magnetite
view src/g23m-gprs/grr/grr_csf.c @ 367:ec0440adb8f8
configs/2092-pwr removed: use plain 2092 config with FCHG instead
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 01 Jan 2018 00:16:57 +0000 |
parents | 219afcfc6250 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | 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 } }