FreeCalypso > hg > fc-magnetite
view src/aci2/alr/alr_cs.c @ 636:57e67ca2e1cb
pcmdata.c: default +CGMI to "FreeCalypso" and +CGMM to model
The present change has no effect whatsoever on Falconia-made and Openmoko-made
devices on which /pcm/CGMI and /pcm/CGMM files have been programmed in FFS
with sensible ID strings by the respective factories, but what should AT+CGMI
and AT+CGMM queries return when the device is a Huawei GTM900 or Tango modem
that has been converted to FreeCalypso with a firmware change? Before the
present change they would return compiled-in defaults of "<manufacturer>" and
"<model>", respectively; with the present change the firmware will self-identify
as "FreeCalypso GTM900-FC" or "FreeCalypso Tango" on the two respective targets.
This firmware identification will become important if someone incorporates an
FC-converted GTM900 or Tango modem into a ZeroPhone-style smartphone where some
high-level software like ofono will be talking to the modem and will need to
properly identify this modem as FreeCalypso, as opposed to some other AT command
modem flavor with different quirks.
In technical terms, the compiled-in default for the AT+CGMI query (which will
always be overridden by the /pcm/CGMI file in FFS if one is present) is now
"FreeCalypso" in all configs on all targets; the compiled-in default for the
AT+CGMM query (likewise always overridden by /pcm/CGMM if present) is
"GTM900-FC" if CONFIG_TARGET_GTM900 or "Tango" if CONFIG_TARGET_TANGO or the
original default of "<model>" otherwise.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 19 Jan 2020 20:14:58 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GSM-PS | Modul : ALR_CS +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This Modul defines the SDL process Cell Selection. +----------------------------------------------------------------------------- */ #ifndef ALR_CS_C #define ALR_CS_C #define ENTITY_PL /*==== INCLUDES ===================================================*/ #include <string.h> #include <stdlib.h> #include <limits.h> #include "typedefs.h" #include "vsi.h" #include "custom.h" #include "gsm.h" #include "prim.h" #include "pei.h" #include "tok.h" #include "pcm.h" #ifdef GPRS #include "alr_gprs.h" #endif #include "alr.h" #include "alr_em.h" #include "cl_list.h" #if defined (_SIMULATION_) #define TRACING #endif #if defined (TRACING) #define ALR_TRACE_CS(a) ALR_TRACE(a) #else #define ALR_TRACE_CS(a) #endif #if defined (TRACING) #define ALR_TRACE_CS_STD(a1) TRACE_EVENT_P1 ("std %d",a1) #define ALR_TRACE_CS_BSIC_REQ(a,s) TRACE_EVENT_P2 ("BSIC REQ [%u] %d", a, s) #define ALR_TRACE_CS_SYNC_VALID(a,f,t) TRACE_EVENT_P3 ("set new SC[%u],valid block fno:%d,time_al%d",a,f,t) #else #define ALR_TRACE_CS_STD(std) #define ALR_TRACE_CS_BSIC_REQ(a,s) #define ALR_TRACE_CS_SYNC_VALID(a,f,t) #endif /*==== EXPORT =====================================================*/ /*==== PRIVAT =====================================================*/ /*==== VARIABLES ==================================================*/ /* Power scan attempts for different search modes */ LOCAL const U8 power_scan_attempts[] = { FULL_SEARCH_MODE_ATTEMPTS, NORMAL_SEARCH_MODE_ATTEMPTS, FAST_SEARCH_MODE_ATTEMPTS, BLACK_LIST_SEARCH_MODE_ATTEMPTS }; /* Power measurements spreading time for different search modes */ #if defined(_SIMULATION_) LOCAL const U16 tim_powermeas_value[] = { 500, 500, 100, 100 }; #else LOCAL const U16 tim_powermeas_value[] = { TIM_FULL_SEARCH_POWERMEAS_VAL, TIM_NORMAL_SEARCH_POWERMEAS_VAL, TIM_FAST_SEARCH_POWERMEAS_VAL, TIM_BLACK_LIST_SEARCH_POWERMEAS_VAL }; #endif LOCAL const int array_band_index[] = { B_GSM_900, B_E_GSM, B_PCS_1900, B_DCS_1800, MAX_NUM_BANDS, MAX_NUM_BANDS, B_GSM_850 }; /*==== FUNCTIONS ==================================================*/ LOCAL void cs_add_and_sort_channels (void); LOCAL void cs_find_inactive_carriers (T_POWER_MEAS **p_results, U16 p_results_size[2],U8 *std, U8 no_of_attempts, SHORT *min_rxlev); LOCAL U8 cs_add_whitelist_carriers (U16 p_results_size[2], U8 std, U8 attempts, SHORT *min_rxlev, T_POWER_MEAS *presults, U8 no_of_carriers_per_band[4]); LOCAL BOOL cs_is_in_black_list (U8 region,U16 arfcn); LOCAL U8 cs_restrict_max_carriers_per_band (U16 arfcn, U8 std, U8 no_of_carriers_per_band[4], U16 p_results_size[2], U8 band_index); LOCAL void cs_move_extra_carriers (U8 i_cnf, U8 extra_cnf); LOCAL void cs_reorder_the_extra_carriers (U8 extra_cnf); LOCAL void cs_power_array_swap_arfcn (T_POWER_ARRAY *from, T_POWER_ARRAY *to); /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_init | +--------------------------------------------------------------------+ PURPOSE : Initialize Cell Selection Process. Set state and dynamic allocated RAM area to NULL. */ GLOBAL void cs_init (void) { TRACE_FUNCTION ("cs_init()"); alr_data->state[STATE_CS] = CS_NULL; memset (&alr_data->cs_data, 0, sizeof (T_CS_DATA)); alr_data->cs_data.p_results1 = (T_POWER_MEAS*)&alr_power_meas_result1; alr_data->cs_data.p_results2 = (T_POWER_MEAS*)&alr_power_meas_result2; alr_data->cs_data.search_mode = SM_WIDE_MODE; alr_data->cs_data.sync_fail_count = CS_SYNC_FAIL_COUNT_MAX; alr_data->cs_data.bcch_fail_count = CS_BCCH_FAIL_COUNT_MAX; if ( IS_EXT_MEAS_RUNNING ) /*alr_data->cs_data.mph_ext_meas_req NEQ NULL*/ { PFREE ( alr_data->cs_data.mph_ext_meas_req ); alr_data->cs_data.mph_ext_meas_req = NULL; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_get_next_area | +--------------------------------------------------------------------+ PURPOSE : This returns the next area to scan ('next_area'). Also it sets 'std' and 'freq_area' - members of 'cs_data' - depend on given 'freq_bands'. */ LOCAL UBYTE cs_get_next_area (void) { UBYTE next_area; if ((alr_data->cs_data.freq_area&ALL_FREQ_AREA) EQ ALL_FREQ_AREA) next_area = (alr_data->cs_data.freq_area&NEXT_AMERICAN_AREA) ? AMERICAN_FREQ_AREA : EUROPEAN_FREQ_AREA; else next_area = alr_data->cs_data.freq_area; /* * In the case the members and value arenīt already initialized, * next_area is set to 0 */ switch (next_area) { default: case EUROPEAN_FREQ_AREA: if ((alr_data->cs_data.std12 & 0x0f) EQ 0) /* not initialized */ next_area = 0; break; case AMERICAN_FREQ_AREA: if ((alr_data->cs_data.std12 >> 4) EQ 0) /* not initialized */ next_area = 0; break; case 0: break; } /* if (next_area) { TRACE_EVENT_P9 ("cs_get_next_area: fb=%02x => cs_std=%u(%u) std12=%02x area=%02x'%c%c' next=%u'%c'", alr_data->cs_data.freq_bands, alr_data->cs_data.std, std, alr_data->cs_data.std12, alr_data->cs_data.freq_area, (alr_data->cs_data.freq_area & EUROPEAN_FREQ_AREA) ? 'E':' ', (alr_data->cs_data.freq_area & AMERICAN_FREQ_AREA) ? 'A':' ', next_area, next_area ? ((next_area EQ AMERICAN_FREQ_AREA) ? 'A':' E') : '?'); } */ return next_area; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_get_std_area | +--------------------------------------------------------------------+ PURPOSE : This returns the frequency band 'std' depend on given 'freq_bands'. It also sets the suitable frequency area to the value of a possible given area pointer. This function knows only the single and dual frequency band combinations. Triple or quad frequency band combinations leads to return values set to 0. */ LOCAL UBYTE cs_get_std_area (UBYTE freq_bands, UBYTE *p_area) { UBYTE cs_freq_area; UBYTE cs_std; switch (freq_bands) { case BAND_GSM_900:/* single band */ cs_freq_area = EUROPEAN_FREQ_AREA; cs_std = STD_900; break; case BAND_DCS_1800:/* single band */ cs_freq_area = EUROPEAN_FREQ_AREA; cs_std = STD_1800; break; case BAND_PCS_1900:/* single band */ cs_freq_area = AMERICAN_FREQ_AREA; cs_std = STD_1900; break; case BAND_E_GSM:/* extended single band */ case BAND_GSM_900|BAND_E_GSM: /* extended single band */ cs_freq_area = EUROPEAN_FREQ_AREA; cs_std = STD_EGSM; break; case BAND_GSM_850:/* single band */ cs_freq_area = AMERICAN_FREQ_AREA; cs_std = STD_850; break; case BAND_DUAL:/* dual band */ cs_freq_area = EUROPEAN_FREQ_AREA; cs_std = STD_DUAL; break; case BAND_DUAL_EXT:/* dual band */ cs_freq_area = EUROPEAN_FREQ_AREA; cs_std = STD_DUAL_EGSM; break; case BAND_DUAL_US:/* dual band */ cs_freq_area = AMERICAN_FREQ_AREA; cs_std = STD_DUAL_US; break; default: cs_freq_area = 0; cs_std = 0; break; } if (p_area) *p_area = cs_freq_area; return cs_std; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_set_std_area | +--------------------------------------------------------------------+ PURPOSE : This returns the next area to scan ('next_area'). Also it sets 'std' and 'freq_area' - members of 'cs_data' - depend on given 'freq_bands'. This function will be executed at least once (single band) and not more than twice (multiband) per power request. */ LOCAL UBYTE cs_set_std_area (void) { UBYTE next_area; UBYTE cs_freq_bands = alr_data->cs_data.freq_bands; UBYTE cs_std; UBYTE cs_freq_area = alr_data->cs_data.freq_area; /* TRACE_EVENT_P1 ("cs_set_std_area(): %s call", cs_freq_area?"second":"first"); */ if (cs_freq_area & NEXT_AMERICAN_AREA) /* * Initializing before second measurement */ next_area = AMERICAN_FREQ_AREA; else next_area = 0; if (cs_freq_bands EQ 0) { TRACE_ERROR ("alr_data->cs_data.freq_bands=0 (Invalid value)!"); TRACE_ASSERT (cs_freq_bands EQ 0); } cs_std = cs_get_std_area(cs_freq_bands, &cs_freq_area); if (cs_std EQ 0) { cs_freq_area = 0; if (cs_freq_bands & BAND_DUAL_EXT) { /* european frequency bands */ cs_freq_area |= EUROPEAN_FREQ_AREA; if (next_area EQ 0) next_area = EUROPEAN_FREQ_AREA; } if (cs_freq_bands & BAND_DUAL_US) { /* american frequency bands */ cs_freq_area |= AMERICAN_FREQ_AREA; if (next_area EQ 0) next_area = AMERICAN_FREQ_AREA; } if (next_area EQ EUROPEAN_FREQ_AREA) { cs_freq_bands &= BAND_DUAL_EXT; } else { cs_freq_bands &= BAND_DUAL_US; cs_freq_area |= NEXT_AMERICAN_AREA; } /* * get the next 'std' depend on the value of 'next_area' */ cs_std = cs_get_std_area (cs_freq_bands, NULL); } if (next_area EQ 0) next_area = cs_freq_area; alr_data->cs_data.freq_area = cs_freq_area; alr_data->cs_data.std = cs_std; TRACE_EVENT_P9 ("cs_set_std_area: fb=%02x => cs_std=%u(%u) std12=%02x area=%02x'%c%c' next=%u'%c'", alr_data->cs_data.freq_bands, alr_data->cs_data.std, std, alr_data->cs_data.std12, alr_data->cs_data.freq_area, (alr_data->cs_data.freq_area & EUROPEAN_FREQ_AREA) ? 'E':' ', (alr_data->cs_data.freq_area & AMERICAN_FREQ_AREA) ? 'A':' ', next_area, next_area ? ((next_area EQ AMERICAN_FREQ_AREA) ? 'A':'E') : '?'); return next_area; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_power_array_swap_arfcn| +--------------------------------------------------------------------+ PURPOSE : This function swaps ARFCN and its RxLev between the locations passed. */ LOCAL void cs_power_array_swap_arfcn(T_POWER_ARRAY *ptr1,T_POWER_ARRAY *ptr2) { U16 temp_arfcn; SHORT temp_rxlev; temp_arfcn = ptr1->radio_freq; temp_rxlev = ptr1->accum_power_result; ptr1->radio_freq = ptr2->radio_freq; ptr1->accum_power_result = ptr2->accum_power_result; ptr2->radio_freq = temp_arfcn; ptr2->accum_power_result = temp_rxlev; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_prepare_power_req | +--------------------------------------------------------------------+ PURPOSE : This prepares the inputs for the power request depending on the frequency areas. */ GLOBAL T_POWER_MEAS* cs_prepare_power_req (void) { UBYTE next_area,region; T_POWER_MEAS *power_meas; T_LIST *black_list; TRACE_FUNCTION ("cs_prepare_power_req"); /* * depending on the set frequency area */ next_area = cs_get_next_area (); if (next_area) { /* members and values are already initialized */ switch (next_area) { default: case EUROPEAN_FREQ_AREA: power_meas = alr_data->cs_data.p_results1; alr_data->cs_data.std = alr_data->cs_data.std12&0x0f; break; case AMERICAN_FREQ_AREA: power_meas = alr_data->cs_data.p_results2; alr_data->cs_data.std = alr_data->cs_data.std12>>4; break; } TRACE_EVENT_WIN_P4 ("cs_prepare_power_req: cs_std=%u(%02x) next=%u'%c'", alr_data->cs_data.std, alr_data->cs_data.std12, next_area, (next_area EQ AMERICAN_FREQ_AREA) ? 'A':'E'); } else { /* must be initialize first */ int i; int power_array_size; int radio_freq_offset = 1; /* * depending on the given frequency bands */ next_area = cs_set_std_area (); /* * depending on the just set frequency standard */ switch(alr_data->cs_data.std) { case STD_900: power_array_size = MAX_CARRIERS_GSM900; break; case STD_EGSM: power_array_size = MAX_CARRIERS_EGSM900; break; case STD_1900: power_array_size = MAX_CARRIERS_PCS1900; radio_freq_offset = 512; break; case STD_1800: power_array_size = MAX_CARRIERS_DCS1800; radio_freq_offset = 512; break; case STD_DUAL: power_array_size = MAX_CARRIERS_DUAL; break; case STD_DUAL_EGSM: power_array_size = MAX_CARRIERS_DUAL_EGSM; break; case STD_850: power_array_size = MAX_CARRIERS_GSM850; radio_freq_offset = 128; break; case STD_DUAL_US: power_array_size = MAX_CARRIERS_DUAL_US; break; default: power_array_size = 0; break; } if (power_array_size) { /* * fill all carriers which shall be measured into the structure * to layer 1. */ T_POWER_ARRAY *power_array; USHORT size; if ( IS_EXT_MEAS_RUNNING ) { power_array_size = alr_data->cs_data.mph_ext_meas_req->num_of_chan; } /* depend on the next area get the right T_POWER_MEAS instance */ switch (next_area) { default: case EUROPEAN_FREQ_AREA: size = sizeof (T_POWER_MEAS1); power_meas = alr_data->cs_data.p_results1; /* TRACE_EVENT_P1 ("static T_POWER_MEAS(EU): size=%u", sizeof (T_POWER_MEAS1)); */ memset (alr_data->cs_data.p_results1, 0, sizeof (T_POWER_MEAS)); /* save value of 'std' for cs_increment_c_channels() */ alr_data->cs_data.std12 |= alr_data->cs_data.std & 0x0f; break; case AMERICAN_FREQ_AREA: size = sizeof (T_POWER_MEAS2); power_meas = alr_data->cs_data.p_results2; /* TRACE_EVENT_P1 ("static T_POWER_MEAS(USA): size=%u", sizeof (T_POWER_MEAS2)); */ /* save value of 'std' for cs_increment_c_channels() */ alr_data->cs_data.std12 |= (alr_data->cs_data.std << 4); break; } memset (power_meas, 0, size); TRACE_EVENT_WIN_P8 ("cs_prepare_power_req: cs_std=%u(%u) std12=%02x rf=%u..%u (%u) next=%u'%c'", alr_data->cs_data.std, std, alr_data->cs_data.std12, radio_freq_offset, power_array_size+radio_freq_offset-1, power_array_size, next_area, (next_area EQ AMERICAN_FREQ_AREA) ? 'A':'E'); power_array = &(power_meas->power_array[0]); memset (power_array, 0, sizeof (T_POWER_ARRAY) * power_array_size); power_meas->power_array_size = power_array_size; if ( IS_EXT_MEAS_RUNNING ) { USHORT *arfcn = &alr_data->cs_data.mph_ext_meas_req->arfcn[0]; for ( i = 0; i < power_array_size; i++, power_array++, arfcn++ ) { power_array->radio_freq = ARFCN_TO_L1 ( *arfcn ); } } else { if(alr_data->cs_data.p_power_req->search_mode NEQ BLACK_LIST_SEARCH_MODE) { power_array_size += radio_freq_offset; for(i=radio_freq_offset; i < power_array_size; i++, power_array++) { power_array->radio_freq = (U16)i; } } else { /* Blacklist search. Fill all Black Listed and "Grey" carriers * sent by RR for L1 measurement */ region = srv_get_region_from_std(std); black_list = (T_LIST*)&alr_data->cs_data.p_power_req->black_list.list[region]; power_meas->power_array_size = 0; for(i=CHANNEL_0;i<CHANNEL_0_INTERNAL;i++) { if(srv_get_channel(black_list, i)) { power_array->radio_freq = ARFCN_TO_L1 ( i ); power_meas->power_array_size++; power_array++; } } } /* Black list search */ } /* !EXT_MEAS */ } /* power_array_size != 0 */ else { TRACE_EVENT_P6 ("cs_prepare_power_req: invalid: fb=%02x cs_std=%u area=%02x'%c%c' next='%c'", alr_data->cs_data.freq_bands, alr_data->cs_data.std, alr_data->cs_data.freq_area, (alr_data->cs_data.freq_area & EUROPEAN_FREQ_AREA) ? 'E':' ', (alr_data->cs_data.freq_area & AMERICAN_FREQ_AREA) ? 'A':' ', (next_area EQ AMERICAN_FREQ_AREA) ? 'A':'E'); power_meas = NULL;/* invalid values */ } } return power_meas;/* do it */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_power_req | +--------------------------------------------------------------------+ PURPOSE : This starts measurement of the fieldstrength of all channels. */ GLOBAL void cs_power_req (UBYTE pch_interrupt) { TRACE_EVENT_P1 (" p_results1=%08x", alr_data->cs_data.p_results1); /* Reset CS data */ alr_data->cs_data.std12 = 0; alr_data->cs_data.freq_area = 0; alr_data->cs_data.c_meas = 0; alr_data->cs_data.p_results1->power_array_size = 0; alr_data->cs_data.p_results2->power_array_size = 0; cs_prepare_power_req(); if(IS_EXT_MEAS_RUNNING) { alr_data->cs_data.c_max_meas = power_scan_attempts[FULL_SEARCH_MODE]; alr_data->cs_data.c_tim_meas = (tim_powermeas_value[FULL_SEARCH_MODE]/ power_scan_attempts[FULL_SEARCH_MODE]); } else { T_MPH_POWER_REQ* mph_power_req = alr_data->cs_data.p_power_req; /* CSI-LLD Section: 4.1.3.4.2.3 * Set the number of RF scan attempts and TIM_POWER_MEAS timer value * based on the search mode */ /* Set the number of RF scan attempts */ alr_data->cs_data.c_max_meas = power_scan_attempts[mph_power_req->search_mode]; /* Set TIM_POWER_MEAS timer value */ alr_data->cs_data.c_tim_meas = (tim_powermeas_value[mph_power_req->search_mode] / power_scan_attempts[mph_power_req->search_mode]); if (((alr_data->cs_data.freq_area & ALL_FREQ_AREA) EQ ALL_FREQ_AREA) AND (mph_power_req->search_mode NEQ BLACK_LIST_SEARCH_MODE)) { /* Multiply the number of field strength measurements by 2 */ alr_data->cs_data.c_max_meas <<= 1; /* Reduce the TIM_POWER_MEAS value by half */ alr_data->cs_data.c_tim_meas >>= 1; } TRACE_EVENT_P2(" Search Type:[%u] Search Mode:[%u]", mph_power_req->pch_interrupt, mph_power_req->search_mode); } /* new state is dependent on necessary of the L1 configuration */ if ((pch_interrupt EQ PCH_INTERRUPT) OR (alr_data->cs_data.std NEQ std)) { SET_STATE (STATE_CS, CS_INIT_L1); } else { SET_STATE (STATE_CS, CS_START_MEASURE); } TRACE_EVENT_P2 ("cs_power_req: c_max_meas=%u c_tim_meas=%u", alr_data->cs_data.c_max_meas, alr_data->cs_data.c_tim_meas); ma_cs_rxlev_req (); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_bsic_req | +--------------------------------------------------------------------+ PURPOSE : Request of RR to search for frequency correction burst and synchron burst. */ GLOBAL void cs_bsic_req (T_MPH_BSIC_REQ * mph_bsic_req) { UBYTE cs_std; if (mph_bsic_req) { ALR_TRACE_CS_BSIC_REQ(mph_bsic_req->arfcn&ARFCN_MASK, GET_STATE (STATE_CS)); ALR_EM_BSIC_REQUEST; } /* * cs_bsic_req is called from several places with mph_bsic_req EQ NULL */ switch (GET_STATE (STATE_CS)) { case CS_ACTIVE_BCCH: ma_stop_scell_bcch_req (); /* * first stop BCCH reading, * then start like in idle mode if * it is a valid channel number */ /*lint -fallthrough*/ default: if (mph_bsic_req) { alr_data->cs_data.arfcn = mph_bsic_req->arfcn; cs_std = STD_GET_FROM_ARFCN (mph_bsic_req->arfcn); if (cs_std AND (cs_std NEQ alr_data->cs_data.std)) { /* * When RR supplies a value of 'std' then init radio band before sync */ TRACE_EVENT_WIN_P2("cs_bsic_req: cs_std=%u->%u", alr_data->cs_data.std, cs_std); alr_data->cs_data.std = cs_std; ma_cs_init_l1_req(alr_data->cs_data.std); SET_STATE(STATE_CS, CS_INIT_SYNC); return; /* wait of MPHC_INIT_L1_CON */ } } /* If no value of 'std' are supplied, then start sync immediately */ /*lint -fallthrough*/ case CS_INIT_DONE: #if defined(STOP_SYNC_TASK) if (alr_data->cs_data.sync_active) { /* * stop any synchronisation task */ SET_STATE(STATE_CS, CS_STOP_SYNC); ma_cs_stop_network_sync_req(); return;/* wait for MPHC_STOP_NETWORK_SYNC_CON */ } /*lint -fallthrough*/ case CS_STOP_SYNC_DONE: #endif /* STOP_SYNC */ /* * start synchronisation * to the frequency correction burst and synchron burst * in layer 1. */ TRACE_EVENT_P1 ("NETWORK_SYNC_REQ[%u]", alr_data->cs_data.arfcn&ARFCN_MASK); ma_cs_network_sync_req (ARFCN_STD_TO_L1(alr_data->cs_data.arfcn, alr_data->cs_data.std)); SET_STATE(STATE_CS, CS_ACTIVE_SYNC); break; #if defined(STOP_SYNC_TASK) case CS_STOP_SYNC: /* do nothing, wait for MPHC_STOP_NETWORK_SYNC_CON */ return; #endif /* STOP_SYNC */ } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_rxlev_ind | +--------------------------------------------------------------------+ PURPOSE : This is the response from layer 1 for a measurement sample request over all channels. */ GLOBAL void cs_rxlev_ind (T_MPHC_RXLEV_IND* rxlev_ind) { #if defined(_SIMULATION_) { /* * special handling for windows simulation. In this case predefined * values are used, because the primitives are too big to be forwarded * via the test interface. */ int index = rxlev_ind->shared_ptr; memcpy(alr_data->cs_data.p_results1,&tap_rxlev_response_european[index], sizeof(T_POWER_MEAS)); memcpy(alr_data->cs_data.p_results2,&tap_rxlev_response_american[index], sizeof(T_POWER_MEAS)); } #endif /* _SIMULATION_ */ TRACE_EVENT_P3 ("cs_rxlev_ind(): cs_std=%u c_meas=%u/%u", alr_data->cs_data.std, alr_data->cs_data.c_meas+1, alr_data->cs_data.c_max_meas); if ( IS_EXT_MEAS_RUNNING AND alr_data->cs_data.ext_meas_state_pend NEQ CS_NULL ) { TIMERSTOP(TIM_POWERMEAS); SET_STATE (STATE_CS, CS_NULL); nc_stop_ext_meas_ind(); return; } switch (GET_STATE (STATE_CS)) { case CS_MEASURED: /* increment the number of measurement samples */ alr_data->cs_data.c_meas++; if (alr_data->cs_data.c_meas EQ alr_data->cs_data.c_max_meas) { /* Allocate memory for MPH_POWER_CNF */ PALLOC (mph_power_cnf, MPH_POWER_CNF); if (alr_data->cs_data.p_power_cnf) { PFREE (alr_data->cs_data.p_power_cnf); } alr_data->cs_data.p_power_cnf = mph_power_cnf; memset (alr_data->cs_data.p_power_cnf, 0, sizeof (T_MPH_POWER_CNF)); TIMERSTOP(TIM_POWERMEAS); /* Sort the channels based on their RxLev */ cs_add_and_sort_channels (); if(!IS_EXT_MEAS_RUNNING) { /* Free MPH_POWER_REQ buffer */ PFREE(alr_data->cs_data.p_power_req); alr_data->cs_data.p_power_req = NULL; } /* Send fieldstrength list to RR */ ma_cs_power_cnf (mph_power_cnf); /* we are done with power measurements, next comes the BCCH detection */ SET_STATE (STATE_CS, CS_NULL); alr_data->cs_data.p_power_cnf = NULL; ALR_EM_POWER_MEASUREMENT_CONFIRM; } else if (alr_data->cs_data.c_meas < alr_data->cs_data.c_max_meas) { /* * start next sample */ if ((alr_data->cs_data.freq_area & ALL_FREQ_AREA) EQ ALL_FREQ_AREA) { /* * toggle radio_band and configure new before the next measurement */ TRACE_EVENT_P2 ("cs_rxlev_ind(): area=%02x->%02x", alr_data->cs_data.freq_area, alr_data->cs_data.freq_area^NEXT_AMERICAN_AREA); alr_data->cs_data.freq_area ^= NEXT_AMERICAN_AREA; SET_STATE (STATE_CS, CS_INIT_L1); } else { /* * start new measurement without new configuration of radio_band */ SET_STATE (STATE_CS, CS_START_MEASURE); } ma_cs_rxlev_req (); } break; default: break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_network_sync_ind | +--------------------------------------------------------------------+ PURPOSE : The function handles the result of a search for FCB or SCB. */ GLOBAL void cs_network_sync_ind (T_MPHC_NETWORK_SYNC_IND* sync_ind) { PALLOC (mph_bsic_cnf, MPH_BSIC_CNF); alr_data->cs_data.sync_active = FALSE; /* * The BCCH fail counter has to be reinitialized for every new cell. */ alr_data->cs_data.bcch_fail_count = CS_BCCH_FAIL_COUNT_MAX; /* * copy arfcn, rxlev and bsic */ mph_bsic_cnf->arfcn = ARFCN_STD_TO_G23(sync_ind->radio_freq, alr_data->cs_data.std); mph_bsic_cnf->arfcn = STD_ADD_TO_ARFCN(mph_bsic_cnf->arfcn, alr_data->cs_data.std); /* US_BIT should be used to differentiate an US frequency channel. */ switch (alr_data->cs_data.std) { case STD_1900: case STD_850: case STD_DUAL_US: mph_bsic_cnf->arfcn |= US_BIT; break; default: break; } /* * set bsic and result code */ mph_bsic_cnf->bsic = (UBYTE)(sync_ind->bsic & 63); mph_bsic_cnf->cs = sync_ind->sb_flag ? CS_NO_ERROR : CS_NO_BCCH_AVAIL; TRACE_EVENT_P4 ("network_sync_ind:[%u] rf=%u cs_std=%u %s", mph_bsic_cnf->arfcn&ARFCN_MASK, sync_ind->radio_freq, alr_data->cs_data.std, sync_ind->sb_flag ? "OK" : "no BCCH avail."); switch (GET_STATE(STATE_CS)) { /* * workarounds for crossing MPHC_STOP_NETWORK_SYNC_REQ and * MPHC_NETWORK_SYNC_IND: * It is possible to receive a MPHC_NETWORK_SYNC_IND from layer 1 at the * same time as sending a MPHC_STOP_NETWORK_SYNC_REQ. The * MPHC_STOP_NETWORK_SYNC_REQ will be ignored by the layer 1 and no * STOP_NW_SYNC_CON will be send. */ case CS_STOP_SYNC: /* The state CS_STOP_SYNC was set and the MPHC_NETWORK_SYNC_REQ was * interrupted to clean the way for a new MPHC_NETWORK_SYNC_REQ. A possible * MPHC_NETWORK_SYNC_IND will be treated as MPHC_STOP_NETWORK_SYNC_CON * because the result does not matter. */ SET_STATE (STATE_CS, CS_STOP_SYNC_DONE); cs_bsic_req(NULL); /*lint -fallthrough */ default: /* * the synchronisation has been broken */ ALR_TRACE_CS ("MPHC_NETWORK_SYNC_IND ignored"); PFREE (mph_bsic_cnf); return; /* break; */ case CS_NW_SYNC_TIMEOUT: /* * The state CS_NW_SYNC_TIMEOUT was set and the MPHC_NETWORK_SYNC_REQ was * interrupted to limit the time for reading the BCCH. A possible * MPHC_NETWORK_SYNC_IND will be treated normal. Otherwise, no BSIC_CNF * will be sent to RR, and RR waits forever. */ SET_STATE(STATE_CS, CS_ACTIVE_SYNC); /*lint -fallthrough */ case CS_ACTIVE_SYNC: ma_bsic_cnf (mph_bsic_cnf); break; } #ifdef GPRS if(alr_data->gprs_data.pcco_active) { USHORT index; /* store data in nc_data.cr_cell */ alr_data->nc_data.cr_cell.ba_arfcn = ARFCN_TO_G23(sync_ind->radio_freq)&ARFCN_MASK; alr_data->nc_data.cr_cell.bsic = (UBYTE)(sync_ind->bsic & 63); alr_data->nc_data.cr_cell.frame_offset = sync_ind->fn_offset; alr_data->nc_data.cr_cell.time_align = sync_ind->time_alignment; index = nc_get_index(alr_data->nc_data.cr_cell.ba_arfcn); if ((index NEQ NOT_PRESENT_16BIT) AND (index NEQ LAST_BSIC_REQ)) { /* * update in nc_data also because this data is not valid * anymore after a network_sync_req and in some special cases * nc_start_reselect will use the data in nc_data.cell[index] */ alr_data->nc_data.cell[index].bsic = (UBYTE)(sync_ind->bsic & 63); alr_data->nc_data.cell[index].frame_offset = sync_ind->fn_offset; alr_data->nc_data.cell[index].time_align = sync_ind->time_alignment; } SET_STATE(STATE_CS, CS_NULL); return; } #endif if (sync_ind->sb_flag) { if (GET_STATE (STATE_CS) EQ CS_ACTIVE_SYNC) { USHORT arfcn; PALLOC(new_scell, MPHC_NEW_SCELL_REQ); arfcn = ARFCN_STD_TO_G23(sync_ind->radio_freq, alr_data->cs_data.std); ALR_TRACE_CS_SYNC_VALID(arfcn, sync_ind->fn_offset, sync_ind->time_alignment); /* store data in nc_data.cr_cell */ alr_data->nc_data.cr_cell.ba_arfcn = ARFCN_TO_G23(sync_ind->radio_freq)&ARFCN_MASK; alr_data->nc_data.cr_cell.bsic = sync_ind->bsic; alr_data->nc_data.cr_cell.frame_offset = 0; alr_data->nc_data.cr_cell.time_align = 0; new_scell->radio_freq = sync_ind->radio_freq; new_scell->fn_offset = sync_ind->fn_offset; new_scell->time_alignment = sync_ind->time_alignment; new_scell->tsc = sync_ind->bsic; ALR_EM_BSIC_CONFIRM(EM_AVAIL); /* after successful sync we can use narrow band search mode for * subsequent syncs. */ alr_data->cs_data.search_mode = SM_NARROW_MODE; alr_data->cs_data.sync_fail_count = CS_SYNC_FAIL_COUNT_MAX; alr_data->sc_band = get_band (arfcn); ma_new_scell_req(new_scell); } } else { ALR_TRACE_CS ("INVALID BLOCK"); ALR_EM_BSIC_CONFIRM(EM_NOT_AVAIL); /* If there are too many failed sync attempts in a row the AFC value * in L1 might be screwed up somehow. */ if(alr_data->cs_data.sync_fail_count EQ 0) { alr_data->cs_data.sync_fail_count = CS_SYNC_FAIL_COUNT_MAX; alr_data->cs_data.search_mode = SM_WIDE_MODE; } else { alr_data->cs_data.sync_fail_count -= 1; } } SET_STATE(STATE_CS, CS_NULL); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_stop | +--------------------------------------------------------------------+ PURPOSE : Process signal cs_stop from SDL process Main_Control. This function stops all cell selection activities of ALR. */ GLOBAL void cs_stop (void) { switch (GET_STATE (STATE_CS)) { case CS_ACTIVE_MEASURE: { PALLOC (stop_req, MPHC_STOP_RXLEV_REQ); PSENDX (L1, stop_req); if ( IS_EXT_MEAS_RUNNING ) { /* wait for MPHC_RXLEV_IND */ alr_data->cs_data.ext_meas_state_pend = CS_ACTIVE_MEASURE; } break; } case CS_ACTIVE_SYNC: { PALLOC (stop_req, MPHC_STOP_NETWORK_SYNC_REQ); TIMERSTOP(TIM_NW_SYNC_GUARD); PSENDX (L1, stop_req); break; } case CS_ACTIVE_BCCH: /* * Stop BCCH reading */ ma_stop_scell_bcch_req (); break; default: break; } SET_STATE (STATE_CS, CS_NULL); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_read_scell_bcch | +--------------------------------------------------------------------+ PURPOSE : Process signal cs_read_scell_bcch from SDL process Main_Control. This funtion requests reading of the full serving cell BCCH. */ GLOBAL void cs_read_scell_bcch (void) { /* * send bcch req * do full normal BCCH reading(modulus=1,position=0) */ SET_STATE(STATE_CS, CS_ACTIVE_BCCH); ma_scell_full_nbcch(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_add_and_sort_channels | +--------------------------------------------------------------------+ PURPOSE : Accumulate power measurements for all found channels sorted by highest fieldstrength. */ LOCAL void cs_add_and_sort_channels (void) { T_MPH_POWER_CNF* mph_power_cnf = alr_data->cs_data.p_power_cnf; T_MPH_POWER_REQ* mph_power_req = alr_data->cs_data.p_power_req; T_POWER_MEAS *p_results[MAX_REGIONS]; T_POWER_ARRAY *parray, *pbig, *last; SHORT rxlev, min_rxlev[MAX_NUM_BANDS]; UBYTE x, band_index; U16 i, j, p_results_size[MAX_REGIONS], arfcn; U8 radio_band_config, std[MAX_REGIONS]; U8 no_of_attempts, region, where_to_add; U8 i_cnf, extra_cnf, extra_space; U8 no_of_carriers_per_band[4] = {0, 0, 0, 0}; /* Counter for Multible frequency band in a Region * Index 0 for GSM_900, * Index 1 for DCS_1800, * Index 2 for GSM_850, * Index 3 for PCS_1900 */ /* Obtain data for European region */ p_results[EUROPEAN_REGION] = alr_data->cs_data.p_results1; p_results_size[EUROPEAN_REGION] = alr_data->cs_data.p_results1 ? (alr_data->cs_data.p_results1->power_array_size) : 0; /* Obtain data for American region */ p_results[AMERICAN_REGION] = alr_data->cs_data.p_results2; p_results_size[AMERICAN_REGION] = alr_data->cs_data.p_results2 ? alr_data->cs_data.p_results2->power_array_size : 0; TRACE_FUNCTION ( "cs_add_and_sort_channels()" ); if (!mph_power_cnf) { TRACE_EVENT ("mph_power_cnf EQ NULL"); SET_STATE (STATE_CS, CS_NULL); return; } i_cnf = 0; extra_cnf = MAX_CHANNELS - 1; mph_power_cnf->num_of_chan = 0; /* Set the minimum signal level */ if ( IS_EXT_MEAS_RUNNING ) { no_of_attempts = power_scan_attempts[FULL_SEARCH_MODE]; for(x=0 ; x<MAX_NUM_BANDS ; x++ ) min_rxlev[x] = SHRT_MIN + 1; } else { if (!mph_power_req) { TRACE_EVENT ("mph_power_req EQ NULL"); SET_STATE (STATE_CS, CS_NULL); return; } no_of_attempts = power_scan_attempts[mph_power_req->search_mode]; for(x=0 ; x<MAX_NUM_BANDS ; x++ ) min_rxlev[x] = mph_power_req->lower_rxlevel_threshold[x] * no_of_attempts; } TRACE_EVENT_P5 ("cs_add_and_sort_channels: std12=%02x max=%u/%u a='%c%c'", alr_data->cs_data.std12, p_results_size[EUROPEAN_REGION], p_results_size[AMERICAN_REGION], (alr_data->cs_data.freq_area & EUROPEAN_FREQ_AREA) ? 'E' : ' ', (alr_data->cs_data.freq_area & AMERICAN_FREQ_AREA) ? 'A' : ' '); if ((alr_data->cs_data.freq_area&ALL_FREQ_AREA) EQ ALL_FREQ_AREA) { /* use 'std' values saved by cs_prepare_power_req() */ std[EUROPEAN_REGION] = alr_data->cs_data.std12&0x0f; std[AMERICAN_REGION] = alr_data->cs_data.std12>>4; } else { /* only one area */ std[EUROPEAN_REGION] = std[AMERICAN_REGION] = alr_data->cs_data.std; if (alr_data->cs_data.freq_area & EUROPEAN_FREQ_AREA) p_results_size[AMERICAN_REGION] = 0; if (alr_data->cs_data.freq_area & AMERICAN_FREQ_AREA) p_results_size[EUROPEAN_REGION] = 0; } if( IS_EXT_MEAS_RUNNING ) { /* * According to 3GPP 05 08 * Section "Range of parameter RxLev" * * The measured signal level shall be mapped to an RXLEV value between 0 and 63, as follows: * RXLEV 0 = less than -110 dBm + SCALE. * RXLEV 1 = -110 dBm + SCALE to -109 dBm + SCALE. * RXLEV 2 = -109 dBm + SCALE to -108 dBm + SCALE. * : * : * RXLEV 62 = -49 dBm + SCALE to -48 dBm + SCALE. * RXLEV 63 = greater than -48 dBm + SCALE. * where SCALE is an offset that is used only in the ENHANCED MEASUREMENT REPORT message, * otherwise it is set to 0. */ for(i=0; i < p_results_size[EUROPEAN_REGION]; i++) if( p_results[EUROPEAN_REGION]->power_array->accum_power_result < 0 ) p_results[EUROPEAN_REGION]->power_array->accum_power_result = 0; for(i=0; i < p_results_size[AMERICAN_REGION]; i++) if( p_results[AMERICAN_REGION]->power_array->accum_power_result < 0 ) p_results[AMERICAN_REGION]->power_array->accum_power_result = 0; } else { /* LLD Section : 4.1.3.4.2 * Find all inactive carriers and add them to MPH_POER_CNF * Also set the Rxlev of all Black Listed carriers to less than * Lower_Rxlev_Threshold */ TRACE_EVENT_P2("BIC->PWR array size, E:%d, A:%d", p_results_size[0], p_results_size[1]); cs_find_inactive_carriers(p_results, p_results_size, std, no_of_attempts, min_rxlev); TRACE_EVENT_P2("AIC->PWR array size, E:%d, A:%d", p_results_size[0], p_results_size[1]); /* * If the search mode is BLACK_LIST_SEARCH_MODE no need for sorting * (based on RXLEV) the carriers (RR will look only for * inactive carrier list) */ if(mph_power_req->search_mode EQ BLACK_LIST_SEARCH_MODE) { /* Allow measurement indications posting to RR */ SET_STATE(STATE_NC,NC_IDLE); return; } /* Put whitelist carriers at the top of power cnf list */ if(mph_power_req->white_list.white_list_valid) { region = mph_power_req->white_list.region; switch(mph_power_req->white_list.region) { case EUROPEAN_REGION : case AMERICAN_REGION : i_cnf = cs_add_whitelist_carriers(p_results_size, std[region], no_of_attempts, min_rxlev, p_results[region], no_of_carriers_per_band); TRACE_EVENT_P5( "[%c]White list Area (B_GSM_EGSM:%d, B_1800:%d, B_850:%d, B_1900:%d)", (mph_power_req->white_list.region ? 'A' : 'E'), no_of_carriers_per_band[0], no_of_carriers_per_band[1], no_of_carriers_per_band[2], no_of_carriers_per_band[3]); break; default : TRACE_EVENT_P1("Invalid whitelist region:%d",region); break; } } /* white list valid */ else { TRACE_EVENT("WL is absent"); } } /* !ext_meas */ TRACE_EVENT_P3("AWL->PWR array size, E:%d A:%d i_cnf:%d", p_results_size[0], p_results_size[1],i_cnf); while (i_cnf < MAX_CHANNELS) { pbig=NULL; rxlev = 0; radio_band_config = where_to_add =0x00; /* Loop through both regions */ for (i=0;i<MAX_REGIONS;i++) { if((p_results_size[i]) AND (p_results[i] NEQ NULL)) { parray = p_results[i]->power_array; for (j=0; j<p_results_size[i]; j++, parray++) { arfcn = ARFCN_STD_TO_G23(parray->radio_freq, std[i]); get_band_index_from_arfcn(arfcn, x, std[i]); if (parray->accum_power_result >= min_rxlev[x] AND parray->accum_power_result > rxlev) { pbig = parray; rxlev = parray->accum_power_result; radio_band_config = std[i]; region = (U8) i; band_index = x; } } } } if( pbig NEQ NULL ) { arfcn = ARFCN_STD_TO_G23(pbig->radio_freq, radio_band_config); if (rxlev > (min_rxlev[band_index] -1)) { /* fill mph_power_cnf */ arfcn = STD_ADD_TO_ARFCN(arfcn, radio_band_config); /* US_BIT should be used to differentiate an US frequency channel. */ switch (radio_band_config) { case STD_1900: case STD_850: case STD_DUAL_US: arfcn |= US_BIT; break; default: break; } where_to_add = cs_restrict_max_carriers_per_band( arfcn&ARFCN_MASK, radio_band_config, no_of_carriers_per_band, p_results_size, band_index); if(where_to_add EQ ADD_AT_THE_TOP) { /* First 40 Strongest Cariiers */ mph_power_cnf->arfcn[i_cnf] = arfcn; mph_power_cnf->rx_lev[i_cnf] = (U8)(rxlev/no_of_attempts); i_cnf++; } else if(where_to_add EQ ADD_AT_THE_BOTTOM) { /* Strongest Carriers which fall between 41 to 60 */ if(extra_cnf >= i_cnf) { mph_power_cnf->arfcn[extra_cnf] = arfcn; mph_power_cnf->rx_lev[extra_cnf] = (U8)(rxlev/no_of_attempts); extra_cnf--; } else { TRACE_EVENT_P2("MPH_POWER_CNF crossover, i_cnf: %d extra_cnf: %d", i_cnf, extra_cnf); } } /* After adding a carrier to MPH_POWER_CNF, the particular carrier will be * replaced by the Last carrier of that region. So that we could avoid * searching the already added (MPH_POWER_CNF) carrier. */ if(where_to_add NEQ REACHED_THE_MAXIMUM) { last = p_results[region]->power_array + (p_results_size[region]-1);/*lint !e644 region may not have been initialized */ pbig->accum_power_result = min_rxlev[band_index] - 1; cs_power_array_swap_arfcn(pbig, last); p_results_size[region]--; } else { TRACE_EVENT_P4("RTM->PWR array size, E:%d A:%d i_cnf:%d extra_cnf:%d", p_results_size[0], p_results_size[1],i_cnf, (MAX_CHANNELS-(extra_cnf+1))); } } } else break; /* no level found higher or equal than min_rxlev -> break sort/fill */ }/* while (i_cnf < MAX_CHANNELS) */ mph_power_cnf->num_of_chan = i_cnf; /* Obtain the number of extra channels(41 to 60) added to * Power cnf array */ extra_cnf = MAX_CHANNELS - (extra_cnf+1); /* Obtain the amount of space available for extra channels * in power_cnf array */ extra_space = MAX_CHANNELS - i_cnf; TRACE_EVENT_P3("After Sorting, i_cnf:%d extra_cnf:%d extra_space:%d", i_cnf,extra_cnf,(extra_space-extra_cnf)); if(extra_cnf AND extra_space) { /* Extra channels are present and space to fit them is also available */ if(extra_space < extra_cnf) { /* Some of the extra channels(41 to 60) are overwritten * Ignore them */ extra_cnf = extra_space; } /* Reordering the carriers(41 to 60) from Strongest to Weakest */ cs_reorder_the_extra_carriers(extra_cnf); /* Move the extra carriers up in power_cnf array, in case there * is empty gap between i_cnf and extra_cnf channels */ if(extra_space > extra_cnf) cs_move_extra_carriers(i_cnf, extra_cnf); mph_power_cnf->num_of_chan += extra_cnf; } TRACE_EVENT_P5( "No. of carriers in POWER_CNF:%d (B_GSM_EGSM:%d, B_1800:%d, B_850:%d, B_1900:%d)", mph_power_cnf->num_of_chan, no_of_carriers_per_band[0], no_of_carriers_per_band[1], no_of_carriers_per_band[2], no_of_carriers_per_band[3]); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : get_band | +--------------------------------------------------------------------+ PURPOSE : The function extracts the frequency band from the given 'arfcn' parameter. */ GLOBAL UBYTE get_band (USHORT arfcn) { UBYTE local_std = STD_GET_FROM_ARFCN(arfcn); UBYTE sc_band; if (local_std EQ 0) local_std = std; switch (local_std) { case STD_900: sc_band = BAND_GSM_900; break; case STD_EGSM: sc_band = BAND_E_GSM; break; case STD_1800: sc_band = BAND_DCS_1800; break; case STD_1900: sc_band = BAND_PCS_1900; break; case STD_850: sc_band = BAND_GSM_850; break; case STD_DUAL: if (arfcn >= LOW_CHANNEL_1800) sc_band = BAND_DCS_1800; else sc_band = BAND_GSM_900; break; case STD_DUAL_EGSM: if (arfcn >= LOW_CHANNEL_EGSM) sc_band = BAND_E_GSM; else if (arfcn >= LOW_CHANNEL_1800) sc_band = BAND_DCS_1800; else if (arfcn EQ CHANNEL_0) sc_band = BAND_E_GSM; else sc_band = BAND_GSM_900; break; case STD_DUAL_US: if (arfcn >= LOW_CHANNEL_1900) sc_band = BAND_PCS_1900; else sc_band = BAND_GSM_850; break; default: sc_band = 0; break; } /* this trace causes a lot of trace load; switch on only if needed TRACE_EVENT_P2 ("[%u] sc_band=%02x", arfcn&ARFCN_MASK, sc_band); */ return sc_band; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_increment_bfc | +--------------------------------------------------------------------+ PURPOSE : The function increments the BCCH fail counter. This counter is decremented on every invalid BCCH block read during CS. It is incremented on evry valid block read on BCCH during CS. Valid means in this case that there was a SYS Info decodable in the block on the BCCH. There is a maximum value to start with and when the counter reaches 0 we switch back to wide band search mode for further MPHC_NETWORK_SYNC_REQs (if any). */ GLOBAL void cs_increment_bfc (void) { alr_data->cs_data.bcch_fail_count += 1; if(alr_data->cs_data.bcch_fail_count > CS_BCCH_FAIL_COUNT_MAX) alr_data->cs_data.bcch_fail_count = CS_BCCH_FAIL_COUNT_MAX; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_decrement_bfc | +--------------------------------------------------------------------+ PURPOSE : The function decrements the BCCH fail counter. This counter is decremented on every invalid BCCH block read during CS. It is incremented on evry valid block read on BCCH during CS. Valid means in this case that there was a SYS Info decodable in the block on the BCCH. There is a maximum value to start with and when the counter reaches 0 we switch back to wide band search mode for further MPHC_NETWORK_SYNC_REQs (if any). */ GLOBAL void cs_decrement_bfc (void) { if(alr_data->cs_data.bcch_fail_count < 3) { alr_data->cs_data.bcch_fail_count = 0; alr_data->cs_data.search_mode = SM_WIDE_MODE; } else alr_data->cs_data.bcch_fail_count -= 2; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_set_wideband_sync | +--------------------------------------------------------------------+ PURPOSE : The function sets wide band search mode for further MPHC_NETWORK_SYNC_REQs (if any). */ GLOBAL void cs_set_wideband_sync (void) { alr_data->cs_data.search_mode = SM_WIDE_MODE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_is_in_black_list | +--------------------------------------------------------------------+ PURPOSE : The function checks whether the given carrier is in the Blacklist or not CSI-LLD section: 4.1.3.4.2.1 */ LOCAL BOOL cs_is_in_black_list(U8 region,U16 arfcn) { if((region EQ EUROPEAN_REGION) OR (region EQ AMERICAN_REGION)) { if(alr_data->cs_data.p_power_req->search_mode EQ FULL_SEARCH_MODE) { return FALSE; } return(srv_get_channel((T_LIST*)&alr_data->cs_data.p_power_req->black_list.list[region], arfcn&ARFCN_MASK)); } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_find_inactive_carriers | +--------------------------------------------------------------------+ PURPOSE : 1. Finds all inactive carriers 2. Sets the RxLev of all Blacklisted carriers to less than LOWER_RXLEV_THRESHOLD CSI-LLD Section: 4.1.3.8.2.2.1 CSI-LLD Section: 4.2 */ LOCAL void cs_find_inactive_carriers (T_POWER_MEAS **p_results, U16 p_results_size[2],U8 *std, U8 no_of_attempts, SHORT *min_rxlev) { T_POWER_ARRAY* parray, *last; U16 j, arfcn; U8 i, x; T_MPH_POWER_CNF* mph_power_cnf = alr_data->cs_data.p_power_cnf; TRACE_FUNCTION("cs_find_inactive_carriers ()"); /* Loop through both regions */ for (i=0;i<MAX_REGIONS;i++) { if((p_results_size[i]) AND (p_results[i] NEQ NULL)) { parray = p_results[i]->power_array; for (j=0; j<p_results_size[i];) { arfcn = ARFCN_STD_TO_G23(parray->radio_freq, std[i]); /* Pointer to the Last Power array for a particular region */ last = (p_results[i]->power_array + (p_results_size[i]-1)); get_band_index_from_arfcn(arfcn, x, std[i]); if (parray->accum_power_result < min_rxlev[x]) { /* Inactive carrier */ srv_set_channel((T_LIST*)&mph_power_cnf->inactive_carrier_list.list[i], arfcn&ARFCN_MASK); /* Replace inactive carrier with the last active carrier */ cs_power_array_swap_arfcn(parray,last); /* Decrement the power array size to exclude this carrier */ p_results_size[i]--; } else if(cs_is_in_black_list(i, (U16)(arfcn&ARFCN_MASK))) { /* Carrier is black listed. No need to consider this */ parray->accum_power_result = min_rxlev[x]-1; /* Replace inactive carrier with the last active carrier */ cs_power_array_swap_arfcn(parray,last); /* Decrement the power array size to exclude this carrier */ p_results_size[i]--; } else { j++, parray++; } } /* for size */ } /* if size */ } /* MAX_REGIONS */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_whitelist_handle | +--------------------------------------------------------------------+ PURPOSE : This function puts the White carriers at the top of the MPH_POWER_CNF list CSI-LLD 4.1.3.4.2.7 */ LOCAL U8 cs_add_whitelist_carriers(U16 p_results_size[2], U8 std, U8 no_of_attempts, SHORT *min_rxlev, T_POWER_MEAS *presults, U8 no_of_carriers_per_band[4]) { T_MPH_POWER_CNF* mph_power_cnf = alr_data->cs_data.p_power_cnf; T_MPH_POWER_REQ* mph_power_req = alr_data->cs_data.p_power_req; U8 i_cnf,j, where_to_add = DO_NOT_ADD; U8 region = mph_power_req->white_list.region; U16 i,arfcn, temp_arfcn; U8 temp_rxlev; UBYTE x; T_POWER_ARRAY *parray, *last; TRACE_FUNCTION ("cs_add_whitelist_carriers()"); i_cnf = 0; if((p_results_size[region]) AND (presults NEQ NULL)) { parray = presults->power_array; } else return i_cnf; /* Move the white list carriers to MPH_POWER_CNF array first */ for (i=0; (i<p_results_size[region] AND i_cnf < 32); ) { /* Convert to GSM standard format from L1 format*/ arfcn = ARFCN_STD_TO_G23(parray->radio_freq,std); get_band_index_from_arfcn(arfcn, x, std); if (parray->accum_power_result > (min_rxlev[x] - 1)) { if(srv_get_channel((T_LIST*)&mph_power_req->white_list.list, arfcn&ARFCN_MASK)) { /* Channel is present in white list. Add this to top of MPH_POWER_CNF */ arfcn = STD_ADD_TO_ARFCN(arfcn, std); /* US_BIT should be used to differentiate an US frequency channel. */ switch (std) { case STD_1900: case STD_850: case STD_DUAL_US: arfcn |= US_BIT; break; default: break; } where_to_add = cs_restrict_max_carriers_per_band(arfcn&ARFCN_MASK, std, no_of_carriers_per_band, p_results_size, x); if(where_to_add NEQ DO_NOT_ADD) { /* White list carriers are always added at the top */ mph_power_cnf->arfcn[i_cnf] = arfcn; mph_power_cnf->rx_lev[i_cnf] = (U8)(parray->accum_power_result/no_of_attempts); i_cnf++; } else { TRACE_EVENT_P2("[WL] [DO_NOT_ADD] [%d] : [%c]", arfcn&ARFCN_MASK, (region ? 'A' :'E')); } /* Exclude this carrier */ parray->accum_power_result = min_rxlev[x]-1; last = presults->power_array + (p_results_size[region] - 1); /* Swapping the current carrier with the last carrier */ cs_power_array_swap_arfcn(parray, last); /* Decrement the power array counter to exclude the above carrier */ p_results_size[region]--; } /* Present in White List */ else { i++; parray++; } } /* Active Carrier */ else { TRACE_EVENT_P2("[WL] [IA] [%d] : [%c]", parray->radio_freq, (region ? 'A' :'E')); i++; parray++; } } /* i < max */ /* Assign the total Number of white list channels */ mph_power_cnf->num_of_white_list_chan = i_cnf; TRACE_EVENT_P1("[WL] no. of channels : %d ",mph_power_cnf->num_of_white_list_chan); /* * Sort the white list carriers added to power_cnf array on the * basis of their field strength */ for(i=0; i < i_cnf; i++) { for(j=i+1; j<i_cnf; j++) { if(mph_power_cnf->rx_lev[i] < mph_power_cnf->rx_lev[j]) { temp_rxlev = mph_power_cnf->rx_lev[i]; temp_arfcn = mph_power_cnf->arfcn[i]; mph_power_cnf->rx_lev[i] = mph_power_cnf->rx_lev[j]; mph_power_cnf->arfcn[i] = mph_power_cnf->arfcn[j]; mph_power_cnf->rx_lev[j] = temp_rxlev; mph_power_cnf->arfcn[j] = temp_arfcn; } } } return (i_cnf); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : | | cs_restrict_max_carriers_per_band | +--------------------------------------------------------------------+ PURPOSE : This function is to handle the Multiple Frequency Bands in a Region. Will help to add the minimum(40) carriers per band on top of the power cnf and the remaining(40 to 60) carriers will be added in at the end (Below the Normal (40) carriers of all band). CSI-LLD : */ U8 cs_restrict_max_carriers_per_band (U16 arfcn, U8 std, U8 no_of_carriers_per_band[4], U16 p_results_size[2], UBYTE x) { T_POWER_MEAS *presults; T_POWER_ARRAY *parray, *last; U16 i; U8 index = 0xff,just_reached_the_maximum=FALSE; U8 min_rxlev, region, where_to_add = DO_NOT_ADD; min_rxlev = IS_EXT_MEAS_RUNNING ? (SHRT_MIN+1) : alr_data->cs_data.p_power_req->lower_rxlevel_threshold[x]; switch(std) { case STD_900 : case STD_DUAL : case STD_EGSM : case STD_DUAL_EGSM : case STD_1800 : if(INRANGE (CHANNEL_0, arfcn, HIGH_CHANNEL_900) OR INRANGE(LOW_CHANNEL_EGSM, arfcn, HIGH_CHANNEL_EGSM)) { index = 0; } else if(INRANGE (LOW_CHANNEL_1800, arfcn, HIGH_CHANNEL_1800)) { index = 1; } else { TRACE_ERROR("[European]Invalid Carrier"); return DO_NOT_ADD; } region = EUROPEAN_REGION; break; case STD_DUAL_US : case STD_850 : case STD_1900 : if(INRANGE (LOW_CHANNEL_850, arfcn, HIGH_CHANNEL_850)) { index = 2; } else if(INRANGE (LOW_CHANNEL_1900, arfcn, HIGH_CHANNEL_1900)) { index = 3; } else { TRACE_ERROR("[American]Invalid Carrier"); return DO_NOT_ADD; } region = AMERICAN_REGION; break; } /* end switch */ if(index < 4) { if(no_of_carriers_per_band[index] < MIN_CHANNELS_PER_BAND) { /* Increment counter for corresponding band */ no_of_carriers_per_band[index]++; if(no_of_carriers_per_band[index] EQ MIN_CHANNELS_PER_BAND) { TRACE_EVENT_P5( "[%d]Band, 40 channels added (B_GSM_EGSM%d, B_1800:%d, B_850:%d, B_1900:%d)", index, no_of_carriers_per_band[0], no_of_carriers_per_band[1], no_of_carriers_per_band[2], no_of_carriers_per_band[3]); } /* Add at the top of MPH_POWER_CNF list */ where_to_add = ADD_AT_THE_TOP; } else if(no_of_carriers_per_band[index] <= MAX_CHANNELS_PER_BAND) { /* Increment counter for corresponding band */ no_of_carriers_per_band[index]++; /* Add at the bottom of MPH_POWER_CNF list */ where_to_add = ADD_AT_THE_BOTTOM; if(no_of_carriers_per_band[index] EQ (MAX_CHANNELS_PER_BAND + 1)) { TRACE_EVENT_P5( "[%d]Band, 60 channels added (B_GSM_EGSM%d, B_1800:%d, B_850:%d, B_1900:%d)", index, no_of_carriers_per_band[0], no_of_carriers_per_band[1], no_of_carriers_per_band[2], no_of_carriers_per_band[3]); just_reached_the_maximum = TRUE; where_to_add = REACHED_THE_MAXIMUM; } } else { where_to_add = DO_NOT_ADD; } } else { TRACE_ERROR("Unknown Band Index"); return DO_NOT_ADD; } /* if index < 4 */ /* When Max number of channels(60) are added for a particular band, * all the remaining carriers belonging to that band are excluded from * further sorting */ if(just_reached_the_maximum) { BOOL exclude; U16 l3_arfcn; if (region EQ AMERICAN_REGION)/*lint !e644 region may not have been initialized */ { /* American band */ presults = alr_data->cs_data.p_results2; } else { /* European band */ presults = alr_data->cs_data.p_results1; } TRACE_EVENT_P3("[%d]Index, E:%d A:%d", index, p_results_size[0], p_results_size[1]); if((presults NEQ NULL) AND (p_results_size[region]))/*lint !e644 region may not have been initialized */ { for(i=0, parray = presults->power_array; i < p_results_size[region];) { exclude = FALSE; l3_arfcn = ARFCN_STD_TO_G23(parray->radio_freq, std); switch(index) { case 0 : if(INRANGE (LOW_CHANNEL_900, l3_arfcn, HIGH_CHANNEL_900) OR INRANGE(LOW_CHANNEL_EGSM, l3_arfcn, HIGH_CHANNEL_EGSM)) { exclude = TRUE; } break; case 1: if(INRANGE (LOW_CHANNEL_1800, l3_arfcn, HIGH_CHANNEL_1800)) { exclude = TRUE; } break; case 2 : if(INRANGE (LOW_CHANNEL_850, l3_arfcn, HIGH_CHANNEL_850)) { exclude = TRUE; } break; case 3: if(INRANGE (LOW_CHANNEL_1900, l3_arfcn, HIGH_CHANNEL_1900)) { exclude = TRUE; } break; default : break; } /* end switch */ if(exclude) { last = presults->power_array + (p_results_size[region] - 1); /*lint !e644 region may not have been initialized */ /* Exclude this carrier */ parray->accum_power_result = min_rxlev-1; /* Swaping the Current carrier with the last carrier */ cs_power_array_swap_arfcn(parray, last); /* Decrement the power array counter to exclude the above carrier */ p_results_size[region]--; } else { parray++; i++; } } /* power array size */ } /* end if(just_reached_the_maximum */ } /* presults NEQ NULL */ return where_to_add; } #endif /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : cs_reorder_the_extra_carriers | +--------------------------------------------------------------------+ PURPOSE : Extra Carriers (More than 40 and below 60) are stored at the bottom of the MPH_POWER_CNF. But these are stored in ascending order (if you see from the TOP). This needs to be reordered (means Strongest carrier should go to top). */ LOCAL void cs_reorder_the_extra_carriers(U8 extra_cnf) { T_MPH_POWER_CNF* mph_power_cnf = alr_data->cs_data.p_power_cnf; U8 i,j,count,max_count,temp_rxlevel; U16 temp_arfcn; TRACE_FUNCTION("cs_reorder_the_extra_carriers"); i = MAX_CHANNELS - 1; j = MAX_CHANNELS - extra_cnf; max_count = extra_cnf/2; for(count=0; count < max_count; i--, j++, count++) { temp_arfcn = mph_power_cnf->arfcn[i]; temp_rxlevel = mph_power_cnf->rx_lev[i]; mph_power_cnf->arfcn[i] = mph_power_cnf->arfcn[j]; mph_power_cnf->rx_lev[i] = mph_power_cnf->rx_lev[j]; mph_power_cnf->arfcn[j] = temp_arfcn; mph_power_cnf->rx_lev[j] = temp_rxlevel; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_CS | | STATE : code ROUTINE : | | cs_move_extra_carriers | +--------------------------------------------------------------------+ PURPOSE : Extra Carriers (More than 40 and below 60) are stored at the bottom of the MPH_POWER_CNF. These carriers needs to be rearranged below the normal (Strangest 40 Carriers) carriers */ LOCAL void cs_move_extra_carriers(U8 i_cnf, U8 extra_cnf) { T_MPH_POWER_CNF* mph_power_cnf = alr_data->cs_data.p_power_cnf; /* * Add the extra carriers below Normal carrier */ TRACE_FUNCTION("cs_move_extra_carriers"); /* Move the extra carriers below the Normal carriers */ memmove (&mph_power_cnf->arfcn[i_cnf], &mph_power_cnf->arfcn[MAX_CHANNELS - extra_cnf], sizeof (mph_power_cnf->arfcn[0]) * (extra_cnf)); memmove (&mph_power_cnf->rx_lev[i_cnf], &mph_power_cnf->rx_lev[MAX_CHANNELS - extra_cnf], sizeof (mph_power_cnf->rx_lev[0]) * (extra_cnf)); }