FreeCalypso > hg > fc-selenite
view src/g23m-gsm/alr2/alr_nc.c @ 86:425ab6d987f3
src/libsys: pieced together from Citrine
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 20 Jul 2018 20:36:19 +0000 |
parents | b4c81ea2d291 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GSM-PS | Modul : ALR_NC +----------------------------------------------------------------------------- | 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 Idle_Neighbour_Cells. +----------------------------------------------------------------------------- */ #ifndef ALR_NC_C #define ALR_NC_C #define ENTITY_PL /*==== INCLUDES ===================================================*/ #include <string.h> #include <stdlib.h> #include <limits.h> #include <ctype.h> #include "typedefs.h" #include "message.h" #include "ccdapi.h" #include "vsi.h" #include "custom.h" #include "gsm.h" #include "prim.h" #include "cnf_alr.h" #include "mon_alr.h" #include "pei.h" #include "tok.h" #include "pcm.h" #ifdef GPRS #include "alr_gprs.h" #endif #if !defined(NTRACE) #define TRACING #endif /* !TRACING */ #include "alr.h" #include "alr_em.h" #if !defined(NTRACE) && defined(TRACING) LOCAL const char *nc_get_nc_state_str(UBYTE status); LOCAL const char * const alr_nc_state_trc[18] = { "INACT", "IDLE", "RD_BCCH", "FB_SB_SYNC", "FB_SB_FAIL", "RD_FB_SB", "RD_SB", "IDLE_SYNC", "EXCL", "FB_SB_SYNC_RR", "RD_SB_BCCH", "RD_BCCH_P", "RD_FB_SB_P", "RD_SB_P", "RD_SB_BCCH_P", "RD_BCCH_RR", "RD_BCCH_P_RR", "???"}; #endif /* !NTRACE && TRACING */ LOCAL const UBYTE unc_values[] = { 2, 4, 8, 12, 16, 22, 30, NOT_PRESENT_8BIT }; /*==== EXPORT =====================================================*/ /*==== PRIVAT =====================================================*/ LOCAL void nc_update_ba_list (USHORT serving_cell, T_MPH_NEIGHBOURCELL_REQ * ncell_list); LOCAL UBYTE nc_remove_channel_from_ba_list (USHORT index); LOCAL UBYTE nc_is_in_ncell_list (USHORT channel, T_MPH_NEIGHBOURCELL_REQ * ncell_list); LOCAL void nc_process_status (void); LOCAL void nc_process_status_sync (void); LOCAL void nc_process_status_last_bsic (void); LOCAL void nc_process_status_bcch (void); LOCAL BOOL nc_ncell_in_plmn_permitted (UBYTE bsic); LOCAL void nc_find_cells (USHORT * c_found, USHORT max, UBYTE limitation, UBYTE min_rxlev); LOCAL void nc_store_rxlev (T_MPHC_RXLEV_PERIODIC_IND * report); LOCAL void nc_rank_ncells (void); LOCAL void nc_check_status (UBYTE start_list); LOCAL void nc_build_rr_report_dedi (T_MPH_MEASUREMENT_IND * rr_report); LOCAL void nc_store_dedicated (T_MPHC_MEAS_REPORT * report); LOCAL UBYTE nc_convert_quality (USHORT errors, USHORT total); LOCAL void nc_store_bcch (T_MPHC_DATA_IND * data_ind, USHORT index, UBYTE which); LOCAL void nc_stop_bcch (USHORT index, UBYTE new_status); LOCAL void nc_stop_sync (USHORT index, UBYTE new_status); LOCAL void nc_clean_store_bcch (USHORT index); LOCAL UBYTE nc_check_bsic (USHORT index, UBYTE bsic); #if 0 #if !defined(NTRACE) && defined(TRACING) LOCAL UBYTE nc_get_status (USHORT index); #endif /* !NTRACE && TRACING */ #endif /* 0|1 */ LOCAL void nc_restart_bcch (USHORT index); LOCAL void nc_set_fb_sb_sync_initial (USHORT index); LOCAL void nc_set_fb_sb_failed (USHORT index, UBYTE c_sync); LOCAL UBYTE nc_sys_info_78_required (USHORT index); LOCAL void nc_sync_failed_attempt (USHORT index); LOCAL void nc_sync_failed_attempt_dedicated(USHORT index); LOCAL void nc_build_rr_report (T_MPH_MEASUREMENT_IND* rr_report); LOCAL void nc_release_bcch (void); LOCAL void nc_find_list_cells (void); LOCAL void nc_ncell_list_req (void); LOCAL void nc_start_eotd_confirm (void); LOCAL void nc_process_pos_req (T_MPH_NCELL_POS_REQ* pos_req); LOCAL void nc_check_sync_ind_eotd (T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT arfcn); LOCAL void nc_store_eotd (T_eotd_sc_res* p_res, T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT arfcn); LOCAL void nc_sync_ind_last_bsic_req (T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT index, USHORT arfcn, UBYTE bsic); LOCAL void nc_sync_ind_ncell (T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT index, USHORT arfcn, UBYTE bsic); LOCAL void nc_clear_last_bsic (void); #if 0 Symbol 'nc_stop_all_bcch(void)' 'nc_stop_all_sync(void)' and not referenced at the moment LOCAL void nc_stop_all_bcch (void); LOCAL void nc_stop_all_sync (void); #endif /* 0|1 */ LOCAL void nc_stop_all (void); LOCAL void nc_stop_all_inactive (void); LOCAL void nc_stop_if_active (USHORT i); LOCAL void nc_ncell_list_req_pos (T_ncell_list* p_ncell_list, T_ncell_eotd* asd_cell, USHORT arfcn); LOCAL void nc_get_timing_eotd (T_ncell_list* p_ncell_list, T_ncell_eotd* asd_cell); LOCAL BOOL nc_is_sync (T_NC * p_ncell); LOCAL void nc_build_sync_req (USHORT index); LOCAL void nc_init_pos_ind (USHORT req_id); LOCAL void nc_enable_conf (void); LOCAL void nc_disable_conf (BOOL bFree); LOCAL void nc_start_ncell_confirm (void); LOCAL void nc_handle_new_strong_cells (void); LOCAL void nc_check_new_strong_cell (USHORT index, UBYTE o_1of6, UBYTE rxlev); #ifdef GPRS LOCAL void nc_rxlev_sc_req (UBYTE rxlev); LOCAL void nc_inform_grr_of_ncell (USHORT index, UBYTE type); LOCAL void remove_ncell_and_inform_grr (USHORT index); LOCAL void nc_sync_failed_gprs (USHORT index); LOCAL void nc_check_bsic_pbcch(T_MPH_NEIGHBOURCELL_REQ* ncell_list); LOCAL void nc_process_status_sync_gprs(void); #endif /* #ifdef GPRS */ #if defined(_SIMULATION_) LOCAL void trace_nc(void); #endif /* _SIMULATION_ */ LOCAL void nc_start_ncsync (void); /*==== CONSTANTS ==================================================*/ #define MAX_L1_SYNC_CNT 12 #define MAX_L1_BCCH_CNT 6 #define MAX_L1_SYNC_EOTD_CNT 14 #define MAX_RR_NCELL_CNT 6 #define ONLY_BCC 7 #define ONLY_BSIC 63 #define NC_CHECK_OK 0 #define NC_CHECK_NCC_FAILED 1 #define NC_CHECK_BSIC_CHANGED 2 #define CHECK_FOR_ACQUIRE_AND_BCCH_AND_FAIL 0 #define CHECK_FOR_CONFIRM 1 #define DONT_FREE_POS_IND 0 #define FREE_POS_IND 1 /* * Counter to realize a time interval of 10sec in terms of Control Multiframe * Idle state : 42 * 51 * 4.615ms = 9885ms * Dedicated State : 42 * 104/2 * 4.615ms = 10079ms */ #define TEN_SECONDS_NCSYNC 42 #define TEN_SECONDS 1 #define TWENTY_SECONDS 2 #define THIRTY_SECONDS 3 #define FIVE_MINUTES 30 #define C_INVALID_SYNC (THIRTY_SECONDS+1) /* +2 for rounding BCCH reading to confirmation boundary */ #define C_INVALID_BCCH (FIVE_MINUTES+2+1) #ifdef GPRS #define GRR_SB_FOUND (MPH_BSIC_UNKNOWN+1) #define GRR_SB_NOT_FOUND NOT_PRESENT_8BIT #define GRR_SB_UNKNOWN MPH_BSIC_UNKNOWN #endif /*==== VARIABLES ==================================================*/ /*==== FUNCTIONS ==================================================*/ #if defined (WIN32) && !defined (_SIMULATION_) #define _SIMULATION_ #endif #if defined (_SIMULATION_) #define TRACING #endif /* _SIMULATION_ */ /* * some traces */ #if defined (TRACING) #define ALR_TRACE_NC(a) ALR_TRACE(a) #define ALR_TRACE_NC_CNT(a,b) TRACE_EVENT_P2 ("[%4u] c_sync %d", \ ARFCN_TO_G23(a)&ARFCN_MASK, b) #define ALR_TRACE_NC_BSIC_CNF(a) TRACE_EVENT_P1 ("[%4u] NC BSIC CNF passed", \ ARFCN_TO_G23(a)&ARFCN_MASK) #define ALR_TRACE_NC_SB_FAILED(a) TRACE_EVENT_P1 ("[%4u] NCELL SB IND failed", \ ARFCN_TO_G23(a)&ARFCN_MASK) #define ALR_TRACE_NC_BSIC_REQ(a) TRACE_EVENT_P4 ("[%4u] NC BSIC REQ %d %d %d", \ a&ARFCN_MASK, GET_STATE (STATE_NC), \ alr_data->nc_data.cell[LAST_BSIC_REQ].status, \ alr_data->nc_data.c_bcch_req) #define ALR_TRACE_NC_BCCH_OK(f,m) TRACE_EVENT_P2 ("[%4u] NCELL BCCH IND passed msg:%d", \ f&ARFCN_MASK,m) #define ALR_TRACE_NC_SB_IND_PASSED(f) TRACE_EVENT_P1 ("[%4u] NCELL SB IND passed", \ f&ARFCN_MASK) #define ALR_TRACE_NC_RESELECT(a) TRACE_EVENT_P1 ("[%4u] start reselect", a&ARFCN_MASK) #define ALR_TRACE_NC_FN_TA(_i,f,t) TRACE_EVENT_P3 ("i %d, fn %d, ta %d ", _i, f, t) #if 0 #define GET_NC_STATE(i) nc_get_status(i) #endif /* 0|1 */ #if defined(_SIMULATION_) #define ALR_TRACE_ALL_NC() trace_nc() #else /* _SIMULATION_ */ #define ALR_TRACE_ALL_NC() #endif /* _SIMULATION_ */ #else /* TRACING */ #define ALR_TRACE_NC(a) #define ALR_TRACE_NC_CNT(a,b) #define ALR_TRACE_NC_BSIC_CNF(a) #define ALR_TRACE_NC_SB_FAILED(a) #define ALR_TRACE_NC_BSIC_REQ(a) #define ALR_TRACE_NC_BCCH_OK(f,m) #define ALR_TRACE_NC_SB_IND_PASSED(f) #define ALR_TRACE_NC_RESELECT(a) #define ALR_TRACE_NC_FN_TA(i,f,t) #define GET_NC_STATE(i) alr_data->nc_data.cell[i].status #define ALR_TRACE_ALL_NC() #undef TRACE_EVENT #undef TRACE_EVENT_P1 #undef TRACE_EVENT_P2 #undef TRACE_EVENT_P3 #undef TRACE_EVENT_P4 #undef TRACE_EVENT_P5 #undef TRACE_EVENT_P6 #undef TRACE_EVENT_P7 #undef TRACE_EVENT_P8 #undef TRACE_EVENT_P9 #define TRACE_EVENT(s) #define TRACE_EVENT_P1(s,a) #define TRACE_EVENT_P2(s,a,b) #define TRACE_EVENT_P3(s,a,b,c) #define TRACE_EVENT_P4(s,a,b,c,d) #define TRACE_EVENT_P5(s,a,b,c,d,e) #define TRACE_EVENT_P6(s,a,b,c,d,e,f) #define TRACE_EVENT_P7(s,a,b,c,d,e,f,g) #define TRACE_EVENT_P8(s,a,b,c,d,e,f,g,h) #define TRACE_EVENT_P9(s,a,b,c,d,e,f,g,h,i) #endif /* TRACING */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_init | +--------------------------------------------------------------------+ PURPOSE : Initialize Idle Neighbour Cell Process. */ GLOBAL void nc_init (void) { nc_stop_all(); alr_data->nc_data.c_ba_arfcn = 0; alr_data->nc_data.ba_id = ALR_BA_LOW; alr_data->nc_data.sc_included = FALSE; alr_data->nc_data.cell[LAST_BSIC_REQ].status = IDLE; alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; alr_data->nc_data.c_reports = (UBYTE)-1; alr_data->nc_data.cr_cell.ba_arfcn = NOT_PRESENT_16BIT; alr_data->nc_data.tim_state = NC_TIM_STOPPED; alr_data->nc_data.c_nc_timer = 0; if (alr_data->nc_data.ppos_ind NEQ NULL) { PFREE(alr_data->nc_data.ppos_ind); alr_data->nc_data.ppos_ind = NULL; } if (alr_data->nc_data.ppos_req NEQ NULL) { PFREE(alr_data->nc_data.ppos_req); alr_data->nc_data.ppos_req = NULL; } /* Initialize the counter for realizing 10sec timer value */ alr_data->nc_data.c_ncsync_tim = 0; alr_data->nc_data.ncsync_start_tim = 0; SET_STATE(STATE_NC_PROC, NC_ACQUIRE); SET_STATE(STATE_NC, NC_NULL); } #ifdef GPRS /* +----------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_GPRS | | STATE : code ROUTINE : nc_start_pbcch| +----------------------------------------------------------------------+ PURPOSE :Checks whether pbcch is available and sets a relevant state. */ GLOBAL void nc_start_pbcch(void) { if(alr_data->gprs_data.ptm AND alr_data->gprs_data.pbcch) { SET_STATE(STATE_NC, NC_PTM_PBCCH); } else if(alr_data->gprs_data.pbcch) { SET_STATE(STATE_NC, NC_PIM_PBCCH); } nc_enable_conf(); nc_process_status(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_GPRS | | STATE : code ROUTINE : gprs_check_bsic_pbcch | +--------------------------------------------------------------------+ PURPOSE : */ LOCAL void nc_check_bsic_pbcch(T_MPH_NEIGHBOURCELL_REQ* ncell_list) { TRACE_EVENT("gprs_alr_check_bsic_pbcch"); if(!alr_data->gprs_data.pbcch) return; if(ncell_list->sync_only EQ SYNC_LIST) { USHORT n_rr; /* index of RR neighbor cell list */ USHORT n_alr; /* index of ALR neighbor cell list */ UBYTE last_alr; /* last index of ALR neighbor cell list */ USHORT arfcn; TRACE_EVENT("pbcch/check bsic"); /* * remove all channels which are not longer member of the * neighbour cell list. */ last_alr = alr_data->nc_data.c_ba_arfcn; /* current last index */ for (n_alr = 0; n_alr < last_alr; n_alr++) { arfcn = alr_data->nc_data.cell[n_alr].ba_arfcn; if (!nc_is_in_ncell_list (arfcn, ncell_list)) /* AND (arfcn NEQ alr_data->serving_cell))*/ { switch(alr_data->nc_data.cell[n_alr].status) { case READ_FB_SB: case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB: case READ_SB_BCCH: /* in case we come from BCCH */ case INACTIVE: /* in case we returned from DEDIC */ case IDLE: /* in case we returned from DEDIC */ case EXCLUDED: /* in case we returned from DEDIC */ TRACE_EVENT_P1("rem cell i%d",n_alr); remove_ncell_and_inform_grr(n_alr); last_alr = alr_data->nc_data.c_ba_arfcn; n_alr--; break; case FB_SB_SYNC_RR_NOT_INFORMED: case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH: case FB_SB_SYNC: case IDLE_SYNC: case FB_SB_FAILED: /*state change will be done with check_status*/ TRACE_EVENT_P1("i%d reset 1o6", n_alr); alr_data->nc_data.cell[n_alr].one_of_six = FALSE; alr_data->nc_data.cell[n_alr].one_of_twelve = FALSE; break; default: TRACE_EVENT_P3("i%d,arfcn:%d illegal status %d",n_alr, alr_data->nc_data.cell[n_alr].ba_arfcn, alr_data->nc_data.cell[n_alr].status); break; } } else { /* ncell is in both lists */ switch(alr_data->nc_data.cell[n_alr].status) { case READ_FB_SB: // case READ_FB_SB_PENDING: //case READ_SB_PENDING: case READ_SB: break; case READ_SB_BCCH: /* in case we come from BCCH */ nc_set_status(n_alr, READ_SB); break; case INACTIVE: /* in case we returned from DEDIC */ case IDLE: /* in case we returned from DEDIC */ case EXCLUDED: /* in case we returned from DEDIC */ nc_set_status (n_alr, INACTIVE); /* ALR does not receive measurements */ /* set them to idle */ nc_set_status (n_alr, IDLE); /* and set it to one_of_six , the rest is done by check_status */ nc_set_status(n_alr, READ_FB_SB); break; case FB_SB_SYNC_RR_NOT_INFORMED: case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH: nc_set_status(n_alr, FB_SB_SYNC); break; default: break; } alr_data->nc_data.cell[n_alr].one_of_six = FALSE; alr_data->nc_data.cell[n_alr].one_of_twelve = TRUE; } } /* * add all new channels. */ for (n_rr = 0; (n_rr < MAX_NEIGHBOURCELLS) AND (last_alr < BA_LIST_SIZE-1); n_rr++) { arfcn = ncell_list->arfcn[n_rr]; if (arfcn EQ NOT_PRESENT_16BIT) break; /* no more entries in the RR ncell_list */ n_alr = nc_get_index (arfcn); if (((n_alr EQ NOT_PRESENT_16BIT) OR (n_alr EQ LAST_BSIC_REQ)) AND (arfcn NEQ alr_data->serving_cell)) { T_NC* pcell = &alr_data->nc_data.cell[last_alr]; #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] add", last_alr, arfcn); #endif /* TRACING */ pcell->ba_arfcn = arfcn; nc_set_status (last_alr, INACTIVE); /* ALR does not receive measurements */ /* set them to idle */ nc_set_status (last_alr, IDLE); /* and set it to one_of_six , the rest is done by check_status */ alr_data->nc_data.cell[last_alr].one_of_six = FALSE; alr_data->nc_data.cell[last_alr].one_of_twelve = TRUE; alr_data->nc_data.cell[last_alr].ba_status = IN_BA; last_alr++; /* increment last index */ } } alr_data->nc_data.c_ba_arfcn = last_alr; /* store new last index */ ALR_TRACE_ALL_NC (); { UBYTE six=0; last_alr = alr_data->nc_data.c_ba_arfcn; /* current last index */ for (n_alr = 0; n_alr < last_alr; n_alr++) { six += alr_data->nc_data.cell[n_alr].one_of_six; } /*XXX change this to handle 12 ncells */ if(six > 6) { TRACE_ERROR("more then six candidates!"); } } #if 0 /*only for easing debugging */ /* * Reorder the entries. The goal is that the propably strongest neigbour * cells * are measured in the first measurement period of a subsequent * MPHC_RXLEV_PERIODIC_REQ/IND. The appropriate arfcn's are the first * ones in * ncell_list->arfcn */ { T_NC temp, *prr, *palr; for (n_rr = 0; n_rr < 7; n_rr++) { if(ncell_list->arfcn[n_rr] NEQ NOT_PRESENT_16BIT) n_alr = nc_get_index (ncell_list->arfcn[n_rr]); else break; if ( ((n_alr NEQ NOT_PRESENT_16BIT) OR (n_alr NEQ LAST_BSIC_REQ)) AND n_rr NEQ n_alr) { palr = &(alr_data->nc_data.cell[n_alr]); prr = &(alr_data->nc_data.cell[n_rr]); memcpy(&temp, palr, sizeof(T_NC)); memcpy(palr, prr, sizeof(T_NC)); memcpy(prr, &temp, sizeof(T_NC)); /*TRACE_EVENT_P4("reordered NC%u[%u] and NC%u[%u]", n_rr, ncell_list->arfcn[n_rr], n_alr, ncell_list->arfcn[n_alr]);*/ } } } #endif nc_check_status(CHECK_FOR_ACQUIRE_AND_BCCH_AND_FAIL); if(alr_data->nc_sync_with_grr) { TRACE_EVENT("sync_with_grr"); last_alr = alr_data->nc_data.c_ba_arfcn; /* current last index */ for (n_alr = 0; n_alr < last_alr; n_alr++) { switch(alr_data->nc_data.cell[n_alr].status) { case IDLE_SYNC: case FB_SB_SYNC: case READ_SB: case READ_SB_PENDING: case READ_FB_SB_PENDING: TRACE_EVENT_P1("sync %d",alr_data->nc_data.cell[n_alr].ba_arfcn); nc_inform_grr_of_ncell(n_alr, GRR_SB_FOUND); break; case FB_SB_FAILED: case EXCLUDED: case INACTIVE: case IDLE: TRACE_EVENT_P1("sync %d",alr_data->nc_data.cell[n_alr].ba_arfcn); nc_inform_grr_of_ncell(n_alr, GRR_SB_NOT_FOUND); break; /* READ_FB_SB ->the cell will be synchronized next and a result will be returnded anyway */ default: break; } } alr_data->nc_sync_with_grr=FALSE; } switch(GET_STATE(STATE_NC)) { case NC_PIM_PBCCH: case NC_PTM_PBCCH: nc_process_status(); break; default: break; } } else if(ncell_list->sync_only EQ RECONFIRM_SYNC_LIST) { nc_ncsync_tim_expiry(); } } #endif /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop | +--------------------------------------------------------------------+ PURPOSE : stop the neighbourcell process. Is called by main process if a recovery with power measurements is started. */ GLOBAL void nc_stop (void) { /* * clean or neighbourcells of the BA and LAST_BSIC_REQ list if needed */ nc_stop_all_inactive(); /* * initialize neighbourcell process and stops timer */ nc_init(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_all_inactive | +--------------------------------------------------------------------+ PURPOSE : This stops all activities to bring a channel to state NC_NULL. */ LOCAL void nc_stop_all_inactive (void) { UBYTE i, stopped_sync=0, stopped_bcch=0; /* * depending on the current status */ for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB_BCCH_PENDING: /* * stop the current running request for synchronisation in layer 1. */ nc_set_status (i, INACTIVE); stopped_sync++; break; case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: /* * stop the current running request for BCCH reading in layer 1. * If sys info 4 is already stored, but sys info 7 or 8 is requested * clear also a stored BCCH message. */ nc_set_status (i, INACTIVE); stopped_bcch++; break; default: /* * sys infos are stored, but RR is still not informed. * Then clean the stored message */ nc_set_status (i, INACTIVE); break; } } switch (alr_data->nc_data.cell[LAST_BSIC_REQ].status) { case READ_FB_SB_PENDING: nc_set_status (LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; stopped_sync++; break; case READ_BCCH_PENDING: nc_set_status (LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; stopped_bcch++; break; } /*send to L1*/ if (stopped_sync > 0) { /* stop all synchronizations */ PALLOC (stop_req, MPHC_STOP_NCELL_SYNC_REQ); stop_req->radio_freq_array_size = MAX_L1_SYNC_CNT; PSENDX(L1, stop_req); } if (stopped_bcch > 0) { /* stop all bcch */ PALLOC (stop_req, MPHC_STOP_NCELL_BCCH_REQ); stop_req->radio_freq_array_size = MAX_L1_BCCH_CNT; PSENDX(L1, stop_req); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_all | +--------------------------------------------------------------------+ PURPOSE : This stops all activities to bring a channel its corresping READ_ state. */ LOCAL void nc_stop_all (void) { UBYTE i, stopped_sync=0, stopped_bcch=0; /* * depending on the current status */ for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case READ_FB_SB_PENDING: nc_set_status (i, READ_FB_SB); stopped_sync++; break; case READ_SB_PENDING: nc_set_status (i, READ_SB); stopped_sync++; break; case READ_SB_BCCH_PENDING: nc_set_status (i, READ_SB_BCCH); stopped_sync++; break; case READ_BCCH_PENDING: nc_set_status (i, READ_BCCH); stopped_bcch++; break; case READ_BCCH_PENDING_RR_NOT_INFORMED: nc_set_status (i, READ_BCCH_RR_NOT_INFORMED); stopped_bcch++; break; case FB_SB_SYNC_RR_NOT_INFORMED: nc_set_status (i, READ_BCCH_RR_NOT_INFORMED); break; } } switch (alr_data->nc_data.cell[LAST_BSIC_REQ].status) { case READ_FB_SB_PENDING: nc_set_status (LAST_BSIC_REQ, READ_FB_SB); stopped_sync++; break; case READ_BCCH_PENDING: nc_set_status (LAST_BSIC_REQ, READ_BCCH); stopped_bcch++; break; } /*send to L1*/ if ( stopped_sync > 0 OR alr_data->nc_data.c_sync_req > 0 OR (alr_data->nc_data.eotd_avail AND GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM)) { /* stop all synchronizations if waiting for any NC synchronization (or 2nd SC in EOTD case) */ PALLOC (stop_req, MPHC_STOP_NCELL_SYNC_REQ); stop_req->radio_freq_array_size = MAX_L1_SYNC_CNT; PSENDX(L1, stop_req); alr_data->nc_data.c_sync_req=0; if (alr_data->nc_data.eotd_avail) SET_STATE(STATE_NC_PROC, NC_ACQUIRE); } if(stopped_bcch > 0) { /* stop all bcch */ PALLOC (stop_req, MPHC_STOP_NCELL_BCCH_REQ); stop_req->radio_freq_array_size = MAX_L1_BCCH_CNT; PSENDX(L1, stop_req); alr_data->nc_data.c_bcch_req=0; } } #if 0 Symbol 'nc_stop_all_bcch(void)' not referenced at the moment /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_all_sync | +--------------------------------------------------------------------+ PURPOSE : This stops all sync activities. */ LOCAL void nc_stop_all_sync (void) { UBYTE i, stopped_sync=0; /* * depending on the current status */ for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case READ_FB_SB_PENDING: nc_set_status (i, READ_FB_SB); stopped_sync++; break; case READ_SB_PENDING: nc_set_status (i, READ_SB); stopped_sync++; break; case READ_SB_BCCH_PENDING: nc_set_status (i, READ_SB_BCCH); stopped_sync++; break; } } switch (alr_data->nc_data.cell[LAST_BSIC_REQ].status) { case READ_FB_SB_PENDING: nc_set_status (LAST_BSIC_REQ, READ_FB_SB); stopped_sync++; break; } /*send to L1*/ if (stopped_sync > 0) { /* stop all synchronizations */ PALLOC (stop_req, MPHC_STOP_NCELL_SYNC_REQ); stop_req->radio_freq_array_size = MAX_L1_SYNC_CNT; PSENDX(L1, stop_req); alr_data->nc_data.c_sync_req=0; } } #endif /* 0|1 */ #if 0 Symbol 'nc_stop_all_bcch(void)' not referenced at the moment /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_all_bcch | +--------------------------------------------------------------------+ PURPOSE : This stops all activities to bring a channel to state NC_NULL. */ LOCAL void nc_stop_all_bcch (void) { UBYTE i, stopped_bcch=0; /* * depending on the current status */ for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case READ_BCCH_PENDING_RR_NOT_INFORMED: nc_set_status (i, READ_BCCH_RR_NOT_INFORMED); stopped_bcch++; break; case READ_BCCH_PENDING: nc_set_status (i, READ_BCCH); stopped_bcch++; break; } } switch (alr_data->nc_data.cell[LAST_BSIC_REQ].status) { case READ_BCCH_PENDING: nc_set_status (LAST_BSIC_REQ, READ_BCCH); stopped_bcch++; break; } /*send to L1*/ if (stopped_bcch > 0) { /* stop all bcch */ PALLOC (stop_req, MPHC_STOP_NCELL_BCCH_REQ); stop_req->radio_freq_array_size = MAX_L1_BCCH_CNT; PSENDX(L1, stop_req); alr_data->nc_data.c_bcch_req=0; } } #endif /* 0|1 */ LOCAL void nc_clear_last_bsic(void) { switch (alr_data->nc_data.cell[LAST_BSIC_REQ].status) { case READ_BCCH_PENDING: nc_stop_bcch (LAST_BSIC_REQ, IDLE); break; case READ_FB_SB_PENDING: nc_stop_sync (LAST_BSIC_REQ, IDLE); break; } nc_set_status(LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; } LOCAL void nc_stop_if_active(USHORT i) { /* * the requested channel number is member of the BA list. * clear a request to layer 1 if needed. */ switch(alr_data->nc_data.cell[i].status) { case READ_SB_PENDING: nc_stop_sync (i, READ_SB); break; case READ_SB_BCCH_PENDING: nc_stop_sync (i, READ_SB_BCCH); break; case READ_FB_SB_PENDING: nc_stop_sync (i, READ_FB_SB); break; case READ_BCCH_PENDING: nc_stop_bcch (i, READ_BCCH); break; case READ_BCCH_PENDING_RR_NOT_INFORMED: nc_stop_bcch (i, READ_BCCH_RR_NOT_INFORMED); break; default: break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncell_list | +--------------------------------------------------------------------+ PURPOSE : Reception of a new neighbourcell list from RR. */ GLOBAL void nc_ncell_list (T_MPH_NEIGHBOURCELL_REQ * mph_neighbourcell_req) { UBYTE i, j; switch (GET_STATE (STATE_NC)) { case NC_DEDICATED: { UBYTE c_ba_arfcn; PALLOC (upd_dedi, MPHC_UPDATE_BA_LIST); /* * mix new list with old list */ nc_update_ba_list (alr_data->serving_cell, mph_neighbourcell_req); /* * create new list for layer 1 */ c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; for (i = 0, j = 0; i < c_ba_arfcn; i++) { if (alr_data->nc_data.cell[i].ba_status EQ IN_BA) upd_dedi->chan_list.radio_freq[j++] = ARFCN_TO_L1(alr_data->nc_data.cell[i].ba_arfcn); } /* * send new list to layer 1 */ upd_dedi->num_of_chans = j; alr_data->nc_data.ba_id = ALR_ALLOCATE_NEW_BA ( alr_data->nc_data.ba_id ); upd_dedi->ba_id = alr_data->nc_data.ba_id; upd_dedi->pwrc = alr_data->nc_data.pwrc; upd_dedi->dtx_allowed = alr_data->nc_data.dtx; alr_data->nc_data.update = TRUE; ma_nc_update_ba_list (upd_dedi); } break; case NC_CON_EST: /*for PBCCH just update the list, is checked in nc_check_bsic_pbcch */ #ifdef GPRS case NC_PIM_PBCCH: case NC_PTM_PBCCH: nc_check_bsic_pbcch(mph_neighbourcell_req); #endif break; default: /* * idle mode */ ALR_TRACE_NC ("ncell req in idle"); /* * mix new list with old list */ nc_update_ba_list (alr_data->serving_cell, mph_neighbourcell_req); /* * configure layer 1 and start monitoring on new list */ nc_start_monitoring(); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_start_monitoring | +--------------------------------------------------------------------+ PURPOSE : Configure layer 1 with a new list for neighbourcell measurements. */ static const UBYTE NO_OF_REPORTS [8] = { 10, 7, 5, 4, 3, 3, 2, 2 }; static const UBYTE INIT_OF_C_REPORTS [8] = { 5, 5, 2, 2, 1, 1, 0, 0 /* empirical for FTA 20.7, 20.19, for TC 084, 047 */ }; static BOOL first_period = FALSE, first_l1_meas = FALSE; GLOBAL void nc_start_monitoring (void) { USHORT index, prim_index; UBYTE report_idx = alr_data->bs_pa_mfrms; UBYTE c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; PALLOC (update, MPHC_RXLEV_PERIODIC_REQ); ALR_TRACE_NC ("nc_start_mon"); first_period = first_l1_meas = TRUE; alr_data->nc_data.max_reports = NO_OF_REPORTS [report_idx]; alr_data->nc_data.fn_offset = (report_idx+2) * NO_OF_REPORTS[report_idx] * 51; if (alr_data->nc_data.c_reports EQ (UBYTE)-1) /* initial value */ alr_data->nc_data.c_reports = INIT_OF_C_REPORTS [report_idx]; else /* don´t touch c_reports except for max_reports is less */ if (alr_data->nc_data.c_reports >= alr_data->nc_data.max_reports) alr_data->nc_data.c_reports = alr_data->nc_data.max_reports - 1; index = nc_get_index(alr_data->serving_cell); if (index NEQ NOT_PRESENT_16BIT) alr_data->nc_data.cell[index].c_rxlev = NOT_PRESENT_8BIT; /* * for all neighbourcells: convert channel number * and fill the primitive to layer 1. */ for (index = 0, prim_index = 0; index < c_ba_arfcn; index++) { if (alr_data->nc_data.cell[index].ba_status EQ IN_BA) update->chan_list.radio_freq[prim_index++] = ARFCN_TO_L1(alr_data->nc_data.cell[index].ba_arfcn); } /* * set number of channels and band id */ update->num_of_chans = (UBYTE)prim_index; alr_data->nc_data.ba_id = ALR_ALLOCATE_NEW_BA ( alr_data->nc_data.ba_id ); update->ba_id = alr_data->nc_data.ba_id; update->next_radio_freq_measured = 0; #if defined(_SIMULATION_) { char buf[80], o; o = sprintf (buf, "RXLEV_PERIODIC: c=%d id=%02x:", update->num_of_chans, update->ba_id); for (index=0; index < update->num_of_chans; index++) { if (o > 80-6) { TRACE_EVENT (buf); o = 0; } o += sprintf (buf+o, "%u,", update->chan_list.radio_freq[index]); } buf[o-1]=0; TRACE_EVENT (buf); } #endif /* _SIMULATION_ */ SET_STATE (STATE_NC, NC_IDLE); /* TRACE_EVENT_P2("glob reps: %d max_report: %d", alr_data->nc_data.c_reports, alr_data->nc_data.max_reports); */ /* * configure layer 1. */ ma_nc_rxlev_periodic_req(update); nc_enable_conf(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_enable_conf | +--------------------------------------------------------------------+ PURPOSE : Maintains what happens after 10 seconds interval. restarts a pending ncell confirmation */ LOCAL void nc_enable_conf(void) { UBYTE tim_state = alr_data->nc_data.tim_state; UBYTE st = GET_STATE(STATE_NC); TRACE_EVENT("nc_enable_conf()"); alr_data->nc_data.tim_state = NC_CONF_ENABLED; SET_STATE(STATE_NC_PROC, NC_ACQUIRE); switch(tim_state) { case NC_TIM_STOPPED: if (alr_data->nc_data.ppos_req) nc_process_pos_req (alr_data->nc_data.ppos_req); /* Load the 10sec timer counter variable */ nc_start_ncsync(); break; case NC_CONF_PENDING: if (alr_data->nc_data.ppos_req) nc_process_pos_req (alr_data->nc_data.ppos_req); else nc_start_ncell_confirm(); break; case NC_CONF_DISABLED: if (alr_data->nc_data.ppos_req) nc_process_pos_req (alr_data->nc_data.ppos_req); else if (alr_data->nc_data.c_nc_timer EQ 0) nc_start_ncell_confirm(); /* a confirmation is to restart */ break; default: break; } /*XXX add PBCCH here also */ #ifdef GPRS if ((st EQ NC_DEDICATED OR st EQ NC_PIM_PBCCH OR st EQ NC_PTM_PBCCH) AND #else if ((st EQ NC_DEDICATED) AND #endif alr_data->nc_data.c_nc_timer > TEN_SECONDS) { alr_data->nc_data.c_nc_timer = TEN_SECONDS; } else if (alr_data->nc_data.c_nc_timer EQ 0) { if( st EQ NC_DEDICATED OR alr_data->nc_data.eotd_avail #ifdef GPRS OR st EQ NC_PIM_PBCCH OR st EQ NC_PTM_PBCCH #endif ) alr_data->nc_data.c_nc_timer = TEN_SECONDS; else alr_data->nc_data.c_nc_timer = THIRTY_SECONDS; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_disable_conf | +--------------------------------------------------------------------+ PURPOSE : Maintains what happens after TIM_NCSYNC expiry. prevents ncell confirmation */ LOCAL void nc_disable_conf(BOOL bFree) { TRACE_EVENT("nc_disable_conf()"); switch(alr_data->nc_data.tim_state) { case NC_TIM_STOPPED: case NC_CONF_PENDING: TRACE_ERROR("nc_disable_conf() in unexpected state"); break; default: break; } if(bFree AND (alr_data->nc_data.ppos_ind NEQ NULL)) { PFREE(alr_data->nc_data.ppos_ind); alr_data->nc_data.ppos_ind = NULL; } if(GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) { /* * restart confirmation if it was aborted * after the first expiry after the POS_REQ is done. */ alr_data->nc_data.c_nc_timer = 0; } SET_STATE(STATE_NC_PROC, NC_ACQUIRE); alr_data->nc_data.tim_state = NC_CONF_DISABLED; } LOCAL void nc_start_ncell_confirm(void) { BOOL acquire = FALSE; switch(GET_STATE(STATE_NC)) { case NC_DEDICATED: case NC_IDLE: #ifdef GPRS case NC_PIM_PBCCH: case NC_PTM_PBCCH: #endif if (alr_data->nc_data.eotd_avail AND alr_data->nc_data.c_nc_timer EQ 0) { alr_data->nc_data.c_nc_timer = TEN_SECONDS; nc_stop_all(); nc_check_status(CHECK_FOR_CONFIRM); nc_start_eotd_confirm(); } else if ((alr_data->nc_data.c_nc_timer EQ 0) OR (alr_data->nc_data.c_sync_intrupted EQ TRUE) ) { /* * confirm ncells every thirty seconds in idle * or every 10 seconds in dedicated */ if (GET_STATE(STATE_NC) EQ NC_DEDICATED #ifdef GPRS OR GET_STATE(STATE_NC) EQ NC_PIM_PBCCH OR GET_STATE(STATE_NC) EQ NC_PTM_PBCCH #endif ) alr_data->nc_data.c_nc_timer = TEN_SECONDS; else alr_data->nc_data.c_nc_timer = THIRTY_SECONDS; nc_stop_all(); nc_check_status(CHECK_FOR_CONFIRM); nc_ncell_list_req(); /* if a list_req was send we are in NC_CONFIRM if no list_req was send we are in NC_ACQUIRE This is needed for PBCCH, because there are no measurements in ALR to trigger the initial synchronizations, so we have to check this here if no list_req was send, when a list_req was send then we continue with initial sync after the last sync_ind */ if(GET_STATE(STATE_NC_PROC) EQ NC_ACQUIRE) acquire = TRUE; } else /* acquire ncells (initial or previous failed ones) or * read bcch */ { acquire = TRUE; } if(acquire EQ TRUE) { SET_STATE(STATE_NC_PROC, NC_ACQUIRE); nc_check_status(CHECK_FOR_ACQUIRE_AND_BCCH_AND_FAIL); nc_process_status(); } break; default: TRACE_ERROR("nc_ncsync_tim_expiry in wrong state"); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_start_ncsync | +--------------------------------------------------------------------+ PURPOSE : Assigns/resets c_ncsync_tim counter */ LOCAL void nc_start_ncsync (void) { alr_data->nc_data.c_ncsync_tim = TEN_SECONDS_NCSYNC; TRACE_EVENT("NCSYNC counter loaded with 10 seconds"); vsi_t_time(VSI_CALLER &alr_data->nc_data.ncsync_start_tim); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncsync_tim_expiry | +--------------------------------------------------------------------+ PURPOSE : Called at the end of 10 seconds interval for NCELL synchronization */ GLOBAL void nc_ncsync_tim_expiry(void) { UBYTE i; UBYTE c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; T_NC* pcell; #ifdef GPRS if(!alr_data->gprs_data.pbcch) #endif { T_TIME tval; vsi_t_time(VSI_CALLER &tval); if(tval<alr_data->nc_data.ncsync_start_tim) TRACE_EVENT_P2("NCSYNC expiry at %d milliseconds, BS_PA_MFRMS = %d", ULONG_MAX-alr_data->nc_data.ncsync_start_tim+tval, alr_data->bs_pa_mfrms+2); else TRACE_EVENT_P2("NCSYNC expiry at %d milliseconds, BS_PA_MFRMS = %d", tval-alr_data->nc_data.ncsync_start_tim, alr_data->bs_pa_mfrms+2); } if (alr_data->nc_data.tim_state NEQ NC_TIM_STOPPED) { #ifdef GPRS if(!alr_data->gprs_data.pbcch) #endif { nc_start_ncsync(); } if (alr_data->nc_data.c_nc_timer > 0) alr_data->nc_data.c_nc_timer--; TRACE_EVENT_P1("c_nc_timer %d", alr_data->nc_data.c_nc_timer); /* decrement counters */ for (i=0,pcell = &alr_data->nc_data.cell[0]; i < c_ba_arfcn; i++,pcell++) { if (pcell->c_sync > 0 AND pcell->c_sync < C_INVALID_SYNC) pcell->c_sync--; if (pcell->c_bcch > 0 AND pcell->c_bcch < C_INVALID_BCCH) pcell->c_bcch--; if(pcell->ba_arfcn NEQ alr_data->serving_cell) { switch(pcell->ba_status) { case NOT_IN_BA_SHORT: pcell->ba_status = NOT_IN_BA_LONG; #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] -> NOT_IN_BA_LONG", i, pcell->ba_arfcn); #endif /* TRACING */ break; case NOT_IN_BA_LONG: #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] remove", i, pcell->ba_arfcn); /* this trace must be performed before the removal to get right results */ #endif /* TRACING */ c_ba_arfcn = nc_remove_channel_from_ba_list (i); i--; pcell--; ALR_TRACE_ALL_NC (); break; case IN_BA: /* do nothing */ break; } } } } switch(alr_data->nc_data.tim_state) { case NC_CONF_ENABLED: nc_start_ncell_confirm(); break; case NC_CONF_DISABLED: alr_data->nc_data.tim_state = NC_CONF_PENDING; break; case NC_CONF_PENDING: TRACE_ERROR("TIM_NCSYNC expiry in unexpected state"); /* * this should never happen, but in case ALR is waiting * more than 20 seconds for the last MPHC_NCELL_SYNC_IND of the * confirmation procedure and the reason isn't a position request, * then the confirmation procedure is restarted */ if (GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM AND alr_data->nc_data.ppos_req EQ NULL) { alr_data->nc_data.c_nc_timer = 0; nc_start_ncell_confirm(); } break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_init_pos_ind | +--------------------------------------------------------------------+ PURPOSE : initial setting of a MPH_NCELL_POS_IND */ LOCAL void nc_init_pos_ind (USHORT req_id) { memset(&(alr_data->nc_data.ppos_ind->eotd_sc_res), 0, sizeof (T_eotd_sc_res )); memset(&(alr_data->nc_data.ppos_ind->eotd_sc_res1), 0, sizeof (T_eotd_sc_res1)); alr_data->nc_data.ppos_ind->c_eotd_nc_res = 0; alr_data->nc_data.ppos_ind->req_id = req_id; alr_data->nc_data.ppos_ind->eotd_res = 0; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_is_sync | +--------------------------------------------------------------------+ PURPOSE : checks whether a ncell is synchronized and timing values are valid */ LOCAL BOOL nc_is_sync (T_NC * p_ncell) { switch (p_ncell->status) { case FB_SB_SYNC: case READ_SB: case READ_SB_BCCH: case READ_BCCH: case READ_BCCH_RR_NOT_INFORMED: case IDLE_SYNC: return TRUE; default: return FALSE; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncell_pos_req | +--------------------------------------------------------------------+ PURPOSE : reception of a ncell_pos_req */ void nc_ncell_pos_req (T_MPH_NCELL_POS_REQ* pos_req) { /* if there is an earlier position request disgard it*/ if (alr_data->nc_data.ppos_req NEQ NULL) PFREE(alr_data->nc_data.ppos_req); /* store the request until the end of the respective position indication */ alr_data->nc_data.ppos_req = pos_req; /* * process the request immediately if confirmation is enabled or * another measurement is in progress * (otherwise start processing when confirmation becomes enabled */ if ( (alr_data->nc_data.tim_state EQ NC_CONF_ENABLED) OR (alr_data->nc_data.tim_state EQ NC_CONF_DISABLED AND GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) ) nc_process_pos_req(pos_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_pos_req | +--------------------------------------------------------------------+ PURPOSE : processes a ncell_pos_req */ LOCAL void nc_process_pos_req (T_MPH_NCELL_POS_REQ* pos_req) { UBYTE fail=1; if (alr_data->nc_data.ppos_ind EQ NULL) { PALLOC (pos_ind, MPH_NCELL_POS_IND); alr_data->nc_data.ppos_ind = pos_ind; } nc_init_pos_ind(pos_req->req_id); #if 0 /* allow position requests also in NC_IDLE mode to be able to answer a test SMS */ switch(GET_STATE(STATE_NC)) { case NC_DEDICATED: #endif /* 0|1 */ if(alr_data->nc_data.eotd_avail) { T_NC* p_ncell; T_ncell_eotd* p_ncell_pos = &pos_req->ncell_eotd[0]; T_NC* list_of_asd_1o12 [12]; T_ncell_eotd* list_of_asd_ba [15]; T_ncell_eotd* list_of_asd [15]; T_NC** p_asd_1o12 = &list_of_asd_1o12[0]; T_ncell_eotd** p_asd_ba = &list_of_asd_ba[0]; T_ncell_eotd** p_asd = &list_of_asd[0]; UBYTE c_ba = alr_data->nc_data.c_ba_arfcn; UBYTE i,j; UBYTE c_list; UBYTE found; fail=0; nc_stop_all(); /* * generate and send an appropriate MPHC_NCELL_LIST_SYNC_REQ * 1/ take all ncells which are in ASD list and the twelve * strongest synchronized of the BA list (using timing values * from former synchronisation) * 2/ then all ncells which are in ASD list and in the BA list * (using timings from the ASD list) * 3/ then rest of ASD cells (using timings from the ASD list) * 4/ then rest of BA list cells which are synchronized (using * timing values from former synchronisation) */ { PALLOC (ncell_list_req, MPHC_NCELL_LIST_SYNC_REQ); ncell_list_req->eotd = TRUE; /* for all ncells in ASD list */ for(j=0; j < MAX_NCELL_EOTD_L1 AND j < pos_req->c_ncell_eotd; j++, p_ncell_pos++) { if (p_ncell_pos->arfcn EQ alr_data->serving_cell) { continue; } /* look if it is in BA list */ found=FALSE; for (i = 0, p_ncell = &alr_data->nc_data.cell[0]; i < c_ba; i++, p_ncell++) { if(p_ncell_pos->arfcn EQ p_ncell->ba_arfcn) { /* * if it is in both list then check * if it is synchronized or not * and use the correct list */ if(nc_is_sync(p_ncell)) { /* case 1/ */ *(p_asd_1o12++) = p_ncell; found=TRUE; } else { /* case 2/ */ *(p_asd_ba++) = p_ncell_pos; found=TRUE; } /* is sync */ break; } /*arfcn*/ } /*ba list*/ /* if nothing was found, then it is case 3/ */ if(!found) *(p_asd++) = p_ncell_pos; } /* asd list */ c_list=0; for(i=0; c_list < MAX_L1_SYNC_CNT AND i < p_asd_1o12-list_of_asd_1o12;i++) { nc_ncell_list_req_pos(&ncell_list_req->ncell_list[c_list++], NULL, list_of_asd_1o12[i]->ba_arfcn); } /*asd_1o12 */ for(i=0 ;c_list < MAX_L1_SYNC_CNT AND i < p_asd_ba-list_of_asd_ba;i++) { nc_ncell_list_req_pos(&ncell_list_req->ncell_list[c_list++], list_of_asd_ba[i], list_of_asd_ba[i]->arfcn); } for(i=0 ;c_list < MAX_L1_SYNC_CNT AND i < p_asd-list_of_asd;i++) { nc_ncell_list_req_pos(&ncell_list_req->ncell_list[c_list++], list_of_asd[i], list_of_asd[i]->arfcn); } /* * fill the ncell list req with the remaining synchronized * neigbour cells of the BA list (case 4/ ) */ for (i=0, p_ncell = &alr_data->nc_data.cell[0]; c_list < MAX_L1_SYNC_CNT AND i < c_ba; i++, p_ncell++) { if (p_ncell->ba_arfcn EQ alr_data->serving_cell) { continue; } if (nc_is_sync(p_ncell)) { USHORT l1_arfcn = ARFCN_TO_L1(p_ncell->ba_arfcn); found=FALSE; for (j=0; j < c_list;j++) { if (ncell_list_req->ncell_list[j].radio_freq EQ l1_arfcn) { found = TRUE; break; } } /* MPHC_NCELL_LIST_SYNC_REQ */ if (!found) nc_ncell_list_req_pos(&ncell_list_req->ncell_list[c_list++], NULL, p_ncell->ba_arfcn); } /* is sync */ } /* BA list */ if (c_list > 0) { ncell_list_req->list_size = c_list; alr_data->nc_data.c_sync_req = c_list; if (c_list < MAX_NCELL_EOTD_L1) memset(&(ncell_list_req->ncell_list[c_list]), 0, (MAX_NCELL_EOTD_L1 - c_list) * sizeof(T_ncell_list)); alr_data->nc_data.c_sync_req += 2; /* for the 2 scell ind's */ nc_disable_conf(DONT_FREE_POS_IND); SET_STATE(STATE_NC_PROC, NC_CONFIRM); ma_nc_list_sync_req (ncell_list_req); TRACE_EVENT_P1("MPHC_NCELL_LIST_SYNC_REQ eotd=TRUE c_sync_req=%u", alr_data->nc_data.c_sync_req); } else fail = TRUE; }/* PALLOC list_req */ } /* eotd_avail */ /* else fail=1*/ #if 0 break; default: /*fail=1*/ break; } /*switch NC_STATE*/ #endif /* 0|1 */ if(fail) { /* TODO complete ?? */ alr_data->nc_data.ppos_ind->eotd_res = EOTD_REF; PSENDX(RR, alr_data->nc_data.ppos_ind); alr_data->nc_data.ppos_ind = NULL; PFREE(pos_req); alr_data->nc_data.ppos_req = NULL; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncell_list_req_pos | +--------------------------------------------------------------------+ PURPOSE : Handles cell lists. */ LOCAL void nc_ncell_list_req_pos(T_ncell_list* p_ncell_list, T_ncell_eotd* asd_cell, USHORT arfcn) { USHORT index = nc_get_index(arfcn); p_ncell_list->radio_freq = ARFCN_TO_L1(arfcn); if(asd_cell) { if(index NEQ NOT_PRESENT_16BIT AND index NEQ LAST_BSIC_REQ AND alr_data->nc_data.cell[index].status EQ IDLE_SYNC) { p_ncell_list->fn_offset = alr_data->nc_data.cell[index].frame_offset; p_ncell_list->time_alignment = alr_data->nc_data.cell[index].time_align; p_ncell_list->timing_validity = TV_VALID_TIMING_INFO; /*TODO what about reception of ncell_sync_ind for this cell are timing info and counter updated ?*/ } else { nc_get_timing_eotd(p_ncell_list, asd_cell); p_ncell_list->timing_validity = TV_VALID_TIMING_INFO; /* TV_APPROX_TIMING_INFO;*/ } } /*asd_cell*/ else { if(index NEQ NOT_PRESENT_16BIT AND index NEQ LAST_BSIC_REQ) { /* cell is in BA list and 1o12, so use the data we have */ switch(alr_data->nc_data.cell[index].status) { case READ_SB_BCCH: case READ_BCCH: nc_set_status(index,READ_SB_BCCH_PENDING); break; case READ_SB: case FB_SB_SYNC: nc_set_status(index,READ_SB_PENDING); break; case READ_FB_SB: case READ_BCCH_RR_NOT_INFORMED: case FB_SB_SYNC_RR_NOT_INFORMED: /*TODO what about reception of ncell_sync_ind for this cell are timing info and counter updated ?*/ break; } /*status*/ p_ncell_list->fn_offset = alr_data->nc_data.cell[index].frame_offset; p_ncell_list->time_alignment = alr_data->nc_data.cell[index].time_align; p_ncell_list->timing_validity = TV_VALID_TIMING_INFO; } else { TRACE_ERROR("nc_ncell_list_req_pos: asd_cell==0 but cell not in BA"); } }/*asd_cell*/ } LOCAL void nc_get_timing_eotd(T_ncell_list* p_ncell_list, T_ncell_eotd* asd_cell) { USHORT td, adjust = 0, offs; /* * The values mfrm_offset, rough_rtd and exp_otd are differences * between the BTS in question and the reference BTS. * L1 expects the differences between serving BTS and BTS in question: * * +----+----+----+----+----+....+----+----+----+----+----+ serving BTS * 0 51 * | * 0 Net | L1 1250 (5000) * +---->V<----+ * \ / * \ / * +----+----+----+----+----+....+----+----+----+----+----+ BTS in question * 0 51 * +-----Net----->| |<---------L1----------------------+ * * time differences are indicated in bits by the net, but expected * in quarterbits by L1 */ offs = asd_cell->mfrm_offset; if (asd_cell->otd_type EQ BOTH_OTD) { int diff = asd_cell->rough_rtd - asd_cell->exp_otd; if (diff >= 850) adjust = 1; else if (diff <= -850) adjust = -1; /* * GSM 04.31 section A.2.2.3 version 8.7.0 says that adjust shall be * equal 0 for -400 <= diff <= 400 and states an error for * -850 < diff < -450 and for 450 < diff < 850, but doesn't * describe the behaviour in this cases. * All this valid and invalid cases are implemented here by * adjust = 0 */ } if (asd_cell->otd_type EQ ROUGH_OTD) td = asd_cell->rough_rtd; else { /* * uncertainty indicates how many bits the search window * for measurement should be opended earlier than the expected * value. Because of the subsequent subtraction we have to ADD * the uncertainty value. * no special handling for uncertainty value 7 (uncertainty > 30 bits) * is implemented yet */ td = asd_cell->exp_otd + unc_values[asd_cell->uncertainty]; if (td >= 1250) offs++; } td %= 1250; if (td) { p_ncell_list->time_alignment = 5000 - 4 * td; offs++; } else p_ncell_list->time_alignment = 0; offs = (offs + adjust) % 51; if (offs) p_ncell_list->fn_offset = 51 - offs; else p_ncell_list->fn_offset = 0; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_start_eotd_confirm | +--------------------------------------------------------------------+ PURPOSE : generates an MPHC_NCELL_LIST_SYNC_REQ from the BA list. */ LOCAL void nc_start_eotd_confirm(void) { /* * this check is needed for the resume * in the GPRS case because we need * to keep the states over a * start transition */ if(alr_data->nc_data.ppos_ind EQ NULL) { PALLOC (pos_ind, MPH_NCELL_POS_IND); alr_data->nc_data.ppos_ind = pos_ind; } nc_init_pos_ind (NOT_PRESENT_16BIT); /* generate and send an appropriate MPHC_NCELL_LIST_SYNC_REQ */ nc_ncell_list_req(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncell_list_req | +--------------------------------------------------------------------+ PURPOSE : generates an MPHC_NCELL_LIST_SYNC_REQ based on the 12 strongest neighbour cells of the BA */ LOCAL void nc_ncell_list_req (void) { UBYTE c_found = 0, found, i, validity; USHORT c_ba = alr_data->nc_data.c_ba_arfcn; T_NC* pcell; T_ncell_list *pnc; PALLOC (ncell_list_req, MPHC_NCELL_LIST_SYNC_REQ); if (alr_data->nc_data.c_sync_req NEQ 0) TRACE_EVENT_P1("nc_ncell_list_req with c_sync_req=%u before", alr_data->nc_data.c_sync_req); ncell_list_req->eotd = alr_data->nc_data.eotd_avail; nc_stop_all(); for (i = 0, pcell = &alr_data->nc_data.cell[0]; i < c_ba; i++, pcell++) { if (alr_data->nc_data.eotd_avail AND pcell->ba_arfcn EQ alr_data->serving_cell) { continue; } if (pcell->one_of_twelve) { switch (pcell->status) { case READ_SB: nc_set_status(nc_get_index(pcell->ba_arfcn), READ_SB_PENDING); found = TRUE; validity = TV_VALID_TIMING_INFO; break; case READ_SB_BCCH: nc_set_status(nc_get_index(pcell->ba_arfcn), READ_SB_BCCH_PENDING); found = TRUE; validity = TV_VALID_TIMING_INFO; break; /* TODO(opt): if !eotd_avail maybe optimize later case READ_FB_SB: break*/ /* case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH_PENDING_RR_NOT_INFORMED: case READ_BCCH: case READ_BCCH_PENDING: found = TRUE; validity = TV_VALID_TIMING_INFO; break;*/ default: found = FALSE; validity = TV_INVALID_TIMING_INFO; break; } if (found) { pnc = &(ncell_list_req->ncell_list[c_found++]); pnc->radio_freq = ARFCN_TO_L1(pcell->ba_arfcn); if (validity EQ TV_VALID_TIMING_INFO) { pnc->fn_offset = pcell->frame_offset; pnc->time_alignment = pcell->time_align; } else { pnc->fn_offset = 0; pnc->time_alignment = 0; } pnc->timing_validity = validity; } } } /* * in case there are no synchronized neighbour cells * send an empty MPHC_NCELL_LIST_SYNC_REQ to L1 * (to serve the cursor task later with a position indication * containing measurements of the serving cell only) */ if(c_found OR alr_data->nc_data.eotd_avail) { ncell_list_req->list_size = c_found; alr_data->nc_data.c_sync_req = c_found; if (c_found < MAX_NCELL_EOTD_L1) memset(&(ncell_list_req->ncell_list[c_found]), 0, (MAX_NCELL_EOTD_L1 - c_found) * sizeof(T_ncell_list)); if(alr_data->nc_data.eotd_avail) /* add the 2 scell sync_ind */ alr_data->nc_data.c_sync_req += 2; nc_disable_conf(DONT_FREE_POS_IND); SET_STATE(STATE_NC_PROC, NC_CONFIRM); ma_nc_list_sync_req (ncell_list_req); TRACE_EVENT_P3("MPHC_NCELL_LIST_SYNC_REQ eotd=%d c_sync_req=%u SC=%u", alr_data->nc_data.eotd_avail, alr_data->nc_data.c_sync_req, alr_data->serving_cell); } else { PFREE(ncell_list_req); SET_STATE(STATE_NC_PROC, NC_ACQUIRE); nc_enable_conf(); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_store_eotd | +--------------------------------------------------------------------+ PURPOSE : copies the measurement results into the MPH_NCELL_POS_IND */ LOCAL void nc_store_eotd (T_eotd_sc_res * p_res, T_MPHC_NCELL_SYNC_IND * sync_ind, USHORT arfcn) { p_res->sb_flag = sync_ind->sb_flag; p_res->bsic = sync_ind->bsic; p_res->arfcn = arfcn; memcpy(&(p_res->eotd_crosscor), &(sync_ind->a_eotd_crosscor), sizeof(sync_ind->a_eotd_crosscor)); p_res->d_eotd_nrj = sync_ind->d_eotd_nrj; p_res->time_tag = sync_ind->time_tag; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_ext_meas_ind | +--------------------------------------------------------------------+ PURPOSE : Notify RR about the end of the end of the Extended Measurement procedure. */ GLOBAL void nc_stop_ext_meas_ind (void) { PALLOC ( mph_sync_ind, MPH_SYNC_IND ); mph_sync_ind->cs = CS_STOP_PLMN_SEARCH; mph_sync_ind->arfcn = NOT_PRESENT_16BIT; PSENDX ( RR, mph_sync_ind ); if( alr_data->cs_data.p_power_cnf NEQ NULL ) { PFREE(alr_data->cs_data.p_power_cnf) alr_data->cs_data.p_power_cnf = NULL; } 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 (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_rr_activity | +--------------------------------------------------------------------+ PURPOSE : Stop BCCH reading or PLMN seach originated by RR. */ GLOBAL void nc_stop_rr_activity (UBYTE stop) { /* * RR signals stop BCCH reading or stop PLMN search */ if( (IS_EXT_MEAS_RUNNING) AND (alr_data->nc_data.cell[LAST_BSIC_REQ].status EQ READ_FB_SB_PENDING) ) { /* * Wait for MPHC_NCELL_SYNC_IND or MPHC_STOP_NCELL_SYNC_CON */ alr_data->cs_data.ext_meas_state_pend = CS_ACTIVE_SYNC; } nc_clear_last_bsic(); /* * RR signals end of PLMN search */ if (stop) { alr_data->plmn_search_running = FALSE; nc_enable_conf(); } if ( IS_EXT_MEAS_RUNNING AND (alr_data->cs_data.ext_meas_state_pend EQ CS_NULL) ) { nc_stop_ext_meas_ind(); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (8403) MODULE : ALR_NC | | STATE : code ROUTINE : nc_bsic_req | +--------------------------------------------------------------------+ PURPOSE : Request of RR to search for frequency correction burst and synchron burst. */ GLOBAL void nc_bsic_req (T_MPH_BSIC_REQ *mph_bsic_req) { USHORT i; mph_bsic_req->arfcn &= ARFCN_MASK; ALR_TRACE_NC_BSIC_REQ (mph_bsic_req->arfcn); ALR_EM_NEIGHBOURCELL_BSIC_REQUEST; nc_clear_last_bsic(); /* * look if the requested channel number is also in the normal * BA list to stop it. */ i = nc_get_index( mph_bsic_req->arfcn ); switch(i) { case NOT_PRESENT_16BIT: case LAST_BSIC_REQ: break; default: nc_stop_if_active(i); TRACE_ERROR("bsic_req for arfcn which is in BA list"); break; } /* * fill in parameters for BSIC request */ nc_set_status (LAST_BSIC_REQ, READ_FB_SB); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = mph_bsic_req->arfcn; /* * forward synchronisation request to layer 1, if not full */ if (alr_data->nc_data.c_sync_req < MAX_L1_SYNC_CNT) { /* * reset if we are in NC_CON_EST */ if(GET_STATE(STATE_NC) EQ NC_CON_EST #ifdef GPRS AND !alr_data->gprs_data.pbcch #endif ) { SET_STATE(STATE_NC, NC_IDLE); } #ifdef GPRS else if(GET_STATE(STATE_NC) EQ NC_CON_EST AND alr_data->gprs_data.pbcch) /* AND */ /* add later alr_data->gprs_data.pim) */ { SET_STATE(STATE_NC, NC_PIM_PBCCH); } #endif nc_process_status (); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_bcch_ind | +--------------------------------------------------------------------+ PURPOSE : Reception of a system information message for a neighbourcell. */ GLOBAL void nc_bcch_ind (T_MPHC_NCELL_BCCH_IND *data_ind) { USHORT index; UBYTE msg_t = data_ind->l2_frame.content[SI_CONTENTS_MSG_T]; if (alr_data->nc_data.cell[LAST_BSIC_REQ].status EQ READ_BCCH_PENDING AND alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn EQ ARFCN_TO_G23(data_ind->radio_freq)) { /* * Cell selection or PLMN available search triggered by RR. */ if (data_ind->error_flag NEQ VALID_BLOCK) { /* * Reception of an invalid block */ ALR_TRACE_NC ("invalid PLMN BCCH"); /* * indicate BCCH read error to RR, too many errors are controlled by RR */ ma_error_ind (CS_BCCH_READ_ERROR, ARFCN_TO_G23(data_ind->radio_freq)); } else { UBYTE mt = data_ind->l2_frame.content[2]; ALR_TRACE_NC ("valid PLMN BCCH"); /* * forward message to RR */ ma_send_unitdata ((T_MPHC_DATA_IND *)data_ind); switch (mt) { case D_SYS_INFO_3: case D_SYS_INFO_4: alr_data->nc_data.cell[LAST_BSIC_REQ].blocks_required = 0; break; default: /* * Reception of any other message. Shall not happen after * GSM 5.02 chapter 6.3.1.3 Mapping of BCCH data, but * is possible for future extensions. * Read this tc again plus all which are not read until now. */ break; } } /* * all frames received, then decrement pending BCCH request */ if (alr_data->nc_data.cell[LAST_BSIC_REQ].blocks_required EQ 0) { nc_set_status (LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; /* * L3 may avoid sending a stop message to terminate a NCELL_BCCH process * if there no more pending request in L1 */ if (alr_data->nc_data.c_bcch_req > 0) { /* * stop any ongoing request in layer 1 */ ma_nc_stop_ncell_bcch_req(ARFCN_TO_G23(data_ind->radio_freq)); /* * decrement the number of pending requests in layer 1. */ alr_data->nc_data.c_bcch_req--; } } else { /* * stop pending request and start again. */ nc_restart_bcch (LAST_BSIC_REQ); } return ; } /* * Normal Ncell Handling, get position in neighbourcell list */ index = nc_get_index (ARFCN_TO_G23(data_ind->radio_freq)); if (index NEQ NOT_PRESENT_16BIT AND index NEQ LAST_BSIC_REQ AND (alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING OR alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED)) { /* * normal member of the neighbourcell list and an answer is expected. */ if (data_ind->error_flag EQ VALID_BLOCK) { switch (msg_t) { case D_SYS_INFO_3: /* * Sys Info 3 contains the needed information in any case */ #if defined(TRACING) TRACE_EVENT_P3("NC%u[%d] BCCH ok %s", index, alr_data->nc_data.cell[index].ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : alr_data->nc_data.cell[index].ba_arfcn&ARFCN_MASK, "si3"); #endif /* TRACING */ if (alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED) { /* * store data if RR is not informed yet about * synchronisation */ nc_store_bcch((T_MPHC_DATA_IND *) data_ind, index,0); nc_set_status (index, FB_SB_SYNC_RR_NOT_INFORMED); } else { /* * forward information to RR */ ma_send_unitdata ((T_MPHC_DATA_IND *)data_ind); nc_set_fb_sb_sync_initial (index); } break; case D_SYS_INFO_4: if ((data_ind->l2_frame.content[SI_CONTENTS_CS2] & ONLY_ACS) EQ 0) { #if defined(TRACING) TRACE_EVENT_P3("NC%u[%d] BCCH ok %s", index, alr_data->nc_data.cell[index].ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : alr_data->nc_data.cell[index].ba_arfcn&ARFCN_MASK, "si4"); #endif /* TRACING */ /* * additional cell selection info from sys info 7 or 8 is not necessary */ if (alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED) { /* * store data if RR is not informed yet about synchronisation */ nc_store_bcch((T_MPHC_DATA_IND *) data_ind, index,0); nc_set_status (index, FB_SB_SYNC_RR_NOT_INFORMED); } else { /* * forward information to RR */ ma_send_unitdata ((T_MPHC_DATA_IND *)data_ind); nc_set_fb_sb_sync_initial (index); } } else { #if defined(TRACING) TRACE_EVENT_P3("NC%u[%d] BCCH ok %s", index, alr_data->nc_data.cell[index].ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : alr_data->nc_data.cell[index].ba_arfcn&ARFCN_MASK, "si4_n78"); #endif /* TRACING */ /* * additional information from system info 7 or 8 * is needed for cell reselection purposes */ if(alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED) { /* * store data if RR is not informed yet about synchronisation */ nc_store_bcch((T_MPHC_DATA_IND *) data_ind, index,0); } else { /* * forward information to RR */ ma_send_unitdata ((T_MPHC_DATA_IND *)data_ind); } /* * system info 3, 7 or 8 required * -> tc = 2,6 for normal BCCH or 3,7 for extended BCCH */ alr_data->nc_data.cell[index].blocks_required = NCELL_BCCH_SI_3_7_8; } break; case D_SYS_INFO_7: case D_SYS_INFO_8: if (nc_sys_info_78_required (index)) { #if defined(TRACING) TRACE_EVENT_P3("NC%u[%d] BCCH ok %s", index, alr_data->nc_data.cell[index].ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : alr_data->nc_data.cell[index].ba_arfcn&ARFCN_MASK, "si78"); #endif /* TRACING */ if(alr_data->nc_data.cell[index].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED) { /* * store data if RR is not informed yet about synchronisation */ nc_store_bcch((T_MPHC_DATA_IND *) data_ind, index,1); nc_set_status (index, FB_SB_SYNC_RR_NOT_INFORMED); } else { /* * forward information to RR */ ma_send_unitdata ((T_MPHC_DATA_IND *)data_ind); nc_set_fb_sb_sync_initial (index); } } else /* * increment error counter and request tc again. */ alr_data->nc_data.cell[index].c_error++; break; default: /* * increment error counter and request tc again. */ alr_data->nc_data.cell[index].c_error++; break; } } else { /* * BCCH reading failed * * error counter is incremented and tc shall be read again. */ alr_data->nc_data.cell[index].c_error++; } /* * restart next attempt */ if (alr_data->nc_data.cell[index].blocks_required EQ 0) { if (alr_data->nc_data.c_bcch_req > 0) { /* * decrement number of pending BCCH requests in layer 1. */ alr_data->nc_data.c_bcch_req--; /* * Stop the pending reading, if not all tc-s read */ ma_nc_stop_ncell_bcch_req (alr_data->nc_data.cell[index].ba_arfcn); } alr_data->nc_data.cell[index].c_attempt = 0; /* * start next request to layer 1 if necessary */ nc_process_status (); } else { if (alr_data->nc_data.cell[index].c_error >= 4) { /* * set status to failed or excluded depending on the failed * attempt counter and/or restart for this channel. */ nc_sync_failed_attempt (index); /* * L3 may avoid sending a stop message to terminate a NCELL_BCCH process * if there no more pending request in L1 */ if (alr_data->nc_data.c_bcch_req > 0) { /* * decrement number of pending BCCH requests in layer 1. */ alr_data->nc_data.c_bcch_req--; /* * Stop the pending reading, if not all tc-s read */ ma_nc_stop_ncell_bcch_req (alr_data->nc_data.cell[index].ba_arfcn); } /* * start next request to layer 1 if necessary */ nc_process_status (); } else { /* * restart the BCCH reading for this TC again. */ nc_restart_bcch (index); } } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_restart_bcch | +--------------------------------------------------------------------+ PURPOSE : Stop old request and start new request to layer 1. */ LOCAL void nc_restart_bcch (USHORT index) { PALLOC (ncell_bcch, MPHC_NCELL_BCCH_REQ); if (alr_data->nc_data.c_bcch_req > 0) { /* * if necessary stop previous request to avoid on the fly change */ ma_nc_stop_ncell_bcch_req(alr_data->nc_data.cell[index].ba_arfcn); } ncell_bcch->radio_freq = ARFCN_TO_L1(alr_data->nc_data.cell[index].ba_arfcn); ncell_bcch->fn_offset = alr_data->nc_data.cell[index].frame_offset; ncell_bcch->time_alignment = alr_data->nc_data.cell[index].time_align; ncell_bcch->tsc = (UBYTE)(alr_data->nc_data.cell[index].bsic & ONLY_BCC); ncell_bcch->bcch_blocks_required = alr_data->nc_data.cell[index].blocks_required; #ifdef GPRS /*if the mobile is in PTM the GPRS_PRIORITY must be set to TOP*/ if(ma_is_ptm()) { ncell_bcch->gprs_prio = GPRS_PRIO_TOP; } else #endif ncell_bcch->gprs_prio = GPRS_PRIO_NORM; /* * and start next request */ ma_nc_bcch_req (ncell_bcch); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_store_sync_ind | +--------------------------------------------------------------------+ PURPOSE : stores the data of an MPHC_NCELL_SYNC_IND end enters a new state of ncell. */ LOCAL void nc_store_sync_ind (USHORT index, T_MPHC_NCELL_SYNC_IND *sync_ind, UBYTE new_status) { T_NC* pcell = &alr_data->nc_data.cell[index]; pcell->bsic = (UBYTE)(sync_ind->bsic & ONLY_BSIC); pcell->frame_offset = sync_ind->fn_offset; pcell->time_align = sync_ind->time_alignment; pcell->tim_valid = TV_VALID_TIMING_INFO; nc_set_status (index, new_status); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_sync_ind | +--------------------------------------------------------------------+ PURPOSE : Confirmation for a synchronisation request to layer 1. */ GLOBAL void nc_sync_ind (T_MPHC_NCELL_SYNC_IND *sync_ind) { USHORT index; UBYTE bsic = (UBYTE)(sync_ind->bsic & ONLY_BSIC); USHORT arfcn = ARFCN_TO_G23(sync_ind->radio_freq)&ARFCN_MASK; index = nc_get_index (arfcn); switch (GET_STATE (STATE_NC)) { case NC_IDLE: case NC_DEDICATED: #ifdef GPRS case NC_PIM_PBCCH: case NC_PTM_PBCCH: /*XXX*/ #endif TRACE_EVENT_P5("nc_sync_ind[%d] sb_flag=%d fn_offset=%ld time_alignment=%ld bsic=%d", arfcn, sync_ind->sb_flag, sync_ind->fn_offset, sync_ind->time_alignment, sync_ind->bsic); if (alr_data->nc_data.c_sync_req > 0) alr_data->nc_data.c_sync_req--; if (alr_data->nc_data.cell[LAST_BSIC_REQ].status EQ READ_FB_SB_PENDING AND alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn EQ arfcn AND #ifdef GPRS (GET_STATE(STATE_NC) EQ NC_IDLE OR GET_STATE(STATE_NC) EQ NC_PIM_PBCCH) ) #else GET_STATE(STATE_NC) EQ NC_IDLE ) #endif { nc_sync_ind_last_bsic_req(sync_ind,index,arfcn,bsic); } else { if (index NEQ NOT_PRESENT_16BIT AND index NEQ LAST_BSIC_REQ) { nc_sync_ind_ncell(sync_ind,index,arfcn,bsic); } /* valid index check */ else if (alr_data->nc_data.eotd_avail AND alr_data->nc_data.ppos_ind NEQ NULL) nc_check_sync_ind_eotd(sync_ind, arfcn); /* LAST_BSIC_REQ check */ else if ( (index EQ NOT_PRESENT_16BIT) AND (IS_EXT_MEAS_RUNNING) AND (GET_STATE(STATE_NC) EQ NC_IDLE)) { if ( alr_data->cs_data.ext_meas_state_pend NEQ CS_NULL ) { nc_stop_ext_meas_ind(); alr_data->cs_data.ext_meas_state_pend = CS_NULL; return; } } } if( alr_data->nc_data.c_sync_intrupted EQ TRUE AND alr_data->nc_data.c_sync_req EQ 0) { nc_enable_conf(); alr_data->nc_data.c_sync_intrupted = FALSE; } if(GET_STATE(STATE_NC_PROC) EQ NC_ACQUIRE) { nc_process_status(); } break; default: break; } /* STATE_NC */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_sync_ind_last_bsic_req | +--------------------------------------------------------------------+ PURPOSE : Confirmation of the LAST_BSIC_REQ synchronisation request */ LOCAL void nc_sync_ind_last_bsic_req(T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT index, USHORT arfcn, UBYTE bsic) { /* * decoding of FB / SB of hplmn cell is in progress * send confirmation to RR. */ PALLOC (mph_bsic_cnf, MPH_BSIC_CNF); mph_bsic_cnf->arfcn = arfcn; mph_bsic_cnf->bsic = bsic; if (sync_ind->sb_flag EQ SB_FOUND) { ALR_TRACE_NC_BSIC_CNF(sync_ind->radio_freq); /* * FCB and SCB found, set result code */ mph_bsic_cnf->cs = CS_NO_ERROR; if ( IS_EXT_MEAS_RUNNING ) { nc_set_status (LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; if ( alr_data->cs_data.ext_meas_state_pend NEQ CS_NULL ) { PFREE ( mph_bsic_cnf ); nc_stop_ext_meas_ind(); } else { ma_bsic_cnf (mph_bsic_cnf); } return; } ALR_EM_NEIGHBOURCELL_BCCH(EM_AVAIL); /* save data for next cell reselection */ { T_NC *pcr_cell = &alr_data->nc_data.cr_cell; pcr_cell->ba_arfcn = arfcn; pcr_cell->bsic = bsic; pcr_cell->frame_offset = sync_ind->fn_offset; pcr_cell->time_align = sync_ind->time_alignment; } ma_bsic_cnf (mph_bsic_cnf); nc_store_sync_ind (LAST_BSIC_REQ, sync_ind, READ_BCCH); #ifdef GPRS /* don't do the next checks for PBCCH just return * maybe later TODO(opt) */ if (GET_STATE (STATE_NC) EQ NC_PIM_PBCCH OR GET_STATE (STATE_NC) EQ NC_PTM_PBCCH) { return; } #endif index = nc_get_index (arfcn); if(index NEQ LAST_BSIC_REQ AND index NEQ NOT_PRESENT_16BIT) { /* * check BSIC of the incoming BCCH message */ switch (nc_check_bsic (index, bsic)) { case NC_CHECK_OK: /* * channel has passed NCC permitted check. */ switch (alr_data->nc_data.cell[index].status) { case IDLE: /* This patch helps during parallel search in Limited service. * Cell synchronised in the last BSIC_REQ fromm RR during parallel * search is also a part of BA list. In such a case, we store the * synchrinisation information, so that its can be used later by * nc_start_reselect. */ if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); else nc_store_sync_ind (index, sync_ind, IDLE_SYNC); break; case READ_FB_SB: /* * the channel shall start synchronisation of FB/SB * so reading of BCCH shall be started. */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); else if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); break; case READ_SB: /* * the channel shall start synchronisation of SB * so this is done. */ if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); break; case FB_SB_FAILED: /* * A channel synchronisation has failed in the past. * Now it is synchronized again. Start BCCH reading * and send this information to RR after indicating * the synchronisation with next measurement report. */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); else if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); break; case READ_SB_BCCH: /* * the channel shall start synchronisation of SB * followed by BCCH reading. SB synchronisation * is done. */ if(alr_data->nc_data.cell[index].one_of_six) nc_store_sync_ind (index, sync_ind, READ_BCCH); break; case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB_BCCH_PENDING: case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: /* * REMARK: this shall not happen, because this * attempt shall be killed if RR requests * procedure for the channel. */ ALR_TRACE_NC ("Abnormal situation sync ind"); break; default: break; } break; case NC_CHECK_BSIC_CHANGED: /* * BSIC of the channel has changed. */ switch (alr_data->nc_data.cell[index].status) { case READ_SB: /* * the channel shall start synchronisation of SB * so this is done, but a changed BSIC is stored. * Read BCCH of the channel and forward to RR. */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); else if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); break; case FB_SB_FAILED: /* * A channel synchronisation has failed in the past. * Now it is synchronized again. Start BCCH reading * and send this information to RR after indicating * the synchronisation with next measurement report. */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); else if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); break; case READ_SB_BCCH: /* * the channel shall start synchronisation of SB * followed by BCCH reading. SB synchronisation * is done. Read BCCH of the channel and forward to RR. */ if(alr_data->nc_data.cell[index].one_of_six) nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); break; case READ_FB_SB: case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB_BCCH_PENDING: case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: /* * REMARK: this shall not happen, because this * attempt shall be killed if RR requests * procedure for the channel. */ ALR_TRACE_NC ("Abnormal situation sync ind (changed BSIC)"); break; default: break; } break; case NC_CHECK_NCC_FAILED: /* * ncc permitted check failed */ nc_set_status (index, EXCLUDED); break; default: break; } } ALR_EM_NEIGHBOURCELL_BSIC_CONFIRM(EM_AVAIL); } else { /* * FCB and SCB not found, set result code, * mark cell[LAST_BSIC_REQ] and cr_cell as invalid * and send negative answer to RR */ mph_bsic_cnf->cs = CS_NO_BCCH_AVAIL; nc_set_status (LAST_BSIC_REQ, IDLE); alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn = NOT_PRESENT_16BIT; alr_data->nc_data.cr_cell.ba_arfcn = NOT_PRESENT_16BIT; ma_bsic_cnf (mph_bsic_cnf); ALR_EM_NEIGHBOURCELL_BSIC_CONFIRM(EM_NOT_AVAIL); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_sync_ind_ncell | +--------------------------------------------------------------------+ PURPOSE : Confirmation of a ncell synchronisation request */ LOCAL void nc_sync_ind_ncell(T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT index, USHORT arfcn, UBYTE bsic) { #ifdef GPRS BOOL bsic_chg = FALSE; #endif if (GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) { /* eotd confirmation is active */ if(alr_data->nc_data.eotd_avail) nc_check_sync_ind_eotd(sync_ind, arfcn); TRACE_EVENT_P2("sync_ind[%u] c_sync_req=%u", arfcn, alr_data->nc_data.c_sync_req); /* * check if the end of the CONFIRM procedure (LIST_REQ) is * reached * this is done here because it is independent from EOTD */ if(alr_data->nc_data.c_sync_req EQ 0) { nc_enable_conf(); } /* * skip the rest of this function for scell * because the status for the scell is always FB_SB_SYNC */ if(alr_data->nc_data.eotd_avail AND arfcn EQ alr_data->serving_cell) return; } if (sync_ind->sb_flag EQ SB_FOUND) { /* * Synchronization successful for a normal member of the BA list. */ ALR_TRACE_NC_SB_IND_PASSED(arfcn); ALR_EM_NEIGHBOURCELL_SB(EM_AVAIL); switch (GET_STATE (STATE_NC)) { case NC_IDLE: case NC_DEDICATED: /* * check neighbourcell */ switch (nc_check_bsic (index, bsic)) { case NC_CHECK_OK: /* * channel has passed NCC permitted check. */ switch (alr_data->nc_data.cell[index].status) { case READ_FB_SB_PENDING: /* * initial synchronization to FB and SB * if the cell is a 1o6 we read the BCCH * otherwise we just set it to synchronized */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) { nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); } else if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); else { TRACE_EVENT_P1("sync ind for not 1o12 cell %d", arfcn); } break; case READ_SB_PENDING: /* * confirmation of SB */ alr_data->nc_data.cell[index].c_attempt = 0; if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); else nc_store_sync_ind (index, sync_ind, IDLE_SYNC); break; case READ_SB_BCCH_PENDING: /* * confirmation of SB before reading * neighbour cell BCCH all five minutes. */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) EQ NC_IDLE) { nc_store_sync_ind (index, sync_ind, READ_BCCH); } else { alr_data->nc_data.cell[index].c_attempt = 0; if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); else nc_store_sync_ind (index, sync_ind, IDLE_SYNC); } break; case READ_BCCH_RR_NOT_INFORMED: /*TODO(opt)*/ case READ_BCCH_PENDING_RR_NOT_INFORMED:/*TODO(opt)*/ case READ_BCCH:/*TODO(opt)*/ case READ_BCCH_PENDING:/*TODO(opt)*/ TRACE_ERROR("sync_ind for ncell in READ_BCCH*"); if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) EQ NC_IDLE) { nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); } break; default: break; } /*switch(status)*/ break; case NC_CHECK_BSIC_CHANGED: /* * channel has passed NCC permitted check, * but a changed BSIC has been detected. */ switch (alr_data->nc_data.cell[index].status) { case READ_SB_PENDING: case READ_SB_BCCH_PENDING: /* * confirmation of SB indicates new BSIC */ if(alr_data->nc_data.cell[index].one_of_six AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) { nc_store_sync_ind (index, sync_ind, READ_BCCH_RR_NOT_INFORMED); } else if(alr_data->nc_data.cell[index].one_of_twelve) { alr_data->nc_data.cell[index].c_attempt = 0; nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); } else { TRACE_EVENT_P1("sync ind for not 1o12 cell %d", arfcn); nc_store_sync_ind (index, sync_ind, IDLE_SYNC); } break; default: break; } /*switch(status)*/ break; case NC_CHECK_NCC_FAILED: /* * ncc permitted check failed. Attempt again. * BSIC of a cell may always change. So do not * exclude this cell in IDLE mode meaurements */ if(GET_STATE(STATE_NC) EQ NC_IDLE) { alr_data->nc_data.cell[index].c_attempt = 0; nc_set_fb_sb_failed (index, TEN_SECONDS); } else if(GET_STATE(STATE_NC) EQ NC_DEDICATED) { alr_data->nc_data.cell[index].c_attempt = 0; nc_set_fb_sb_failed (index, THIRTY_SECONDS); } else { nc_set_status (index, EXCLUDED); } break; } break; #ifdef GPRS case NC_PIM_PBCCH: case NC_PTM_PBCCH: /*XXX*/ TRACE_EVENT("sync_ind PBCCH"); switch (alr_data->nc_data.cell[index].status) { case READ_FB_SB_PENDING: nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); nc_inform_grr_of_ncell(index, GRR_SB_FOUND); break; case READ_SB_PENDING: if(bsic NEQ alr_data->nc_data.cell[index].bsic) bsic_chg = TRUE; else bsic_chg = FALSE; if(alr_data->nc_data.cell[index].one_of_twelve) nc_store_sync_ind (index, sync_ind, FB_SB_SYNC); else nc_store_sync_ind (index, sync_ind, IDLE_SYNC); if(bsic_chg) nc_inform_grr_of_ncell(index, GRR_SB_FOUND); break; default: break; } break; default: break; #endif } /* NC_STATE */ } else /* sb_flag EQ FALSE */ { /* * Synchronization failed */ ALR_TRACE_NC_SB_FAILED (sync_ind->radio_freq); if (alr_data->nc_data.cell[index].ba_status EQ IN_BA) { switch (alr_data->nc_data.cell[index].status) { case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB_BCCH_PENDING: ALR_EM_NEIGHBOURCELL_SB(EM_NOT_AVAIL); if(GET_STATE(STATE_NC) EQ NC_IDLE) nc_sync_failed_attempt(index); else if(GET_STATE(STATE_NC) EQ NC_DEDICATED) nc_sync_failed_attempt_dedicated(index); #ifdef GPRS /*XXX*/ else nc_sync_failed_gprs(index); #endif break; default: break; } } else { /* * the cell currently or perhaps for a longer time doesn't * belong to the BA list, no more attempts to synchronize now */ switch (alr_data->nc_data.cell[index].status) { case READ_FB_SB_PENDING: nc_set_status (index, IDLE); break; case READ_SB_PENDING: alr_data->nc_data.cell[index].c_attempt++; alr_data->nc_data.cell[index].tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (index, READ_SB); break; case READ_SB_BCCH_PENDING: alr_data->nc_data.cell[index].c_attempt++; alr_data->nc_data.cell[index].tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (index, READ_SB_BCCH); break; default: break; } } } /* error_flag check */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_check_sync_ind_eotd | +--------------------------------------------------------------------+ PURPOSE : copies the measurement results to the MPH_NCELL_POS_IND while EOTD is active */ LOCAL void nc_check_sync_ind_eotd (T_MPHC_NCELL_SYNC_IND* sync_ind, USHORT arfcn) { T_MPH_NCELL_POS_IND* ppos_ind; if ((ppos_ind = alr_data->nc_data.ppos_ind) EQ NULL) { TRACE_ERROR("nc_check_sync_ind_eotd() while alr_data->nc_data.ppos_ind==0"); return; } if (arfcn EQ alr_data->serving_cell) { if (ppos_ind->eotd_res EQ 0) /*0 doesn't mean EOTD_SUCC here - it indicates that no SC results are present*/ { nc_store_eotd(&(ppos_ind->eotd_sc_res), sync_ind, arfcn); ppos_ind->fn = sync_ind->fn_in_sb; ppos_ind->eotd_res++; } else /*first EOTD results for SC are already present - now continue with second SC results*/ { nc_store_eotd((T_eotd_sc_res*)(&(ppos_ind->eotd_sc_res1)), sync_ind, arfcn); ppos_ind->eotd_res = EOTD_SUCC; ppos_ind->ta = GET_STATE(STATE_NC) EQ NC_DEDICATED ? alr_data->nc_data.tav : NOT_PRESENT_8BIT; PSENDX (RR, ppos_ind); alr_data->nc_data.ppos_ind = NULL; if (alr_data->nc_data.ppos_req NEQ NULL) { PFREE(alr_data->nc_data.ppos_req); alr_data->nc_data.ppos_req = NULL; } } } else { if (ppos_ind->c_eotd_nc_res < MAX_NCELL_EOTD_RES) { nc_store_eotd((T_eotd_sc_res*)( &(ppos_ind->eotd_nc_res[ppos_ind->c_eotd_nc_res])) , sync_ind, arfcn); (ppos_ind->c_eotd_nc_res)++; } else TRACE_ERROR("more than MAX_NCELL_EOTD_RES ncell sync indications"); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_sync_failed_attempt | +--------------------------------------------------------------------+ PURPOSE : A synchronisation attempt has failed during idle mode. */ LOCAL void nc_sync_failed_attempt (USHORT index) { switch (alr_data->nc_data.cell[index].c_attempt) { case 0: case 1: case 2: case 3: /* * for attempts 1 to 4 try it again * after ten seconds */ nc_set_fb_sb_failed (index, TEN_SECONDS); break; default: /* * if there are more attempts, exclude * the cell from further attempts * Store last fieldstrength value */ nc_set_status (index, EXCLUDED); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_sync_failed_attempt_dedicated | +--------------------------------------------------------------------+ PURPOSE : A synchronisation attempt has failed during dedicated mode. */ LOCAL void nc_sync_failed_attempt_dedicated (USHORT index) { /* * Store last fieldstrength value */ switch (alr_data->nc_data.cell[index].c_attempt) { case 0: case 1: case 2: /* * for attempts 1 to 3 try it again immediately */ alr_data->nc_data.cell[index].c_attempt++; if (alr_data->nc_data.cell[index].status EQ READ_FB_SB_PENDING) alr_data->nc_data.cell[index].tim_valid = TV_INVALID_TIMING_INFO; else alr_data->nc_data.cell[index].tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (index, READ_FB_SB); break; default: /* * if there are more attempts, exclude * the cell from further attempts */ nc_set_status (index, EXCLUDED); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_start_dedicated | +--------------------------------------------------------------------+ PURPOSE : Process signal nc_start_dedicated from SDL process Main_Control. */ GLOBAL void nc_start_dedicated (UBYTE pwrc, UBYTE dtx) { USHORT i; switch(GET_STATE(STATE_NC)) { case NC_CON_EST: for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case READ_BCCH_RR_NOT_INFORMED: case FB_SB_SYNC_RR_NOT_INFORMED: case READ_BCCH: /* * BCCH reading is not needed during dedicated mode, * but SB synchronisation is already done. * clear a stored BCCH if needed. */ nc_set_status (i, FB_SB_SYNC); break; case READ_SB_BCCH: nc_set_status (i, READ_SB); break; case READ_FB_SB_PENDING: case READ_SB_PENDING: case READ_SB_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: case READ_BCCH_PENDING: TRACE_ERROR("Abnormal situation nc_start_dedi"); nc_set_status (i, IDLE); break; case FB_SB_FAILED: nc_set_status (i, IDLE); break; case IDLE_SYNC: if (alr_data->nc_data.cell[i].c_sync > 0) alr_data->nc_data.cell[i].c_sync = TEN_SECONDS; break; default: break; } } nc_clear_last_bsic(); alr_data->nc_data.pwrc = pwrc; alr_data->nc_data.dtx = dtx; SET_STATE (STATE_NC, NC_DEDICATED); nc_enable_conf(); break; default: TRACE_ERROR("nc_start_dedicated in wrong state"); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_suspend | +--------------------------------------------------------------------+ PURPOSE : This stops all active processes like FB/SB and BCCH reading if - the mobile start connection establishment - RR requests power measurements parallel to idle mode - leave dedicated mode. */ GLOBAL void nc_suspend (void) { ALR_TRACE_NC( "nc_suspend"); switch (GET_STATE(STATE_NC)) { case NC_IDLE: case NC_DEDICATED: nc_clear_last_bsic(); nc_stop_all(); nc_disable_conf(FREE_POS_IND); SET_STATE(STATE_NC, NC_CON_EST); break; case NC_CON_EST: break; #ifdef GPRS case NC_PIM_PBCCH: if(alr_data->nc_data.cell[LAST_BSIC_REQ].status NEQ IDLE) nc_clear_last_bsic(); /*lint -fallthrough*/ case NC_PTM_PBCCH: nc_stop_all(); nc_disable_conf(FREE_POS_IND); SET_STATE(STATE_NC, NC_CON_EST); break; #endif default: break; } } GLOBAL void nc_suspend_handover (void) { ALR_TRACE_NC( "nc_suspend_handover"); switch (GET_STATE(STATE_NC)) { case NC_DEDICATED: nc_stop_all(); nc_disable_conf(FREE_POS_IND); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : alr_nc | | STATE : code ROUTINE : nc_resume | +--------------------------------------------------------------------+ PURPOSE : Only needed for alr_gprs.c */ GLOBAL void nc_resume (void) { SET_STATE (STATE_NC, NC_IDLE); nc_enable_conf(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_update_dedicated | +--------------------------------------------------------------------+ PURPOSE : Process signal nc_update_dedicated from SDL process Dedi_Control. */ GLOBAL void nc_update_dedicated (UBYTE dtx, UBYTE pwrc) { UBYTE i, j; UBYTE c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; switch(GET_STATE (STATE_NC)) { case NC_DEDICATED: { PALLOC (upd_dedi, MPHC_UPDATE_BA_LIST); /* * updated values of pwrc or dtx can be configure * only by sending a new neighbourcell list to layer 1 */ alr_data->nc_data.pwrc = pwrc; alr_data->nc_data.dtx = dtx; for (i = 0, j = 0; i < c_ba_arfcn; i++) { if (alr_data->nc_data.cell[i].ba_status EQ IN_BA) upd_dedi->chan_list.radio_freq[j++] = ARFCN_TO_L1(alr_data->nc_data.cell[i].ba_arfcn); } upd_dedi->num_of_chans = j; alr_data->nc_data.ba_id = ALR_ALLOCATE_NEW_BA ( alr_data->nc_data.ba_id ); upd_dedi->ba_id = alr_data->nc_data.ba_id; upd_dedi->pwrc = alr_data->nc_data.pwrc; upd_dedi->dtx_allowed = alr_data->nc_data.dtx; alr_data->nc_data.update = TRUE; ma_nc_update_ba_list (upd_dedi); } break; default: TRACE_ERROR("nc_update_dedicated in wrong state"); break; } } GLOBAL void nc_resume_dedicated(void) { nc_enable_conf(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_get_fn_time | +--------------------------------------------------------------------+ PURPOSE : Export Procedure to request frame offset and time alignment of neighbour cells. Returns FALSE if timing information not found. */ GLOBAL BOOL nc_get_fn_time (USHORT channel, ULONG *fn, ULONG *time) { USHORT index; if( channel EQ alr_data->serving_cell) { *fn = 0; *time = 0; return TRUE; } /* Check if we have read SYNC on this channel */ index = nc_get_index (channel); if (index NEQ NOT_PRESENT_16BIT) { *fn = alr_data->nc_data.cell[index].frame_offset; *time = alr_data->nc_data.cell[index].time_align; if( (*fn EQ NOT_PRESENT_32BIT) OR (*time EQ NOT_PRESENT_32BIT)) { return FALSE; } else { return TRUE; } } else { *fn = NOT_PRESENT_32BIT; *time = NOT_PRESENT_32BIT; return FALSE; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_start_reselect | +--------------------------------------------------------------------+ PURPOSE : Process signal nc_start_reselect from SDL process Main_Control. */ GLOBAL void nc_start_reselect (USHORT arfcn) { USHORT index; T_NC *pcell; ALR_TRACE_NC_RESELECT(arfcn); index = nc_get_index (arfcn); if (index EQ NOT_PRESENT_16BIT) { if (arfcn NEQ alr_data->nc_data.cr_cell.ba_arfcn) { ma_error_ind (CS_BCCH_READ_ERROR, arfcn); return; } else { pcell = &alr_data->nc_data.cr_cell; } } else { pcell = &alr_data->nc_data.cell[index]; /* Cannot to reselect to a cell for which the synchronization information * is not available */ if (pcell->bsic EQ NOT_PRESENT_8BIT) { ma_error_ind (CS_NC_SYNC_FAILED, arfcn); return; } } { PALLOC(reselect, MPHC_NEW_SCELL_REQ); reselect->radio_freq = ARFCN_TO_L1(arfcn); reselect->fn_offset = (ULONG)pcell->frame_offset; reselect->time_alignment = (ULONG)pcell->time_align; reselect->tsc = pcell->bsic; alr_data->nc_data.channel = arfcn; ALR_TRACE_NC_FN_TA(index, reselect->fn_offset, reselect->time_alignment); ALR_EM_CONFIGURE_CELL_RESELECTION; ma_new_scell_req(reselect); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_report | +--------------------------------------------------------------------+ PURPOSE : Process signal nc_report from SDL process Main_Control. */ GLOBAL void nc_report (T_MPHC_RXLEV_PERIODIC_IND *rxlev_periodic_ind) { ALR_TRACE_NC("nc_report"); switch(GET_STATE(STATE_NC)) { case NC_IDLE: case NC_CON_EST: nc_store_rxlev (rxlev_periodic_ind); #ifdef GPRS nc_rxlev_sc_req (rxlev_periodic_ind->s_rxlev); #endif nc_check_activity(); break; default: TRACE_ERROR("nc_report in invalid state"); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_report_dedicated | +--------------------------------------------------------------------+ PURPOSE : Process signal nc_report_dedicated from SDL process Main_Control. */ GLOBAL void nc_report_dedicated (T_MPHC_MEAS_REPORT *meas_report) { switch(GET_STATE(STATE_NC)) { case NC_DEDICATED: nc_store_dedicated (meas_report); nc_check_activity (); break; default: TRACE_ERROR("nc_report_dedicated in wrong state"); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_update_list | +--------------------------------------------------------------------+ PURPOSE : Procedure to update frame offset and time alignment after cell change. All values are relative to the actual serving cell. */ #define TDMA_FRAMES_PER_HYPERFRAME 2715648 GLOBAL void nc_update_list (USHORT channel) { USHORT index; USHORT i; switch(GET_STATE(STATE_NC)) { case NC_CON_EST: case NC_DEDICATED: case NC_IDLE: index = nc_get_index (channel); if (index NEQ NOT_PRESENT_16BIT) { for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { if (i NEQ index) { ULONG new_frame_offset; ULONG new_time_align; new_frame_offset = (alr_data->nc_data.cell[i].frame_offset - alr_data->nc_data.cell[index].frame_offset + TDMA_FRAMES_PER_HYPERFRAME) % TDMA_FRAMES_PER_HYPERFRAME; if (alr_data->nc_data.cell[i].time_align >= alr_data->nc_data.cell[index].time_align) { new_time_align = alr_data->nc_data.cell[i].time_align - alr_data->nc_data.cell[index].time_align; } else { new_time_align = 5000 + alr_data->nc_data.cell[i].time_align - alr_data->nc_data.cell[index].time_align; new_frame_offset = (new_frame_offset + 1) % TDMA_FRAMES_PER_HYPERFRAME; } /* time_align */ alr_data->nc_data.cell[i].frame_offset = new_frame_offset; alr_data->nc_data.cell[i].time_align = new_time_align; } /* i NEQ index */ } /* for(all ncells) */ ALR_TRACE_NC("set chan to 0"); alr_data->nc_data.cell[index].frame_offset = 0; alr_data->nc_data.cell[index].time_align = 0; } /* NOT_PRESENT */ break; default: TRACE_ERROR("nc_update_list in invalid state"); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_add_offset | +--------------------------------------------------------------------+ PURPOSE : If the mobile comes back from dedicated mode all synchronized neighbourcells make a status transition to READ_BCCH_RR_NOT_INFORMED. This triggers reading of the neighbourcell BCCH. */ GLOBAL void nc_add_offset (void) { USHORT i; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; for (i = 0; i < c_ba_arfcn; i++) { if (alr_data->nc_data.cell[i].ba_arfcn NEQ alr_data->serving_cell) { /*XXX c_sync should be the same in idle and dedic also for pbcchc so no action here */ switch (alr_data->nc_data.cell[i].status) { case FB_SB_SYNC: case READ_SB: nc_set_status (i, READ_BCCH_RR_NOT_INFORMED); break; default: break; } } else nc_set_status (i, FB_SB_SYNC); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_fill_report_sc_dedi | +--------------------------------------------------------------------+ PURPOSE : Fills the serving cell values for a measurement report. */ GLOBAL void nc_fill_report_sc_dedi (T_MPH_MEASUREMENT_IND *rr_report, UBYTE ncells) { rr_report->valid = TRUE; rr_report->ncells.no_of_ncells = ncells; rr_report->arfcn = alr_data->serving_cell; rr_report->fn_offset = 103; /* average of SDCCH/FACCH */ rr_report->dtx = alr_data->nc_data.act_dtx; rr_report->rx_lev_full = (UBYTE)alr_data->nc_data.rxlev_full; if (rr_report->rx_lev_full > 63) rr_report->rx_lev_full = 63; rr_report->rx_lev_sub = (UBYTE)alr_data->nc_data.rxlev_sub; if (rr_report->rx_lev_sub > 63) rr_report->rx_lev_sub = 63; rr_report->rx_qual_full = alr_data->nc_data.rxqual_full; rr_report->rx_qual_sub = alr_data->nc_data.rxqual_sub; rr_report->otd = alr_data->nc_data.tav; if(ncells EQ 0) { /* * rxlev of SC BCCH channel is not avail * use approx value (rxlev_sub) */ rr_report->bcch_rxlev_of_sc = rr_report->rx_lev_sub; } else { USHORT index = nc_get_index(alr_data->serving_cell); if(index EQ NOT_PRESENT_16BIT) { TRACE_EVENT("Error SC not present in BA list"); rr_report->bcch_rxlev_of_sc = rr_report->rx_lev_sub; } else { if((UBYTE) alr_data->nc_data.cell[index].rxlev_average > 63) rr_report->bcch_rxlev_of_sc = 63; else rr_report->bcch_rxlev_of_sc = (UBYTE)alr_data->nc_data.cell[index].rxlev_average; } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : inform GRR | +--------------------------------------------------------------------+ PURPOSE : inform GRR */ #ifdef GPRS LOCAL void nc_inform_grr_of_ncell (USHORT index, UBYTE type) { PALLOC(rr_rep, MPH_MEASUREMENT_IND); rr_rep->ncells.no_of_ncells = 1; rr_rep->ncells.arfcn[0] = alr_data->nc_data.cell[index].ba_arfcn; if(type EQ GRR_SB_FOUND) rr_rep->ncells.bsic[0] = alr_data->nc_data.cell[index].bsic; else rr_rep->ncells.bsic[0] = type; rr_rep->gprs_sync = SYNC_RESULTS; PSENDX(RR,rr_rep); } LOCAL void remove_ncell_and_inform_grr (USHORT index) { nc_inform_grr_of_ncell (index, GRR_SB_UNKNOWN); nc_remove_channel_from_ba_list(index); } #endif /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_build_rr_report | +--------------------------------------------------------------------+ PURPOSE : Fills a measurement report to RR with neighbour cell information. */ LOCAL void nc_build_rr_report (T_MPH_MEASUREMENT_IND *rr_report) { UBYTE c_report; UBYTE c_ba_list; T_NC * pcell = alr_data->nc_data.cell; c_report = 0; rr_report->valid = TRUE; for (c_ba_list = 0; c_ba_list < alr_data->nc_data.c_ba_arfcn AND c_report < MAX_RR_NCELL_CNT; c_ba_list++, pcell++) { if(pcell->one_of_six AND pcell->ba_status EQ IN_BA) { switch (pcell->status) { case FB_SB_SYNC_RR_NOT_INFORMED: /* * the cell is synchronized but RR has no prior * knowledge of the cell, but we may have already * read data from the ncell BCCH. This check is performed * after sending the measurement report */ case FB_SB_SYNC: case READ_BCCH: case READ_SB: case READ_SB_BCCH: /* * we may be currently reading this SB/FB or BCCH of the cell * pass up this cell also * if READ_FB_SB_PENDING this may be the first time that the * cell is read so check if the bsic of this cell has been * read already */ case READ_SB_PENDING: case READ_SB_BCCH_PENDING: case READ_BCCH_PENDING: case READ_FB_SB_PENDING: if (pcell->ba_arfcn NEQ alr_data->serving_cell AND pcell->bsic NEQ NOT_PRESENT_8BIT) { rr_report->ncells.arfcn[c_report] = pcell->ba_arfcn; rr_report->ncells.rx_lev[c_report] = (UBYTE)pcell->rxlev_average; #if defined(_SIMULATION_) TRACE_EVENT_P3 ("rx_lev%u[%u]=%d", c_report, rr_report->ncells.arfcn[c_report], rr_report->ncells.rx_lev[c_report]); #endif /* _SIMULATION_ */ rr_report->ncells.bsic[c_report] = pcell->bsic; rr_report->ncells.time_alignmt[c_report] = pcell->time_align; rr_report->ncells.frame_offset[c_report++] = pcell->frame_offset; } break; case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH_PENDING_RR_NOT_INFORMED: case READ_FB_SB: /* do nothing */ default: break; } }/* not one_of_six*/ } rr_report->ncells.no_of_ncells = c_report; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_build_nwctrl_rr_report | +--------------------------------------------------------------------+ PURPOSE : Fills a measurement report to RR with neighbour cell information. */ #ifdef GPRS GLOBAL void nc_build_nwctrl_rr_report (T_MPH_MEAS_REP_CNF *rr_report) { UBYTE c_report; UBYTE c_ba_list; USHORT index; T_NC * pcell; /* * Store the rxlev average for the serving cell */ index = nc_get_index(alr_data->serving_cell); if ( index NEQ NOT_PRESENT_16BIT ) { pcell = &alr_data->nc_data.cell[index]; rr_report->meas_rep[0].arfcn = alr_data->serving_cell; rr_report->meas_rep[0].bsic = pcell->bsic; if(pcell->c_nc_rxlev) { rr_report->meas_rep[0].rx_lev = pcell->nc_rxlev/pcell->c_nc_rxlev; } #if defined(_SIMULATION_) TRACE_EVENT_P3 ("nw_sc__rxlev[%u]=acc : %d, count:%d",rr_report->meas_rep[0].arfcn,pcell->nc_rxlev,pcell->c_nc_rxlev); #endif /* _SIMULATION_ */ } c_report = 0; pcell = alr_data->nc_data.cell; for (c_ba_list = 0; c_ba_list < alr_data->nc_data.c_ba_arfcn AND c_report < MAX_RR_NCELL_CNT; c_ba_list++, pcell++) { if(pcell->one_of_six AND pcell->ba_status EQ IN_BA) { switch (pcell->status) { case FB_SB_SYNC_RR_NOT_INFORMED: /* * the cell is synchronized but RR has no prior * knowledge of the cell, but we may have already * read data from the ncell BCCH. This check is performed * after sending the measurement report */ case FB_SB_SYNC: case READ_BCCH: case READ_SB: case READ_SB_BCCH: /* * we may be currently reading this SB/FB or BCCH of the cell * pass up this cell also * if READ_FB_SB_PENDING this may be the first time that the * cell is read so check if the bsic of this cell has been * read already */ case READ_SB_PENDING: case READ_SB_BCCH_PENDING: case READ_BCCH_PENDING: case READ_FB_SB_PENDING: if (pcell->ba_arfcn NEQ alr_data->serving_cell AND pcell->bsic NEQ NOT_PRESENT_8BIT) { rr_report->meas_rep[c_report+1].arfcn = pcell->ba_arfcn; rr_report->meas_rep[c_report+1].bsic = pcell->bsic; if(pcell->c_nc_rxlev) { rr_report->meas_rep[c_report+1].rx_lev = pcell->nc_rxlev/pcell->c_nc_rxlev; } #if defined(_SIMULATION_) TRACE_EVENT_P3 ("nwctrl_rxlev%u[%u]=%d",c_report+1, rr_report->meas_rep[c_report+1].arfcn,rr_report->meas_rep[c_report+1].rx_lev); #endif /* _SIMULATION_ */ c_report++; } break; case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH_PENDING_RR_NOT_INFORMED: case READ_FB_SB: /* do nothing */ default: break; } }/* not one_of_six*/ } if( (c_report + 1 ) < RR_ALR_MEAS_REPORT_SIZE ) { rr_report->meas_rep[c_report+1].arfcn = NOT_PRESENT_16BIT ; rr_report->meas_rep[c_report+1].rx_lev = NOT_PRESENT_8BIT ; rr_report->meas_rep[c_report+1].bsic = NOT_PRESENT_8BIT ; } } #endif /* ifdef GPRS */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_store_tav | +--------------------------------------------------------------------+ PURPOSE : Stores timing advance receveived with dedicated mode SI's */ GLOBAL void nc_store_tav(USHORT tav) { alr_data->nc_data.tav = tav; } /* *======================================================================== * Helper Functions *======================================================================== */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_check_status | +--------------------------------------------------------------------+ PURPOSE : Checks the status of the neighbour cells. */ LOCAL void nc_check_status (UBYTE start_list) { USHORT i; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; T_NC * pcell = alr_data->nc_data.cell; for (i = 0; i < c_ba_arfcn; i++, pcell++) { if (pcell->ba_arfcn NEQ alr_data->serving_cell) { switch (GET_STATE(STATE_NC)) { case NC_DEDICATED: switch (pcell->status) { case INACTIVE: break; case IDLE: if (pcell->one_of_twelve) nc_set_status (i, READ_FB_SB); if (start_list EQ CHECK_FOR_CONFIRM) { if (pcell->tim_valid EQ TV_VALID_TIMING_INFO) pcell->tim_valid = TV_APPROX_TIMING_INFO; else if (pcell->tim_valid EQ TV_APPROX_TIMING_INFO) pcell->tim_valid = TV_INVALID_TIMING_INFO; } break; case READ_FB_SB: if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE); if (start_list EQ CHECK_FOR_CONFIRM AND pcell->tim_valid EQ TV_APPROX_TIMING_INFO) pcell->tim_valid = TV_INVALID_TIMING_INFO; } break; case FB_SB_SYNC: if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } else { if ( (start_list) AND (alr_data->nc_data.c_sync_intrupted EQ FALSE)) nc_set_status (i, READ_SB); } break; case IDLE_SYNC: if (pcell->one_of_twelve) { if (pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); else nc_set_status (i, FB_SB_SYNC); } else { if (pcell->c_sync EQ 0) { nc_set_status (i, IDLE); } } break; case READ_SB: if (pcell->one_of_twelve EQ FALSE) { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } break; case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH: case READ_SB_BCCH: TRACE_EVENT("unexpected STATE_NC during NC_DEDICATED"); if (pcell->one_of_twelve) nc_set_status (i, READ_FB_SB); else { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } break; case FB_SB_FAILED: if (pcell->one_of_twelve EQ FALSE) nc_set_status (i, IDLE); else if (pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); break; default: break; } break; case NC_IDLE: switch (pcell->status) { case INACTIVE: break; case IDLE: if (pcell->one_of_twelve) nc_set_status (i, READ_FB_SB); if (start_list EQ CHECK_FOR_CONFIRM) { if (pcell->tim_valid EQ TV_VALID_TIMING_INFO) pcell->tim_valid = TV_APPROX_TIMING_INFO; else if (pcell->tim_valid EQ TV_APPROX_TIMING_INFO) pcell->tim_valid = TV_INVALID_TIMING_INFO; } break; case READ_FB_SB: if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE); if (start_list EQ CHECK_FOR_CONFIRM AND pcell->tim_valid EQ TV_APPROX_TIMING_INFO) pcell->tim_valid = TV_INVALID_TIMING_INFO; } break; case FB_SB_SYNC: if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } else { if (start_list) nc_set_status (i, READ_SB); if (pcell->one_of_six AND pcell->c_bcch EQ 0) nc_set_status (i, READ_SB_BCCH); } break; case FB_SB_SYNC_RR_NOT_INFORMED: if (pcell->one_of_six EQ FALSE) { if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } else { nc_set_status (i, FB_SB_SYNC); } } break; case FB_SB_FAILED: if (pcell->one_of_twelve EQ FALSE) nc_set_status (i, IDLE); else if (pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); break; case IDLE_SYNC: if (pcell->one_of_twelve) { if(pcell->one_of_six) { if (pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); else nc_set_status (i, READ_BCCH_RR_NOT_INFORMED); } else { if (pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); else nc_set_status (i, FB_SB_SYNC); } } else { if (pcell->c_sync EQ 0) { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } } break; case READ_SB: if (pcell->one_of_twelve EQ FALSE) { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } else { if (pcell->c_bcch EQ 0) nc_set_status (i, READ_SB_BCCH); } break; case READ_BCCH: if (pcell->one_of_six EQ FALSE) { if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } else { nc_set_status (i, FB_SB_SYNC); } } break; case READ_BCCH_RR_NOT_INFORMED: if (pcell->one_of_six EQ FALSE) { if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } else { nc_set_status (i, FB_SB_SYNC); } } break; case READ_SB_BCCH: if (pcell->one_of_six EQ FALSE) { if (pcell->one_of_twelve) nc_set_status(i, READ_SB); else { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } } break; default: break; } break; #ifdef GPRS case NC_PIM_PBCCH: case NC_PTM_PBCCH: /*XXX*/ case NC_CON_EST: /*in case of an updated list in CON_EST */ switch (pcell->status) { case IDLE: if(pcell->one_of_twelve) nc_set_status (i, READ_FB_SB); if (start_list EQ CHECK_FOR_CONFIRM) { if (pcell->tim_valid EQ TV_VALID_TIMING_INFO) pcell->tim_valid = TV_APPROX_TIMING_INFO; else if (pcell->tim_valid EQ TV_APPROX_TIMING_INFO) pcell->tim_valid = TV_INVALID_TIMING_INFO; } break; case FB_SB_SYNC: if(pcell->one_of_twelve EQ FALSE) nc_set_status (i, IDLE_SYNC); else { if (start_list) nc_set_status (i, READ_SB); } break; case FB_SB_FAILED: if(pcell->one_of_twelve EQ FALSE) remove_ncell_and_inform_grr(i); else if(pcell->c_sync EQ 0) nc_set_status (i, READ_FB_SB); break; case READ_FB_SB: break; case READ_SB: if (pcell->one_of_twelve EQ FALSE) { pcell->tim_valid = TV_APPROX_TIMING_INFO; nc_set_status (i, IDLE); } break; case IDLE_SYNC: if(pcell->c_sync EQ 0) remove_ncell_and_inform_grr(i); else { if(pcell->one_of_twelve) nc_set_status (i, FB_SB_SYNC); } break; case READ_BCCH_RR_NOT_INFORMED: case READ_BCCH: case FB_SB_SYNC_RR_NOT_INFORMED: if (pcell->one_of_twelve EQ FALSE) { nc_set_status (i, IDLE_SYNC); } break; default: TRACE_EVENT_P4("wrong state in check_st: i%d a%d 1o6%d st%d", i, pcell->ba_arfcn, pcell->one_of_six, pcell->status); break; } #endif break; default: break; }/*switch state*/ } /*if*/ } /*for*/ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_build_rr_report_dedi | +--------------------------------------------------------------------+ PURPOSE : Fills a measurement report to RR with neighbour cell information in dedicated mode. In dedicated mode the serving cell may be included. */ LOCAL void nc_build_rr_report_dedi (T_MPH_MEASUREMENT_IND *rr_report) { UBYTE c_report = 0; UBYTE c_ba_list; UBYTE found = TRUE; UBYTE index; UBYTE i; UBYTE in_report[34]; T_NC * pcell1; memset (in_report, 0, 34); for ( i = 0; i < 6 AND found EQ TRUE; i++) { found = FALSE; index = NOT_PRESENT_8BIT; pcell1 = alr_data->nc_data.cell; for (c_ba_list = 0; c_ba_list < alr_data->nc_data.c_ba_arfcn; c_ba_list++, pcell1++) { if (in_report[c_ba_list] EQ FALSE AND pcell1->ba_status EQ IN_BA) { switch (pcell1->status) { case FB_SB_SYNC: case READ_SB: case READ_SB_PENDING: if (nc_ncell_in_plmn_permitted(pcell1->bsic)) { if ((pcell1->ba_arfcn NEQ alr_data->serving_cell AND pcell1->one_of_six) OR (pcell1->ba_arfcn EQ alr_data->serving_cell AND alr_data->nc_data.sc_included)) { if (index EQ NOT_PRESENT_8BIT) index = c_ba_list; else { if (pcell1->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) index = c_ba_list; } } } break; } } } if (index NEQ NOT_PRESENT_8BIT) { T_NC* pcell = &alr_data->nc_data.cell[index]; found = TRUE; in_report[index] = TRUE; rr_report->ncells.arfcn[c_report] = pcell->ba_arfcn; if ((UBYTE)pcell->rxlev_average > 63) rr_report->ncells.rx_lev[c_report] = 63; else rr_report->ncells.rx_lev[c_report] = (UBYTE)pcell->rxlev_average; rr_report->ncells.bsic[c_report] = pcell->bsic; rr_report->ncells.time_alignmt[c_report] = pcell->time_align; rr_report->ncells.frame_offset[c_report++] = pcell->frame_offset; } } /*for (up to 6 ncells)*/ /* * insert serving cell values */ nc_fill_report_sc_dedi (rr_report, c_report); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_rank_ncells | +--------------------------------------------------------------------+ PURPOSE : Searches for the six and additionally the twelve strongest neighbourcells. */ LOCAL void nc_rank_ncells (void) { USHORT c_found, i; USHORT last = (sizeof alr_data->nc_data.cell / sizeof alr_data->nc_data.cell[0]); UBYTE old_1of6[ sizeof alr_data->nc_data.cell / sizeof alr_data->nc_data.cell[0] ]; UBYTE num_1of6, hyst_rxlev, nc_conf_active = FALSE; num_1of6 = 0; hyst_rxlev = 63; alr_data->nc_data.new_strong_cell_detect = FALSE; for ( i = 0; i < last; i++ ) { old_1of6[i] = alr_data->nc_data.cell[i].one_of_six; alr_data->nc_data.cell[i].new_strong_cell = FALSE; if(old_1of6[i]) { num_1of6++; if(alr_data->nc_data.cell[i].rxlev_average < hyst_rxlev) hyst_rxlev = alr_data->nc_data.cell[i].rxlev_average; } alr_data->nc_data.cell[i].one_of_six = FALSE; } if(num_1of6 < MAX_RR_NCELL_CNT) hyst_rxlev = 0; if((GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) AND (GET_STATE(STATE_NC) EQ NC_DEDICATED) AND (!alr_data->nc_data.eotd_avail)) nc_conf_active = TRUE; c_found = 0; if ((std EQ STD_DUAL) OR (std EQ STD_DUAL_EGSM) OR (std EQ STD_DUAL_US)) { switch (alr_data->nc_data.multiband) { case MULTI_BAND_0: /* Find 6 cells from any band */ nc_find_cells (&c_found, MAX_RR_NCELL_CNT, NO_BAND_LIMITATION, ALR_RXLEV_AVERAGE_MIN); break; case MULTI_BAND_1: /* Find 1 cell from bands other than Serving cell band */ nc_find_cells (&c_found, 1, EXCLUDE_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* Find 5 cells from the Serving cell band */ nc_find_cells (&c_found, MAX_RR_NCELL_CNT-1, ONLY_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* If number of found cells are less than six, find the remaining from any band. * Also relax the Rxlev criteria */ nc_find_cells (&c_found, (USHORT)(MAX_RR_NCELL_CNT - c_found), NO_BAND_LIMITATION, ALR_RXLEV_AVERAGE_MIN); break; case MULTI_BAND_2: /* Find 2 cell from bands other than Serving cell band */ nc_find_cells (&c_found, 2, EXCLUDE_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* Find 4 cells from the Serving cell band */ nc_find_cells (&c_found, MAX_RR_NCELL_CNT-2, ONLY_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* If number of found cells are less than six, find the remaining from any band. * Also relax the Rxlev criteria */ nc_find_cells (&c_found, (USHORT)(MAX_RR_NCELL_CNT - c_found), NO_BAND_LIMITATION, ALR_RXLEV_AVERAGE_MIN); break; case MULTI_BAND_3: /* Find 3 cell from bands other than Serving cell band */ nc_find_cells (&c_found, 3, EXCLUDE_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* Find 3 cells from the Serving cell band */ nc_find_cells (&c_found, MAX_RR_NCELL_CNT-3, ONLY_SC_BAND, ALR_RXLEV_AVERAGE_LWR_THR); /* If number of found cells are less than six, find the remaining from any band. * Also relax the Rxlev criteria */ nc_find_cells (&c_found, (USHORT)(MAX_RR_NCELL_CNT - c_found), NO_BAND_LIMITATION, ALR_RXLEV_AVERAGE_MIN); break; } } else nc_find_cells (&c_found, MAX_RR_NCELL_CNT, NO_BAND_LIMITATION, ALR_RXLEV_AVERAGE_MIN); for ( i = 0; i < last; i++ ) { if (alr_data->nc_data.cell[i].one_of_six AND !old_1of6[i] AND GET_STATE(STATE_NC) NEQ NC_DEDICATED) { /* the cell becomes one of six */ switch (alr_data->nc_data.cell[i].status) { case FB_SB_SYNC: /* the cell is treaded as synchronized, perform BCCH reading ASAP */ nc_set_status(i, READ_BCCH_RR_NOT_INFORMED); break; case READ_SB: case IDLE_SYNC: case FB_SB_FAILED: /* the cell shall be synchronized ASAP, then BCCH info is to send to RR */ nc_set_status(i, READ_FB_SB); break; case READ_SB_PENDING: /* after receipt of sync ind the BCCH is to read and to send to RR */ nc_set_status(i, READ_FB_SB_PENDING); break; default: break; } } if (old_1of6[i] AND !alr_data->nc_data.cell[i].one_of_six AND alr_data->nc_data.cell[i].status EQ FB_SB_SYNC) alr_data->nc_data.cell[i].c_attempt = 0; /* Check the new strong cell criteria when confirmation is active */ if(nc_conf_active) { nc_check_new_strong_cell(i, old_1of6[i], hyst_rxlev); } } nc_find_list_cells(); TRACE_EVENT_P1("New strong cell detect:%d", alr_data->nc_data.new_strong_cell_detect); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_find_cells | +--------------------------------------------------------------------+ PURPOSE : Searches for the six strongest neighbourcells, using multiband parameter if needed. Called only in case of the value of 'std' is set to STD_DUAL, STD_DUAL_EGSM or STD_DUAL_US. (And therefore only for the combination of GSM900/E-GSM/DCS1800 or GSM850/PCS1900.) */ LOCAL void nc_find_cells (USHORT *c_found, USHORT max, UBYTE limitation, UBYTE min_rxlev) { int i, j; BOOL limit; int index; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; T_NC* pcell; UBYTE band_nc; UBYTE band_sc = get_band (alr_data->serving_cell); if (*c_found >= MAX_RR_NCELL_CNT) return; if (band_sc EQ BAND_E_GSM) band_sc = BAND_GSM_900; /* equal treatment of E-GSM and GSM900 */ for (j = 0, index = 0; (j < max) AND (index NEQ NOT_PRESENT_16BIT); j++) { index = NOT_PRESENT_16BIT; for (i = 0; i < c_ba_arfcn; i++) { pcell = &alr_data->nc_data.cell[i]; /* * The six strongest neighbour cells do not include cells * currently not belonging to BA list */ if (pcell->ba_status NEQ IN_BA) continue; switch (pcell->status) { case INACTIVE: case EXCLUDED: /* * The six strongest neighbour cells do not include failed ncells. */ break; default: if (pcell->ba_arfcn NEQ alr_data->serving_cell AND pcell->one_of_six EQ FALSE AND pcell->rxlev_average > min_rxlev) /* > -106 dBm */ { band_nc = get_band (pcell->ba_arfcn); if (band_nc EQ BAND_E_GSM) band_nc = BAND_GSM_900; /* equal treatment of E-GSM and GSM900 */ switch (limitation) { default: case NO_BAND_LIMITATION: limit = FALSE; break; case EXCLUDE_SC_BAND: limit = (band_sc EQ band_nc); break; case ONLY_SC_BAND: limit = (band_sc NEQ band_nc); break; } if (!limit) { if (index EQ NOT_PRESENT_16BIT) { index = i; } else { if (pcell->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) { index = i; } } } } break; } /*ncell status*/ } if (index NEQ NOT_PRESENT_16BIT) { alr_data->nc_data.cell[index].one_of_six = TRUE; (*c_found)++; } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_find_list_cells | +--------------------------------------------------------------------+ PURPOSE : Searches for the 6 or 12 strongest neighbourcells */ LOCAL void nc_find_list_cells (void) { USHORT i, j; UBYTE found, c_found = 0; USHORT index; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; T_NC* pcell; for (i = 0, pcell = &alr_data->nc_data.cell[0]; i < c_ba_arfcn; i++, pcell++ ) { if ((pcell->one_of_twelve = pcell->one_of_six) EQ TRUE) c_found++; } /* * The flag one_of_six controls the property to include a neighbour cell * into the measurement report, * the flag one_of_twelve controls whether the ncell is included into the * synchronisation confirmation process. In case of EOTD up to 12 cell are * included, in case of non-EOTD 6 cells are sufficient. */ if (!alr_data->nc_data.eotd_avail) return; for (j = c_found, found = TRUE; (j < MAX_L1_SYNC_CNT) AND (found EQ TRUE); j++) { index = NOT_PRESENT_16BIT; found = FALSE; for (i = 0; i < c_ba_arfcn; i++) { pcell = &alr_data->nc_data.cell[i]; /* * The 12 strongest neighbour cells do not include ncells currently not belonging to BA list. */ if (pcell->ba_status NEQ IN_BA) continue; switch (pcell->status) { case INACTIVE: case EXCLUDED: /* * The 12 strongest neighbour cells do not include failed ncells. */ break; default: if (pcell->ba_arfcn NEQ alr_data->serving_cell AND pcell->one_of_twelve EQ FALSE AND pcell->rxlev_average > ALR_RXLEV_AVERAGE_MIN) /* > -110 dBm */ { if (index EQ NOT_PRESENT_16BIT) { index = i; found = TRUE; } else { if (pcell->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) { index = i; found = TRUE; } } } break; } /*ncell status*/ } if (found AND (index NEQ NOT_PRESENT_16BIT)) alr_data->nc_data.cell[index].one_of_twelve = TRUE; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_store_rxlev | +--------------------------------------------------------------------+ PURPOSE : Stores the fieldstrength values of the neighbour cells. Calculates the average of the fieldstrength after five samples. */ LOCAL void nc_store_rxlev (T_MPHC_RXLEV_PERIODIC_IND *report) { USHORT i; USHORT index; UBYTE diff; int max_attempt; T_NC* pcell; ALR_TRACE_NC("store rxlev"); /* * Patch for 20.5 * The fieldstrength average for a new channel * increases too slow if more then eight channels * are in the neighbourcell list, because layer 1 * sends not raw data every paging period. */ if (test_house AND alr_data->nc_data.c_ba_arfcn > 8) max_attempt = 3; else max_attempt = 5; if (alr_data->nc_data.tim_state NEQ NC_TIM_STOPPED) { /* Decrement the 10sec timer counter variable by BS_PA_MFRMS */ alr_data->nc_data.c_ncsync_tim = (UBYTE)(alr_data->nc_data.c_ncsync_tim - alr_data->bs_pa_mfrms - 2); if ((signed char)(alr_data->nc_data.c_ncsync_tim) < 0) alr_data->nc_data.c_ncsync_tim = 0; if( alr_data->nc_data.c_ncsync_tim EQ 0 ) nc_ncsync_tim_expiry(); /* 10 sec have elapsed. Perform all requisite tasks */ } /* serving cell rxlev storage */ index = nc_get_index (alr_data->serving_cell); pcell = &alr_data->nc_data.cell[index]; if ( (signed char)report->s_rxlev < 0) report->s_rxlev = 0; if (pcell->c_rxlev EQ NOT_PRESENT_8BIT) { pcell->c_rxlev = 0; memset (pcell->rxlev, report->s_rxlev, 5); } else { pcell->rxlev[pcell->c_rxlev++] = report->s_rxlev; } pcell->c_rxlev %= 5; /* * store the results seperately for averaging when NC=1 or NC=2 */ #ifdef GPRS if(alr_data->nwctrl_meas_active) { pcell->nc_rxlev += report->s_rxlev; pcell->c_nc_rxlev++; } #endif /* * ncell rxlev storage */ for (i = 0; i < report->nbr_of_carriers; i++) { /* * The RX level from TI is signed in the SAP * we define it as unsigned */ if ((signed char) (report->result[i].rxlev) < 0) { report->result[i].rxlev = 0; } index = nc_get_index (ARFCN_TO_G23(report->result[i].radio_freq)); if (index NEQ NOT_PRESENT_16BIT AND index NEQ LAST_BSIC_REQ AND ARFCN_TO_G23(report->result[i].radio_freq) NEQ alr_data->serving_cell) { int temp; UBYTE rxlev = report->result[i].rxlev; pcell = &alr_data->nc_data.cell[index]; if (pcell->c_rxlev EQ NOT_PRESENT_8BIT) { /* * if it is a new cell, build an average from the first value * to speed up fb sb read */ pcell->rxlev[0] = rxlev; pcell->rxlev[1] = rxlev; pcell->rxlev[2] = rxlev; pcell->rxlev[3] = rxlev; pcell->rxlev[4] = rxlev; pcell->c_rxlev = 0; } else { pcell->rxlev[pcell->c_rxlev++] = rxlev; if (pcell->c_rxlev >= (UBYTE)max_attempt) pcell->c_rxlev = 0; } temp = pcell->rxlev[0] + pcell->rxlev[1] + pcell->rxlev[2]; if (max_attempt EQ 5) { temp += pcell->rxlev[3] + pcell->rxlev[4]; } pcell->rxlev_average = (UBYTE)(temp / max_attempt); /* * store the results seperately for averaging when NC=1 or NC=2 */ #ifdef GPRS if(alr_data->nwctrl_meas_active) { pcell->nc_rxlev += rxlev; pcell->c_nc_rxlev++; } #endif #if defined(TRACING) TRACE_EVENT_P4("NC%u[%d] rx=%d av=%d", index, pcell->ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : pcell->ba_arfcn&ARFCN_MASK, report->result[i].rxlev, pcell->rxlev_average); #endif /* TRACING */ switch (pcell->status) { case INACTIVE: nc_set_status (index, IDLE); break; case EXCLUDED: diff = (UBYTE)(pcell->rxlev_average - pcell->last_rxlev); if (diff < 128 AND diff >= 6) { /* * result is positive and more than 6 dBm */ nc_set_status (index, IDLE); } break; default: break; } } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_find_serving_cell_entry | +--------------------------------------------------------------------+ PURPOSE : Finds an entry for serving cell in the BCCH allocation list. */ LOCAL T_NC* nc_find_serving_cell_entry (USHORT serving_cell) { T_NC* pcell; USHORT i; UBYTE last_alr = alr_data->nc_data.c_ba_arfcn; if (last_alr < LAST_BSIC_REQ) { pcell = &alr_data->nc_data.cell[last_alr]; #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] add", last_alr, serving_cell); #endif /* TRACING */ alr_data->nc_data.c_ba_arfcn = last_alr+1; /* store new last index */ i = last_alr; ALR_TRACE_ALL_NC (); } else { /* ALR list is full, search for an entry not in state IN_BA */ for (i = 0, pcell = alr_data->nc_data.cell; i < LAST_BSIC_REQ; i++, pcell++) { if (pcell->ba_status NEQ IN_BA) break; } /* for (i...) */ if (i >= LAST_BSIC_REQ) { /* * no entry found * reuse the last entry to make sure there is a place for serving cell */ i = LAST_BSIC_REQ-1; pcell = &alr_data->nc_data.cell[i]; } nc_stop_if_active(i); #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] replace", i, serving_cell); #endif /* TRACING */ } nc_set_status (i, FB_SB_SYNC); pcell->ba_status = IN_BA; /* even if not in the BA but other functions need it */ pcell->ba_arfcn = serving_cell; return pcell; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_add_serving_cell_ba_list| +--------------------------------------------------------------------+ PURPOSE : Adds serving cell to neighbourcell list. This function is called just before nc_start_reselect and not after the MPHC_NEW_SCELL_CNF. */ LOCAL void nc_add_serving_cell_ba_list (USHORT serving_cell) { USHORT index = nc_get_index (serving_cell); T_NC* pcell; /* * Add serving cell if not included */ switch (index) { case NOT_PRESENT_16BIT: case LAST_BSIC_REQ: /* serving cell isn´t inside the BA list */ pcell = nc_find_serving_cell_entry(serving_cell); pcell->bsic = alr_data->nc_data.cr_cell.bsic; pcell->frame_offset = alr_data->nc_data.cr_cell.frame_offset; pcell->time_align = alr_data->nc_data.cr_cell.time_align; break; default: if (index < ELEMENTS(alr_data->nc_data.cell)) { /* serving cell is already included in ba list */ /* For GPRS the scell may not be in FB_SB_SYNC so put it there */ pcell = &alr_data->nc_data.cell[index]; /* Check whether the cell has valid sync info */ if (pcell->bsic NEQ NOT_PRESENT_8BIT) { nc_set_status(index, FB_SB_SYNC); alr_data->nc_data.cell[index].one_of_six = FALSE; alr_data->nc_data.cell[index].ba_status = IN_BA; /* even if not in the BA but other functions need it */ } } break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_update_ba_list | +--------------------------------------------------------------------+ PURPOSE : Updates the BCCH allocation list. */ LOCAL void nc_update_ba_list (USHORT serving_cell, T_MPH_NEIGHBOURCELL_REQ *ncell_list) { USHORT n_rr; /* index of RR neighbor cell list */ USHORT n_alr; /* index of ALR neighbor cell list */ UBYTE last_alr; /* last index of ALR neighbor cell list */ USHORT arfcn; T_NC* pcell; alr_data->nc_data.multiband = ncell_list->multi_band; /* * remove or mark all channels which are not longer member of the * neighbour cell list. */ last_alr = alr_data->nc_data.c_ba_arfcn; /* current last index */ for (n_alr = 0; n_alr < last_alr; n_alr++) { pcell = &alr_data->nc_data.cell[n_alr]; arfcn = pcell->ba_arfcn; if (!nc_is_in_ncell_list (arfcn, ncell_list) AND (arfcn NEQ serving_cell)) { if (GET_STATE(STATE_NC) EQ NC_IDLE) { /* the RR neighbor cell list is complete */ last_alr = nc_remove_channel_from_ba_list (n_alr); #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] remove", n_alr, arfcn); #endif /* TRACING */ n_alr--; ALR_TRACE_ALL_NC (); } else { /* the RR neighbor cell list may be incomplete so mark only the entry */ if (pcell->ba_status EQ IN_BA) { pcell->ba_status = NOT_IN_BA_SHORT; #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] -> NOT_IN_BA_SHORT", n_alr, arfcn); #endif /* TRACING */ } } } } /* * add all new channels. */ for (n_rr = 0; n_rr < MAX_NEIGHBOURCELLS; n_rr++) { arfcn = ncell_list->arfcn[n_rr]; if (arfcn EQ NOT_PRESENT_16BIT) break; /* no more entries in the RR ncell_list */ n_alr = nc_get_index (arfcn); if (arfcn NEQ serving_cell) { if (n_alr EQ NOT_PRESENT_16BIT OR n_alr EQ LAST_BSIC_REQ) { if (last_alr < BA_LIST_SIZE) { pcell = &alr_data->nc_data.cell[last_alr]; #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] add", last_alr, arfcn); #endif /* TRACING */ pcell->ba_arfcn = arfcn; nc_set_status (last_alr, INACTIVE); pcell->ba_status = IN_BA; last_alr++; /* increment last index */ } else { /* ALR list is full, search for an entry not in state IN_BA */ USHORT i; for (i = 0, pcell = alr_data->nc_data.cell; i < BA_LIST_SIZE; i++, pcell++) { if (pcell->ba_status NEQ IN_BA AND pcell->ba_arfcn NEQ serving_cell) { nc_stop_if_active(i); #if defined(TRACING) TRACE_EVENT_P2 ("NC%u[%u] replace", i, arfcn); #endif /* TRACING */ pcell->ba_arfcn = arfcn; nc_set_status (i, INACTIVE); pcell->ba_status = IN_BA; break; } } /* for (i...) */ } } else { #if defined(TRACING) if (alr_data->nc_data.cell[n_alr].ba_status NEQ IN_BA) TRACE_EVENT_P2 ("NC%u[%u] -> IN_BA", n_alr, arfcn); #endif alr_data->nc_data.cell[n_alr].ba_status = IN_BA; } } /* if (arfcn NEQ serving_cell) */ } /* * store whether SC was included into the BA list by the net */ if (nc_is_in_ncell_list (serving_cell, ncell_list)) { alr_data->nc_data.sc_included = TRUE; } else { alr_data->nc_data.sc_included = FALSE; } alr_data->nc_data.c_ba_arfcn = last_alr; /* store new last index */ /* * Add serving cell if not included */ n_alr = nc_get_index (serving_cell); switch (n_alr) { case NOT_PRESENT_16BIT: case LAST_BSIC_REQ: pcell = nc_find_serving_cell_entry(serving_cell); pcell->bsic = alr_data->bsic; pcell->frame_offset = 0; pcell->time_align = 0; break; default: /* serving cell is already included */ pcell = &alr_data->nc_data.cell[n_alr]; pcell->bsic = alr_data->bsic; pcell->frame_offset = 0; pcell->time_align = 0; pcell->ba_status = IN_BA; /* even if not in the BA but other functions need it */ nc_set_status (n_alr, FB_SB_SYNC); /* make sure the SC is reported in measurement reports if included into BA list */ break; } /* * reset status of neighbour cells with failed * synchronisation attempts. */ for (n_alr = 0; n_alr < last_alr; n_alr++) { switch (alr_data->nc_data.cell[n_alr].status) { case FB_SB_FAILED: case EXCLUDED: alr_data->nc_data.cell[n_alr].tim_valid = TV_INVALID_TIMING_INFO; nc_set_status (n_alr, IDLE); break; } } /* * Reorder the entries. The goal is that the propably strongest neigbour cells * are measured in the first measurement period of a subsequent * MPHC_RXLEV_PERIODIC_REQ/IND. The appropriate arfcn's are the first ones in * ncell_list->arfcn */ if (last_alr > 8) { T_NC temp, *prr, *palr; for (n_rr = 0; n_rr < 8 && ncell_list->arfcn[n_rr] NEQ NOT_PRESENT_16BIT; n_rr++) { n_alr = nc_get_index (ncell_list->arfcn[n_rr]); if (n_rr NEQ n_alr) { palr = &(alr_data->nc_data.cell[n_alr]); prr = &(alr_data->nc_data.cell[n_rr]); memcpy(&temp, palr, sizeof(T_NC)); memcpy(palr, prr, sizeof(T_NC)); memcpy(prr, &temp, sizeof(T_NC)); /*TRACE_EVENT_P4("reordered NC%u[%u] and NC%u[%u]", n_rr, ncell_list->arfcn[n_rr], n_alr, ncell_list->arfcn[n_alr]);*/ } } } ALR_TRACE_ALL_NC (); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_new_serving_cell | +--------------------------------------------------------------------+ PURPOSE : Store old, set new serving cell, and add to neighbourcell list. */ GLOBAL void nc_new_serving_cell (USHORT serving_cell) { alr_data->old_serving_cell = alr_data->serving_cell; alr_data->serving_cell = serving_cell; alr_data->sc_band = get_band (alr_data->serving_cell); nc_add_serving_cell_ba_list(serving_cell); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_is_in_ncell_list | +--------------------------------------------------------------------+ PURPOSE : Checks whether a channel is in the ncell_list of RR. */ LOCAL UBYTE nc_is_in_ncell_list (USHORT channel, T_MPH_NEIGHBOURCELL_REQ *ncell_list) { USHORT i; for (i = 0; i < MAX_NEIGHBOURCELLS AND ncell_list->arfcn[i] NEQ NOT_PRESENT_16BIT; i++) { if (channel EQ ncell_list->arfcn[i]) return TRUE; } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_remove_channel_from_ba_list | +--------------------------------------------------------------------+ PURPOSE : Removes one channel from the BCCH allocation. */ LOCAL UBYTE nc_remove_channel_from_ba_list (USHORT index) { USHORT i; UBYTE c_ba_arfcn; switch(alr_data->nc_data.cell[index].status) { case READ_SB_PENDING: case READ_SB_BCCH_PENDING: if ( alr_data->nc_data.eotd_avail AND ( GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) ) { /* we cannot stop this * because we are using a list_req */ nc_set_status(index, INACTIVE); break; } /*lint -fallthrough*/ case READ_FB_SB_PENDING: /* * sync request is ongoing in layer 1. */ nc_stop_sync (index, INACTIVE); break; case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: /* * stop pending BCCH request */ nc_stop_bcch (index, INACTIVE); break; default: nc_set_status (index, INACTIVE); break; } c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; for (i = index + 1; i < c_ba_arfcn; i++) { memcpy (&alr_data->nc_data.cell[i - 1],&alr_data->nc_data.cell[i],sizeof(T_NC)); /*shift NC*/ } memset (&alr_data->nc_data.cell[i - 1],0,sizeof (T_NC));/*delete old content of obsolete ba_list entry*/ alr_data->nc_data.c_ba_arfcn--; return (alr_data->nc_data.c_ba_arfcn); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_get_index | +--------------------------------------------------------------------+ PURPOSE : Calculates the index in the BCCH allocation. */ GLOBAL USHORT nc_get_index (USHORT arfcn) { USHORT i; T_NC *pcell; /* use pointer to increase processing speed */ USHORT last_alr; /* last index of ALR neighbor cell list */ last_alr = alr_data->nc_data.c_ba_arfcn; pcell = &alr_data->nc_data.cell[0]; /* pointer to first cell */ for (i = 0; i < last_alr; i++, pcell++) { if (arfcn EQ pcell->ba_arfcn) return i; } if (arfcn EQ alr_data->nc_data.cell[LAST_BSIC_REQ].ba_arfcn) return LAST_BSIC_REQ; return NOT_PRESENT_16BIT; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_build_sync_req | +--------------------------------------------------------------------+ PURPOSE : Builds an MPHC_NCELL_SYNC_REQ and sends it to L1. */ LOCAL void nc_build_sync_req (USHORT index) { T_NC * p_ncell = &alr_data->nc_data.cell[index]; PALLOC (sync_req, MPHC_NCELL_SYNC_REQ); sync_req->radio_freq = ARFCN_TO_L1(p_ncell->ba_arfcn); if (p_ncell->tim_valid EQ TV_INVALID_TIMING_INFO) { sync_req->fn_offset = 0; sync_req->time_alignment = 0; } else { sync_req->fn_offset = p_ncell->frame_offset; sync_req->time_alignment = p_ncell->time_align; } sync_req->timing_validity = p_ncell->tim_valid; TRACE_EVENT_P4("nc_build_sync_req[%d] timing_validity=%d fn_offset=%ld, time_alignment=%ld", p_ncell->ba_arfcn, sync_req->timing_validity, sync_req->fn_offset, sync_req->time_alignment); ma_nc_sync_req (sync_req); ALR_EM_READ_NEIGHBOURCELL_SB; nc_set_status (index, READ_FB_SB_PENDING); alr_data->nc_data.c_sync_req++; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_status | +--------------------------------------------------------------------+ PURPOSE : Starts a specific procedure for neighbour cells like synchronisation to frequency correction burst and synchron burst, confirmation of synchron burst or reading of BCCH. With the new ALR interface it's possible to send up to 12 SYNC_REQ's and BCCH_REQ's. */ LOCAL void nc_process_status (void) { UBYTE st = GET_STATE(STATE_NC); /* Sync requests for New cells are allowed only in dedicated state * when eotd is not enabled. Fix for */ if(((alr_data->nc_data.eotd_avail) OR ( st NEQ NC_DEDICATED)) AND (GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM)) return; #ifdef GPRS if((st EQ NC_IDLE AND !ma_is_ptm()) OR st EQ NC_PIM_PBCCH ) nc_process_status_last_bsic(); #else nc_process_status_last_bsic(); #endif if(alr_data->plmn_search_running) return; #ifdef GPRS if(st EQ NC_PIM_PBCCH OR st EQ NC_PTM_PBCCH ) nc_process_status_sync_gprs(); else #endif nc_process_status_sync(); if(st EQ NC_IDLE) nc_process_status_bcch(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_status_last_bsic| +--------------------------------------------------------------------+ PURPOSE : When doing idle mode cell selection we use LAST_BSIC_REQ for storing the information of the cell. This has priority over normal neighbour cell monitoring. */ LOCAL void nc_process_status_last_bsic(void) { T_NC* pbsic = &alr_data->nc_data.cell[LAST_BSIC_REQ]; switch (pbsic->status) { case READ_FB_SB: if (alr_data->nc_data.c_sync_req < MAX_L1_SYNC_CNT) { pbsic->tim_valid = TV_INVALID_TIMING_INFO; nc_build_sync_req (LAST_BSIC_REQ); ALR_TRACE_NC ("ncell_sync_req HPLMN"); /* If the Mobile is in page mode REORG the NC search cannot be * performed because L1 is too busy listening to the PCH. Therefore * the page mode is changed from REORG to REORG_NC_SYNC (NORMAL). */ if(alr_data->pch_data.pl_idle.page_mode EQ PGM_REORG OR alr_data->pch_data.pl_idle.page_mode EQ PGM_REORG_CS) { page_mode_before_hplmn_search = alr_data->pch_data.pl_idle.page_mode; alr_data->pch_data.pl_idle.page_mode = PGM_REORG_NC_SYNC; pch_start_ccch_req (); ALR_TRACE_NC ("HPLMN search cannot be performed with REORG - possible loss of pagings"); } } return ; case READ_BCCH: if (alr_data->nc_data.c_bcch_req < MAX_L1_BCCH_CNT) { PALLOC (ncell_bcch, MPHC_NCELL_BCCH_REQ); ncell_bcch->radio_freq = ARFCN_TO_L1(pbsic->ba_arfcn); ncell_bcch->fn_offset = pbsic->frame_offset; ncell_bcch->time_alignment = pbsic->time_align; /* * The training sequence code on broadcast and common control channels * has to be equal to the base station color code see GSM 5.02 */ ncell_bcch->tsc = (UBYTE)(pbsic->bsic & ONLY_BCC); /* * Read SI 3/4 to get the MNC/MCC */ pbsic->blocks_required = ncell_bcch->bcch_blocks_required = NCELL_BCCH_SI_3_4; ncell_bcch->gprs_prio = GPRS_PRIO_NORM; ma_nc_bcch_req (ncell_bcch); alr_data->nc_data.c_bcch_req++; nc_set_status (LAST_BSIC_REQ, READ_BCCH_PENDING); } return; case READ_FB_SB_PENDING: case READ_BCCH_PENDING: return; default: break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_status_sync | +--------------------------------------------------------------------+ PURPOSE : Processes cell synchronisation. */ LOCAL void nc_process_status_sync(void) { USHORT i; USHORT index; T_NC* pbsic = &alr_data->nc_data.cell[LAST_BSIC_REQ]; /* Sync requests for New cells are allowed only in dedicated state * when eotd is not enabled. Patch for */ if((!alr_data->nc_data.eotd_avail) AND ( GET_STATE(STATE_NC) EQ NC_DEDICATED) AND (GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM)) { if(alr_data->nc_data.new_strong_cell_detect) nc_handle_new_strong_cells(); alr_data->nc_data.new_strong_cell_detect = FALSE; return; } while (alr_data->nc_data.c_sync_req < MAX_L1_SYNC_CNT) { /* * It is possible to send more sync requests to layer 1 */ USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; index = NOT_PRESENT_16BIT; for (i = 0; i < c_ba_arfcn; i++) { /* * search for the candidate with the highest fieldstrength */ T_NC* pcell = &alr_data->nc_data.cell[i]; if ((pcell->ba_arfcn NEQ pbsic->ba_arfcn) AND (pcell->ba_arfcn NEQ alr_data->serving_cell)) { switch (pcell->status) { case READ_FB_SB: if (index EQ NOT_PRESENT_16BIT) index = i; else { if (pcell->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) index = i; } break; default: break; } } } if (index NEQ NOT_PRESENT_16BIT) { /* * Request synchronisation for this cell */ nc_build_sync_req(index); ALR_TRACE_NC ("ncell_sync_req"); } else break; /*while loop */ } /* while( c_sync_req < MAX_L1_SYNC_CNT) */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_status_sync_gprs| +--------------------------------------------------------------------+ PURPOSE : Processes GPRS cell synchronisation. */ #ifdef GPRS /*XXX*/ LOCAL void nc_process_status_sync_gprs(void) { USHORT i; T_NC* pbsic = &alr_data->nc_data.cell[LAST_BSIC_REQ]; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; for (i = 0; i < c_ba_arfcn AND alr_data->nc_data.c_sync_req < MAX_L1_SYNC_CNT; i++) { /* * search for the candidate with the highest fieldstrength */ T_NC* pcell = &alr_data->nc_data.cell[i]; if ((pcell->ba_arfcn NEQ pbsic->ba_arfcn) AND (pcell->ba_arfcn NEQ alr_data->serving_cell) AND (pcell->status EQ READ_FB_SB)) { /* * Request synchronisation for this cell */ nc_build_sync_req(i); ALR_TRACE_NC ("ncell_sync_req"); } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_sync_failed_gprs | +--------------------------------------------------------------------+ PURPOSE : Handles synchronisation failed situation */ LOCAL void nc_sync_failed_gprs(USHORT index) { alr_data->nc_data.cell[index].c_sync = 1; /*XXX*/ nc_set_status (index, FB_SB_FAILED); nc_inform_grr_of_ncell(index, GRR_SB_NOT_FOUND); } #endif /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_process_status_bcch | +--------------------------------------------------------------------+ PURPOSE : Processes CB status */ LOCAL void nc_process_status_bcch(void) { USHORT i; USHORT index; T_NC* pbsic = &alr_data->nc_data.cell[LAST_BSIC_REQ]; while (alr_data->nc_data.c_bcch_req < MAX_L1_BCCH_CNT) { /* * It is possible to send more BCCH request to layer 1 */ USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; index = NOT_PRESENT_16BIT; for (i = 0; i < c_ba_arfcn; i++) { /* * search for the candidate with the highest fieldstrength */ T_NC* pcell = &alr_data->nc_data.cell[i]; if ((pcell->ba_arfcn NEQ pbsic->ba_arfcn) AND (pcell->ba_arfcn NEQ alr_data->serving_cell)) { switch (pcell->status) { case READ_BCCH: case READ_BCCH_RR_NOT_INFORMED: if (index EQ NOT_PRESENT_16BIT) index = i; else { if (pcell->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) index = i; } break; default: break; } } } if (index NEQ NOT_PRESENT_16BIT) { /* * Request BCCH reading for this cell */ T_NC* pcell = &alr_data->nc_data.cell[index]; PALLOC (ncell_bcch, MPHC_NCELL_BCCH_REQ); ncell_bcch->radio_freq = ARFCN_TO_L1(pcell->ba_arfcn); ncell_bcch->fn_offset = pcell->frame_offset; ncell_bcch->time_alignment = pcell->time_align; /* * The training sequence code on broadcast and common control channels * has to be equal to the Base Station Colour Code (BCC), * see 3GPP TS 5.02, section 5.2.3 and * 3GPP TS 03.03, section 4.3.2 Base Station Identify Code (BSIC) */ ncell_bcch->tsc = (UBYTE)(pcell->bsic & ONLY_BCC); pcell->blocks_required = ncell_bcch->bcch_blocks_required = NCELL_BCCH_SI_3_4; #ifdef GPRS /*if the mobile is in PTM the GPRS_PRIORITY must be set to TOP*/ if(ma_is_ptm()) { ncell_bcch->gprs_prio = GPRS_PRIO_TOP; } else #endif ncell_bcch->gprs_prio = GPRS_PRIO_NORM; ma_nc_bcch_req (ncell_bcch); ALR_TRACE_NC("ncell_bcch_read"); alr_data->nc_data.c_bcch_req++; /* * read a maximum of four blocks * * sys info 3 normal BCCH TC 2 or 6 * sys info 4 normal BCCH TC 3 or 7 */ if(pcell->status EQ READ_BCCH) nc_set_status (index, READ_BCCH_PENDING); else nc_set_status (index, READ_BCCH_PENDING_RR_NOT_INFORMED); } else break; /*while loop */ } /* while(c_bcch_req < MAX_L1_BCCH_CNT)*/ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_ncell_in_plmn_permitted | +--------------------------------------------------------------------+ PURPOSE : checks whether the national colour code (ncc) is member of the ncc permitted field. */ static const UBYTE ncc_bit_mask[8] = { BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7 }; LOCAL BOOL nc_ncell_in_plmn_permitted (UBYTE bsic) { return ((BOOL) ((UBYTE) (alr_data->ncc_permitted & ncc_bit_mask[(bsic >> 3) & BIT_012])) NEQ 0); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_store_dedicated | +--------------------------------------------------------------------+ PURPOSE : Stores the values of the neighbour cells and the serving cell. */ LOCAL void nc_store_dedicated (T_MPHC_MEAS_REPORT *report) { USHORT i; USHORT index; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; if (alr_data->nc_data.tim_state NEQ NC_TIM_STOPPED) { /* Decrement the 10sec timer counter variable by 2 */ alr_data->nc_data.c_ncsync_tim = alr_data->nc_data.c_ncsync_tim-2; if ((signed char)( alr_data->nc_data.c_ncsync_tim) < 0) alr_data->nc_data.c_ncsync_tim = 0; if( alr_data->nc_data.c_ncsync_tim EQ 0 ) /* 10 sec have elapsed. Perform all requisite tasks */ nc_ncsync_tim_expiry(); } for (i = 0; i < report->no_of_ncells_meas; i++) { T_NC* pcell; T_res_list* plist = &report->ncell_meas.res_list[i]; index = nc_get_index (ARFCN_TO_G23(plist->bcch_freq)); if ((index EQ NOT_PRESENT_16BIT) OR (index EQ LAST_BSIC_REQ)) continue; pcell = &alr_data->nc_data.cell[index]; if (plist->rxlev_nbr_meas EQ 0) pcell->rxlev_average = 0; else { if ((signed short)(plist->rxlev_acc) < 0) plist->rxlev_acc = 0; /* why this casting? - a "real" expression is of type int */ pcell->rxlev_average = (UBYTE)(plist->rxlev_acc/plist->rxlev_nbr_meas); } if (pcell->status EQ INACTIVE) nc_set_status (index, IDLE); if (pcell->status EQ EXCLUDED) { int diff; diff = pcell->rxlev_average - pcell->last_rxlev; if (diff >= 6) { /* * result is positive and more than 6 dBm */ nc_set_status (index, IDLE); } } } alr_data->nc_data.act_dtx = report->dtx_used; if (report->rxlev_full_nbr_meas EQ 0) alr_data->nc_data.rxlev_full = 0; else { if ((signed short)(report->rxlev_full_acc) < 0) report->rxlev_full_acc = 0; alr_data->nc_data.rxlev_full = (UBYTE)(report->rxlev_full_acc / report->rxlev_full_nbr_meas); } if (report->rxlev_sub_nbr_meas EQ 0) alr_data->nc_data.rxlev_sub = 0; else { if ((signed short)(report->rxlev_sub_acc) < 0) report->rxlev_sub_acc = 0; alr_data->nc_data.rxlev_sub = (UBYTE)(report->rxlev_sub_acc / report->rxlev_sub_nbr_meas); } alr_data->nc_data.rxqual_full = nc_convert_quality (report->rxqual_full_acc_errors, report->rxqual_full_nbr_bits); alr_data->nc_data.rxqual_sub = nc_convert_quality (report->rxqual_sub_acc_errors, report->rxqual_sub_nbr_bits); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_convert_quality | +--------------------------------------------------------------------+ PURPOSE : Calculates the quality Value. */ LOCAL UBYTE nc_convert_quality (USHORT errors, USHORT total) { USHORT quality; if (total EQ 0) quality = 0; else quality = (USHORT)((errors * 500) / total); if (quality EQ 0) return 0; /* RX_QUAL_0 */ if (quality EQ 1) return 1; /* RX_QUAL_1 */ if (quality < 4) return 2; /* RX_QUAL_2 */ if (quality < 8) return 3; /* RX_QUAL_3 */ if (quality < 16) return 4; /* RX_QUAL_4 */ if (quality < 32) return 5; /* RX_QUAL_5 */ if (quality < 64) return 6; /* RX_QUAL_6 */ return 7; /* RX_QUAL_7 */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_release_bcch | +--------------------------------------------------------------------+ PURPOSE : Check if we have read the BCCH of a ncell but RR has not yet received the data because this cell has not been reported to RR before. */ LOCAL void nc_release_bcch (void) { USHORT i; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; /* * for every ncell */ for (i = 0; i < c_ba_arfcn; i++) { T_NC* pcell = &alr_data->nc_data.cell[i]; switch (pcell->status) { case FB_SB_SYNC_RR_NOT_INFORMED: /* * Reading of the BCCH of the neighbourcell is performed, * but RR has been just informed with a measurement report * about synchronisation. */ if(pcell->mph_unitdata_ind NEQ NULL) { ALR_TRACE_NC ("send 34"); /* * a system info type 3 or 4 message is stored. * Send the message to RR and clear the internal variable. */ PSENDX(RR, pcell->mph_unitdata_ind); pcell->mph_unitdata_ind = NULL; } if(pcell->mph_unitdata_ind78 NEQ NULL) { ALR_TRACE_NC ("send 78"); /* * a system info type 7 or 8 message is stored. * Send the message to RR and clear the internal variable. */ PSENDX(RR, pcell->mph_unitdata_ind78); pcell->mph_unitdata_ind78 = NULL; } /* * set status to FB_SB_SYNC, that means RR is completely informed. */ nc_set_fb_sb_sync_initial (i); break; default: break; } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_store_bcch | +--------------------------------------------------------------------+ PURPOSE : Temporarily store BCCH data for ncell. */ LOCAL void nc_store_bcch (T_MPHC_DATA_IND* data_ind, USHORT index, UBYTE sys_info_78) { #define SYS_INFO_LEN 24 USHORT len_in_bits = SYS_INFO_LEN * BITS_PER_BYTE; T_NC* pcell = &alr_data->nc_data.cell[index]; /* * Allocate a SDU for sending later to RR */ PALLOC_SDU (data_out, MPH_UNITDATA_IND, len_in_bits); /* * set length and offset, but cut IE and Pseudo Length */ data_out->sdu.l_buf = (SYS_INFO_LEN - 2) * BITS_PER_BYTE; data_out->sdu.o_buf = 1 * BITS_PER_BYTE; /* * copy content of the message */ memcpy (data_out->sdu.buf, &data_ind->l2_frame, SYS_INFO_LEN - 1);/*lint !e419 (Warning -- Apparent data overrun)*/ /* * set BCCH frequency of the message */ data_out->arfcn = ARFCN_TO_G23(data_ind->radio_freq)&ARFCN_MASK; data_out->fn = data_ind->fn; if (sys_info_78) { ALR_TRACE_NC ("store 78"); /* * if it is a system info 7 or 8 message, free the previous * stored message, if something is stored and store the new * one. */ if (pcell->mph_unitdata_ind78 NEQ NULL) { ALR_TRACE_NC ("store,free old 78"); PFREE(pcell->mph_unitdata_ind78); } pcell->mph_unitdata_ind78 = data_out; } else { ALR_TRACE_NC ("store 34"); /* * if it is a system info 3 or 4 message, free the previous * stored message, if something is stored and store the new * one. */ if (pcell->mph_unitdata_ind NEQ NULL) { ALR_TRACE_NC( "store,free old 34"); PFREE(pcell->mph_unitdata_ind); } pcell->mph_unitdata_ind = data_out; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_sys_info_78_required | +--------------------------------------------------------------------+ PURPOSE : The function checks whether sys info 7 or 8 are expected and required. */ LOCAL UBYTE nc_sys_info_78_required (USHORT index) { if (alr_data->nc_data.cell[index].mph_unitdata_ind NEQ 0) { T_sdu * sdu = &alr_data->nc_data.cell[index].mph_unitdata_ind->sdu; /*lint -e415 (Warning -- creation of out-of-bounds pointer)*/ /*lint -e416 (Warning -- access of out-of-bounds pointer)*/ if ((sdu->buf[SI_CONTENTS_CS2] & ONLY_ACS) NEQ 0) return TRUE; /*lint +e415 (Warning -- creation of out-of-bounds pointer)*/ /*lint +e416 (Warning -- access of out-of-bounds pointer)*/ } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_bcch | +--------------------------------------------------------------------+ PURPOSE : Stop a pending BCCH. */ LOCAL void nc_stop_bcch (USHORT index, UBYTE new_status) { /* * L3 may avoid sending a stop message to terminate a NCELL_BCCH process * if there no more pending request in L1 */ if (alr_data->nc_data.c_bcch_req > 0) { /* * stop BCCH request in layer 1. */ ma_nc_stop_ncell_bcch_req(alr_data->nc_data.cell[index].ba_arfcn); /* * decrement counter of pending requests */ alr_data->nc_data.c_bcch_req--; } /* * set new status */ nc_set_status (index, new_status); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_stop_sync | +--------------------------------------------------------------------+ PURPOSE : Stop a pending Sync request. */ LOCAL void nc_stop_sync (USHORT index, UBYTE new_status) { /* * L3 may avoid sending a stop message to terminate a NCELL_SYNC process * if there no more pending request in L1 */ if (alr_data->nc_data.c_sync_req > 0) { /* * stop sync request in layer 1. */ ma_nc_stop_ncell_sync_req (alr_data->nc_data.cell[index].ba_arfcn); /* * decrement counter of pending requests */ alr_data->nc_data.c_sync_req--; /* * check whether the confirmation procedure is finished indirectly */ if (alr_data->nc_data.c_sync_req EQ 0 AND alr_data->nc_data.eotd_avail EQ FALSE AND GET_STATE(STATE_NC_PROC) EQ NC_CONFIRM) { nc_enable_conf(); } } /* * set new status */ nc_set_status (index, new_status); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_clean_store_bcch | +--------------------------------------------------------------------+ PURPOSE : Clean a stored BCCH. */ LOCAL void nc_clean_store_bcch (USHORT index) { T_NC* pcell = &alr_data->nc_data.cell[index]; if (pcell->mph_unitdata_ind NEQ NULL) { ALR_TRACE_NC ("free 34"); /* * a system info type 3 or 4 message is stored * then free the message and clean the pointer. */ PFREE(pcell->mph_unitdata_ind); pcell->mph_unitdata_ind = NULL; } if(pcell->mph_unitdata_ind78 NEQ NULL) { ALR_TRACE_NC ("free 78"); /* * a system info type 7 or 8 message is stored * then free the message and clean the pointer. */ PFREE(pcell->mph_unitdata_ind78); pcell->mph_unitdata_ind78 = NULL; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_check_bsic | +--------------------------------------------------------------------+ PURPOSE : Check a base station identification code of a neighbourcell The following return values are possible: NC_CHECK_OK : BSIC has not changed and is permitted. NC_CHECK_NCC_FAILED : NCC permitted check has failed NC_CHECK_BSIC_CHANGED : a BSIC change has occured */ LOCAL UBYTE nc_check_bsic (USHORT index, UBYTE bsic) { /* * check only the lowest 6 bits (= NCC + BCC) */ bsic = (UBYTE)(bsic & ONLY_BSIC); /* * first check whether ncc is member of the ncc permitted field */ if (!nc_ncell_in_plmn_permitted (bsic)) return NC_CHECK_NCC_FAILED; /* * no bsic stored until now. */ if (alr_data->nc_data.cell[index].bsic EQ NOT_PRESENT_8BIT) return NC_CHECK_OK; /* * check against BSIC changes */ if (alr_data->nc_data.cell[index].bsic NEQ bsic) return NC_CHECK_BSIC_CHANGED; /* * all checks passed */ return NC_CHECK_OK; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_check_new_ncc_permitted | +--------------------------------------------------------------------+ PURPOSE : Checks whether status transitions are needed after reception of a changed NCC permitted field. */ GLOBAL void nc_check_new_ncc_permitted (UBYTE new_ncc_permitted) { USHORT i; USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; if (new_ncc_permitted NEQ alr_data->ncc_permitted) { /* * a change has occured, so store new value and check all cells */ alr_data->ncc_permitted = new_ncc_permitted; for (i = 0; i < c_ba_arfcn; i++) { switch (alr_data->nc_data.cell[i].status) { case FB_SB_SYNC: case FB_SB_SYNC_RR_NOT_INFORMED: case READ_SB: case READ_BCCH: case IDLE_SYNC: case READ_SB_BCCH: case READ_BCCH_RR_NOT_INFORMED: if (nc_ncell_in_plmn_permitted(alr_data->nc_data.cell[i].bsic) EQ FALSE) nc_set_status (i, EXCLUDED); break; case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: if (nc_ncell_in_plmn_permitted(alr_data->nc_data.cell[i].bsic) EQ FALSE) nc_set_status (i, EXCLUDED); break; case EXCLUDED: /* * give channel a new chance */ nc_set_status (i, IDLE); break; } } } } #if !defined(DEFINE_OLD_NC_STATUS) LOCAL UBYTE nc_get_nc_status(UBYTE status) { UBYTE st; switch (status) { case INACTIVE:st=0;break; case IDLE:st=1;break; case READ_BCCH:st=2;break; case FB_SB_SYNC:st=3;break; case FB_SB_FAILED:st=4;break; case READ_FB_SB:st=5;break; case READ_SB:st=6;break; case IDLE_SYNC:st=7;break; case EXCLUDED:st=8;break; case FB_SB_SYNC_RR_NOT_INFORMED:st=9;break; case READ_SB_BCCH:st=10;break; case READ_BCCH_PENDING:st=11;break; case READ_FB_SB_PENDING:st=12;break; case READ_SB_PENDING:st=13;break; case READ_SB_BCCH_PENDING:st=14;break; case READ_BCCH_RR_NOT_INFORMED:st=15;break; case READ_BCCH_PENDING_RR_NOT_INFORMED:st=16;break; default:st=17;break; } return st; } #else /* DEFINE_OLD_NC_STATUS */ #define nc_get_nc_status(st) (((int)(st) >= 18) ? 18 : (st)) #endif /* DEFINE_OLD_NC_STATUS */ #if !defined(NTRACE) && defined(TRACING) LOCAL const char * nc_get_nc_state_str(UBYTE status) { return alr_nc_state_trc[nc_get_nc_status(status)]; } #endif /* !NTRACE && TRACING */ #if 0 /* not needed currently */ #if defined(TRACING) /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_get_status | +--------------------------------------------------------------------+ PURPOSE : The function returns the status for a channel. */ LOCAL UBYTE nc_get_status (USHORT index) { /* use pointer to save time and ROM */ T_NC* pcell = &alr_data->nc_data.cell[index]; TRACE_USER_CLASS_P3 (TC_USER1, "NC%u[%d] %s", index, pcell->ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : pcell->ba_arfcn&ARFCN_MASK, nc_get_nc_state_str(pcell->status)); return pcell->status; } #endif /* TRACING */ #endif /* 0|1 */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_set_status | +--------------------------------------------------------------------+ PURPOSE : The function sets a new status for a channel. Depending on the new status several variables which are not valid in the new status are initialised to their default values. */ GLOBAL void nc_set_status (USHORT index, UBYTE new_status) { /* use pointer to save time and ROM */ T_NC* pcell = &alr_data->nc_data.cell[index]; #if defined(TRACING) TRACE_EVENT_P4 ("NC%u[%d] %s -> %s", index, pcell->ba_arfcn EQ NOT_PRESENT_16BIT ? -1 : pcell->ba_arfcn&ARFCN_MASK, nc_get_nc_state_str(pcell->status), nc_get_nc_state_str(new_status)); #endif /* TRACING */ switch (new_status) { case INACTIVE: pcell->bsic = NOT_PRESENT_8BIT; pcell->frame_offset = NOT_PRESENT_32BIT; pcell->time_align = NOT_PRESENT_32BIT; pcell->last_rxlev = 0; pcell->c_rxlev = NOT_PRESENT_8BIT; pcell->rxlev_average = 0; memset (pcell->rxlev, 0, 5); pcell->one_of_six = FALSE; pcell->one_of_twelve = FALSE; pcell->c_attempt = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->tim_valid = TV_INVALID_TIMING_INFO; pcell->blocks_required = 0; pcell->c_error = 0; nc_clean_store_bcch (index); break; case IDLE: pcell->bsic = NOT_PRESENT_8BIT; /* pcell->frame_offset = 0; pcell->time_align = 0; pcell->last_rxlev = 0; */ pcell->one_of_six = FALSE; pcell->one_of_twelve = FALSE; /*pcell->c_attempt = 0;*/ pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->blocks_required = 0; pcell->c_error = 0; nc_clean_store_bcch (index); break; case READ_FB_SB: case READ_FB_SB_PENDING: pcell->bsic = NOT_PRESENT_8BIT; /* pcell->frame_offset = 0; pcell->time_align = 0; */ pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->blocks_required = 0; pcell->c_error = 0; nc_clean_store_bcch (index); break; case READ_BCCH: pcell->last_rxlev = 0; /*pcell->c_attempt = 0;*/ pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->c_error = 0; pcell->blocks_required = 0; nc_clean_store_bcch (index); break; case READ_BCCH_RR_NOT_INFORMED: pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->c_error = 0; pcell->blocks_required = 0; nc_clean_store_bcch (index); break; case FB_SB_SYNC_RR_NOT_INFORMED: pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->blocks_required = 0; pcell->c_attempt = 0; pcell->c_error = 0; break; case FB_SB_SYNC: pcell->last_rxlev = 0; pcell->blocks_required = 0; if (!pcell->one_of_six) pcell->c_attempt = 0; pcell->c_error = 0; pcell->c_sync = C_INVALID_SYNC; nc_clean_store_bcch (index); break; case READ_SB: case READ_SB_PENDING: pcell->last_rxlev = 0; pcell->c_sync = C_INVALID_SYNC; pcell->blocks_required = 0; /*pcell->c_attempt = 0;*/ pcell->c_error = 0; nc_clean_store_bcch (index); break; case READ_SB_BCCH: case READ_SB_BCCH_PENDING: pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->blocks_required = 0; pcell->c_error = 0; /*pcell->c_attempt = 0;*/ nc_clean_store_bcch (index); break; case IDLE_SYNC: pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->one_of_six = FALSE; pcell->one_of_twelve = FALSE; pcell->c_attempt = 0; pcell->blocks_required = 0; pcell->c_error = 0; pcell->c_sync = alr_data->nc_data.c_nc_timer; /*TODO maybe move this to a function*/ nc_clean_store_bcch (index); break; case FB_SB_FAILED: pcell->bsic = NOT_PRESENT_8BIT; if (pcell->status EQ READ_FB_SB_PENDING) { pcell->frame_offset = NOT_PRESENT_32BIT; pcell->time_align = NOT_PRESENT_32BIT; pcell->tim_valid = TV_INVALID_TIMING_INFO; } else pcell->tim_valid = TV_APPROX_TIMING_INFO; pcell->last_rxlev = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->blocks_required = 0; pcell->c_error = 0; nc_clean_store_bcch (index); break; case EXCLUDED: pcell->bsic = NOT_PRESENT_8BIT; pcell->frame_offset = NOT_PRESENT_32BIT; pcell->time_align = NOT_PRESENT_32BIT; pcell->one_of_six = FALSE; pcell->one_of_twelve = FALSE; pcell->last_rxlev = pcell->rxlev_average; /* TODO maybe move this to a function */ pcell->c_attempt = 0; pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; pcell->tim_valid = TV_INVALID_TIMING_INFO; pcell->blocks_required = 0; pcell->c_error = 0; nc_clean_store_bcch (index); break; case READ_BCCH_PENDING: case READ_BCCH_PENDING_RR_NOT_INFORMED: pcell->last_rxlev = 0; /*pcell->c_attempt = 0;*/ pcell->c_bcch = C_INVALID_BCCH; pcell->c_sync = C_INVALID_SYNC; nc_clean_store_bcch (index); break; } /* * set new status */ pcell->status = new_status; } GLOBAL void nc_check_activity (void) { int i; switch(GET_STATE(STATE_NC)) { case NC_IDLE: /* count number of reports */ alr_data->nc_data.c_reports++; nc_rank_ncells (); nc_check_status (CHECK_FOR_ACQUIRE_AND_BCCH_AND_FAIL); nc_process_status(); if (first_period AND !first_l1_meas) { if (alr_data->nc_data.c_reports EQ alr_data->nc_data.max_reports OR alr_data->nc_data.c_reports EQ alr_data->nc_data.max_reports - 1) { UBYTE all_sync = TRUE; /* * for every ncell */ for (i = 0; i < alr_data->nc_data.c_ba_arfcn; i++) { if (alr_data->nc_data.cell[i].status EQ READ_BCCH_PENDING OR alr_data->nc_data.cell[i].status EQ READ_BCCH_PENDING_RR_NOT_INFORMED) { /* not all needed SI are read yet */ all_sync = FALSE; break; } } if (!all_sync AND alr_data->nc_data.c_reports EQ alr_data->nc_data.max_reports) { /* spend an additional reporting period to give FTA 20.7 a better chance to pass */ alr_data->nc_data.c_reports--; first_period = FALSE; ALR_TRACE_NC ("one additional period"); } else if (all_sync AND alr_data->nc_data.c_reports EQ alr_data->nc_data.max_reports - 1) { /* skip an additional reporting period to give FTA 20.19 a better chance to pass */ alr_data->nc_data.c_reports++; first_period = FALSE; ALR_TRACE_NC ("one period skipped"); } } } first_l1_meas = FALSE; #if defined(_SIMULATION_) TRACE_EVENT_P2 ("c_reports=%u/%u", alr_data->nc_data.c_reports, alr_data->nc_data.max_reports); #endif /* WIN32 */ /* check if 5sec have passed, we then have to inform RR */ if (alr_data->nc_data.c_reports EQ alr_data->nc_data.max_reports) { USHORT index, average; T_NC* pcell; PALLOC (report, MPH_MEASUREMENT_IND); memset (report, 0, sizeof (T_MPH_MEASUREMENT_IND)); first_period = FALSE; #ifdef GPRS report->gprs_sync = NORMAL_MEAS_REP; #endif report->arfcn = alr_data->serving_cell; average = 0; index = nc_get_index(alr_data->serving_cell); if ( index NEQ NOT_PRESENT_16BIT ) { pcell = &alr_data->nc_data.cell[index]; pcell->rxlev_average = 0; /* Is this really needed? */ for (i = 0; i < 5; i++) average += pcell->rxlev[i]; } report->rx_lev_full = (UBYTE) (average / 5); report->fn_offset = alr_data->nc_data.fn_offset; alr_data->nc_data.c_reports = 0; nc_build_rr_report (report); ma_nc_report_res (report); nc_release_bcch (); } break; case NC_DEDICATED: nc_rank_ncells (); nc_check_status (CHECK_FOR_ACQUIRE_AND_BCCH_AND_FAIL); nc_process_status(); { PALLOC(mph_measurement_ind, MPH_MEASUREMENT_IND); #ifdef GPRS mph_measurement_ind->gprs_sync = NORMAL_MEAS_REP; #endif nc_build_rr_report_dedi (mph_measurement_ind); ma_nc_report_res (mph_measurement_ind); } break; default: break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_set_fb_sb_sync_initial | +--------------------------------------------------------------------+ PURPOSE : Inital setting of status FB_SB_SYNC. Counter for SB confirmation and BCCH re-reading are initialized. */ LOCAL void nc_set_fb_sb_sync_initial (USHORT index) { alr_data->nc_data.cell[index].c_bcch = FIVE_MINUTES; if(!alr_data->nc_data.eotd_avail) { /*round to next confirmation boundary */ if(alr_data->nc_data.c_nc_timer NEQ THIRTY_SECONDS) alr_data->nc_data.cell[index].c_bcch += alr_data->nc_data.c_nc_timer; } nc_set_status (index, FB_SB_SYNC); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_set_fb_sb_failed | +--------------------------------------------------------------------+ PURPOSE : Set the status to FB_SB_FAILED, update the attempt counter and set time until next attempt is started. */ LOCAL void nc_set_fb_sb_failed (USHORT index, UBYTE c_sync) { alr_data->nc_data.cell[index].c_attempt++; alr_data->nc_data.cell[index].c_sync = c_sync; nc_set_status (index, FB_SB_FAILED); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_rxlev_sc_req | +--------------------------------------------------------------------+ PURPOSE : A new RXLEV value of the serving cell has been measured. Inform GPL in case it is necessary. */ #ifdef GPRS LOCAL void nc_rxlev_sc_req (UBYTE rxlev) { if(GET_STATE (STATE_NC) EQ NC_IDLE) { PALLOC (rxlev_sc_req, TB_RXLEV_SC_REQ); rxlev_sc_req->sc_rxlev = rxlev; ma_nc_rxlev_sc_req (rxlev_sc_req); } } #endif /* #ifdef GPRS */ #if defined(_SIMULATION_) LOCAL void trace_nc(void) { char buf[80]; int i, o; T_NC* pcell; o = sprintf (buf, "NC: "); for (i=0,pcell = &alr_data->nc_data.cell[0]; i < alr_data->nc_data.c_ba_arfcn; i++,pcell++) { if(pcell->ba_arfcn EQ alr_data->serving_cell) { o += sprintf (buf+o, "%u[SC=%u]%u, ", i, pcell->ba_arfcn, pcell->ba_status); } else { o += sprintf (buf+o, "%u[%u]%u, ", i, pcell->ba_arfcn, pcell->ba_status); } if (o > 60) { TRACE_EVENT (buf); o = sprintf (buf, "NC: "); } } if (o>4) { buf[o-2]=0; TRACE_EVENT (buf); } } #endif /* _SIMULATION_ */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_check_new_strong_cell | +--------------------------------------------------------------------+ PURPOSE : Checks the New strong cell criteria */ LOCAL void nc_check_new_strong_cell(USHORT index, UBYTE o_1of6, UBYTE rxlev) { T_NC* pcell = &alr_data->nc_data.cell[index]; if((pcell->one_of_six ) AND (!o_1of6)) { /* NCELL confirmation active. New 1of6 cell found */ if((pcell->rxlev_average > rxlev) AND ((pcell->rxlev_average - rxlev ) >= 5)) pcell->new_strong_cell = TRUE; } else if ((pcell->one_of_six ) AND (o_1of6) AND (pcell->status EQ READ_FB_SB) AND (pcell->c_attempt EQ 0 )) { /* NCELL confirmation interrupted the sync of last 1of6 cell * This has to be synchronized again */ pcell->new_strong_cell = TRUE; } if(pcell->new_strong_cell) { alr_data->nc_data.new_strong_cell_detect = TRUE; TRACE_EVENT_P1("[%d]New strong cell",pcell->ba_arfcn); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6103) MODULE : ALR_NC | | STATE : code ROUTINE : nc_handle_new_strong_cells | +--------------------------------------------------------------------+ PURPOSE : Processes cell synchronisation. */ LOCAL void nc_handle_new_strong_cells(void) { USHORT i; USHORT index; UBYTE first_sync_req = TRUE; T_NC* pbsic = &alr_data->nc_data.cell[LAST_BSIC_REQ]; alr_data->nc_data.c_sync_intrupted = FALSE; while (alr_data->nc_data.c_sync_req < MAX_L1_SYNC_CNT) { /* * It is possible to send more sync requests to layer 1 */ USHORT c_ba_arfcn = alr_data->nc_data.c_ba_arfcn; index = NOT_PRESENT_16BIT; for (i = 0; i < c_ba_arfcn; i++) { /* * search for "New strong cell" with the highest fieldstrength */ T_NC* pcell = &alr_data->nc_data.cell[i]; if ((pcell->ba_arfcn NEQ pbsic->ba_arfcn) AND (pcell->ba_arfcn NEQ alr_data->serving_cell) AND (pcell->new_strong_cell)) { switch (pcell->status) { case READ_FB_SB: if (index EQ NOT_PRESENT_16BIT) index = i; else { if (pcell->rxlev_average > alr_data->nc_data.cell[index].rxlev_average) index = i; } break; default: break; } } } if (index NEQ NOT_PRESENT_16BIT) { if(first_sync_req EQ TRUE) { first_sync_req = FALSE; if(alr_data->nc_data.c_sync_req > 0) { TRACE_EVENT("RE-SYNC interrupted"); alr_data->nc_data.c_sync_intrupted = TRUE; nc_stop_all(); if(!alr_data->nc_data.c_sync_req) { alr_data->nc_data.tim_state = NC_CONF_PENDING; SET_STATE(STATE_NC_PROC, NC_ACQUIRE); } } } /* first_sync_req */ /* * Request synchronisation for this cell */ nc_build_sync_req(index); alr_data->nc_data.cell[index].new_strong_cell = FALSE; TRACE_EVENT_P1("[%d]N_S_C sync req",alr_data->nc_data.cell[index].ba_arfcn); } else break; /*while loop */ } /* while( c_sync_req < MAX_L1_SYNC_CNT) */ } #endif