FreeCalypso > hg > fc-tourmaline
view src/g23m-gprs/grlc/grlc_meass.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GPRS (8441) | Modul : GRLC +----------------------------------------------------------------------------- | 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 signal handler functions for service | MEAS of entity GRLC. +----------------------------------------------------------------------------- */ #ifndef GRLC_MEASS_C #define GRLC_MEASS_C #endif /* #ifndef GRLC_MEASS_C */ #define ENTITY_GRLC /*==== INCLUDES =============================================================*/ #include "typedefs.h" #include "vsi.h" #include "macdef.h" #include "gprs.h" #include "gsm.h" #include "ccdapi.h" #include "prim.h" #include "message.h" #include "grlc.h" #include "grlc_meass.h" #include "grlc_measf.h" #include "cl_rlcmac.h" /*==== CONST ================================================================*/ #define MEAS_MAX_NUM_MEAN 1000 /* maximum numbers of element considered for */ /* calculating the mean */ /* maybe for later use */ /* #define M_ROUND_UP(x,meas_acrcy) (((x)>=0)? \ ((((x)%(meas_acrcy))< ((meas_acrcy)/ 2))? \ ( (x)/(meas_acrcy) ):(((x)/(meas_acrcy))+1)): \ ((((x)%(meas_acrcy))<=((meas_acrcy)/-2))? \ (((x)/(meas_acrcy))-1):( (x)/(meas_acrcy) ))) */ #define M_ROUND_UP(x,meas_acrcy) ((((x)%(meas_acrcy))< ((meas_acrcy)/ 2))? \ ( (x)/(meas_acrcy) ):(((x)/(meas_acrcy))+1)) #define MEAS_C_INC_INDEX(index) { \ if( index < (T_C_INDEX)(~0) ) index++; \ } #define NORM_FFB_MAX (ULONG)100000 /* normalised forgetting factor b maximum value */ #define NORM_FFC_MAX (ULONG)500000 /* normalised forgetting factor c maximum value */ #define NORM_FFB_DIV (ULONG)10 /* normalised forgetting factor b divisor value */ #define NORM_FFC_DIV (ULONG)20 /* normalised forgetting factor c divisor value */ #define SV_ACRCY_DIV (ULONG)10 /* signal variance accuracy divisor */ #define C_VALUE_IDX_DEFAULT 0 #define C_VALUE_DEFAULT 0 #define SV_VALUE_DEFAULT 0 #define RXQUAL_VALUE_DEFAULT 0 #define SV_LEVEL_MAX 63 #define SV_LEVEL_STEP ((T_SIGN_VAR_VALUE)(MEAS_ACRCY/4)) /* dB2 step size of the signal */ /* variance */ /*==== LOCAL VARS ===========================================================*/ /* * normalised forgetting factor b used in context of C value calculation * * NORM_FFB_MAX * ( 1 / ( 6 * t_avg_t ) ) */ LOCAL const ULONG norm_ffb[] = { NORM_FFB_MAX, 70711, 50000, 35355, 25000, 17678, 12500, 8839, 6250, 4419, 3125, 2210, 1563, 1105, 781, 552, 391, 276, 195, 138, 98, 69, 49, 35, 24, 17 }; /* * normalised forgetting factor c used in context of C value calculation * * NORM_FFC_MAX * ( 1 / ( 12 * t_avg_t ) ) */ LOCAL const ULONG norm_ffc[] = { NORM_FFC_MAX, 353553, 250000, 176777, 125000, 88388, 62500, 44194, 31250, 22097, 15625, 11049, 7813, 5524, 3906, 2762, 1953, 1381, 977, 691, 488, 345, 244, 173, 122, 86 }; /*==== LOCAL TYPES===========================================================*/ #if !defined (NTRACE) LOCAL void meas_int_trace_i_level( T_ilev *i_level ); #endif /* #if !defined (NTRACE) */ /*==== PUBLIC FUNCTIONS =====================================================*/ /* +------------------------------------------------------------------------------ | Function : meas_grlc_init +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void meas_grlc_init ( void ) { TRACE_FUNCTION( "meas_grlc_init" ); /* initialization of C value management */ meas_c_restart( ); /* initialization of signal variance management */ meas_sv_restart( ); /* initialization of signal quality management */ meas_sq_restart( ); } /* grlc_meas_init() */ /* +------------------------------------------------------------------------------ | Function : sig_rd_meas_qual_rpt_sent +------------------------------------------------------------------------------ | Description : Handles the internal signal SIG_RD_MEAS_QUAL_RPT_SENT | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void sig_rd_meas_qual_rpt_sent ( void ) { TRACE_ISIG( "sig_rd_meas_qual_rpt_sent" ); meas_sv_restart( ); grlc_data->meas.sq_restart = TRUE; } /* sig_rd_meas_qual_rpt_sent() */ /* +------------------------------------------------------------------------------ | Function : sig_tm_meas_ptm +------------------------------------------------------------------------------ | Description : Handles the internal signal SIG_TM_MEAS_PTM | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void sig_tm_meas_ptm ( void ) { TRACE_ISIG( "sig_tm_meas_ptm" ); meas_sv_restart( ); meas_sq_restart( ); } /* sig_tm_meas_ptm() */ /* +------------------------------------------------------------------------------ | Function : meas_grlc_c_get_value +------------------------------------------------------------------------------ | Description : This function returns the current C value. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL UBYTE meas_grlc_c_get_value ( void ) { UBYTE c_value; TRACE_FUNCTION( "meas_grlc_c_get_value" ); if( grlc_data->meas.c_filter.index > 0 ) { c_value = ( M_ROUND_UP( grlc_data->meas.c_filter.value, MEAS_ACRCY ) ); } else { #ifdef _SIMULATION_ TRACE_ERROR( "meas_grlc_c_get_value: grlc_data->meas.c_filter.index EQ 0" ); #endif /* #ifdef _SIMULATION_ */ c_value = C_VALUE_DEFAULT; } return( c_value ); } /* meas_grlc_c_get_value() */ /* +------------------------------------------------------------------------------ | Function : meas_grlc_c_get_c_value +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void meas_grlc_c_get_c_value ( T_CGRLC_c_value *c_value ) { TRACE_FUNCTION( "meas_grlc_c_get_c_value" ); c_value->c_acrcy = MEAS_ACRCY; c_value->c_lev = grlc_data->meas.c_filter.value; c_value->c_idx = grlc_data->meas.c_filter.index; } /* meas_grlc_c_get_c_value() */ /* +------------------------------------------------------------------------------ | Function : meas_grlc_c_set_c_value +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void meas_grlc_c_set_c_value ( T_CGRLC_c_value *c_value ) { TRACE_FUNCTION( "meas_grlc_c_set_c_value" ); grlc_data->meas.c_filter.value = (c_value->c_lev / c_value->c_acrcy) * MEAS_ACRCY; grlc_data->meas.c_filter.index = c_value->c_idx; } /* meas_grlc_c_set_c_value() */ /* +------------------------------------------------------------------------------ | Function : meas_c_val_update_ptm +------------------------------------------------------------------------------ | Description : ... | | Parameters : - | +------------------------------------------------------------------------------ */ GLOBAL void meas_c_val_update_ptm ( T_MAC_PWR_CTRL_IND *mac_pwr_ctrl_ind, T_CGRLC_glbl_pwr_ctrl_param *pwr_ctrl_param, T_CGRLC_freq_param *freq_param ) { UBYTE pb_rdc; /* Pb reduction */ UBYTE vld_smpl = 0; /* valid measurement samples */ ULONG ff_value; ULONG c_value; T_C_FILTER *c_filter = &grlc_data->meas.c_filter; TRACE_FUNCTION( "meas_c_val_update_ptm" ); if( pwr_ctrl_param->pc_meas_chan EQ CGRLC_MEAS_CHAN_BCCH AND mac_pwr_ctrl_ind->bcch_level NEQ MAC_RXLEV_NONE ) { MEAS_C_INC_INDEX( c_filter->index ); if( c_filter->index EQ 1 ) { c_filter->value = MEAS_ACRCY * mac_pwr_ctrl_ind->bcch_level; } else { /* calculate the forgetting factor */ ff_value = norm_ffb[pwr_ctrl_param->t_avg_t]; /* update the filter */ c_value = ( NORM_FFB_MAX - ff_value ) * ( c_filter->value / NORM_FFB_DIV ) + ff_value * ( MEAS_ACRCY / NORM_FFB_DIV ) * mac_pwr_ctrl_ind->bcch_level; c_filter->value = (T_C_VALUE)(c_value / (NORM_FFB_MAX / NORM_FFB_DIV)); } #ifdef _SIMULATION_ TRACE_EVENT_P2( "C-Value = %d, C-Index = %d", c_filter->value, c_filter->index ); #endif /* #ifdef _SIMULATION_ */ } else if( pwr_ctrl_param->pc_meas_chan EQ CGRLC_MEAS_CHAN_PDCH ) { vld_smpl = meas_c_calc_mean ( mac_pwr_ctrl_ind->burst_level, mac_pwr_ctrl_ind->radio_freq, &c_value, &pb_rdc, freq_param ); if( vld_smpl ) { MEAS_C_INC_INDEX( c_filter->index ); /* consider the BTS output power reduction */ c_value -= ( ( 2 * pwr_ctrl_param->pb ) * ( MEAS_ACRCY * pb_rdc ) / MAC_BURST_PER_BLOCK ); if( c_filter->index EQ 1 ) { c_filter->value = (T_C_VALUE)c_value; } else { /* calculate the forgetting factor */ ff_value = norm_ffc[pwr_ctrl_param->t_avg_t]; /* update the filter */ c_value = ( NORM_FFC_MAX - ff_value ) * ( c_filter->value / NORM_FFC_DIV ) + ff_value * ( c_value / NORM_FFC_DIV ); c_filter->value = (T_C_VALUE)(c_value / (NORM_FFC_MAX / NORM_FFC_DIV)); } } else { #ifdef _SIMULATION_ TRACE_EVENT( "no valid RXLEV information in meas_c_val_update_ptm 1" ); #endif /* #ifdef _SIMULATION_ */ } #ifdef _SIMULATION_ TRACE_EVENT_P2( "C-Value = %d, C-Index = %d", c_filter->value, c_filter->index ); #endif /* #ifdef _SIMULATION_ */ } else { #ifdef _SIMULATION_ TRACE_EVENT( "no valid RXLEV information in meas_c_val_update_ptm 2" ); #endif /* #ifdef _SIMULATION_ */ } } /* meas_c_val_update_ptm() */ /* +------------------------------------------------------------------------------ | Function : meas_c_restart +------------------------------------------------------------------------------ | Description : This function initializes the parameters for deriving the | C value. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void meas_c_restart ( void ) { TRACE_FUNCTION( "meas_c_restart" ); grlc_data->meas.c_filter.value = 0; grlc_data->meas.c_filter.index = 0; } /* meas_c_restart() */ /* +------------------------------------------------------------------------------ | Function : meas_sv_get_value +------------------------------------------------------------------------------ | Description : This function returns the current signal variance. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL UBYTE meas_sv_get_value ( void ) { T_SIGN_VAR_VALUE sv_val; TRACE_FUNCTION( "meas_sv_get_value" ); sv_val = grlc_data->meas.sign_var.value / SV_LEVEL_STEP; if( grlc_data->meas.sign_var.value % SV_LEVEL_STEP EQ 0 AND grlc_data->meas.sign_var.value NEQ 0 ) { sv_val -= 1; } if( sv_val > SV_LEVEL_MAX ) { sv_val = SV_LEVEL_MAX; } return( (UBYTE)sv_val ); } /* meas_sv_get_value() */ /* +------------------------------------------------------------------------------ | Function : meas_sv_update +------------------------------------------------------------------------------ | Description : ... | | Parameters : - | +------------------------------------------------------------------------------ */ GLOBAL void meas_sv_update ( T_MAC_PWR_CTRL_IND *mac_pwr_ctrl_ind, T_CGRLC_glbl_pwr_ctrl_param *pwr_ctrl_param, T_CGRLC_freq_param *freq_param ) { T_SIGN_VAR *sign_var = &grlc_data->meas.sign_var; UBYTE i; /* used for counting */ UBYTE ss_on_bcch[MAC_BURST_PER_BLOCK]; /* receive signal level measured on BCCH */ UBYTE ss_off_bcch[MAC_BURST_PER_BLOCK]; /* receive signal level not measured on BCCH */ UBYTE j = 0; /* indicates the number of bursts received */ /* on BCCH frequency */ UBYTE *ss_k = NULL; /* points to the receive signal levels */ TRACE_FUNCTION( "meas_sv_update" ); /* initialize arrays */ for( i = 0; i < MAC_BURST_PER_BLOCK; i++ ) { ss_on_bcch [i] = MAC_RXLEV_NONE; ss_off_bcch[i] = MAC_RXLEV_NONE; } if( mac_pwr_ctrl_ind->crc_error EQ GRLC_CRC_PASS AND pwr_ctrl_param->pc_meas_chan EQ CGRLC_MEAS_CHAN_PDCH ) { if( !freq_param->pdch_hopping ) { /* sort burst level acc. its radio frequency */ for( i = 0; i < MAC_BURST_PER_BLOCK; i++ ) { if( mac_pwr_ctrl_ind->radio_freq[i] EQ freq_param->bcch_arfcn ) { j++; ss_on_bcch[i] = mac_pwr_ctrl_ind->burst_level[i]; } else { ss_off_bcch[i] = mac_pwr_ctrl_ind->burst_level[i]; } } /* calculate the burst level that should be taken into account */ switch( j ) { case( 0 ): ss_k = &ss_off_bcch[0]; j = 4; break; case( 1 ): ss_k = &ss_off_bcch[0]; j = 3; break; case( 2 ): ss_k = NULL; break; case( 3 ): ss_k = &ss_on_bcch[0]; j = 3; break; case( 4 ): ss_k = &ss_on_bcch[0]; j = 4; break; default : TRACE_ASSERT( j < 4 ); break; } } else { /* calculate the burst level that should be taken into account */ ss_k = &mac_pwr_ctrl_ind->burst_level[0]; j = 4; } } if( ss_k NEQ NULL ) { T_SIGN_VAR_INDEX old_num; ULONG old_elem; UBYTE pb_rdc; /* Pb reduction */ LONG base; ULONG sum = 0; /* sum of all squares */ ULONG bl_var; /* block variance */ ULONG ss_block; if( meas_c_calc_mean ( ss_k, mac_pwr_ctrl_ind->radio_freq, &ss_block, &pb_rdc, freq_param ) > 0 ) { /* calculate the sum of the squares of the difference between */ /* each individual burst level value and the mean */ for( i = 0; i < j; i++ ) { if( ss_k[i] NEQ MAC_RXLEV_NONE ) { base = ( ( ss_k[i] * MEAS_ACRCY ) / SV_ACRCY_DIV ) - ( ss_block / SV_ACRCY_DIV ); sum += ( ULONG )( base * base ); } } /* * calculate block variance * * in case ss_k NEQ NULL, j will be either set to the value 3 or 4 * * the lint comment below only works when linting current file alone, * when linting current file together with all other files of the project, * an error message will be generated anyway * * I don't know why and gave-up to fix it */ bl_var = sum / ( UBYTE )( j - 1 ); /*lint !e414*/ /* calculate the signal variance */ if( sign_var->index EQ MEAS_MAX_NUM_MEAN ) { old_num = MEAS_MAX_NUM_MEAN - 1; } else { old_num = sign_var->index; sign_var->index++; } old_elem = sign_var->value * old_num; sign_var->value = (T_SIGN_VAR_VALUE)((old_elem + (bl_var / SV_ACRCY_DIV)) / sign_var->index); } else { #ifdef _SIMULATION_ TRACE_EVENT( "no valid RXLEV information in meas_sv_update 1" ); #endif /* #ifdef _SIMULATION_ */ } #ifdef _SIMULATION_ TRACE_EVENT_P2( "SIGN-VAR-Value = %d, SIGN-VAR-Index = %d", sign_var->value, sign_var->index ); #endif /* #ifdef _SIMULATION_ */ } else { #ifdef _SIMULATION_ TRACE_EVENT( "no valid RXLEV information in meas_sv_update 2" ); #endif /* #ifdef _SIMULATION_ */ } } /* meas_sv_update() */ /* +------------------------------------------------------------------------------ | Function : meas_sv_restart +------------------------------------------------------------------------------ | Description : This function initializes the parameters for deriving the | signal variance. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void meas_sv_restart ( void ) { TRACE_FUNCTION( "meas_sv_restart" ); grlc_data->meas.sign_var.value = 0; grlc_data->meas.sign_var.index = 0; } /* meas_sv_restart() */ /* +------------------------------------------------------------------------------ | Function : meas_sq_get_rxqual_value +------------------------------------------------------------------------------ | Description : This function returns the current RXQUAL value | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL UBYTE meas_sq_get_rxqual_value ( void) { UBYTE rxqual; T_BER_AVG *ber_avg = &grlc_data->meas.ber_avg; TRACE_FUNCTION( "meas_sq_get_rxqual_value" ); if ( ber_avg->value < 200 ) { rxqual = 0; /* RX_QUAL_0 */ } else if ( ber_avg->value < 400 ) { rxqual = 1; /* RX_QUAL_1 */ } else if ( ber_avg->value < 800 ) { rxqual = 2; /* RX_QUAL_2 */ } else if ( ber_avg->value < 1600 ) { rxqual = 3; /* RX_QUAL_3 */ } else if ( ber_avg->value < 3200 ) { rxqual = 4; /* RX_QUAL_4 */ } else if ( ber_avg->value < 6400 ) { rxqual = 5; /* RX_QUAL_5 */ } else if ( ber_avg->value < 12800 ) { rxqual = 6; /* RX_QUAL_6 */ } else { rxqual = 7; /* RX_QUAL_7 */ } return ( rxqual ); } /* meas_sq_get_rxqual_value() */ /* +------------------------------------------------------------------------------ | Function : meas_sq_update +------------------------------------------------------------------------------ | Description : This function updates the RXQUAL value. | | Parameters : per_ind - Ptr to struct T_BER_IND | +------------------------------------------------------------------------------ */ GLOBAL void meas_sq_update ( T_BER_IND *ber_ind ) { UBYTE i; ULONG norm_fault; ULONG norm_ber; ULONG old_elem; T_BER_INDEX old_num; T_BER_AVG *ber_avg = &grlc_data->meas.ber_avg; TRACE_FUNCTION( "meas_sq_update" ); if(grlc_data->meas.sq_restart) { grlc_data->meas.ber_avg.value = 0; grlc_data->meas.ber_avg.index = 0; grlc_data->meas.sq_restart = FALSE; } for( i = 0; i < ber_ind->num_dl_blck; i++ ) { if( ber_ind->be_info[i].total NEQ 0 ) { if( ber_avg->index EQ MEAS_MAX_NUM_MEAN ) { old_num = MEAS_MAX_NUM_MEAN - 1; } else { old_num = ber_avg->index; ber_avg->index++; } old_elem = ber_avg->value * old_num; norm_fault = ber_ind->be_info[i].fault * MEAS_ACRCY * 100; norm_ber = norm_fault / ber_ind->be_info[i].total; ber_avg->value = (T_BER_VALUE)((old_elem + norm_ber) / ber_avg->index); RX_SetRxQual( meas_sq_get_rxqual_value( ) ); } } #ifdef _SIMULATION_ TRACE_EVENT_P2( "BER-Value = %d, BER-Index = %d", ber_avg->value, ber_avg->index ); #endif /* #ifdef _SIMULATION_ */ } /* meas_sq_update() */ /* +------------------------------------------------------------------------------ | Function : meas_sq_restart +------------------------------------------------------------------------------ | Description : This function initializes the parameters for deriving the | RXQUAL value. | | Parameters : void | +------------------------------------------------------------------------------ */ GLOBAL void meas_sq_restart ( void ) { TRACE_FUNCTION( "meas_sq_restart" ); grlc_data->meas.ber_avg.value = 0; grlc_data->meas.ber_avg.index = 0; } /* meas_sq_restart() */ /* +------------------------------------------------------------------------------ | Function : meas_int_get_rel_i_level +------------------------------------------------------------------------------ | Description : This function returns the interference level values mapped to | values relative to the C value. | | Parameters : *i_level - Ptr to relative interference level values | +------------------------------------------------------------------------------ */ GLOBAL void meas_int_get_rel_i_level ( T_ilev *i_level ) { USHORT c_raw_data_lev = grlc_data->meas.c_filter.value; TRACE_FUNCTION( "meas_int_get_rel_i_level" ); meas_int_fill_rel_iLevel( &i_level->v_ilev0, &i_level->ilev0, 0, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev1, &i_level->ilev1, 1, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev2, &i_level->ilev2, 2, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev3, &i_level->ilev3, 3, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev4, &i_level->ilev4, 4, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev5, &i_level->ilev5, 5, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev6, &i_level->ilev6, 6, c_raw_data_lev ); meas_int_fill_rel_iLevel( &i_level->v_ilev7, &i_level->ilev7, 7, c_raw_data_lev ); #if !defined (NTRACE) meas_int_trace_i_level( i_level ); #endif /* #if !defined (NTRACE) */ } /* meas_int_get_rel_i_level() */ #if !defined (NTRACE) /* +------------------------------------------------------------------------------ | Function : meas_int_trace_i_level +------------------------------------------------------------------------------ | Description : | | Parameters : | +------------------------------------------------------------------------------ */ LOCAL void meas_int_trace_i_level( T_ilev *i_level ) { if( grlc_data->meas.v_im_trace NEQ 0 ) { TRACE_EVENT_P8( "meas_int_trace_i_level: %02X %02X %02X %02X %02X %02X %02X %02X", i_level->ilev0, i_level->ilev1, i_level->ilev2, i_level->ilev3, i_level->ilev4, i_level->ilev5, i_level->ilev6, i_level->ilev7 ); } } /* meas_int_trace_i_level() */ #endif /* #if !defined (NTRACE) */