FreeCalypso > hg > fc-tourmaline
view src/cs/layer1/cfile/l1_async.c @ 220:0ed36de51973
ABB semaphore protection overhaul
The ABB semaphone protection logic that came with TCS211 from TI
was broken in several ways:
* Some semaphore-protected functions were called from Application_Initialize()
context. NU_Obtain_Semaphore() called with NU_SUSPEND fails with
NU_INVALID_SUSPEND in this context, but the return value wasn't checked,
and NU_Release_Semaphore() would be called unconditionally at the end.
The latter call would increment the semaphore count past 1, making the
semaphore no longer binary and thus no longer effective for resource
protection. The fix is to check the return value from NU_Obtain_Semaphore()
and skip the NU_Release_Semaphore() call if the semaphore wasn't properly
obtained.
* Some SPI hardware manipulation was being done before entering the semaphore-
protected critical section. The fix is to reorder the code: first obtain
the semaphore, then do everything else.
* In the corner case of L1/DSP recovery, l1_abb_power_on() would call some
non-semaphore-protected ABB & SPI init functions. The fix is to skip those
calls in the case of recovery.
* A few additional corner cases existed, all of which are fixed by making
ABB semaphore protection 100% consistent for all ABB functions and code paths.
There is still one remaining problem of priority inversion: suppose a low-
priority task calls an ABB function, and some medium-priority task just happens
to preempt right in the middle of that semaphore-protected ABB operation. Then
the high-priority SPI task is locked out for a non-deterministic time until
that medium-priority task finishes its work and goes back to sleep. This
priority inversion problem remains outstanding for now.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 26 Apr 2021 20:55:25 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/************* Revision Controle System Header ************* * GSM Layer 1 software * L1_ASYNC.C * * Filename l1_async.c * Copyright 2003 (C) Texas Instruments * ************* Revision Controle System Header *************/ //#pragma DUPLICATE_FOR_INTERNAL_RAM_START #include "l1_macro.h" #include "l1_confg.h" //#pragma DUPLICATE_FOR_INTERNAL_RAM_END #if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM !=0)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM enabled //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise #define L1_ASYNC_C //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END // KEEP IN EXTERNAL MEM otherwise #endif //#pragma DUPLICATE_FOR_INTERNAL_RAM_START #if (CODE_VERSION == SIMULATION) #include <string.h> #include "l1_types.h" #include "sys_types.h" #include "l1_const.h" #include "l1_signa.h" #include "cust_os.h" #if TESTMODE #include "l1tm_defty.h" #include "l1tm_signa.h" #endif #if (AUDIO_TASK == 1) #include "l1audio_const.h" #include "l1audio_cust.h" #include "l1audio_defty.h" #endif #if (L1_GTT == 1) #include "l1gtt_const.h" #include "l1gtt_defty.h" #endif #if (L1_MP3 == 1) #include "l1mp3_defty.h" #endif #if (L1_MIDI == 1) #include "l1midi_proto.h" #include "l1midi_defty.h" #endif //ADDED FOR AAC #if (L1_AAC == 1) #include "l1aac_defty.h" #endif #if (L1_DYN_DSP_DWNLD == 1) #include "l1_dyn_dwl_signa.h" #endif #include "l1_defty.h" #include "l1_msgty.h" #include "l1_varex.h" #include "l1_proto.h" #include "l1_mftab.h" #if L1_GPRS #include "l1p_mfta.h" #include "l1p_msgt.h" #include "l1p_cons.h" #include "l1p_deft.h" #include "l1p_vare.h" #include "l1p_sign.h" #endif #include "l1_tabs.h" #if (VCXO_ALGO == 1) #include "l1_ctl.h" #endif #if L2_L3_SIMUL #include "hw_debug.h" #endif #else #include <string.h> #include "l1_types.h" #include "sys_types.h" #include "l1_const.h" #include "l1_time.h" #include "l1_signa.h" #include "cust_os.h" #if TESTMODE #include "l1tm_defty.h" #include "l1tm_signa.h" #endif #if (AUDIO_TASK == 1) #include "l1audio_const.h" #include "l1audio_cust.h" #include "l1audio_defty.h" #include "l1audio_signa.h" #endif #if (L1_GTT == 1) #include "l1gtt_const.h" #include "l1gtt_defty.h" #endif #if (L1_MP3 == 1) #include "l1mp3_defty.h" #include "l1mp3_signa.h" #endif #if (L1_MIDI == 1) #include "l1midi_proto.h" #include "l1midi_defty.h" #endif //ADDED FOR AAC #if (L1_AAC == 1) #include "l1aac_defty.h" #include "l1aac_signa.h" #endif #if (L1_DYN_DSP_DWNLD == 1) #include <stdio.h> #include "l1_dyn_dwl_signa.h" #endif #include "l1_defty.h" #include "l1_msgty.h" #include "l1_varex.h" #include "l1_proto.h" #include "l1_mftab.h" #if L1_GPRS #include "l1p_mfta.h" #include "l1p_msgt.h" #include "l1p_cons.h" #include "l1p_deft.h" #include "l1p_vare.h" #include "l1p_sign.h" #endif #include "l1_tabs.h" #if L1_RECOVERY #if ((CHIPSET == 12) || (CHIPSET == 15)) #include "sys_inth.h" #else #include "iq.h" #include "inth.h" #include "mem.h" #endif #endif #if (VCXO_ALGO == 1) #include "l1_ctl.h" #endif #if L2_L3_SIMUL #include "hw_debug.h" #endif #if (OP_L1_STANDALONE == 1) #include "dynamic_clock.h" #endif #endif // External function prototypes extern void l1ctl_gauging (UWORD32 nb_32khz, UWORD32 nb_hf); extern void l1_tpu_init_light(void); extern void tm_receive(UWORD8 *inbuf, UWORD16 size); #if L1_RECOVERY extern void l1_initialize_for_recovery(void); #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) extern void l1_trace_recovery(void); #endif #endif #if (L1_GTT == 1) extern void l1a_mmi_gtt_process (xSignalHeaderRec *msg); #endif #if(L1_DYN_DSP_DWNLD == 1) extern void l1a_dyn_dsp_dwnld_process(xSignalHeaderRec *msg); #endif #if (AUDIO_TASK == 1) /**************************************/ /* External audio prototypes */ /**************************************/ #if (OP_RIV_AUDIO == 1) #if (L1_AUDIO_DRIVER == 1) // driver task extern void l1a_audio_driver_process (xSignalHeaderRec *msg); #endif #endif #if (KEYBEEP) // Keybeep task process extern void l1a_mmi_keybeep_process (xSignalHeaderRec *msg); #endif #if (TONE) // Keybeep task process extern void l1a_mmi_tone_process (xSignalHeaderRec *msg); #endif #if (L1_CPORT == 1) // Cport task process extern void l1a_mmi_cport_process (xSignalHeaderRec *msg); #endif #if (MELODY_E1) // Melody 0 task process extern void l1a_mmi_melody0_process (xSignalHeaderRec *msg); // Melody 1 task process extern void l1a_mmi_melody1_process (xSignalHeaderRec *msg); #endif #if (VOICE_MEMO) // Voice memo playing process extern void l1a_mmi_vm_playing_process (xSignalHeaderRec *msg); // Voice memo recording process extern void l1a_mmi_vm_recording_process (xSignalHeaderRec *msg); #endif #if (L1_PCM_EXTRACTION) /* PCM download process */ void l1a_mmi_pcm_download_process (xSignalHeaderRec *msg); /* PCM upload process */ void l1a_mmi_pcm_upload_process (xSignalHeaderRec *msg); #endif #if (L1_VOICE_MEMO_AMR) // Voice memo amr playing process extern void l1a_mmi_vm_amr_playing_process (xSignalHeaderRec *msg); // Voice memo amr recording process extern void l1a_mmi_vm_amr_recording_process(xSignalHeaderRec *msg); #endif #if (SPEECH_RECO) // Speech recognition enrollment process extern void l1a_mmi_sr_enroll_process (xSignalHeaderRec *msg); // Speech recognition update process extern void l1a_mmi_sr_update_process (xSignalHeaderRec *msg); // Speech recognition reco process extern void l1a_mmi_sr_reco_process (xSignalHeaderRec *msg); // Speech recognition update-check process extern void l1a_mmi_sr_update_check_process (xSignalHeaderRec *msg); #endif #if (AEC) // AEC process extern void l1a_mmi_aec_process (xSignalHeaderRec *msg); #endif #if (FIR) // FIR process extern void l1a_mmi_fir_process (xSignalHeaderRec *msg); #endif #if (AUDIO_MODE) // AUDIO MODE process extern void l1a_mmi_audio_mode_process (xSignalHeaderRec *msg); #endif #if (MELODY_E2) extern void l1a_mmi_melody0_e2_process (xSignalHeaderRec *msg); extern void l1a_mmi_melody1_e2_process (xSignalHeaderRec *msg); #endif #if (L1_MP3 == 1) extern void l1a_mmi_mp3_process (xSignalHeaderRec *msg); #endif //ADDED FOR AAC #if (L1_AAC == 1) extern void l1a_mmi_aac_process (xSignalHeaderRec *msg); #endif #if (L1_EXTERNAL_AUDIO_VOICE_ONOFF == 1 || L1_EXT_MCU_AUDIO_VOICE_ONOFF == 1) extern void l1a_mmi_audio_onoff_process (xSignalHeaderRec *msg); #endif #if (L1_EXT_AUDIO_MGT == 1) // External audio_mgt task process extern void l1a_mmi_ext_audio_mgt_process (xSignalHeaderRec *msg); #endif #if (L1_ANR == 1 || L1_ANR == 2) extern void l1a_mmi_anr_process (xSignalHeaderRec *msg); #endif #if (L1_IIR == 1 || L1_IIR == 2) extern void l1a_mmi_iir_process (xSignalHeaderRec *msg); #endif #if (L1_WCM == 1) extern void l1a_mmi_wcm_process (xSignalHeaderRec *msg); #endif #if (L1_AGC_UL == 1) extern void l1a_mmi_agc_ul_process (xSignalHeaderRec *msg); #endif #if (L1_AGC_DL == 1) extern void l1a_mmi_agc_dl_process (xSignalHeaderRec *msg); #endif #if (L1_DRC == 1) extern void l1a_mmi_drc_process (xSignalHeaderRec *msg); #endif #if (L1_LIMITER == 1) extern void l1a_mmi_limiter_process (xSignalHeaderRec *msg); #endif #if (L1_ES == 1) extern void l1a_mmi_es_process (xSignalHeaderRec *msg); #endif #if (L1_VOCODER_IF_CHANGE == 1) extern void l1a_mmi_vocoder_cfg_process (xSignalHeaderRec *msg); #endif //VOCODER_IF_CHANGE == 1 #if(L1_BT_AUDIO ==1) extern void l1a_mmi_bt_process(xSignalHeaderRec *msg); #endif extern void l1a_mmi_outen_cfg_process (xSignalHeaderRec *msg); #endif #if(L1_CHECK_COMPATIBLE == 1) extern void l1a_checkmsg_compatibility (xSignalHeaderRec *msg); #endif #if TESTMODE void l1a_tmode(xSignalHeaderRec *msg); #if (OP_L1_STANDALONE == 0) typedef void (*TM_CALLBACK_FUNC)(UWORD8*, UWORD16); extern int etm_register(char name[], int mid, int task_id, UWORD16 addr_id, TM_CALLBACK_FUNC callback); #endif #endif #if L1_GPRS void l1pa_task(xSignalHeaderRec *msg); #endif #if (TRACE_TYPE == 1) ||(TRACE_TYPE == 4) || (TRACE_TYPE == 7) || (TESTMODE) #include "l1_trace.h" extern T_RVT_USER_ID tm_trace_user_id; extern void l1_trace_configuration(T_RVT_BUFFER trace_msg, UINT16 trace_msg_size); #endif //#pragma DUPLICATE_FOR_INTERNAL_RAM_END #if (TRACE_TYPE == 1) ||(TRACE_TYPE == 4) || (TRACE_TYPE == 7) || (TESTMODE) T_RVT_USER_ID tm_trace_user_id; #endif #if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM !=0)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM enabled //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise /*-------------------------------------------------------*/ /* l1a_task() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* L1A (Layer 1 Asynchronous) task function. This */ /* function manages the interface between L3 and L1. It */ /* is composed with a set of state machine, each machine */ /* handles a particular GSM functionality. When a */ /* message is received in L1_C1 message queue, it is */ /* submitted to every state machine. The one which are */ /* impacted by the message process it. At the end of */ /* "l1a_task()" function, a balance routine is called, */ /* it enables L1S tasks consequently to the state machine*/ /* requests. */ /* */ /*-------------------------------------------------------*/ void l1a_task(UWORD32 argc, void *argv) { xSignalHeaderRec *msg; #if (TRACE_TYPE == 7) rvt_register_id("L1", &trace_info.l1_trace_user_id, (RVT_CALLBACK_FUNC)NULL); #endif #if ((TESTMODE) && (CODE_VERSION != SIMULATION)) // Testmode register for UART TX only in standalone L1 #if (OP_L1_STANDALONE == 0) // Register the tm_receive func. as the TM3 packet receptor in the ETM database etm_register("TML1", 0x0, 0, 0, tm_receive); // 0x00 = use of TM3 Signalling PC<->MS #else rvt_register_id("TM", &tm_trace_user_id, tm_receive); #endif // End of OP_L1_STANDALONE #endif // End of TESTMODE && (CODE_VERSION != SIMULATION) #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) // Enable auto-test HW in order to trace versions trace_info.init_trace = 1; l1a_l1s_com.l1s_en_task[HWTEST] = TASK_ENABLED; l1a_l1s_com.l1a_activity_flag = TRUE; #endif while(1) /*************************************************************/ /* LOOP on L1A message queue... */ /*************************************************************/ { UWORD8 process; /***********************************************/ /* Wait for a new message from RRM1 or L1S */ /***********************************************/ msg = os_receive_sig(L1C1_QUEUE); DEBUGMSG(status,NU_RCVE_QUEUE_ERR) // Reset "l1_msg_forwarded" flag for this new incoming msg. // ======================================================== l1a.l1_msg_forwarded = FALSE; #if (TRACE_TYPE==1) || (TRACE_TYPE==4) || (TRACE_TYPE==7) l1_trace_message(msg); #endif #if(L1_CHECK_COMPATIBLE == 1) l1a_checkmsg_compatibility(msg); #endif #if (DRP_FW_EXT == 1) if(!l1s.boot_result) { #endif /* DRP_FW_EXT*/ #if (GSM_IDLE_RAM <= 1) #if TESTMODE // if NOT in TestMode, go through normal mode processes if (l1_config.TestMode == 0) { #endif #if(L1_DYN_DSP_DWNLD==1) // Dynamic download L1A state machine l1a_dyn_dsp_dwnld_process(msg); #endif #if L1_GPRS // Pass the new msg to packet L1A. l1pa_task(msg); #endif #if TESTMODE } #endif #endif #if (GSM_IDLE_RAM != 0) #if L1_GPRS if ((msg->SignalCode != L1C_NP_INFO) && (msg->SignalCode != L1C_EP_INFO) && (msg->SignalCode != L1C_RXLEV_PERIODIC_DONE) && (msg->SignalCode != L1P_PNP_INFO) && (msg->SignalCode != L1P_PEP_INFO) && (l1a_l1s_com.mode == I_MODE)) #else if ((msg->SignalCode != L1C_NP_INFO) && (msg->SignalCode != L1C_EP_INFO) && (msg->SignalCode != L1C_RXLEV_PERIODIC_DONE) && (l1a_l1s_com.mode == I_MODE)) #endif #if (GSM_IDLE_RAM > 1) // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM { #endif { l1s.gsm_idle_ram_ctl.l1s_full_exec = TRUE; } #endif // GSM_IDLE_RAM // Clear L1A "enable meas and tasks" variables. //--------------------------------------------- for(process=0; process<NBR_L1A_PROCESSES; process++) { l1a.l1a_en_meas[process] = NO_TASK; } // Go through all processes... /******************************/ #if TESTMODE // if NOT in TestMode, go through normal mode processes if (l1_config.TestMode == 0) { #endif // Hardware test: //--------------- l1a_test_process(msg); #if (OP_L1_STANDALONE == 1) // Dynamic configuration : clock management for test l1a_test_config_process(msg); #endif #if (TRACE_TYPE==3) // Statistics or Test process: //--------------------------- l1a_stats_process(msg); #endif // ADC conversion: //---------------- l1a_mmi_adc_req(msg); // Frequency Band configuration: GSM900, E-GSM900, DCS1800, DUAL, DUALEXT, PCS 1900 //---------------------------------------------------------------------------------- l1a_freq_band_configuration(msg); // Network synchronization process: //--------------------------------- // Synchronization with a Neighbour cell for Cell Selection. l1a_initial_network_sync_process(msg); // lost Network l1a_network_lost(msg); // Cell Selection/Idle processes: //------------------------------- // Full list receive level monitoring. l1a_full_list_meas_process(msg); // 6 strongest Neighbor cells synchro. monitoring. l1a_idle_6strongest_monitoring_process(msg); // 6 strongest Neighbor cells BCCH reading. l1a_neighbour_cell_bcch_reading_process(msg); // Serving Cell BCCH reading. l1a_idle_serving_cell_bcch_reading_process(msg); #if (GSM_IDLE_RAM <= 1) // Serving Cell PAGING reading. l1a_idle_serving_cell_paging_process(msg); #endif // Short Message Servive Cell Broadcast reading. l1a_idle_smscb_process(msg); #if (GSM_IDLE_RAM <= 1) // BA list (periodic) power monitoring. l1a_idle_ba_list_meas_process(msg); #endif // Cell Reselection processes: //---------------------------- // Synchronization and requested BCCH reading. // --> camp on new serving cell. l1a_cres_process(msg); // Connection Establishment processes (also called "Link Access"): //---------------------------------------------------------------- // Link Access process. l1a_access_process(msg); // Dedicated mode processes: //-------------------------- // Dedicated mode process. l1a_dedicated_process(msg); // 6 strongest Neighbor cells synchro. monitoring and BCCH reading. l1a_dedic6_process(msg); // BA list (periodic) power monitoring. l1a_dedic_ba_list_meas_process(msg); #if (L1_GTT == 1) // GTT process handling. l1a_mmi_gtt_process(msg); #endif #if (AUDIO_TASK == 1) #if (OP_RIV_AUDIO == 1) #if (L1_AUDIO_DRIVER == 1) l1a_audio_driver_process(msg); #endif #endif #if (KEYBEEP) // Keybeep task process l1a_mmi_keybeep_process(msg); #endif #if (TONE) // Tone task process l1a_mmi_tone_process(msg); #endif #if (L1_CPORT == 1) // Cport task process l1a_mmi_cport_process(msg); #endif #if (MELODY_E1) // Melody 0 task process l1a_mmi_melody0_process(msg); // Melody 1 task process l1a_mmi_melody1_process(msg); #endif #if (VOICE_MEMO) // Voice memo playing process l1a_mmi_vm_playing_process(msg); // Voice memo recording process l1a_mmi_vm_recording_process(msg); #endif #if (L1_PCM_EXTRACTION) /* PCM download process */ l1a_mmi_pcm_download_process(msg); /* PCM upload process */ l1a_mmi_pcm_upload_process(msg); #endif #if (L1_VOICE_MEMO_AMR) // Voice memo amr playing process l1a_mmi_vm_amr_playing_process(msg); // Voice memo amr recording process l1a_mmi_vm_amr_recording_process(msg); #endif #if (SPEECH_RECO) // Speech recognition enrollment process l1a_mmi_sr_enroll_process(msg); // Speech recognition update process l1a_mmi_sr_update_process(msg); // Speech recognition reco process l1a_mmi_sr_reco_process(msg); // Speech recognition update-check process l1a_mmi_sr_update_check_process(msg); #endif #if (AEC) // AEC process l1a_mmi_aec_process(msg); #endif #if (FIR) // FIR process l1a_mmi_fir_process(msg); #endif #if (AUDIO_MODE) // AUDIO MODE process l1a_mmi_audio_mode_process(msg); #endif #if (MELODY_E2) // MELODY E2 process l1a_mmi_melody0_e2_process(msg); l1a_mmi_melody1_e2_process(msg); #endif #if (L1_MP3==1) // MP3 process l1a_mmi_mp3_process(msg); #endif #if (L1_MIDI==1) // MIDI process l1a_mmi_midi_process(msg); #endif //ADDED FOR AAC #if (L1_AAC==1) // AAC process l1a_mmi_aac_process(msg); #endif #if (L1_EXTERNAL_AUDIO_VOICE_ONOFF == 1 || L1_EXT_MCU_AUDIO_VOICE_ONOFF == 1) l1a_mmi_audio_onoff_process(msg); #endif #if (L1_EXT_AUDIO_MGT == 1) // External audio_mgt task process l1a_mmi_ext_audio_mgt_process(msg); #endif #if (L1_ANR == 1 || L1_ANR == 2) l1a_mmi_anr_process(msg); #endif #if (L1_IIR == 1 || L1_IIR == 2) l1a_mmi_iir_process(msg); #endif #if (L1_AGC_UL == 1) l1a_mmi_agc_ul_process(msg); #endif #if (L1_AGC_DL == 1) l1a_mmi_agc_dl_process(msg); #endif #if (L1_WCM == 1) l1a_mmi_wcm_process(msg); #endif #if (L1_DRC == 1) l1a_mmi_drc_process(msg); #endif #if (L1_LIMITER == 1) l1a_mmi_limiter_process(msg); #endif #if (L1_ES == 1) l1a_mmi_es_process(msg); #endif #if (L1_VOCODER_IF_CHANGE == 1) l1a_mmi_vocoder_cfg_process(msg); #endif // L1_VOCODER_IF_CHANGE == 1 #if(L1_BT_AUDIO ==1) l1a_mmi_bt_process(msg); #endif // L1_VOCODER_IF_CHANGE == 1 /* * FreeCalypso Frankenstein: the following call to * l1a_mmi_outen_cfg_process() was totally unconditional * in the LoCosto source we got, but no such function * exists in TCS211. To be investigated further when * we reach the audio stuff. */ #if 0 l1a_mmi_outen_cfg_process(msg); #endif #endif //AUDIO TASK // Only processes supported by GSM IDLE in Internal RAM #if (GSM_IDLE_RAM > 1) #if L1_GPRS if ((msg->SignalCode >> 8) == P_GPRS) l1pa_task(msg); #endif // Serving Cell PAGING reading. l1a_idle_serving_cell_paging_process(msg); // BA list (periodic) power monitoring. l1a_idle_ba_list_meas_process(msg); #endif // GSM_IDLE_RAM > 1 #if TESTMODE } // end if not in TestMode //TestMode State Machine l1a_tmode(msg); #endif // TESTMODE // Make a balance for L1A "tasks and meas tasks". //=============================================== l1a_balance_l1a_tasks(); l1a_l1s_com.l1a_activity_flag = TRUE; #if (DRP_FW_EXT == 1) } /* end if DRP boot success boot_result == 0 */ #endif // Deallocate memory for the received message if msg not forwarded to L3. // ---------------------------------------------------------------------- if(l1a.l1_msg_forwarded == FALSE) { os_free_sig(msg); DEBUGMSG(status,NU_DEALLOC_ERR) } } // end while(). } // end of procedure. //----------------------------------------------------------------------------------------------- /*-------------------------------------------------------*/ /* l1a_balance_l1a_tasks() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* This function enables the L1S tasks consequently to */ /* the L1A state machine requests. */ /* */ /*-------------------------------------------------------*/ void l1a_balance_l1a_tasks() { UWORD8 process; UWORD32 l1a_en_meas = 0; #if L1_GPRS UWORD32 l1pa_en_meas = 0; #endif UWORD32 l1a_dl_en_task = 0; for(process=0; process<NBR_L1A_PROCESSES; process++) { // Balance for measurement tasks. l1a_en_meas |= l1a.l1a_en_meas[process]; } #if L1_GPRS for(process=0; process<NBR_L1PA_PROCESSES; process++) { // Balance for measurement tasks. l1pa_en_meas |= l1pa.l1pa_en_meas[process]; } // Balance for Packet measurement tasks. l1pa_l1ps_com.l1ps_en_meas |= l1pa_en_meas; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_l1tsk(l1pa_en_meas, l1pa.l1pa_en_meas); #endif #endif // Balance for measurement tasks. l1a_l1s_com.l1s_en_meas |= l1a_en_meas; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_l1tsk(l1a_en_meas, l1a.l1a_en_meas); #endif } // end of procedure. //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END #endif //----------------------------------------------------------------------------------------------- #if (TRACE_TYPE==3) /*-------------------------------------------------------*/ /* l1a_stats_process() */ /*-------------------------------------------------------*/ /* Description : This function handles statistics */ /* or test mode setting. */ /* */ /* Starting messages: L1_STATS_REQ. */ /* L1_PLAY_REQ. */ /* */ /* Result messages (input): none */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_stats_process(xSignalHeaderRec *msg) { UWORD32 SignalCode = msg->SignalCode; if(SignalCode == L1_STATS_REQ) { // store type of burst to spy... l1_stats.type = ((T_L1_STATS_REQ *)(msg->SigP))->type; // initialize variables and buffer for statistics... initialize_stats(); } } #endif /*-------------------------------------------------------*/ /* l1a_test_process() */ /*-------------------------------------------------------*/ /* Description : This function tests hardware and DSP. */ /* */ /* Starting messages: TST_TEST_HW_REQ */ /* */ /* Result messages (input): TST_TEST_HW_CON */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_test_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_RESULT = 2 }; UWORD8 *state = &l1a.state[HW_TEST]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) if (trace_info.init_trace == 1) { *state = WAIT_RESULT; if(SignalCode == TST_TEST_HW_REQ) { trace_info.init_trace = 0; } } #endif while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset tasks used in the process. l1a_l1s_com.l1s_en_task[HWTEST] = TASK_DISABLED; // Clear task enable flag. } break; case WAIT_INIT: { // Use incoming message //--------------------- if(SignalCode == TST_TEST_HW_REQ) { *state = WAIT_RESULT; // set tasks used in the process. l1a_l1s_com.l1s_en_task[HWTEST] = TASK_ENABLED; // Set task enable flag. } // End of process. end_process = 1; } break; case WAIT_RESULT: { // Use incoming message //--------------------- if(SignalCode == L1_TEST_HW_INFO) { #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) if (trace_info.init_trace == 0) #endif // Forward result message to L3. l1a_send_result(TST_TEST_HW_CON, msg, RRM1_QUEUE); #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) else trace_info.init_trace = 0; #endif *state = RESET; } else { end_process = 1; } } break; } } } #if (OP_L1_STANDALONE == 1) /*-------------------------------------------------------*/ /* l1a_test_config_process() */ /*-------------------------------------------------------*/ /* Description : This function allows modify the original*/ /* initialization of hardware parameters */ /* like for example clock configuration. */ /* */ /* Starting messages: TST_HW_CONFIG_REQ */ /* TST_SW_CONFIG_REQ */ /* */ /* Result messages (input): none */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_test_config_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1 }; UWORD8 *state = &l1a.state[HSW_CONF]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // step in state machine. *state = WAIT_INIT; // Reset tasks used in the process. //l1a_l1s_com.l1s_en_task[HSWCONF] = TASK_DISABLED; // Clear task enable flag. } break; case WAIT_INIT: { if(SignalCode == TST_HW_CONFIG_REQ) /* * Depending on the arguments of the message, * actions are different (clock config, ABB config, ...). * The first argument is for clock configuration. */ { #if (CHIPSET == 4) || (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 10) || \ (CHIPSET == 11) || (CHIPSET == 12) || (CHIPSET == 15) /* Only SAMSON/CALYPSO families are considered for dynamic clock configuration.*/ UWORD8 d_clock_cfg; // Num of selected clock configuration. /* * Read num of selected clock configuration as first arg of message */ d_clock_cfg = ((T_TST_HW_CONFIG_REQ *)(msg->SigP))->num_of_clock_cfg; /* * Check if dynamic clock configuration requested. * If FFh, no dynamic clock configuration is requested. */ #if (CODE_VERSION != SIMULATION) if (d_clock_cfg != C_CLOCK_NO_CFG) { /* If wrong index, keep the current clock configuration unchanged */ f_dynamic_clock_cfg(d_clock_cfg); } #endif /* Only SAMSON/CALYPSO families are considered for dynamic clock configuration.*/ #endif // CHIPSET = 4 or 7 or 8 or 10 or 11 or 12 // set tasks used in the process. //l1a_l1s_com.l1s_en_task[HSWCONF] = TASK_ENABLED; // Set task enable flag. // step in state machine. *state = RESET; } if(SignalCode == TST_SW_CONFIG_REQ) /* * Depending on the arguments of the message, * actions are different. */ { #if IDS l1_config.ids_enable = ((T_TST_SW_CONFIG_REQ *)(msg->SigP))->ids_enable; #endif l1_config.facch_test.enable = ((T_TST_SW_CONFIG_REQ *)(msg->SigP))->facch_test.enable; l1_config.facch_test.period = ((T_TST_SW_CONFIG_REQ *)(msg->SigP))->facch_test.period; if ((l1_config.facch_test.enable) && (l1_config.facch_test.period == 0)) { l1_config.facch_test.period = 1; } // set tasks used in the process. //l1a_l1s_com.l1s_en_task[HSW_CONF] = TASK_ENABLED; // Set task enable flag. // step in state machine. *state = RESET; } // End of process. end_process = 1; } break; } // end of "switch". } // end of "while" } // end of procedure. #endif // OP_L1_STANDALONE /*-------------------------------------------------------*/ /* l1a_mmi_adc_req () */ /*-------------------------------------------------------*/ /* Description : This function is in charge of requesting*/ /* L1 to trigger an ADC conversion sequence*/ /* */ /* Starting messages: MMI_ADC_REQ */ /* */ /* Result messages (input): none */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_mmi_adc_req(xSignalHeaderRec *msg) { UWORD32 SignalCode = msg->SignalCode; UWORD8 *state = &l1a.state[I_ADC]; enum states { RESET = 0, WAIT_INIT = 1 }; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { l1a_l1s_com.adc_cpt = 0; l1a_l1s_com.adc_mode = ADC_DISABLED; // Disable ADC tasks used in CS_MODE0 l1a_l1s_com.l1s_en_task[ADC_CSMODE0] = TASK_DISABLED; // Reset ADC task enable flag. // Step in state machine. *state = WAIT_INIT; } break; case WAIT_INIT: { // Use incoming message //--------------------- if(SignalCode == MMI_ADC_REQ) { UWORD8 tx_flag; tx_flag = ((T_MMI_ADC_REQ *)(msg->SigP))-> tx_flag; l1a_l1s_com.adc_traffic_period = ((T_MMI_ADC_REQ *)(msg->SigP))-> traffic_period; l1a_l1s_com.adc_idle_period = ((T_MMI_ADC_REQ *)(msg->SigP))-> idle_period; // ------------------------------- // Activation for Idle and CS_MODE // ------------------------------- l1a_l1s_com.adc_mode = ADC_DISABLED; l1a_l1s_com.adc_cpt = 0; if (l1a_l1s_com.adc_idle_period == 0) { // performed only one time l1a_l1s_com.adc_mode |= ADC_NEXT_NORM_PAGING | ADC_NEXT_MEAS_SESSION | ADC_NEXT_CS_MODE0 ; } else { // performed on each periode l1a_l1s_com.adc_mode |= ADC_EACH_NORM_PAGING | ADC_EACH_MEAS_SESSION | ADC_EACH_CS_MODE0 ; } // ---------------------------------------------------------- // Activation for Dedicated and Connection Establishment mode // ---------------------------------------------------------- if (tx_flag == 1) // ADC is performed inside a TX burst { l1a_l1s_com.adc_mode |= ADC_EACH_RACH; // traffic_period is meaningless for RACH / PRACH if (l1a_l1s_com.adc_traffic_period == 0) { // performed only one time l1a_l1s_com.adc_mode |= ADC_NEXT_TRAFFIC_UL; } else { // performed on each periode l1a_l1s_com.adc_mode |= ADC_EACH_TRAFFIC_UL; } } else // ADC is performed outside a TX burst { if (l1a_l1s_com.adc_traffic_period == 0) { // performed only one time l1a_l1s_com.adc_mode |= ADC_NEXT_TRAFFIC_DL; } else { // performed on each periode l1a_l1s_com.adc_mode |= ADC_EACH_TRAFFIC_DL; } if (l1a_l1s_com.adc_idle_period == 0) { // performed only one time l1a_l1s_com.adc_mode |= ADC_NEXT_NORM_PAGING_REORG; } else { // performed on each periode l1a_l1s_com.adc_mode |= ADC_EACH_NORM_PAGING_REORG; } } l1a_l1s_com.l1s_en_task[ADC_CSMODE0] = TASK_ENABLED; // enable ADC task for CS_MODE0 } else if(SignalCode == MMI_STOP_ADC_REQ) { // send confirmation message l1a_send_confirmation(MMI_STOP_ADC_CON,RRM1_QUEUE); // Disable ADC tasks used in CS_MODE0 // It is mandatory to disable the task here because in CS_MODE0 there is no new messages // to validate the RESET state in the state machine. l1a_l1s_com.l1s_en_task[ADC_CSMODE0] = TASK_DISABLED; // Reset ADC task enable flag. // This process must be reset. *state = RESET; } // End of process. end_process = 1; } break; } } } /*-------------------------------------------------------*/ /* l1a_network_lost() */ /*-------------------------------------------------------*/ /* Description : This function allows the MS to enter in */ /* deep sleep while it is performig cell */ /* selection full power measurement */ /* */ /* Starting messages: MPHC_NETWORK_LOST_IND */ /* */ /* Result messages (input): none */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_network_lost(xSignalHeaderRec *msg) { UWORD32 SignalCode = msg->SignalCode; if(SignalCode == MPHC_NETWORK_LOST_IND) { // set new mode in order to allow the deep sleep l1a_l1s_com.mode = CS_MODE0; // reset the gauging algorithm in order to re-compute // the 32khz/13Mhz when re-enter in IDLE mode. l1ctl_gauging (0,0); } } #if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2 //#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise /*-------------------------------------------------------*/ /* l1a_idle_ba_list_meas_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles neigbor cell */ /* measurement process in IDLE mode with BA list. */ /* */ /* Starting messages: MPHC_RXLEV_PERIODIC_REQ */ /* ------------------ */ /* L1 starts then the periodic BA list receive level */ /* monitoring. */ /* */ /* Subsequent messages: MPHC_RXLEV_PERIODIC_REQ */ /* -------------------- */ /* L1 changes the BA list and starts the periodic BA */ /* list receive level monitoring with this new list. */ /* */ /* Result messages (input): L1C_RXLEV_PERIODIC_DONE */ /* ------------------------ */ /* This is the periodic reporting message from L1s. */ /* */ /* Result messages (output): MPHC_RXLEV_PERIODIC_IND */ /* ------------------------- */ /* This is the periodic reporting message to L3. */ /* */ /* Reset messages (input): MPHC_STOP_RXLEV_PERIODIC_REQ*/ /* ----------------------- */ /* BA list neigbor cell measurement process in IDLE */ /* is stopped by this message. */ /* */ /*-------------------------------------------------------*/ void l1a_idle_ba_list_meas_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_RESULT = 3 }; UWORD8 *state = &l1a.state[I_NMEAS]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // step in state machine. *state = WAIT_INIT; // Reset I_NMEAS process. l1a_l1s_com.l1s_en_meas &= I_BAMS_MEAS_MASK; // Reset I_BAMS Measurement enable flag. } break; case WAIT_INIT: { if(SignalCode == MPHC_RXLEV_PERIODIC_REQ) // We receive the BA list to be monitored. //---------------------------------------- { UWORD8 ba_id; UWORD8 nbchans; TC_CHAN_LIST *listptr; UWORD8 next_radio_freq_measured; UWORD8 i; nbchans = ((T_MPHC_RXLEV_PERIODIC_REQ *)(msg->SigP))->num_of_chans; listptr = &(((T_MPHC_RXLEV_PERIODIC_REQ *)(msg->SigP))->chan_list); ba_id = ((T_MPHC_RXLEV_PERIODIC_REQ *)(msg->SigP))->ba_id; next_radio_freq_measured = ((T_MPHC_RXLEV_PERIODIC_REQ *)(msg->SigP))->next_radio_freq_measured; // Set parameter synchro semaphore for I_BAMS task. l1a_l1s_com.meas_param |= I_BAMS_MEAS; // Reset the BA list structure. l1a_reset_ba_list(); // Store ARFCN list in the BA structure. for(i=0;i<nbchans;i++) l1a_l1s_com.ba_list.A[i].radio_freq = listptr->A[i]; // Set number of carrier in the BA list. l1a_l1s_com.ba_list.nbr_carrier = nbchans; // Set BA identifier. l1a_l1s_com.ba_list.ba_id = ba_id; // Carrier for next power measurement control. l1a_l1s_com.ba_list.next_to_ctrl = next_radio_freq_measured; // Carrier for next power measurement result. l1a_l1s_com.ba_list.next_to_read = next_radio_freq_measured; // Set first BA index measured in current session. l1a_l1s_com.ba_list.first_index = next_radio_freq_measured; // Enable BA list measurement task. l1a.l1a_en_meas[I_NMEAS] |= I_BAMS_MEAS; // step in state machine. *state = WAIT_RESULT; } // End of process. end_process = 1; } break; case WAIT_RESULT: { if(SignalCode == L1C_RXLEV_PERIODIC_DONE) // One bunch of measurement has been completed. //--------------------------------------------- { // Forward result message to L3. l1a_send_result(MPHC_RXLEV_PERIODIC_IND, msg, RRM1_QUEUE); // End of process. return; } else #if (L1_GPRS) if((SignalCode == MPHC_STOP_RXLEV_PERIODIC_REQ) || (SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1C_DEDIC_DONE)) #else if((SignalCode == MPHC_STOP_RXLEV_PERIODIC_REQ) || (SignalCode == L1C_DEDIC_DONE)) #endif // Request to STOP this activity. //------------------------------- { // send confirmation message l1a_send_confirmation(MPHC_STOP_RXLEV_PERIODIC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else if (SignalCode == MPHC_RXLEV_PERIODIC_REQ) { // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END // KEEP IN EXTERNAL MEM otherwise #endif /*-------------------------------------------------------*/ /* l1a_full_list_meas_process() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* This function is a state machine which handles the */ /* Cell Selection Full List Power Measurement L1/L3 */ /* interface and it handles the neigbour cell */ /* measurement process in IDLE mode with FULL list. */ /* When a message MPHC_RXLEV_REQ is received */ /* the L1S task FSMS_MEAS is enabled. When this task */ /* is completed a reporting message L1C_VALID_MEAS_INFO */ /* is received and forwarded to L3. */ /* */ /* Starting messages: MPHC_RXLEV_REQ. */ /* */ /* Result messages (input): L1C_VALID_MEAS_INFO */ /* */ /* Result messages (output): MPHC_RXLEV_IND */ /* */ /* Reset messages (input): none */ /* */ /* Stop message (input): MPHC_STOP_RXLEV_REQ */ /* */ /* Stop message (output): MPHC_STOP_RXLEV_CON */ /* */ /* Rem: */ /* ---- */ /* L3 is in charge of the number of pass to follow the */ /* GSM recommendation. */ /* */ /*-------------------------------------------------------*/ void l1a_full_list_meas_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_RESULT = 2 }; UWORD8 *state = &l1a.state[FULL_MEAS]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset FULL_MEAS process. l1a_l1s_com.l1s_en_meas &= FSMS_MEAS_MASK; // Clear Cell Selection Measurement enable flag. } break; case WAIT_INIT: { if(SignalCode == MPHC_RXLEV_REQ) // Request to enter the Cell Selection measurements. //-------------------------------------------------- { UWORD16 i; #if L1_RECOVERY // check whether we need to recover L1 if (l1a_l1s_com.recovery_flag == TRUE) { // recovery only allowed during cell selection to avoid side effects // Transition rules: MPHC_RXLEV_REQ may also be sent in idle mode or packet idle mode // check whether idle mode task NP inactive #if L1_GPRS if ((l1a_l1s_com.l1s_en_task[NP] == TASK_DISABLED) && (l1a_l1s_com.l1s_en_task[PNP] == TASK_DISABLED)) #else if (l1a_l1s_com.l1s_en_task[NP] == TASK_DISABLED) #endif { #if (CHIPSET == 12) || (CHIPSET == 15) F_INTH_DISABLE_ONE_IT(C_INTH_FRAME_IT); // disable IT TDMA #else INTH_DISABLEONEIT(IQ_FRAME); // disable IT TDMA #endif #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) { l1_trace_recovery(); } #endif l1_initialize_for_recovery(); // Set SYNCHRO task enable flag in order to call the function l1d_reset_hw l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; #if (CHIPSET == 12) || (CHIPSET == 15) F_INTH_ENABLE_ONE_IT(C_INTH_FRAME_IT); // enable IT TDMA #else INTH_ENABLEONEIT(IQ_FRAME); // enable IT TDMA #endif } } #endif // download info from message l1a_l1s_com.full_list_ptr=(T_MPHC_RXLEV_REQ *)(msg->SigP); if (l1a_l1s_com.full_list_ptr->power_array_size==0) return; //empty list -> return // Set "parameter synchro semaphores" l1a_l1s_com.meas_param |= FSMS_MEAS; // Reset the full list structure. l1a_reset_full_list(); // Reset the Input Level (IL) memory table. if ((l1a_l1s_com.mode == CS_MODE) || (l1a_l1s_com.mode == CS_MODE0)) { #if (L1_FF_MULTIBAND == 0) for(i=0; i<=l1_config.std.nbmax_carrier; i++) #else for(i=0; i<= NBMAX_CARRIER; i++) #endif { l1a_l1s_com.last_input_level[i].input_level = l1_config.params.il_min; l1a_l1s_com.last_input_level[i].lna_off = 0; } } // Enable Cell Selection Full list measurement task. l1a.l1a_en_meas[FULL_MEAS] |= FSMS_MEAS; // Step in state machine. *state = WAIT_RESULT; } // End of process. end_process = 1; } break; case WAIT_RESULT: { if(SignalCode == L1C_VALID_MEAS_INFO) // One valid measurement pass has been completed over the full list of carriers. //------------------------------------------------------------------------------ { //-------------------------------------------------------- // WE COULD PUT HERE THE CODE TO TRANSLATE IL -> RXLEV !!! //-------------------------------------------------------- // Forward result message to L3. l1a_send_result(MPHC_RXLEV_IND, msg, RRM1_QUEUE); // Reset the machine. *state = RESET; } else if (SignalCode == MPHC_STOP_RXLEV_REQ) { // Forward result message to L3. l1a_send_confirmation(MPHC_STOP_RXLEV_CON,RRM1_QUEUE); // Reset the machine. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_cres_process() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* This function is a state machine which handles Cell */ /* Reselection. */ /* */ /* Starting messages: MPHC_NEW_SCELL_REQ */ /* ------------------ */ /* L1 camps on the given ARFCN. */ /* */ /* Result messages (output): MPHC_NEW_SCELL_CON */ /* ------------------------- */ /* */ /*-------------------------------------------------------*/ void l1a_cres_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1 }; UWORD8 *state = &l1a.state[CR_B]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; } break; case WAIT_INIT: { if(SignalCode == MPHC_NEW_SCELL_REQ) // Request to enter the Cell Reselection BCCH reading. //---------------------------------------------------- // L1 must keep reading the system informations flagged // in the bitmap. { // Reset the Neighbor Cell information structure. l1a_reset_cell_info(&(l1a_l1s_com.Scell_info)); // Reset serving cell E-OTD store on Cell Change #if ((L1_EOTD == 1) && (L1_EOTD_QBIT_ACC == 1)) l1a_l1s_com.nsync.serv_fn_offset = 0; l1a_l1s_com.nsync.serv_time_alignmt = 0; #endif // Download ARFCN, timing information and bitmap from the command message. l1a_l1s_com.Scell_info.radio_freq = ((T_MPHC_NEW_SCELL_REQ *)(msg->SigP))->radio_freq; l1a_l1s_com.Scell_info.bsic = ((T_MPHC_NEW_SCELL_REQ *)(msg->SigP))->bsic; l1a_l1s_com.Scell_info.time_alignmt = ((T_MPHC_NEW_SCELL_REQ *)(msg->SigP))->time_alignmt; l1a_l1s_com.Scell_info.fn_offset = ((T_MPHC_NEW_SCELL_REQ *)(msg->SigP))->fn_offset; #if (L1_FF_MULTIBAND == 1) { UWORD8 physical_band_id; physical_band_id = l1_multiband_radio_freq_convert_into_physical_band_id(l1a_l1s_com.Scell_info.radio_freq ); L1_MULTIBAND_TRACE_PARAMS(MULTIBAND_PHYSICAL_BAND_TRACE_ID,multiband_rf[physical_band_id].gsm_band_identifier); } #endif /*#if (L1_FF_MULTIBAND == 1)*/ // Layer 1 internal mode is set to CS MODE. l1a_l1s_com.mode = CS_MODE; // Set flag for toa init. #if (TOA_ALGO != 0) l1a_l1s_com.toa_reset = TRUE; #endif // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += 0 - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = 0; // Camping on timeslot 0. #if L1_GPRS // Select GSM DSP Scheduler. l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; #endif // Timing must be shifted to a new timeslot, enables SYNCHRO task.. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Step in state machine. *state = RESET; // Send confirmation message to L3. l1a_send_confirmation(MPHC_NEW_SCELL_CON,RRM1_QUEUE); // End of process. end_process = 1; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_neighbour_cell_bcch_reading_process() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* This function is a state machine which handles the */ /* BCCH reading from up to 6 neighbour cells */ /* */ /* Starting messages: MPHC_NCELL_BCCH_REQ */ /* ------------------ */ /* */ /* Result messages (input): L1C_BCCHN_INFO */ /* ------------------------ */ /* */ /* Result messages (output): MPHC_NCELL_BCCH_IND */ /* ------------------------- */ /* */ /* Reset messages (input): MPHC_STOP_NCELL_BCCH_REQ */ /* ----------------------- (MPHC_STOP_NCELL_BCCH_CON) */ /* */ /*-------------------------------------------------------*/ void l1a_neighbour_cell_bcch_reading_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, BCCHN_CONFIG = 2, WAIT_BCCHN_RESULT = 3 }; UWORD8 *state = &l1a.state[I_BCCHN]; UWORD32 SignalCode = msg->SignalCode; UWORD32 time_alignmt; UWORD32 fn_offset; UWORD8 task; // use only in packet transfer mode // in this mode only one neighbor is allowed to be decoded // so these variables memorize this neighbor parameters. static UWORD32 time_alignmt_mem; static UWORD32 fn_offset_mem; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset CS_MEAS process. l1a_l1s_com.l1s_en_task[BCCHN] = TASK_DISABLED; // Clear BCCHN task enable flag. l1a_l1s_com.l1s_en_task[BCCHN_TOP] = TASK_DISABLED; // Clear BCCHN_TOP task enable flag. #if (L1_GPRS) l1a_l1s_com.l1s_en_task[BCCHN_TRAN] = TASK_DISABLED; // Clear BCCHN_TRAN task enable flag. #endif } break; case WAIT_INIT: { if(SignalCode == MPHC_NCELL_BCCH_REQ) // Request to read BCCH from one neighbour cell. //---------------------------------------------- { // there are 3 priorities with BCCH neighbor task // => TOP PRIORITY: this request has priority over serving cell activity // and any other neighbor cells activity (used for GPRS). // In IDLE circuit this priority enable the task BCCHN_TOP // In Packet Transfer this priority enable the task BCCHN_TRAN // => HIGH_PRIORITY:this request has priority over the neighbor cell BCCH reading // with priority set to NORMAL_PRIORITY. // => NORMAL_PRIORITY:this request has no special priority. // Note: HIGH_PRIORITY and NORMAL_PRIORITY enable the task BCCHN. #if (L1_GPRS) if(l1a_l1s_com.mode == PACKET_TRANSFER_MODE) task = BCCHN_TRAN; else if(((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->gprs_priority == TOP_PRIORITY) task = BCCHN_TOP; else task = BCCHN; #else task = BCCHN; #endif // Set semaphores for neighbor BCCH task. l1a_l1s_com.task_param[task] = SEMAPHORE_SET; // Step in state machine. *state = BCCHN_CONFIG; } // No action in this machine for other messages. else { // End of process. return; } } break; case BCCHN_CONFIG: { // Request to read BCCH from one neighbour cell. //---------------------------------------------- UWORD8 neigh_number = 0; UWORD8 neigh_id; // there are 3 priorities with BCCH neighbor task // => TOP PRIORITY: this request has priority over serving cell activity // and any other neighbor cells activity (used for GPRS). // In IDLE circuit this priority enable the task BCCHN_TOP // In Packet Transfer this priority enable the task BCCHN_TRAN // => HIGH_PRIORITY:this request has priority over the neighbor cell BCCH reading // with priority set to NORMAL_PRIORITY. // => NORMAL_PRIORITY:this request has no special priority. // Note: HIGH_PRIORITY and NORMAL_PRIORITY enable the task BCCHN. #if (L1_GPRS) if(l1a_l1s_com.mode == PACKET_TRANSFER_MODE) task = BCCHN_TRAN; else if(((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->gprs_priority == TOP_PRIORITY) task = BCCHN_TOP; else task = BCCHN; #else task = BCCHN; #endif #if (L1_GPRS) //in case of packet transfer mode //only one neighbor is allowed to be decoded => clear the BCCHN list. if(l1a_l1s_com.mode == PACKET_TRANSFER_MODE) { for (neigh_id=0;neigh_id<6;neigh_id++) l1a_l1s_com.bcchn.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.bcchn.current_list_size = 0; } #endif // Abort if there is no room for a new neighbour BCCH reading request. if(l1a_l1s_com.bcchn.current_list_size >= 6) { *state = WAIT_BCCHN_RESULT; return; } // Look for first free location within L1 structure. while((neigh_number < 6) && (l1a_l1s_com.bcchn.list[neigh_number].status != NSYNC_FREE)) neigh_number++; // Download neighbour info from request message. //---------------------------------------------- // Download ARFCN, timing information and bitmap from the command message. time_alignmt_mem = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->time_alignmt; fn_offset_mem = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->fn_offset; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. time_alignmt =time_alignmt_mem; fn_offset =fn_offset_mem; l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_l1s_com.bcchn.list[neigh_number].radio_freq = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->radio_freq; l1a_l1s_com.bcchn.list[neigh_number].fn_offset = fn_offset; l1a_l1s_com.bcchn.list[neigh_number].time_alignmt = time_alignmt; l1a_l1s_com.bcchn.list[neigh_number].tsc = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->tsc; l1a_l1s_com.bcchn.list[neigh_number].bcch_blks_req = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->bcch_blks_req; #if L1_GPRS // in packet transfer only one priority is allowed : TOP_PRIORITY if(l1a_l1s_com.mode != PACKET_TRANSFER_MODE) l1a_l1s_com.bcchn.list[neigh_number].gprs_priority = ((T_MPHC_NCELL_BCCH_REQ *)(msg->SigP))->gprs_priority; else l1a_l1s_com.bcchn.list[neigh_number].gprs_priority = TOP_PRIORITY; #else l1a_l1s_com.bcchn.list[neigh_number].gprs_priority = NORMAL_PRIORITY; #endif // Enable L1S activity on this new neighbour task BCCH. l1a_l1s_com.bcchn.list[neigh_number].status = NSYNC_PENDING; l1a_l1s_com.bcchn.current_list_size += 1; l1a_l1s_com.l1s_en_task[task] = TASK_ENABLED; // Step in state machine. *state = WAIT_BCCHN_RESULT; // End of process. end_process = 1; } break; // case BCCHN_CONFIG case WAIT_BCCHN_RESULT: { if(SignalCode == L1C_BCCHN_INFO) // Neighbor cell BCCH reading result. //----------------------------------- { UWORD8 neigh_id = ((T_L1C_BCCHN_INFO *)(msg->SigP))->neigh_id; UWORD16 neigh_radio_freq = ((T_L1C_BCCHN_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_BCCH_REQ message has been received // in the same frame than this L1s message) // BUG_973: an issue occurs when this 3 messages arrives in this order and // in the same frame MPHC_STOP_NCELL_BCCH_REQ(A) + MPHC_NCELL_BCCH_REQ(B) + this L1s message(A) // In this case the carrier B wasn't handled because the L1s message deletes the carrier B in the list if (neigh_radio_freq != l1a_l1s_com.bcchn.list[neigh_id].radio_freq) { // REM: the message is not sent to L3 return; // Stay in current state. } // Disable neigh BCCH reading when any of the TC have been read. l1a_l1s_com.bcchn.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.bcchn.current_list_size -= 1; // Forward result message to L3. l1a_send_result(MPHC_NCELL_BCCH_IND, msg, RRM1_QUEUE); // Is it the end of the complete process ? if(l1a_l1s_com.bcchn.current_list_size == 0) { // This process must be reset. *state = RESET; } else { // End of process. return; } } else if(SignalCode == MPHC_NCELL_BCCH_REQ) // Request to read BCCH from one neighbour cell. //----------------------------------- { // Step in state machine. *state = BCCHN_CONFIG; } else if(SignalCode == MPHC_STOP_NCELL_BCCH_REQ) // Request to STOP neighbour cell activity for certain carriers. //-------------------------------------------------------------- { UWORD8 i,j; UWORD8 array_size; // Disable neighbor BCCH task. l1a_l1s_com.l1s_en_task[BCCHN] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[BCCHN_TOP] = TASK_DISABLED; #if (L1_GPRS) l1a_l1s_com.l1s_en_task[BCCHN_TRAN] = TASK_DISABLED; #endif array_size = ((T_MPHC_STOP_NCELL_BCCH_REQ *)(msg->SigP))->radio_freq_array_size; if(array_size != 6) { // Stop some of the Neighb. synchro. for(i=0;i<array_size;i++) { UWORD16 radio_freq = ((T_MPHC_STOP_NCELL_BCCH_REQ *)(msg->SigP))->radio_freq_array[i]; // Search for same value within L1 structure. j=0; while(!((radio_freq == l1a_l1s_com.bcchn.list[j].radio_freq) && (l1a_l1s_com.bcchn.list[j].status != NSYNC_FREE)) && (j < 6)) { j++; } // If found, reset L1 structure for this carrier. if(j<6) { l1a_l1s_com.bcchn.list[j].status = NSYNC_FREE; l1a_l1s_com.bcchn.current_list_size --; } } } else { // Stop all the Neighb. BCCH reading. l1a_l1s_com.bcchn.current_list_size = 0; for(i=0;i<6;i++) l1a_l1s_com.bcchn.list[i].status = NSYNC_FREE; } // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_NCELL_BCCH_CON,RRM1_QUEUE); // All neigh synchro have been removed. if(l1a_l1s_com.bcchn.current_list_size == 0) { // This process must be reset. *state = RESET; } else { // NOTE: in packet transfer mode only one BCCHN is allowed to be decoded // so it is impossible to be here after the STOP message in this mode // The tasks that may be restart are: BCCHN_TOP and/or BCCHN // Check if it remains some BCCHN_TOP or BCCHN tasks to restart for(i=0;i<6;i++) { if (l1a_l1s_com.bcchn.list[i].status != NSYNC_FREE) { if (l1a_l1s_com.bcchn.list[i].gprs_priority == TOP_PRIORITY) { // it remains one BCCHN_TOP task to restart l1a_l1s_com.task_param[BCCHN_TOP] = SEMAPHORE_SET; l1a_l1s_com.l1s_en_task[BCCHN_TOP] = TASK_ENABLED; } else { // it remains one BCCHN task to restart l1a_l1s_com.task_param[BCCHN] = SEMAPHORE_SET; l1a_l1s_com.l1s_en_task[BCCHN] = TASK_ENABLED; } } } // Stay in current state. return; } } #if (L1_GPRS) else // End of packet transfer mode if TBF downlink and uplink have been released if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)) { l1a_l1s_com.bcchn.list[0].status = NSYNC_FREE; l1a_l1s_com.bcchn.current_list_size = 0; // This process must be reset. *state = RESET; } else if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_TBF_RELEASED) || //change of Time Slot (SignalCode == L1P_REPEAT_ALLOC_DONE)|| (SignalCode == L1P_ALLOC_EXHAUST_DONE)) { // We consider only the case: packet Transfer => packet Transfer,the serving TS may be changed // For other cases such as Idle -> Transfer... decision not yet taken. // update the BCCHN parameters // Clear BCCHN_TRAN task enable flag. l1a_l1s_com.l1s_en_task[BCCHN_TRAN] = TASK_DISABLED; // Set semaphores for neighbor BCCH task. l1a_l1s_com.task_param[BCCHN_TRAN] = SEMAPHORE_SET; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. time_alignmt = time_alignmt_mem; fn_offset = fn_offset_mem; l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_l1s_com.bcchn.list[0].fn_offset = fn_offset; l1a_l1s_com.bcchn.list[0].time_alignmt = time_alignmt; l1a_l1s_com.l1s_en_task[BCCHN_TRAN] = TASK_ENABLED; // Stay in current state. return; } #endif else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_idle_6strongest_monitoring_process() */ /*-------------------------------------------------------*/ /* */ /* Description: */ /* ------------ */ /* This function is a state machine which handles the */ /* synchronization with up to 6 neighbor cells */ /* */ /* Starting messages: MPHC_NCELL_SYNC_REQ */ /* ------------------ MPHC_NCELL_LIST_SYNC_REQ */ /* L1 makes an attempt to read the FB/SB or to confirm */ /* SB. */ /* */ /* */ /* Result messages (input): L1C_FB_INFO */ /* ------------------------ L1C_SB_INFO */ /* L1C_SBCONF_INFO */ /* Result messages from L1S. FB detection, SB detection,*/ /* SB confirmation. */ /* */ /* Result messages (output): MPHC_NCELL_SYNC_IND */ /* ------------------------- */ /* SB indication. */ /* */ /* Reset messages (input): MPHC_STOP_NCELL_SYNC_REQ */ /* ----------------------- (MPHC_STOP_NCELL_SYNC_CON) */ /* */ /*-------------------------------------------------------*/ void l1a_idle_6strongest_monitoring_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, NSYNC_CONFIG = 2, WAIT_NSYNC_RESULT = 3 #if (L1_12NEIGH == 1) ,NSYNC_LIST_CONFIG = 4 ,WAIT_SSYNC_RESULT = 5 #endif }; UWORD8 *state = &l1a.state[I_6MP]; UWORD32 SignalCode = msg->SignalCode; #if (L1_12NEIGH == 1) static UWORD8 list_size; #endif #if (L1_EOTD ==1) static UWORD8 last_cell; #endif BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset of process is embbeded in other state to // avoid conflicts between processes using the same // L1S tasks. } break; case WAIT_INIT: { #if (L1_12NEIGH ==1) if(SignalCode == MPHC_NCELL_LIST_SYNC_REQ) { // Check request validity for this process: // -> This machine works only for IDLE MODE. // -> Search must be correct. if(l1a_l1s_com.mode != I_MODE) return; #if (L1_EOTD ==1) // For EOTD, nsync must be FREE... if ( (((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP))->eotd == TRUE) && (l1a_l1s_com.nsync.current_list_size != 0) ) // End of process. return; #endif l1a_l1s_com.nsync.first_in_list=0; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FBNEW] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB2] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCONF] = SEMAPHORE_SET; // Step in state machine. *state = NSYNC_LIST_CONFIG; } else #endif if(SignalCode == MPHC_NCELL_SYNC_REQ) // Request to READ the FB/SB or SB from the given carrier. //-------------------------------------------------------- { // Check request validity for this process: // -> This machine works only for IDLE MODE. // -> Search must be correct. if(l1a_l1s_com.mode != I_MODE) return; l1a_l1s_com.nsync.first_in_list=0; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FBNEW] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB2] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCONF] = SEMAPHORE_SET; // Step in state machine. *state = NSYNC_CONFIG; } // No action in this machine for other messages. else { // End of process. return; } } break; case NSYNC_CONFIG: { // Request to read FB/SB or SB from one neighbour cell. //----------------------------------------------------- UWORD8 neigh_number = l1a_l1s_com.nsync.first_in_list; // Abort if there is no room for a new neighbour synchro request. #if (L1_12NEIGH ==1) if (l1a_l1s_com.nsync.current_list_size >= NBR_NEIGHBOURS) #else if (l1a_l1s_com.nsync.current_list_size >= 6) #endif { *state = WAIT_NSYNC_RESULT; return; } // Look for first free location within L1 structure. #if (L1_12NEIGH ==1) while((neigh_number<NBR_NEIGHBOURS) && (l1a_l1s_com.nsync.list[neigh_number].status != NSYNC_FREE)) { neigh_number++; if ( neigh_number == NBR_NEIGHBOURS ) neigh_number=0; } #else while((neigh_number<6) && (l1a_l1s_com.nsync.list[neigh_number].status != NSYNC_FREE)) { neigh_number++; if ( neigh_number == 6 ) neigh_number=0; } #endif // Download neighbour info from request message. //---------------------------------------------- l1a_l1s_com.nsync.list[neigh_number].radio_freq = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq; l1a_l1s_com.nsync.list[neigh_number].timing_validity = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->timing_validity; #if ((REL99 == 1) && (FF_RTD ==1)) // RTD feature // In this case that timing information is provided related to Real Time Difference RTD of the cell. // We force the timing_validity to no timing information because there is no special mechanism to take into // account RTD information in idle mode. So it is preferable to do a complete FB search than // using inaccurate timing in a bad way. if(l1a_l1s_com.nsync.list[neigh_number].timing_validity == 3) l1a_l1s_com.nsync.list[neigh_number].timing_validity = 0 ; #endif if(l1a_l1s_com.nsync.list[neigh_number].timing_validity != 0) { UWORD32 time_alignmt; UWORD32 fn_offset; // Download ARFCN, timing information and bitmap from the command message. time_alignmt = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->fn_offset; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); l1a_l1s_com.nsync.list[neigh_number].fn_offset = fn_offset; l1a_l1s_com.nsync.list[neigh_number].time_alignmt = time_alignmt; } else { l1a_l1s_com.nsync.list[neigh_number].fn_offset = 0; l1a_l1s_com.nsync.list[neigh_number].time_alignmt = 0; } // Enable L1S activity on this new neighbour task BCCH. l1a_l1s_com.nsync.list[neigh_number].status = NSYNC_PENDING; l1a_l1s_com.nsync.current_list_size += 1; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_NSYNC_RESULT; // End of process. end_process = 1; } break; // case NSYNC_CONFIG #if (L1_12NEIGH == 1) case NSYNC_LIST_CONFIG: { // Request to read FB/SB or SB from 1 to 12 neighbour cells. //---------------------------------------------------------- UWORD8 neigh_number = l1a_l1s_com.nsync.first_in_list; UWORD8 nbr_free = (UWORD8) (NBR_NEIGHBOURS) - l1a_l1s_com.nsync.current_list_size; T_MPHC_NCELL_LIST_SYNC_REQ *pt = ((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP)); UWORD8 i; //Read list size list_size= ((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP))->list_size; // Abort if there is no room for a new neighbour synchro request. if ( (l1a_l1s_com.nsync.current_list_size >= NBR_NEIGHBOURS) || (nbr_free < list_size) ) { *state = WAIT_NSYNC_RESULT; return; } #if (L1_EOTD==1) // Abort if list Not empty and request for an EOTD session.... if ( (l1a_l1s_com.nsync.current_list_size != 0) && ( pt->eotd == TRUE) ) { *state = WAIT_NSYNC_RESULT; return; } // store Eotd flag l1a_l1s_com.nsync.eotd_meas_session = pt->eotd; #endif // Download neighbour info from request message. //---------------------------------------------- for (i=0; i<list_size; i++,neigh_number++) { if ( neigh_number == NBR_NEIGHBOURS ) neigh_number=0; //cyclic buffer // Look for first free location within L1 structure. while((neigh_number<NBR_NEIGHBOURS) && (l1a_l1s_com.nsync.list[neigh_number].status != NSYNC_FREE)) { neigh_number++; if ( neigh_number == NBR_NEIGHBOURS ) neigh_number=0; } l1a_l1s_com.nsync.list[neigh_number].radio_freq = pt->ncell_list[i].radio_freq; l1a_l1s_com.nsync.list[neigh_number].timing_validity = pt->ncell_list[i].timing_validity; #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature // In this case that timing information is provided related to Real Time Difference RTD of the cell. // We force the timing_validity to no timing information because there is no special mechanism to take into // account RTD information in idle mode. So it is preferable to do a complete FB search than // using inaccurate timing in a bad way. if(l1a_l1s_com.nsync.list[neigh_number].timing_validity == 3) l1a_l1s_com.nsync.list[neigh_number].timing_validity = 0 ; #endif if(l1a_l1s_com.nsync.list[neigh_number].timing_validity != 0) { UWORD32 time_alignmt; UWORD32 fn_offset; // Download ARFCN, timing information and bitmap from the command message. time_alignmt = pt->ncell_list[i].time_alignmt; fn_offset = pt->ncell_list[i].fn_offset; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); l1a_l1s_com.nsync.list[neigh_number].fn_offset = fn_offset; l1a_l1s_com.nsync.list[neigh_number].time_alignmt = time_alignmt; } else { l1a_l1s_com.nsync.list[neigh_number].fn_offset = 0; l1a_l1s_com.nsync.list[neigh_number].time_alignmt = 0; } // Increment list size l1a_l1s_com.nsync.current_list_size += 1; // Enable L1S activity on all new neighbour tasks if NOT eotd. #if (L1_EOTD==1) if (pt->eotd == FALSE) #endif l1a_l1s_com.nsync.list[neigh_number].status = NSYNC_PENDING; } // end for // If NOT Eotd start new neighbours. #if (L1_EOTD == 1) if (pt->eotd == FALSE) { #endif l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_NSYNC_RESULT; #if (L1_EOTD == 1) } else { UWORD32 time_alignmt =0; UWORD32 fn_offset = 0; // Set eotd mode l1a_l1s_com.nsync.eotd_meas_session = TRUE; // In Eotd : Serving cell is not part of the list //----------------------------------------------- // But it must be the 1st monitored // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. #if (L1_EOTD_QBIT_ACC==1) time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; fn_offset = l1a_l1s_com.nsync.serv_fn_offset; #endif l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); // Load Serving cell in last position [NBR_NEIGHBOURS] l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].radio_freq = l1a_l1s_com.Scell_info.radio_freq; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset = fn_offset; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].timing_validity = 2; // Set list size l1a_l1s_com.nsync.current_list_size = 1; // start Eotd last_cell = FALSE; // Enable Serving cell monitoring l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_PENDING; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_SSYNC_RESULT; } #endif // L1_EOTD == 1 // End of process. end_process = 1; } break; // case NSYNC_LIST_CONFIG #endif //(L1_12NEIGH == 1) #if ((L1_EOTD == 1)&&L1_12NEIGH) case WAIT_SSYNC_RESULT: { if(SignalCode == L1C_SBCONF_INFO) // Synchro Burst confirmation attempt result. //------------------------------------------- { UWORD8 neigh_id = ((T_L1C_SBCONF_INFO *)(msg->SigP))->neigh_id; BOOL sb_found = ((T_L1C_SBCONF_INFO *)(msg->SigP))->sb_flag; UWORD16 neigh_radio_freq= ((T_L1C_SBCONF_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor is NOT serving cell if ( (neigh_radio_freq != l1a_l1s_com.Scell_info.radio_freq) || (neigh_id !=12)) { //REM: the message is not sent to L3 return;// Stay in current state. } // Set mode IDLE for EOTD ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 0; if(sb_found == TRUE) // SB detection is a success. { UWORD32 *fn_offset_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->time_alignmt); UWORD32 fn_sb_neigh = ((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_sb_neigh; WORD16 d_eotd_first= ((T_L1C_SBCONF_INFO *)(msg->SigP))->d_eotd_first; UWORD32 toa = ((T_L1C_SBCONF_INFO *)(msg->SigP))->toa; WORD32 ta_sb_neigh = l1a_l1s_com.nsync.list[neigh_id].time_alignmt; UWORD32 delta_fn; WORD32 delta_qbit; // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); // compute the true Serving/Neighbor time difference. // 1) update time_alignmt with (23bit - d_eotd_first) delta // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. ta_sb_neigh += (d_eotd_first - (23))*4 + (l1a_l1s_com.dl_tn * 625); if (last_cell == FALSE) { l1a_l1s_com.nsync.fn_sb_serv = fn_sb_neigh; l1a_l1s_com.nsync.ta_sb_serv = ta_sb_neigh; ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->timetag = 0; } else // End of EOTD meas. Consider Serving Cell as a neighbour cell // for timetag computation... { UWORD32 timetag; delta_fn = (fn_sb_neigh - l1a_l1s_com.nsync.fn_sb_serv + MAX_FN)%MAX_FN; delta_qbit = ta_sb_neigh - l1a_l1s_com.nsync.ta_sb_serv; timetag = (delta_fn*5000) + (WORD32)(delta_qbit); ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->timetag = timetag; #if (L1_EOTD_QBIT_ACC ==1) // Attempt QB tracking of the serving cell (independent of the TOA algorithm) // This is only performed on the second SYNC IND as we do not want to move the serving cell // timing during the E-OTD session. l1a_compensate_sync_ind((T_MPHC_NCELL_SYNC_IND *)(msg->SigP)); l1a_l1s_com.nsync.serv_fn_offset = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset; l1a_l1s_com.nsync.serv_time_alignmt = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt; #endif // #if (CODE_VERSION == SIMULATION) // #if (TRACE_TYPE==5) ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->delta_fn = delta_fn; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->delta_qbit = delta_qbit; // #endif // #endif } // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else // SB detection failled. { #if (L1_EOTD_QBIT_ACC==1) l1a_l1s_com.nsync.serv_time_alignmt = 0; l1a_l1s_com.nsync.serv_fn_offset = 0; #endif // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); // // Send reporting message with a faillure indication. // l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } // Disable the serving sync. reading. l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size = 0; if (last_cell == TRUE) { // reset list size list_size = 0; // stop eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; // reset process. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; // This process must be reset. *state = RESET; } else { UWORD8 i; // Curious case where there are no previously synchronised neighbours, // but an EOTD session is requested. Apparently, this is legal. // Here, we synchronise to the serving cell a second time with the // eotd_meas_session flag set so that no AFC or TOA updates are performed. #if (L1_EOTD_QBIT_ACC == 1) if(list_size == 0) { // L1 SW : Create a temporary copy of the serving time_alignmt and fn_offset // as we don't want to do the timeslot maths on the reference version // in case the synchronisation fails and we can't write the new values // back to the store... UWORD32 time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; UWORD32 fn_offset = l1a_l1s_com.nsync.serv_fn_offset; // In Eotd : Serving cell is not part of the list //----------------------------------------------- // But it must be the 1st and last monitored // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); // Load Serving cell in last position [NBR_NEIGHBOURS] l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].radio_freq = l1a_l1s_com.Scell_info.radio_freq; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset = fn_offset; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].timing_validity = 2; // Set list size l1a_l1s_com.nsync.current_list_size = 1; // start Eotd last_cell = TRUE; // Enable Serving cell monitoring l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_PENDING; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // No step in state machine in this case. *state = WAIT_SSYNC_RESULT; return; } else { #endif // (L1_EOTD_QBIT_ACC == 1) // enable all neighbour monitoring l1a_l1s_com.nsync.current_list_size = list_size; for (i=0; i<list_size; i++) l1a_l1s_com.nsync.list[i].status = NSYNC_PENDING; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // step in state machine *state = WAIT_NSYNC_RESULT; return; #if (L1_EOTD_QBIT_ACC == 1) } #endif } } else if(SignalCode == MPHC_STOP_NCELL_SYNC_REQ) // Request to STOP neighbour cell activity for all carriers. //-------------------------------------------------------------- { UWORD8 array_size; array_size = ((T_MPHC_STOP_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq_array_size; // TOP accepted only for ALL cells if ( (array_size != l1a_l1s_com.nsync.current_list_size) && (array_size != NBR_NEIGHBOURS)) // Stay in current state. return; // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; // Disable neighbor sync. tasks. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; // Stop Serv. sync reading. l1a_l1s_com.nsync.current_list_size = 0; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_FREE; // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_NCELL_SYNC_CON,RRM1_QUEUE); // All neigh synchro have been removed. // This process must be reset. *state = RESET; } // No action in this machine for other messages. else { // End of process. return; } } break; #endif case WAIT_NSYNC_RESULT: { if(SignalCode == L1C_FB_INFO) // Frequency Burst acquisition attempt result. //-------------------------------------------- { BOOL fb_found; UWORD8 neigh_id = ((T_L1C_FB_INFO *)(msg->SigP))->neigh_id; UWORD16 neigh_radio_freq = ((T_L1C_FB_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) // BUG_973: an issue occurs when this 3 messages arrives in this order and // in the same frame MPHC_STOP_NCELL_SYNC_REQ(A) + MPHC_NCELL_SYNC_REQ(B) + this L1s message(A) // In this case the carrier B wasn't handled because the L1s message deletes the carrier B in the list if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) { //REM: the message is not sent to L3 return;// Stay in current state. } // Get result from the message. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; if(fb_found == TRUE) // FB attempt is a success. { // Enable NSYNC task for SB detection (SB2). #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) l1a_l1s_com.nsync.list[neigh_id].timing_validity = SB_ACQUISITION_PHASE; #else l1a_l1s_com.nsync.list[neigh_id].timing_validity = 3; #endif // Enable neighbour sync 0. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_PENDING; // End of process. return; } else // FB attempt failed. //------------------- { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } // Disable a neigh sync. reading. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; // Is it the end of the complete process ? if(l1a_l1s_com.nsync.current_list_size == 0) { // Reset process. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; // This process must be reset. *state = RESET; } // End of process. else { // Check if first in list was removed from the list. Go to next first in list while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; #if (L1_12NEIGH==1) if (l1a_l1s_com.nsync.first_in_list == NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; #else if (l1a_l1s_com.nsync.first_in_list == 6) l1a_l1s_com.nsync.first_in_list = 0; #endif } return; } } else if(SignalCode == L1C_SB_INFO) // Synchro Burst acquisition attempt result. //------------------------------------------ { typedef struct { BOOL sb_found_flag; UWORD8 bsic; UWORD32 fn_offset; UWORD32 time_alignmt; } T_L1A_NSYNC; #if (L1_12NEIGH ==1) static T_L1A_NSYNC static_nsync[NBR_NEIGHBOURS]; #else static T_L1A_NSYNC static_nsync[6]; #endif BOOL sb_found = ((T_L1C_SB_INFO *)(msg->SigP))->sb_flag; UWORD8 attempt = ((T_L1C_SB_INFO *)(msg->SigP))->attempt; UWORD8 neigh_id = ((T_L1C_SB_INFO *)(msg->SigP))->neigh_id; UWORD16 neigh_radio_freq = ((T_L1C_SB_INFO *)(msg->SigP))->radio_freq; T_L1A_NSYNC *static_nsync_ptr = &(static_nsync[neigh_id]); // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) // BUG_973: an issue occurs when this 3 messages arrives in this order and // in the same frame MPHC_STOP_NCELL_SYNC_REQ(A) + MPHC_NCELL_SYNC_REQ(B) + this L1s message(A) // In this case the carrier B wasn't handled because the L1s message deletes the carrier B in the list if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) { //REM: the message is not sent to L3 return;// Stay in current state. } // Reset static structure SB detection flag. if(attempt == 1) static_nsync[neigh_id].sb_found_flag = FALSE; if(sb_found == TRUE) // SB detection is a success... //----------------------------- { // Save Results. static_nsync_ptr->sb_found_flag = TRUE; static_nsync_ptr->bsic = ((T_L1C_SB_INFO *)(msg->SigP))->bsic; static_nsync_ptr->fn_offset = ((T_L1C_SB_INFO *)(msg->SigP))->fn_offset; static_nsync_ptr->time_alignmt = ((T_L1C_SB_INFO *)(msg->SigP))->time_alignmt; } // Report message to L3 is generated after the 2 attempts. if(attempt == 2) { // Disable a neigh sync. reading. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; if(static_nsync_ptr->sb_found_flag == FALSE) { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } else { UWORD32 *fn_offset_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->time_alignmt); // Download neighbour info in result message. ((T_L1C_SB_INFO *)(msg->SigP))->sb_flag = static_nsync_ptr->sb_found_flag; ((T_L1C_SB_INFO *)(msg->SigP))->fn_offset = static_nsync_ptr->fn_offset; ((T_L1C_SB_INFO *)(msg->SigP))->time_alignmt = static_nsync_ptr->time_alignmt; ((T_L1C_SB_INFO *)(msg->SigP))->bsic = static_nsync_ptr->bsic; // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } // Is it the end of the complete process ? if(l1a_l1s_com.nsync.current_list_size == 0) { // Reset process. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; // This process must be reset. *state = RESET; } // End of process. else { // Check if first in list was removed from the list. Go to next first in list while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; #if (L1_12NEIGH==1) if (l1a_l1s_com.nsync.first_in_list == NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; #else if (l1a_l1s_com.nsync.first_in_list == 6) l1a_l1s_com.nsync.first_in_list = 0; #endif } return; } } // End of process. else { return; } } else if(SignalCode == L1C_SBCONF_INFO) // Synchro Burst confirmation attempt result. //------------------------------------------- { UWORD8 neigh_id = ((T_L1C_SBCONF_INFO *)(msg->SigP))->neigh_id; BOOL sb_found = ((T_L1C_SBCONF_INFO *)(msg->SigP))->sb_flag; UWORD16 neigh_radio_freq= ((T_L1C_SBCONF_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) // BUG_973: an issue occurs when this 3 messages arrives in this order and // in the same frame MPHC_STOP_NCELL_SYNC_REQ(A) + MPHC_NCELL_SYNC_REQ(B) + this L1s message(A) // In this case the carrier B wasn't handled because the L1s message deletes the carrier B in the list if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) { //REM: the message is not sent to L3 return;// Stay in current state. } if(sb_found == TRUE) // SB detection is a success. { UWORD32 *fn_offset_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->time_alignmt); // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { UWORD32 fn_sb_neigh = ((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_sb_neigh; WORD16 d_eotd_first= ((T_L1C_SBCONF_INFO *)(msg->SigP))->d_eotd_first; UWORD32 toa = ((T_L1C_SBCONF_INFO *)(msg->SigP))->toa; WORD32 ta_sb_neigh = l1a_l1s_com.nsync.list[neigh_id].time_alignmt; UWORD32 delta_fn; WORD32 delta_qbit; UWORD32 timetag; // compute the true Serving/Neighbor time difference. // 1) update time_alignmt with (23bit - d_eotd_first) delta // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. ta_sb_neigh += (d_eotd_first - (23))*4 + (l1a_l1s_com.dl_tn * 625); delta_fn = (fn_sb_neigh - l1a_l1s_com.nsync.fn_sb_serv + MAX_FN)%MAX_FN; delta_qbit = ta_sb_neigh - l1a_l1s_com.nsync.ta_sb_serv; // Set timetag timetag = (delta_fn*5000) + (WORD32)(delta_qbit); ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->timetag = timetag; // Set mode ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 0; // #if (CODE_VERSION == SIMULATION) // #if (TRACE_TYPE == 5) ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->delta_fn = delta_fn; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->delta_qbit = delta_qbit; // #endif // #endif } #endif #if ((L1_EOTD == 1) && (L1_EOTD_QBIT_ACC == 1)) // Attempt to compensate each N-Cell SYNC IND for QB tracking. l1a_compensate_sync_ind((T_MPHC_NCELL_SYNC_IND *)(msg->SigP)); #endif // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else // SB detection failled. { #if (L1_EOTD ==1) // Set mode if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 0; // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else #endif // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } // Disable a neigh sync. reading. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; // Is it the end of the complete process ? if(l1a_l1s_com.nsync.current_list_size == 0) { #if ((L1_EOTD ==1)&& L1_12NEIGH) // Is it EOTD ? if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { UWORD32 time_alignmt=0; UWORD32 fn_offset=0; // Init list to serving cell // Download ARFCN, timing information and bitmap from the command message. // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. #if (L1_EOTD_QBIT_ACC==1) time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; fn_offset = l1a_l1s_com.nsync.serv_fn_offset; #endif l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); // Store Serving cell infos in location [NBR_NEIGHBOURS] l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].radio_freq = l1a_l1s_com.Scell_info.radio_freq; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset = fn_offset; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].timing_validity = 2; // Set list size && last cell flag. l1a_l1s_com.nsync.current_list_size = 1; last_cell = TRUE; // Enable Serving cell monitoring l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_PENDING; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; *state = WAIT_SSYNC_RESULT; return; } else #endif { // Reset process. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; // This process must be reset. *state = RESET; } } // End of process. else { // Check if first in list was removed from the list. Go to next first in list while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; #if (L1_12NEIGH==1) if (l1a_l1s_com.nsync.first_in_list == NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; #else if (l1a_l1s_com.nsync.first_in_list == 6) l1a_l1s_com.nsync.first_in_list = 0; #endif } return; } } #if (L1_12NEIGH ==1) else if(SignalCode == MPHC_NCELL_LIST_SYNC_REQ) // Request to READ the FB/SB or SB of 1 to 12 carriers. //-------------------------------------------------------- { #if (L1_EOTD ==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) // Stay in current state. return; else #endif // Step in state machine. *state = NSYNC_LIST_CONFIG; } #endif else if(SignalCode == MPHC_NCELL_SYNC_REQ) // Request to READ the FB/SB or SB from the given carrier. //-------------------------------------------------------- { #if (L1_EOTD ==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) // Stay in current state. return; else #endif // Step in state machine. *state = NSYNC_CONFIG; } else if(SignalCode == MPHC_STOP_NCELL_SYNC_REQ) // Request to STOP neighbour cell activity for certain carriers. //-------------------------------------------------------------- { UWORD8 i,j; UWORD8 array_size; array_size = ((T_MPHC_STOP_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq_array_size; #if (L1_EOTD ==1) // Only stop for ALL neighbours in list are accepted. if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { if ( (array_size != l1a_l1s_com.nsync.current_list_size) && (array_size != NBR_NEIGHBOURS)) // Stay in current state. return; } // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; #endif // Disable neighbor sync. tasks. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FBNEW] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCONF] = TASK_DISABLED; #if (L1_12NEIGH ==1) if(array_size != NBR_NEIGHBOURS) #else if(array_size != 6) #endif { // Stop some of the Neighb. synchro. for(i=0;i<array_size;i++) { UWORD16 radio_freq = ((T_MPHC_STOP_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq_array[i]; // Search for same value within L1 structure. j=0; while(!((radio_freq == l1a_l1s_com.nsync.list[j].radio_freq) && (l1a_l1s_com.nsync.list[j].status != NSYNC_FREE)) && #if (L1_12NEIGH ==1) (j < NBR_NEIGHBOURS)) #else (j < 6)) #endif { j++; } // If found, reset L1 structure for this carrier. #if (L1_12NEIGH ==1) if(j<NBR_NEIGHBOURS) #else if(j<6) #endif { l1a_l1s_com.nsync.list[j].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size --; } } } else { // Stop all the Neighb. BCCH reading. l1a_l1s_com.nsync.current_list_size = 0; #if (L1_12NEIGH ==1) for(i=0;i<NBR_NEIGHBOURS;i++) #else for(i=0;i<6;i++) #endif l1a_l1s_com.nsync.list[i].status = NSYNC_FREE; } // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_NCELL_SYNC_CON,RRM1_QUEUE); // All neigh synchro have been removed. if(l1a_l1s_com.nsync.current_list_size == 0) { // Tasks already disabled. // This process must be reset. *state = RESET; } else { // Check if first in list was removed from the list. Go to next first in list while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; #if (L1_12NEIGH==1) if (l1a_l1s_com.nsync.first_in_list == NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; #else if (l1a_l1s_com.nsync.first_in_list == 6) l1a_l1s_com.nsync.first_in_list = 0; #endif } // Set semaphores for all neighbor relative task before re-enebling NSYNC task. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FBNEW] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB2] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCONF] = SEMAPHORE_SET; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Stay in current state. return; } } // No action in this machine for other messages. else { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_idle_serving_cell_bcch_reading_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles serving cell */ /* BCCH reading. */ /* */ /* Starting messages: MPHC_SCELL_NBCCH_REQ */ /* ------------------ MPHC_SCELL_EBCCH_REQ */ /* */ /* L1 continuously reads the serving cell BCCH and/or */ /* Extended BCCH as requested by the scheduling info. */ /* */ /* Result messages (input): L1C_BCCHS_INFO */ /* ------------------------ */ /* System information data block from L1S. */ /* */ /* Reset messages (input): MPHC_STOP_SCELL_BCCH_REQ */ /* ----------------------- (MPHC_STOP_SCELL_BCCH_CON) */ /* */ /*-------------------------------------------------------*/ void l1a_idle_serving_cell_bcch_reading_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, NBCCHS_CONFIG = 2, EBCCHS_CONFIG = 3, WAIT_BCCHS_RESULT = 4 }; UWORD8 *state = &l1a.state[I_SCB]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset CS_MEAS process. l1a_l1s_com.l1s_en_task[NBCCHS] = TASK_DISABLED; // Clear NBCCHS task enable flag. l1a_l1s_com.l1s_en_task[EBCCHS] = TASK_DISABLED; // Clear EBCCHS task enable flag. } break; case WAIT_INIT: { // Request to read Normal BCCH from serving cell. if(SignalCode == MPHC_SCELL_NBCCH_REQ) { // Step in state machine. *state = NBCCHS_CONFIG; } // Request to read Extended BCCH from serving cell. else if(SignalCode == MPHC_SCELL_EBCCH_REQ) { // Step in state machine. *state = EBCCHS_CONFIG; } // No action in this machine for other messages. else { // End of process. return; } } break; case NBCCHS_CONFIG: { UWORD8 i; // Set semaphores for Normal Serving BCCH reading task. l1a_l1s_com.task_param[NBCCHS] = SEMAPHORE_SET; // Download message content. //-------------------------- l1a_l1s_com.nbcchs.schedule_array_size = ((T_MPHC_SCELL_NBCCH_REQ *)(msg->SigP))->schedule_array_size; for(i=0;i<l1a_l1s_com.nbcchs.schedule_array_size;i++) { l1a_l1s_com.nbcchs.schedule_array[i].modulus = ((T_MPHC_SCELL_NBCCH_REQ *)(msg->SigP))->schedule_array[i].modulus; l1a_l1s_com.nbcchs.schedule_array[i].relative_position = ((T_MPHC_SCELL_NBCCH_REQ *)(msg->SigP))->schedule_array[i].relative_position; } // Enable NBCCHS task. l1a_l1s_com.l1s_en_task[NBCCHS] = TASK_ENABLED; // Step in state machine. *state = WAIT_BCCHS_RESULT; // End of process. end_process = 1; } break; case EBCCHS_CONFIG: { UWORD8 i; // Set semaphores for Normal Serving BCCH reading task. l1a_l1s_com.task_param[EBCCHS] = SEMAPHORE_SET; // Download message content. //-------------------------- l1a_l1s_com.ebcchs.schedule_array_size = ((T_MPHC_SCELL_EBCCH_REQ *)(msg->SigP))->schedule_array_size; for(i=0;i<l1a_l1s_com.ebcchs.schedule_array_size;i++) { l1a_l1s_com.ebcchs.schedule_array[i].modulus = ((T_MPHC_SCELL_EBCCH_REQ *)(msg->SigP))->schedule_array[i].modulus; l1a_l1s_com.ebcchs.schedule_array[i].relative_position = ((T_MPHC_SCELL_EBCCH_REQ *)(msg->SigP))->schedule_array[i].relative_position; } // Enable EBCCHS task. l1a_l1s_com.l1s_en_task[EBCCHS] = TASK_ENABLED; // Step in state machine. *state = WAIT_BCCHS_RESULT; // End of process. end_process = 1; } break; case WAIT_BCCHS_RESULT: { if(SignalCode == L1C_BCCHS_INFO) // Serving cell BCCH reading result. //---------------------------------- { // Forward result message to L3. l1a_send_result(MPHC_DATA_IND, msg, RRM1_QUEUE); // End of process. return; } else if(SignalCode == MPHC_SCELL_NBCCH_REQ) // Request to re-configure Normal BCCH reading. //--------------------------------------------- { // Step in state machine. *state = NBCCHS_CONFIG; } else if(SignalCode == MPHC_SCELL_EBCCH_REQ) // Request to re-configure Normal BCCH reading. //--------------------------------------------- { // Step in state machine. *state = EBCCHS_CONFIG; } else if((SignalCode == MPHC_STOP_SCELL_BCCH_REQ) || (SignalCode == L1C_DEDIC_DONE)) // Request to STOP any serving cell bcch activity. //------------------------------------------------ { // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_SCELL_BCCH_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } #if L1_GPRS else if((SignalCode == L1P_SINGLE_BLOCK_CON) || (SignalCode == MPHP_SINGLE_BLOCK_CON)) // If Two Phase Access is ongoing: Packet Resource Request // msg has been sent to the network. BCCH reading must be // stopped to let PDCH reading going. // REM: we must check both L1P/MPHP messages since an other // process could have renamed L1P into MPHP. //-------------------------------------------------------- { if(((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose == TWO_PHASE_ACCESS) { // This process must be reset. *state = RESET; } else { // End of process. return; } } else // End of packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)) { // This process must be reset. *state = RESET; } else if((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update == FALSE)) // Transition IDLE -> Packet Transfer // Request to STOP serving cell BCCH activity. //-------------------------------------------- { // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_SCELL_BCCH_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else if((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update == TRUE)) // Transition Packet Transfer -> Packet Transfer { // Remark: the synchro is handled by the task CTRL. // stay in the same state // End of process. return; } #endif else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. #if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2 //#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise /*-------------------------------------------------------*/ /* l1a_idle_serving_cell_paging_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles paging */ /* */ /* Starting messages: MPHC_START_CCCH_REQ */ /* ------------------ */ /* */ /* L1 continuously reads the serving cell BCCH and/or */ /* Extended BCCH as requested by the scheduling info. */ /* */ /* Result messages (input): L1C_ALLC_INFO */ /* ------------------------ L1C_NP_INFO */ /* L1C_EP_INFO */ /* */ /* Reset messages (input): MPHC_STOP_CCCH_REQ */ /* ----------------------- (MPHC_STOP_CCCH_CON) */ /* */ /*-------------------------------------------------------*/ /* * FreeCalypso Frankenstein: the source we got with LoCosto contains * some logic, apparently designed to increase opportunities for * deep sleep, marked with "Nina added" comments. This addition by * Nina showed up on our radar because it makes use of a new member * in the l1s structure which is not present in the TCS211 version * of this data structure, which we are not allowed to change while * deblobbing L1 one module at a time. I am going to turn Nina's * addition into a conditional compilation option. -- Mychaela */ #define NINA_ADDED 0 #if NINA_ADDED INT8 last_page_mode = 2; //REORG; #endif void l1a_idle_serving_cell_paging_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_MSG = 2 }; enum pg_modes { NORMAL = 0, EXTENDED = 1, REORG = 2 }; UWORD8 *state = &l1a.state[I_SCP]; UWORD32 SignalCode = msg->SignalCode; static UWORD8 page_mode = REORG; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Disable serving cell tasks. l1a_l1s_com.l1s_en_task[NP] = TASK_DISABLED; // Reset NP task enable flag. l1a_l1s_com.l1s_en_task[EP] = TASK_DISABLED; // Reset EP task enable flag. l1a_l1s_com.l1s_en_task[ALLC] = TASK_DISABLED; // Reset ALLC (reorg) task enable flag. // No Paging => no gauging => no Deep sleep //Nina modify to save power, not forbid deep sleep, only force gauging in next paging #if NINA_ADDED if(l1s.force_gauging_next_paging_due_to_CCHR == 0) // Force gauging next paging #endif l1s.pw_mgr.enough_gaug = FALSE; // forbid Deep sleep } break; case WAIT_INIT: { if (SignalCode == MPHC_START_CCCH_REQ) { // download page mode from message (msg) page_mode = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_mode; #if NINA_ADDED if(((last_page_mode == NORMAL) && (page_mode == EXTENDED)) || ((last_page_mode == EXTENDED) && (page_mode == NORMAL))) { l1s.force_gauging_next_paging_due_to_CCHR = 1; } last_page_mode = page_mode; #endif if(page_mode == REORG) // Request to enter the PAGING REORGANIZATION paging mode. //-------------------------------------------------------- // L1 must start the Serving cell paging monitoring in PAGING REORGANIZATION // paging mode. L1 starts reading the FULL BCCH and CCCH informations. { // Set semaphores for all serving cell tasks. l1a_l1s_com.task_param[ALLC] = SEMAPHORE_SET; // Set ALLC task semaphore. l1a_l1s_com.task_param[NP] = SEMAPHORE_SET; // Set NP task semaphore. // Set parameter synchro semaphore for I_BAMS task. // Rem: changing the paging parameters changes the place where I_BAMS // task must be executed. l1a_l1s_com.meas_param |= I_BAMS_MEAS; // Download the PAGING PARAMETERS from the command message. l1a_l1s_com.bcch_combined = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bcch_combined; l1a_l1s_com.bs_pa_mfrms = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_pa_mfrms; l1a_l1s_com.bs_ag_blks_res = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_ag_blks_res; l1a_l1s_com.ccch_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->ccch_group; l1a_l1s_com.page_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_group; l1a_l1s_com.page_block_index = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_block_index; /*----------------------------------------------------*/ /* Download Idle parameters and Info in the Serving */ /* structure. */ /*----------------------------------------------------*/ /* Rem: Get Idle Information from ROM table. Get nbr */ /* of paging blocks in a MF51 from ROM table. */ /* "nb_pch_per_mf51" = N div BS_PA_MFRMS. */ /* "idle_task_info" = info about PCH, EXT_PCH and */ /* other task to settle in IM. */ /*----------------------------------------------------*/ if(l1a_l1s_com.bcch_combined == TRUE) { l1a_l1s_com.idle_task_info = IDLE_INFO_COMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_COMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_COMB[l1a_l1s_com.bs_ag_blks_res]; } else { l1a_l1s_com.idle_task_info = IDLE_INFO_NCOMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_NCOMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_NCOMB[l1a_l1s_com.bs_ag_blks_res]; } // Layer 1 internal mode is set to IDLE MODE. l1a_l1s_com.mode = I_MODE; // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // We must shift the mobile time setting to the timeslot provided by // the "ccch_group" parameter. // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += (2 * l1a_l1s_com.ccch_group) - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = 2 * l1a_l1s_com.ccch_group; // Save new TN id. #if L1_GPRS // Select GSM DSP Scheduler. l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; #endif // Timing must be shifted to a new timeslot, enables SYNCHRO task.. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // In paging reorganization, Full BCCH reading must be setup. l1a_l1s_com.Scell_info.si_bit_map = ALL_SI; // Step in state machine. *state = WAIT_MSG; // Enable Paging Reorganisation tasks. l1a_l1s_com.l1s_en_task[NP] = TASK_ENABLED; // Set NP task enable flag. l1a_l1s_com.l1s_en_task[ALLC] = TASK_ENABLED; // Set ALLC (for paging reorg) task enable flag. // End of process. return; } else if(page_mode == NORMAL) { // Request to enter the NORMAL PAGING paging mode. //------------------------------------------------ // L1 must start the Serving cell paging monitoring in NORMAL PAGING // paging mode. L1 starts reading only its own paging subchannel. #if (TRACE_TYPE==3) if (l1_stats.type == FER_CCCH || l1_stats.type == FER_CCCH_TN246) l1_stats.wait_time = 0; #endif // Disable the paging reorganization tasks. l1a_l1s_com.l1s_en_task[NP] = TASK_DISABLED; // Reset NP task enable flag. l1a_l1s_com.l1s_en_task[ALLC] = TASK_DISABLED; // Reset ALLC (reorg) task enable flag. // Set parameter synchro semaphore for I_BAMS task. // Rem: changing the paging parameters changes the place where I_BAMS // task must be executed. l1a_l1s_com.meas_param |= I_BAMS_MEAS; // Set semaphores for the normal paging reading task. l1a_l1s_com.task_param[NP] = SEMAPHORE_SET; // Set NP task semaphore. // Download the PAGING PARAMETERS from the command message. l1a_l1s_com.bcch_combined = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bcch_combined; l1a_l1s_com.bs_pa_mfrms = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_pa_mfrms; l1a_l1s_com.bs_ag_blks_res = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_ag_blks_res; l1a_l1s_com.ccch_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->ccch_group; l1a_l1s_com.page_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_group; l1a_l1s_com.page_block_index = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_block_index; /*----------------------------------------------------*/ /* Download Idle parameters and Info in the Serving */ /* structure. */ /*----------------------------------------------------*/ /* Rem: Get Idle Information from ROM table. Get nbr */ /* of paging blocks in a MF51 from ROM table. */ /* "nb_pch_per_mf51" = N div BS_PA_MFRMS. */ /* "idle_task_info" = info about PCH, EXT_PCH and */ /* other task to settle in IM. */ /*----------------------------------------------------*/ if(l1a_l1s_com.bcch_combined == TRUE) { l1a_l1s_com.idle_task_info = IDLE_INFO_COMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_COMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_COMB[l1a_l1s_com.bs_ag_blks_res]; } else { l1a_l1s_com.idle_task_info = IDLE_INFO_NCOMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_NCOMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_NCOMB[l1a_l1s_com.bs_ag_blks_res]; } #if L1_GPRS //In case of network mode of operation II or III, CCCH reading is possible //in packet idle mode and in packet transfer mode. //But the SYNCHRO task is not used anymore as opposite to CS mode for CCCH readings if (!((l1a_l1s_com.l1s_en_task[PNP] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PEP] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PALLC] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED))) #endif { // Layer 1 internal mode is set to IDLE MODE. l1a_l1s_com.mode = I_MODE; // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // We stay on the same serving cell but change the RX timeslot // (CCCH_GROUP or timeslot), then the "timeslot difference" between new // and old configuration is given in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += (2 * l1a_l1s_com.ccch_group) - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = 2 * l1a_l1s_com.ccch_group; // Save new TN id. #if L1_GPRS // Select GSM DSP Scheduler. l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; // Timing must be shifted to a new timeslot, enables SYNCHRO task.. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. #else if(l1a_l1s_com.tn_difference != 0) // Timing must be shifted to a new timeslot, enables SYNCHRO task.. { l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. } #endif } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. } // Step in state machine. *state = WAIT_MSG; // Enable normal paging mode. l1a_l1s_com.l1s_en_task[NP] = TASK_ENABLED; // Set NP task enable flag. // End of process. return; } else { // No action for other page mode return; } }//if (SignalCode == MPHC_START_CCCH_REQ) else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; case WAIT_MSG: { if(SignalCode == MPHC_START_CCCH_REQ) { // download paging mode from msg page_mode = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_mode; #if NINA_ADDED if(((last_page_mode == NORMAL) && (page_mode == EXTENDED)) || ((last_page_mode == EXTENDED) && (page_mode == NORMAL))) { l1s.force_gauging_next_paging_due_to_CCHR = 1; } last_page_mode = page_mode; #endif if ((page_mode == NORMAL) || (page_mode == REORG)) { // Step in state machine. *state = RESET; } else if (page_mode == EXTENDED) { // Request to enter the EXTENDED PAGING paging mode. //------------------------------------------------ #if (TRACE_TYPE==3) if (l1_stats.type == FER_CCCH || l1_stats.type == FER_CCCH_TN246) l1_stats.wait_time = 0; #endif // Disable the paging reorganization tasks. l1a_l1s_com.l1s_en_task[NP] = TASK_DISABLED; // Reset NP task enable flag. l1a_l1s_com.l1s_en_task[ALLC] = TASK_DISABLED; // Reset ALLC (reorg) task enable flag. // Set parameter synchro semaphore for I_BAMS task. // Rem: changing the paging parameters changes the place where I_BAMS // task must be executed. l1a_l1s_com.meas_param |= I_BAMS_MEAS; // Set semaphores for the normal/extended paging reading task. l1a_l1s_com.task_param[NP] = SEMAPHORE_SET; // Set NP task semaphore. l1a_l1s_com.task_param[EP] = SEMAPHORE_SET; // Set EP task semaphore. // Download the PAGING PARAMETERS from the command message. l1a_l1s_com.bcch_combined = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bcch_combined; l1a_l1s_com.bs_pa_mfrms = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_pa_mfrms; l1a_l1s_com.bs_ag_blks_res = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->bs_ag_blks_res; l1a_l1s_com.ccch_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->ccch_group; l1a_l1s_com.page_group = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_group; l1a_l1s_com.page_block_index = ((T_MPHC_START_CCCH_REQ *)(msg->SigP))->page_block_index; /*----------------------------------------------------*/ /* Download Idle parameters and Info in the Serving */ /* structure. */ /*----------------------------------------------------*/ /* Rem: Get Idle Information from ROM table. Get nbr */ /* of paging blocks in a MF51 from ROM table. */ /* "nb_pch_per_mf51" = N div BS_PA_MFRMS. */ /* "idle_task_info" = info about PCH, EXT_PCH and */ /* other task to settle in IM. */ /*----------------------------------------------------*/ if(l1a_l1s_com.bcch_combined == TRUE) { l1a_l1s_com.idle_task_info = IDLE_INFO_COMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_COMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_COMB[l1a_l1s_com.bs_ag_blks_res]; } else { l1a_l1s_com.idle_task_info = IDLE_INFO_NCOMB[(l1a_l1s_com.bs_ag_blks_res * (MAX_PG_BLOC_INDEX_NCOMB+1)) + (l1a_l1s_com.page_block_index)]; l1a_l1s_com.nb_pch_per_mf51 = NBPCH_IN_MF51_NCOMB[l1a_l1s_com.bs_ag_blks_res]; } #if L1_GPRS //In case of network mode of operation II or III, CCCH reading is possible //in packet idle mode and in packet transfer mode. //But the SYNCHRO task is not used anymore as opposite to CS mode for CCCH readings if (!((l1a_l1s_com.l1s_en_task[PNP] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PEP] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PALLC] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) || (l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED))) #endif { // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // We stay on the same serving cell but change the RX timeslot // (CCCH_GROUP or timeslot), then the "timeslot difference" between new // and old configuration is given in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. // Layer 1 internal mode is set to IDLE MODE. l1a_l1s_com.mode = I_MODE; l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += (2 * l1a_l1s_com.ccch_group) - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = 2 * l1a_l1s_com.ccch_group; // Save new TN id. #if L1_GPRS // Select GSM DSP Scheduler. l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; // Timing must be shifted to a new timeslot, enables SYNCHRO task.. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. #else if(l1a_l1s_com.tn_difference != 0) // Timing must be shifted to a new timeslot, enables SYNCHRO task.. { l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. } #endif } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. } // Enable normal/extended paging mode. l1a_l1s_com.l1s_en_task[NP] = TASK_ENABLED; // Set NP task enable flag. l1a_l1s_com.l1s_en_task[EP] = TASK_ENABLED; // Set EP task enable flag also. // Paging parameters change => perform the gauging on the next paging //Nina modify to save power, not forbid deep sleep, only force gauging in next paging #if NINA_ADDED if(l1s.force_gauging_next_paging_due_to_CCHR == 0) #endif l1s.pw_mgr.enough_gaug = FALSE; // forbid Deep sleep until next gauging //End Nina modify // end of process return; }//end if (page_mode == EXTENDED) }// end if(SignalCode == MPHC_START_CCCH_REQ) else if((SignalCode == L1C_ALLC_INFO) || (SignalCode == L1C_NP_INFO) || (SignalCode == L1C_EP_INFO)) // Paging reorganization tasks results. //------------------------------------- { // Forward result message to L3. l1a_send_result(MPHC_DATA_IND, msg, RRM1_QUEUE); // End of process. return; } else if((SignalCode == MPHC_STOP_CCCH_REQ) || (SignalCode == L1C_DEDIC_DONE)) // Request to STOP any serving cell paging activity. //-------------------------------------------------- { // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_CCCH_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } #if L1_GPRS else if((SignalCode == L1P_SINGLE_BLOCK_CON) || (SignalCode == MPHP_SINGLE_BLOCK_CON)) // If Two Phase Access is ongoing: Packet Resource Request // msg has been sent to the network. CCCH reading must be // stopped to let PDCH reading going. // REM: we must check both L1P/MPHP messages since an other // process could have renamed L1P into MPHP. //-------------------------------------------------------- { if(((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose == TWO_PHASE_ACCESS) { // This process must be reset. *state = RESET; } else { // End of process. return; } } else // End of packet transfer mode if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)) { // This process must be reset. *state = RESET; } else if((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update == FALSE)) // Transition IDLE -> Packet Transfer // Request to STOP serving cell CCCH activity. //-------------------------------------------- { // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_CCCH_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else if((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update == TRUE)) // Transition Packet Transfer -> Packet Transfer { // Remark: the synchro is handled by the task CTRL. // stay in the same state // End of process. return; } #endif else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } }// end case WAIT_MSG break; } // end of "switch". } // end of "while" } // end of procedure. //#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END #endif /*-------------------------------------------------------*/ /* l1a_initial_network_sync_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles the 1st */ /* synchronization with the network. */ /* */ /* Starting messages: MPHC_NETWORK_SYNC_REQ */ /* */ /* Result messages (input): L1C_FB_INFO */ /* L1C_SB_INFO */ /* */ /* Result messages (output): MPHC_NETWORK_SYNC_IND */ /* */ /* Reset messages (input): MPHC_STOP_NETWORK_SYNC_REQ */ /* (MPHC_STOP_NETWORK_SYNC_CON) */ /* */ /*-------------------------------------------------------*/ void l1a_initial_network_sync_process(xSignalHeaderRec *msg) { enum states { RESET = 0, // Reset state. WAIT_INIT = 1, // Initial state. SET_FS_FB1_MODE0 = 2, // First Synchro, Setting of 1st FB mode 0. WAIT_FS_FB1_MODE0 = 3, // First Synchro, 1st FB mode 0 state. SET_FS_FB2_MODE0 = 10, // First Synchro, Setting of 2nd FB mode 0. WAIT_FS_FB2_MODE0 = 11, // First Synchro, 2nd FB mode 0 state. SET_FS_FB_MODE1 = 12, // First Synchro, Setting of FB mode 1. WAIT_FS_FB_MODE1 = 13, // First Synchro, FB mode 1 state. WAIT_FS_SB = 14, // First Synchro, SB state. SET_FB_MODE1 = 15, // Setting of FB mode 1. WAIT_FB_MODE1 = 16, // FB mode 1 (freq. in tracking) state. WAIT_SB = 17, // SB state. WAIT_BCCHS = 18 // BCCHS state. }; #if (VCXO_ALGO == 1) #define FS_FB1_MODE0_CENTER 1 #define FS_FB1_MODE0_MAX 2 #define FS_FB1_MODE0_MIN 3 static UWORD32 state_vcxo; #endif UWORD8 *state = &l1a.state[CS_NORM]; UWORD32 SignalCode = msg->SignalCode; static WORD16 static_attempt_counter_0; static WORD16 static_attempt_counter_1; static UWORD8 static_sb_found_flag; static UWORD8 static_bsic; static UWORD32 static_fn_offset; static UWORD32 static_time_alignmt; static UWORD8 static_timing_validity; // to keep track of the old AFC value static WORD16 old_afc; while(1) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset tasks used in the process. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; // Disable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_FREE; } break; case WAIT_INIT: { if(SignalCode == MPHC_NETWORK_SYNC_REQ) // Request to READ the FULL BCCH on the given carrier. //---------------------------------------------------- // L1 must first synchronize with the given carrier and then start // reading the FULL BCCH. { UWORD8 search_mode = ((T_MPHC_NETWORK_SYNC_REQ *)(msg->SigP))->search_mode; #if L1_FF_WA_OMAPS00099442 // reset TPU offset to current value + half a TDMA to avoid having the Fb burst at the begining of the FBNEW TPU window // This can be done safely in L1A at this point //l1s.tpu_offset = (l1s.tpu_offset + TPU_CLOCK_RANGE >> 1 ) % TPU_CLOCK_RANGE; //l1dmacro_synchro(IMM, l1s.tpu_offset); #endif // Set task semaphores. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FBNEW] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB2] = SEMAPHORE_SET; l1a_l1s_com.nsync.current_list_size = 0; // Downlink stuff timeslot is 0 (default in CS) l1a_l1s_com.dl_tn = 0; // Download neighbour info from request message. //---------------------------------------------- l1a_l1s_com.nsync.list[0].radio_freq = ((T_MPHC_NETWORK_SYNC_REQ *)(msg->SigP))->radio_freq; #if (L1_FF_MULTIBAND== 1) { UWORD8 physical_band_id; physical_band_id = l1_multiband_radio_freq_convert_into_physical_band_id(l1a_l1s_com.nsync.list[0].radio_freq); L1_MULTIBAND_TRACE_PARAMS(MULTIBAND_PHYSICAL_BAND_TRACE_ID,multiband_rf[physical_band_id].gsm_band_identifier); } #endif /*#if (L1_FF_MULTIBAND == 1)*/ l1a_l1s_com.nsync.list[0].timing_validity = ((T_MPHC_NETWORK_SYNC_REQ *)(msg->SigP))->timing_validity; #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature // In this case that timing information is provided related to Real Time Difference RTD of the cell. // We force the timing_validity to no timing information because there is no special mechanism to take into // account RTD information in idle mode. So it is preferable to do a complete FB search than // using inaccurate timing in a bad way. if(l1a_l1s_com.nsync.list[0].timing_validity == 3) // force complete search l1a_l1s_com.nsync.list[0].timing_validity = 0 ; #endif static_timing_validity = l1a_l1s_com.nsync.list[0].timing_validity; if(l1a_l1s_com.nsync.list[0].timing_validity != 0) { UWORD32 time_alignmt; UWORD32 fn_offset; // Download ARFCN, timing information and bitmap from the command message. time_alignmt = ((T_MPHC_NETWORK_SYNC_REQ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_NETWORK_SYNC_REQ *)(msg->SigP))->fn_offset; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); l1a_l1s_com.nsync.list[0].fn_offset = fn_offset; l1a_l1s_com.nsync.list[0].time_alignmt = time_alignmt; } else { l1a_l1s_com.nsync.list[0].fn_offset = 0; l1a_l1s_com.nsync.list[0].time_alignmt = 0; } // Reset attempt counters static_attempt_counter_0 = 0; #if (TRACE_TYPE==3) if (l1_stats.type == FER_FCH_MODE1) search_mode = 1; else search_mode = 0; #endif // Set functional mode. l1a_l1s_com.mode = CS_MODE; #if L1_FF_WA_OMAPS00099442 l1a_l1s_com.change_tpu_offset_flag = TRUE; #endif #if L1_GPRS // Select GSM DSP Scheduler. l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; // Timing must be shifted to a new timeslot, enables SYNCHRO task.. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; // Set SYNCHRO task enable flag. #else // Enable SYNCHRO task to cleanup the MFTAB. l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; #endif if(search_mode == 0) // Run "FIRST SYNCHRO" algorithme. //-------------------------------- { // Step in state machine. #if (VCXO_ALGO == 1) if ((l1_config.params.afc_algo == ALGO_AFC_LQG_PREDICTOR) || (l1_config.params.afc_algo == ALGO_AFC_KALMAN_PREDICTOR)) state_vcxo = FS_FB1_MODE0_CENTER; #endif *state = SET_FS_FB1_MODE0; } else // Run "Frequency in Tracking" algorithme. //---------------------------------------- { // Step in state machine. *state = SET_FB_MODE1; } } // No action in this machine for other messages. //---------------------------------------------- else { // End of process. return; } } break; case SET_FS_FB1_MODE0: { if(static_attempt_counter_0 >= 4) // Max number of FB1/Mode0 attempt is reached... Stop process. { #if (VCXO_ALGO == 1) if ((l1_config.params.afc_algo == ALGO_AFC_LQG_PREDICTOR) || (l1_config.params.afc_algo == ALGO_AFC_KALMAN_PREDICTOR)) { if (state_vcxo == FS_FB1_MODE0_CENTER) { // update vcxo state, reset attempts FB1_MODE0 state_vcxo = FS_FB1_MODE0_MAX; static_attempt_counter_0 = 0; break; } else if (state_vcxo == FS_FB1_MODE0_MAX) { // update vcxo state, reset attempts FB1_MODE0 state_vcxo = FS_FB1_MODE0_MIN; static_attempt_counter_0 = 0; break; } } #endif // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } else // Make a new attempt FB1/mode0. { // Step in state machine. *state = WAIT_FS_FB1_MODE0; // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // Wideband search for FB detection. l1a_l1s_com.fb_mode = FB_MODE_0; // Initialize AFC control function. #if AFC_ALGO #if TESTMODE if (l1_config.afc_enable) #endif { #if (VCXO_ALGO == 1) if ((l1_config.params.afc_algo == ALGO_AFC_LQG_PREDICTOR) || (l1_config.params.afc_algo == ALGO_AFC_KALMAN_PREDICTOR)) { if (state_vcxo == FS_FB1_MODE0_CENTER) l1s.afc = l1ctl_afc(AFC_INIT_CENTER, &l1s.afc_frame_count, l1_config.params.eeprom_afc, 0, l1a_l1s_com.nsync.list[0].radio_freq,l1a_l1s_com.mode); else if (state_vcxo == FS_FB1_MODE0_MAX) l1s.afc = l1ctl_afc(AFC_INIT_MAX, &l1s.afc_frame_count, l1_config.params.eeprom_afc, 0, l1a_l1s_com.nsync.list[0].radio_freq,l1a_l1s_com.mode); else if (state_vcxo == FS_FB1_MODE0_MIN) l1s.afc = l1ctl_afc(AFC_INIT_MIN, &l1s.afc_frame_count, l1_config.params.eeprom_afc, 0, l1a_l1s_com.nsync.list[0].radio_freq,l1a_l1s_com.mode); } else l1s.afc = l1ctl_afc(AFC_INIT, &l1s.afc_frame_count, l1_config.params.eeprom_afc, 0, l1a_l1s_com.nsync.list[0].radio_freq,l1a_l1s_com.mode); #else l1s.afc = l1ctl_afc(AFC_INIT, &l1s.afc_frame_count, l1_config.params.eeprom_afc, 0, l1a_l1s_com.nsync.list[0].radio_freq); #endif } #endif // Restart synch process as initialized by L3->L1 msg l1a_l1s_com.nsync.list[0].timing_validity = static_timing_validity; // Enable NSYNC task for FB detection mode 0. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // End of process. return; } } break; case WAIT_FS_FB1_MODE0: { if(SignalCode == L1C_FB_INFO) // Frequency Burst acquisition result. //------------------------------------ { UWORD8 fb_found; // Increment "static_attempt_counter_0". static_attempt_counter_0++; // Get result from message parameters. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; // Loop on FB reception when making statistics. #if (TRACE_TYPE==3) if (l1_stats.type == FER_FCH_MODE0 || l1_stats.type == FER_FCH_MODE1) { // Enable FB_new. l1a_l1s_com.l1s_en_task[FBNEW] = TASK_ENABLED; // Set FB_new task enable flag. // End of process. return; } #endif if(fb_found == TRUE) // FB attempt is a success. //------------------------- { // Stop the search in this current interval #if (VCXO_ALGO == 1) static_attempt_counter_0 = 4; #endif // Reset "static_attempt_counter_1". static_attempt_counter_1 = 0; // We consider the result of this successfull FB search attempt // as a good a-priori information for next attempt. // "fn_offset" is reversed to satisfy its definition, // fn_offset = Fn_neigh - Fn_serving. l1a_l1s_com.nsync.list[0].timing_validity = 1; l1a_l1s_com.nsync.list[0].fn_offset = 51 - l1a_l1s_com.nsync.list[0].fn_offset; // Step in state machine. *state = SET_FS_FB2_MODE0; } else // FB attempt failled. //-------------------- { // Step in state machine. *state = SET_FS_FB1_MODE0; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case SET_FS_FB2_MODE0: { if (static_attempt_counter_1 >= 4) // Max number of attempt is reached... go back to 1st FB mode 0. // otherwise stop the search and report message with failure indication #if (VCXO_ALGO == 1) { if (state_vcxo == FS_FB1_MODE0_MIN) { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } else { // Step in state machine. *state = SET_FS_FB1_MODE0; } } #else // VCXO_ALGO { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } #endif // VCXO_ALGO else // Make a new attempt FB2/mode0. { // Step in state machine. *state = WAIT_FS_FB2_MODE0; // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // End of process. return; } } break; case WAIT_FS_FB2_MODE0: { // Use incoming message. //---------------------- if(SignalCode == L1C_FB_INFO) { UWORD8 fb_found; // Increment "static_attempt_counter_1". static_attempt_counter_1++; // Get result from message parameters. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; if(fb_found == TRUE) // FB attempt is a success. //------------------------- { // Reset "static_attempt_counter_1". static_attempt_counter_1 = 0; // We consider the result of this successfull FB search attempt // as a good a-priori information for next attempt. // "fn_offset" is reversed to satisfy its definition, // fn_offset = Fn_neigh - Fn_serving. l1a_l1s_com.nsync.list[0].timing_validity = 1; l1a_l1s_com.nsync.list[0].fn_offset = 51 - l1a_l1s_com.nsync.list[0].fn_offset; // Step in state machine. *state = SET_FS_FB_MODE1; } else // FB attempt failed. //------------------- { // Step in state machine. *state = SET_FS_FB2_MODE0; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case SET_FS_FB_MODE1: { if(static_attempt_counter_1 >= 4) // Max number of attempt is reached... go back to 1st FB mode 0. // otherwise stop the search and report message with failure indication #if (VCXO_ALGO == 1) { if (state_vcxo == FS_FB1_MODE0_MIN) { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } else { // Step in state machine. *state = SET_FS_FB1_MODE0; } } #else // VCXO_ALGO { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } #endif // VCXO_ALGO else // Make a new attempt FB/Mode1. { // Step in state machine. *state = WAIT_FS_FB_MODE1; // Set FB detection mode. l1a_l1s_com.fb_mode = FB_MODE_1; // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // End of process. return; } } break; case WAIT_FS_FB_MODE1: { // Use incoming message. //---------------------- if(SignalCode == L1C_FB_INFO) { UWORD8 fb_found; // Increment "static_attempt_counter_1". static_attempt_counter_1++; // get result from message parameters. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; if(fb_found == TRUE) // FB attempt is a success. //------------------------- { // Reset "static_attempt_counter_1". static_attempt_counter_1 = 0; // Reset "static_sb_found_flag". static_sb_found_flag = FALSE; // Step in state machine. *state = WAIT_FS_SB; // WE SHOULD UPDATE THE APRIORI TIMING. // Enable NSYNC task for SB detection (SB2). #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) l1a_l1s_com.nsync.list[0].timing_validity = SB_ACQUISITION_PHASE; #else l1a_l1s_com.nsync.list[0].timing_validity = 3; #endif // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // End of process. return; } else // FB attempt failed. //------------------- { // Step in state machine. *state = SET_FS_FB_MODE1; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case WAIT_FS_SB: { // Use incoming message. //---------------------- if(SignalCode == L1C_SB_INFO) { UWORD8 sb_found = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->sb_flag; UWORD8 bsic = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->bsic; // Increment "static_attempt_counter_1". static_attempt_counter_1++; if(sb_found == TRUE) // SB detection is a success... //----------------------------- { // Save Results. static_sb_found_flag = TRUE; static_bsic = bsic; static_fn_offset = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset; static_time_alignmt = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt; } if(static_attempt_counter_1 >= 8) { #if (TRACE_TYPE==3) // Loop on FB mode 1 detection when making SB statistics. if (l1_stats.type == FER_SCH) { // Reset SB2 task enable flag. l1a_l1s_com.l1s_en_task[SB2] = TASK_DISABLED; // Reset "static_attempt_counter_1". static_attempt_counter_1 = 0; // go back to FB mode 1 detection... *state = SET_FS_FB_MODE1; break; } #endif // Disable NSYNC task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; if(static_sb_found_flag == TRUE) // SB detection is a success. //---------------------------- { // Save results. l1a_l1s_com.nsync.list[0].fn_offset = static_fn_offset; l1a_l1s_com.nsync.list[0].time_alignmt = static_time_alignmt; // Correct "ntdma" and "time_alignment" to shift 20 bit to the // futur for Normal Burst reading tasks. l1a_add_time_for_nb(&l1a_l1s_com.nsync.list[0].time_alignmt, &l1a_l1s_com.nsync.list[0].fn_offset); // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference = 0; // No timeslot shift to be performed. l1a_l1s_com.dl_tn = 0; // Camping on timeslot 0. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Clear "time_alignmt, fn_offset" in the result message since we are // going to camp on that cell. ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset = l1a_l1s_com.nsync.list[0].fn_offset; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt = l1a_l1s_com.nsync.list[0].time_alignmt; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->sb_flag = static_sb_found_flag; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->bsic = static_bsic; // Forward result message to L3. l1a_send_result(MPHC_NETWORK_SYNC_IND, msg, RRM1_QUEUE); // keep in memory the last good AFC value old_afc = l1s.afc; // Set flag for toa init. #if (TOA_ALGO != 0) l1a_l1s_com.toa_reset = TRUE; #endif // End of this process. *state = RESET; } else // SB detection failed. //--------------------- { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } } else // Make a new attempt SB. { // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // End of process. return; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; // In case of narrowband search case SET_FB_MODE1: { if (static_attempt_counter_0 >= 4) // Max number of FB/Mode1 attempt is reached... Stop process. { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } else // Make a new attempt FB/Mode1. { // Step in state machine. *state = WAIT_FB_MODE1; // Set FB detection mode. l1a_l1s_com.fb_mode = FB_MODE_1; // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // Restart synch process as initialized by L3->L1 msg l1a_l1s_com.nsync.list[0].timing_validity = static_timing_validity; // Enable NSYNC for FB detection mode 1. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // End of process. return; } } break; case WAIT_FB_MODE1: { // Use incoming message. //---------------------- if(SignalCode == L1C_FB_INFO) { UWORD8 fb_found; // Increment "static_attempt_counter_0". static_attempt_counter_0++; // get result from message parameters. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; // Loop on FB reception when making statistics. #if (TRACE_TYPE==3) if (l1_stats.type == FER_FCH_MODE0 || l1_stats.type == FER_FCH_MODE1 ) { // Enable FB_new. l1a_l1s_com.l1s_en_task[FBNEW] = TASK_ENABLED; // Set FB_new task enable flag. // End of process. return; } #endif if(fb_found == TRUE) // FB attempt is a success. //------------------------- { // Reset "static_attempt_counter_1". static_attempt_counter_1 = 0; // Reset "static_sb_found_flag". static_sb_found_flag = FALSE; // Enable NSYNC task for SB detection (SB2). #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) l1a_l1s_com.nsync.list[0].timing_validity = SB_ACQUISITION_PHASE; #else l1a_l1s_com.nsync.list[0].timing_validity = 3; #endif // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // Step in state machine. *state = WAIT_SB; // End of process. return; } else // FB attempt failed. //------------------- { // Step in state machine. *state = SET_FB_MODE1; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case WAIT_SB: { // Use incoming message. //---------------------- if(SignalCode == L1C_SB_INFO) { UWORD8 sb_found = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->sb_flag; UWORD8 bsic = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->bsic; // Increment "static_attempt_counter_1". static_attempt_counter_1++; if(sb_found == TRUE) // SB detection is a success, check plmn... //----------------------------------------- { // Save Results. static_sb_found_flag = TRUE; static_bsic = bsic; static_fn_offset = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset; static_time_alignmt = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt; } if (static_attempt_counter_1 >= 8) { // Reset NSYNC task enable flag. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; if(static_sb_found_flag == TRUE) // SB detection is a success. //---------------------------- { // Save results. l1a_l1s_com.nsync.list[0].fn_offset = static_fn_offset; l1a_l1s_com.nsync.list[0].time_alignmt = static_time_alignmt; // Correct "ntdma" and "time_alignment" to shift 20 bit to the // futur for Normal Burst reading tasks. l1a_add_time_for_nb(&l1a_l1s_com.nsync.list[0].time_alignmt, &l1a_l1s_com.nsync.list[0].fn_offset); // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference = 0; // No timeslot shift to be performed. l1a_l1s_com.dl_tn = 0; // Camping on timeslot 0. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Clear "time_alignmt, fn_offset" in the result message since we are // going to camp on that cell. ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset = l1a_l1s_com.nsync.list[0].fn_offset; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt = l1a_l1s_com.nsync.list[0].time_alignmt; // Recreate the last sucessful attempt. ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->sb_flag = static_sb_found_flag; ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->bsic = static_bsic; // Forward result message to L3. l1a_send_result(MPHC_NETWORK_SYNC_IND, msg, RRM1_QUEUE); // Keep in memory the AFC value driving to a good synchro old_afc = l1s.afc; // Initialize toa. #if (TOA_ALGO != 0) l1a_l1s_com.toa_reset = TRUE; #endif // step in state machine. *state = RESET; } else // SB detection failed. //--------------------- { // Send reporting message with a faillure indication. // Set the flag spurious_fb_detected to TRUE to reuse in the // AFC algo the old variables l1s.spurious_fb_detected = TRUE; // reuse the old AFC value l1s.afc = old_afc; l1a_report_failling_ncell_sync(MPHC_NETWORK_SYNC_IND, 0); // Reset state machine. *state = RESET; } } else // Make a new attempt SB. { // Enable neighbour sync 0. l1a_l1s_com.nsync.list[0].status = NSYNC_PENDING; // End of process. return; } } else if(SignalCode == MPHC_STOP_NETWORK_SYNC_REQ) // Request to STOP reading the FULL BCCH. //--------------------------------------- { l1a_send_confirmation(MPHC_STOP_NETWORK_SYNC_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_idle_smscb_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles the SMSCB */ /* (Short Message Service Cell Broadcast). */ /* */ /* Starting messages: MPHC_CONFIG_CBCH_REQ */ /* */ /* Subsequent messages: MPHC_CBCH_SCHEDULE_REQ */ /* MPHC_CBCH_INFO_REQ */ /* MPHC_CBCH_UPDATE_REQ */ /* */ /* Result messages (input): L1C_CB_INFO */ /* */ /* Result messages (output): MPHC_DATA_IND */ /* */ /* Reset messages (input): MPHC_STOP_CBCH_REQ */ /* */ /*-------------------------------------------------------*/ void l1a_idle_smscb_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_CONFIG = 1, WAIT_FOR_CHANGE = 2, SET_SCHEDULE = 3, WAIT_RESULT = 4 }; UWORD8 *state = &l1a.state[I_SMSCB]; UWORD32 SignalCode = msg->SignalCode; UWORD32 first_block_0; UWORD32 first_block_1; BOOL extended_cbch; T_CBCH_HEAD_SCHEDULE *cbch_schedule_ptr; UWORD8 schedule_length; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_CONFIG; // Reset SMSCB process. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Clear RAACC task enable flag. } break; case WAIT_CONFIG: { if(SignalCode == MPHC_CONFIG_CBCH_REQ) // CBCH configuration message. //---------------------------------------------------- // L1 must download the CBCH description from the command // message. { WORD8 tn_smscb; #define SMSCB_NCOMB_START_TIME 6 // SMSCB (case not combined, SDCCH/8). #define SMSCB_COMB_START_TIME 30 // SMSCB (case combined, SDCCH/4). // Set "parameter synchro semaphores" l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; // Set "parameter synchro semaphore for SMSCB task. // Download new CBCH parameters. l1a_l1s_com.cbch_desc = ((T_MPHC_CONFIG_CBCH_REQ *)(msg->SigP))->cbch_desc; l1a_l1s_com.cbch_freq_list = ((T_MPHC_CONFIG_CBCH_REQ *)(msg->SigP))->cbch_freq_list; if(l1a_l1s_com.cbch_desc.channel_type == SDCCH_8) // case SDCCH/8... // Rem: Serving tasks on timeslot 0 is a special case, // start frame is 1 later than other cases. { if(l1a_l1s_com.cbch_desc.timeslot_no < l1a_l1s_com.dl_tn) { l1a_l1s_com.cbch_start_in_mf51 = SMSCB_NCOMB_START_TIME; l1a_l1s_com.pre_scheduled_cbch = TRUE; } else { l1a_l1s_com.cbch_start_in_mf51 = SMSCB_NCOMB_START_TIME + 1; l1a_l1s_com.pre_scheduled_cbch = FALSE; } } else // case SDCCH/4... { if(l1a_l1s_com.cbch_desc.timeslot_no < l1a_l1s_com.dl_tn) { l1a_l1s_com.cbch_start_in_mf51 = SMSCB_COMB_START_TIME; l1a_l1s_com.pre_scheduled_cbch = TRUE; } else { l1a_l1s_com.cbch_start_in_mf51 = SMSCB_COMB_START_TIME + 1; l1a_l1s_com.pre_scheduled_cbch = FALSE; } } // Set "change_synchro" flag to trigger L1S to change the synchro on fly // within SMSCB task and to restore current synchro when SMSCB task is completed. if(((l1a_l1s_com.cbch_desc.timeslot_no - l1a_l1s_com.dl_tn + 8) % 8) >=4) { // L1S will make a intra SMSCB task synchro to current TS + 4. l1a_l1s_com.change_synchro_cbch = TRUE; tn_smscb = l1a_l1s_com.cbch_desc.timeslot_no - l1a_l1s_com.dl_tn - 4; } else { // L1S will NOT make the intra SMSCB task synchro. l1a_l1s_com.change_synchro_cbch = FALSE; tn_smscb = l1a_l1s_com.cbch_desc.timeslot_no - l1a_l1s_com.dl_tn; } if(tn_smscb < 0) l1a_l1s_com.tn_smscb = tn_smscb + 8; else l1a_l1s_com.tn_smscb = tn_smscb; // Disable TB1/2/3/5/6/7 reading. l1a_l1s_com.cbch_info_req.cbch_num = 0; l1a_l1s_com.cbch_info_req.next = 0; // Reset the CBCH/TB0/TB4 activity. l1a_l1s_com.norm_cbch_schedule.cbch_state = CBCH_INACTIVE; l1a_l1s_com.ext_cbch_schedule.cbch_state = CBCH_INACTIVE; // Step in state machine. *state = WAIT_FOR_CHANGE; } // end of process. end_process = 1; } break; case WAIT_FOR_CHANGE: { if(SignalCode == MPHC_CBCH_SCHEDULE_REQ) // CBCH scheduling message. //---------------------------------------------------- { // Stop SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Clear SMSCB task enable flag. // Set "parameter synchro semaphore for SMSCB task. l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; extended_cbch = ((T_MPHC_CBCH_SCHEDULE_REQ *)(msg->SigP))->extended_cbch; schedule_length = ((T_MPHC_CBCH_SCHEDULE_REQ *)(msg->SigP))->schedule_length; // Choose schedule table according to the considered CBCH (normal or extended). if(extended_cbch) cbch_schedule_ptr = &l1a_l1s_com.ext_cbch_schedule; else cbch_schedule_ptr = &l1a_l1s_com.norm_cbch_schedule; // Correction of BUG2176: CBCH_HEAD_STRUCTURE has to be updated with schedule_length // value, potentially used in SET_SCHEDULE state after receipt of an CBCH_UPDATE_REQ cbch_schedule_ptr->schedule_length = schedule_length; if(schedule_length == 0) { // Continuous CBCH header reading. //-------------------------------- // No scheduling info provided, L1 must start reading continously TB0 on // normal CBCH or TB4 on extended CBCH. cbch_schedule_ptr->cbch_state = CBCH_CONTINUOUS_READING; // Continuous reading must start immediately. cbch_schedule_ptr->start_continuous_fn = -1; // Activate SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_ENABLED; // Set SMSCB task enable flag. // Step in state machine. *state = WAIT_RESULT; // End of process. return; } else { UWORD32 starting_fn; // Scheduled CBCH header reading. //-------------------------------- cbch_schedule_ptr->cbch_state = CBCH_SCHEDULED; first_block_0 = ((T_MPHC_CBCH_SCHEDULE_REQ *)(msg->SigP))->first_block_0; first_block_1 = ((T_MPHC_CBCH_SCHEDULE_REQ *)(msg->SigP))->first_block_1; // Compute "schedule period" starting frame number. // Note: the reception of MPHC_CBCH_SCHEDULE_REQ schedule message always // refers to a scheduling period starting at the next "8*MF51" boundary. // There is no real time issue there since we have plenty TDMA frame // between the reception of the scheduling message from CBCH and the // starting of the considered scheduling period. starting_fn = l1s.actual_time.fn - (l1s.actual_time.fn%(8*51)) + 8*51; if(starting_fn >= MAX_FN) starting_fn -= MAX_FN; cbch_schedule_ptr->starting_fn = starting_fn; // Step in state machine. *state = SET_SCHEDULE; } } else if(SignalCode == MPHC_CBCH_INFO_REQ) // CBCH info request message. //---------------------------------------------------- { UWORD32 starting_fn; UWORD8 i,j; UWORD8 tb_bitmap; // This request message is a consequence of a CBCH/TB0 or CBCH/TB4 reading. // Stop SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Set "parameter synchro semaphore for SMSCB task. l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; // Store TB bitmap from message. tb_bitmap = ((T_MPHC_CBCH_INFO_REQ *)(msg->SigP))->tb_bitmap; // Compute next TB1 multiframe 51 starting frame number. starting_fn = l1s.actual_time.fn - (l1s.actual_time.fn%(8*51)) + 51; if(starting_fn >= MAX_FN) starting_fn -= MAX_FN; // Compute schedule table according to the provided bitmap. j=0; for(i=0; i<3; i++) // TB 1\2\3 { if(tb_bitmap & (1L<<i)) { l1a_l1s_com.cbch_info_req.start_fn[j] = (starting_fn + (UWORD32)i*51L + l1a_l1s_com.cbch_start_in_mf51) % MAX_FN; j++; } } // End "for" for(i=3; i<6; i++) // TB 4\5\6 { if(tb_bitmap & (1L<<i)) { l1a_l1s_com.cbch_info_req.start_fn[j] = (starting_fn + (UWORD32)i*51L + l1a_l1s_com.cbch_start_in_mf51 + 51L) % MAX_FN; j++; } } // End "for" // Store number of CBCH info to read. l1a_l1s_com.cbch_info_req.cbch_num = j; l1a_l1s_com.cbch_info_req.next = 0; // Activate SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_ENABLED; // Set SMSCB task enable flag. // Step in state machine. *state = WAIT_RESULT; // End of process. return; } else if(SignalCode == MPHC_CBCH_UPDATE_REQ) // CBCH scheduling message. //---------------------------------------------------- { // Stop SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Clear SMSCB task enable flag. // Set "parameter synchro semaphore for SMSCB task. l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; extended_cbch = ((T_MPHC_CBCH_UPDATE_REQ *)(msg->SigP))->extended_cbch; // Choose schedule table according to the considered CBCH (normal or extended). if(extended_cbch) cbch_schedule_ptr = &l1a_l1s_com.ext_cbch_schedule; else cbch_schedule_ptr = &l1a_l1s_com.norm_cbch_schedule; // Scheduled CBCH header reading. //-------------------------------- cbch_schedule_ptr->cbch_state = CBCH_SCHEDULED; first_block_0 = ((T_MPHC_CBCH_UPDATE_REQ *)(msg->SigP))->first_block_0; first_block_1 = ((T_MPHC_CBCH_UPDATE_REQ *)(msg->SigP))->first_block_1; // DO NOT CHANGE "cbch_schedule_ptr->starting_fn" content. // Step in state machine. *state = SET_SCHEDULE; } else if(SignalCode == MPHC_STOP_CBCH_REQ) // Request to STOP reading the CBCH. //---------------------------------- { BOOL normal_cbch = ((T_MPHC_STOP_CBCH_REQ *)(msg->SigP))->normal_cbch; BOOL extended_cbch = ((T_MPHC_STOP_CBCH_REQ *)(msg->SigP))->extended_cbch; // Stop SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Set "parameter synchro semaphore for SMSCB task. l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; if(normal_cbch) l1a_l1s_com.norm_cbch_schedule.cbch_state = CBCH_INACTIVE; if(extended_cbch) l1a_l1s_com.ext_cbch_schedule.cbch_state = CBCH_INACTIVE; if((l1a_l1s_com.norm_cbch_schedule.cbch_state == CBCH_INACTIVE) && (l1a_l1s_com.ext_cbch_schedule.cbch_state == CBCH_INACTIVE)) // This process must be reset. { // send confirmation l1a_send_confirmation(MPHC_STOP_CBCH_CON,RRM1_QUEUE); // Step in state machine. *state = RESET; } else { // Activate SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_ENABLED; // Step in state machine. *state = WAIT_RESULT; // End of process. return; } } #if 0 /* match TCS211 */ else if(SignalCode == L1C_DEDIC_DONE) { // Stop SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_DISABLED; // Set "parameter synchro semaphore for SMSCB task. l1a_l1s_com.task_param[SMSCB] = SEMAPHORE_SET; l1a_l1s_com.norm_cbch_schedule.cbch_state = CBCH_INACTIVE; l1a_l1s_com.ext_cbch_schedule.cbch_state = CBCH_INACTIVE; // Step in state machine. *state = RESET; } #endif else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case SET_SCHEDULE: { UWORD8 i,j; UWORD8 mf51_offset; // Choose schedule table according to the considered CBCH (normal or extended). if(extended_cbch) mf51_offset = 4*51; // Offset to read TB4. else mf51_offset = 0; // No offset to read TB0. // Compute schedule table according to the provided bitmap. j=0; for(i=0; i<48; i++) { if(i<32) { if(first_block_0 & (1L<<i)) { cbch_schedule_ptr->first_block[j] = (cbch_schedule_ptr->starting_fn + (UWORD32)i*8L*51L + l1a_l1s_com.cbch_start_in_mf51 + mf51_offset) % MAX_FN; j++; } } else { if(first_block_1 & (1L<<(i-32))) { cbch_schedule_ptr->first_block[j] = (cbch_schedule_ptr->starting_fn + (UWORD32)i*8L*51L + l1a_l1s_com.cbch_start_in_mf51 + mf51_offset) % MAX_FN; j++; } } } // End "for" // Compute FN for starting continuous CBCH/TB0 reading. // Rem: this FN is given by the starting FN of the schedule period starting // immediately after the schedule period considered in the message. cbch_schedule_ptr->start_continuous_fn = ( cbch_schedule_ptr->starting_fn + (UWORD32)cbch_schedule_ptr->schedule_length*8L*51L + l1a_l1s_com.cbch_start_in_mf51 + mf51_offset ) % MAX_FN; // Store number of scheduled CBCH according to the considered CBCH (normal or extended). // Store "schedule period" starting frame number. cbch_schedule_ptr->cbch_num = j; cbch_schedule_ptr->next = NULL;//o omaps 00090550 // Activate SMSCB task. l1a_l1s_com.l1s_en_task[SMSCB] = TASK_ENABLED; // Set SMSCB task enable flag. // Step in state machine. *state = WAIT_RESULT; // End of process. return; } case WAIT_RESULT: { if(SignalCode == L1C_CB_INFO) // CBCH result message. //--------------------- { // Forward result message to L3. l1a_send_result(MPHC_DATA_IND, msg, RRM1_QUEUE); // End of process. return; } else if((SignalCode == MPHC_CBCH_SCHEDULE_REQ) || (SignalCode == MPHC_CBCH_UPDATE_REQ) || (SignalCode == MPHC_CBCH_INFO_REQ)) // Request to reconsider the ongoing CBCH activity. //----------------------------------------------------------- { // Step in state machine. *state = WAIT_FOR_CHANGE; } else //if((SignalCode == MPHC_STOP_CBCH_REQ)||(SignalCode == L1C_DEDIC_DONE)) if(SignalCode == MPHC_STOP_CBCH_REQ) // Request to (may be partially) STOP reading the CBCH. //----------------------------------------------------- { // This process must be reset. *state = WAIT_FOR_CHANGE; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_access_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles the access */ /* to the network while in IDLE mode. */ /* */ /* Starting messages: MPHC_RA_REQ */ /* */ /* Subsequent messages: MPHC_RA_REQ */ /* */ /* Result messages (input): L1C_RA_DONE */ /* */ /* Result messages (output): MPHC_RA_CON */ /* */ /* Reset message (input): MPHC_STOP_RA_REQ */ /* */ /* Reset message (input): MPHC_STOP_RA_CON */ /*-------------------------------------------------------*/ void l1a_access_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_RESULT = 2 }; UWORD8 *state = &l1a.state[ACCESS]; UWORD32 SignalCode = msg->SignalCode; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset RAACC process. l1a_l1s_com.l1s_en_task[RAACC] = TASK_DISABLED; // Clear RAACC task enable flag. } break; case WAIT_INIT: { if(SignalCode == MPHC_RA_REQ) // 1st Random access request message. //----------------------------------- { UWORD8 supplied_txpwr; // Download Transmit power configuration. supplied_txpwr = ((T_MPHC_RA_REQ *)(msg->SigP))->txpwr; #if (L1_FF_MULTIBAND == 0) //Config. if ((l1_config.std.id == DUAL) || (l1_config.std.id == DUALEXT) || (l1_config.std.id == DUAL_US)) { l1a_l1s_com.powerclass_band1 = ((T_MPHC_RA_REQ *)(msg->SigP))->powerclass_band1; l1a_l1s_com.powerclass_band2 = ((T_MPHC_RA_REQ *)(msg->SigP))->powerclass_band2; } else { l1a_l1s_com.powerclass_band1 = ((T_MPHC_RA_REQ *)(msg->SigP))->powerclass_band1; } #endif // Check max transmit power (min txpwr) according to powerclass // and clip to MIN_TXPWR_LEVEL. supplied_txpwr = l1a_clip_txpwr(supplied_txpwr,l1a_l1s_com.Scell_info.radio_freq); // Given value must be used on 1st TX. l1s.applied_txpwr = supplied_txpwr; // Init RAACC process. l1a_l1s_com.ra_info.rand = ((T_MPHC_RA_REQ *)(msg->SigP))->rand; l1a_l1s_com.ra_info.channel_request = ((T_MPHC_RA_REQ *)(msg->SigP))->channel_request; // Increment "rand" value in order to avoid to abort RACH by SYNCHRO task // when MPHC_START_CCCH_REQ and MPHC_RA_REQ are sent in same TDMA. l1a_l1s_com.ra_info.rand+=4; // step in state machine. *state = WAIT_RESULT; // Change mode to connection establishment part 1. l1a_l1s_com.mode = CON_EST_MODE1; // Activate RAACC task (no semaphore for UL tasks). // Enable Paging Reorg and Normal paging tasks. l1a_l1s_com.l1s_en_task[RAACC] = TASK_ENABLED; // Set RAACC task enable flag. } // end of process. end_process = 1; } break; case WAIT_RESULT: { if(SignalCode == L1C_RA_DONE) // Random access acqnowledge message. //----------------------------------- { // Forward result message to L3. l1a_send_result(MPHC_RA_CON, msg, RRM1_QUEUE); // Change mode to connection establishment part 2. l1a_l1s_com.mode = CON_EST_MODE2; // end of process. return; } else if(SignalCode == MPHC_RA_REQ) // Random access message. //----------------------- { // REM: rand is added the msg content since its current content is the already // spent "slots" from the last RACH sending. l1a_l1s_com.ra_info.rand += ((T_MPHC_RA_REQ *)(msg->SigP))->rand; l1a_l1s_com.ra_info.channel_request = ((T_MPHC_RA_REQ *)(msg->SigP))->channel_request; // Activate RAACC task (no semaphore for UL tasks). l1a_l1s_com.l1s_en_task[RAACC] = TASK_ENABLED; // Set RAACC task enable flag. // end of process. return; } else if(SignalCode == MPHC_STOP_RA_REQ) // Request to STOP the LINK ACCESS procedure. //------------------------------------------- { #if L1_GPRS UWORD8 i; // Store MAX TXPWR value to be used for first Tx PDCH blocks for(i = 0; i < 8; i++) { l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = l1s.applied_txpwr; } #endif // send confirmation l1a_send_confirmation(MPHC_STOP_RA_CON,RRM1_QUEUE); // This process must be reset. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. //----------------------------------------------------------------------------------------------- /*-------------------------------------------------------*/ /* l1a_dedicated_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles the dedicated*/ /* mode setup (L1A side). */ /* */ /* Starting messages: MPHC_IMMED_ASSIGN_REQ */ /* */ /* Subsequent messages: MPHC_CHANNEL_ASSIGN_REQ */ /* MPHC_SYNC_HO_REQ */ /* MPHC_PRE_SYNC_HO_REQ */ /* MPHC_PSEUDO_SYNC_HO_REQ */ /* MPHC_ASYNC_HO_REQ */ /* MPHC_ASYNC_HO_COMPLETE */ /* MPHC_HANDOVER_FAIL_REQ */ /* MPHC_CHANGE_FREQUENCY */ /* OML1_CLOSE_TCH_LOOP_REQ */ /* OML1_OPEN_TCH_LOOP_REQ */ /* OML1_START_DAI_TEST_REQ */ /* OML1_STOP_DAI_TEST_REQ */ /* */ /* Result messages (input): L1C_DEDIC_DONE */ /* L1C_SACCH_INFO */ /* */ /* Result messages (output): MPHC_CHANNEL_ASSIGN_CON */ /* MPHC_SYNC_HO_CON */ /* MPHC_PRE_SYNC_HO_CON */ /* MPHC_PSEUDO_SYNC_HO_CON */ /* MPHC_ASYNC_HO_CON */ /* MPHC_TA_FAIL_IND */ /* MPHC_DATA_IND */ /* OML1_CLOSE_TCH_LOOP_CON */ /* OML1_OPEN_TCH_LOOP_CON */ /* OML1_START_DAI_TEST_CON */ /* OML1_STOP_DAI_TEST_CON */ /* */ /* Reset messages (input): MPHC_CHANNEL_RELEASE */ /* */ /*-------------------------------------------------------*/ void l1a_dedicated_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_DYN_DWNLD = 2, WAIT_MSG = 3 }; T_DEDIC_SET *free_set; UWORD8 *state = &l1a.state[DEDICATED]; UWORD32 SignalCode = msg->SignalCode; static UWORD32 static_ho_fail_time_alignmt; static UWORD32 static_ho_fail_fn_offset; static T_DEDIC_SET *static_ho_fail_aset; #if ((L1_EOTD==1) && (L1_EOTD_QBIT_ACC == 1)) static UWORD32 static_serv_fn_offset = 0; static UWORD32 static_serv_time_alignmt = 0; #endif BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset L1S dedicated mode manager trigger. l1a_l1s_com.dedic_set.SignalCode = NULL; } break; case WAIT_INIT: { switch(SignalCode) // switch on input message. //------------------------------- { case MPHC_IMMED_ASSIGN_REQ: // Immediate assignement message. //------------------------------- { UWORD8 maio_bef_sti; #if (L1_FF_MULTIBAND == 1) UWORD16 operative_radio_freq; #endif // Get Ptr to the free dedicated parameter set. // All important fields are initialised. free_set = l1a_get_free_dedic_set(); // Save given dedicated channel parameters from MPHC_IMMED_ASSIGN_REQ msg. //======================================================================== // Rem1: Mode is forced to Signalling Only. free_set->chan1.mode = SIG_ONLY_MODE; free_set->chan1.desc = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->channel_desc; free_set->ma.freq_list = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->frequency_list; free_set->ma.freq_list_bef_sti = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->frequency_list_bef_sti; maio_bef_sti = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->maio_bef_sti; free_set->new_timing_advance = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->timing_advance; free_set->dtx_allowed = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->dtx_allowed; l1a_l1s_com.dedic_set.pwrc = ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->pwrc; //---------------------------------------------- //Rem: bcch_allocation, ba_id are not used!!!!!! //---------------------------------------------- // New Timing Advance value must be applied on 1st frame of dedic. channel. free_set->timing_advance = free_set->new_timing_advance; // TXPWR command was given in Idle, save it in dedicated mode structure. free_set->new_target_txpwr = l1s.applied_txpwr; // Serving Cell stays the same. free_set->cell_desc = l1a_l1s_com.Scell_info; #if (L1_FF_MULTIBAND == 0) free_set->cell_desc.traffic_meas_beacon = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset]; free_set->cell_desc.traffic_meas = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset]; #else // L1_FF_MULTIBAND = 1 below operative_radio_freq = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); free_set->cell_desc.traffic_meas_beacon = l1a_l1s_com.last_input_level[operative_radio_freq]; free_set->cell_desc.traffic_meas = l1a_l1s_com.last_input_level[operative_radio_freq]; #endif // #if (L1_FF_MULTIBAND == 0) else // Decode the "starting time field", since staying on the same serving // the same STI fn is saved in both "neig_sti_fn" and "serv_sti_fn". free_set->neig_sti_fn = l1a_decode_starting_time(((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->starting_time); free_set->serv_sti_fn = free_set->neig_sti_fn; // Check/Fill "before starting time" fields. l1a_fill_bef_sti_param(free_set, ((T_MPHC_IMMED_ASSIGN_REQ *)(msg->SigP))->starting_time.start_time_present); // Use provided "before starting time MAIO" if hopping channel. if(free_set->chan1.desc_bef_sti.chan_sel.h) free_set->chan1.desc_bef_sti.chan_sel.rf_channel.hopping_rf.maio = maio_bef_sti; // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // Save the "timeslot difference" between new and old configuration // in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += free_set->chan1.desc.timeslot_no - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = free_set->chan1.desc.timeslot_no; // Save new TN id. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Set "fset" pointer to the new parameter set. l1a_l1s_com.dedic_set.fset = free_set; /* * FreeCalypso: the following logic related to dynamic DSP * patching has been reconstructed from our only available * binary object version. */ #if (L1_DYN_DSP_DWNLD == 1) if (l1a.dyn_dwnld.semaphore_vect[DEDI_STATE_MACHINE]==GREEN) #endif { // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = MPHC_IMMED_ASSIGN_REQ; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // Set confirmation message name. l1a.confirm_SignalCode = MPHC_IMMED_ASSIGN_CON; // step in state machine. *state = WAIT_MSG; } #if (L1_DYN_DSP_DWNLD == 1) else { *state = WAIT_DYN_DWNLD; #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4) || (TRACE_TYPE == 5)) if((trace_info.current_config->l1_dyn_trace) & (1<<L1_DYN_TRACE_DYN_DWNLD)) { char str[30]; sprintf(str,"DEDI SM blocked by DYN DWNLD\r\n"); #if(CODE_VERSION == SIMULATION) trace_fct_simu_dyn_dwnld(str); #else rvt_send_trace_cpy((T_RVT_BUFFER)str,trace_info.l1_trace_user_id,strlen(str),RVT_ASCII_FORMAT); #endif } #endif // (TRACE_TYPE == 1) || (TRACE_TYPE == 4) } #endif } break; case MPHC_CHANNEL_ASSIGN_REQ: // Channel assignement message. //----------------------------- { UWORD8 supplied_txpwr; UWORD16 tch_radio_freq; #if ((REL99 == 1) && (FF_BHO == 1)) //restore long_rem_handover_type from previous handover activites l1a_l1s_com.dedic_set.long_rem_handover_type = 0; //reset handover to normal #endif // #if ((REL99 == 1) && (FF_BHO == 1)) #if(L1_CHECK_COMPATIBLE == 1) l1a.stop_req = FALSE; #endif // Get Ptr to the free dedicated parameter set. free_set = l1a_get_free_dedic_set(); // Save given dedicated channel parameters from MPHC_CHANNEL_ASSIGN_REQ msg. //=============================================================--========== free_set->chan1.desc = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_desc_1; free_set->chan1.desc_bef_sti = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_desc_1_bef_sti; free_set->chan1.mode = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_mode_1; free_set->chan2.desc = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_desc_2; free_set->chan2.desc_bef_sti = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_desc_2_bef_sti; free_set->chan2.mode = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->channel_mode_2; free_set->ma.freq_list = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->frequency_list; free_set->ma.freq_list_bef_sti = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->frequency_list_bef_sti; free_set->dtx_allowed = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->dtx_allowed; supplied_txpwr = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->txpwr; #if (AMR == 1) // download AMR ver 1.0 information free_set->amr_configuration = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->amr_configuration; free_set->cmip = C_AMR_CMIP_DEFAULT; #endif #if (TRACE_TYPE==3) l1_stats.chan_mode = free_set->chan1.mode; #endif // Determine which band we are transmitting on if(free_set->chan1.desc.chan_sel.h == TRUE) // we are hopping therefore tch_radio_freq = free_set->ma.freq_list.rf_chan_no.A[0]; // take band from first element in maio list else // else take band from fixed radio_freq tch_radio_freq = free_set->chan1.desc.chan_sel.rf_channel.single_rf.radio_freq; // Check max transmit power (min txpwr) according to powerclass // and clip to MIN_TXPWR_LEVEL using new TCH radio_freq info. supplied_txpwr = l1a_clip_txpwr(supplied_txpwr,tch_radio_freq); free_set->new_target_txpwr = supplied_txpwr; if(((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->cipher_mode != 0) free_set->a5mode = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->a5_algorithm + 1; else free_set->a5mode = 0; // Grab the cipher key free_set->ciph_key = ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->cipher_key; // Serving Cell stays the same. free_set->cell_desc = l1a_l1s_com.Scell_info; // Decode the "starting time field", since staying on the same serving // the same STI fn is saved in both "neig_sti_fn" and "serv_sti_fn". free_set->neig_sti_fn = l1a_decode_starting_time(((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->starting_time); free_set->serv_sti_fn = free_set->neig_sti_fn; // Check/Fill "before starting time" fields. l1a_fill_bef_sti_param(free_set, ((T_MPHC_CHANNEL_ASSIGN_REQ *)(msg->SigP))->starting_time.start_time_present); // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // Save the "timeslot difference" between new and old configuration // in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += free_set->chan1.desc.timeslot_no - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = free_set->chan1.desc.timeslot_no; // Save new TN id. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Carry over the previous "tch_loop" settings for HW bit error testing */ free_set->chan1.tch_loop = l1a_l1s_com.dedic_set.aset->chan1.tch_loop; free_set->chan2.tch_loop = l1a_l1s_com.dedic_set.aset->chan2.tch_loop; // Set "fset" pointer to the new parameter set. l1a_l1s_com.dedic_set.fset = free_set; // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = MPHC_CHANNEL_ASSIGN_REQ; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // Set confirmation message name. l1a.confirm_SignalCode = MPHC_CHANNEL_ASSIGN_CON; // step in state machine. *state = WAIT_MSG; } break; case MPHC_SYNC_HO_REQ: case MPHC_PRE_SYNC_HO_REQ: case MPHC_PSEUDO_SYNC_HO_REQ: case MPHC_ASYNC_HO_REQ: // Handover messages. //------------------- { WORD32 new_ta = 0; BOOL nci = 0; UWORD16 radio_freq; UWORD16 tch_radio_freq; UWORD32 ncc; UWORD32 bcc; UWORD32 time_alignmt = 0; UWORD32 fn_offset = 0; UWORD8 supplied_txpwr; #if (L1_FF_MULTIBAND == 1) UWORD16 operative_radio_freq; #endif #if ((REL99 == 1) && (FF_BHO == 1)) // Get the handover type: regular or blind switch(SignalCode) { case MPHC_SYNC_HO_REQ: { l1a_l1s_com.dedic_set.handover_type = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_type; } break; case MPHC_PRE_SYNC_HO_REQ: { l1a_l1s_com.dedic_set.handover_type = ((T_MPHC_PRE_SYNC_HO_REQ *)(msg->SigP))->handover_type; } break; case MPHC_ASYNC_HO_REQ: { l1a_l1s_com.dedic_set.handover_type = ((T_MPHC_ASYNC_HO_REQ *)(msg->SigP))->handover_type; } break; case MPHC_PSEUDO_SYNC_HO_REQ: { l1a_l1s_com.dedic_set.handover_type = ((T_MPHC_PSEUDO_SYNC_HO_REQ *)(msg->SigP))->handover_type; } break; } // BCCH frequency of target cell l1a_l1s_com.dedic_set.bcch_carrier_of_nbr_cell = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.cell_description.bcch_carrier; //Store handover type in another variable to be used in L1S till handover finished is issued. l1a_l1s_com.dedic_set.long_rem_handover_type = l1a_l1s_com.dedic_set.handover_type; #endif // #if ((REL99 == 1) && (FF_BHO == 1)) // Get Ptr to the free dedicated parameter set. free_set = l1a_get_free_dedic_set(); /*--------------------------------------------------------------*/ /* Save msg content in the free "DEDICATED PARAM. STRUCT." */ /* Rem: since the HANDOVER PARAMETER structure is on the top of */ /* each handover message, we can access it using any "cast". */ /* Here we chose the "(T_MPHC_SYNC_HO_REQ *)". */ /*--------------------------------------------------------------*/ // Download timing information from the command message. #if ((REL99 == 1) && (FF_BHO == 1)) if (l1a_l1s_com.dedic_set.handover_type == NORMAL_HANDOVER) #endif { time_alignmt = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->fn_offset; } // Save time difference between new serving and previous one // in case of HANDOVER FAIL. static_ho_fail_time_alignmt = (5000 - time_alignmt) % 5000; static_ho_fail_fn_offset = (1 + MAX_FN - fn_offset) % MAX_FN; #if ((L1_EOTD==1) && (L1_EOTD_QBIT_ACC ==1)) // Save time_alignmt and fn_offset for Serving Cell E-OTD // in case of handover failure... static_serv_fn_offset = l1a_l1s_com.nsync.serv_fn_offset; static_serv_time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; l1a_l1s_com.nsync.serv_fn_offset = 0; l1a_l1s_com.nsync.serv_time_alignmt = 0; #endif if(time_alignmt == 0) // The 2 base stations are seen qbit synchronized... // -> Prevent frame diff. side effect. { static_ho_fail_fn_offset = (static_ho_fail_fn_offset + MAX_FN - 1) % MAX_FN; } // Save Acitve dedicated mode parameter set // in case of HANDOVER FAIL. static_ho_fail_aset = l1a_l1s_com.dedic_set.aset; // Setup new serving cell information. radio_freq = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.cell_description.bcch_carrier; ncc = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.cell_description.ncc; bcc = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.cell_description.bcc; free_set->cell_desc.radio_freq = radio_freq; free_set->cell_desc.bsic = (bcc) | (ncc << 3); free_set->cell_desc.time_alignmt = time_alignmt; free_set->cell_desc.fn_offset = fn_offset; free_set->cell_desc.meas.acc = 0; free_set->cell_desc.meas.nbr_meas = 0; #if 0 /* FreeCalypso TCS211 reconstruction */ #if (L1_FF_MULTIBAND == 0) // TBD free_set->cell_desc.traffic_meas_beacon = l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset]; free_set->cell_desc.traffic_meas = l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset]; #else // L1_FF_MULTIBAND = 1 below operative_radio_freq = l1_multiband_radio_freq_convert_into_operative_radio_freq(radio_freq); free_set->cell_desc.traffic_meas_beacon = l1a_l1s_com.last_input_level[operative_radio_freq]; free_set->cell_desc.traffic_meas = l1a_l1s_com.last_input_level[operative_radio_freq]; #endif // #if (L1_FF_MULTIBAND == 1) else #endif // Download the message content. free_set->chan1.desc = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_desc_1; free_set->chan1.desc_bef_sti = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_desc_1_bef_sti; free_set->chan1.mode = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_mode_1; free_set->chan2.desc = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_desc_2; free_set->chan2.desc_bef_sti = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_desc_2_bef_sti; free_set->chan2.mode = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.channel_mode_2; free_set->ma.freq_list = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.frequency_list; free_set->ma.freq_list_bef_sti = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.frequency_list_bef_sti; supplied_txpwr = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.txpwr; #if (AMR == 1) // download AMR ver 1.0 information switch(SignalCode) { case MPHC_SYNC_HO_REQ: { free_set->amr_configuration = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->amr_configuration; } break; case MPHC_PRE_SYNC_HO_REQ: { free_set->amr_configuration = ((T_MPHC_PRE_SYNC_HO_REQ *)(msg->SigP))->amr_configuration; } break; case MPHC_ASYNC_HO_REQ: { free_set->amr_configuration = ((T_MPHC_ASYNC_HO_REQ *)(msg->SigP))->amr_configuration; } break; } free_set->cmip = C_AMR_CMIP_DEFAULT; #endif // Determine which band we are transmitting on if(free_set->chan1.desc.chan_sel.h == TRUE) // we are hopping therefore tch_radio_freq = free_set->ma.freq_list.rf_chan_no.A[0]; // take band from first element in maio list else // else take band from fixed radio_freq tch_radio_freq = free_set->chan1.desc.chan_sel.rf_channel.single_rf.radio_freq; // Check max transmit power (min txpwr) according to powerclass // and clip to MIN_TXPWR_LEVEL using new TCH radio_freq info. supplied_txpwr = l1a_clip_txpwr(supplied_txpwr,tch_radio_freq); free_set->new_target_txpwr = supplied_txpwr; free_set->ho_acc = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.ho_acc; // Copy in cipher key Kc. free_set->ciph_key = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->cipher_key; if(((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.cipher_mode != 0) free_set->a5mode = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.a5_algorithm + 1; else free_set->a5mode = 0; // Decode the "starting time field". Since changing the serving cell // a different STI fn is saved in "neig_sti_fn" and "serv_sti_fn". free_set->neig_sti_fn = l1a_decode_starting_time(((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.starting_time); if(free_set->neig_sti_fn != -1) free_set->serv_sti_fn = (free_set->neig_sti_fn - free_set->cell_desc.fn_offset + MAX_FN) % MAX_FN; // Check/Fill "before starting time" fields. l1a_fill_bef_sti_param(free_set, ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.starting_time.start_time_present); // TIMING ADVANCED COMPUTATION...(GSM05.10) //-------------------------------- switch(SignalCode) { case MPHC_SYNC_HO_REQ: case MPHC_PSEUDO_SYNC_HO_REQ: { WORD32 t1_hbit; WORD32 otd_hbit; if(SignalCode == MPHC_SYNC_HO_REQ) // Synchronous Handover { l1a.confirm_SignalCode = MPHC_SYNC_HO_CON; // Set confirmation message name. //rtd_hbit_mod256 = 0; nci = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->nci; } // Compute Timing Advance TA. //--------------------------- // t1 = t0 + OTD - RTD (GSM05.10, $A1.3) // OTD: Observed Time Difference. ( OTD = time(BTS0) - time(BTS1) ) // RTD: Report Time Difference. // t0: one way line of sight propagation MS-BTS0 (old BTS) ( t0 = TA(BTS0) / 2 ). // t1: one way line of sight propagation MS-BTS1 (new BTS) ( t1 = TA(BTS1) / 2 ). /*** Convert QBO to Half bits (HBO) ***/ otd_hbit = (((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->time_alignmt / 2); // If OTD is too high, it should be seen as a Negative value. if(otd_hbit > 1250) { /*** Cell is advanced in timing from serving, hence TDMA arrives earlier => Smaller Timing Advance and OTD is -ve ***/ otd_hbit -= 2500 ; } else { /*** Cell is retarted in timing from serving, hence TDMA arrives later => Larger Timing Advance and OTD is +ve ***/ } t1_hbit = (WORD32) (otd_hbit + (WORD32) l1a_l1s_com.dedic_set.aset->new_timing_advance); if(t1_hbit < 0) t1_hbit = 0; new_ta = t1_hbit; } break; case MPHC_PRE_SYNC_HO_REQ: // Pre-Synchronous Handover... { l1a.confirm_SignalCode = MPHC_PRE_SYNC_HO_CON; // Set confirmation message name. if(((T_MPHC_PRE_SYNC_HO_REQ *)(msg->SigP))->timing_advance_valid) new_ta = ((T_MPHC_PRE_SYNC_HO_REQ *)(msg->SigP))->timing_advance; else new_ta = 1; } break; case MPHC_ASYNC_HO_REQ: // Asynchronous Handover... { l1a.confirm_SignalCode = MPHC_ASYNC_HO_CON; // Set confirmation message name. } break; } // End switch... // Ensure TA is never set to > 63. if(new_ta > 63) { if(nci == 1) // Out of range TA must trigger a HO failure procedure. // GSM04.08, $3.4.4.4 and $10.5.2.39. { // Send confirmation message to L3. l1a_send_confirmation(MPHC_TA_FAIL_IND,RRM1_QUEUE); // step in state machine. *state = WAIT_MSG; // Stop current L1A process. return; } else // Max TA is 63. { new_ta = 63; } } // Save computed TA in the new set. // This new TA shall be applied on 1st frame of new channel. free_set->new_timing_advance = (UWORD8)new_ta; free_set->timing_advance = free_set->new_timing_advance; #if ((REL99 == 1) && (FF_BHO == 1)) free_set->nci = nci; free_set->report_time_diff = ((T_MPHC_SYNC_HO_REQ *)(msg->SigP))->handover_command.report_time_diff; if(SignalCode == MPHC_PSEUDO_SYNC_HO_REQ) free_set->real_time_difference = ((T_MPHC_PSEUDO_SYNC_HO_REQ *)(msg->SigP))->real_time_difference; #endif // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // Save the "timeslot difference" between new and old configuration // in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. #if ((REL99 == 1) && (FF_BHO == 1)) if(l1a_l1s_com.dedic_set.handover_type == NORMAL_HANDOVER) { #endif l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += free_set->chan1.desc.timeslot_no - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = free_set->chan1.desc.timeslot_no; // Save new TN id. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. #if ((REL99 == 1) && (FF_BHO == 1)) } #endif //#if ((REL99 == 1) && (FF_BHO == 1)) // Set "fset" pointer to the new parameter set. l1a_l1s_com.dedic_set.fset = free_set; #if ((REL99 == 1) && (FF_BHO == 1)) // check whether handover is Normal or Blind. If it is normal handover, // follow the normal path. Otherwise go to blind handover state. if(l1a_l1s_com.dedic_set.handover_type == NORMAL_HANDOVER) { #endif // #if ((REL99 == 1) && (FF_BHO == 1)) // Give new msg code to L1S. // Rem: only 2 cases handled by L1S, SYNC and ASYNC. if(SignalCode == MPHC_ASYNC_HO_REQ) l1a_l1s_com.dedic_set.SignalCode = MPHC_ASYNC_HO_REQ; else l1a_l1s_com.dedic_set.SignalCode = MPHC_SYNC_HO_REQ; #if ((REL99 == 1) && (FF_BHO == 1)) } else // Handover type is blind. { // step in state machine. free_set->HO_SignalCode = SignalCode; // Give new msg code to L1S. (below process is done by l1a_dedicated_process()) l1a_l1s_com.dedic_set.SignalCode = MPHC_STOP_DEDICATED_REQ; } #endif // #if ((REL99 == 1) && (FF_BHO == 1)) #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // step in state machine. *state = WAIT_MSG; } break; case MPHC_HANDOVER_FAIL_REQ: // Handover failled, we must go back to the previous channel. //----------------------------------------------------------- { // Give back the previous configuration in the "fset" ptr. l1a_l1s_com.dedic_set.fset = static_ho_fail_aset; // Set confirmation message name. l1a.confirm_SignalCode = MPHC_HANDOVER_FAIL_CON; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(SignalCode); #endif #if ((L1_EOTD==1) && (L1_EOTD_QBIT_ACC ==1)) // Restore E-OTD serving cell time_alignmt and fn_offset // from the cached versions... l1a_l1s_com.nsync.serv_fn_offset = static_serv_fn_offset; l1a_l1s_com.nsync.serv_time_alignmt = static_serv_time_alignmt; #endif // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&static_ho_fail_time_alignmt, &static_ho_fail_fn_offset, l1a_l1s_com.dl_tn); // Setup new serving cell information. l1a_l1s_com.dedic_set.fset->cell_desc.time_alignmt = static_ho_fail_time_alignmt; l1a_l1s_com.dedic_set.fset->cell_desc.fn_offset = static_ho_fail_fn_offset; // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't followed // the generic rules of the Semaphore shared between L1A and L1S. // Since switching to a neigh cell, the known time_alignmt is about TN=0. // Set "tn_difference" with the new timeslot. // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; { l1a_l1s_com.tn_difference += l1a_l1s_com.dedic_set.fset->chan1.desc.timeslot_no; l1a_l1s_com.dl_tn = l1a_l1s_com.dedic_set.fset->chan1.desc.timeslot_no; // Save new TN id. } l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // step in state machine. *state = WAIT_MSG; } break; case MPHC_STOP_DEDICATED_REQ: // Release dedicated mode message. //-------------------------------- { // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // step in state machine. *state = WAIT_MSG; } break; case MPHC_CHANGE_FREQUENCY: // Frequency redefinition msg. //---------------------------- { UWORD8 subchannel; // Get Ptr to the free dedicated parameter set. free_set = l1a_get_free_dedic_set(); // Download Active set in the new set. *free_set = *l1a_l1s_com.dedic_set.aset; // Get subchannel for the target channel. subchannel = ((T_MPHC_CHANGE_FREQUENCY *)(msg->SigP))->channel_desc.subchannel; // Copy current parameters to BEF STI. free_set->chan1.desc_bef_sti = free_set->chan1.desc; free_set->chan2.desc_bef_sti = free_set->chan2.desc; free_set->ma.freq_list_bef_sti = free_set->ma.freq_list; // Download new param in AFTER STI. free_set->ma.freq_list = ((T_MPHC_CHANGE_FREQUENCY *)(msg->SigP))->frequency_list; if(subchannel == free_set->chan1.desc.subchannel) // Target channel is CHAN1. free_set->chan1.desc = ((T_MPHC_CHANGE_FREQUENCY *)(msg->SigP))->channel_desc; else // Target channel is CHAN2. free_set->chan2.desc = ((T_MPHC_CHANGE_FREQUENCY *)(msg->SigP))->channel_desc; // Compute starting time. free_set->neig_sti_fn = l1a_decode_starting_time(((T_MPHC_CHANGE_FREQUENCY *)(msg->SigP))->starting_time); free_set->serv_sti_fn = free_set->neig_sti_fn; // Set FREQUENCY REDEFINITION flag to trigger a confirmation when STI is reached. free_set->freq_redef_flag = TRUE; // Set "fset" pointer to the new parameter set. l1a_l1s_com.dedic_set.fset = free_set ; // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // step in state machine. *state = WAIT_MSG; } break; } // end of "switch(SignalCode)". // end of process. end_process = 1; } break; /* * FreeCalypso: the following logic related to dynamic DSP * patching has been reconstructed from our only available * binary object version. */ #if (L1_DYN_DSP_DWNLD == 1) case WAIT_DYN_DWNLD: { if((SignalCode==API_L1_DYN_DWNLD_FINISHED) && (l1a.dyn_dwnld.semaphore_vect[DEDI_STATE_MACHINE] == GREEN)) { /* replicate the code that would have executed originally */ // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = MPHC_IMMED_ASSIGN_REQ; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // Set confirmation message name. l1a.confirm_SignalCode = MPHC_IMMED_ASSIGN_CON; #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4) || (TRACE_TYPE == 5)) if((trace_info.current_config->l1_dyn_trace) & (1<<L1_DYN_TRACE_DYN_DWNLD)) { char str[30]; sprintf(str,"DEDI SM un-blocked\r\n"); #if(CODE_VERSION == SIMULATION) trace_fct_simu_dyn_dwnld(str); #else rvt_send_trace_cpy((T_RVT_BUFFER)str,trace_info.l1_trace_user_id,strlen(str),RVT_ASCII_FORMAT); #endif } #endif // (TRACE_TYPE == 1) || (TRACE_TYPE == 4) // step in state machine. *state = WAIT_MSG; } // End process end_process = 1; } break; #endif case WAIT_MSG: { switch(SignalCode) // switch on input message. //------------------------------- { case L1C_DEDIC_DONE: // Dedicated channel activated. //----------------------------- { // Send confirmation message to L3. l1a_send_confirmation(l1a.confirm_SignalCode,RRM1_QUEUE); // End of process. end_process = 1; } break; case L1C_REDEF_DONE: // Dedicated channel activated. //----------------------------- { // Send confirmation message to L3. l1a_send_confirmation(MPHC_CHANGE_FREQUENCY_CON,RRM1_QUEUE); // End of process. end_process = 1; } break; case L1C_HANDOVER_FINISHED: // HANDOVER finished. //------------------- { #if ((REL99 == 1) && (FF_BHO == 1)) // Forwarding the BHO params to L2/L3. ((T_MPHC_HANDOVER_FINISHED *)(msg->SigP))->fn_offset = l1a_l1s_com.dedic_set.fn_offset;//static_nsync_bho.fn_offset; ((T_MPHC_HANDOVER_FINISHED *)(msg->SigP))->time_alignment = l1a_l1s_com.dedic_set.time_alignment;//static_nsync_bho.time_alignmt; #endif // Forward result message to L3. l1a_send_result(MPHC_HANDOVER_FINISHED, msg, RRM1_QUEUE); // End of process. end_process = 1; } break; case MPHC_CHANNEL_MODE_MODIFY_REQ: // New parameters are given concerning channel mode. //-------------------------------------------------- { l1a_l1s_com.dedic_set.mode_modif.subchannel = ((T_MPHC_CHANNEL_MODE_MODIFY_REQ *)(msg->SigP))->subchannel; l1a_l1s_com.dedic_set.mode_modif.channel_mode = ((T_MPHC_CHANNEL_MODE_MODIFY_REQ *)(msg->SigP))->channel_mode; #if (AMR == 1) // download AMR ver 1.0 information l1a_l1s_com.dedic_set.mode_modif.amr_configuration = ((T_MPHC_CHANNEL_MODE_MODIFY_REQ *)(msg->SigP))->amr_configuration; l1a_l1s_com.dedic_set.aset->cmip = C_AMR_CMIP_DEFAULT; #endif // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // Send confirmation message to L3. l1a_send_confirmation(MPHC_CHANNEL_MODE_MODIFY_CON,RRM1_QUEUE); // End of process. end_process = 1; } break; case OML1_CLOSE_TCH_LOOP_REQ: // Close TCH loop. //---------------- // Rem: frame_erasure field is supposed to contain "Y" and "Z" bit from // CLOSE_TCH_LOOP_CMD (GSM11.10 $36.2.4.1). Wait for confirmation // from CAPDEBIS. WARNING!!!!!!!!!1 // frame_erasure | Loop | tch_loop // ---------------|--------|----------- // | none | 0 // 0 | A | 1 // 1 | B | 2 // 2 | C | 3 // 3 | D | 4 // 4 | E | 5 // 5 | F | 6 // 6 | I | 7 { if(l1a_l1s_com.mode == DEDIC_MODE) // Command message is valid only when dedic. mode is running. { UWORD8 subchannel = ((T_OML1_CLOSE_TCH_LOOP_REQ *)(msg->SigP))->sub_channel; UWORD8 tch_loop = ((T_OML1_CLOSE_TCH_LOOP_REQ *)(msg->SigP))->frame_erasure + 1; if(subchannel == l1a_l1s_com.dedic_set.aset->chan1.desc.subchannel) // Loop must be closed on CHAN1, this is done "on fly". { l1a_l1s_com.dedic_set.aset->chan1.tch_loop = tch_loop; } else // Loop must be closed on CHAN2, this is done "on fly". { l1a_l1s_com.dedic_set.aset->chan2.tch_loop = tch_loop; } // Send confirmation message to L3. l1a_send_confirmation(OML1_CLOSE_TCH_LOOP_CON,RRM1_QUEUE); } // End of process. end_process = 1; } break; case OML1_OPEN_TCH_LOOP_REQ: // Open TCH loop. //--------------- { // Any loop is opened, this is done "on fly". l1a_l1s_com.dedic_set.aset->chan1.tch_loop = 0; l1a_l1s_com.dedic_set.aset->chan2.tch_loop = 0; // Send confirmation message to L3. l1a_send_confirmation(OML1_OPEN_TCH_LOOP_CON,RRM1_QUEUE); // End of process. end_process = 1; } break; case OML1_START_DAI_TEST_REQ: // Start DAI test. //---------------- // tested_device | dai_mode | test // ---------------|-----------|-------------------- // 0 | 0 | no test // 1 | 2 | speech decoder // 2 | 1 | speech encoder // 3 | 0 | no test // 4 | 3 | Acouustic devices { const UWORD8 dai_transcode[] = {0, 2, 1, 0, 3}; const UWORD8 dai_vbctl3[] = {0, 1, 2, 0, 3}; UWORD32 vbctl3; UWORD8 dai_mode = dai_transcode[((T_OML1_START_DAI_TEST_REQ *)(msg->SigP))->tested_device]; // DAI mode is set "on fly". l1a_l1s_com.dedic_set.aset->dai_mode = dai_mode; // program vbctl3 // bit 12 | bit 11 // ---------------- // 1 | 1 Acouustic devices // 1 | 0 speech encoder // 0 | 1 speech decoder // 0 | 0 no test #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (ANLG_FAM == 11)) vbctl3 = ( (l1s_dsp_com.dsp_ndb_ptr ->d_dai_onoff & 0xE7FF) | (dai_vbctl3[((T_OML1_START_DAI_TEST_REQ *)(msg->SigP))->tested_device] << 11) ); l1s_dsp_com.dsp_ndb_ptr ->d_dai_onoff = vbctl3 | TRUE; #endif // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // Send confirmation message to L3. #if (OP_RIV_AUDIO == 1) l1a_audio_send_confirmation(OML1_START_DAI_TEST_CON); #else l1a_send_confirmation(OML1_START_DAI_TEST_CON,RRM1_QUEUE); #endif // End of process. end_process = 1; } break; case OML1_STOP_DAI_TEST_REQ: { UWORD32 vbctl3; // DAI test is stopped "on fly". l1a_l1s_com.dedic_set.aset->dai_mode = 0; #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) // program vbctl3 vbctl3 = (l1s_dsp_com.dsp_ndb_ptr ->d_dai_onoff & 0xE7FF); l1s_dsp_com.dsp_ndb_ptr ->d_dai_onoff = vbctl3 | TRUE; #endif // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // Send confirmation message to L3. #if (OP_RIV_AUDIO == 1) l1a_audio_send_confirmation(OML1_STOP_DAI_TEST_CON); #else l1a_send_confirmation(OML1_STOP_DAI_TEST_CON,RRM1_QUEUE); #endif // End of process. end_process = 1; } break; case MPHC_SET_CIPHERING_REQ: // Ciphering must be started or stopped. //-------------------------------------- { if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // the request must be ignored. // And a confirmation is returned to the L3. { // Send confirmation message to L3. l1a_send_confirmation(MPHC_SET_CIPHERING_CON,RRM1_QUEUE); } else { // GSM 4.08 $10.5.2.9 says (we suppose that "a5_algorithm" is // loaded with "algorithm identifier" and "cipher_mode" with // "SC"). // a5_algorithm from msg | A5 algo | a5_algorithm in dedic set // -----------------------|--------------|-------------------------- // | | 0 (no ciphering) // 0 | A5/1 | 1 // 1 | A5/2 | 2 // 2 | A5/3 | 3 // 3 | A5/4 | 4 // 4 | A5/5 | 5 // 5 | A5/6 | 6 // 6 | A5/7 | 7 UWORD8 cipher_mode = ((T_MPHC_SET_CIPHERING_REQ *)(msg->SigP))->cipher_mode; l1a_l1s_com.dedic_set.aset->ciph_key = ((T_MPHC_SET_CIPHERING_REQ *)(msg->SigP))->new_ciph_param; if(cipher_mode != 0) // Save A5 algo. l1a_l1s_com.dedic_set.aset->a5mode = ((T_MPHC_SET_CIPHERING_REQ *)(msg->SigP))->a5_algorithm + 1; else // No cipering. l1a_l1s_com.dedic_set.aset->a5mode = 0; // Give new msg code to L1S. l1a_l1s_com.dedic_set.SignalCode = SignalCode; // Send confirmation message to L3. l1a_send_confirmation(MPHC_SET_CIPHERING_CON,RRM1_QUEUE); } end_process = 1; } break; case L1C_SACCH_INFO: // SACCH result messages. //----------------------- { // Forward result message to L3. l1a_send_result(PH_DATA_IND, msg, DLL1_QUEUE); // end of process. end_process = 1; } break; case L1C_STOP_DEDICATED_DONE: // Dedicated channel released //----------------------------- { #if ((REL99 == 1) && (FF_BHO == 1)) // This event is disregarded in case of blind handover // (target cell synchro started) if(l1a_l1s_com.dedic_set.handover_type != BLIND_HANDOVER) #endif { // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_DEDICATED_CON,RRM1_QUEUE); // Step in state machine. *state = RESET; } // end of process. end_process = 1; } break; case MPHC_STOP_DEDICATED_REQ: case MPHC_CHANNEL_ASSIGN_REQ: case MPHC_SYNC_HO_REQ: case MPHC_PRE_SYNC_HO_REQ: case MPHC_PSEUDO_SYNC_HO_REQ: case MPHC_ASYNC_HO_REQ: case MPHC_HANDOVER_FAIL_REQ: case MPHC_CHANGE_FREQUENCY: // Reset messages. //---------------- { // Step in state machine. *state = RESET; } break; #if ((REL99 == 1) && (FF_BHO == 1)) case L1C_FBSB_INFO: { T_DEDIC_SET *free_set = l1a_l1s_com.dedic_set.fset; BOOL fb_found = ((T_L1C_FBSB_INFO*)(msg->SigP))->fb_flag; BOOL sb_found = ((T_L1C_FBSB_INFO*)(msg->SigP))->sb_flag; UWORD8 bsic = ((T_L1C_FBSB_INFO*)(msg->SigP))->bsic; UWORD32 fn_offset = ((T_L1C_FBSB_INFO*)(msg->SigP))->fn_offset; UWORD32 time_alignmt = ((T_L1C_FBSB_INFO*)(msg->SigP))->time_alignmt; if ((fb_found == FALSE) || (sb_found == FALSE) || (bsic != free_set->cell_desc.bsic)) // ------------------------ // FB + SB detection failed // ------------------------ { // Send reporting message with a faillure indication. xSignalHeaderRec *msg_new; msg_new = os_alloc_sig(sizeof(T_MPHC_HANDOVER_FINISHED)); DEBUGMSG(status,NU_ALLOC_ERR) msg_new->SignalCode = MPHC_HANDOVER_FINISHED; if (fb_found == FALSE) { // FB attempt failed. ((T_MPHC_HANDOVER_FINISHED *)(msg_new->SigP))->cause = HO_FB_FAIL; } else // (fb_found == FALSE) { // SB attempt failed. // or BSIC is not matching. ((T_MPHC_HANDOVER_FINISHED *)(msg_new->SigP))->cause = HO_SB_FAIL; } // (fb_found == FALSE) l1a_send_result(MPHC_HANDOVER_FINISHED, msg_new, RRM1_QUEUE); // Reset handover to normal l1a_l1s_com.dedic_set.handover_type = 0; // End of process. end_process=1;//return; } else //((fb_found == FALSE) || (sb_found == FALSE) || (bsic != free_set->cell_desc.bsic)) // ------------------------- // FB + SB detection success // ------------------------- { // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); // update time_alignmt and fn_offset of new cell free_set->cell_desc.fn_offset = fn_offset; free_set->cell_desc.time_alignmt = time_alignmt; if(free_set->neig_sti_fn != -1) free_set->serv_sti_fn = (free_set->neig_sti_fn - free_set->cell_desc.fn_offset + MAX_FN) % MAX_FN; // This is to send across fn_offset and time_alignmt of new cell to L2/L3. l1a_l1s_com.dedic_set.fn_offset = fn_offset; l1a_l1s_com.dedic_set.time_alignment = time_alignmt; // reset handover to normal l1a_l1s_com.dedic_set.handover_type = 0; SignalCode = free_set->HO_SignalCode; // Save time difference between new serving and previous one // in case of HANDOVER FAIL. static_ho_fail_time_alignmt = (5000 - time_alignmt) % 5000; static_ho_fail_fn_offset = (1 + MAX_FN - fn_offset) % MAX_FN; if (time_alignmt == 0) // The 2 base stations are seen qbit synchronized... // -> Prevent frame diff. side effect. { static_ho_fail_fn_offset = (static_ho_fail_fn_offset + MAX_FN - 1) % MAX_FN; } // TIMING ADVANCED COMPUTATION...(GSM05.10) //----------------------------------------- switch(SignalCode) { case MPHC_SYNC_HO_REQ: case MPHC_PSEUDO_SYNC_HO_REQ: { WORD32 t1_hbit; WORD32 otd_hbit; WORD32 new_ta = 0; BOOL nci = 0; if(SignalCode == MPHC_SYNC_HO_REQ) // Synchronous Handover { nci = free_set->nci; } // Compute Timing Advance TA. //--------------------------- // t1 = t0 + OTD - RTD (GSM05.10, $A1.3) // OTD: Observed Time Difference. ( OTD = time(BTS0) - time(BTS1) ) // RTD: Report Time Difference. // t0: one way line of sight propagation MS-BTS0 (old BTS) ( t0 = TA(BTS0) / 2 ). // t1: one way line of sight propagation MS-BTS1 (new BTS) ( t1 = TA(BTS1) / 2 ). // Convert QBO to Half bits (HBO) otd_hbit = (time_alignmt / 2); // If OTD is too high, it should be seen as a Negative value. if(otd_hbit > 1250) { // Cell is advanced in timing from serving, hence TDMA arrives earlier // => Smaller Timing Advance and OTD is -ve otd_hbit -= 2500 ; } else { // Cell is retarted in timing from serving, hence TDMA arrives later // => Larger Timing Advance and OTD is +ve } t1_hbit = (WORD32) (otd_hbit + (WORD32) static_ho_fail_aset->new_timing_advance); if(t1_hbit < 0) t1_hbit = 0; new_ta = t1_hbit; // Ensure TA is never set to > 63. if(new_ta > 63) { if(nci == 1) // Out of range TA must trigger a HO failure procedure. // GSM04.08, $3.4.4.4 and $10.5.2.39. { // Send confirmation message to L3. l1a_send_confirmation(MPHC_TA_FAIL_IND,RRM1_QUEUE); // End of process. return; } else // Max TA is 63. { new_ta = 63; } } // Save computed TA in the new set. // This new TA shall be applied on 1st frame of new channel. free_set->new_timing_advance = (UWORD8)new_ta; free_set->timing_advance = free_set->new_timing_advance; } break; case MPHC_PRE_SYNC_HO_REQ: // Pre-Synchronous Handover... { // no action for this message } break; case MPHC_ASYNC_HO_REQ: // Asynchronous Handover... { // no action for this message } break; } // End switch... // In order to keep tn_difference and dl_tn consistent, we need to avoid // the execution of the SYNCHRO task with tn_difference updated and // dl_tn not yet updated (this can occur if we go in the HISR just after // the update of tn_difference). To do this the solution is to use the Semaphore // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its // associated Semaphore is reset. // Note: Due to the specificity of the SYNCHRO task which can be enabled // by L1A state machines as by L1S processes, the semaphore can't follow // the generic rules of the Semaphore shared between L1A and L1S. // Save the "timeslot difference" between new and old configuration // in "tn_difference". // tn_difference -> loaded with the number of timeslot to shift. // dl_tn -> loaded with the new timeslot. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; l1a_l1s_com.tn_difference += free_set->chan1.desc.timeslot_no - l1a_l1s_com.dl_tn; l1a_l1s_com.dl_tn = free_set->chan1.desc.timeslot_no; // Save new TN id. l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; // Note: The using of the semaphore associated to the SYNCHRO task can't be done // as it is for the other semaphores. This is due to the specificity of the SYNCHRO // task both touch by L1A and L1S. Here above the semaphore is set prior to touching // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. // Give new msg code to L1S. // Rem: only 2 cases handled by L1S, SYNC and ASYNC. if(SignalCode == MPHC_ASYNC_HO_REQ) { l1a_l1s_com.dedic_set.SignalCode = MPHC_ASYNC_HO_REQ; } else { l1a_l1s_com.dedic_set.SignalCode = MPHC_SYNC_HO_REQ; } if (((l1a_l1s_com.dedic_set.SignalCode == MPHC_ASYNC_HO_REQ ) || (l1a_l1s_com.dedic_set.SignalCode == MPHC_SYNC_HO_REQ )) && (l1a_l1s_com.dedic_set.aset != NULL) && (l1a_l1s_com.l1s_en_task[DEDIC] == TASK_DISABLED)) l1a_l1s_com.l1s_en_task[DEDIC] = TASK_ENABLED; #if (TRACE_TYPE==5) && FLOWCHART trace_flowchart_dedic(l1a_l1s_com.dedic_set.SignalCode); #endif // End of process. end_process=1;// return; } // if ((fb_found == FALSE) || (sb_found == FALSE) || (bsic != free_set->cell_desc.bsic)) } // case L1C_FBSB_INFO: break; #endif // #if ((REL99 == 1) && (FF_BHO == 1)) default: // End of process. //---------------- { end_process = 1; } } // end of "switch(SignalCode)". } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_dedic6_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles the 6 strong.*/ /* neighbor cells management in dedicated mode. */ /* */ /* Remark: in dedicated mode there is no reason to use */ /* the task parameters semaphores since there is no */ /* ambiguity and no asynchronous/synchronous conflict to */ /* care about. */ /* */ /* Starting messages: L1C_DEDIC_DONE */ /* */ /* Result messages (input): L1C_FB_INFO */ /* L1C_SB_INFO */ /* L1C_SBCONF_INFO */ /* */ /* Reset messages (input): MPHC_CHANNEL_RELEASE */ /* */ /*-------------------------------------------------------*/ #if (L1_12NEIGH == 0) void l1a_dedic6_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_FB_RESULT = 2, WAIT_SB_RESULT = 3, WAIT_SBCONF_RESULT = 4 }; UWORD8 *state = &l1a.state[DEDIC_6]; UWORD32 SignalCode = msg->SignalCode; static UWORD8 nb_fb_attemp; // use only in packet transfer mode // these variables memorize this SBCNF parameters. static UWORD32 time_alignmt_mem; static UWORD32 fn_offset_mem; while(1) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset DEDIC6 tasks. l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; } break; case WAIT_INIT: { #if (L1_GPRS) // This machine works only for DEDICATED MODE and PACKET TRANSFER MODE // (Remark: PACKET TRANSFER MODE activated == PDTCH task activated) if((l1a_l1s_com.mode != DEDIC_MODE) && (l1a_l1s_com.l1s_en_task[PDTCH] != TASK_ENABLED)) return; #else // This machine works only for DEDICATED MODE. if (l1a_l1s_com.mode != DEDIC_MODE) return; #endif if(SignalCode == MPHC_NCELL_FB_SB_READ) // Request to make a synchro. ACQUISITION attempt with the given ARFCN. //--------------------------------------------------------------------- // L1 makes 1 attempt to read the Frequency Burst (FBNEW task). // 1 attempt to read the Synchro Burst (SB2 task). { if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // the request must be ignored. // Therefor the reporting message with a faillure indication is sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // Reset state machine. *state = RESET; // End of process. return; } else { // Set task semaphores. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; // Set SB51 task semaphore. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set SB26 task semaphore. l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; // Set SBCNF51 task semaphore. l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // Set SBCNF26 task semaphore. // This process always use the first element of "nsync" structure. l1a_l1s_com.nsync.current_list_size = 0; // Download Radio Freq Nb from the command message. // Other "nsync" parameters are unused. l1a_l1s_com.nsync.list[0].radio_freq = ((T_MPHC_NCELL_FB_SB_READ *)(msg->SigP))->radio_freq; // Step in state machine. *state = WAIT_FB_RESULT; // Enable FB task. if (l1a_l1s_com.mode == DEDIC_MODE) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) { nb_fb_attemp = 1; // 1 attempt for FB51 detection. l1a_l1s_com.l1s_en_task[FB51] = TASK_ENABLED; } else { nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; } } #if (L1_GPRS) else { // packet transfer mode nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; } #endif // End of process. return; } } else if(SignalCode == MPHC_NCELL_SB_READ) // Request to make a synchro. CONFIRMATION attempt with the given ARFCN. //--------------------------------------------------------------------- // L1 makes 1 attempt to read the Synchro Burst (SBCONF task). { if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // The request must be ignored // Therefor the reporting message with a failure indication is sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // Reset state machine. *state = RESET; // End of process. return; } else { UWORD32 time_alignmt; UWORD32 fn_offset; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; // Set SB51 task semaphore. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set SB26 task semaphore. l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; // Set SBCNF51 task semaphore. l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // Set SBCNF26 task semaphore. // Download ARFCN & timing information from the command message. time_alignmt = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->fn_offset; time_alignmt_mem = time_alignmt; fn_offset_mem = fn_offset; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); // Save neighbor information in the neighbor confirmation cell structure. l1a_l1s_com.nsync.list[0].radio_freq = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->radio_freq; l1a_l1s_com.nsync.list[0].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[0].fn_offset = fn_offset; // Step in state machine. *state = WAIT_SBCONF_RESULT; // Enable SBCONF task. if (l1a_l1s_com.mode == DEDIC_MODE) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_ENABLED; else l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_ENABLED; } #if (L1_GPRS) else { // packet transfer mode l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_ENABLED; } #endif // End of process. return; } } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; // case WAIT_INIT case WAIT_FB_RESULT: { // Use incoming message. //---------------------- if(SignalCode == L1C_FB_INFO) { if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is trhe dedicated mode during an handover fail // The monitoring task must be stopped // And the reporting message with a failure indication must be sent back { // Disable the FB detection task l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // Reset state machine. *state = RESET; } else { BOOL fb_found; // get result from message parameters. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; if(fb_found == TRUE) // FB attempt is a success. //------------------------- { // Step in state machine. *state = WAIT_SB_RESULT; // Enable SB task. if (l1a_l1s_com.mode == DEDIC_MODE) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) // case SDCCH, mutliframe 51... { l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; // Disable FB51 task. l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; // Set synchro semaphore for SB51 task. l1a_l1s_com.l1s_en_task[SB51] = TASK_ENABLED; // Enable SB51. } else // Dedicated D26 mode or Packet Transfer mode. { l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; // Disable FB26 task. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set synchro semaphore for SB26 task. l1a_l1s_com.l1s_en_task[SB26] = TASK_ENABLED; // Enable SB51. } } #if (L1_GPRS) else { // packet transfer mode l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; // Disable FB26 task. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set synchro semaphore for SB26 task. l1a_l1s_com.l1s_en_task[SB26] = TASK_ENABLED; // Enable SB51. l1a_l1s_com.nsync.list[0].sb26_attempt =0; } #endif // End of process. return; } else // FB attempt failed. //------------------- { // REM: // case SDCCH, mutliframe 51..., FB51: 1 attempt. // case TCH, mutliframe 26..., FB26: 11 attempts. if(--nb_fb_attemp == 0) { // Disable the FB detection task l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // Reset state machine. *state = RESET; } else return; } // endif fb_found }// endif l1a_l1s_com.dedic_set.handover_fail_mode } else // test in mode D26: L1C_DEDIC_DONE if(SignalCode == L1C_DEDIC_DONE) // New channel activated. //----------------------- { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; //--------------------------------------------- // We restart the FB detection from scratch !!! //--------------------------------------------- // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. // Step in state machine. *state = WAIT_FB_RESULT; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) { nb_fb_attemp = 1; // 1 attempt for FB51 detection. l1a_l1s_com.l1s_en_task[FB51] = TASK_ENABLED; } else { nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; } // End of process. return; } #if (L1_GPRS) else // a new synchronisation was performed if(((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->tn_difference!=0)) || (SignalCode == L1P_ALLOC_EXHAUST_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *) (msg->SigP))->tn_difference!=0) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all==0))) // New channel activated. //----------------------- { //--------------------------------------------- // We restart the FB detection from scratch !!! //--------------------------------------------- // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. // Step in state machine. *state = WAIT_FB_RESULT; nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; // End of process. return; } #endif else #if (L1_GPRS) // End of packet transfer mode if TBF downlink and uplink have been released if((SignalCode == MPHC_STOP_DEDICATED_REQ) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))) #else if(SignalCode == MPHC_STOP_DEDICATED_REQ) #endif // Reset messages. //---------------- { // Step in state machine. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case WAIT_SB_RESULT: { if(SignalCode == L1C_SB_INFO) // Synchro Burst acquisition attempt result. //------------------------------------------ { BOOL sb_found = ((T_L1C_SB_INFO *)(msg->SigP))->sb_flag; #if (L1_GPRS) static UWORD8 SB26_attempt_counter =0; #endif if(sb_found == TRUE) // SB detection is a success. { UWORD32 *fn_offset_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->time_alignmt); #if (L1_GPRS) if(l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) { SB26_attempt_counter = 0; // reset for next time } #endif // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); // This process must be reset. *state = RESET; } else // SB detection failled. { #if L1_GPRS if(l1a_l1s_com.l1s_en_task[DEDIC] == TASK_ENABLED) //--------------------------------------------- // Dedicated mode tasks are enabled. //--------------------------------------------- { #endif // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // This process must be reset. *state = RESET; #if L1_GPRS } else if(l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) //--------------------------------------------- // Packet Transfer mode task is enabled. //--------------------------------------------- { SB26_attempt_counter++; if (SB26_attempt_counter >= 2) { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); SB26_attempt_counter = 0; // This process must be reset. *state = RESET; } else { // End of process. return; } } #endif } } else // test in mode D26: L1C_DEDIC_DONE if (SignalCode == L1C_DEDIC_DONE) // New channel activated. //----------------------- { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; //--------------------------------------------- // We restart the FB detection from scratch !!! //--------------------------------------------- // Disable SB26 and SB51 l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. // Step in state machine. *state = WAIT_FB_RESULT; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) { nb_fb_attemp = 1; // 1 attempt for FB51 detection. l1a_l1s_com.l1s_en_task[FB51] = TASK_ENABLED; } else { nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; } // End of process. return; } #if (L1_GPRS) else // a new synchronisation was performed if(((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->tn_difference!=0)) || (SignalCode == L1P_ALLOC_EXHAUST_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *) (msg->SigP))->tn_difference!=0) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all==0))) // New channel activated. //----------------------- { //--------------------------------------------- // We restart the FB detection from scratch !!! //--------------------------------------------- // Disable SB26 and SB51 l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. // Step in state machine. *state = WAIT_FB_RESULT; nb_fb_attemp = 11; // 11 attempts for FB26 detection. l1a_l1s_com.l1s_en_task[FB26] = TASK_ENABLED; // End of process. return; } #endif else #if (L1_GPRS) // in packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released if((SignalCode == MPHC_STOP_DEDICATED_REQ) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))) #else if(SignalCode == MPHC_STOP_DEDICATED_REQ) #endif // Reset messages. //---------------- { // Step in state machine. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; case WAIT_SBCONF_RESULT: { if(SignalCode == L1C_SBCONF_INFO) // Synchro Burst acquisition attempt result. //------------------------------------------ { UWORD8 sb_found = ((T_L1C_SBCONF_INFO *)(msg->SigP))->sb_flag; if(sb_found == TRUE) // SB detection is a success. { UWORD32 *fn_offset_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->time_alignmt); // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); // This process must be reset. *state = RESET; } else // SB detection failled. { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); // This process must be reset. *state = RESET; } } else #if (L1_GPRS) // a new synchronisation was performed if((SignalCode == L1C_DEDIC_DONE) || ((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->tn_difference!=0)) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *) (msg->SigP))->tn_difference!=0) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all==0)) || (SignalCode == L1P_ALLOC_EXHAUST_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE)) #else if (SignalCode == L1C_DEDIC_DONE) #endif // New channel activated. //----------------------- { UWORD32 time_alignmt= 0; //omaps00090550 UWORD32 fn_offset =0; //omaps00090550 // update the SBCNF26 parameters // disable SBCNF26 task l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; // Set semaphores for SBCNF26 task. l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; time_alignmt = time_alignmt_mem; fn_offset = fn_offset_mem; // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); l1a_l1s_com.nsync.list[0].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[0].fn_offset = fn_offset; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_ENABLED; // Step in state machine. *state = WAIT_SBCONF_RESULT; // End of process. return; } else #if (L1_GPRS) // End of packet transfer mode if TBF downlink and uplink have been released if((SignalCode == MPHC_STOP_DEDICATED_REQ) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))) #else if(SignalCode == MPHC_STOP_DEDICATED_REQ) #endif // Reset messages. //---------------- { // Step in state machine. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { // End of process. return; } } break; } // end of "switch". } // end of "while" } // end of procedure. #endif //==================================================================// //==================================================================// //==================================================================// //==================================================================// //==================================================================// //==================================================================// //==================================================================// #if (L1_12NEIGH ==1) void l1a_dedic6_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, NSYNC_CONFIG = 2, SELECT_BEST_NSYNC = 3, WAIT_NSYNC_RESULT = 4, STOP_NSYNC = 5 #if (L1_EOTD==1) ,SCELL_CONFIG = 6 #endif }; UWORD8 *state = &l1a.state[DEDIC_6]; UWORD32 SignalCode = msg->SignalCode; //#if !L1_R99 static UWORD8 nb_fb_attempt; //#endif // For EOTD purpose we need of flag to identify 1st/last SB Serving Cell #if (L1_EOTD==1) static BOOL first_scell; static BOOL last_scell; static BOOL eotd_started; #endif BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; // Reset of process is embbeded in other state to // avoid conflicts between processes using the same // L1S tasks (Initial Netwirk sync + Idle 6 strongest) } break; case WAIT_INIT: { #if (L1_GPRS) // This machine works only for DEDICATED MODE and PACKET TRANSFER MODE // (Remark: PACKET TRANSFER MODE activated == PDTCH task activated) if((l1a_l1s_com.mode != DEDIC_MODE) && (l1a_l1s_com.l1s_en_task[PDTCH] != TASK_ENABLED)) return; #else // This machine works only for DEDICATED MODE. if (l1a_l1s_com.mode != DEDIC_MODE) return; #endif // Request to make a synchro. ACQUISITION attempt with the given ARFCN. //--------------------------------------------------------------------- if ((SignalCode == MPHC_NCELL_FB_SB_READ) || (SignalCode == MPHC_NCELL_SB_READ) || (SignalCode == MPHC_NCELL_SYNC_REQ) ||(SignalCode == MPHC_NCELL_LIST_SYNC_REQ) ) { if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // So the monitoring tasks must ALL be stopped and the reporting // message with a failure indication must be sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, 0); *state = STOP_NSYNC; break; } else { #if (L1_EOTD==1) // Check request validity for this process: for EOTD, nsync must be FREE... if( (SignalCode == MPHC_NCELL_LIST_SYNC_REQ) && (((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP))->eotd == TRUE) && (l1a_l1s_com.nsync.current_list_size != 0) ) // End of process. return; #endif l1a_l1s_com.nsync.first_in_list=0; //reset first_in_list // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[NSYNC]= SEMAPHORE_SET; // Set NSYNC task semaphore. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; // Set SB51 task semaphore. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set SB26 task semaphore. l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; // Set SBCNF51 task semaphore. l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // Set SBCNF26 task semaphore. // Step in state machine. *state = NSYNC_CONFIG; } } // No action in this machine for other messages. else { // End of process. return; } } break; case NSYNC_CONFIG: { UWORD8 neigh_id = l1a_l1s_com.nsync.first_in_list; UWORD32 time_alignmt; UWORD32 fn_offset; // Request to acquire FB/SB or to confirm FB or SB from one ncell. //---------------------------------------------------------------- // Abort if there is no room for a new neighbour synchro request. if(l1a_l1s_com.nsync.current_list_size >= NBR_NEIGHBOURS) { *state = WAIT_NSYNC_RESULT; // end of this process return; } // There is at least one free location within L1 structure. Find it! while((l1a_l1s_com.nsync.list[neigh_id].status != NSYNC_FREE)) { neigh_id++; if (neigh_id == NBR_NEIGHBOURS) neigh_id=0; } // TEMPORARY Code to insure transition between // OLD and NEW "6 strongest Interface" //---------------------------------------------- if (SignalCode == MPHC_NCELL_FB_SB_READ) { // Init timing_validity and read radio freq. l1a_l1s_com.nsync.list[neigh_id].timing_validity = 0; l1a_l1s_com.nsync.list[neigh_id].radio_freq = ((T_MPHC_NCELL_FB_SB_READ *)(msg->SigP))->radio_freq; l1a_l1s_com.nsync.list[neigh_id].time_alignmt = 0; l1a_l1s_com.nsync.list[neigh_id].fn_offset = 0; // Ncell WAITING l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_WAIT; // Increment list size l1a_l1s_com.nsync.current_list_size += 1; } else if (SignalCode == MPHC_NCELL_SB_READ) { // Init timing_validity and read radio freq. l1a_l1s_com.nsync.list[neigh_id].timing_validity = 2; l1a_l1s_com.nsync.list[neigh_id].radio_freq = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->radio_freq; time_alignmt = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_NCELL_SB_READ *)(msg->SigP))->fn_offset; // Ncell WAITING l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_WAIT; // Increment list size l1a_l1s_com.nsync.current_list_size += 1; } else if (SignalCode == MPHC_NCELL_SYNC_REQ) { // Init timing_validity and read radio freq. l1a_l1s_com.nsync.list[neigh_id].timing_validity =((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->timing_validity; l1a_l1s_com.nsync.list[neigh_id].radio_freq = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq; #if (L1_FF_MULTIBAND == 1) { UWORD8 physical_band_id; physical_band_id = l1_multiband_radio_freq_convert_into_physical_band_id(l1a_l1s_com.nsync.list[neigh_id].radio_freq); L1_MULTIBAND_TRACE_PARAMS(MULTIBAND_PHYSICAL_BAND_TRACE_ID,multiband_rf[physical_band_id].gsm_band_identifier); } #endif /*#if (L1_FF_MULTIBAND == 1)*/ if (l1a_l1s_com.nsync.list[neigh_id].timing_validity != 0) { time_alignmt = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->time_alignmt; fn_offset = ((T_MPHC_NCELL_SYNC_REQ *)(msg->SigP))->fn_offset; #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature if (l1a_l1s_com.nsync.list[neigh_id].timing_validity == 3) { l1a_l1s_com.nsync.list[neigh_id].nb_fb_attempt = 2 ; l1a_l1s_com.nsync.list[neigh_id].fb26_position = 255 ; } #endif } else { l1a_l1s_com.nsync.list[neigh_id].time_alignmt = 0; l1a_l1s_com.nsync.list[neigh_id].fn_offset = 0; } // Ncell WAITING l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_WAIT; // Increment list size l1a_l1s_com.nsync.current_list_size += 1; } if ( (SignalCode == MPHC_NCELL_SYNC_REQ) || (SignalCode == MPHC_NCELL_SB_READ) ) { // Correct timing info from request message with serving cell info. //----------------------------------------------------------------- if ( l1a_l1s_com.nsync.list[neigh_id].timing_validity != 0) { // correct timing l1a_correct_timing (neigh_id,time_alignmt,fn_offset); } } if ( SignalCode == MPHC_NCELL_LIST_SYNC_REQ ) { // Request to read FB/SB or SB from 1 to 12 neighbour cells. //---------------------------------------------------------- UWORD8 nbr_free = (UWORD8) (NBR_NEIGHBOURS) - l1a_l1s_com.nsync.current_list_size; UWORD8 list_size = ((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP))->list_size; T_MPHC_NCELL_LIST_SYNC_REQ *pt = ((T_MPHC_NCELL_LIST_SYNC_REQ *)(msg->SigP)); UWORD8 i; // Abort if there is no room for a new neighbour synchro request. if ( (l1a_l1s_com.nsync.current_list_size >= NBR_NEIGHBOURS) || (nbr_free < list_size) ) { *state = WAIT_NSYNC_RESULT; // end of this process return; } #if (L1_EOTD==1) // Abort if list is not empty before receiving EOTD request ... if ((pt->eotd == TRUE) && (l1a_l1s_com.nsync.current_list_size !=0)) { *state = WAIT_NSYNC_RESULT; // end of this process return; } // store Eotd flag l1a_l1s_com.nsync.eotd_meas_session = pt->eotd; #endif // Download neighbour info from request message. //---------------------------------------------- for (i=0; i<list_size; i++,neigh_id++) { if (neigh_id == NBR_NEIGHBOURS) neigh_id = 0; // Look for first free location within L1 structure. // There is at least one free location within L1 structure. Find it! while((l1a_l1s_com.nsync.list[neigh_id].status != NSYNC_FREE)) { neigh_id++; if(neigh_id == NBR_NEIGHBOURS) neigh_id=0;; } l1a_l1s_com.nsync.list[neigh_id].radio_freq = pt->ncell_list[i].radio_freq; l1a_l1s_com.nsync.list[neigh_id].timing_validity = pt->ncell_list[i].timing_validity; if( l1a_l1s_com.nsync.list[neigh_id].timing_validity != 0) { UWORD32 time_alignmt; UWORD32 fn_offset; // Download ARFCN, timing information and bitmap from the command message. time_alignmt = pt->ncell_list[i].time_alignmt; fn_offset = pt->ncell_list[i].fn_offset; // correct timing l1a_correct_timing (neigh_id,time_alignmt,fn_offset); #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature if (l1a_l1s_com.nsync.list[neigh_id].timing_validity == 3) { l1a_l1s_com.nsync.list[neigh_id].nb_fb_attempt = 2 ; l1a_l1s_com.nsync.list[neigh_id].fb26_position = 255 ; } #endif } else { l1a_l1s_com.nsync.list[neigh_id].fn_offset = 0; l1a_l1s_com.nsync.list[neigh_id].time_alignmt = 0; } // set Ncell WAITING l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_WAIT; // Increment list size l1a_l1s_com.nsync.current_list_size += 1; } // end for } // end if MPHC_NCELL_LIST_SYNC_REQ #if (L1_EOTD ==1) if ( l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // Step in state machine. *state = SCELL_CONFIG; } else #endif { // Step in state machine. *state = SELECT_BEST_NSYNC; } } break; // case NSYNC_CONFIG #if (L1_EOTD==1) case SCELL_CONFIG: { UWORD32 fn_offset=0; UWORD32 time_alignmt=0; // Enable L1S activity on the Serving Cell confirmation task // selects 1st Serving cell monitoring if (eotd_started == FALSE) { eotd_started = TRUE; first_scell = TRUE; } // selects last Serving cell monitoring else { eotd_started = FALSE; last_scell = TRUE; } // In Eotd : Serving cell is not part of the list //----------------------------------------------- // But it must be the 1st monitored // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. #if (L1_EOTD_QBIT_ACC== 1) time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; fn_offset = l1a_l1s_com.nsync.serv_fn_offset; #endif l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); // Load Serving cell in last position [NBR_NEIGHBOURS] l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].radio_freq = l1a_l1s_com.Scell_info.radio_freq; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset = fn_offset; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].timing_validity = 2; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset_mem = 0; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt_mem= 0; // Increment list size l1a_l1s_com.nsync.current_list_size += 1; // Enable Serving cell monitoring l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_PENDING; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_NSYNC_RESULT; // End of process. return; } #endif case SELECT_BEST_NSYNC: { BOOL exec_pending_task = FALSE; UWORD8 id_acquisition; UWORD8 i = 0; // list empty return to STOP_NSYNC //--------------------------- if (l1a_l1s_com.nsync.current_list_size == 0) { #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { *state = SCELL_CONFIG; // Step in state machine. break; } else #endif { *state = STOP_NSYNC; // reset process break; } } // disable all tasks l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; // Set semaphores for all neighbor relative task. l1a_l1s_com.task_param[NSYNC]= SEMAPHORE_SET; // Set NSYNC task semaphore. l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; // Set FB51 task semaphore. l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; // Set FB26 task semaphore. l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; // Set SB51 task semaphore. l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; // Set SB26 task semaphore. l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; // Set SBCNF51 task semaphore. l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // Set SBCNF26 task semaphore. // Look if there is an ACQUISITION in progress (PENDING) in order to disable // other cells. // If MF51, ACQUISITION means FB and SB. If MF26, ACQUISITION means FB only //--------------------------------------------------------------------------- // If so, let the new request in WAIT ... while ( (i<NBR_NEIGHBOURS) && (exec_pending_task==FALSE)) { if (l1a_l1s_com.nsync.list[i].status == NSYNC_PENDING) { // check FB or SB acquisition if ( l1a_l1s_com.nsync.list[i].timing_validity == 0 ) { exec_pending_task = TRUE; } else if (l1a_l1s_com.mode == DEDIC_MODE) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) if( (l1a_l1s_com.nsync.list[i].timing_validity == SB_ACQUISITION_PHASE) #else if( (l1a_l1s_com.nsync.list[i].timing_validity == 3) #endif &&((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) ) exec_pending_task = TRUE; } } i++; } // If there is an ACQUISITION in progress, put all other tasks in WAIT //-------------------------------------------------------------------- if (exec_pending_task == TRUE) { // if This SB acquisition comes from an FB CONFIRMATION, there may be some SB or // FB CONFIRMATIONS in PENDING state ==> put them in WAIT to insure FB/SB acquisition. UWORD8 cell_in_acquisition = i-1; #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) if (l1a_l1s_com.nsync.list[cell_in_acquisition].timing_validity == SB_ACQUISITION_PHASE) #else if (l1a_l1s_com.nsync.list[cell_in_acquisition].timing_validity == 3) #endif { //This case is only for MF51 for (i=0; i < NBR_NEIGHBOURS; i++) if ((l1a_l1s_com.nsync.list[i].status == NSYNC_PENDING) && (i != cell_in_acquisition)) l1a_l1s_com.nsync.list[i].status = NSYNC_WAIT; } // enable NSYNC l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_NSYNC_RESULT; // End of process. return; } // Otherwise : may be some other tasks (everything but FB aquisition) to set PENDING // In case we are in MF51, these tasks are SB and FB confirmation // In case we are in MF26, these tasks are SB and FB confirmation and SB acquisition //------------------------------------------------------ exec_pending_task = FALSE; for (i=0; i < NBR_NEIGHBOURS; i++) { if ( (l1a_l1s_com.nsync.list[i].status == NSYNC_WAIT) || (l1a_l1s_com.nsync.list[i].status == NSYNC_PENDING) ) { // set all other requested tasks PENDING if ( l1a_l1s_com.nsync.list[i].timing_validity != 0 ) { l1a_l1s_com.nsync.list[i].status = NSYNC_PENDING; exec_pending_task = TRUE; // initialise FB attempts for FB CONFIRMATION if (l1a_l1s_com.nsync.list[i].timing_validity == 1) #if ((REL99 == 1) && (FF_BHO == 1)) l1a_l1s_com.nsync.list[i].nb_fb_attempt = 1; #else nb_fb_attempt = 1; #endif } } } // If there are no pending task, perhaps there is an FB aquisition task to set pending. // In this case it is the older request, i.e. first_in_list. if (exec_pending_task == FALSE) { id_acquisition = l1a_l1s_com.nsync.first_in_list; // id has already been found....... l1a_l1s_com.nsync.list[id_acquisition].status = NSYNC_PENDING; if (l1a_l1s_com.mode == DEDIC_MODE) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) { #if ((REL99 == 1) && (FF_BHO == 1)) if (l1a_l1s_com.nsync.list[id_acquisition].timing_validity != 3) l1a_l1s_com.nsync.list[id_acquisition].nb_fb_attempt = 1;; #else nb_fb_attempt = 1; // 1 attempt for FB51 detection. #endif } else { #if ((REL99 == 1) && (FF_BHO == 1)) l1a_l1s_com.nsync.list[id_acquisition].nb_fb_attempt = 11; #else nb_fb_attempt = 11; // 11 attempts for FB26 detection. #endif // #if ((REL99 == 1) && (FF_BHO == 1)) } } #if (L1_GPRS) else { // packet transfer mode #if ((REL99 == 1) && (FF_BHO == 1)) if (l1a_l1s_com.nsync.list[i].timing_validity == 0) l1a_l1s_com.nsync.list[id_acquisition].nb_fb_attempt = 11; // 11 attempts for FB26 detection. else if (l1a_l1s_com.nsync.list[i].timing_validity == 1) l1a_l1s_com.nsync.list[id_acquisition].nb_fb_attempt = 1; #else nb_fb_attempt = 11; // 11 attempts for FB26 detection. #endif //#if ((REL99 == 1) && (FF_BHO == 1)) } #endif } // enable NSYNC l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = WAIT_NSYNC_RESULT; // End of process. end_process = 1; } break; // case SELECT_BEST_NSYNC case WAIT_NSYNC_RESULT: { if(SignalCode == L1C_FB_INFO) // Frequency Burst acquisition attempt result. //-------------------------------------------- { BOOL fb_found; UWORD8 neigh_id = ((T_L1C_FB_INFO *)(msg->SigP))->neigh_id; UWORD16 neigh_radio_freq = ((T_L1C_FB_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) #if ((REL99 == 1) && (FF_BHO == 1)) if ((neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq)|| ((neigh_radio_freq == l1a_l1s_com.nsync.list[neigh_id].radio_freq)&& (l1a_l1s_com.nsync.list[neigh_id].status==NSYNC_FREE))) #else if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) #endif { //REM: the message is not sent to L3 return;// Stay in current state. } if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // The monitoring tasks must be stopped // And the reporting message with a failure indication must be sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; // Set mode DEDIC ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; } #endif // This process must be reset *state = STOP_NSYNC; break; } // Get result from the message. fb_found = ((T_L1C_FB_INFO*)(msg->SigP))->fb_flag; if(fb_found == TRUE) // FB attempt is a success. // same process Now for DEDIC and PDTCH !!!! { // request was FB Confirmation + SB acquisition ..... #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) l1a_l1s_com.nsync.list[neigh_id].timing_validity = SB_ACQUISITION_PHASE ; #else l1a_l1s_com.nsync.list[neigh_id].timing_validity = 3; #endif l1a_l1s_com.nsync.list[neigh_id].sb26_attempt = 0; *state = SELECT_BEST_NSYNC; // Must break here to make sure the scheduler // runs immediately, else the next synchro attempt is not // started and we get a lock-up condition. break; } else // FB attempt failed. //------------------- { #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature if ((l1a_l1s_com.nsync.list[neigh_id].timing_validity != 0) && (l1a_l1s_com.mode == DEDIC_MODE)) { UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; if((channel_type == SDCCH_4) || (channel_type == SDCCH_8)) l1a_l1s_com.nsync.list[neigh_id].nb_fb_attempt = 1; // force attempt to 1 because we are in SDCCH } l1a_l1s_com.nsync.list[neigh_id].nb_fb_attempt-- ; if (l1a_l1s_com.nsync.list[neigh_id].nb_fb_attempt == 0) #else --nb_fb_attempt; if (nb_fb_attempt == 0) #endif { // if attempt was an FB confirmation, go back to FB full acquisition // and set it to WAIT state if (l1a_l1s_com.nsync.list[neigh_id].timing_validity == 1) { l1a_l1s_com.nsync.list[neigh_id].timing_validity = 0; l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_WAIT; // Step in state machine. *state = SELECT_BEST_NSYNC; // Must break here otherwise a SYNC IND (failure) // is generated for this event, when we really want the // FB acquisition to start from scratch with timing_validity=0. // If the subsequent process fails, then an indication will be // posted to L3. break; } // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); // Remove cell from list. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; if ((l1a_l1s_com.nsync.current_list_size != 0) && (neigh_id == l1a_l1s_com.nsync.first_in_list)) { while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; if (l1a_l1s_com.nsync.first_in_list==NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; } } // Step in state machine. *state = SELECT_BEST_NSYNC; // Must break here to make sure the scheduler // runs immediately, else the next synchro attempt is not // started and we get a lock-up condition. break; } #if ((REL99 == 1) && (FF_RTD == 1)) // RTD feature else { // we have to restore timing information which are destroyed after fb search failure if (l1a_l1s_com.nsync.list[neigh_id].timing_validity == 3) { // restore timing and frame information l1a_l1s_com.nsync.list[neigh_id].fn_offset = l1a_l1s_com.nsync.list[neigh_id].fn_offset_mem; l1a_l1s_com.nsync.list[neigh_id].time_alignmt = l1a_l1s_com.nsync.list[neigh_id].time_alignmt_mem; // apply timing correction l1a_correct_timing (neigh_id,l1a_l1s_com.nsync.list[neigh_id].time_alignmt,l1a_l1s_com.nsync.list[neigh_id].fn_offset); } } #endif } // End FB failed // End of process. return; } // End L1C_FB_INFO else if(SignalCode == L1C_SB_INFO) // Synchro Burst acquisition attempt result. //------------------------------------------ { BOOL sb_found = ((T_L1C_SB_INFO *)(msg->SigP))->sb_flag; UWORD8 neigh_id = ((T_L1C_SB_INFO *)(msg->SigP))->neigh_id; UWORD16 neigh_radio_freq = ((T_L1C_SB_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) { //REM: the message is not sent to L3 return;// Stay in current state. } if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // The monitoring tasks must be stopped // And the reporting message with a failure indication must be sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; // Set mode DEDIC ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; } #endif // This process must be reset *state = STOP_NSYNC; break; } if (sb_found == TRUE) // SB detection is a success... //----------------------------- { // Read Results. UWORD32 *fn_offset_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SB_INFO *)(msg->SigP))->time_alignmt); // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // compute EOTD data l1a_compute_Eotd_data(&first_scell,neigh_id, SignalCode, msg); // Set mode DEDIC ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; #if (L1_EOTD_QBIT_ACC ==1) if (neigh_id != 12) { l1a_compensate_sync_ind((T_MPHC_NCELL_SYNC_IND *)(msg->SigP)); } if( (neigh_id == 12) && (last_scell== TRUE) ) { l1a_l1s_com.nsync.serv_fn_offset = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset; l1a_l1s_com.nsync.serv_time_alignmt = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt; } #endif } #endif // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else // SB detection failed. { // Fix BUG2842 & BUG2864. In packet transfer SB aquisition task can be delayed // by a higer prioritary task. Two following attempts are re-scheduled. // First one can fail and we must not init process neither report any // failure indication to upper layers. if (l1a_l1s_com.nsync.list[neigh_id].sb26_attempt == 2) { // sb26_attempt = 2 : first attempt // sb26_attempt = 3 : second attempt return; } #if (L1_EOTD ==1) // Set mode DEDIC if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else #endif // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } // Remove cell from list. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; #if (L1_EOTD ==1) // Stop EOTD monitoring after last Serving cell result //==================================================== if (last_scell == TRUE) { l1a_l1s_com.nsync.eotd_meas_session = FALSE; *state = STOP_NSYNC; } else { #endif if ((l1a_l1s_com.nsync.current_list_size != 0) && (neigh_id == l1a_l1s_com.nsync.first_in_list)) { while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; if (l1a_l1s_com.nsync.first_in_list==NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; } } // Step in state machine. *state = SELECT_BEST_NSYNC; #if (L1_EOTD ==1) } #endif } // End L1C_SB_INFO else if(SignalCode == L1C_SBCONF_INFO) // Synchro Burst confirmation attempt result. //------------------------------------------- { UWORD8 neigh_id = ((T_L1C_SBCONF_INFO *)(msg->SigP))->neigh_id; BOOL sb_found = ((T_L1C_SBCONF_INFO *)(msg->SigP))->sb_flag; UWORD16 neigh_radio_freq = ((T_L1C_SBCONF_INFO *)(msg->SigP))->radio_freq; // Check if this neighbor wasn't removed from the list // (it's possible if MPHC_STOP_NCELL_SYNC_REQ message has been received // in the same frame than this L1s message) if (neigh_radio_freq != l1a_l1s_com.nsync.list[neigh_id].radio_freq) { //REM: the message is not sent to L3 return;// Stay in current state. } if (l1a_l1s_com.dedic_set.handover_fail_mode) // The current state is the dedicated mode during an handover fail // The monitoring tasks must be stopped // And the reporting message with a failure indication must be sent back { // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; // Set mode DEDIC ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; } #endif // This process must be reset *state = STOP_NSYNC; break; } if(sb_found == TRUE) // SB detection is a success. { UWORD32 *fn_offset_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->fn_offset); UWORD32 *time_alignmt_ptr = &(((T_L1C_SBCONF_INFO *)(msg->SigP))->time_alignmt); // Correct "fn_offset" and "time_alignmt" to report the true // Serving/Neighbor time difference. // 1) Shift 20 bit since result is from a SB detection. // 2) Add the serving cell timeslot number to the Serving/Neighbor time difference. l1a_add_time_for_nb(time_alignmt_ptr, fn_offset_ptr); l1a_add_timeslot(time_alignmt_ptr, fn_offset_ptr, l1a_l1s_com.dl_tn); #if (L1_EOTD==1) if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { // compute EOTD data l1a_compute_Eotd_data(&first_scell,neigh_id,SignalCode,msg); // Set mode DEDIC ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; #if (L1_EOTD_QBIT_ACC ==1) if (neigh_id != 12) { l1a_compensate_sync_ind((T_MPHC_NCELL_SYNC_IND *)(msg->SigP)); } if( (neigh_id == 12) && (last_scell== TRUE) ) { l1a_l1s_com.nsync.serv_fn_offset = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->fn_offset; l1a_l1s_com.nsync.serv_time_alignmt = ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->time_alignmt; } #endif } #endif // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else // SB detection failed. { #if (L1_EOTD ==1) // Set mode DEDIC if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { ((T_MPHC_NCELL_SYNC_IND *)(msg->SigP))->mode = 1; // Forward the result msg to L3. l1a_send_result(MPHC_NCELL_SYNC_IND, msg, RRM1_QUEUE); } else #endif // Send reporting message with a faillure indication. l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, neigh_id); } // Disable a neigh sync. reading. l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size -= 1; #if (L1_EOTD ==1) // reset first_scell flag first_scell = FALSE; // Stop EOTD monitoring after last Serving cell result //==================================================== if (last_scell == TRUE) { l1a_l1s_com.nsync.eotd_meas_session = FALSE; *state = STOP_NSYNC; } else { #endif if ((l1a_l1s_com.nsync.current_list_size != 0) && (neigh_id == l1a_l1s_com.nsync.first_in_list)) { while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; if(l1a_l1s_com.nsync.first_in_list==NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; } } // Step in state machine. *state = SELECT_BEST_NSYNC; #if (L1_EOTD ==1) } #endif } // End L1C_SBCONF_INFO else if((SignalCode == MPHC_NCELL_FB_SB_READ) || (SignalCode == MPHC_NCELL_SB_READ) || (SignalCode == MPHC_NCELL_SYNC_REQ) || (SignalCode == MPHC_NCELL_LIST_SYNC_REQ)) // New Request to READ the FB/SB or SB from a given carrier. // Request to READ the FB/SB or SB of 1 to 12 carriers. //-------------------------------------------------------- { #if (L1_EOTD ==1) // during EOTD update of list is forbidden..... if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) // Stay in current state. return; else #endif // Step in state machine. *state = NSYNC_CONFIG; } // End new NCELL REQ else if(SignalCode == MPHC_STOP_NCELL_SYNC_REQ) // Request to STOP neighbour cell activity for certain carriers. //-------------------------------------------------------------- { UWORD8 i,j; UWORD8 array_size; array_size = ((T_MPHC_STOP_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq_array_size; #if (L1_EOTD ==1) // Only stop for ALL neighbours in list are accepted. if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) { if ( (array_size != l1a_l1s_com.nsync.current_list_size) && (array_size != NBR_NEIGHBOURS) ) // Stay in current state. return; } // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; #endif // Disable neighbor sync. tasks. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; if(array_size != NBR_NEIGHBOURS) { // Stop some of the Neighb. synchro. for(i=0;i<array_size;i++) { UWORD16 radio_freq = ((T_MPHC_STOP_NCELL_SYNC_REQ *)(msg->SigP))->radio_freq_array[i]; // Search for same value within L1 structure. j=0; while(!((radio_freq == l1a_l1s_com.nsync.list[j].radio_freq) && (l1a_l1s_com.nsync.list[j].status != NSYNC_FREE)) && (j < NBR_NEIGHBOURS)) { j++; } // If found, reset L1 structure for this carrier. if(j<NBR_NEIGHBOURS) { l1a_l1s_com.nsync.list[j].status = NSYNC_FREE; l1a_l1s_com.nsync.current_list_size --; #if 0 /* FreeCalypso: match TCS211 object */ if (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq == radio_freq) l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; #endif } } } else { // Stop all the Neighb. BCCH reading. l1a_l1s_com.nsync.current_list_size = 0; // clear also last location... for(i=0;i<NBR_NEIGHBOURS+1;i++) l1a_l1s_com.nsync.list[i].status = NSYNC_FREE; } // Send confirmation message to L3. l1a_send_confirmation(MPHC_STOP_NCELL_SYNC_CON,RRM1_QUEUE); // All neigh synchro have been removed. if(l1a_l1s_com.nsync.current_list_size == 0) { // Tasks already disabled. // This process must be reset. *state = STOP_NSYNC; } else { // Check if first in list was removed from the list. Go to next first in list while (l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.first_in_list].status == NSYNC_FREE) { l1a_l1s_com.nsync.first_in_list++; if (l1a_l1s_com.nsync.first_in_list==NBR_NEIGHBOURS) l1a_l1s_com.nsync.first_in_list = 0; } // Set semaphores for all neighbor relative task before re-enebling NSYNC task. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Step in state machine. *state = SELECT_BEST_NSYNC; } } // End MPHC_STOP_NCELL_SYNC_REQ else #if (L1_GPRS) // a new synchronisation was performed if ( (SignalCode == L1C_DEDIC_DONE) || ((SignalCode == L1P_TRANSFER_DONE) && (((T_L1P_TRANSFER_DONE *) (msg->SigP))->tn_difference!=0)) || (SignalCode == L1P_ALLOC_EXHAUST_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *) (msg->SigP))->tn_difference!=0) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all==0))) #else //L1_GPRS // test in mode D26: L1C_DEDIC_DONE : // New channel activated. if (SignalCode == L1C_DEDIC_DONE) #endif //L1_GPRS // New channel activated or new synchronisation was performed //----------------------------------------------------------- { UWORD32 time_alignmt; UWORD32 fn_offset; UWORD8 i; if ( (SignalCode == L1C_DEDIC_DONE) && ((l1a.confirm_SignalCode == MPHC_SYNC_HO_CON) || (l1a.confirm_SignalCode == MPHC_PRE_SYNC_HO_CON) || (l1a.confirm_SignalCode == MPHC_ASYNC_HO_CON) || (l1a.confirm_SignalCode == MPHC_HANDOVER_FAIL_CON)) ) { #if 0 /* LoCosto L1 code, doesn't match TCS211 */ l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; // In case of a handover, it is hard to update neighbor timings with timing changes. // Therefore all pending request are restarted as FB acquisition. // If an EOTD session was running, the 300 ms duration constraint of the session can't // be achieved. L1 returns a fail to L3 for the session. #if (L1_EOTD ==1) for(i=NBR_NEIGHBOURS+1;i>0;i--) #else for(i=0;i<NBR_NEIGHBOURS;i++) #endif { if ( (l1a_l1s_com.nsync.list[i-1].status == NSYNC_PENDING)|| (l1a_l1s_com.nsync.list[i-1].status == NSYNC_WAIT) ) { l1a_l1s_com.nsync.list[i-1].timing_validity = 0; l1a_l1s_com.nsync.list[i-1].time_alignmt = 0; l1a_l1s_com.nsync.list[i-1].fn_offset = 0; // force WAIT state l1a_l1s_com.nsync.list[i-1].status = NSYNC_WAIT; #if (L1_EOTD ==1) if ( l1a_l1s_com.nsync.eotd_meas_session == TRUE ) { //If an EOTD session is pending, return a fail for remaining requests l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, i-1); } #endif } // if } // for #if (L1_EOTD ==1) if ( l1a_l1s_com.nsync.eotd_meas_session == TRUE ) { // If the code goes there, an EOTD session is aborting. // return a fail for last serving cell and reset L1A state machine l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, NBR_NEIGHBOURS); l1a_l1s_com.nsync.eotd_meas_session = FALSE; *state = STOP_NSYNC; break; } else #endif { // Step in state machine. *state = SELECT_BEST_NSYNC; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; } // if #else /* code from TSM30 version, matches TCS211 object */ #if (L1_EOTD ==1) // FN and time reference are WRONG for remaining neigbours.... // --> abort all. l1a_l1s_com.nsync.eotd_meas_session = FALSE; #endif // Step in state machine. *state = STOP_NSYNC; break; #endif } // if else { // Channel changes : Restart all neighbors //----------------------------------------- // propagate new dl_tn to all neigbours remaining in EOTD_list !!! // Reset process. and then restart all tasks. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; #if (L1_EOTD ==1) for(i=0;i<NBR_NEIGHBOURS+1;i++) #else for(i=0;i<NBR_NEIGHBOURS;i++) #endif { if ( (l1a_l1s_com.nsync.list[i].status == NSYNC_PENDING)|| (l1a_l1s_com.nsync.list[i].status == NSYNC_WAIT) ) { // reset SB acquisitions : need to restart from FB !!!! #if ((REL99 == 1) && ((FF_BHO == 1) || (FF_RTD == 1))) if (l1a_l1s_com.nsync.list[i].timing_validity == SB_ACQUISITION_PHASE) #else if( l1a_l1s_com.nsync.list[i].timing_validity == 3 ) // SB acquisition #endif { l1a_l1s_com.nsync.list[i].timing_validity = 0; #if ((REL99 == 1) && (FF_BHO == 1)) l1a_l1s_com.nsync.list[i].status = NSYNC_WAIT ; #endif } // FB or SB Confirmations : update timing info if ((l1a_l1s_com.nsync.list[i].timing_validity == 2) || // SB confirmation (l1a_l1s_com.nsync.list[i].timing_validity == 1)) // FB confirmation { // update the SBCNF26 parameters #if (L1_EOTD==1) if ( (i==12) && (l1a_l1s_com.nsync.eotd_meas_session == TRUE)) { // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. #if (L1_EOTD_QBIT_ACC== 1) time_alignmt = l1a_l1s_com.nsync.serv_time_alignmt; fn_offset = l1a_l1s_com.nsync.serv_fn_offset; #else time_alignmt = l1a_l1s_com.nsync.list[i].time_alignmt_mem; fn_offset = l1a_l1s_com.nsync.list[i].fn_offset_mem; #endif l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].fn_offset_mem = 0; l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].time_alignmt_mem= 0; } else #endif { time_alignmt = l1a_l1s_com.nsync.list[i].time_alignmt_mem; fn_offset = l1a_l1s_com.nsync.list[i].fn_offset_mem; } // Sub the serving cell timeslot number to the Neigh./Serving timing // difference to format it for L1S use. l1a_sub_timeslot(&time_alignmt, &fn_offset, l1a_l1s_com.dl_tn); l1a_sub_time_for_nb(&time_alignmt, &fn_offset); l1a_l1s_com.nsync.list[i].time_alignmt = time_alignmt; l1a_l1s_com.nsync.list[i].fn_offset = fn_offset; } // force WAIT state l1a_l1s_com.nsync.list[i].status = NSYNC_WAIT; } } //------------------------------------------------------------ // We restart the FB/SB and SBCONF detection from scratch !!! //------------------------------------------------------------ // Set semaphores for all neighbor relative task before re-enebling NSYNC task. l1a_l1s_com.task_param[NSYNC] = SEMAPHORE_SET; l1a_l1s_com.task_param[FB51] = SEMAPHORE_SET; l1a_l1s_com.task_param[FB26] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB51] = SEMAPHORE_SET; l1a_l1s_com.task_param[SB26] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCNF51] = SEMAPHORE_SET; l1a_l1s_com.task_param[SBCNF26] = SEMAPHORE_SET; // For EOTD : if the 1st serving cell SB is pending // or if last serving cell SB is pending // (when the channel change occured),we must re-start from 1st SB // of serving cell. // // during WAIT_NSYNC_RESULT // ========================= // first_scell eotd_started last_scell // T T F waiting for 1st SB Serving cell // F T F waiting for SBs Neighbor cells // F F T waiting for Last SB Serving cell // F F F no EOTD // #if (L1_EOTD == 1) if ( (first_scell == TRUE) || (last_scell == TRUE)) { // force PENDING state for SERVING CELL l1a_l1s_com.nsync.list[NBR_NEIGHBOURS].status = NSYNC_PENDING; // Step in state machine. *state = WAIT_NSYNC_RESULT; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; // Must be a return there otherwise there is a lockup on // handover/channel changes test condition (need to free // this message...) return; } #endif // Step in state machine. *state = SELECT_BEST_NSYNC; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; } // end Else } // End CHANNEL CHANGE or HANDOVERS else #if (L1_GPRS) // End of packet transfer mode if TBF downlink and uplink have been released if((SignalCode == MPHC_STOP_DEDICATED_REQ) || ((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all))) #else if(SignalCode == MPHC_STOP_DEDICATED_REQ) #endif // Reset messages. //---------------- { #if (L1_EOTD==1) // Stop Eotd session. l1a_l1s_com.nsync.eotd_meas_session = FALSE; #endif // Step in state machine. *state = STOP_NSYNC; } #if ((REL99 == 1) && (FF_BHO == 1)) else if( ((SignalCode == MPHC_SYNC_HO_REQ) || (SignalCode == MPHC_PRE_SYNC_HO_REQ) || (SignalCode == MPHC_PSEUDO_SYNC_HO_REQ) || (SignalCode == MPHC_ASYNC_HO_REQ) ) && (l1a_l1s_com.dedic_set.handover_type == BLIND_HANDOVER) ) { UWORD8 i; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; // In case of a handover, it is hard to update neighbor timings with timing changes. // Therefore all pending request are restarted as FB acquisition. // If an EOTD session was running, the 300 ms duration constraint of the session can't // be achieved. L1 returns a fail to L3 for the session. #if (L1_EOTD ==1) for(i=NBR_NEIGHBOURS+1;i>0;i--) #else for(i=0;i<NBR_NEIGHBOURS;i++) #endif { if ( (l1a_l1s_com.nsync.list[i-1].status == NSYNC_PENDING)|| (l1a_l1s_com.nsync.list[i-1].status == NSYNC_WAIT) ) { l1a_l1s_com.nsync.list[i-1].timing_validity = 0; l1a_l1s_com.nsync.list[i-1].time_alignmt = 0; l1a_l1s_com.nsync.list[i-1].fn_offset = 0; // force WAIT state l1a_l1s_com.nsync.list[i-1].status = NSYNC_WAIT; #if (L1_EOTD ==1) if ( l1a_l1s_com.nsync.eotd_meas_session == TRUE ) { //If an EOTD session is pending, return a fail for remaining requests l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, i-1); } #endif } // if } // for #if (L1_EOTD ==1) if ( l1a_l1s_com.nsync.eotd_meas_session == TRUE ) { // If the code goes there, an EOTD session is aborting. // return a fail for last serving cell and reset L1A state machine l1a_report_failling_ncell_sync(MPHC_NCELL_SYNC_IND, NBR_NEIGHBOURS); l1a_l1s_com.nsync.eotd_meas_session = FALSE; *state = STOP_NSYNC; break; } else #endif { // Step in state machine. *state = SELECT_BEST_NSYNC; // Enable neighbour sync task. l1a_l1s_com.l1s_en_task[NSYNC] = TASK_ENABLED; } // if } #endif // #if ((REL99 == 1) && (FF_BHO == 1)) // No action in this machine for other messages. else { // End of process. return; } } break; case STOP_NSYNC: { UWORD8 i; // Reset process. // WARNING : NSYNC task and nsync_list are COMMON to dedic and Idle.... l1a_l1s_com.l1s_en_task[FB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[FB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SB26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF26] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[SBCNF51] = TASK_DISABLED; l1a_l1s_com.l1s_en_task[NSYNC] = TASK_DISABLED; // Disable all neigh sync. reading. l1a_l1s_com.nsync.current_list_size = 0; #if (L1_EOTD==1) // reset EOTD flags first_scell =FALSE; last_scell =FALSE; eotd_started =FALSE; l1a_l1s_com.nsync.eotd_toa_phase = 0; l1a_l1s_com.nsync.eotd_meas_session = FALSE; l1a_l1s_com.nsync.eotd_cache_toa_tracking = 0; l1a_l1s_com.nsync.eotd_toa_tracking = 0; for (i=0; i<NBR_NEIGHBOURS+1; i++) l1a_l1s_com.nsync.list[i].status = NSYNC_FREE; #else for (i=0; i<NBR_NEIGHBOURS; i++) l1a_l1s_com.nsync.list[i].status = NSYNC_FREE; #endif // Step in state machine. *state = WAIT_INIT; // End of process end_process = 1; } break; } // end of "switch". } // end of "while" } // end of procedure. #endif /*-------------------------------------------------------*/ /* l1a_dedic_ba_list_meas_process() */ /*-------------------------------------------------------*/ /* Description : This state machine handles neigbor cell */ /* measurement process in DEDICATED mode with BA list. */ /* */ /* Starting messages: L1C_DEDIC_DONE */ /* ------------------ */ /* L1 starts then the periodic BA list receive level */ /* monitoring. */ /* */ /* Subsequent messages: MPHC_UPDATE_BA_LIST */ /* -------------------- */ /* L1 changes the BA list and starts the periodic BA */ /* list receive level monitoring with this new list. */ /* */ /* Result messages (input): L1C_MEAS_DONE */ /* ------------------------ */ /* This is the periodic reporting message from L1s. */ /* */ /* Result messages (output): MPHC_MEAS_REPORT */ /* ------------------------- */ /* This is the periodic reporting message to L3. */ /* */ /* Reset messages (input): MPHC_STOP_DEDICATED_REQ */ /* ----------------------- */ /* BA list neigbor cell measurement process in DEDICATED*/ /* is stopped by this message. */ /* */ /*-------------------------------------------------------*/ void l1a_dedic_ba_list_meas_process(xSignalHeaderRec *msg) { enum states { RESET = 0, WAIT_INIT = 1, WAIT_RESULT = 3 }; UWORD8 *state = &l1a.state[D_NMEAS]; UWORD32 SignalCode = msg->SignalCode; static BOOL meas_valid; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // step in state machine. *state = WAIT_INIT; // Reset D_NMEAS process. l1a_l1s_com.l1s_en_meas &= D_BAMS_MEAS_MASK; // Reset D_BAMS Measurement enable flag. } break; case WAIT_INIT: { #if 0 /* FreeCalypso: match TCS211 object */ #if (OP_SAP == 0) if (SignalCode == MPHC_UPDATE_BA_LIST) #else if (SignalCode == MPHC_UPDATE_BA_LIST_REQ) #endif /* if (OP_SAP == 0) */ // One reporting period has been completed. //----------------------------------------- { UWORD16 i; // Set parameter synchro semaphore for D_BAMS task. l1a_l1s_com.meas_param |= D_BAMS_MEAS; // Reset the BA list structure. l1a_reset_ba_list(); // Next measurement report must indicate INVALID. meas_valid = FALSE; // Enable Dedicated mode BA list measurement task. l1a.l1a_en_meas[D_NMEAS] |= D_BAMS_MEAS; // Reset present flag to avoid to mix 2 updates in case of // an update already pending within "l1a_l1s_com.ba_list.new_list". // This case can occur after a Handover and both previous and new // serving cells are requesting an update. l1a_l1s_com.ba_list.new_list_present = FALSE; // Download new list within L1A_L1S_COM structure. #if (OP_SAP == 0) l1a_l1s_com.ba_list.new_list = *((T_MPHC_UPDATE_BA_LIST *)(msg->SigP)); #else l1a_l1s_com.ba_list.new_list = *((T_MPHC_UPDATE_BA_LIST_REQ *)(msg->SigP)); #endif /* if (OP_SAP == 0) */ // Download new list. for(i=0;i<l1a_l1s_com.ba_list.new_list.num_of_chans;i++) { #if (OP_SAP == 0) l1a_l1s_com.ba_list.A[i].radio_freq = l1a_l1s_com.ba_list.new_list.chan_list.A[i]; #else l1a_l1s_com.ba_list.A[i].radio_freq = l1a_l1s_com.ba_list.new_list.chan_list.BA[i]; #endif /* if (OP_SAP == 0) */ } l1a_l1s_com.ba_list.ba_id = l1a_l1s_com.ba_list.new_list.ba_id; l1a_l1s_com.ba_list.nbr_carrier = l1a_l1s_com.ba_list.new_list.num_of_chans; // Set present flag only when the list has been downloaded. l1a_l1s_com.ba_list.new_list_present = TRUE; // step in state machine. *state = WAIT_RESULT; } else #endif /* FreeCalypso TCS211 reconstruction */ if(SignalCode == L1C_DEDIC_DONE) // We enter DEDICATED mode. //------------------------- { #if 0 /* FreeCalypso: match TCS211 object */ #if (CODE_VERSION == NOT_SIMULATION) if (l1a_l1s_com.ba_list.nbr_carrier == 0) return; #endif #endif // Set parameter synchro semaphore for D_BAMS task. l1a_l1s_com.meas_param |= D_BAMS_MEAS; // Reset the BA list structure. l1a_reset_ba_list(); // Next measurement report must indicate INVALID. meas_valid = FALSE; // Enable Dedicated mode BA list measurement task. l1a.l1a_en_meas[D_NMEAS] |= D_BAMS_MEAS; // step in state machine. *state = WAIT_RESULT; } // End of process. end_process = 1; } break; case WAIT_RESULT: { if(SignalCode == L1C_MEAS_DONE) // One reporting period has been completed. //----------------------------------------- { // Fill "meas_valid" parameter. ((T_MPHC_MEAS_REPORT*)(msg->SigP))->meas_valid = meas_valid; // Forward result message to L3. l1a_send_result(MPHC_MEAS_REPORT, msg, RRM1_QUEUE); // Next measurement report must indicate VALID. meas_valid = TRUE; // End of process. return; } if(SignalCode == MPHC_UPDATE_BA_LIST) // One reporting period has been completed. //----------------------------------------- { // Reset present flag to avoid to mix 2 updates in case of // an update already pending within "l1a_l1s_com.ba_list.new_list". // This case can occur after a Handover and both previous and new // serving cells are requesting an update. l1a_l1s_com.ba_list.new_list_present = FALSE; // Download new list within L1A_L1S_COM structure. l1a_l1s_com.ba_list.new_list = *((T_MPHC_UPDATE_BA_LIST *)(msg->SigP)); // Set present flag only when the list has been downloaded. l1a_l1s_com.ba_list.new_list_present = TRUE; // End of process. return; } else #if ((REL99 == 1) && (FF_BHO == 1)) if ((SignalCode == MPHC_STOP_DEDICATED_REQ) || (((SignalCode == MPHC_SYNC_HO_REQ) || (SignalCode == MPHC_PRE_SYNC_HO_REQ) || (SignalCode == MPHC_PSEUDO_SYNC_HO_REQ) || (SignalCode == MPHC_ASYNC_HO_REQ) ) && (l1a_l1s_com.dedic_set.handover_type == BLIND_HANDOVER) ) ) #else if(SignalCode == MPHC_STOP_DEDICATED_REQ) #endif // #if ((REL99 == 1) && (FF_BHO == 1)) // We exit DEDICATED mode. { // Stop D_BAMS_MEAS task. l1a_l1s_com.l1s_en_meas &= D_BAMS_MEAS_MASK; // When leaving dedicated mode we must clear the NEW BA // present flag to keep L1 and L1 in step and to avoid // taking it into account on the next Dedicated mode // session. // Check inf any NEW BA available, if so download it... if(l1a_l1s_com.ba_list.new_list_present == TRUE) { UWORD16 i; // Download new list. for(i=0;i<l1a_l1s_com.ba_list.new_list.num_of_chans;i++) { l1a_l1s_com.ba_list.A[i].radio_freq = l1a_l1s_com.ba_list.new_list.chan_list.A[i]; } l1a_l1s_com.ba_list.ba_id = l1a_l1s_com.ba_list.new_list.ba_id; l1a_l1s_com.ba_list.nbr_carrier = l1a_l1s_com.ba_list.new_list.num_of_chans; l1a_l1s_com.ba_list.new_list_present = 0; } // Step in state machine. *state = RESET; } else if(SignalCode == L1C_DEDIC_DONE) // Reset messages. //---------------- { // Step in state machine. *state = RESET; } else // No action in this machine for other messages. //---------------------------------------------- { end_process = 1; } } break; } // end of "switch". } // end of "while" } // end of procedure. /*-------------------------------------------------------*/ /* l1a_freq_band_configuration () */ /*-------------------------------------------------------*/ /* Description : This state machine handles the frequency*/ /*band configuration: E_GSM900, GSM900, DCS1800, PCS1900,*/ /*DUAL, DUALEXT, DUALEXT_PCS1900... */ /* */ /* Starting messages: MPHC_INIT_L1_REQ */ /* */ /* Result messages (input): none */ /* Result messages (output): MPHC_INIT_L1_CON */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ void l1a_freq_band_configuration(xSignalHeaderRec *msg) { UWORD32 SignalCode = msg->SignalCode; UWORD8 *state = &l1a.state[INIT_L1]; enum states { RESET = 0, WAIT_INIT = 1 }; BOOL end_process = 0; while(!end_process) { switch(*state) { case RESET: { // Step in state machine. *state = WAIT_INIT; } break; case WAIT_INIT: { if (SignalCode == MPHC_INIT_L1_REQ) // Request from L3 which defined the standard, GSM, E-GSM, DCS1800, DUALEXT... //------------------------------------------------------------------------------- { #if (L1_FF_MULTIBAND == 0) l1_config.std.id = ((T_MPHC_INIT_L1_REQ *)(msg->SigP))->radio_band_config; #else UWORD8 physical_band_id; static UWORD8 rf_band_id_to_l23_band_id[]={PGSM900, GSM850, DCS1800, PCS1900}; #endif Cust_init_std(); l1_tpu_init_light(); #if (L1_FF_MULTIBAND == 0) #if (TRACE_TYPE == 5) trace_sim_freq_band_configuration(l1_config.std.id); #endif #endif /*if (L1_FF_MULTIBAND == 0)*/ // Forward result message to L3. #if (L1_FF_MULTIBAND == 0) l1a_send_confirmation(MPHC_INIT_L1_CON,RRM1_QUEUE); #else // L1_FF_MULTIBAND 1 below msg = os_alloc_sig(sizeof(T_MPHC_INIT_L1_CON)); DEBUGMSG(status, NU_ALLOC_ERR) msg->SignalCode = MPHC_INIT_L1_CON; for (physical_band_id = 0; physical_band_id < RF_NB_SUPPORTED_BANDS; physical_band_id ++) { ((T_MPHC_INIT_L1_CON *)(msg->SigP))->multiband_power_class[physical_band_id].radio_band = rf_band_id_to_l23_band_id[multiband_rf[physical_band_id].gsm_band_identifier]; ((T_MPHC_INIT_L1_CON *)(msg->SigP))->multiband_power_class[physical_band_id].power_class = multiband_rf[physical_band_id].power_class; l1a_l1s_com.powerclass[physical_band_id]=multiband_rf[physical_band_id].power_class; } for (physical_band_id=RF_NB_SUPPORTED_BANDS; physical_band_id<NB_MAX_GSM_BANDS; physical_band_id++) { ((T_MPHC_INIT_L1_CON *)(msg->SigP))->multiband_power_class[physical_band_id].radio_band = 0xFF; } os_send_sig(msg, RRM1_QUEUE); #endif // #if (L1_FF_MULTIBAND == 0) else // This process must be reset. *state = RESET; return; } else // No action in this machine for other messages. //---------------------------------------------- { end_process = 1; } break; } } // End of switch } // End of while } /*-------------------------------------------------------*/ /* l1a_checkmsg_compatibility () */ /*-------------------------------------------------------*/ /* Description : This checks the message compatibility, If the */ /*received message is not compatible with current scenario, */ /*delay the message or ignore the message.*/ /* */ /* */ /* Result messages (input): xSignalHeaderRec *msg */ /* Result messages (output): none */ /* Reset messages (input): none */ /* */ /*-------------------------------------------------------*/ #if(L1_CHECK_COMPATIBLE == 1) void l1a_checkmsg_compatibility (xSignalHeaderRec *msg) { UWORD32 SignalCode = msg->SignalCode; /* stop_req is set to True, if ringer stop message is received from MMI */ if((SignalCode == MMI_AAC_STOP_REQ) || (SignalCode == MMI_MP3_STOP_REQ)) { l1a.stop_req = TRUE; } /* This disables vocoder if vocoder is enabled and set vcr_wait to TRUE */ /* to trigger VCH_R msg when AAC/MP3 is stopped completely. */ /* This is the case of inband tone where first VCH_R is recvieved and */ /* then ringer is started */ if((SignalCode == MMI_AAC_START_REQ) || (SignalCode == MMI_MP3_START_REQ)) { if (l1a.vocoder_state.enabled == TRUE) { l1a.vcr_wait = TRUE; l1a.vch_auto_disable = TRUE; } } /* This is to trigger VCH_R message if message is delayed earliar */ /* and ringer is stopped completely */ if ((l1a.stop_req == TRUE) && (l1a.vcr_wait==TRUE)) { if ((SignalCode == L1_MP3_DISABLE_CON) || (SignalCode == L1_AAC_DISABLE_CON)) { xSignalHeaderRec *msg_vcr; msg_vcr = os_alloc_sig(sizeof(T_MMI_TCH_VOCODER_CFG_REQ)); DEBUGMSG(status,NU_ALLOC_ERR) msg_vcr->SignalCode = MMI_TCH_VOCODER_CFG_REQ; ((T_MMI_TCH_VOCODER_CFG_REQ *) (msg_vcr->SigP))->vocoder_state = l1a.vcr_msg_param; os_send_sig(msg_vcr,L1C1_QUEUE); DEBUGMSG(status,NU_SEND_QUEUE_ERR) l1a.vcr_wait = FALSE; l1a.stop_req = FALSE; { char str[25]; sprintf(str,"TRIGGER VCH"); rvt_send_trace_cpy((T_RVT_BUFFER)str,trace_info.l1_trace_user_id,strlen(str),RVT_ASCII_FORMAT); } } } /* vcr_wait is set to TRUE to delay the VCH_R if MP3/AAC is not stopped completey*/ if(SignalCode == MMI_TCH_VOCODER_CFG_REQ) { l1a.vcr_msg_param = ((T_MMI_TCH_VOCODER_CFG_REQ *) (msg->SigP))->vocoder_state; // MP3 ON or AAC ON if ((!((l1a.state[L1A_MP3_STATE] == 0) || (l1a.state[L1A_MP3_STATE] == 1))) || (!((l1a.state[L1A_AAC_STATE] == 0) || (l1a.state[L1A_AAC_STATE] == 1)))) { l1a.vcr_wait = TRUE; msg->SignalCode = NULL; { char str[25]; sprintf(str,"VCH DELAY"); rvt_send_trace_cpy((T_RVT_BUFFER)str,trace_info.l1_trace_user_id,strlen(str),RVT_ASCII_FORMAT); } } } } #endif