# HG changeset patch # User Mychaela Falconia # Date 1446004792 0 # Node ID cb63ce91342a306afc2351a6fd62a7a4c9b1fca8 # Parent bd7effdeba687c7a798b6b430aaaf37c1049bcc6 l1_cmplx.c: imported LoCosto version with necessary FC fixes diff -r bd7effdeba68 -r cb63ce91342a chipsetsw/layer1/cfile/l1_cmplx.c --- a/chipsetsw/layer1/cfile/l1_cmplx.c Wed Oct 28 03:13:17 2015 +0000 +++ b/chipsetsw/layer1/cfile/l1_cmplx.c Wed Oct 28 03:59:52 2015 +0000 @@ -1,1 +1,11970 @@ -/* dummy C source file */ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1_CMPLX.C + * + * Filename l1_cmplx.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1_CMPLX_C + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +#include "l1_macro.h" +#include "l1_confg.h" + +#if (CODE_VERSION == SIMULATION) + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + #include "l1_signa.h" + #include + + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_signa.h" + #include "l1audio_defty.h" + #include "l1audio_msgty.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_defty.h" + #endif +//ADDED FOR AAC + #if (L1_AAC == 1) + #include "l1aac_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_proto.h" + #include "l1_mftab.h" + #include "l1_tabs.h" + #include "l1_ver.h" + #if L2_L3_SIMUL + #include "l2_l3.h" + #include "hw_debug.h" + #endif + + #if L1_GPRS + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" + #endif + + #include "sim_cons.h" + #include "sim_def.h" + extern T_hw FAR hw; + +#else + #include "abb.h" + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + #include "l1_signa.h" + #if TESTMODE + #include "l1tm_defty.h" + #if (RF_FAM == 60) + #include "pld.h" + #endif + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_signa.h" + #include "l1audio_defty.h" + #include "l1audio_msgty.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_defty.h" + #endif +//ADDED FOR AAC + #if (L1_AAC == 1) + #include "l1aac_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_proto.h" + #include "l1_mftab.h" + #include "l1_tabs.h" + #include "l1_ver.h" + #include "l1_trace.h" + #include "l1_ctl.h" + #if L2_L3_SIMUL + #include "l2_l3.h" + #include "hw_debug.h" + #include "l2_simul.h" + #endif + + #if L1_GPRS + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" + #endif +#endif + +#if(RF_FAM == 61) + #include "l1_rf61.h" + #include "tpudrv61.h" +#endif +#include "l1_ctl.h" + +#if W_A_DSP1 +extern UWORD8 old_sacch_DSP_bug; +#endif + +#if TESTMODE + #include "l1tm_msgty.h" + #include "l1tm_signa.h" + #include "l1tm_varex.h" + void l1tm_fill_burst (UWORD16 pattern, UWORD16 *TM_ul_data); + #if (ANLG_FAM != 11) + void ABB_Write_Uplink_Data(SYS_UWORD16 *TM_ul_data); + #else + // TODO + #endif +#endif + +#if ((TRACE_TYPE==2) || (TRACE_TYPE==3)) + extern void L1_trace_string(char *s); + extern void L1_trace_char (char s); +#endif + +#if (GSM_IDLE_RAM != 0) +#if (OP_L1_STANDALONE == 1) +#include "csmi_simul.h" +#else +#include "csmi/sleep.h" +#endif +#endif + +#if (RF_FAM == 61) + #include "l1_rf61.h" +#if (DRP_FW_EXT==1) + #include "l1_drp_inc.h" +#else + #include "drp_drive.h" +#endif +#endif + +/*-------------------------------------------------------*/ +/* Prototypes of external functions used in this file. */ +/*-------------------------------------------------------*/ +void l1dmacro_synchro (UWORD32 when, UWORD32 value); + +void l1dmacro_offset (UWORD32 offset_value, WORD32 relative_time); +void l1dmacro_rx_synth (UWORD16 arfcn); +void l1dmacro_agc (UWORD16 arfcn,WORD8 gain, UWORD8 lna + #if (RF_FAM == 61) + ,UWORD8 if_ctl + #endif + ); +void l1dmacro_rx_nb (UWORD16 arfcn); +void l1dmacro_afc (UWORD16 afc_value, UWORD8 win_id); +void l1dmacro_adc_read_rx (void); +#if (CODE_VERSION != SIMULATION) +#if (L1_MADC_ON ==1) +void l1dmacro_adc_read_rx_cs_mode0(void); +#endif +#endif + +#if (RF_FAM != 61) +void l1dtpu_serv_rx_nb (UWORD16 radio_freq, WORD8 agc, UWORD8 lna_off, + UWORD32 synchro_serv,UWORD32 new_offset,BOOL change_offset, UWORD8 adc_active); +#endif + +#if (RF_FAM == 61) +void l1dtpu_serv_rx_nb (UWORD16 radio_freq, WORD8 agc, UWORD8 lna_off, + UWORD32 synchro_serv,UWORD32 new_offset,BOOL change_offset, + UWORD8 adc_active, UWORD8 csf_filter_choice, UWORD8 if_ctl +#if (NEW_SNR_THRESHOLD == 1) + ,UWORD8 saic_flag +#endif /* NEW_SNR_THRESHOLD*/ + ); +#endif /* RF_FAM == 61*/ + +void l1ddsp_meas_read (UWORD8 nbmeas, UWORD16 *pm); + +#if L1_GPRS +void l1pddsp_synchro (UWORD8 switch_mode, UWORD8 camp_timeslot); +void l1pddsp_load_bcchn_task (UWORD8 tsq,UWORD16 radio_freq); +void l1pddsp_meas_ctrl (UWORD8 nbmeas, UWORD8 pm_pos); +void l1pddsp_meas_read (UWORD8 nbmeas, UWORD16 *a_pm); +#if FF_L1_IT_DSP_USF +void l1pddsp_idle_rx_nb (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq, + UWORD8 timeslot_no, BOOL ptcch_dl, BOOL usf_interrupt); +#else +void l1pddsp_idle_rx_nb (UWORD8 burst_nb, UWORD8 tsq, UWORD16 radio_freq, + UWORD8 timeslot_no, BOOL ptcch_dl); +#endif +#endif + +#if (RF_FAM == 61) +void cust_get_if_dco_ctl_algo (UWORD16* dco_algo_ctl, UWORD8* if_ctl, + UWORD8 input_level_flag, UWORD8 input_level, UWORD16 radio_freq, UWORD8 if_threshold); +#endif + + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END + +extern UWORD16 toa_tab[4]; + + +#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 + UWORD16 toa_tab[4]; +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + + +#if TESTMODE + UWORD16 TM_ul_data[16]; //Uplink data to be stored into Omega Uplink buffer +#endif +#if ((REL99 == 1) && (FF_BHO == 1)) + void l1dtpu_neig_fbsb(UWORD16 radio_freq, WORD8 agc, UWORD8 lna_off); // Blind handover +#endif + +/*-------------------------------------------------------*/ +/* l1s_ctrl_hwtest() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task HWTEST. This function check the checksum of the */ +/* DSP. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_TEST bit in the register. */ +/*-------------------------------------------------------*/ +void l1s_ctrl_hwtest(UWORD8 task, UWORD8 param2) +{ + // Flag DSP programmation. + // ************************ + l1ddsp_load_monit_task(DSP_TASK_CODE[task],0); + + // Set "CTRL_TEST" flag in the controle flag register. + l1s.dsp_ctrl_reg |= CTRL_TEST; +} + +/*-------------------------------------------------------*/ +/* l1s_read_hwtest() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task HWTEST. This function read the checksum of the */ +/* DSP. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* -> disable HWTEST task. */ +/* */ +/* "l1s.task_status[HWTEST].current_status" */ +/* current task status for HWTEST task. */ +/* -> disactivate HWTEST task. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_hwtest(UWORD8 task, UWORD8 param2) +{ + #if (TRACE_TYPE==2) || (TRACE_TYPE==3)//OMAPS00090550 + UWORD32 flash_type = 0; + #endif + xSignalHeaderRec *msg; + + #if (CODE_VERSION != SIMULATION) + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39) + l1s.version.dsp_code_version = l1s_dsp_com.dsp_ndb_ptr->d_version_number1; + l1s.version.dsp_checksum = (UWORD16) (l1s_dsp_com.dsp_db_r_ptr->a_pm[1] & 0xffff); + l1s.version.dsp_patch_version = l1s_dsp_com.dsp_ndb_ptr->d_version_number2; + #else + l1s.version.dsp_code_version = (UWORD16) (l1s_dsp_com.dsp_db_r_ptr->a_pm[0] & 0xffff); + l1s.version.dsp_checksum = (UWORD16) (l1s_dsp_com.dsp_db_r_ptr->a_pm[1] & 0xffff); + //l1s.version.dsp_patch_version = (UWORD16) (l1s_dsp_com.dsp_db_r_ptr->a_pm[2] & 0xffff); + l1s.version.dsp_patch_version = (UWORD32) *((API *) SC_CHKSUM_VER); + //NOTE: dsp_patch_version is duplicated in d_version_number + #endif + #endif // NOT_SIMULATION + + // send L1_INIT_HW_CON to L1A... + msg = os_alloc_sig(sizeof(T_TST_TEST_HW_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = L1_TEST_HW_INFO; + + // added for the new naming convention + ((T_TST_TEST_HW_CON*)(msg->SigP))->dsp_code_version = l1s.version.dsp_code_version; + ((T_TST_TEST_HW_CON*)(msg->SigP))->dsp_checksum = l1s.version.dsp_checksum; + ((T_TST_TEST_HW_CON*)(msg->SigP))->dsp_patch_version = l1s.version.dsp_patch_version; + ((T_TST_TEST_HW_CON*)(msg->SigP))->mcu_tcs_program_release = l1s.version.mcu_tcs_program_release; + ((T_TST_TEST_HW_CON*)(msg->SigP))->mcu_tcs_official = l1s.version.mcu_tcs_official; + ((T_TST_TEST_HW_CON*)(msg->SigP))->mcu_tcs_internal = l1s.version.mcu_tcs_internal; + + os_send_sig(msg, L1C1_QUEUE); + + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + #if (TRACE_TYPE==2) || (TRACE_TYPE==3) + uart_trace_checksum(flash_type); + #endif + + // HWTEST task is completed, make it INACTIVE. + // It is a 1 shot task, it must be also disabled in L1S. + l1s.task_status[task].current_status = INACTIVE; + l1a_l1s_com.l1s_en_task[HWTEST] = TASK_DISABLED; + + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch" only. + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +/*-------------------------------------------------------*/ +/* l1s_new_synchro() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task SYNCHRO. This function mainly adapts the L1/TPU */ +/* timebase to a new setting. This new setting can come */ +/* from a timeslot change or a full change of serving */ +/* cell. This change is a big discontinuity, it requires */ +/* some global variable reset. Here is a summary of the */ +/* execution: */ +/* */ +/* - Traces for debug. */ +/* - Disables the L1S task SYNCHRO (SYNCHRO is 1 shot) */ +/* and make it inactive (current status set to */ +/* INACTIVE). */ +/* - Compute timeshift. */ +/* - Program serving cell fine timeshift for TPU. */ +/* - Execute serving cell frame number timeshift. */ +/* - Flag TPU programmation. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1a_l1s_com.tn_difference" */ +/* timeslot difference between new and old setting. */ +/* This is used when timeshift is due to a change of */ +/* timeslot but on the same serving cell. */ +/* -> reset to 0. */ +/* */ +/* "l1a_l1s_com.Scell_inf.time_alignmt" */ +/* fine time difference between current setting and */ +/* new setting to achieve. */ +/* -> reset to 0. */ +/* */ +/* "l1a_l1s_com.Scell_inf.fn_offset" */ +/* frame number offset between current setting and new */ +/* setting to achieve. */ +/* -> reset to 0. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for SYNCHRO and OFFSET register in the TPU */ +/* for current serving cell setting. */ +/* -> set to the new setting. */ +/* */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* -> disable SYNCHRO task. */ +/* */ +/* "l1s.task_status[SYNCHRO].current_status" */ +/* current task status for SYNCHRO task. */ +/* -> disactivate SYNCHRO task. */ +/* */ +/* "l1s.actual_time, l1s.next_time" */ +/* frame number and derived numbers for current frame */ +/* and next frame. */ +/* -> update to new setting. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_SYNC bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_new_synchro(UWORD8 param1, UWORD8 param2) +{ + WORD32 offset; + UWORD32 tpu_offset_shift; + T_CELL_INFO *sptr = &(l1a_l1s_com.Scell_info); + + // Traces for debug mainly used during L1 simulation. + // *************************************************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_NEW_SYNCHRO, l1a_l1s_com.Scell_info.radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_tpu(dltsk_trace[SYNCHRO].name); + #endif + + // Disable SYNCHRO task. + // ********************** + + // SYNCHRO task is a one shot task enabled by L1A and + // disables after its execution in L1S. Here is the disabling. + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_DISABLED; + l1s.task_status[SYNCHRO].current_status = INACTIVE; + + #if L1_GPRS + //Change of mode when synchro is executed when switching from idle to transfer + //In this case, PDTCH task has been enabled in transfer mode manager, but the mode is still not PACKET_TRANSFER_MODE + if((l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) && (l1a_l1s_com.mode != PACKET_TRANSFER_MODE)) + l1a_l1s_com.mode = PACKET_TRANSFER_MODE; + #endif + + // Compute timeshift. + // ******************* + + if(l1a_l1s_com.tn_difference < 0) + // "tn_difference" field is not 0 only when the new serving cell is the same + // as the old one. Therefore, we are just changing the timeslot. + // If the new timeslot if lower than the old one then the serving FN must + // be incremented by 1. To do so, we use the "fn_offset" field which is + // loaded with "1". + { + sptr->fn_offset += 1; + l1a_l1s_com.tn_difference += 8; + } + + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // Manage shifting value for TPU offset register... + // if staying on the same serving cell but changing the RX timeslot (CCCH_GROUP or timeslot), + // then the "timeslot difference" between old and new configuration is given in "tn_difference", + // else "tn_difference" must contain 0. + tpu_offset_shift = (sptr->time_alignmt) + (l1a_l1s_com.tn_difference * BP_DURATION); + + // Clear "timeslot difference" parameter. + l1a_l1s_com.tn_difference = 0; + + // Get FN difference between actual synchro and the one we are going to switch to. + // The switch (slide of OFFSET and REG_COM_INT) is performed at the time "OFFSET - epsilon". + // If "tpu_offset_shift" is greater than "OFFSET - epsilon (called SWITCH_TIME)" then + // the next interrupt is going to occur very soon after the switch, and new FN comes directly + // from current FN + the "fn_offset" (minus 1 since FN has just been incremented). Else 1 frame + // is missed and new FN comes from "fn_offset + 1" (minus 1 since FN has just been incremented). + offset = sptr->fn_offset - 1; + if(tpu_offset_shift <= SWITCH_TIME) offset++; + #if L1_FF_WA_OMAPS00099442 + if(l1a_l1s_com.change_tpu_offset_flag == TRUE){ + l1s.tpu_offset = (l1s.tpu_offset + (TPU_CLOCK_RANGE >> 1) ) % TPU_CLOCK_RANGE; + l1a_l1s_com.change_tpu_offset_flag = FALSE; + } + #endif + + // Shift "tpu_offset" accordingly to the computed "tpu_offset_shift" value. + // Rem: "%" is required since the result value can be greater than 2*TPU_CLOCK_RANGE. + l1s.tpu_offset = (l1s.tpu_offset + tpu_offset_shift) % TPU_CLOCK_RANGE; + + // Program serving cell fine timeshift for TPU. + // ********************************************* + + // Store the fine time shifting program in the MCU/TPU com. + l1dmacro_synchro(SWITCH_TIME, l1s.tpu_offset); + + // Execute serving cell frame number timeshift. + // ********************************************* + + // Slide frame numbers and derived numbers to jump on new setting. + l1s_increment_time(&(l1s.actual_time), offset); // Update actual_time. + + l1s.next_time = l1s.actual_time; + l1s_increment_time(&(l1s.next_time), 1); // Next time is actual_time + 1 + + #if L1_GPRS + l1s.next_plus_time = l1s.next_time; + l1s_increment_time(&(l1s.next_plus_time), 1); // Next_plus time is next_time + 1 + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + trace_fct(CST_L1S_ADJUST_TIME, (UWORD32)(-1));//OMAPS00090550 + #endif + + #if (TOA_ALGO == 2) + // Fix in case of handovers and Test Mode + l1s.toa_var.toa_update_fn = l1s.toa_var.toa_update_fn + offset; + if(l1s.toa_var.toa_update_fn >= MAX_FN) + { + l1s.toa_var.toa_update_fn-= MAX_FN; + } + #endif + + + + // the FN was changed: it could have an impact on the gauging algorithm + //Nina modify to save power, not forbid deep sleep, only force gauging in next paging +if(l1s.force_gauging_next_paging_due_to_CCHR != 1) +{ +l1s.pw_mgr.enough_gaug = FALSE; // forbid Deep sleep until next gauging +} + + + // Clear Serving offset and bob. + sptr->fn_offset = 0; + sptr->time_alignmt = 0; + + // Flag TPU programmation. + // ************************ + + // Set "CTRL_SYNC" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_SYNC; + + #if (CODE_VERSION == SIMULATION) + si_scheduling(MPHC_SCELL_NBCCH_REQ, NULL, TRUE); + si_scheduling(MPHC_SCELL_EBCCH_REQ, NULL, TRUE); + #endif + + #if TESTMODE + // Continuous mode: if we are in continuous mode: return to the no continuous mode. + if ((l1_config.TestMode) && (l1_config.tmode.rf_params.tmode_continuous == TM_CONTINUOUS)) + l1_config.tmode.rf_params.tmode_continuous = TM_NO_CONTINUOUS; + #endif + + #if L1_GPRS + // Signals the GSM->GPRS or GPRS->GSM switch to the DSP. + // ****************************************************** + l1pddsp_synchro(l1a_l1s_com.dsp_scheduler_mode, l1a_l1s_com.dl_tn); + + // Flag DSP programmation. + // Set "CTRL_SYNC" flag in the controle flag register. + l1s.dsp_ctrl_reg |= CTRL_SYNC; + #endif + + #if (CODE_VERSION == SIMULATION) + si_scheduling(MPHC_SCELL_NBCCH_REQ, NULL, TRUE); + si_scheduling(MPHC_SCELL_EBCCH_REQ, NULL, TRUE); + #endif +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_ADC() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task ADC. This function program the L1/TPU in order */ +/* to perform an ADC measurement in CS_MODE0 */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_ADC(UWORD8 param1, UWORD8 param2) +{ + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_ADC, (UWORD32)(-1));//OMAPS00090550 + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + // In CS_MODE0, MPHC_RXLEV_REQ is not received periodically. In case network is not found, + //the period between 2 MPHC_RXLEV_REQ increases and can be as high as 360 seconds (Max Value) + // To enable MADC periodically, the function l1dmacro_adc_read_rx_cs_mode0; is called + #if (CODE_VERSION != SIMULATION) + #if (L1_MADC_ON ==1) + if (l1a_l1s_com.mode == CS_MODE0) + l1dmacro_adc_read_rx_cs_mode0(); + else + l1dmacro_adc_read_rx(); // ADC performed into a rx scenario to have BULON and BULENA signals off so maintaining + // low power consumption on ABB + #else + l1dmacro_adc_read_rx(); // ADC performed into a rx scenario to have BULON and BULENA signals off so maintaining + // low power consumption on ABB + #endif // End of L1_MADC_ON == 1 + #else + l1dmacro_adc_read_rx(); // ADC performed into a rx scenario to have BULON and BULENA signals off so maintaining + // low power consumption on ABB + #endif + + + l1s.task_status[ADC_CSMODE0].current_status = INACTIVE; + + if (l1a_l1s_com.adc_mode & ADC_NEXT_CS_MODE0) // performe ADC only one time + { + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_IDLE; // reset in order to have only one ADC measurement in CS_MODE0 + l1a_l1s_com.l1s_en_task[ADC_CSMODE0] = TASK_DISABLED; // disable the ADC task in case of one shot + } + + // Set "CTRL_MS" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_ADC; +} + +#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 + +/*-------------------------------------------------------*/ +/* l1s_abort() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task ABORT. When the L1S merge manager routine, */ +/* "l1s_merge_manager()", finds a conflict between a */ +/* running task and a pending task, it can come to */ +/* aborting the running one to start executing the */ +/* pending. Here is the routine which resets the comm. */ +/* between the MCU and the DSP and TPU. The DSP is also */ +/* signaled to abort any ongoing task. Here is a summary */ +/* of the execution: */ +/* */ +/* - Traces for debug. */ +/* - Reset MCU/DSP and MCU/TPU communications. */ +/* - Signals the ABORT process to the DSP. */ +/* - Flag DSP programmation. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1s.tpu_offset" */ +/* OFFSET/SYNCHRO registers value for current serving */ +/* cell setting. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_ABORT bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_abort(UWORD8 param1, UWORD8 param2) +{ + // Traces for debug. + // ****************** + + #if (TRACE_TYPE==5) + trace_fct(CST_L1S_ABORT, l1a_l1s_com.Scell_info.radio_freq); + #endif + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_ABORT_W0_R0, (UWORD32)(-1));//OMAPS00090550 + #endif + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + if (trace_info.current_config->l1_dyn_trace & 1<d_debug = (l1s.debug_time + 2) ; + + // Signals the ABORT process to the DSP. + // ************************************** + + // Set "b_abort" to TRUE, dsp will reset current and pending tasks. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= (1 << B_TASK_ABORT); + + + // Tasks are aborted on DSP side => forbid measurements during ABORT + l1s.forbid_meas = 1; + + // Flag DSP programmation. + // ************************ + + // Set "CTRL_ABORT" flag in the controle flag register. + l1s.dsp_ctrl_reg |= CTRL_ABORT; +#if (FF_L1_FAST_DECODING == 1) + /* Reset fast decoding */ + l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_NONE; + l1a_apihisr_com.fast_decoding.contiguous_decoding = FALSE; +#endif /* #if (FF_L1_FAST_DECODING == 1) */ +} + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + +/*-------------------------------------------------------*/ +/* l1s_ctrl_msagc() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: BCCHN,FBNEW,SB1,SB2,SBCONF. This function is */ +/* the control function for making a power measurement */ +/* for refreshing the AGC for those tasks. It programs */ +/* the DSP and the TPU for making 1 measurement in the */ +/* next frame. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Get the cell information structure. */ +/* - Traces and debug. */ +/* - Programs DSP for measurement task. */ +/* - Programs TPU for measurement task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* BCCHN, BCCH Neighbor reading task. */ +/* FBNEW, Frequency Burst detection task in Idle mode. */ +/* SB1, Synchro Burst reading task in Idle mode. */ +/* SB2, Synchro Burst detection task in Idle mode. */ +/* SBCONF, Synchro Burst confirmation task in Idle */ +/* mode. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1s.afc" */ +/* current AFC value to be applied for FBNEW and SB2 */ +/* tasks in Cell Selection only. */ +/* */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip this */ +/* control if L1A has changed or is changing some of */ +/* the task parameters. */ +/* */ +/* "l1a_l1s_com.Ncell_info.bcch" */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* "l1a_l1s_com.Ncell_info.conf" */ +/* cell information structure used for BCCHN,FBNEW, */ +/* SB1/SB2,SBCONF respectively. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> incremented. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_msagc(UWORD8 task, UWORD8 param2) +{ + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_pw = 0; + UWORD8 if_ctl = 0; +//OMAPS00090550 UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; + #endif + + if(!(l1a_l1s_com.task_param[task])) + // Check the task semaphore. The control body is executed only + // when the task semaphore is 0. This semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. + { + T_NCELL_SINGLE *cell_info_ptr = NULL; +#if (L1_GPRS) + T_NCELL_SINGLE pbcchn_cell_info; +#endif +#if ((REL99 == 1) && (FF_BHO == 1)) + T_NCELL_SINGLE bho_cell_info; +#endif + + // Get the cell information structure. + // ************************************ + + switch(task) + { + case BCCHN: cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_norm];break; + case BCCHN_TOP:cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_top];break; + case FBNEW: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id]; break; + case SB2: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; break; + case SBCONF: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sbconf_id];break; + +#if ((REL99 == 1) && (FF_BHO == 1)) + case FBSB: + { + cell_info_ptr = &bho_cell_info; + bho_cell_info.radio_freq = l1a_l1s_com.nsync_fbsb.radio_freq; + bho_cell_info.fn_offset = l1a_l1s_com.nsync_fbsb.fn_offset; + } + break; +#endif + + #if (L1_GPRS) + case PBCCHN_IDLE: + { + cell_info_ptr = &pbcchn_cell_info; + pbcchn_cell_info.radio_freq = l1pa_l1ps_com.pbcchn.bcch_carrier; + pbcchn_cell_info.fn_offset = l1pa_l1ps_com.pbcchn.fn_offset; + } + break; + #endif + default: return; + } + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_MSAGC, cell_info_ptr->radio_freq); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + + // Programs DSP for measurement task. + // *********************************** + + // Dsp pgm... (2 measurement). + #if L1_GPRS + switch (l1a_l1s_com.dsp_scheduler_mode) + { + case GPRS_SCHEDULER: + { + l1pddsp_meas_ctrl(2,0); + } break; + + case GSM_SCHEDULER: + { + l1ddsp_load_monit_task(2, 0); + } break; + } + #else + l1ddsp_load_monit_task(2, 0); + #endif + + #if (RF_FAM == 61) + #if (PWMEAS_IF_MODE_FORCE == 0) + cust_get_if_dco_ctl_algo (&dco_algo_ctl_pw, &if_ctl, + (UWORD8) L1_IL_INVALID, 0, + cell_info_ptr->radio_freq,C_IF_ZERO_LOW_THRESHOLD_GSM);//OMAPS00090550 + #else + if_ctl = IF_120KHZ_DSP; + dco_algo_ctl_pw = DCO_IF_0KHZ; + #endif + + // Duplicate the outcome of DCO control as there are 2 PM + dco_algo_ctl_pw = (((dco_algo_ctl_pw<<2) & 0x0C) | (dco_algo_ctl_pw & 0x03)); // 0000ZLZL + l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw); + #endif + + // Programs TPU for measurement task. + // *********************************** + // tpu pgm: measurement only. + if (task == FBNEW) + { + l1dtpu_meas(cell_info_ptr->radio_freq, + l1_config.params.high_agc, + 0, // 0 is set for lna_off = 0 + l1s.tpu_win, + l1s.tpu_offset, INACTIVE + #if(RF_FAM == 61) + ,L1_AFC_NONE + ,if_ctl + #endif + ); + } + else + { + l1dtpu_meas(cell_info_ptr->radio_freq, + l1_config.params.high_agc, + 0, // 0 is set for lna_off = 0 + l1s.tpu_win, + l1s.tpu_offset, INACTIVE + #if(RF_FAM == 61) + ,L1_AFC_SCRIPT_MODE + ,if_ctl + #endif + ); + } + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, cell_info_ptr->radio_freq, + cell_info_ptr->fn_offset, l1s.tpu_win); + #endif + #endif + +if (task == FBNEW) +{ + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + PWR_LOAD); + + // tpu pgm: measurement only. + l1dtpu_meas(cell_info_ptr->radio_freq, + l1_config.params.low_agc, + 0, // 0 is set for lna_off = 0 + l1s.tpu_win, + l1s.tpu_offset, + INACTIVE +#if(RF_FAM == 61) + ,L1_AFC_SCRIPT_MODE + ,if_ctl +#endif + ); +} +else +{ + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + PWR_LOAD); + + // tpu pgm: measurement only. + l1dtpu_meas(cell_info_ptr->radio_freq, + l1_config.params.low_agc, + 0, // 0 is set for lna_off = 0 + l1s.tpu_win, + l1s.tpu_offset, + INACTIVE +#if(RF_FAM == 61) + ,L1_AFC_SCRIPT_MODE + ,if_ctl +#endif + ); +} + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + PWR_LOAD); + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_MS" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_MS; + l1s.dsp_ctrl_reg |= CTRL_MS; + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + l1s.forbid_meas = TASK_ROM_MFTAB[task].size; +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_fb() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: FBNEW,FB51. This function is the control */ +/* function for making a frequency burst acquisition on */ +/* a neighbor cell. It programs the DSP and the TPU for */ +/* making 1 attempt in reading the frequency burst.Here */ +/* is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for FB acquisition task. */ +/* - Programs TPU for FB acquisition task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* FBNEW, Frequency Burst detection task in Idle mode. */ +/* FB51, Frequency Burst detection task in Dedicated */ +/* mode. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip this */ +/* control if L1A has changed or is changing some of */ +/* the task parameters. */ +/* */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* cell information structure used for FBNEW and FB51 */ +/* tasks. */ +/* */ +/* "l1a_l1s_com.fb_mode" */ +/* the frequency burst detection algorithm implemented */ +/* in the DSP uses 2 different modes. The mode to use */ +/* is indicated by this global variable and is passed */ +/* to the DSP. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_fb(UWORD8 task, UWORD8 param2) +{ + WORD8 agc; + UWORD8 lna_off; + BOOL en_task; + BOOL task_param; + UWORD32 dsp_task; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) + // Check the task semaphore and enable flag. The control body is executed only + // when the task semaphore is 0 and enable flag is 1. The semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. The enable can be + // reset to 0 when the task is no more enabled. + { + T_NCELL_SINGLE *cell_info_ptr = NULL; + + // Get the cell information structure. + // ************************************ + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id]; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_FB, cell_info_ptr->radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 13) ; + + // Programs DSP for required task. + // ******************************** + + // dsp pgm... + + dsp_task = l1s_swap_iq_dl(cell_info_ptr->radio_freq,task); + + l1ddsp_load_monit_task(dsp_task, l1a_l1s_com.fb_mode); + + // Programs TPU for required task. + // ******************************** +#if (L1_FF_MULTIBAND == 0) + + // lna_off flag is updated ONLY in case of l1ctl_pgc2 control algo + lna_off = l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + // Get AGC to be applied. + agc = Cust_get_agc_from_IL(cell_info_ptr->radio_freq,l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].input_level >> 1, AV_ID, lna_off); + +#else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = l1_multiband_radio_freq_convert_into_operative_radio_freq(cell_info_ptr->radio_freq ); + // lna_off flag is updated ONLY in case of l1ctl_pgc2 control algo + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + // Get AGC to be applied. + agc = Cust_get_agc_from_IL(cell_info_ptr->radio_freq,l1a_l1s_com.last_input_level[operative_radio_freq].input_level >> 1, AV_ID, lna_off); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + // tpu pgm... + l1dtpu_neig_fb(cell_info_ptr->radio_freq, agc, lna_off); + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + // Rem: Only FB51 task starts from this ctrl function. + if(task==FB51) l1s.forbid_meas = TASK_ROM_MFTAB[task].size; +} + + +/*-------------------------------------------------------*/ +/* l1s_ctrl_fbsb() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: FBSB. This function is the control */ +/* function for making a frequency + synchro burst */ +/* on a neighbor cell in case of blind handover */ +/* It programs the DSP and the TPU for */ +/* making 1 attempt in reading the frequency & synchro */ +/* burst */ +/* Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for FB+SB acquisition task. */ +/* - Programs TPU for FB+SB acquisition task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* FBSB, Frequency + Synchro burst detection task in */ +/* blind handover */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip this */ +/* control if L1A has changed or is changing some of */ +/* the task parameters. */ +/* */ +/* "l1a_l1s_com.nsync_fbsb" */ +/* cell information structure used for FBSB tasks. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP */ +/* interface. This is used mainly to swap then the */ +/* com. page at the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +#if ((REL99 == 1) && (FF_BHO == 1)) +void l1s_ctrl_fbsb(UWORD8 task, UWORD8 param2) +{ + + WORD8 agc; + UWORD8 lna_off; + UWORD32 dsp_task; + //added by sajal for DCXO + UWORD8 input_level; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_sb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; + #endif +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + + // Traces and debug. + // ****************** + +#if (TRACE_TYPE!=0) + // trace_fct(CST_L1S_CTRL_FBSB, l1a_l1s_com.nsync_fbsb.radio_freq); +#endif + +#if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); +#endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 13) ; + + // Programs DSP for required task. + // ******************************** + + // dsp pgm... + + dsp_task = l1s_swap_iq_dl(l1a_l1s_com.nsync_fbsb.radio_freq, task); + + l1ddsp_load_monit_task(dsp_task, 1); +#if (L1_FF_MULTIBAND == 0) + input_level = l1a_l1s_com.last_input_level[l1a_l1s_com.nsync_fbsb.radio_freq - l1_config.std.radio_freq_index_offset].input_level; +#else + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.nsync_fbsb.radio_freq); + input_level = + l1a_l1s_com.last_input_level[operative_radio_freq].input_level; +#endif + + #if (RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_sb, &if_ctl, (UWORD8) L1_IL_VALID , + input_level, + l1a_l1s_com.nsync_fbsb.radio_freq,if_threshold); + + l1ddsp_load_dco_ctl_algo_sb(dco_algo_ctl_sb); + #endif + + // Programs TPU for required task. + // ******************************** +#if (L1_FF_MULTIBAND == 0) + + // lna_off flag is updated ONLY in case of l1ctl_pgc2 control algo + lna_off = l1a_l1s_com.last_input_level[l1a_l1s_com.nsync_fbsb.radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + + // Get AGC to be applied. + agc = Cust_get_agc_from_IL(l1a_l1s_com.nsync_fbsb.radio_freq, l1a_l1s_com.last_input_level[l1a_l1s_com.nsync_fbsb.radio_freq - l1_config.std.radio_freq_index_offset].input_level >> 1, AV_ID, lna_off); + +#else // L1_FF_MULTIBAND = 1 below + + /*operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.nsync_fbsb.radio_freq);*/ + + // lna_off flag is updated ONLY in case of l1ctl_pgc2 control algo + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + + // Get AGC to be applied. + agc = + Cust_get_agc_from_IL(l1a_l1s_com.nsync_fbsb.radio_freq, l1a_l1s_com.last_input_level[operative_radio_freq].input_level >> 1, AV_ID, lna_off); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + // tpu pgm... + + l1dtpu_neig_fbsb(l1a_l1s_com.nsync_fbsb.radio_freq, agc, lna_off); + + // Disable Task +// FTH l1a_l1s_com.l1s_en_task[FBSB] = TASK_DISABLED; + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; +} +#endif //#if ((REL99 == 1) && (FF_BHO == 1)) + + + +/*-------------------------------------------------------*/ +/* l1s_ctrl_sbgen() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: SB1,SB2,SB51,SBCONF,SBCNF51. This function is */ +/* the control function for making a synchro burst */ +/* reading on a neighbor cell in Cell Selection, Idle */ +/* mode and dedicated mode SDCCH. It programs the DSP */ +/* and the TPU for making 1 attempt in reading the */ +/* synchro burst. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Get the cell information structure. */ +/* - Traces and debug. */ +/* - Programs DSP for SB reading task. */ +/* - Programs TPU for SB reading task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* SB1, Synchro Burst reading task in Idle mode. */ +/* SB2, Synchro Burst detection task in Idle mode. */ +/* SBCONF, Synchro Burst confirmation task in Idle */ +/* mode. */ +/* SB51, Synchro Burst reading task in Dedicated mode. */ +/* SBCNF51, Synchro Burst confirmation task in */ +/* Dedicated mode. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip this */ +/* control if L1A has changed or is changing some of */ +/* the task parameters. */ +/* */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* cell information structure used for SB1, SB2 and */ +/* SB51 tasks. */ +/* */ +/* "l1a_l1s_com.Ncell_info.conf" */ +/* cell information structure used for SBCONF and */ +/* SBCNF51 tasks. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for SYNCHRO and OFFSET register in the TPU */ +/* for current serving cell setting. It is used here */ +/* by the synchro burst reading TPU driver since this */ +/* driver changes the OFFSET register. At the end of */ +/* the task it restores the serving cell offset value. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_sbgen(UWORD8 task, UWORD8 attempt) +{ + UWORD8 reload_serv_offset = TRUE; // Default: offset serving reloaded. + WORD8 agc; + UWORD8 lna_off; + BOOL en_task; + BOOL task_param; + UWORD32 dsp_task; + UWORD8 input_level; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_sb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; + #endif +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) + // Check the task semaphore and enable flag. The control body is executed only + // when the task semaphore is 0 and enable flag is 1. The semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. The enable can be + // reset to 0 when the task is no more enabled. + { + T_NCELL_SINGLE *cell_info_ptr = NULL; + + switch(task) + { + case SB2: + { + // Get the cell information structure. + // ************************************ + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; + + if(attempt == 1) reload_serv_offset = FALSE; // Offset serving not reloaded on 1st CTRL. + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_SB2, cell_info_ptr->radio_freq); + #endif + } + break; + + case SB51: + { + // Get the cell information structure. + // ************************************ + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_SB51, cell_info_ptr->radio_freq); + #endif + } + break; + + case SBCONF: + case SBCNF51: + { + // Get the cell information structure. + // ************************************ + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sbconf_id]; + + #if (TRACE_TYPE!=0) + if(task == SBCONF) + trace_fct(CST_L1S_CTRL_SBCONF, cell_info_ptr->radio_freq); + else + trace_fct(CST_L1S_CTRL_SBCNF51, cell_info_ptr->radio_freq); + #endif +#if (L1_EOTD==1) + // We need to trigger the TOA tracking / adjustment period + // which logs all TOA updates after E-OTD has started... + + if(l1a_l1s_com.nsync.eotd_meas_session == TRUE) + { + if( (l1a_l1s_com.nsync.eotd_toa_phase == 0) + && (l1a_l1s_com.nsync.active_sbconf_id == 12) ) + { + l1a_l1s_com.nsync.eotd_toa_tracking = 0; + l1a_l1s_com.nsync.eotd_toa_phase = 1; + } + + l1a_l1s_com.nsync.eotd_cache_toa_tracking = l1a_l1s_com.nsync.eotd_toa_tracking; + } +#endif + + + } + break; + + default: return; + } + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 3) ; + + // Programs DSP for required task. + // ******************************** + + // dsp pgm... + dsp_task = l1s_swap_iq_dl(cell_info_ptr->radio_freq,task); + l1ddsp_load_monit_task(dsp_task, 0); + +#if (L1_FF_MULTIBAND == 0) + input_level = l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].input_level; +#else // L1_FF_MULTIBAND = 1 below + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(cell_info_ptr->radio_freq); + input_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; +#endif //#if (L1_FF_MULTIBAND == 0) else + + #if (RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_sb, &if_ctl, (UWORD8) L1_IL_VALID , + input_level, + cell_info_ptr->radio_freq,if_threshold); + + // This is a work-around for a DSP problem (OMAPS00117845) + // The problem happens during neighbor FB/SB, when there is an + // IDLE frame between neighbor FB and SB. + // Neighbor cell SB(SB2) is different from other kind of SB decode. + // For SB2 we open the RF window for 2 frames (2 C W W R) + // For both Control, l1s_dsp_com.dsp_db_common_w_ptr->d_dco_algo_ctrl_sb is updated. + // However DSP copies DB value to NDB and this value is copied only once. + // At the end of the first SB, DSP right shifts the NDB variable. + // The fix below replicates the DCO control information 4 times + // so that DSP has correct information even after right shifting during first SB. + + if(task == SB2) + { + dco_algo_ctl_sb *= 0x55; + } + + + + + l1ddsp_load_dco_ctl_algo_sb(dco_algo_ctl_sb); + #endif + + // Programs TPU for required task. + // ******************************** +#if (L1_FF_MULTIBAND == 0) + + // lna_off flag is ONLY updated in case of l1ctl_pgc2 control algorithm + lna_off = l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + // Get AGC to be applied. + agc = Cust_get_agc_from_IL(cell_info_ptr->radio_freq, input_level >> 1, AV_ID,lna_off); + +#else // L1_FF_MULTIBAND = 0 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(cell_info_ptr->radio_freq); + // lna_off flag is ONLY updated in case of l1ctl_pgc2 control algorithm + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + // Get AGC to be applied. + agc = + Cust_get_agc_from_IL(cell_info_ptr->radio_freq, input_level >> 1, AV_ID,lna_off); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + // tpu pgm... + l1dtpu_neig_sb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + reload_serv_offset, + attempt + #if (RF_FAM == 61) + ,if_ctl + #endif + ); + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, cell_info_ptr->radio_freq, + cell_info_ptr->time_alignmt,l1s.tpu_offset); + #endif + #endif + } + else + // The task has been disabled or some parameters have changed, the serving tpu offset + // must be restored. + { + if(attempt==2) + { + l1dmacro_offset(l1s.tpu_offset,IMM); + } + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + // Rem: Only SB51/SBCNF51 tasks start from this ctrl function. + if((task==SB51)||(task==SBCNF51)) l1s.forbid_meas = TASK_ROM_MFTAB[task].size; +} + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_ctrl_fb26() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: FB26. This function is the control function */ +/* for making a frequency burst acquisition attempt on */ +/* a neighbor cell in dedicated mode TCH. It programs */ +/* the DSP and the TPU for making 1 attempt in reading */ +/* the frequency burst.Here is a summary of the */ +/* execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for FB acquisition task. */ +/* - Programs TPU for FB acquisition task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* cell information structure used for FB26 task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for SYNCHRO and OFFSET register in the TPU */ +/* for current serving cell setting. It is used here */ +/* by the frequency burst reading TPU driver since */ +/* this driver changes the OFFSET register. At the end */ +/* of the task it restores the serving cell offset */ +/* value. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_fb26(UWORD8 param1, UWORD8 param2) +{ + WORD8 agc; + BOOL lna_off; + UWORD32 dsp_task; + UWORD16 radio_freq = 0; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + +#if (L1_12NEIGH ==1) + BOOL en_task; + BOOL task_param; + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[param1]; + task_param = l1a_l1s_com.task_param[param1]; + + if((en_task) && !(task_param)) + // Check the task semaphore and enable flag. The control body is executed only + // when the task semaphore is 0 and enable flag is 1. The semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. The enable can be + // reset to 0 when the task is no more enabled. +#else + if(!(l1a_l1s_com.task_param[FB26] == SEMAPHORE_SET)) +#endif + // Check the task semaphore. The control body is executed only + // when the task semaphore is 0. This semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. + { +#if (L1_12NEIGH ==1) + T_NCELL_SINGLE *cell_info_ptr = NULL; + + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id]; + radio_freq = cell_info_ptr->radio_freq; +#else + radio_freq = l1a_l1s_com.nsync.list[0].radio_freq; +#endif + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_FB26, radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[FB26].name); + #endif + + // Programs DSP for FB26 task. + // **************************** + + // dsp pgm... + + dsp_task = l1s_swap_iq_dl(radio_freq,FB26); + + l1ddsp_load_monit_task(dsp_task, 1); + + // Programs TPU for FB26 task. + // **************************** +#if (L1_FF_MULTIBAND == 0) + + lna_off = l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + // agc is just computed from last stored IL + agc = Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].input_level >> 1, AV_ID, lna_off); + +#else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(radio_freq); + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + // agc is just computed from last stored IL + agc = + Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.last_input_level[operative_radio_freq].input_level >> 1, AV_ID, lna_off); + +#endif // #if (L1_FF_MULTIBAND == 1) else + + + // tpu pgm... + l1dtpu_neig_fb26(radio_freq, + agc, + lna_off, + l1s.tpu_offset); + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + // Special case: we set forbid_meas to skip the measurements in the frames + // FN%26=24 or 25. + l1s.forbid_meas = 3; +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_ctrl_sb26() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: SB1,SB2,SB51,SBCONF,SBCNF51. This function is */ +/* the control function for making a synchro burst */ +/* reading on a neighbor cell in Cell Selection, Idle */ +/* mode and dedicated mode SDCCH. It programs the DSP */ +/* and the TPU for making 1 attempt in reading the */ +/* synchro burst. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Get the cell information structure. */ +/* - Traces and debug. */ +/* - Programs DSP for SB reading task. */ +/* - Programs TPU for SB reading task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* SB26, Synchro Burst reading task in Dedicated mode, */ +/* TCH. */ +/* SBCNF26, Synchro Burst confirmation task in Dedic. */ +/* mode TCH. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* cell information structure used for SB26 task. */ +/* */ +/* "l1a_l1s_com.Ncell_info.conf" */ +/* cell information structure used for SBCNF26 task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for SYNCHRO and OFFSET register in the TPU */ +/* for current serving cell setting. It is used here */ +/* by the synchro burst reading TPU driver since this */ +/* driver changes the OFFSET register. At the end of */ +/* the task it restores the serving cell offset value. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_sb26(UWORD8 task, UWORD8 param2) +{ + UWORD32 nb_nop = 0; + WORD8 agc; + BOOL lna_off; + UWORD32 dsp_task; + UWORD8 input_level; + UWORD32 temp; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + +#if (L1_12NEIGH ==1) + BOOL en_task; + BOOL task_param; +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_sb = 0; + UWORD8 if_ctl = 0 ; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) +#else + if(!(l1a_l1s_com.task_param[task])) +#endif + // Check the task semaphore. The control body is executed only + // when the task semaphore is 0. This semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. + { + UWORD16 radio_freq = 0; + UWORD32 time_alignmt = 0; +#if (L1_12NEIGH ==1) + T_NCELL_SINGLE *cell_info_ptr = NULL; + + if (task == SB26) + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; + if (task == SBCNF26) + { + +#if (L1_EOTD==1) + // We need to trigger the TOA tracking / adjustment period + // which logs all TOA updates after E-OTD has started... + + if(l1a_l1s_com.nsync.eotd_meas_session == TRUE) + { + if( (l1a_l1s_com.nsync.eotd_toa_phase == 0) + && (l1a_l1s_com.nsync.active_sbconf_id == 12) ) + { + l1a_l1s_com.nsync.eotd_toa_tracking = 0; + l1a_l1s_com.nsync.eotd_toa_phase = 1; + } + + l1a_l1s_com.nsync.eotd_cache_toa_tracking = l1a_l1s_com.nsync.eotd_toa_tracking; + } +#endif + + cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sbconf_id]; + + } +if(cell_info_ptr != NULL)//OMAPS00090550 +{ + radio_freq = cell_info_ptr->radio_freq; + time_alignmt = cell_info_ptr->time_alignmt; +} + +#else + // Get the cell information. + // ************************** + radio_freq = l1a_l1s_com.nsync.list[0].radio_freq; + time_alignmt = l1a_l1s_com.nsync.list[0].time_alignmt; +#endif + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + switch(task) + { + case SB26: trace_fct(CST_L1S_CTRL_SB26, radio_freq); break; + case SBCNF26: trace_fct(CST_L1S_CTRL_SBCNF26, radio_freq); break; + } + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + // Programs DSP for required task. + // ******************************** + // dsp pgm... + + dsp_task = l1s_swap_iq_dl(radio_freq,task); + l1ddsp_load_monit_task(dsp_task, 0); + + // Programs TPU for required task. + // ******************************** + temp = (UWORD32)(l1_config.params.fb26_anchoring_time - EPSILON_SYNC); + #if (L1_12NEIGH ==1) + if(cell_info_ptr != NULL)//OMAPS00090550 + { + if((cell_info_ptr->sb26_offset == 1) && + (time_alignmt >= temp)) //omaps00090550 + #else + if((l1a_l1s_com.nsync.list[0].sb26_offset == 1) && + (time_alignmt >= temp)) //omaps00090550 + #endif + // SB is in the 2nd frame of the search slot... + // ...and SB is at the very end of the slot. + // We insert a nop in the tpu scenario to + // be able to jump the 1st frame. + { + nb_nop = 1; + } + #if (L1_12NEIGH ==1) + } + #endif + +#if (L1_FF_MULTIBAND == 0) + + // agc is just computed from last stored IL + input_level = l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].input_level; + lna_off = l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + agc = Cust_get_agc_from_IL(radio_freq, input_level >> 1, AV_ID, lna_off); + +#else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(radio_freq); + // agc is just computed from last stored IL + input_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + agc = Cust_get_agc_from_IL(radio_freq, input_level >> 1, AV_ID, lna_off); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + #if (RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_sb, &if_ctl, (UWORD8) L1_IL_VALID, + input_level, + radio_freq,if_threshold); + l1ddsp_load_dco_ctl_algo_sb(dco_algo_ctl_sb); + #endif + + // tpu pgm... + l1dtpu_neig_sb26(radio_freq, + agc, + lna_off, + time_alignmt, + nb_nop, + l1s.tpu_offset + #if (RF_FAM == 61) + ,if_ctl + #endif + ); + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + // Special case: we set forbid_meas to skip the measurements in the frames + // FN%26=24 or 25. + l1s.forbid_meas = 3; +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +/*-------------------------------------------------------*/ +/* l1s_ctrl_smscb() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: SMSCB. This function is the control function */ +/* for reading a CBCH burst on the serving cell. It */ +/* shifts the OFFSET register to match the normal burst */ +/* receive task with the CBCH timeslot number (0,1,2 or */ +/* 3), programs a normal burst reading and restores the */ +/* OFFSET to the serving cell timeslot 0. On the last */ +/* control (4th burst), the SYNCHRO/OFFSET registers are */ +/* shifted back to the normal idle mode PCH reading */ +/* setting. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for SMSCB task, reading 1 burst. */ +/* - Programs TPU for SMSCB task, reading 1 burst. */ +/* - Shift TPU SYNCHRO/OFFSET registers back to the */ +/* PAGING TASK timeslot. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* SMSCB, Short Message Service Cell Broadcast. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.cbch_desc" */ +/* Cell Broadcast CHannel description structure. */ +/* */ +/* "l1a_l1s_com.Scell_info.bsic" */ +/* BSIC of the serving cell. It is used here to pass */ +/* the training sequence number (part of BSIC) to the */ +/* DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for SMSCB reading */ +/* task. */ +/* */ +/* "l1a_l1s_com.offset_tn0" */ +/* value to load in the OFFSET register to shift then */ +/* any receive task to the timeslot 0 of the serving */ +/* cell. This is the default setting to restore after */ +/* any CBCH burst reading. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. It is used here */ +/* at the end of the CBCH task controls to restore the */ +/* SYNCHRO/OFFSET registers to the normal setting in */ +/* idle mode. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.actual_time, l1s.next_time" */ +/* frame number and derived numbers for current frame */ +/* and next frame. */ +/* -> update to cope with side effect due to synchro. */ +/* changes/restores. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_smscb(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 rx_radio_freq; + UWORD32 offset_smscb; + WORD8 agc; + UWORD8 lna_off; + UWORD32 dsp_task; + static WORD32 new_tpu_offset; + static BOOL change_synchro; + UWORD8 input_level; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + +#if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; +#endif /* NEW_SNR_THRESHOLD */ +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; + + // Needed for simulated DSP GRPS scheduler + #if (CODE_VERSION == SIMULATION) + UWORD32 tpu_w_page; + + if (hw.tpu_r_page==0) + tpu_w_page=1; + else + tpu_w_page=0; + + hw.rx_id[tpu_w_page][0]=0; + hw.num_rx[tpu_w_page][0]=1; + hw.rx_group_id[tpu_w_page]=1; + #endif + + + if((l1a_l1s_com.l1s_en_task[task] == TASK_ENABLED) && + !(l1a_l1s_com.task_param[task] == SEMAPHORE_SET)) + // Check the task semaphore. The control body is executed only + // when the task semaphore is 0. This semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. + { + // Get ARFCN to be used for current control. Output of the hopping algorithm. + rx_radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_SMSCB, rx_radio_freq); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Programs DSP for SMSCB task according to the DSP scheduler used + // **************************************************************** + + #if L1_GPRS + switch(l1a_l1s_com.dsp_scheduler_mode) + { + // dsp pgm is made using GSM scheduler... + case GSM_SCHEDULER: + { + dsp_task = l1s_swap_iq_dl(rx_radio_freq, task); + + // dsp pgm... + l1ddsp_load_rx_task(dsp_task,burst_id,l1a_l1s_com.cbch_desc.tsc); + } + break; + + // dsp pgm is made using GPRS scheduler... + case GPRS_SCHEDULER: + { + #if FF_L1_IT_DSP_USF + l1pddsp_idle_rx_nb(burst_id,l1a_l1s_com.cbch_desc.tsc,rx_radio_freq,0,FALSE,FALSE); + #else + l1pddsp_idle_rx_nb(burst_id,l1a_l1s_com.cbch_desc.tsc,rx_radio_freq,0,FALSE); + #endif + } + break; + } + #else + dsp_task = l1s_swap_iq_dl(rx_radio_freq, task); + + // dsp pgm... + l1ddsp_load_rx_task(dsp_task,burst_id,l1a_l1s_com.cbch_desc.tsc); + #endif + + // Check if "Synchro" change is needed. + // ************************************* + + // If so the synchro is changed by 4 timeslots. + if(burst_id == BURST_1) + { + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + l1s.forbid_meas = TASK_ROM_MFTAB[task].size; + + change_synchro = l1a_l1s_com.change_synchro_cbch; + + if(change_synchro) + { + // compute TPU offset for "current timeslot + 4 timeslot" + new_tpu_offset = l1s.tpu_offset + (4 * TN_WIDTH); + + if(new_tpu_offset >= TPU_CLOCK_RANGE) + new_tpu_offset -= TPU_CLOCK_RANGE; + + // Slide synchro to match current timeslot + 4 timeslot. + l1dmacro_synchro(l1_config.params.rx_change_synchro_time, new_tpu_offset); + } + else + { + new_tpu_offset = l1s.tpu_offset; + } + } + + // Programs TPU for SMSCB task, reading 1 burst. + // ********************************************** + + offset_smscb = new_tpu_offset + l1a_l1s_com.tn_smscb * TN_WIDTH; + if (offset_smscb >= TPU_CLOCK_RANGE) + offset_smscb -= TPU_CLOCK_RANGE; + +#if (L1_FF_MULTIBAND == 0) + + // agc is set with the input_level computed from PAGC algo + input_level = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset].input_level; + lna_off = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + agc = Cust_get_agc_from_IL(l1a_l1s_com.Scell_info.radio_freq,input_level >> 1, MAX_ID, lna_off); + +#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); + input_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + agc = Cust_get_agc_from_IL(l1a_l1s_com.Scell_info.radio_freq,input_level >> 1, MAX_ID, lna_off); + + +#endif // #if (L1_FF_MULTIBAND == 0) else + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + input_level, + l1a_l1s_com.Scell_info.radio_freq,if_threshold); + + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + // Store IL used for current CTRL in order to be able to buil IL from pm + // in READ phase. +#if (L1_FF_MULTIBAND == 0) + + l1a_l1s_com.Scell_used_IL.input_level = input_level; + l1a_l1s_com.Scell_used_IL.lna_off = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + +#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); + l1a_l1s_com.Scell_used_IL.input_level = input_level; + l1a_l1s_com.Scell_used_IL.lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + +#endif // #if (L1_FF_MULTIBAND == 1) else + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + ,&saic_flag + #endif + ); + #endif + + // tpu pgm... + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + new_tpu_offset, + offset_smscb, + TRUE, + FALSE + #if (RF_FAM == 61) + ,csf_filter_choice + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /* NEW_SNR_THRESHOLD */ + ); + + } // End if(task enabled and semaphore false) + + // Remark: + //-------- + // When the task is aborted, we must continue to make dummy + // DSP programming to avoid communication mismatch due + // to C/W/R pipelining. + + // We must also ensure the Synchro back since synchro change has surely be done + // in the 1st CTRL phase. + + // Shift TPU SYNCHRO/OFFSET registers back to the default timeslot (normally (P)CCCH one). + // **************************************************************************************** + // When the CBCH reading control is completed (4 burst controled), + // the SYNCHRO/OFFSET registers are shifted back to the normal idle + // setting used for (P)CCCH reading on the serving cell. + + // Check if "Synchro" change was needed. + // If so the synchro is changed to recover normal synchro. + if(burst_id == BURST_4) + { + if(change_synchro) + { + // Slide synchro back to mach current serving timeslot. + l1dmacro_synchro(SWITCH_TIME, l1s.tpu_offset); + + // Increment frame number. + #if L1_GPRS + l1s.actual_time = l1s.next_time; + l1s.next_time = l1s.next_plus_time; + l1s_increment_time(&(l1s.next_plus_time), 1); // Increment "next_plus time". + #else + l1s.actual_time = l1s.next_time; + l1s_increment_time(&(l1s.next_time), 1); // Increment "next time". + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + trace_fct(CST_L1S_ADJUST_TIME, (UWORD32)(-1));//OMAPS00090550 + #endif + + l1s.tpu_ctrl_reg |= CTRL_SYCB; + l1s.dsp_ctrl_reg |= CTRL_SYNC; + } + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; +} + +#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 + +UWORD32 qual_acc_idle1[2]; + +/*-------------------------------------------------------*/ +/* l1s_ctrl_snb_dl() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* serving cell normal burst reading tasks: NP, EP, */ +/* BCCHS, ALLC, DDL and ADL. This function is the control*/ +/* function for reading a normal burst on the serving */ +/* cell. It programs the DSP and the TPU for reading a */ +/* normal burst without change on the TPU OFFSET */ +/* register and flags the reading of the normal paging */ +/* burst. This flag is used by the measurement manager */ +/* "l1s_meas_manager()" at the end of L1S. Here is a */ +/* summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Catch ARFCN and set CIPHERING reduced frame */ +/* number. */ +/* - Traces and debug. */ +/* - Programs DSP for required task. */ +/* - Programs TPU for required task. */ +/* - Flag the reading of a Normal Paging burst. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* NP, Normal paging reading task. */ +/* EP, Extended paging reading task. */ +/* BCCHS, BCCH Serving reading task. */ +/* ALLC, All serving cell CCCH reading task. */ +/* */ +/* DDL, SDCCH DOWNLINK reading task. */ +/* ADL, SACCH DOWNLINK (associated with SDCCH)reading */ +/* task. */ +/* */ +/* "burst_id" */ +/* BURST_1, 1st burst of the task. */ +/* BURST_2, 2nd burst of the task. */ +/* BURST_3, 3rd burst of the task. */ +/* BURST_4, 4th burst of the task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set" */ +/* Dedicated channel parameter structure. It is used */ +/* to get the ARFCN to use for SDCCH (DDL, ADL). This */ +/* ARFCN comes from the HOPPING algorithm called just */ +/* before calling this function. */ +/* */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .radio_freq, serving cell beacon frequency. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. It is used here */ +/* to refresh the TPU SYNCHRO and OFFSET registers */ +/* with a corrected (time tracking of the serving) */ +/* value prior to reading a serving cell normal burst. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.np_ctrl" */ +/* Flag set when a normal paging burst reading is */ +/* controled. This flag is used by the measurement */ +/* manager "l1s_meas_manager()", at the end of L1S, to */ +/* scheduling the neighbor cell measurements. */ +/* -> set to 1. */ +/* */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> incremented. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_snb_dl(UWORD8 task, UWORD8 burst_id) +{ + UWORD8 lna_off; + WORD8 agc; + UWORD16 rx_radio_freq; + UWORD8 tsc; + T_INPUT_LEVEL *IL_info_ptr; + UWORD32 dsp_task; + //static BOOL change_synchro; + UWORD8 adc_active = INACTIVE; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif /*L1_FF_MULTIBAND*/ + +#if L1_GPRS + static BOOL BCCHS_in_transfert = FALSE; + static BOOL change_synchro;//OMAPS90550-new +#endif +UWORD8 input_level = 0; //omaps00090550 +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif +#if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; +#endif /* NEW_SNR_THRESHOLD */ + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; +#if (FF_L1_FAST_DECODING == 1) + BOOL fast_decoding_authorized = FALSE; + + if ( (burst_id == BURST_1) && (l1a_apihisr_com.fast_decoding.status == C_FAST_DECODING_FORBIDDEN) ) + { + l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_NONE; + } + + fast_decoding_authorized = l1s_check_fast_decoding_authorized(task); + + if ( fast_decoding_authorized && l1s_check_deferred_control(task,burst_id) ) + { + /* Control is deferred until the upcoming fast decoding IT */ + return; + } /* if (fast_decoding_authorized)*/ + + /* In all other cases, control must be performed now. */ +#endif /* FF_L1_FAST_DECODING == 1 */ + + if(!(l1a_l1s_com.task_param[task] == SEMAPHORE_SET)) + // Check the task semaphore. The control body is executed only + // when the task semaphore is 0. This semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. + { + // Catch ARFCN and set CIPHERING reduced frame number. + // Catch Training sequence. + // **************************************************** + + if((task == DDL) || (task == ADL)) + // Dedicated mode SDCCH downlink. + { + // Get ARFCN to be used for current control. + rx_radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + if (rx_radio_freq==l1a_l1s_com.Scell_info.radio_freq) // we are working on a beacon freq. + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon; + else + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas;// we are working on a daughter freq + + // Catch training sequence code from the channel description. + tsc = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->tsc; + + // Set CIPHERING reduced frame number. +#if (AMR == 1) +#if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0, 0, 0); +#else + 0, 0, 0, 0, 0, 0, 0); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0); + #else + 0, 0, 0, 0, 0); +#endif + #endif +#else +#if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0, 0); +#else + 0, 0, 0, 0, 0, 0); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0); + #else + 0, 0, 0, 0); +#endif +#endif +#endif + lna_off = IL_info_ptr->lna_off; + // for SDCCH we use DPAGC algorithm. +#if DPAGC_MAX_FLAG + agc = Cust_get_agc_from_IL(rx_radio_freq, IL_info_ptr->input_level >> 1, MAX_ID, lna_off); +#else + agc = Cust_get_agc_from_IL(rx_radio_freq, IL_info_ptr->input_level >> 1, AV_ID, lna_off); +#endif + + + + // Store input_level and lna_off field used for current CTRL in order to be able to build IL + // from pm in READ phase. + l1a_l1s_com.Scell_used_IL = *IL_info_ptr; + } // end if (task == DDL) || (task == ADL) + else + { + rx_radio_freq = l1a_l1s_com.Scell_info.radio_freq; + + // Catch training sequence code from serving cell BCC (part of BSIC). + tsc = l1a_l1s_com.Scell_info.bsic & 0x0007; + + // for PCH/E_PCH/Serving BCCH and All CCCH we use + // PAGC algorithm. +#if (L1_FF_MULTIBAND == 0) + + input_level = l1a_l1s_com.last_input_level[rx_radio_freq - l1_config.std.radio_freq_index_offset].input_level ; + lna_off = l1a_l1s_com.last_input_level[rx_radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + agc = Cust_get_agc_from_IL(rx_radio_freq, input_level >> 1, MAX_ID, lna_off); + + + // Store input_level and lna_off fields used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL = l1a_l1s_com.last_input_level[rx_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(rx_radio_freq); + + input_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level ; + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + agc = Cust_get_agc_from_IL(rx_radio_freq, input_level >> 1, MAX_ID, lna_off); + + + // Store input_level and lna_off fields used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL = l1a_l1s_com.last_input_level[operative_radio_freq]; + + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + } + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID , + input_level, + rx_radio_freq,if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif //RF_FAM =61 + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + ,&saic_flag + #endif + ); + #endif //L!SAIC != 0 + + // ADC measurement + // *************** + // check if during the 1st burst of the bloc an ADC measurement must be performed + if ((burst_id == BURST_1) && (task == NP)) + { +#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. + //ADC measurements are already managed by comlex function of Packet idle tasks + 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 + { + adc_active = l1s_ADC_decision_on_NP(); + } + } // end if (burst_id == BURST_1) && (task == NP) + + if (task == ADL) + { + // ADC measurement for SACCH DL + // **************************** + + // check if during the SACCH burst an ADC measurement must be performed + if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_DL) // perform ADC only one time + { + adc_active = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic + } + else + if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_DL) // perform ADC on each period bloc + { + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period + { + adc_active = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + } + } + + // Traces and debug. + // ****************** + +#if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); +#endif + +#if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_CTRL_SNB_DL_BURST0 + burst_id, (UWORD32)(-1));//OMAPS00090550 +#endif + +#if (TRACE_TYPE==5) + trace_fct(CST_L1S_CTRL_SNB_DL, rx_radio_freq); +#endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // the l1a_l1s_com.mode variable could change during the block: So test this variable only on the 1st block + // See BUG2237 (mode change from Idle to Transfert during BCCHS task) +#if (L1_GPRS) + if (burst_id == BURST_1) + BCCHS_in_transfert = ((l1a_l1s_com.mode == PACKET_TRANSFER_MODE) && ((task == EBCCHS) || (task == NBCCHS))); +#endif + + // Programs DSP according to the DSP scheduler used + // ************************************************* + + +#if (L1_GPRS) + switch(l1a_l1s_com.dsp_scheduler_mode) + { + // dsp pgm is made using GSM scheduler... + case GSM_SCHEDULER: +#if (FF_L1_FAST_DECODING == 1) + l1ddsp_load_fast_dec_task(task,burst_id); +#endif + dsp_task = l1s_swap_iq_dl(rx_radio_freq,task); + l1ddsp_load_rx_task(dsp_task, burst_id, tsc); + break; + + // dsp pgm is made using GPRS scheduler... + case GPRS_SCHEDULER: +#if (FF_L1_FAST_DECODING == 1) + l1ddsp_load_fast_dec_task(task,burst_id); +#endif + #if FF_L1_IT_DSP_USF + l1pddsp_idle_rx_nb(burst_id,tsc,rx_radio_freq,0,FALSE,FALSE); + #else + l1pddsp_idle_rx_nb(burst_id,tsc,rx_radio_freq,0,FALSE); + #endif + break; + } +#else +#if (FF_L1_FAST_DECODING == 1) + l1ddsp_load_fast_dec_task(task,burst_id); +#endif + dsp_task = l1s_swap_iq_dl(rx_radio_freq,task); + l1ddsp_load_rx_task(dsp_task, burst_id, tsc); +#endif + + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // Programs TPU for required task. + // ******************************** +#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. + // if (TS(CCCH) - TS(current task))%8 >= 4 synchro change is required + // if not, OFFSET change is required + // + if (((task == EP) || (task == NP)) && + ((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))) + { + UWORD32 new_offset; + WORD32 new_synchro; + UWORD32 ts_ccch; + + ts_ccch = (l1a_l1s_com.ccch_group * 2); //timeslot CCCH burts + new_offset = (ts_ccch - l1a_l1s_com.dl_tn + 8) % 8; //dl_tn is the current time slot from previous task + + if (burst_id == BURST_1) + l1s.forbid_meas = TASK_ROM_MFTAB[task].size; + + if (new_offset >= 4) + l1s.algo_change_synchro_active = TRUE; + + if (l1s.algo_change_synchro_active) + { + // compute TPU offset for "current timeslot + 4 timeslot" + new_synchro = l1s.tpu_offset + (4 * TN_WIDTH); + + if(new_synchro >= TPU_CLOCK_RANGE) + new_synchro -= TPU_CLOCK_RANGE; + + //compute new offset + new_offset = (((ts_ccch + 4 - l1a_l1s_com.dl_tn)%8) * TN_WIDTH) + new_synchro; + } + //no synchro change required, but new offset is computed + else + { + new_synchro = l1s.tpu_offset; + new_offset = (new_offset * TN_WIDTH) + new_synchro; + } + + if (new_offset >= TPU_CLOCK_RANGE) + new_offset -= TPU_CLOCK_RANGE; + + // tpu pgm... + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + new_synchro, + new_offset, + TRUE, + adc_active + #if (RF_FAM == 61) + ,csf_filter_choice + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /*NEW_SNR_THRESHOLD */ + ); + } // end if (task == EP) || (task == NP) in packet Idle + + // in case of EBCCHS and NBCCHS in packet transfer a change synchro is performed + else if (BCCHS_in_transfert) + { + UWORD32 new_offset; + WORD32 new_synchro; + + change_synchro = ((l1a_l1s_com.dl_tn > 0) && (l1a_l1s_com.dl_tn < 5 )); + + // if change synchro is needed + if(change_synchro) // TS= [1,2,3,4] + { + // the synchro is changed by 4 timeslots. + new_synchro = l1s.tpu_offset + (4 * TN_WIDTH); + if(new_synchro >= TPU_CLOCK_RANGE) + new_synchro -= TPU_CLOCK_RANGE; + + // the TPU offset is changed according to the PDTCH time slot + // because of the new synchro above with a shift of 4TS, + // 4TS are substract to the offset + new_offset = (8 - 4 - l1a_l1s_com.dl_tn) * TN_WIDTH; + } + else + { + // the synchro is unchanged + new_synchro = l1s.tpu_offset; + + // the TPU offset is changed according to the PDTCH time slot + new_offset = (8 - l1a_l1s_com.dl_tn) * TN_WIDTH; + } + + new_offset += new_synchro; + if (new_offset >= TPU_CLOCK_RANGE) + new_offset -= TPU_CLOCK_RANGE; + + // tpu pgm... + #if (RF_FAM == 61) + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + new_synchro, + new_offset, + TRUE, + adc_active, + csf_filter_choice, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /*NEW_SNR_THRESHOLD */ + ); + #endif + + #if(RF_FAM != 61) + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + new_synchro, + new_offset, + TRUE, + adc_active); + #endif + + } // end if (task == EBCCHS) || (task == NBCCHS) in packet Idle + else +#endif + { + // tpu pgm... + #if (RF_FAM == 61) + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE, + adc_active, + csf_filter_choice, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /*NEW_SNR_THRESHOLD */ + ); + #endif + #if (RF_FAM != 61) + l1dtpu_serv_rx_nb(rx_radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE, + adc_active); + #endif + } + + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + RX_LOAD); + + // GSM DSP scheduler is not able to handle PWR too close to RX normal burst. + // We have to oblige a min of 1 burst period between RX and PWR + if(l1_config.params.rx_synth_load_split < BP_SPLIT) + l1s.tpu_win += BP_SPLIT - l1_config.params.rx_synth_load_split; + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, rx_radio_freq, + l1s.tpu_win,l1s.tpu_offset); + #endif + #endif + } + + #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. + + if (((task == EP) || (task == NP)) && + ((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))) + { + if((burst_id == BURST_4) && l1s.algo_change_synchro_active) + { + + // Slide synchro back to mach current serving timeslot. + l1dmacro_synchro(SWITCH_TIME, l1s.tpu_offset); + + + // Increment frame number. + l1s.actual_time = l1s.next_time; + l1s.next_time = l1s.next_plus_time; + l1s_increment_time (&(l1s.next_plus_time), 1); // Increment "next_plus time". + + l1s.tpu_ctrl_reg |= CTRL_SYCB; + l1s.dsp_ctrl_reg |= CTRL_SYNC; + l1s.ctrl_synch_before = FALSE; + l1s.algo_change_synchro_active = FALSE; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + trace_fct(CST_L1S_ADJUST_TIME, (UWORD32)(-1));//OMAPS00090550 + #endif + } + } + + // in case of EBCCHS and NBCCHS in packet transfer a change synchro is performed + else if (BCCHS_in_transfert) + { + // Shift TPU SYNCHRO/OFFSET registers back to the default timeslot . + // **************************************************************** + // When the E/NBCCHS reading control is completed , + // the SYNCHRO/OFFSET registers are shifted back to the normal + // setting used for PCCH reading on the serving cell. + // Check if "Synchro" change was needed. + // If so the synchro is changed to recover normal synchro. + if(burst_id == BURST_4) + { + if(change_synchro) // TS= [1,2,3,4] + { + // Slide synchro back to mach current serving timeslot. + l1dmacro_synchro(SWITCH_TIME, l1s.tpu_offset); + + // Increment frame number. + l1s.actual_time = l1s.next_time; + l1s.next_time = l1s.next_plus_time; + l1s_increment_time(&(l1s.next_plus_time), 1); // Increment "next_plus time". + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + trace_fct(CST_L1S_ADJUST_TIME, (UWORD32)(-1));//OMAPS00090550 + #endif + + l1s.tpu_ctrl_reg |= CTRL_SYCB; + l1s.dsp_ctrl_reg |= CTRL_SYNC; + } + } + + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + if(burst_id == BURST_1) + l1s.forbid_meas = TASK_ROM_MFTAB[task].size; + } + #endif + + // Flag the reading of a Normal Paging burst. + // ******************************************* + + // Set flag "NP contoled !!". Used in "l1_synch()" to generate meas. controles. + if(task == NP) + l1a_l1s_com.ba_list.np_ctrl = burst_id+1; + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; +} + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + +/*-------------------------------------------------------*/ +/* l1s_ctrl_snb_ul() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* serving cell normal burst sending tasks: DUL, AUL. */ +/* This function is the control function for sending a */ +/* burst on a SDCCH channel. It programs the DSP and the */ +/* TPU for sending a normal burst taking into account */ +/* the timing adavance. Here is a summary of the */ +/* execution: */ +/* */ +/* - Catch ARFCN. */ +/* - Traces and debug. */ +/* - Programs DSP for required task. */ +/* - Catch UL data block from DLL and gives it to DSP. */ +/* - Programs TPU for required task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* DUL, SDCCH UPLINK sending task. */ +/* AUL, SACCH UPLINK (associated with SDCCH)sending */ +/* task. */ +/* */ +/* "burst_id" */ +/* BURST_1, 1st burst of the task. */ +/* BURST_2, 2nd burst of the task. */ +/* BURST_3, 3rd burst of the task. */ +/* BURST_4, 4th burst of the task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set" */ +/* Dedicated channel parameter structure. It is used */ +/* to get the ARFCN to use for SDCCH (DUL, AUL). This */ +/* ARFCN comes from the HOPPING algorithm called just */ +/* before calling this function. */ +/* */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. It is used here */ +/* to restore this value in the OFFSET register after */ +/* the TX burst programming. */ +/* */ +/* "l1s.applied_txpwr" */ +/* Applied transmit power. */ +/* */ +/* "l1s.reported_txpwr" */ +/* Transmit power to report in the L1 header of the */ +/* SACCH data block. */ +/* */ +/* "l1a_l1s_com.dedic_set.aset" */ +/* Active dedicated mode parameter set. */ +/* .timing_advance, Timing advance to apply to the UL */ +/* burst transmission. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> set to TDMA_WIN3. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_snb_ul(UWORD8 task, UWORD8 burst_id) +{ + T_RADIO_FRAME *tx_data = NULL; + UWORD16 tx_radio_freq; + UWORD32 dsp_task; + UWORD8 adc_active_ul = INACTIVE; + + // Catch ARFCN. + // ************* + + // Get ARFCN to be used for current control. + tx_radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + if(burst_id == BURST_1) trace_flowchart_dsptx(dltsk_trace[task].name); + #endif + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_SNB_UL, tx_radio_freq); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Programs DSP for required task. + // ******************************** + + // Set CIPHERING reduced frame number. + #if (AMR == 1) + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0, 0, 0); + #else + 0, 0, 0, 0, 0, 0, 0); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0); + #else + 0, 0, 0, 0, 0); + #endif + #endif + #else + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0, 0, 0); + #else + 0, 0, 0, 0, 0, 0); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + SIG_ONLY_MODE, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type, + #if !FF_L1_IT_DSP_DTX + 0, 0, 0); + #else + 0, 0, 0, 0); + #endif + #endif + #endif + + if(task == DUL) + // SDCCH/UL task. + { + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != 0) + // "ho_acc_to_send" is a counter of Handover Access burst still to send. + // This counter is set by "l1s_dedicated_mode_manager()" in L1S when a + // Handover command is received from L3 through L1A. + { + // TX burst is a RACH. + // ******************** + // dsp and tpu pgm... + l1s_ctrl_rach(RAHO,NO_PAR); + + // Decrement number of HO ACCESS burst still to be sent. + // Rem: (-1) is used for Async. HO. + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != -1) + l1a_l1s_com.dedic_set.aset->ho_acc_to_send --; + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send == 0) + // Handover access procedure is completed. + // -> send L1C_HANDOVER_FINISHED message with "cause = COMPLETED" to L1A. + { + l1s_send_ho_finished(HO_COMPLETE); + } + } + + else + { + // TX burst is a Normal Burst. + // **************************** + // dsp pgm... + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.applied_txpwr) + #endif + + dsp_task = l1s_swap_iq_ul(tx_radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, + burst_id, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->tsc); + + // tpu pgm... + l1dtpu_serv_tx_nb(tx_radio_freq, + l1a_l1s_com.dedic_set.aset->timing_advance, + l1s.tpu_offset, + l1s.applied_txpwr,INACTIVE); + + // Catch UL data block from DLL and gives it to DSP. + // ************************************************** + // SDCCH info. + if(burst_id == BURST_1) + // perform "PH_DATA_REQ" from L2... + { + // Get SDCCH/UL data block from L2. + tx_data = dll_read_dcch(SIG_ONLY_MODE); + + // Store the UL data block in MCU/DSP interface. + if(tx_data != NULL) // NULL should never occur !!! + { + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + RTTL1_FILL_UL_DCCH + trace_info.facch_ul_count ++; + #endif + + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_cu, &(tx_data->A[0])); + } + } + } + + // In any case set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, tx_radio_freq); + + } // End if(task == DUL) + + else + // SACCH/UL task. + { + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != 0) + // "ho_acc_to_send" is a counter of Handover Access burst still to send. + // This counter is set by "l1s_dedicated_mode_manager()" in L1S when a + // Handover command is received from L3 through L1A. + // Rem: it is not allowed to send HO ACCESS burst on SACCH/UL. We must + // then avoid any normal burst transmission by setting txpwr=NO_TXPWR. The DSP + // and TPU are controled normally. + { + // Set TXPWR. + l1ddsp_load_txpwr(NO_TXPWR, tx_radio_freq); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, NO_TXPWR) + #endif + } + + else + { + // Set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, tx_radio_freq); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.applied_txpwr) + #endif + } + + //ADC Measurements + // + + // Check if during the SACCH burst an ADC measurement shall be performed + + if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_UL) // perform ADC only one time + { + adc_active_ul = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic + } + else + { + if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_UL) // perform ADC on each period bloc + { + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period + { + adc_active_ul = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + } + } + + + // In any case TX burst is a Normal Burst. + // **************************************** + // dsp pgm... + + dsp_task = l1s_swap_iq_ul(tx_radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, + burst_id, + l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->tsc); + + // tpu pgm... + l1dtpu_serv_tx_nb(tx_radio_freq, + l1a_l1s_com.dedic_set.aset->timing_advance, + l1s.tpu_offset, + l1s.applied_txpwr,adc_active_ul); + + + // Catch UL data block from DLL and gives it to DSP. + // ************************************************** + // SACCH info. + if(burst_id == BURST_1) + // perform "PH_DATA_REQ" from L2... + { + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + BOOL tx_data_flag = FALSE; //omaps00090550 + #endif + + #if (FF_REPEATED_SACCH == 1) + #if TESTMODE + if(l1_config.repeat_sacch_enable != REPEATED_SACCH_ENABLE) /* disable the repeated sacch mode */ + { + l1s.repeated_sacch.sro = 0; /* set no repetition order */ + l1s.repeated_sacch.buffer_empty = TRUE; /* set no buffer */ + } + #endif /* TESTMODE */ + #endif /* (FF_REPEATED_SACCH == 1) */ + #if (FF_REPEATED_SACCH == 1) + /* Get data from PS if only no repetition order is required (1st condition) + or no repetition candidate exists (2nd condition) */ + if( (l1s.repeated_sacch.sro == 0) || (l1s.repeated_sacch.buffer_empty == TRUE) ) +{ + #endif /* (FF_REPEATED_SACCH == 1) */ + tx_data = dll_read_sacch(SIG_ONLY_MODE); + + if(tx_data != NULL) // NULL should never occur !!! + { +#if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + tx_data_flag =TRUE; //omaps00090550 +#endif + // Set L1 Header... + tx_data->A[0] = l1s.reported_txpwr; + #if (FF_REPEATED_SACCH == 1) + /* Include the SACCH Repetition Request (SRR) in the L1 Header */ + tx_data->A[0] |= (l1s.repeated_sacch.srr <<6); + + #endif /* FF_REPEATED_SACCH */ + tx_data->A[1] = l1a_l1s_com.dedic_set.aset->timing_advance; + + // Store the UL data block in MCU/DSP interface. + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_cu, &(tx_data->A[0])); + #if (FF_REPEATED_SACCH == 1 ) + /* Store the block data in case of a retransmission order */ + /* Retransmission is done in case of a SAPI0 and not 3 */ + if(((tx_data->A[2]&0x1C) >> 2) == SAPI_0) + { + l1s_store_sacch_buffer( &(l1s.repeated_sacch), &(tx_data->A[0])); + } + else // FIXME FIXME NOT sure whether this needs to be done + { + /* the SACCH repetition block occurrence will always come as a consecutive pair */ + /* To handle DL UL | DL UL | DL UL */ + /* - 0 | SRO 3 | - new data should be asked from PS old 0 cannot be repeated */ + l1s.repeated_sacch.buffer_empty=TRUE; + } + #endif /* FF_REPEATED_SACCH */ + + }/* end of if(tx_data != NULL) */ +#if (FF_REPEATED_SACCH == 1) + } + + else if ((l1s.repeated_sacch.sro == 1) && (l1s.repeated_sacch.buffer_empty == FALSE)) + { + /* Put data block in MCU/DSP com. */ + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_cu, l1s.repeated_sacch.buffer ); + l1s.repeated_sacch.buffer_empty = TRUE; /* Set that the buffer is now empty (only one repetition) */ + } +#endif /* FF_REPEATED_SACCH */ + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + RTTL1_FILL_UL_SACCH(tx_data_flag,l1a_l1s_com.dedic_set.aset->timing_advance, l1s.reported_txpwr) //omaps00090550 + #endif + + } + } + + // Set tpu window identifier for Power meas after TX. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split; + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_TX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; +} + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_ctrl_nnb() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* neigbor cell normal burst reading tasks: BCCHN. */ +/* This function is the control function for reading 4 */ +/* normal bursts on a neighbor cell. It programs the DSP */ +/* and the TPU for reading the 4 bursts taking into */ +/* account the time difference between the serving and */ +/* the neighbor cells. To this avail, it shifts the TPU */ +/* OFFSET register according to this time difference and */ +/* restores the serving offset value when the 4 burst */ +/* reading are completed. Here is a summary of the */ +/* execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for required task. */ +/* - Programs TPU for required task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* BCCHN, BCCH Neighbor reading task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.Ncell_info.bcch" */ +/* cell information structure used for BCCHN task. */ +/* */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. Used here to check if */ +/* the Full BCCH Reading task is enabled and then to */ +/* take the decision to reloading the serving value */ +/* in the TPU OFFSET register. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for SYNCHRO and OFFSET register in the TPU */ +/* for current serving cell setting. At the end of */ +/* the task this value is restored in the OFFSET */ +/* register. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_nnb(UWORD8 task, UWORD8 param2) +{ + UWORD8 lna_off; + WORD8 agc; + T_NCELL_SINGLE *cell_info_ptr = NULL; + BOOL en_task; + BOOL task_param; + UWORD32 dsp_task; +#if(L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; + UWORD8 input_level; +#endif + +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + + + if((en_task) && !(task_param)) + // Check the task semaphore and enable flag. The control body is executed only + // when the task semaphore is 0 and enable flag is 1. The semaphore can be set to + // 1 whenever L1A makes some changes to the task parameters. The enable can be + // reset to 0 when the task is no more enabled. + { + // Get the cell information structure. + // ************************************ + if (task == BCCHN) + cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_norm]; + else // BCCHN_TOP and BCCHN_TRAN tasks + cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_top]; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_NNB, cell_info_ptr->radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 6) ; + + // Programs DSP for required task. + // ******************************** + + #if L1_GPRS + switch(l1a_l1s_com.dsp_scheduler_mode) + { + // dsp pgm is made using GSM scheduler... + case GSM_SCHEDULER: + dsp_task = l1s_swap_iq_dl(cell_info_ptr->radio_freq,task); + l1ddsp_load_rx_task(dsp_task, + 0, + cell_info_ptr->tsc); + break; + + // dsp pgm is made using GPRS scheduler... + case GPRS_SCHEDULER: + l1pddsp_load_bcchn_task(cell_info_ptr->tsc, cell_info_ptr->radio_freq); + break; + } + #else + // dsp pgm... + dsp_task = l1s_swap_iq_dl(cell_info_ptr->radio_freq,task); + l1ddsp_load_rx_task(dsp_task, + 0, + cell_info_ptr->tsc); + #endif + + // Programs TPU for required task. + // ******************************** + + // We program 4 burst reading. The OFFSET register is used to + // cope with the time difference between the serving and the + // neighbor cells. The serving cell offset value (l1s.tpu_offset) + // is restored at the end of the 4 burst reading. +#if (L1_FF_MULTIBAND == 0) + + lna_off = l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].lna_off; + // agc is computed from PGC2 algo result. + agc = Cust_get_agc_from_IL(cell_info_ptr->radio_freq, l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].input_level >> 1, AV_ID, lna_off); + +#else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(cell_info_ptr->radio_freq); + lna_off = l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + input_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; + // agc is computed from PGC2 algo result. + agc = Cust_get_agc_from_IL(cell_info_ptr->radio_freq, l1a_l1s_com.last_input_level[operative_radio_freq].input_level >> 1, AV_ID, lna_off); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, +#if (L1_FF_MULTIBAND == 0) + l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].input_level, +#else + input_level, +#endif + cell_info_ptr->radio_freq,if_threshold); + + //dco_algo_ctl has 0000 00ZL + dco_algo_ctl_nb *= 0x55; // replicate 0000 00zL as ZLZL ZLZL + + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, cell_info_ptr->radio_freq, + cell_info_ptr->time_alignmt, cell_info_ptr->fn_offset); + #endif + #endif + + #if (RF_FAM == 61) + if ( cell_info_ptr->time_alignmt >= TPU_CLOCK_RANGE - EPSILON_SYNC) + { + // Insert 1 NOP to correct the EPSILON_SYNC side effect + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 1, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,SAIC_OFF + #endif /* NEW_SNR_THRESHOLD == 1*/ + ); + } + else + { + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,SAIC_OFF + #endif /* NEW_SNR_THRESHOLD == 1*/ + ); + } + + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,SAIC_OFF + #endif /* NEW_SNR_THRESHOLD == 1*/ + ); + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,SAIC_OFF + #endif /* NEW_SNR_THRESHOLD == 1*/ + ); + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + TRUE, 0, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,SAIC_OFF + #endif /* NEW_SNR_THRESHOLD == 1*/ + ); + #endif // RF_FAM == 61 + + #if (RF_FAM != 61) + if ( cell_info_ptr->time_alignmt >= TPU_CLOCK_RANGE - EPSILON_SYNC) + { + // Insert 1 NOP to correct the EPSILON_SYNC side effect + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 1); + } + else + { + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0); + } + + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0); + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + FALSE, 0); + l1dtpu_neig_rx_nb(cell_info_ptr->radio_freq, + agc, + lna_off, + cell_info_ptr->time_alignmt, + l1s.tpu_offset, + TRUE, 0); + #endif // RF_FAM != 61 + } + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + + #if L1_GPRS + // This task is not compatible with Neigh. Measurement. Store task length + // in "forbid_meas" to indicate when the task will last. + if(task == BCCHN_TRAN) + { + // In IDLE mode, l1s.forbid_meas is setted by the AGC ctrl + l1s.forbid_meas = TASK_ROM_MFTAB[task].size; + } + #endif +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +/*-------------------------------------------------------*/ +/* l1s_ctrl_rach() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* serving cell Random Access burst sending tasks: RAAC, */ +/* RAHO. This function is the control function for */ +/* sending a random access burst to the serving cell. */ +/* This sending is either a Channel Request (connection */ +/* establishment) or a Handover Access burst (dedicated */ +/* mode). It programs the DSP and the TPU for sending a */ +/* random access burst with a null timing advance. */ +/* Here is a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Programs DSP for required task. */ +/* - Build RACH data block and store in MCU/DSP com. */ +/* - Programs TPU for required task. */ +/* - Send confirmation msg to L1A. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* RAAC, RACH sending task for Channel Request. */ +/* RAHO, RACH sending task for Handover Access. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* .radio_freq, serving cell beacon frequency. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. It is used here */ +/* to restore this value in the OFFSET register after */ +/* the TX burst programming. */ +/* */ +/* "l1s.applied_txpwr" */ +/* Applied transmit power. */ +/* */ +/* "l1a_l1s_com.ra_info" */ +/* random access task parameters. */ +/* .channel_request, random number sent in the case */ +/* of Channel Request (RAAC). */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> set to TDMA_WIN3. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_rach(UWORD8 task, UWORD8 param2) +{ + UWORD8 tx_data[2]; + UWORD16 radio_freq=0; + UWORD32 dsp_task; + UWORD8 adc_active=INACTIVE; + + // Get ARFCN to be used for current control. + // ******************************************* + + if(task == RAHO) + // Handover Access... + { + // The ARFCN comes from the HOPPING algorithm called + // prior to calling any CTRL function in the current frame. + radio_freq = l1a_l1s_com.dedic_set.radio_freq; + } + else + // Network Access... + { + #if TESTMODE + if (l1_config.TestMode) + { + // A TX_TCH task has been enabled in TestMode with burst_type=access burst. + // Thus set radio_freq to tch_arfcn . + radio_freq = l1_config.tmode.rf_params.tch_arfcn; + } + else + #endif + { + // The ARFCN is the BEACON frequency. + radio_freq = l1a_l1s_com.Scell_info.radio_freq; + } + } + + + // ADC measurement + // *************** + + // check if during the RACH an ADC measurement must be performed + if (task == RAACC) + if (l1a_l1s_com.adc_mode & ADC_EACH_RACH) // perform ADC on each burst + adc_active = ACTIVE; + + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_RACH, radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + #if (CODE_VERSION!=SIMULATION) + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + L1_trace_string("RA"); + #endif + #endif + + // Programs DSP for required task. + // ******************************** + + // dsp pgm... + + dsp_task = l1s_swap_iq_ul(radio_freq,task); + + l1ddsp_load_ra_task(dsp_task); + + // Set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, radio_freq); + + // Build RACH data block and store in MCU/DSP com. + // ************************************************ + + // RACH info. + if(task == RAACC) + // RACH data is only the "channel_request". (BYTE format data). + { + tx_data[0] = (l1a_l1s_com.Scell_info.bsic << 2); + tx_data[1] = l1a_l1s_com.ra_info.channel_request; + + } + else + // RACH data is only the "handover access" (BYTE format data). + { + tx_data[0] = (l1a_l1s_com.Scell_info.bsic << 2); + tx_data[1] = l1a_l1s_com.dedic_set.aset->ho_acc; + } + + // Store data block in MCU/DSP com. + l1ddsp_load_info(DSP_TASK_CODE[task], &(l1s_dsp_com.dsp_ndb_ptr->d_rach), &(tx_data[0])); + + // Programs TPU for required task. + // ******************************** + + // tpu pgm... + l1dtpu_serv_tx_ra(radio_freq, l1s.tpu_offset, l1s.applied_txpwr, adc_active); + + // Set tpu window identifier for Power meas if any. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_ra_load_split + l1_config.params.rx_synth_load_split; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_AB(task, l1s.applied_txpwr) + #endif + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_TX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_tchtd() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: This function controls the non transmitting slot in case of Half Rate TCH */ +/* ------------ */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_tchtd(UWORD8 task, UWORD8 param2) +{ + T_CHANNEL_DESCRIPTION *desc_ptr; + #if FF_L1_IT_DSP_DTX + BOOL dtx_dsp_interrupt = FALSE; + #endif + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[TCHD].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Catch channel description. + // *************************** + + // Catch the active channel description used along the routine. + // It contains: + // "channel_type", {TCH_F, TCH_H, SDCCH_4, SDCCH_8}. + // "subchannel", {0, 1}. 0 is the default value for TCH_F. + desc_ptr = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr; + + /**************************************************************************/ + /* TCH/Dummy Receive... */ + /**************************************************************************/ + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHT_DUMMY__DL, l1a_l1s_com.dedic_set.radio_freq); + #endif + + #if FF_L1_IT_DSP_DTX + // Fast DTX active only in TCH AHS + if ((l1a_l1s_com.dedic_set.aset->achan_ptr->mode == TCH_AHS_MODE) + && (l1a_l1s_com.dedic_set.aset->dtx_allowed == TRUE)) + { + // AHS0 + if (desc_ptr->subchannel == 0) + { + // DTX interrupt request for B1 and B2 (no DTX uncertainty on B0 thanks to idle frame) + if (l1s.next_time.fn_mod13 <= 7) + dtx_dsp_interrupt = TRUE; + } + + // AHS1 + else + { + // DTX interrupt requested for ALL blocks (idle frame does not help) + dtx_dsp_interrupt = TRUE; + } + } + #endif + + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + // dsp pgm. + l1ddsp_load_rx_task(DSP_TASK_CODE[task], 0, desc_ptr->tsc); + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + + // Set "CTRL_RX" flag in the controle flag register. + l1s.dsp_ctrl_reg |= CTRL_RX; + + + /*----------------------------------------------*/ + /* Common for Dedicated mode: DSP parameters... */ + /*----------------------------------------------*/ + #if (AMR == 1) + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + 0, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + #if !FF_L1_IT_DSP_DTX + 0); + #else + 0, + dtx_dsp_interrupt); + #endif + #endif + #else + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_tch); + #else + l1a_l1s_com.dedic_set.sync_tch, + dtx_dsp_interrupt); + #endif + #endif + #endif + + // Clear "sync_tch" and "reset_sacch" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_tch = FALSE; +#if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1a_l1s_com.dedic_set.reset_sacch = FALSE; +#endif + + // Set tpu window identifier for Power meas in case of dummy burst in Half-rate + l1s.tpu_win = 0; +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_tchth() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* dedicated mode TCH task: TCHTH. This function is the */ +/* control function for reading the DL burst and sending */ +/* the UL burst. The UL burst can be a Normal Burst in */ +/* normal case or an Access Burst when starting a */ +/* Handover procedure. Both Half rate and Full rate TCH */ +/* channel are handled. The DSP and the TPU are */ +/* programmed for both the DL and UL bursts. The timing */ +/* advance is taken into account for positionning the UL */ +/* burst. */ +/* */ +/* This function accesses the L1/DLL and L1/DATA */ +/* interface ("dll_read_dcch()", "tx_tch_data()" */ +/* functions respectively) and passes then the returned */ +/* data blocks to the DSP. */ +/* */ +/* Here is a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Catch channel description and ARFCN. */ +/* - TCH/T Receive... */ +/* - Program DSP for RX. */ +/* - Program TPU for RX. */ +/* - Flag DSP and TPU programmation. */ +/* - TCH/T Transmit... */ +/* - If Any Handover Access burst to send */ +/* - Call "l1s_ctrl_rach()". */ +/* - Else */ +/* - Get DATA block if required for TCH. */ +/* - Program DSP for TX. */ +/* - Program TPU for TX. */ +/* - Flag DSP and TPU programmation. */ +/* - Common for DL/UL: DSP parameters. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* TCHTH, Traffic Channel TCH Half rate. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set" */ +/* Dedicated channel parameter structure. */ +/* .radio_freq, ARFCN value set by the Hopping algo. */ +/* .aset, active dedicated parameter set. */ +/* */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. */ +/* */ +/* "l1s.applied_txpwr" */ +/* Applied transmit power. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> set to TDMA_WIN3. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_tchth(UWORD8 task, UWORD8 param2) +{ + UWORD16 radio_freq=0; + T_CHANNEL_DESCRIPTION *desc_ptr; + UWORD8 lna_off; + WORD8 agc; + T_INPUT_LEVEL *IL_info_ptr; + UWORD32 dsp_task; + UWORD32 fn_mod_52; + UWORD8 input_level; +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; +#if FF_L1_IT_DSP_DTX + BOOL dtx_dsp_interrupt=FALSE; //omaps00090550 +#endif +#if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; +#endif /* NEW_SNR_THRESHOLD */ + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[TCHTH].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Catch channel description and ARFCN. + // ************************************* + + // Catch the active channel description used along the routine. + // It contains: + // "channel_type", {TCH_F, TCH_H, SDCCH_4, SDCCH_8}. + // "subchannel", {0, 1}. 0 is the default value for TCH_F. + desc_ptr = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr; + + // Get ARFCN to be used for current control. This ARFCN comes from + // the HOPPING algorithm called just before calling this function. + radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon; + // we are working on a beacon freq. + else + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas; + // we are working on a daughter freq. + +#if FF_L1_IT_DSP_DTX + // Skip RX DSP/RF programming part during DTX HISR + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { +#endif + + /**************************************************************************/ + /* TCH/T Receive... */ + /**************************************************************************/ + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHTH__DL, radio_freq); + #endif + + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + + dsp_task = l1s_swap_iq_dl(radio_freq,task); + + // dsp pgm. + l1ddsp_load_rx_task(dsp_task, 0, desc_ptr->tsc); + + // Set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, radio_freq); + + input_level = IL_info_ptr->input_level ; + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + input_level , + radio_freq,if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + lna_off = IL_info_ptr->lna_off; + // for TCHTH we use DPAGC algorithm. + #if DPAGC_MAX_FLAG + agc = Cust_get_agc_from_IL(radio_freq, input_level >> 1, MAX_ID, lna_off); + #else + agc = Cust_get_agc_from_IL(radio_freq, input_level >> 1, AV_ID, lna_off); + #endif + + + // Store input_level and lna_off fields used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL = *IL_info_ptr; + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + ,&saic_flag + #endif + ); + #endif + + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // Program a serving cell normal burst reading in TPU. + #if (RF_FAM == 61) + l1dtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE,INACTIVE, csf_filter_choice, if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /*NEW_SNR_THRESHOLD */ + ); + #endif + #if (RF_FAM != 61) + l1dtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE,INACTIVE); + #endif + + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + RX_LOAD); + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; +#if FF_L1_IT_DSP_DTX + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) +#endif + + /**************************************************************************/ + /* TCH/T Transmit... */ + /**************************************************************************/ + + // Any Handover Access burst to send ? + // ************************************ + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != 0) + // "ho_acc_to_send" is a counter of Handover Access burst still to send. + // This counter is set by "l1s_dedicated_mode_manager()" in L1S when a + // Handover command is received from L3 through L1A. + // We must then replace the TCH UL normal burst by a RACH and decrement + // this counter. + { + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != -1) + l1a_l1s_com.dedic_set.aset->ho_acc_to_send --; + l1s_ctrl_rach(RAHO,NO_PAR); + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send == 0) + // Handover access procedure is completed. + // -> send L1C_HANDOVER_FINISHED message with "cause = COMPLETED" to L1A. + { + l1s_send_ho_finished(HO_COMPLETE); + } + } + else + // TCH/UL is a normal burst. + { + UWORD8 channel_mode = l1a_l1s_com.dedic_set.aset->achan_ptr->mode; + //omaps00090550 UWORD8 channel_type = desc_ptr->channel_type; + UWORD8 subchannel = desc_ptr->subchannel; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHTH__UL, radio_freq); + #endif + +#if FF_L1_IT_DSP_DTX + // FACCH and IDS handled during L1S, have to be skipped during DTX HISR + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { + #endif + + /*--------------------------------------------*/ + /* Get DATA block if required for TCH. */ + /*--------------------------------------------*/ + // Half rate traffic channel... + { + // Rem: time to get data block is + // Subchannel 0: FN%26 in {0, 8, 17}. + // Subchannel 1: FN%26 in {1, 9, 18}. + // => normalised time: FN_normalised = FN%26 - subchannel, in {0, 8, 17}. + // so CTL: must occur 2 TDMAs before, on + // Subchannel 0: FN%26 in {23, 6, 15}. + // Subchannel 1: FN%26 in {24, 7, 16}. + UWORD8 normalised_fn = l1s.next_time.t2 - subchannel; // FN%26 - subchannel + + if((normalised_fn == 23) || (normalised_fn == 6) || (normalised_fn == 15)) + // It is time to check if a FACCH/UL data block is available from DLL or + // if a data block is available from the DATA interface. + { + T_RADIO_FRAME *tx_data = NULL; + + // Check if any FACCH to transmit. + // Rem: when mode is "SIGNALLING ONLY" the "dll_read_dcch()" function + // always give back a block of FACCH (true block or dummy one). + tx_data = dll_read_dcch(channel_mode); + if(tx_data != NULL) + { + // In DTX mode in HS, all 6 FACCH 1/2 bursts must always be transmitted. + // Note: FACCH presence is checked 1 "control" before "control" of 1st burst of FACCH due to a DSP constraint + // i.e. 3 bursts before FACCH interleaving boundary + // So we must wait 1 control before controlling the transmission of 6 FACCH 1/2 bursts + l1s.facch_bursts = 7; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + RTTL1_FILL_UL_DCCH + trace_info.facch_ul_count ++; + #endif + + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_fu, &(tx_data->A[0])); + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsptx(dltsk_trace[TCHTH].name); + #endif + } + + #if (AMR == 1) + // Check if any DATA traffic info frame available. + // This check is used for all full rate channels except when + // this channel is in SIGNALLING ONLY mode or in Half Rate + // Speech mode or in adaptative Half Rate mode. + if((channel_mode != TCH_HS_MODE) && + (channel_mode != TCH_AHS_MODE) && + (channel_mode != SIG_ONLY_MODE)) + #else + // Check if any DATA traffic info frame available. + // This check is used for all full rate channels except when + // this channel is in SIGNALLING ONLY mode or in Half Rate + // Speech mode. + if((channel_mode != TCH_HS_MODE) && (channel_mode != SIG_ONLY_MODE)) + #endif + { + UWORD8 *tx_data = NULL; + + tx_data = tx_tch_data(); + if(tx_data != NULL) + { + // Store the DATA/UL data block in the MCU/DSP com. according + // to the "subchannel". + if(subchannel == 0) l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_0, tx_data); + else l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_1, tx_data); + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsptx(dltsk_trace[TCHTH].name); + #endif + } + } + } + } + +#if FF_L1_IT_DSP_DTX + // Fast DTX active only in TCH AHS + if ((l1a_l1s_com.dedic_set.aset->achan_ptr->mode == TCH_AHS_MODE) + && (l1a_l1s_com.dedic_set.aset->dtx_allowed == TRUE)) + { + // AHS0 + if (desc_ptr->subchannel == 0) + { + // DTX interrupt request for B1 and B2 (no DTX uncertainty on B0 thanks to idle frame) + if (l1s.next_time.fn_mod13 <= 7) + dtx_dsp_interrupt = TRUE; + + // DTX uncertainty check + if ((l1a_apihisr_com.dtx.fast_dtx_ready == TRUE) && // Fast DTX can be used + ((l1s.next_time.fn_mod13 == 4) || (l1s.next_time.fn_mod13 == 8))) // new block boundary + l1a_apihisr_com.dtx.dtx_status = DTX_AWAITED; + } + + // AHS1 + else + { + // DTX interrupt requested for ALL blocks (idle frame does not help) + dtx_dsp_interrupt = TRUE; + + // DTX uncertainty check + if ((l1a_apihisr_com.dtx.fast_dtx_ready == TRUE) && // Fast DTX can be used + ((l1s.next_time.fn_mod13 == 1) || (l1s.next_time.fn_mod13 == 5)|| (l1s.next_time.fn_mod13 == 9))) // new block boundary + l1a_apihisr_com.dtx.dtx_status = DTX_AWAITED; + } + } + else + l1a_apihisr_com.dtx.dtx_status = DTX_AVAILABLE; + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + + // Postpone TPU/DSP programming when DTX status not available from DSP + if (l1a_apihisr_com.dtx.dtx_status != DTX_AWAITED) + { + BOOL tx_active =FALSE; //omaps00090550 +#endif + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + + dsp_task = l1s_swap_iq_ul(radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, 0, desc_ptr->tsc); + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + + fn_mod_52 = l1s.actual_time.fn % 52; + + l1s.facch_bursts--; + if (l1s.facch_bursts < 0) + l1s.facch_bursts = -1; + #if FF_L1_IT_DSP_DTX + // Condition for TX TPU programming channel mode dependant + switch (channel_mode) + { + case SIG_ONLY_MODE: + case TCH_24H_MODE: + case TCH_48H_MODE: + // DTX not supported + tx_active = TRUE; + break; + + case TCH_HS_MODE: + if ((l1s.dtx_ul_on == FALSE) || // No DTX + ((l1s.facch_bursts >= 0) && (l1s.facch_bursts <= 5)) || // FACCH in progress + ((subchannel == 0) && ((fn_mod_52 == 51) || (/*(fn_mod_52 >= 0) && omaps00090550*/(fn_mod_52 <= 5)))) || // SID HS0 + ((subchannel == 1) && (fn_mod_52 >= 13) && (fn_mod_52 <= 19)) // SID HS1 + ) + tx_active = TRUE; + else + tx_active = FALSE; + break; + + case TCH_AHS_MODE: + if (l1a_apihisr_com.dtx.tx_active) // DSP (Fast) DTX status + tx_active = TRUE; + else + tx_active = FALSE; + break; + } + + // TPU TX burst programming + if (tx_active) + #else + + // In DTX mode, UL bursts should not be transmitted when no voice activity is detected + // we must not call TPU scenario if dtx_on == TRUE in HS (See Technical Memo) + // However, in DTX mode, several bursts must always be transmitted (See ETSI 05.08, 8.3) + if ( (channel_mode != TCH_HS_MODE) || + (l1s.dtx_ul_on == FALSE) || + ( (l1s.facch_bursts >= 0) && (l1s.facch_bursts <= 5) ) || + ( (subchannel == 0) && ((fn_mod_52 == 51) || ((fn_mod_52 >= 0) && (fn_mod_52 <= 5))) ) || + ( (subchannel == 1) && (fn_mod_52 >= 13) && (fn_mod_52 <= 19) )) + #endif + { + l1dtpu_serv_tx_nb(radio_freq, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.tpu_offset, l1s.applied_txpwr,INACTIVE); + } + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.applied_txpwr) + #endif + + #if FF_L1_IT_DSP_DTX + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_AWAITED) + #endif + } // TCH/UL is a normal burst. + + +#if FF_L1_IT_DSP_DTX + // Postpone TPU/DSP programming when DTX status not available from DSP + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { +#endif + + /*----------------------------------------------*/ + /* Common for Dedicated mode: DSP parameters... */ + /*----------------------------------------------*/ + #if (AMR == 1) + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.sync_amr, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_amr); + #else + l1a_l1s_com.dedic_set.sync_amr, + dtx_dsp_interrupt); + #endif + #endif + + // Clear "sync_amr" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_amr = FALSE; + #else + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_tch); + #else + l1a_l1s_com.dedic_set.sync_tch, + dtx_dsp_interrupt); + #endif + #endif + #endif + + // reset the FACCH header of the API buffer on the control following an ABORT to avoid decoding unwanted FACCH + if (l1a_l1s_com.dedic_set.reset_facch == TRUE) + { + // Reset A_FD header. + // B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 + l1s_dsp_com.dsp_ndb_ptr->a_fd[0] = (1<a_fd[2] = 0xffff; + } + + // Clear "sync_tch" and "reset_sacch" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_tch = FALSE; + l1a_l1s_com.dedic_set.reset_facch = FALSE; +#if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1a_l1s_com.dedic_set.reset_sacch = FALSE; +#endif + + // Set tpu window identifier for Power meas. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split; + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + + // Set "CTRL_TX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; +#if FF_L1_IT_DSP_DTX + } //if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) +#endif +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_tchtf() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* dedicated mode TCH task: TCHTF. This function is the */ +/* control function for reading the DL burst and sending */ +/* the UL burst. The UL burst can be a Normal Burst in */ +/* normal case or an Access Burst when starting a */ +/* Handover procedure. Both Half rate and Full rate TCH */ +/* channel are handled. The DSP and the TPU are */ +/* programmed for both the DL and UL bursts. The timing */ +/* advance is taken into account for positionning the UL */ +/* burst. */ +/* */ +/* This function accesses the L1/DLL and L1/DATA */ +/* interface ("dll_read_dcch()", "tx_tch_data()" */ +/* functions respectively) and passes then the returned */ +/* data blocks to the DSP. */ +/* */ +/* Here is a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Catch channel description and ARFCN. */ +/* - TCH/T Receive... */ +/* - Program DSP for RX. */ +/* - Program TPU for RX. */ +/* - Flag DSP and TPU programmation. */ +/* - TCH/T Transmit... */ +/* - If Any Handover Access burst to send */ +/* - Call "l1s_ctrl_rach()". */ +/* - Else */ +/* - Get DATA block if required for TCH. */ +/* - Program DSP for TX. */ +/* - Program TPU for TX. */ +/* - Flag DSP and TPU programmation. */ +/* - Common for DL/UL: DSP parameters. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* TCHTF, Traffic Channel TCH Full rate. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set" */ +/* Dedicated channel parameter structure. */ +/* .radio_freq, ARFCN value set by the Hopping algo. */ +/* .aset, active dedicated parameter set. */ +/* */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. */ +/* */ +/* "l1s.applied_txpwr" */ +/* Applied transmit power. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> set to TDMA_WIN3. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_tchtf(UWORD8 task, UWORD8 param2) +{ + UWORD16 radio_freq=0; + T_CHANNEL_DESCRIPTION *desc_ptr; + UWORD8 lna_off; + WORD8 agc; + T_INPUT_LEVEL *IL_info_ptr; + UWORD32 dsp_task; + UWORD32 fn_mod_104; +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb; + UWORD8 if_ctl =0 ; //omaps00090550 + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; +#if FF_L1_IT_DSP_DTX + BOOL dtx_dsp_interrupt = FALSE; +#endif +#if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag; +#endif + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[TCHTF].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Catch channel description and ARFCN. + // ************************************* + + // Catch the active channel description used along the routine. + // It contains: + // "channel_type", {TCH_F, TCH_H, SDCCH_4, SDCCH_8}. + // "subchannel", {0, 1}. 0 is the default value for TCH_F. + desc_ptr = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr; + + // Get ARFCN to be used for current control. This ARFCN comes from + // the HOPPING algorithm called just before calling this function. + radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon; + // we are working on a beacon freq. + else + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas; + // we are working on a daughter freq. + +#if FF_L1_IT_DSP_DTX + // Skip RX DSP/RF programming part during DTX HISR + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { +#endif + + /**************************************************************************/ + /* TCH/T Receive... */ + /**************************************************************************/ + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHTF__DL, radio_freq); + #endif + + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + // dsp pgm. + + dsp_task = l1s_swap_iq_dl(radio_freq,task); + + l1ddsp_load_rx_task(dsp_task, 0, desc_ptr->tsc); + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + IL_info_ptr->input_level , + radio_freq,if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + #if TESTMODE + // if Normal Mode or + // if TestMode DL+UL + // NOTE: UL only true if DL is true in TCHTF! + if ( !l1_config.TestMode || + (l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK))) + #endif + { + // Set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, radio_freq); + } + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + + lna_off = IL_info_ptr->lna_off; + // for TCHTF we use DPAGC algorithm. + #if DPAGC_MAX_FLAG + agc = Cust_get_agc_from_IL(radio_freq, IL_info_ptr->input_level >> 1, MAX_ID, lna_off); + #else + agc = Cust_get_agc_from_IL(radio_freq, IL_info_ptr->input_level >> 1, AV_ID, lna_off); + #endif + + + // Store input_level and lna_off fields used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL = *IL_info_ptr; + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + ,&saic_flag + #endif + ); + #endif + + #if TESTMODE + // Continuous mode: Rx TPU programmation only in NO_CONTINUOUS or START_RX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_RX_CONTINUOUS)) + #endif + { + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // Program a serving cell normal burst reading in TPU. + l1dtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE,INACTIVE + #if (RF_FAM == 61) + ,csf_filter_choice + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /*NEW_SNR_THRESHOLD*/ + ); + } + + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + RX_LOAD); + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + + // Set "CTRL_RX" flag in the controle flag register. + + #if TESTMODE + // Continuous mode: swap TPU page for Rx only in NO_CONTINUOUS or START_RX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_RX_CONTINUOUS)) + #endif + { + l1s.tpu_ctrl_reg |= CTRL_RX; + } + l1s.dsp_ctrl_reg |= CTRL_RX; +#if FF_L1_IT_DSP_DTX + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) +#endif + + /**************************************************************************/ + /* TCH/T Transmit... */ + /**************************************************************************/ + + // Any Handover Access burst to send ? + // ************************************ + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != 0) + // "ho_acc_to_send" is a counter of Handover Access burst still to send. + // This counter is set by "l1s_dedicated_mode_manager()" in L1S when a + // Handover command is received from L3 through L1A. + // We must then replace the TCH UL normal burst by a RACH and decrement + // this counter. + { + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != -1) + l1a_l1s_com.dedic_set.aset->ho_acc_to_send --; + l1s_ctrl_rach(RAHO,NO_PAR); + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send == 0) + // Handover access procedure is completed. + // -> send L1C_HANDOVER_FINISHED message with "cause = COMPLETED" to L1A. + { + l1s_send_ho_finished(HO_COMPLETE); + } + } + else + // TCH/UL is a normal burst. + { + UWORD8 channel_mode = l1a_l1s_com.dedic_set.aset->achan_ptr->mode; + //OMAPS00090550 UWORD8 channel_type = desc_ptr->channel_type; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHTF__UL, radio_freq); + #endif + +#if FF_L1_IT_DSP_DTX + // FACCH and IDS handled during L1S, have to be skipped during DTX HISR + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { +#endif + /*--------------------------------------------*/ + /* Get DATA block if required for TCH. */ + /*--------------------------------------------*/ + // Full rate traffic channel... + { + UWORD8 fn_report_mod13_mod4 = (l1s.next_time.fn_in_report % 13) % 4; + + if(fn_report_mod13_mod4 == 3) + // It is time to check if a FACCH/UL data block is available from DLL or + // if a data block is available from the DATA interface. + { + T_RADIO_FRAME *tx_data = NULL; + + // Check if any FACCH to transmit. + // Rem: when mode is "SIGNALLING ONLY" the "dll_read_dcch()" function + // always gives back a block of FACCH (true block or dummy one). + // In ETM test mode, the protocol stack is not active and hence we do not require any FACCH data from L23 + // But this change is applicable only when ETM scripts are run with PS-builds. In case of L1-SA, + // dll_read_dcch() is called which is just a stub function (It just returns a NULL ptr for L1 SA) + #if TESTMODE + #if (OP_L1_STANDALONE == 0) + if(!l1_config.TestMode) + #endif // (OP_L1_STANDALONE == 0) + #endif // TESTMODE + { + tx_data = dll_read_dcch(channel_mode); + } + + if(tx_data != NULL) + { + // In DTX mode in FR and EFR, all 8 FACCH 1/2 bursts must always be transmitted. + // Note: FACCH presence is checked 1 "control" before "control" of 1st burst of FACCH due to a DSP constraint + // i.e. 2 bursts before FACCH interleaving boundary + //So we must wait 1 burst before controlling the transmission of 8 FACCH 1/2 bursts + l1s.facch_bursts = 9; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + RTTL1_FILL_UL_DCCH + trace_info.facch_ul_count ++; + #endif + + // Store the FACCH/UL data block in the MCU/DSP com. + #if TRACE_TYPE==3 + if (l1_stats.type == PLAY_UL) + { + // load A_DU_1 in PLAY Uplink mode. + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_1, &(tx_data->A[0])); + + + if (channel_mode == TCH_EFR_MODE) + { + WORD32 bit5word14, bit2word14, bit12word15, bit15word15; + + // clear CRC bits and repetition bits + l1s_dsp_com.dsp_ndb_ptr->a_du_1[7] &= 0x807f; + l1s_dsp_com.dsp_ndb_ptr->a_du_1[14] &= 0xfc24; + l1s_dsp_com.dsp_ndb_ptr->a_du_1[15] &= 0x93ff; + l1s_dsp_com.dsp_ndb_ptr->a_du_1[19] &= 0xff00; + + // read repetition bits + bit5word14 = (l1s_dsp_com.dsp_ndb_ptr->a_du_1[14] >> 5)& 0x1; + bit2word14 = (l1s_dsp_com.dsp_ndb_ptr->a_du_1[14] >> 2)& 0x1; + bit12word15 = (l1s_dsp_com.dsp_ndb_ptr->a_du_1[15] >> 12) & 0x1; + bit15word15 = (l1s_dsp_com.dsp_ndb_ptr->a_du_1[15] >> 15)& 0x1; + + // copy repetition bits + l1s_dsp_com.dsp_ndb_ptr->a_du_1[14] |= + (bit5word14 << 4 | bit5word14 << 3 | + bit2word14 | bit2word14 << 1); + + l1s_dsp_com.dsp_ndb_ptr->a_du_1[15] |= + (bit15word15 << 13 | bit12word15 << 14 | + bit12word15 << 10 | bit15word15 << 11); + } + else + { + l1s_dsp_com.dsp_ndb_ptr->a_du_1[14] &= 0xfc3f; + l1s_dsp_com.dsp_ndb_ptr->a_du_1[19] &= 0xff00; + } + + // set PLAY Uplink bit ....... + l1s_dsp_com.dsp_ndb_ptr->d_tch_mode |= (1 << B_PLAY_UL); + } + else + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_fu, &(tx_data->A[0])); + #else + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_fu, &(tx_data->A[0])); + #endif + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsptx(dltsk_trace[TCHTF].name); + #endif + } + + #if (AMR == 1) + // Check if any DATA traffic info frame available. + // This check is used for all full rate channels except when + // this channel is in SIGNALLING ONLY mode or in Full Rate + // Speech mode or adaptative full rate mode. + if((channel_mode != TCH_FS_MODE) && + (channel_mode != SIG_ONLY_MODE) && + (channel_mode != TCH_EFR_MODE) && + (channel_mode != TCH_AFS_MODE)) + #else + // Check if any DATA traffic info frame available. + // This check is used for all full rate channels except when + // this channel is in SIGNALLING ONLY mode or in Full Rate + // Speech mode. + if((channel_mode != TCH_FS_MODE) && + (channel_mode != SIG_ONLY_MODE) && + (channel_mode != TCH_EFR_MODE)) + #endif + { + #if IDS + { + UWORD8 fn_report_mod26; + API *data_ul; + + data_ul = l1s_dsp_com.dsp_ndb_ptr->a_du_0; + fn_report_mod26 = l1s.next_time.fn_in_report%26; + + // Set flag for UL/DL block information: for TCH/F48 mode only + if((channel_mode == TCH_48F_MODE) && ((fn_report_mod26 == 7) || (fn_report_mod26 == 16) + || (fn_report_mod26 == 24))) + l1s_dsp_com.dsp_ndb_ptr->d_ra_act |= (3 << B_F48BLK); + else + l1s_dsp_com.dsp_ndb_ptr->d_ra_act &= ~(3 << B_F48BLK); + dll_data_ul(l1s_dsp_com.dsp_ndb_ptr->a_data_buf_ul, &l1s_dsp_com.dsp_ndb_ptr->d_ra_conf, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_act, &l1s_dsp_com.dsp_ndb_ptr->d_ra_test, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_statu, &l1s_dsp_com.dsp_ndb_ptr->d_fax); + + // Fill a_du_0 data block Header. + // Note: a_du_0 header is fill when dummy block is filled as well when data block + // is filled (buffer a_data_buf_ul + data_ul[0] = (1 << B_BLUD); // 1st word: Set B_BLU bit. + data_ul[1] = 0; // 2nd word: cleared. + data_ul[2] = 0; // 3rd word: cleared. + + } + #else + { + UWORD8 *tx_data = NULL; + + tx_data = tx_tch_data(); + if(tx_data != NULL) + { + // Store the DATA/UL data block in the MCU/DSP com. + #if TRACE_TYPE==3 + if (l1_stats.type == PLAY_UL) + { + // load A_DU_1 in PLAY Uplink mode. + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_1, tx_data); + if (channel_mode == TCH_48F_MODE) + l1s_dsp_com.dsp_ndb_ptr->a_du_1[10] &= 0x00ff; + if (channel_mode == TCH_24F_MODE) + l1s_dsp_com.dsp_ndb_ptr->a_du_1[7] &= 0x00ff; + // set PLAY Uplink bit ....... + l1s_dsp_com.dsp_ndb_ptr->d_tch_mode |= (1 << B_PLAY_UL); + } + else + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_0, tx_data); + #else + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_du_0, tx_data); + #endif + } + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsptx(dltsk_trace[TCHTF].name); + #endif + } + #endif + } + } + } + +#if FF_L1_IT_DSP_DTX + // Fast DTX active only in TCH AFS, for TDMA3 from speech block = 0, 1 [MOD 3] + if ((l1a_l1s_com.dedic_set.aset->achan_ptr->mode == TCH_AFS_MODE) + && (l1a_l1s_com.dedic_set.aset->dtx_allowed == TRUE)) + { + // DTX interrupt request for B1 and B2 (no DTX uncertainty on B0 thanks to idle frame) + if (l1s.next_time.fn_mod13 <= 7) + dtx_dsp_interrupt = TRUE; + + // DTX uncertainty check + if ((l1a_apihisr_com.dtx.fast_dtx_ready == TRUE) && // Fast DTX can be used + ((l1s.next_time.fn_mod13 == 4) || (l1s.next_time.fn_mod13 == 8))) // new block boundary + l1a_apihisr_com.dtx.dtx_status = DTX_AWAITED; + } + else + l1a_apihisr_com.dtx.dtx_status = DTX_AVAILABLE; + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + + // Postpone TPU/DSP programming when DTX status not available from DSP + if (l1a_apihisr_com.dtx.dtx_status != DTX_AWAITED) + { + BOOL tx_active =FALSE; //omaps00090550 +#endif + #if TESTMODE + // if Normal Mode or + // if TestMode and UL+DL + // NOTE: UL only true if DL is true in TCHTF! + if ( !l1_config.TestMode || + (l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK))) + #endif + { + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + + dsp_task = l1s_swap_iq_ul(radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, 0, desc_ptr->tsc); + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + + fn_mod_104 = l1s.actual_time.fn % 104; + + #if TESTMODE + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_TX_CONTINUOUS)) + #endif + { + l1s.facch_bursts--; + if (l1s.facch_bursts < 0) + l1s.facch_bursts = -1; + + #if FF_L1_IT_DSP_DTX + // Condition for TX TPU programming channel mode dependant + switch (channel_mode) + { + case SIG_ONLY_MODE: + case TCH_24F_MODE: + case TCH_48F_MODE: + case TCH_96_MODE: + case TCH_144_MODE: + // DTX not supported + tx_active = TRUE; + break; + + case TCH_FS_MODE: + case TCH_EFR_MODE: + if ((l1s.dtx_ul_on == FALSE) || // No DTX + ((l1s.facch_bursts >= 0) && (l1s.facch_bursts <= 7)) || // FACCH in progress + ((fn_mod_104 >= 51) && (fn_mod_104 <= 58)) // SID + ) + tx_active = TRUE; + else + tx_active = FALSE; + break; + + case TCH_AFS_MODE: + if (l1a_apihisr_com.dtx.tx_active) // DSP (Fast) DTX status + tx_active = TRUE; + else + tx_active = FALSE; + break; + } + + // TPU TX burst programming + if (tx_active) + #else + // In DTX mode, UL bursts should not be transmitted when no voice activity is detected + // we must not call TPU scenario if dtx_on == TRUE in EFR and FR (See Technical Memo) + // However, in DTX mode, bursts 52 to 59 (modulo 104) must always be transmitted + // FACCH must also be transmitted but we must wait 1 bursts before transmitting 8 1/2 bursts + if ( ((channel_mode != TCH_FS_MODE) && (channel_mode != TCH_EFR_MODE)) || + (l1s.dtx_ul_on == FALSE) || + ( (l1s.facch_bursts >= 0) && (l1s.facch_bursts <= 7) ) || + ((fn_mod_104 >= 51) && (fn_mod_104 <= 58)) ) + #endif + { + l1dtpu_serv_tx_nb(radio_freq, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.tpu_offset, l1s.applied_txpwr,INACTIVE); + } + } + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.applied_txpwr) + #endif + + } + #if FF_L1_IT_DSP_DTX + } // if (l1a_apihisr_com.dtx.dtx_status != DTX_AWAITED) + #endif + } // TCH/UL is a normal burst. +#if FF_L1_IT_DSP_DTX + // Postpone TPU/DSP programming when DTX status not available from DSP + if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + { +#endif + + /*----------------------------------------------*/ + /* Common for Dedicated mode: DSP parameters... */ + /*----------------------------------------------*/ + #if (AMR == 1) + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + 0, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.sync_amr, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + 0, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_amr); + #else + l1a_l1s_com.dedic_set.sync_amr, + dtx_dsp_interrupt); + #endif + #endif + + // Clear "sync_amr" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_amr = FALSE; + #else + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + 0, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + dtx_dsp_interrupt); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + 0, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_tch); + #else + l1a_l1s_com.dedic_set.sync_tch, + dtx_dsp_interrupt); + #endif + #endif + #endif + + // reset the FACCH header of the API buffer on the control following an ABORT to avoid decoding unwanted FACCH + if (l1a_l1s_com.dedic_set.reset_facch == TRUE) + { + // Reset A_FD header. + // B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 + l1s_dsp_com.dsp_ndb_ptr->a_fd[0] = (1<a_fd[2] = 0xffff; + } + + // Clear "sync_tch" and "reset_sacch" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_tch = FALSE; + l1a_l1s_com.dedic_set.reset_facch = FALSE; +#if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1a_l1s_com.dedic_set.reset_sacch = FALSE; +#endif + + // Set tpu window identifier for Power meas or FS/SB search. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split; + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + + #if TESTMODE + // if Normal Mode or + // if TestMode and UL+DL + // NOTE: UL only true if DL is true in TCHTF! + if ( !l1_config.TestMode || + ( l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK))) + #endif + { + #if TESTMODE + // Continuous mode: swap TPU page for Tx in NO_CONTINUOUS or START_TX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_TX_CONTINUOUS)) + #endif + { + l1s.tpu_ctrl_reg |= CTRL_TX; + } + l1s.dsp_ctrl_reg |= CTRL_TX; + } + + #if TESTMODE + // Continuous mode: if end of control of START_RX/TX: go to CONTINUOUS state + if (l1_config.TestMode && (l1_config.tmode.rf_params.tmode_continuous != TM_NO_CONTINUOUS)) + l1_config.tmode.rf_params.tmode_continuous = TM_CONTINUOUS; + #endif +#if FF_L1_IT_DSP_DTX + } //if (l1a_apihisr_com.dtx.dtx_status != DTX_IT_DSP) + #endif +} + +/*-------------------------------------------------------*/ +/* l1s_ctrl_tcha() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* dedicated mode TCH task: TCHA. This function is the */ +/* control function for reading the DL burst and sending */ +/* the UL burst on the Slow Associated Channel (SACCH) */ +/* associated with the traffic channel. The UL burst can */ +/* be a Normal Burst in normal case or an Access Burst */ +/* when starting a Handover procedure. Both Half rate */ +/* and Full rate TCH channel are handled. The DSP and */ +/* the TPU are programmed for both the DL and UL bursts. */ +/* The timing advance is taken into account for */ +/* positionning the UL burst. */ +/* */ +/* This function accesses the L1/DLL interface */ +/* ("dll_read_sacch()" function) and passes then the */ +/* returned data blocks to the DSP after having set the */ +/* L1 header part of the block. */ +/* */ +/* Here is a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Catch channel description and ARFCN. */ +/* - TCH/SACCH Receive... */ +/* - Program DSP for RX. */ +/* - Program TPU for RX. */ +/* - Flag DSP and TPU programmation. */ +/* - TCH/SACCH Transmit... */ +/* - If Any Handover Access burst to send */ +/* - Call "l1s_ctrl_rach()". */ +/* - Else */ +/* - Get DATA block from DLL if required. */ +/* - Program DSP for TX. */ +/* - Program TPU for TX. */ +/* - Flag DSP and TPU programmation. */ +/* - Common for DL/UL: DSP parameters. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* TCHA, Associated channel task when dedicated/TCH. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set" */ +/* Dedicated channel parameter structure. */ +/* .radio_freq, ARFCN value set by the Hopping algo. */ +/* .aset, active dedicated parameter set. */ +/* */ +/* "l1a_l1s_com.Scell_info" */ +/* Serving cell information structure. */ +/* .bsic, BSIC of the serving cell. It is used here */ +/* to pass the training sequence number (part */ +/* of BSIC) to the DSP. */ +/* */ +/* "l1s.afc" */ +/* current AFC value to be applied for the given task. */ +/* */ +/* "l1s.tpu_offset" */ +/* value for the TPU SYNCHRO and OFFSET registers */ +/* for current serving cell setting. */ +/* */ +/* "l1s.applied_txpwr" */ +/* Applied transmit power. */ +/* */ +/* "l1s.reported_txpwr" */ +/* Transmit power to report in the L1 header of the */ +/* SACCH data block. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.tpu_win" */ +/* each frame is composed with a maximum of 3 */ +/* working/TPU windows (typically RX/TX/PW). This is */ +/* a counter used to count the number of windows */ +/* used. */ +/* -> set to TDMA_WIN3. */ +/* */ +/* "l1s.tpu_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/TPU com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/* "l1s.dsp_ctrl_reg" */ +/* bit register used to know at the end of L1S if */ +/* something has been programmed on the MCU/DSP com. */ +/* This is used mainly to swap then the com. page at */ +/* the end of a control frame. */ +/* -> set CTRL_RX bit in the register. */ +/* -> set CTRL_TX bit in the register. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_ctrl_tcha(UWORD8 task, UWORD8 param2) +{ + UWORD16 radio_freq=0; + T_CHANNEL_DESCRIPTION *desc_ptr; + UWORD8 lna_off =0;//omaps00090550 + WORD8 agc =0; //omaps00090550 + T_INPUT_LEVEL *IL_info_ptr; + UWORD32 dsp_task; + UWORD8 adc_active_ul = INACTIVE; + UWORD8 adc_active_dl = INACTIVE; +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; +#if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; +#endif /*NEW_SNR_THRESHOLD */ + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[TCHA].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Catch channel description and ARFCN. + // ************************************* + + // Catch the active channel description used along the routine. + // It contains: + // "channel_type", {TCH_F, TCH_H, SDCCH_4, SDCCH_8}. + // "subchannel", {0, 1}. 0 is the default value for TCH_F. + desc_ptr = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr; + + // Get ARFCN to be used for current control. + radio_freq = l1a_l1s_com.dedic_set.radio_freq; + + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon; + // we are working on a beacon freq. + else + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas; + // we are working on a daughter freq. + + /**************************************************************************/ + /* SACCH Receive... */ + /**************************************************************************/ + + // ADC measurement + // *************** + + // check if during the SACCH burst an ADC measurement must be performed + if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_DL) // perform ADC only one time + { + adc_active_dl = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic + } + else + if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_DL) // perform ADC on each period bloc + if (l1s.next_time.fn_in_report == 12) //periodic with each 1st SACCH burst + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period + { + adc_active_dl = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + + #if TESTMODE + // if Normal Mode or + // if TestMode and DL-only or DL+UL + if ( !l1_config.TestMode || + (l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_DOWNLINK))) + #endif + { + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHA___DL, radio_freq); + #endif + + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + // dsp pgm. + + dsp_task = l1s_swap_iq_dl(radio_freq,task); + l1ddsp_load_rx_task(dsp_task, 0, desc_ptr->tsc); + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID , + IL_info_ptr->input_level , + radio_freq,if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + lna_off = IL_info_ptr->lna_off; + // for TCHA we use DPAGC algorithm. + #if DPAGC_MAX_FLAG + agc = Cust_get_agc_from_IL(radio_freq, IL_info_ptr->input_level >> 1, MAX_ID, lna_off); + #else + agc = Cust_get_agc_from_IL(radio_freq, IL_info_ptr->input_level >> 1, AV_ID, lna_off); + #endif + + + + // Store input_level and lna_off fields used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL = *IL_info_ptr; + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + csf_filter_choice = l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + ,&saic_flag + #endif + ); + #endif + + #if TESTMODE + // Continuous mode: Rx TPU programmation only in NO_CONTINUOUS or START_RX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_RX_CONTINUOUS)) + #endif + { + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // Program a serving cell normal burst reading in TPU. + l1dtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE,adc_active_dl + #if (RF_FAM == 61) + ,csf_filter_choice + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /* NEW_SNR_THRESHOLD */ + ); + } + + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + RX_LOAD); + + // Set "CTRL_RX" flag in the control flag register. + #if TESTMODE + // Continuous mode: swap TPU page for Rx only in NO_CONTINUOUS or START_RX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_RX_CONTINUOUS)) + #endif + { + l1s.tpu_ctrl_reg |= CTRL_RX; + } + l1s.dsp_ctrl_reg |= CTRL_RX; + + } + + /**************************************************************************/ + /* TCH/T Transmit... */ + /**************************************************************************/ + + // Any Handover Access burst to send ? --> TXPWR management + // ************************************ + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send != 0) + // "ho_acc_to_send" is a counter of Handover Access burst still to send. + // This counter is set by "l1s_dedicated_mode_manager()" in L1S when a + // Handover command is received from L3 through L1A. + // When Handover access is in progress, nothing but RACH can be transmitted. + // RACH is not allowed on SACCH therefore TX is avoided by setting + // the txpwr to NO_TXPWR !!! + { + // NOTE: The spec says RACH bursts on SACCH UL is optional. hence it should not be counted + // Refer spec 04.08 + l1s_ctrl_rach(RAHO,NO_PAR); + } + else + // TCH/UL is a normal burst. + // TX power must be the normal one + { + // Set TXPWR. + l1ddsp_load_txpwr(l1s.applied_txpwr, radio_freq); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.applied_txpwr) + #endif + + // ADC measurement + // *************** + + // check if during the SACCH burst an ADC measurement must be performed + if (l1a_l1s_com.adc_mode & ADC_NEXT_TRAFFIC_UL) // perform ADC only one time + { + adc_active_ul = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_TRAFFIC; // reset in order to have only one ADC measurement in Traffic + } + else + if (l1a_l1s_com.adc_mode & ADC_EACH_TRAFFIC_UL) // perform ADC on each period bloc + if (l1s.next_time.fn_in_report == 12) //periodic with each 1st SACCH burst + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period + { + adc_active_ul = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + + + // In any case (normal TX or no TX due to Handover Access process) + // the full TCHA task must be controled for TPU and DSP. + { + T_RADIO_FRAME *tx_data = NULL; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_CTRL_TCHA___UL, radio_freq); + #endif + + /*--------------------------------------------*/ + /* Get DATA block if required for SACCH. */ + /*--------------------------------------------*/ + if(l1s.next_time.fn_in_report == 12) + // It is time to get a SACCH data block from DLL. + // Call "dll_read_sacch()" to perform "PH_DATA_REQ" and pass + // the data block to the DSP.. + { + #if ((FF_REPEATED_SACCH) && ( TESTMODE)) + if(l1_config.repeat_sacch_enable != REPEATED_SACCH_ENABLE) + { + l1s.repeated_sacch.sro = 0; + l1s.repeated_sacch.buffer_empty = TRUE; + } + #endif /* #if ((FF_REPEATED_SACCH) && ( TESTMODE)) */ +#if FF_REPEATED_SACCH + /* Get data from PS if only no repetition order is required (1st condition) */ + /* or no repetition candidate exists (2nd condition) */ + if((l1s.repeated_sacch.sro == 0) || (l1s.repeated_sacch.buffer_empty == TRUE)) +#endif /* FF_REPEATED_SACCH */ + { + tx_data = dll_read_sacch(SIG_ONLY_MODE); + if(tx_data != NULL) + { + // Set L1 Header... + tx_data->A[0] = l1s.reported_txpwr; + tx_data->A[1] = l1a_l1s_com.dedic_set.aset->timing_advance; + + #if FF_REPEATED_SACCH + /* Include the SACCH Repetition Request (SRR) in the L1 Header */ + tx_data->A[0] |= (l1s.repeated_sacch.srr <<6); + #endif /* FF_REPEATED_SACCH */ + // Put data block in MCU/DSP com. + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_cu, &(tx_data->A[0])); + #if (FF_REPEATED_SACCH == 1 ) + if(((tx_data->A[2]&0x1C) >> 2) == SAPI_0) /* Store the block data in case of a retransmission order */ + { + l1s_store_sacch_buffer( &(l1s.repeated_sacch), &(tx_data->A[0])); + /* Stores the buffer and turns of the buffer_empty flag as false */ + } + else + { + /* the SACCH repetition block occurrence will always come as a consecutive pair */ + /* To handle DL UL | DL UL | DL UL */ + /* - 0 | SRO 3 | - new data should be asked from PS old 0 cannot be repeated */ + l1s.repeated_sacch.buffer_empty=TRUE; + } + #endif /* FF_REPEATED_SACCH */ + } /* if(tx_data != NULL) */ + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsptx(dltsk_trace[TCHA].name); + #endif + }/* if((l1s.repeated_sacch.sro == 0) || (l1s.repeated_sacch.buffer_empty == TRUE))*/ + #if FF_REPEATED_SACCH + else if ((l1s.repeated_sacch.sro == 1) && (l1s.repeated_sacch.buffer_empty == FALSE)) + { + /* Put data block in MCU/DSP com. */ + l1ddsp_load_info(DSP_TASK_CODE[task], l1s_dsp_com.dsp_ndb_ptr->a_cu, l1s.repeated_sacch.buffer ); + l1s.repeated_sacch.buffer_empty = TRUE; /* Set that the buffer is now empty (only one repetition) */ + } /* end else repetition */ + #endif /* FF_REPEATED_SACCH */ + // check to be removed + } + + /*--------------------------------------------*/ + /* Program DSP... */ + /*--------------------------------------------*/ + #if TESTMODE + // UL-only... + // Use SPI to write to Omega uplink buffer, do NOT use DSP + if (l1_config.TestMode && l1_config.tmode.rf_params.down_up == TMODE_UPLINK) + { + #if (CODE_VERSION != SIMULATION) + // For Calyso+ & Before... + #if (RF_FAM == 12) + ABB_Write_Register_on_page(PAGE0, AUXAPC, Cust_get_pwr_data(l1s.applied_txpwr, radio_freq + #if(REL99 && FF_PRF) + ,1 + #endif + )); + l1tm_fill_burst(l1_config.tmode.tx_params.burst_data, &TM_ul_data[0]); + ABB_Write_Uplink_Data(&TM_ul_data[0]); + #endif + + //For UppCosto, Tx Data Write is via PLD to DRP & Ramp is via the ABB Driver + #if (RF_FAM == 60) + ABB_Write_Register_on_page(PAGE0, AUXAPC, Cust_get_pwr_data(l1s.applied_txpwr, radio_freq + #if(REL99 && FF_PRF) + ,1 + #endif + )); + l1tm_fill_burst(l1_config.tmode.tx_params.burst_data, &TM_ul_data[0]); + PLD_Write_Uplink_Data(&TM_ul_data[0]); + #endif + + #if (RF_FAM == 61) + // For DRP we use the DSP to write the TX Power via a new variable apclev in API + // A new variable is required in API as DSP copies the tx_power_ctl (which is + // normally used to pass the APCLEV value to DSP) to APCLEV ONLY when there is a + // burst to be transmitted + l1ddsp_apc_load_apclev(Cust_get_pwr_data(l1s.applied_txpwr, radio_freq + #if(REL99 && FF_PRF) + ,1 + #endif + )); + l1tm_fill_burst(l1_config.tmode.tx_params.burst_data, &TM_ul_data[0]); + DRP_Write_Uplink_Data(&TM_ul_data[0]); + #endif + + #endif + } + // Use DSP... + // if Normal Mode or + // if TestMode and DL+UL + else if ( !l1_config.TestMode || + (l1_config.TestMode && l1_config.tmode.rf_params.down_up == (TMODE_DOWNLINK|TMODE_UPLINK))) + { + dsp_task = l1s_swap_iq_ul(radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, 0, desc_ptr->tsc); + } + #else + dsp_task = l1s_swap_iq_ul(radio_freq,task); + + l1ddsp_load_tx_task(dsp_task, 0, desc_ptr->tsc); + #endif + + /*--------------------------------------------*/ + /* Program TPU... */ + /*--------------------------------------------*/ + #if TESTMODE + // if Normal Mode or + // if TestMode and UL-only or DL+UL + if ( !l1_config.TestMode || + (l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK) && + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS || + l1_config.tmode.rf_params.tmode_continuous == TM_START_TX_CONTINUOUS))) + #endif + { + l1dtpu_serv_tx_nb(radio_freq, l1a_l1s_com.dedic_set.aset->timing_advance, l1s.tpu_offset, l1s.applied_txpwr, adc_active_ul); + } + } + + } // End of "TCH/UL is a normal burst" + + /*----------------------------------------------*/ + /* Common for Dedicated mode: DSP parameters... */ + /*----------------------------------------------*/ + + #if (AMR == 1) + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.sync_amr, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + 0); + #endif + #else // FF_L1_TCH_VOCODER_CONTROL + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_amr); + #else + l1a_l1s_com.dedic_set.sync_amr, + 0); + #endif + #endif // FF_L1_TCH_VOCODER_CONTROL + + l1a_l1s_com.dedic_set.sync_amr = FALSE; + + #else // AMR + #if (FF_L1_TCH_VOCODER_CONTROL == 1) + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + l1a_l1s_com.dedic_set.sync_tch, + l1a_l1s_com.dedic_set.reset_sacch, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.vocoder_on); + #else + l1a_l1s_com.dedic_set.vocoder_on, + 0); + #endif + #else + l1ddsp_load_tch_param(&(l1s.next_time), + l1a_l1s_com.dedic_set.aset->achan_ptr->mode, + desc_ptr->channel_type, + desc_ptr->subchannel, + l1a_l1s_com.dedic_set.aset->achan_ptr->tch_loop, + #if !FF_L1_IT_DSP_DTX + l1a_l1s_com.dedic_set.sync_tch); + #else + l1a_l1s_com.dedic_set.sync_tch, + 0); + #endif + #endif + #endif // AMR + + // Clear "sync_tch" flag to maintain normal TCH process. + l1a_l1s_com.dedic_set.sync_tch = FALSE; +#if (FF_L1_TCH_VOCODER_CONTROL) + l1a_l1s_com.dedic_set.reset_sacch = FALSE; +#endif + + if(l1a_l1s_com.dedic_set.aset->ho_acc_to_send == 0) + { + // Set tpu window identifier for Power meas or FS/SB search. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split; + + /*--------------------------------------------*/ + /* Flag DSP and TPU programmation... */ + /*--------------------------------------------*/ + #if TESTMODE + // if Normal Mode or + // if TestMode and UL-only or DL+UL + if ( !l1_config.TestMode || + (l1_config.TestMode && (l1_config.tmode.rf_params.down_up & TMODE_UPLINK))) + #endif + { + #if TESTMODE + // Continuous mode: swap TPU page for Tx in NO_CONTINUOUS or START_TX_CONTINUOUS mode. + if ((!l1_config.TestMode) || + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS) || + (l1_config.tmode.rf_params.tmode_continuous == TM_START_TX_CONTINUOUS)) + #endif + { + l1s.tpu_ctrl_reg |= CTRL_TX; + } + l1s.dsp_ctrl_reg |= CTRL_TX; + } + + #if TESTMODE + // Continuous mode: if end of control of START_RX/TX: go to CONTINUOUS state + if (l1_config.TestMode && (l1_config.tmode.rf_params.tmode_continuous != TM_NO_CONTINUOUS)) + l1_config.tmode.rf_params.tmode_continuous = TM_CONTINUOUS; + #endif + } + +} + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_hopping_algo() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* dedicated mode tasks: DDL, DUL, ADL, AUL, TCHTH/F and */ +/* TCHA. This function performs the Hopping Sequence */ +/* generation. It computes the ARFCN to use on the next */ +/* frame. When the channel does not hop, it returns */ +/* the fixe ARFCN provided in the channel description. */ +/* */ +/* If the channel is hopping and the ARFCN result is the */ +/* BEACON frequency, an indication flag is set to warn */ +/* the DSP ("b_bcch_freq_ind"). */ +/* */ +/* (see GSM05.02 $6.2.3) */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.dedic_set.aset" */ +/* Active set of Dedicated channel parameters. */ +/* */ +/* "l1s.l1s.next_time" */ +/* frame number and derived numbers for next frame. */ +/* */ +/* Returned parameter in globals: */ +/* ------------------------------ */ +/* */ +/* "l1a_l1s_com.dedic_set.radio_freq" */ +/* ARFCN to be used on the next frame. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_hopping_algo(UWORD8 task, UWORD8 param2) +{ + UWORD8 mai; + T_CHN_SEL *chan_sel; + T_MOBILE_ALLOCATION *alist_ptr; + + UWORD16 *ma; + UWORD8 n; + UWORD8 hsn; + UWORD8 maio; + UWORD16 *radio_freq_ptr; + UWORD16 *beacon_channel_ptr=&l1a_l1s_com.Scell_info.radio_freq; // beacon channel of the serving cell + T_TIME_INFO *time_ptr; + T_TIME_INFO next_neighbor_time; + + + switch(task) + { + +#if L1_GPRS + case PTCCH: + { + chan_sel = &(l1pa_l1ps_com.transfer.aset->freq_param.chan_sel); + alist_ptr = &(l1pa_l1ps_com.transfer.aset->freq_param.freq_list); + radio_freq_ptr = &l1pa_l1ps_com.transfer.ptcch.radio_freq; + time_ptr = &l1s.next_time; + } + break; + + case PDTCH: + case SINGLE: + // For PDTCH, set pointers to the PACKET parameter structures. + { + chan_sel = &(l1pa_l1ps_com.transfer.aset->freq_param.chan_sel); + alist_ptr = &(l1pa_l1ps_com.transfer.aset->freq_param.freq_list); + radio_freq_ptr = &l1a_l1s_com.dedic_set.radio_freq; + time_ptr = &l1s.next_time; + } + break; + + case PALLC: + case PNP: + case PEP: + { + chan_sel = &l1pa_l1ps_com.pccch.packet_chn_desc.chan_sel; + alist_ptr = &l1pa_l1ps_com.pccch.frequency_list; + radio_freq_ptr = &l1pa_l1ps_com.p_idle_param.radio_freq; + time_ptr = &l1s.next_time; + } + break; + + case POLL: + { + // Load adequat freq. list according to the current mode: + // SINGLE (i.e. 2 phase access) else Packet Access or Packet Idle + if(l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED) + { + chan_sel = &(l1pa_l1ps_com.transfer.aset->freq_param.chan_sel); + alist_ptr = &(l1pa_l1ps_com.transfer.aset->freq_param.freq_list); + radio_freq_ptr = &l1a_l1s_com.dedic_set.radio_freq; + } + else + { + chan_sel = &l1pa_l1ps_com.pccch.packet_chn_desc.chan_sel; + alist_ptr = &l1pa_l1ps_com.pccch.frequency_list; + radio_freq_ptr = &l1pa_l1ps_com.p_idle_param.radio_freq; + } + time_ptr = &l1s.next_time; + } + break; + + case PBCCHS: + { + chan_sel = &l1pa_l1ps_com.pbcchs.packet_chn_desc.chan_sel; + alist_ptr = &l1pa_l1ps_com.pbcchs.frequency_list; + radio_freq_ptr = &l1pa_l1ps_com.p_idle_param.radio_freq; + + // If PBCCHS controlled one frame in advance --> correct Frame Number when PBCCH block is read + if (l1pa_l1ps_com.pbcchs.control_offset) + time_ptr = &l1s.next_plus_time; + else + time_ptr = &l1s.next_time; + } + break; + + case PBCCHN_IDLE: + case PBCCHN_TRAN: + { + WORD32 next_neighbor_time_fn; + + chan_sel = &l1pa_l1ps_com.pbcchn.packet_chn_desc.chan_sel; + alist_ptr = &l1pa_l1ps_com.pbcchn.frequency_list; + radio_freq_ptr = &l1pa_l1ps_com.p_idle_param.radio_freq; + beacon_channel_ptr = &l1pa_l1ps_com.pbcchn.bcch_carrier; + time_ptr = &next_neighbor_time; + + // To review (is there any better solution?)........... + next_neighbor_time_fn = l1s.next_time.fn + l1pa_l1ps_com.pbcchn.fn_offset; + + if (next_neighbor_time_fn > ((WORD32)MAX_FN))//OMAPS00090550 + next_neighbor_time.fn = (UWORD32) (next_neighbor_time_fn - MAX_FN); + else if (next_neighbor_time_fn < 0) + next_neighbor_time.fn = (UWORD32) (next_neighbor_time_fn + MAX_FN); + else + next_neighbor_time.fn = (UWORD32) (next_neighbor_time_fn); + + next_neighbor_time.t1 = next_neighbor_time.fn / (26L*51L); // T1 = FN div 26*51 + next_neighbor_time.t2 = next_neighbor_time.fn % 26; // T2 = FN % 26. + next_neighbor_time.t3 = next_neighbor_time.fn % 51; // T3 = FN % 51. + } + break; + + case ITMEAS: + { + // Packet transfer mode + if (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) + { + // We use the active TBF frequency parameters + chan_sel = &(l1pa_l1ps_com.transfer.aset->freq_param.chan_sel); + alist_ptr = &(l1pa_l1ps_com.transfer.aset->freq_param.freq_list); + } + + // Packet idle mode + else + { + // We use the frequency parameters given in the MPHP_INT_MEAS_REQ message + chan_sel = &(l1pa_l1ps_com.itmeas.packet_intm_freq_param.chan_sel); + alist_ptr = &(l1pa_l1ps_com.itmeas.packet_intm_freq_param.freq_list); + } + + radio_freq_ptr = &l1pa_l1ps_com.itmeas.radio_freq; + time_ptr = &l1s.next_plus_time; + } + break; + +#endif + + case SMSCB: + // For SMSCB, set pointers to the SMSCB parameter structures. + { + chan_sel = &l1a_l1s_com.cbch_desc.chan_sel; + alist_ptr = &l1a_l1s_com.cbch_freq_list; + radio_freq_ptr = &l1a_l1s_com.dedic_set.radio_freq; + + // If SMSCB is controlled one frame in advance --> correct Frame Number when SMSCB block is read + if (l1a_l1s_com.pre_scheduled_cbch) + time_ptr = &l1s.next_plus_time; + else + time_ptr = &l1s.next_time; + } + break; + + default: + // For SDCCH/TCH, set pointers to the active channel description. + { + chan_sel = &(l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->chan_sel); + alist_ptr = l1a_l1s_com.dedic_set.aset->ma.alist_ptr; + radio_freq_ptr = &l1a_l1s_com.dedic_set.radio_freq; + time_ptr = &l1s.next_time; + } + } // End of switch(task) + + // Set local variables. + ma = &(alist_ptr->rf_chan_no.A[0]); + n = alist_ptr->rf_chan_cnt; + hsn = chan_sel->rf_channel.hopping_rf.hsn; + maio = chan_sel->rf_channel.hopping_rf.maio; + + if(chan_sel->h == FALSE) + // Single RF channel, NOT HOPPING. + { + *radio_freq_ptr = chan_sel->rf_channel.single_rf.radio_freq; + } + + else + // Hopping channel... + { + /**************************************************/ + /* Perform the HOPPING algorithm. */ + /**************************************************/ + if(hsn == 0) + // Cyclic hopping... + { + mai = (time_ptr->fn + maio) % n; + } + else + { + UWORD8 i = 0; + UWORD8 m; + UWORD8 mp; + UWORD8 nbin =0; //omaps00090550 + UWORD8 tp; + UWORD8 s; + UWORD8 t1r = (UWORD8)(time_ptr->t1 % 64); + + while(i<=6) + { + if((n >> i) > 0) nbin = i; + i++; + } + nbin++; + + m = time_ptr->t2 + RNTABLE[(hsn ^ t1r) + time_ptr->t3]; + mp = m % (1L << nbin); + tp = time_ptr->t3 % (1L << nbin); + + if(mp < n) s = mp; + else s = (mp + tp) % n; + + mai = (s + maio) % n; + } + + *radio_freq_ptr = ma[mai]; + } + + if(*radio_freq_ptr == *beacon_channel_ptr) + // If ARFCN is the BEACON... + { + // Set "b_bcch_freq_ind" to TRUE. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= (1 << B_BCCH_FREQ_IND); + + } +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +//===============================================================================================// + +#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 + +/*-------------------------------------------------------*/ +/* l1s_read_dummy() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task: ABORT. Since this task just aborts any ongoing */ +/* DSP task, there is no result returned by the DSP to */ +/* the MCU when this abort is completed, but the MCU/DSP */ +/* com. read page must be switched properly. This the */ +/* only reason why we have created this function. */ +/* */ +/* Modified parameter in globals: */ +/* ------------------------------ */ +/* */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_dummy(UWORD8 task, UWORD8 param2) +{ + l1_check_com_mismatch(task); + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_DUMMY ,(UWORD32)(-1));//OMAPS00090550 + #endif + + // task is completed, make it INACTIVE (only in case of TCHD). + if(task == TCHD) + l1s.task_status[task].current_status = INACTIVE; + + #if FF_L1_IT_DSP_DTX + // Fast DTX status update + if(task == TCHD) + { + UWORD8 subchannel = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->subchannel; + + // Currently used for TCH-AHS only + if (((subchannel == 0) && (l1s.actual_time.fn_mod13_mod4 == 0)) || // FN%13 = 4, 8 and 12 for TCH/H0 (no Read on FN%13=0) + ((subchannel == 1) && (l1s.actual_time.fn_mod13_mod4 == 1))) // FN%13 = 1, 5 and 9 for TCH/H1 + { + // Latch TX activity status if DTX allowed + if ((l1a_l1s_com.dedic_set.aset->dtx_allowed == FALSE) || // No DTX allowed + (l1s_dsp_com.dsp_ndb_ptr->d_fast_dtx_enc_data ) || // DTX allowed but not used + (l1a_apihisr_com.dtx.fast_dtx_ready == FALSE)) // Fast DTX status is invalid + l1a_apihisr_com.dtx.tx_active = TRUE; + else + l1a_apihisr_com.dtx.tx_active = FALSE; + } + } + #endif + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + +/*-------------------------------------------------------*/ +/* l1s_read_msagc() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: BCCHN,FBNEW,SB1,SB2,SBCONF. This function is */ +/* the reading result function used for reading a power */ +/* measurement result used then to refreshing the AGC */ +/* for those tasks. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Get the cell information structure. */ +/* - Traces and debug. */ +/* - Read receive level result from MCU/DSP interface.*/ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* BCCHN, BCCH Neighbor reading task. */ +/* FBNEW, Frequency Burst detection task in Idle mode. */ +/* SB1, Synchro Burst reading task in Idle mode. */ +/* SB2, Synchro Burst detection task in Idle mode. */ +/* SBCONF, Synchro Burst confirmation task in Idle */ +/* mode. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.Ncell_info.bcch" */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* "l1a_l1s_com.Ncell_info.acquis" */ +/* "l1a_l1s_com.Ncell_info.conf" */ +/* cell information structure used for BCCHN,FBNEW, */ +/* SB1/SB2,SBCONF respectively. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_msagc(UWORD8 task, UWORD8 param2) +{ + BOOL en_task; + BOOL task_param; + UWORD16 pm_level[2]={0}; //omaps00090550 +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + T_NCELL_SINGLE *cell_info_ptr = NULL; + #if (L1_GPRS) + T_NCELL_SINGLE pbcchn_cell_info; + #endif +#if ((REL99 == 1) && (FF_BHO == 1)) + T_NCELL_SINGLE bho_cell_info; +#endif + + // Get the cell information structure. + // ************************************ + + switch(task) + { + case BCCHN_TOP: cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_top ]; break; + case BCCHN: cell_info_ptr = &l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_norm ]; break; + case FBNEW: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id]; break; + case SB2: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; break; + case SBCONF: cell_info_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sbconf_id]; break; +#if ((REL99 == 1) && (FF_BHO == 1)) + case FBSB: + { + cell_info_ptr = &bho_cell_info; + bho_cell_info.radio_freq = l1a_l1s_com.nsync_fbsb.radio_freq; + bho_cell_info.fn_offset = l1a_l1s_com.nsync_fbsb.fn_offset; + } + break; +#endif + #if (L1_GPRS) + case PBCCHN_IDLE: + { + cell_info_ptr = &pbcchn_cell_info; + pbcchn_cell_info.radio_freq = l1pa_l1ps_com.pbcchn.bcch_carrier; + pbcchn_cell_info.fn_offset = l1pa_l1ps_com.pbcchn.fn_offset; + } + break; + #endif + + default: return; + } + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_MSAGC , cell_info_ptr->radio_freq); + #endif + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, cell_info_ptr->radio_freq, + cell_info_ptr->fn_offset, pm); + #endif + #endif + + l1_check_com_mismatch(MS_AGC_ID); + + // Read receive level result from MCU/DSP interface. + // ************************************************** + // Read 2 received levels... + #if L1_GPRS + switch (l1a_l1s_com.dsp_scheduler_mode) + { + case GPRS_SCHEDULER: + { + // Call the reading driver using GPRS scheduler + l1pddsp_meas_read(2, pm_level); + } break; + + case GSM_SCHEDULER: + { + // Call the reading driver using GSM scheduler + l1ddsp_meas_read(2, pm_level); + } break; + } + #else + l1ddsp_meas_read(2, pm_level); + #endif + + // Power Measurement performed during last l1s_ctrl_msagc with HIGH_AGC + // returned in pm_level[0] + // Power measurement performed during last l1s_ctrl_msagc with LOW_AGC + // returned in pm_level[1] + + l1_check_pm_error(pm_level[0], MS_AGC_ID); + l1_check_pm_error(pm_level[1], MS_AGC_ID); + + pm_level[0] = pm_level[0] >> 5; + pm_level[1] = pm_level[1] >> 5; + + l1ctl_pgc2(((UWORD8 )(pm_level[0])),((UWORD8 )(pm_level[1])),cell_info_ptr->radio_freq); + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_LNA) + + #if (L1_FF_MULTIBAND == 0) + buffer_trace (4, 22, cell_info_ptr->radio_freq, + l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].input_level, + l1a_l1s_com.last_input_level[cell_info_ptr->radio_freq - l1_config.std.radio_freq_index_offset].lna_off); + + #else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(cell_info_ptr->radio_freq); + buffer_trace (4, 22, cell_info_ptr->radio_freq, + l1a_l1s_com.last_input_level[cell_info_ptr->agc_index].input_level, + l1a_l1s_com.last_input_level[cell_info_ptr->agc_index].lna_off); + + #endif // #if (L1_FF_MULTIBAND == 0) else + + #endif + #endif + } + + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_read_mon_result() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: FBNEW,SB1,SB2,SBCONF,SB51,SBCNF51,SB26,SBCNF26.*/ +/* This function is the reading result function used for */ +/* reading the neighbor cell monitoring results. Here is */ +/* a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Get task result from MCU/DSP read interface. */ +/* */ +/* - case: FBNEW/FB51. */ +/* - If SEMAPHORE(task) is low. */ +/* - Update AFC if required. */ +/* - Read FB detection results. */ +/* - Reports results to L1A. */ +/* - Disactivate and Disable task. */ +/* - Reset buffers and flags in NDB. */ +/* */ +/* - case: FB26. */ +/* - Read FB detection results. */ +/* - Reports results to L1A. */ +/* - Disactivate task. */ +/* */ +/* - case: SB26/SBCNF26. */ +/* - Read SB reading results. */ +/* - Reports results to L1A. */ +/* - Disactivate task. */ +/* */ +/* - case: SB1/SB2/SB51/SBCONF/SBCNF51. */ +/* - If SEMAPHORE(task) is low. */ +/* - Update AFC if required. */ +/* - Read FB detection results. */ +/* - Reports results to L1A. */ +/* - Disactivate task when required. */ +/* */ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* FBNEW, Frequency Burst detection task in Idle mode. */ +/* SB1, Synchro Burst reading task in Idle mode. */ +/* SB2, Synchro Burst detection task in Idle mode. */ +/* SBCONF, Synchro Burst confirmation task in Idle */ +/* mode. */ +/* SB51, Synchro Burst reading task in SDCCH Dedicated */ +/* mode. */ +/* SBCNF51, Synchro Burst confirmation task in SDCCH */ +/* Dedicated mode. */ +/* SB26, Synchro Burst reading task in TCH Dedicated */ +/* mode. */ +/* SBCNF26, Synchro Burst confirmation task in TCH */ +/* Dedicated mode. */ +/* */ +/* "attempt_for_sb2" */ +/* Since SB2 calls twice this function, this parameter */ +/* tells the function which call it it. Used mainly */ +/* to know when to DISACTIVATE the task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip the body */ +/* of this function if L1A has changed or is changing */ +/* some of the task parameters. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* -> disable FBNEW,FB51 task. */ +/* */ +/* "l1s.task_status[task].current_status" */ +/* current task status. It must be reset (INACTIVE) */ +/* when the task is completed. */ +/* -> disactivate task. */ +/* */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/* Use of MCU/DSP interface: */ +/* ------------------------- */ +/* "l1s_dsp_com.dsp_ndb_ptr" */ +/* pointer to the non double buffered part (NDB) of */ +/* the MCU/DSP interface. This part is R/W for both */ +/* DSP and MCU. */ +/* */ +/* "l1s_dsp_com.dsp_db_r_ptr" */ +/* pointer to the double buffered part (DB) of the */ +/* MCU/DSP interface. This pointer points to the READ */ +/* page. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_mon_result(UWORD8 task, UWORD8 attempt) +{ + UWORD32 flag=0; + UWORD32 toa; + UWORD32 pm; + UWORD32 angle; + UWORD32 snr; + + #if TESTMODE + UWORD32 pm_fullres; + #endif + + API *data; + + BOOL en_task; + BOOL task_param; + UWORD32 fb_abort_flag=0; + + /*-------------------------------------------------------------------------------*/ + /* READ MONITORING TASK RESULTS FROM MCU/DSP INTERFACE... */ + /*-------------------------------------------------------------------------------*/ + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + // Traces and debug. + // ****************** + #if (TRACE_TYPE!=0)&& (TRACE_TYPE !=5) + trace_fct(CST_L1S_READ_MON_RESULT,(UWORD32)(-1)); + #endif + + if(!(en_task) || (task_param)) + { + #if (TRACE_TYPE!=0) + // Current task is no more alive, L1A changed the task parameters. + // -> Trace "ABORT" on log file and screen. + trace_fct(CST_TASK_KILLED, (UWORD32)(-1)); + #endif + } + else + // Current task is still alive, check task identifier and debug number... + { + #if (TRACE_TYPE!=0) + if((task != FB26) && (task != SB26) && (task != SBCNF26)) // DB cannot be used for FB26/SB26/SBCNF26 result. + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_md & 0xffff) != + (UWORD32)DSP_TASK_CODE[task]) + // Task id. different than the one expected... + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND,(UWORD32)(-1)); + #endif + + if((task != FB26) && (task != SB26) + && (task != SBCNF26) && (attempt==12) + #if ((REL99 == 1) && (FF_BHO == 1)) + && (task != FBSB) + #endif + ) // DB cannot be used for FB26/SB26/SBCNF26 result. + { + l1_check_com_mismatch(task); + } + } + + // Get task result from MCU/DSP read interface. + // ********************************************* + + switch(task) + { + case FBNEW : + case FB51 : + /*---------------------------------------------------*/ + /* Frequency burst detection result... */ + /*---------------------------------------------------*/ + { + if((en_task)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + flag = l1s_dsp_com.dsp_ndb_ptr->d_fb_det & 0xffff; // 1 means FOUND. + toa = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff); + // WARNING... to be used!!! + #if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F26.6 + #endif + angle = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_ANGLE] & 0xffff; // WARNING... to be used!!! + snr = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_SNR] & 0xffff; // WARNING... to be used!!! + + + // Check FB detection flag and attempt: + // If no detection and attempt < 12 than continue FB search + // Attempt=11: special case: wait for next (last) read, as + // other task may already be programmed in MFTAB (do not flush !!!) + if(((!flag) && (attempt < 11)) || (attempt==11)) + break; + + // If FB detection occurs before 11th attempt, abort FB search + if((flag == TRUE) && (attempt < 11)) + fb_abort_flag=TRUE; + + + if (fb_abort_flag == TRUE) + { + if ((l1s_dsp_com.dsp_db_r_ptr->d_debug & 0xffff) != ((l1s.debug_time + (12 - attempt)) % 65536)) + l1_check_com_mismatch(task); + } + +// l1_check_pm_error(pm, task); + pm = pm >> 5; + + #if TRACE_TYPE==3 + stats_samples_fb(flag,toa,pm,angle,snr); + #endif + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(FB51); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + WORD16 old_afc=l1s.afc; + + if((flag == TRUE) && (l1a_l1s_com.mode == CS_MODE)) + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_OPEN_LOOP, + &l1s.afc_frame_count, + (WORD16)angle, + 0, + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_OPEN_LOOP, + &l1s.afc_frame_count, + (WORD16)angle, + 0, + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq,l1a_l1s_com.mode); + #endif + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_AFC_OPEN) + buffer_trace (4,(WORD16)angle,old_afc,l1s.afc,0); + #endif + #endif + } + } + #endif + + // Call FB report function (send report msg to L1A). + #if TESTMODE + if (l1_config.TestMode) + l1s_read_fb(task, flag, toa, attempt, pm_fullres, angle, snr); + else + l1s_read_fb(task, flag, toa, attempt, pm, angle, snr); + #else + l1s_read_fb(task, flag, toa, attempt, pm, angle, snr); + #endif + + // The Frequency Burst detection task in Idle (FBNEW) and + // Dedicated/SDCCH (FB51) are 1 shot tasks, they must be + // disabled in L1S when they are completed. Disable it. + l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED; + + // the status is not used in D51 and D26 modes + if (task != FB51 ) + { + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].status = NSYNC_COMPLETED; + } + } + + if ((fb_abort_flag == TRUE) || (attempt==12)) + { + // FB task is completed, make it INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + + // Reset buffers and flags in NDB ... + l1s_dsp_com.dsp_ndb_ptr->d_fb_det = FALSE; + l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] = 0; + + // This task is not compatible with Neigh. Measurement. + // Clear "forbid_meas" to indicate when the task is complete. + l1s.forbid_meas = 0; + } + + // FB search finished before 11th attempt: + // -reset DSP R/W pages, DSP tasks and TPU + // -flush MFTAB and reset frame count + // -adjust debug time + if(fb_abort_flag) + { + l1d_reset_hw(l1s.tpu_offset); + l1s.tpu_ctrl_reg |= CTRL_FB_ABORT; // set CTRL bit -> tpu_end_scenario + l1s_clear_mftab(l1s.mftab.frmlst); + l1s.frame_count = 0; + + // This task is not compatible with Neigh. Measurement. + // Clear "forbid_meas" to indicate when the task is complete. + l1s.forbid_meas = 0; + } + } + break; + + case FB26 : + /*---------------------------------------------------*/ + /* Frequency burst detection result... */ + /*---------------------------------------------------*/ + { + UWORD8 neigh_id; + + // read cell identifier. + neigh_id = l1a_l1s_com.nsync.active_fb_id; + + if((en_task)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + flag = l1s_dsp_com.dsp_ndb_ptr->d_fb_det & 0xffff; // 1 means FOUND. + toa = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff); + // WARNING... to be used!!! + #if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F10.6 + #endif + + // CQ 19836: do not check PM on FB26 + //l1_check_pm_error(pm, task); + pm = pm >> 5; + + angle = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_ANGLE] & 0xffff; // WARNING... to be used!!! + snr = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_SNR] & 0xffff; // WARNING... to be used!!! + + // Call FB report function (send report msg to L1A). + #if TESTMODE + if (l1_config.TestMode) + l1s_read_fb(task, flag, toa, NO_PAR, pm_fullres, angle, snr); + else + l1s_read_fb(task, flag, toa, NO_PAR, pm, angle, snr); + #else + l1s_read_fb(task, flag, toa, NO_PAR, pm, angle, snr); + #endif + } + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(FB26); + #endif + + + // The Frequency Burst detection task in Dedicated/TCH + // is composed with several attempts managed in L1A. + // -> task is completed: set INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + + // Reset buffers and flags in NDB ... + l1s_dsp_com.dsp_ndb_ptr->d_fb_det = FALSE; + l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] = 0; + } + break; + + case SB26 : + case SBCNF26 : + /*---------------------------------------------------*/ + /* Synchro. burst detection result... */ + /*---------------------------------------------------*/ + { + if((en_task) && !(task_param)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + flag = !(((l1s_dsp_com.dsp_ndb_ptr->a_sch26[0] & 0xffff) & (1<> B_SCH_CRC); // 1 means ERROR. + toa = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff); + // WARNING... to be used!!! + #if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F26.6 + #endif + + angle = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_SNR] & 0xffff; + data = &(l1s_dsp_com.dsp_ndb_ptr->a_sch26[3]); // Set data block pointer (skip header). + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + // Call SB report function (send report msg to L1A). + #if TESTMODE + if (l1_config.TestMode) + l1s_read_sb(task, flag, data, toa, attempt, pm_fullres, angle, snr); + else + l1s_read_sb(task, flag, data, toa, attempt, pm, angle, snr); + #else + l1s_read_sb(task, flag, data, toa, attempt, pm, angle, snr); + #endif + } + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(SB26); + #endif + + + // The Synchro Burst detection (SB26) and confirmation (SBCNF26) + // tasks in Dedicated/TCH are enabling/disabling are fully + // managed by L1A. + // -> task is completed: set INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + + // Reset buffers and flags in NDB ... + l1s_dsp_com.dsp_ndb_ptr->a_sch26[0] = (1<a_sch[0] & 0xffff) & (1<> B_SCH_CRC); // 1 means ERROR. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + // WARNING... to be used!!! + #if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F26.6 + #endif + + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + data = &(l1s_dsp_com.dsp_db_r_ptr->a_sch[3]); // Set data block pointer (skip header). + + l1ddsp_read_iq_dump(task); + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + // CQ30474. In case SNR is too low, the SB shall be considered as failed. + // This is valuable for code running on target with DSP 3606. +#if (CODE_VERSION == NOT_SIMULATION) + if ( snr < MIN_ACCEPTABLE_SNR_FOR_SB ) + flag = FALSE; +#endif + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, toa,pm, l1s_dsp_com.dsp_db_r_ptr->a_sch[0] & 0xffff); + #endif + #endif + + #if TRACE_TYPE==3 + stats_samples_sb(flag,toa,pm,angle,snr); + #endif + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + if (task == SBCONF) uart_trace(SBCONF); + else uart_trace(SB2); // display result code... + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + WORD16 old_afc=l1s.afc; + + if((flag == TRUE) && (l1a_l1s_com.mode == CS_MODE)) + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_OPEN_LOOP, + &l1s.afc_frame_count, + (WORD16)angle, + 0, + l1a_l1s_com.nsync.list[neigh_id].radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_OPEN_LOOP, + &l1s.afc_frame_count, + (WORD16)angle, + 0, + l1a_l1s_com.nsync.list[neigh_id].radio_freq,l1a_l1s_com.mode); + #endif + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_AFC_OPEN) + buffer_trace (4,(WORD16)angle,old_afc,l1s.afc,1); + #endif + #endif + } + } + #endif + + // Call SB report function (send report msg to L1A). + #if TESTMODE + if (l1_config.TestMode) + l1s_read_sb(task, flag, data, toa, attempt, pm_fullres, angle, snr); + else + l1s_read_sb(task, flag, data, toa, attempt, pm, angle, snr); + #else + l1s_read_sb(task, flag, data, toa, attempt, pm, angle, snr); + #endif + + // the status is not used in D51 and D26 modes + if ((task != SBCNF51 ) && (task != SB51)) + { + // SB2 activity completed for this neighbour cell. + if((task != SB2) || ((task == SB2) && (attempt == 2))) + l1a_l1s_com.nsync.list[neigh_id].status = NSYNC_COMPLETED; + } + } + + // All tasks are completed by this function except SB2 which + // calls it twice. SB2 is then completed only when making the + // second execution of this function. + // -> task is completed: set INACTIVE. + if((task != SB2) || (task == SB2) && (attempt == 2)) + { + l1s.task_status[task].current_status = INACTIVE; + l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED; + } + } + break; +#if ((REL99 == 1) && (FF_BHO == 1)) + case FBSB : + + /*---------------------------------------------------*/ + /* Frequency + Synchro burst detection result... */ + /*---------------------------------------------------*/ + { + BOOL abort_flag = FALSE; + + if (l1a_l1s_com.nsync_fbsb.fb_found_attempt == 0) + // Looking for FB + { + flag = l1s_dsp_com.dsp_ndb_ptr->d_fb_det & 0xffff; // flag = TRUE means FOUND. + toa = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff) >> 5; +#if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F26.6 +#endif + angle = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_SNR] & 0xffff; + + if (flag) // FB detected + { + // Store toa and attempt for future use + l1a_l1s_com.nsync_fbsb.fb_toa = toa; + l1a_l1s_com.nsync_fbsb.fb_found_attempt = attempt; + +#if (TRACE_TYPE == 3) + stats_samples_fb(flag, toa, pm, angle, snr); +#endif + +#if (TRACE_TYPE == 2 ) || (TRACE_TYPE == 3) + // uart_trace(FBSB); +#endif + } + else + { + if (attempt < 12) + { + // FB not found, some attempts remaining + break; + } + else + { + // FB not found, no attempt remaining + // Call FBSB report function (send report msg to L1A). +#if TESTMODE + if (l1_config.TestMode) + l1s_read_fbsb(task, attempt, FALSE, FALSE, (API *)NULL, toa, pm, angle, snr); + else +#endif + l1s_read_fbsb(task, attempt, FALSE, FALSE, (API *)NULL, toa, pm, angle, snr); + + abort_flag = TRUE; + } + } + } + else // if (l1a_l1s_com.nsync_fbsb.fb_found_attempt == 0) + // Looking for SB + { + flag = !(((l1s_dsp_com.dsp_db_r_ptr->a_sch[0] & 0xffff) & (1<> B_SCH_CRC); // // flag = TRUE means FOUND. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; // Unit is BIT. + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff) >> 5; +#if TESTMODE + pm_fullres = l1s_dsp_com.dsp_ndb_ptr->a_sync_demod[D_PM] & 0xffff; // F26.6 +#endif + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + data = &(l1s_dsp_com.dsp_db_r_ptr->a_sch[3]); // Set data block pointer (skip header). + + if (flag) // SB detected + { + // SB found report SUCCESS + +#if L2_L3_SIMUL +#if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, toa,pm, l1s_dsp_com.dsp_db_r_ptr->a_sch[0] & 0xffff); +#endif +#endif + +#if (TRACE_TYPE == 3) + stats_samples_sb(flag, toa, pm, angle, snr); +#endif + +#if (TRACE_TYPE == 2 ) || (TRACE_TYPE == 3) + // uart_trace(FBSB); // display result code... +#endif + + // Call FBSB report function (send report msg to L1A). +#if TESTMODE + if (l1_config.TestMode) + l1s_read_fbsb(task, attempt, TRUE, TRUE, data, toa, pm, angle, snr); + else +#endif + l1s_read_fbsb(task, attempt, TRUE, TRUE, data, toa, pm, angle, snr); + + abort_flag = TRUE; + } + else // if (flag) + { + if (attempt < (l1a_l1s_com.nsync_fbsb.fb_found_attempt + 2)) + { + // SB not found, one attempt remaining + break; + } + else + { + // SB not found, no attempt remaining + // Call FBSB report function (send report msg to L1A). +#if TESTMODE + if (l1_config.TestMode) + l1s_read_fbsb(task, attempt, TRUE, FALSE, (API *)NULL, toa, pm, angle, snr); + else +#endif + l1s_read_fbsb(task, attempt, TRUE, FALSE, (API *)NULL, toa, pm, angle, snr); + + abort_flag = TRUE; + } + } + } // if(l1a_l1s_com.nsync_fbsb.fb_found_attempt == 0) + + + if(abort_flag == TRUE) + { + // -> task is completed: set INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED; + + if (attempt < 14) + { + // FBSB search finished before last attempt: + // -reset DSP R/W pages, DSP tasks and TPU + // -flush MFTAB and reset frame count + // -adjust debug time + l1d_reset_hw(l1s.tpu_offset); + l1s.tpu_ctrl_reg |= CTRL_FBSB_ABORT; // set CTRL bit -> tpu_end_scenario + l1s_clear_mftab(l1s.mftab.frmlst); + l1s.frame_count = 0; + } + } + } +#endif // #if ((REL99 == 1) && (FF_BHO == 1)) + } + + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch" only if not + // in dedicated/TCH mode (FB26,SB26,SBCNF26). Those task are not following the + // common principle. They use only the NDB part of the MCU/DSP interface, no + // page swapping is then needed. +#if ((REL99 == 1) && (FF_BHO == 1)) + if(((task != FB26) && (task != SB26) && (task != SBCNF26) && (task != FBNEW) && (task != FB51) && (task != FBSB)) || +#else + if(((task != FB26) && (task != SB26) && (task != SBCNF26) && (task != FBNEW) && (task != FB51)) || +#endif // #if ((REL99 == 1) && (FF_BHO == 1)) + ((!fb_abort_flag) && (attempt==12))) + l1s_dsp_com.dsp_r_page_used = TRUE; +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +#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 + +/*-------------------------------------------------------*/ +/* l1s_read_snb_dl() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: BCCHS,NP,EP,ALLC,SMSCB. */ +/* This function is the reading result function used for */ +/* reading a serving cell burst acquisition result in */ +/* any mode except dedicated mode. Here is a summary of */ +/* the execution: */ +/* */ +/* - If SEMAPHORE(task) is low and task still enabled. */ +/* - Traces and debug. */ +/* - Read control results and feed control algo. */ +/* - Read DL DATA block from MCU/DSP interface. */ +/* - Disactivate task. */ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* NP, Normal paging reading task. */ +/* EP, Extended paging reading task. */ +/* BCCHS, BCCH Serving reading task. */ +/* ALLC, All serving cell CCCH reading task. */ +/* SMSCB, Short Message Service Cell Broadcast task. */ +/* */ +/* "burst_id" */ +/* BURST_1, 1st burst of the task. */ +/* BURST_2, 2nd burst of the task. */ +/* BURST_3, 3rd burst of the task. */ +/* BURST_4, 4th burst of the task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip the body */ +/* of this function if L1A has changed or is changing */ +/* some of the task parameters. */ +/* */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.task_status[task].current_status" */ +/* current task status. It must be reset (INACTIVE) */ +/* when the task is completed. */ +/* -> disactivate task. */ +/* */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/* Use of MCU/DSP interface: */ +/* ------------------------- */ +/* "l1s_dsp_com.dsp_ndb_ptr" */ +/* pointer to the non double buffered part (NDB) of */ +/* the MCU/DSP interface. This part is R/W for both */ +/* DSP and MCU. */ +/* */ +/* "l1s_dsp_com.dsp_db_r_ptr" */ +/* pointer to the double buffered part (DB) of the */ +/* MCU/DSP interface. This pointer points to the READ */ +/* page. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_snb_dl(UWORD8 task, UWORD8 burst_id) +{ + UWORD32 toa; + UWORD32 pm; + UWORD32 angle; + UWORD32 snr; + BOOL en_task; + BOOL task_param; + UWORD16 radio_freq=0; + static UWORD16 pwr_level; +#if L1_FF_MULTIBAND == 1 + UWORD16 operative_radio_freq; +#endif + +#if (FF_L1_FAST_DECODING == 1) + UWORD8 skipped_bursts = 0; + BOOL fast_decoding_authorized = l1s_check_fast_decoding_authorized(task); + BOOL fast_decoded = (l1a_apihisr_com.fast_decoding.status == C_FAST_DECODING_COMPLETE); + if (fast_decoded) + { + skipped_bursts = BURST_4 - burst_id; + } +#endif /* if (FF_L1_FAST_DECODING == 1) */ + + /*--------------------------------------------------------*/ + /* READ SERVING CELL RECEIVE TASK RESULTS... */ + /*--------------------------------------------------------*/ + /* Rem: only a partial result is present in the mcu<-dsp */ + /* communication buffer. The DATA BLOCK content itself is */ + /* in the last comm. (BURST_4) */ + /*--------------------------------------------------------*/ + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_SNB_DL , (UWORD32)(-1));//OMAPS00090550 + #endif + + #if (TRACE_TYPE!=0) + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + { + // Check task identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_d & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1));//OMAPS00090550 + + // Check burst identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_burst_d & 0xffff) != burst_id) + trace_fct(CST_DL_BURST_DOES_NOT_CORRESPOND, (UWORD32)(-1));//OMAPS00090550 + } + else // GPRS scheduler + { + // Check burst identifier... + if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs != burst_id) + trace_fct(CST_DL_BURST_DOES_NOT_CORRESPOND, (UWORD32)(-1)); + } + #else + // Check task identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_d & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1)); + + // Check burst identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_burst_d & 0xffff) != burst_id) + trace_fct(CST_DL_BURST_DOES_NOT_CORRESPOND,(UWORD32)( -1)); + #endif + #endif + + l1_check_com_mismatch(task); + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + { + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + } + else + { + toa = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_toa_gprs[0] & 0xffff; + pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[0] & 0xffff); + angle = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_angle_gprs[0] & 0xffff; + snr = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_snr_gprs[0] & 0xffff; + } + #else + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + #endif + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + // Update AGC: Call PAGC algorithm + radio_freq = l1a_l1s_com.Scell_info.radio_freq; + +#if (L1_FF_MULTIBAND == 0) + + l1a_l1s_com.Scell_IL_for_rxlev = l1ctl_pagc((UWORD8)pm, radio_freq, + &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); + l1a_l1s_com.Scell_IL_for_rxlev = l1ctl_pagc((UWORD8)pm, radio_freq, + &l1a_l1s_com.last_input_level[operative_radio_freq]); + +#endif // #if (L1_FF_MULTIBAND == 0) else + + +#if (FF_L1_FAST_DECODING == 1) + if (skipped_bursts>0) + { + l1ctl_pagc_missing_bursts(skipped_bursts); + } +#endif /* if (FF_L1_FAST_DECODING == 1) */ + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_LNA) + + #if (L1_FF_MULTIBAND == 0) + buffer_trace (4, 33, radio_freq, + l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].input_level, + l1a_l1s_com.last_input_level[radio_freq - l1_config.std.radio_freq_index_offset].lna_off); + + #else // L1_FF_MULTIBAND = 1 below + + buffer_trace (4, 33, radio_freq, + l1a_l1s_com.last_input_level[operative_radio_freq].input_level, + l1a_l1s_com.last_input_level[operative_radio_freq].lna_off); + + #endif // #if (L1_FF_MULTIBAND == 0) else + + #endif + #endif + + #if TRACE_TYPE==3 + stats_samples_nb(toa,pm,angle,snr,burst_id,task); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_AFC_OPEN)//omaps00090550 + WORD16 old_afc = l1s.afc; + WORD16 old_count= l1s.afc_frame_count; + #endif + #endif + + + + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq,l1a_l1s_com.mode); + #endif + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_AFC_OPEN) + buffer_trace (4,(WORD16)angle,old_count,old_afc,l1s.afc); + #endif + #if (DEBUG_TRACE == BUFFER_TRACE_TOA) + if (task == NP || task == EP) + buffer_trace(5, + l1s.debug_time, + 0xf1, + i, + l1s.afc, + angle ); + #endif + #endif + } + #endif + + //Feed TOA histogram. + #if (TOA_ALGO != 0) + if (task != SMSCB) + { + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + #if (RF_FAM == 2) // RF 2 + #if (TOA_ALGO == 2) + if(l1a_l1s_com.Scell_IL_for_rxlev < IL_FOR_RXLEV_SNR) + { + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr, toa); + } + else + { + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, 0, toa); + } + #else + if(l1a_l1s_com.Scell_IL_for_rxlev a_cd[2] != 0xffff) + { + qual_acc_idle1[0] += l1s_dsp_com.dsp_ndb_ptr->a_cd[2]; + //RX Qual value reporting- total number of decoded bits + qual_acc_idle1[1] += 1; + } + +#if (FF_L1_FAST_DECODING == 1) + /* Perform the reporting if + - Burst is the 4th one (whether CRC is ok or not) + - Fast decoding enabled and CRC already ok + */ + if ( (burst_id == BURST_4) || fast_decoded ) +#else /* #if (FF_L1_FAST_DECODING == 1) */ + if(burst_id == BURST_4) +#endif /* FF_L1_FAST_DECODING */ + { + UWORD8 i; + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(task); + #endif + + // the data power bloc = pwr_level/4. +#if (FF_L1_FAST_DECODING == 1) + /* Data power block = pwr_level / (nb of bursts)*/ + pwr_level = pwr_level / (burst_id + 1); +#else /* #if (FF_L1_FAST_DECODING == 1) */ + // the data power bloc = pwr_level/4. + pwr_level = pwr_level >> 2; +#endif /* #if (FF_L1_FAST_DECODING == 1) #else*/ + +#if (FF_L1_FAST_DECODING == 1) + if(!fast_decoding_authorized) + { + /* When fast decoding wasn't used, burst_id is undefined (for the trace) */ + l1a_l1s_com.last_fast_decoding = 0; + } + else + { + l1a_l1s_com.last_fast_decoding = burst_id + 1; + } +#endif /* #if (FF_L1_FAST_DECODING == 1) */ + + // Read L3 frame block and send msg to L1A. + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + l1s_read_l3frm(pwr_level,&(l1s_dsp_com.dsp_ndb_ptr->a_cd[0]), task); + else + l1s_read_l3frm(pwr_level,&(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]), task); + #else + l1s_read_l3frm(pwr_level,&(l1s_dsp_com.dsp_ndb_ptr->a_cd[0]), task); + #endif + + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + #endif + { + // reset buffers and flags in NDB ... + // reset nerr.... + // reset A_CD contents....... + l1s_dsp_com.dsp_ndb_ptr->a_cd[2] = 0xffff; + for (i=0;i<12;i++) + l1s_dsp_com.dsp_ndb_ptr->a_cd[3+i] = 0x0000; + } + + } // End if... + } // End if... + + // The NP/EP task was enabled and could cancel a PTCCH burst + // This incomplete PTCCH decoding block cause DSP troubles and so COM/PM errors + // and then a recovery => in this case restart the PTCCH from the burst 0 +#if L1_GPRS + if((task == NP)||(task == EP)) + if(l1a_l1s_com.l1s_en_task[PTCCH] == TASK_ENABLED) + if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL) // a PTCCH DL task is running + if((l1s.actual_time.t2 >= 13) && (l1s.actual_time.t2 <= 17)) // only if the NP/EP remove a PTCCH activity + { + // Restart PTCCH DL task from the begining (i.e BURST 0). + l1pa_l1ps_com.transfer.ptcch.activity ^= PTCCH_DL; // disable PTCCH_DL activity running + l1pa_l1ps_com.transfer.ptcch.request_dl = TRUE; // restart PTCCH DL from the Burst0 + } +#endif + + // Deactivate task. + // ****************** + + // End of task -> task must become INACTIVE. + // Rem: some TASKS (ALLC) can be pipelined and therefore must stay active if + // they have already reentered the flow. +#if (FF_L1_FAST_DECODING == 1) + if ( (burst_id == BURST_4) || fast_decoded ) +#else /* #if (FF_L1_FAST_DECODING == 1) */ + if(burst_id == BURST_4) +#endif /* #if (FF_L1_FAST_DECODING == 1) #else*/ + + { +#if (FF_L1_FAST_DECODING == 1) + if((task == NP) || (task == NBCCHS)) + { + if (l1a_apihisr_com.fast_decoding.contiguous_decoding == TRUE) + { + /* A new block has started, a new fast API IT is expected */ + l1a_apihisr_com.fast_decoding.contiguous_decoding = FALSE; + l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_AWAITED; + } + else if(task == l1a_apihisr_com.fast_decoding.task) + { + /* Reset decoding status */ + l1a_apihisr_com.fast_decoding.status = C_FAST_DECODING_NONE; + } + } /* end if tsk == NP */ +#endif /* #if (FF_L1_FAST_DECODING == 1) */ + if(l1s.task_status[task].current_status == RE_ENTERED) + l1s.task_status[task].current_status = ACTIVE; + else + l1s.task_status[task].current_status = INACTIVE; +#if (FF_L1_FAST_DECODING == 1) + if (burst_id != BURST_4) + { + /* Successful decode before the 4th burst, no other control/read activities are needed */ + l1s_clean_mftab(task, burst_id + 3); + if(l1s.frame_count == (4 -burst_id)) + { + l1s.frame_count = 1; + } + } +#endif /* #if (FF_L1_FAST_DECODING == 1) */ + } + + l1ddsp_read_iq_dump(task); + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + +/*-------------------------------------------------------*/ +/* l1s_read_nnb() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: BCCHN. */ +/* This function is the reading result function used for */ +/* reading a neighbor cell block acquisition result in */ +/* idle mode. Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low and task still enabled. */ +/* - Traces and debug. */ +/* - Read DL DATA block from MCU/DSP interface. */ +/* - Disactivate task. */ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* BCCHN, BCCH Neighbor reading task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip the body */ +/* of this function if L1A has changed or is changing */ +/* some of the task parameters. */ +/* */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.task_status[task].current_status" */ +/* current task status. It must be reset (INACTIVE) */ +/* when the task is completed. */ +/* -> disactivate task. */ +/* */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/* Use of MCU/DSP interface: */ +/* ------------------------- */ +/* "l1s_dsp_com.dsp_ndb_ptr" */ +/* pointer to the non double buffered part (NDB) of */ +/* the MCU/DSP interface. This part is R/W for both */ +/* DSP and MCU. */ +/* */ +/* "l1s_dsp_com.dsp_db_r_ptr" */ +/* pointer to the double buffered part (DB) of the */ +/* MCU/DSP interface. This pointer points to the READ */ +/* page. */ +/* */ +/*-------------------------------------------------------*/ +void l1s_read_nnb(UWORD8 task, UWORD8 param) +{ + BOOL en_task; + BOOL task_param; + UWORD16 neigh_radio_freq; + UWORD16 pwr_level; + UWORD8 active_neigh_id; +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + /*--------------------------------------------------------*/ + /* READ NEIGBOR CELL RECEIVE TASK RESULTS... */ + /*--------------------------------------------------------*/ + /* Rem: the full result is present in the mcu<-dsp */ + /* communication buffer. */ + /*--------------------------------------------------------*/ + // Get "enable" task flag and "synchro semaphore" for current task. + en_task = l1a_l1s_com.l1s_en_task[task]; + task_param = l1a_l1s_com.task_param[task]; + + if((en_task) && !(task_param)) + // Check the task semaphore and the task enable bit. The reading + // task body is executed only when the task semaphore is 0 and the + // task is still enabled. + // The semaphore can be set to 1 whenever L1A makes some changes + // to the task parameters. The task can be disabled by L1A. + { + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_NNB ,(UWORD32)(-1)); + #endif + + + #if (TRACE_TYPE!=0) + // Check task identifier... + #if L1_GPRS + switch(l1a_l1s_com.dsp_scheduler_mode) + { + case GSM_SCHEDULER: + { + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_d & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1)); + } break; + case GPRS_SCHEDULER: + { + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_md & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1)); + } break; + } + #else + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_d & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1)); + #endif + #endif + + l1_check_com_mismatch(task); + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(task); + #endif + + if(task == BCCHN) + active_neigh_id = l1a_l1s_com.bcchn.active_neigh_id_norm; + else // BCCHN_TRAN and BCCHN_TOP tasks + active_neigh_id = l1a_l1s_com.bcchn.active_neigh_id_top; + + // the mean power level is impossible for the neighbor bloc, so the las input level is used. + neigh_radio_freq = l1a_l1s_com.bcchn.list[active_neigh_id].radio_freq; +#if (L1_FF_MULTIBAND == 0) + pwr_level = l1a_l1s_com.last_input_level[neigh_radio_freq - l1_config.std.radio_freq_index_offset].input_level; +#else + operative_radio_freq = l1_multiband_radio_freq_convert_into_operative_radio_freq(neigh_radio_freq); + pwr_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; +#endif + + + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + + // Read L3 frame block and send msg to L1A. + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + l1s_read_l3frm(pwr_level,&(l1s_dsp_com.dsp_ndb_ptr->a_cd[0]), task); + else + l1s_read_l3frm(pwr_level,&(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]), task); + #else + l1s_read_l3frm(pwr_level,&(l1s_dsp_com.dsp_ndb_ptr->a_cd[0]), task); + #endif + // Disable the served TC from the TC bitmap. + if(task == BCCHN) + l1a_l1s_com.bcchn.list[active_neigh_id].bcch_blks_req ^= + ((UWORD16)(1L << l1a_l1s_com.bcchn.active_neigh_tc_norm)); + else // BCCHN_TRAN and BCCHN_TOP tasks + l1a_l1s_com.bcchn.list[active_neigh_id].bcch_blks_req ^= + ((UWORD16)(1L << l1a_l1s_com.bcchn.active_neigh_tc_top)); + } + + // The BCCHN task was enabled and could cancel a PTCCH burst + // This incomplete PTCCH decoding block cause DSP troubles and so COM/PM errors + // and then a recovery (seen with ULYSS) => in this case restart the PTCCH from the burst 0 + #if L1_GPRS + if (task == BCCHN_TRAN) + if(l1a_l1s_com.l1s_en_task[PTCCH] == TASK_ENABLED) + if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL) // a PTCCH DL task is running + if ((l1s.actual_time.t2 >= 13) && (l1s.actual_time.t2 <= 18)) // only if the BCCHN remove a PTCCH activity + { + // Restart PTCCH DL task from the begining (i.e BURST 0). + l1pa_l1ps_com.transfer.ptcch.activity ^= PTCCH_DL; // disable PTCCH_DL activity running + l1pa_l1ps_com.transfer.ptcch.request_dl = TRUE; // restart PTCCH DL from the Burst0 + } + #endif + + // Disactivate task. + // ****************** + + // End of task -> task must become INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + + l1ddsp_read_iq_dump(task); + + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +/*-------------------------------------------------------*/ +/* l1s_read_dedic_dl() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: DDL,ADL,TCHTH,TCHTF,TCHA. */ +/* This function is the reading result function used for */ +/* dedicated mode. Here is a summary of the execution: */ +/* */ +/* - Traces and debug. */ +/* - Read control results and feed control algo. */ +/* - Read DL DATA block from MCU/DSP interface. */ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* DDL, SDCCH DOWNLINK reading task. */ +/* ADL, SACCH DOWNLINK (associated with SDCCH)reading */ +/* task. */ +/* TCHTH, TCH channel task when dedicated/TCH Half rate*/ +/* TCHTF, TCH channel task when dedicated/TCH Full rate*/ +/* TCHA, Associated channel task when dedicated/TCH. */ +/* */ +/* "burst_id" (used only by DDL/ADL tasks). */ +/* BURST_1, 1st burst of the task. */ +/* BURST_2, 2nd burst of the task. */ +/* BURST_3, 3rd burst of the task. */ +/* BURST_4, 4th burst of the task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1a_l1s_com.task_param" */ +/* task semaphore bit register. Used to skip the body */ +/* of this function if L1A has changed or is changing */ +/* some of the task parameters. */ +/* */ +/* "l1a_l1s_com.l1s_en_task" */ +/* L1S task enable bit register. */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* "l1s.task_status[task].current_status" */ +/* current task status. It must be reset (INACTIVE) */ +/* when the task is completed. */ +/* -> disactivate task. */ +/* */ +/* "l1s_dsp_com.dsp_r_page_used" */ +/* Flag used by the function which closes L1S */ +/* execution ("l1s_end_manager()") to know if the */ +/* MCU/DSP read page must be switched. */ +/* -> Set to 1. */ +/* */ +/* Use of MCU/DSP interface: */ +/* ------------------------- */ +/* "l1s_dsp_com.dsp_ndb_ptr" */ +/* pointer to the non double buffered part (NDB) of */ +/* the MCU/DSP interface. This part is R/W for both */ +/* DSP and MCU. */ +/* */ +/* "l1s_dsp_com.dsp_db_r_ptr" */ +/* pointer to the double buffered part (DB) of the */ +/* MCU/DSP interface. This pointer points to the READ */ +/* page. */ +/* */ +/* RXQUAL : */ +/* 1) SDCCH : for RXQUAL_FULL and RXQUAL_SUB we accumu- */ +/* -late number of estimated errors (a_cd[2]) */ +/* for ALL SACCH and SDCCH TDMA frames. */ +/* 2) TCH : for RXQUAL_FULL in TCH_FS_MODE and */ +/* TCH_24F_MODE, we accumulate number of */ +/* estimated errors for ALL FACCH (a_fd[2]) */ +/* TDMA frames and ALL speech (a_dd_0[2]) */ +/* TDMA frames. */ +/* for RXQUAL_FULL in all data modes (except */ +/* TCH_24F_MODE, see above) we accumulate */ +/* number of errors for ALL FACCH (a_fd[2]) */ +/* TDMA frames and ALL data (a_dd_0[2]) */ +/* TDMA frames. */ +/* for RXQUAL_SUB in TCH_FS_MODE and */ +/* TCH_24F_MODE, we only accumulate number of */ +/* estimated errors for FACCH (a_fd[2]) TDMA */ +/* frames and speech (a_dd_0[2]) TDMA frames */ +/* at SID block boundary position. */ +/* for RXQUAL_SUB in all data modes (except */ +/* TCH_24F_MODE, see above) we only accumulate*/ +/* number of estimated errors for FACCH */ +/* (a_fd[2]) TDMA frames at SID block boundary*/ +/* position. The GSM specification 5.08 $8.4 */ +/* is not clear about data block at SID block */ +/* boundary position. Do we need to accumulate*/ +/* if L2/fill frame at this SID block boundary*/ +/* position. */ +/* Note: before accumulating FACCH TDMA frame we only */ +/* check b_blud value, we don't mind about b_fire. */ +/*-------------------------------------------------------*/ +void l1s_read_dedic_dl(UWORD8 task, UWORD8 burst_id) +{ + UWORD32 toa; + UWORD32 pm; + UWORD32 angle; + UWORD32 snr; + BOOL beacon; + T_INPUT_LEVEL *IL_info_ptr; + UWORD16 radio_freq=0; + + #if TESTMODE + UWORD32 pm_fullres =0;//omaps00090550 + #endif + + + #if REL99 + #if FF_EMR + T_EMR_PARAMS emr_params; // strucutre to store pre-calculated parameter + + /*--------------------------------------------------------*/ + /* INITIALIZATION OF EMR params.. */ + /*--------------------------------------------------------*/ + + emr_params.task = task; + emr_params.burst_id = burst_id; + emr_params.facch_present = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + emr_params.facch_fire1 = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_FIRE1; + emr_params.a_dd_0_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + emr_params.a_dd_0_bfi = ((l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0])&(1<> B_BFI; // 3rd bit tells the BAD frame + emr_params.a_dd_1_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_BLUD; + emr_params.a_dd_1_bfi = ((l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0])&(1<> B_BFI; // 3rd bit tells the BAD frame + emr_params.b_m1 = ((l1s_dsp_com.dsp_ndb_ptr->a_data_buf_dl[1]) &(1<> B_M1; // = 1 if second half frame for data 14.4 + emr_params.b_f48blk_dl = ((l1s_dsp_com.dsp_ndb_ptr->d_ra_act) &(1<> B_F48BLK_DL; // = 1 if second half frame for data 4.8 + emr_params.b_ce = (((l1s_dsp_com.dsp_ndb_ptr->d_ra_conf) & (1<> B_CE); + emr_params.a_ntd = (((l1s_dsp_com.dsp_ndb_ptr->a_data_buf_dl[1]) & (1<> B_FCS_OK); + emr_params.a_cd_fire1 = (l1s_dsp_com.dsp_ndb_ptr->a_cd[0] & (1<> B_FIRE1; + emr_params.sid_present_sub0 = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_SID1; // find out whether sid1 is 0/1 + emr_params.sid_present_sub1 = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_SID1; // find out whether sid1 is 0/1 + #if (AMR == 1) + emr_params.amr_facch_present= (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + emr_params.amr_facch_fire1 = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_FIRE1; + emr_params.b_ratscch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & (1<> B_BLUD; + emr_params.ratscch_rxtype = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + emr_params.amr_rx_type_sub0 = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + emr_params.amr_rx_type_sub1 = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + #endif //(AMR == 1) + #endif //FF_EMR + #endif //REL99 + + + + /*--------------------------------------------------------*/ + /* READ DEDICATED CHANNEL DL RESULTS... */ + /*--------------------------------------------------------*/ + + // Traces and debug. + // ****************** + #if (TRACE_TYPE!=0) && (TRACE_TYPE !=5) + trace_fct(CST_L1S_READ_DEDIC_DL, 1);//omaps00090550 + #endif + + #if (TRACE_TYPE!=0) + // Check task identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_d & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_DL_TASKS_DO_NOT_CORRESPOND, (UWORD32)(-1)); + #endif + + #if (TESTMODE) + // WARNING! + // Don't trace MCU-DSP mismatches during UL-only in TestMode. The DSP is not working + // in that case so it is normal. However, if tracing happens the CPU overloads + if (l1_config.TestMode && l1_config.tmode.rf_params.down_up & TMODE_DOWNLINK) + #endif + { + l1_check_com_mismatch(task); + } + + radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd; + + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + beacon=1; + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas_beacon; + } + else + { + beacon=0; + IL_info_ptr = &l1a_l1s_com.Scell_info.traffic_meas; + } + + #if (AMR == 1) + { + // RATSCCH detection + UWORD16 ratscch_dl_header=l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0]; + UWORD16 b_ratscch_dl_blud = (ratscch_dl_header & (1<> B_BLUD; + + if(b_ratscch_dl_blud==TRUE) + { + UWORD8 rx_type = (ratscch_dl_header & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + + if(rx_type==C_RATSCCH_GOOD) + { + // RATSCCH block detected + l1s_amr_update_from_ratscch(&l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0]); + } + } + } + #endif // AMR + + switch(task) + { + case DDL : + case ADL : + /*---------------------------------------------------*/ + /* Dedicated mode: SDCCH receive task. */ + /* Rem: only a partial result is present in the */ + /* mcu<-dsp communication buffer. The BLOCK content */ + /* itself is in the last comm. (BURST_4) */ + /*---------------------------------------------------*/ + { + UWORD8 i, IL_for_rxlev; + + #if (TRACE_TYPE!=0) + // Check burst identifier... + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_burst_d & 0xffff) != burst_id) + trace_fct(CST_DL_BURST_DOES_NOT_CORRESPOND, (UWORD32)(-1)); + #endif + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(0,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); // dtx_on = 0 + + // Dedicated mode serving cell measurement reading. + #if REL99 + #if FF_EMR + // only task,burst_id is valid in structure pointed by *emr_params + l1s_read_dedic_scell_meas(IL_for_rxlev, 1, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + #if TRACE_TYPE==3 + stats_samples_nb(toa,pm,angle,snr,burst_id,task); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq,l1a_l1s_com.mode); + #endif + } + #endif + + //Feed TOA histogram. + #if (TOA_ALGO != 0) + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING ==1) + ,0 +#endif + ); + #endif + + } + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev) + #endif + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + + if(burst_id == BURST_4) + { + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(task); + #endif + + if(task == DDL) + { + // Read DCCH DL data block from DSP, pass it to L2. + l1s_read_dcch_dl(l1s_dsp_com.dsp_ndb_ptr->a_cd, task); + } + else + { + // Read L2 frame block and send msg to L1A. + l1s_read_sacch_dl(l1s_dsp_com.dsp_ndb_ptr->a_cd, task); + } + + // RXQUAL_FULL/RXQUAL_SUB : number of estimated errors, this value is contained + // in a_cd[2] field, for every SACCH and SDDCH blocks + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_cd[2]&0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += A_D_BLEN; + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_cd[2]&0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += A_D_BLEN; + + // TEMPORARY : reset buffers and flags in NDB ... + // reset nerr.... + // reset A_CD contents....... + l1s_dsp_com.dsp_ndb_ptr->a_cd[0] = (1<a_cd[2] = 0xffff; + for (i=0; i<12 ;i++) + l1s_dsp_com.dsp_ndb_ptr->a_cd[3+i] = 0x0000; + + // task is completed, make it INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + } + } + break; + + case TCHTH: + /*---------------------------------------------------*/ + /* Dedicated mode: TCHTH receive task. */ + /* HALF RATE */ + /*---------------------------------------------------*/ + { + UWORD32 b_blud; + UWORD8 channel_mode; + //OMAPS00090550 UWORD8 channel_type; + UWORD8 subchannel; + UWORD32 l1_mode; + UWORD32 fn_mod_104; + UWORD32 fn_mod_52; + //OMAPS00090550 UWORD32 fn_report_mod13_mod4; + UWORD32 normalised_fn_report_mod13_mod4; + UWORD32 normalised_fn_report_mod26; + UWORD8 IL_for_rxlev = 0; //omaps00090550 + #if (AMR == 1) + UWORD8 rx_type; + UWORD8 b_ratscch_blud,b_facch_blud; + UWORD8 voco_type; + BOOL facch_present = FALSE; + #if REL99 + #if FF_EMR + emr_params.amr_facch_present = FALSE; + emr_params.amr_facch_fire1 = FALSE; + #endif + #endif + #endif + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + #if TRACE_TYPE==3 + stats_samples_tch(toa,pm,angle,snr); + #endif + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(TCHTH); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq,l1a_l1s_com.mode); + #endif + } + #endif + + // Increment number of burst not sent due to DTX. + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_u & 0xffff) == TCH_DTX_UL) + { + l1a_l1s_com.Smeas_dedic.dtx_used++; + l1s.dtx_ul_on = TRUE; + } + else + { + l1s.dtx_ul_on = FALSE; + } + + // Check SID frame subset... + channel_mode = l1a_l1s_com.dedic_set.aset->achan_ptr->mode; +//OMAPS00090550 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; + subchannel = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->subchannel; + fn_mod_104 = l1s.actual_time.fn % 104; + fn_mod_52 = l1s.actual_time.fn % 52; + + #if REL99 + #if FF_EMR + // Compute FN in reporting period % 13 % 4 = (((FN-subchannel)+ 13) %13) %4 + normalised_fn_report_mod13_mod4 = ((l1s.actual_time.fn - subchannel + 13) % 13) % 4; + + // Compute FN in reporting period % 26 independently of the considered subchannel. + normalised_fn_report_mod26 = (l1s.actual_time.fn - subchannel + 26) % 26; + + emr_params.channel_mode = channel_mode; + emr_params.subchannel = subchannel; + emr_params.normalised_fn_mod13_mod4 = normalised_fn_report_mod13_mod4; + #endif //FF_EMR + #endif //REL99 + + + #if (AMR == 1) + // Check if we're in AMR DTX mode + if(channel_mode==TCH_AHS_MODE && + ( (((l1s.actual_time.fn_mod13 % 4)==3) && (subchannel==0)) || // AHS0: block is decoded on DSP side at fn%13%4=2 + (((l1s.actual_time.fn_mod13 % 4)==0) && (subchannel==1)) )) // AHS1: block is decoded on DSP side at fn%13%4=3 + { + if(subchannel==0) + { + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + } + else + { + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_BLUD; + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + } + b_ratscch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & (1<> B_BLUD; + b_facch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + + // Check if AMR DTX mode is on + if((((rx_type==SID_FIRST) || (rx_type==SID_UPDATE) || (rx_type==SID_BAD)) && b_blud==TRUE) || + (rx_type==AMR_NO_DATA && b_blud==FALSE)) + { + l1s.dtx_amr_dl_on=TRUE; + } + else if(b_ratscch_blud==FALSE && b_facch_blud==FALSE) + { + l1s.dtx_amr_dl_on=FALSE; + } + } + #endif + + #if (AMR == 1) + if (channel_mode != TCH_AHS_MODE) + { + // This AGC and TOA update isn't applied to the adaptative half rate mode. + if(((channel_mode == TCH_HS_MODE) && (subchannel == 0) && + (fn_mod_52 > 0) && (fn_mod_52 <= 7)) || + ((channel_mode == TCH_HS_MODE) && (subchannel == 1) && + (fn_mod_52 > 14) && (fn_mod_52 <= 21)) || + ((channel_mode != TCH_HS_MODE) && + (subchannel == 0) && (fn_mod_104 > 56) && (fn_mod_104 <= 76)) || + ((channel_mode != TCH_HS_MODE) && + (subchannel == 1) && (fn_mod_104 > 66) && (fn_mod_104 <= 86))) + #else + if(((channel_mode == TCH_HS_MODE) && (subchannel == 0) && + (fn_mod_52 > 0) && (fn_mod_52 <= 7)) || + ((channel_mode == TCH_HS_MODE) && (subchannel == 1) && + (fn_mod_52 > 14) && (fn_mod_52 <= 21)) || + ((channel_mode != TCH_HS_MODE) && (subchannel == 0) && + (fn_mod_104 > 56) && (fn_mod_104 <= 76)) || + ((channel_mode != TCH_HS_MODE) && (subchannel == 1) && + (fn_mod_104 > 66) && (fn_mod_104 <= 86))) + #endif + // Current results are from the TDMA frame subset always received (GSM05.08, $8.3). + // -> pwr meas. must be used for SUB set result. + // -> TOA filtering can be fed with SNR/TOA. + // WARNING: TCH/H in signalling only is here processed like TCH/H data. GSM spec is + // ======== unclear !!!!!!!!!!!!!!!1 + { + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(1,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + + // Dedicated mode serving cell measurement reading, indicate "SUB". + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 1,&emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + //Feed TOA histogram. + #if (TOA_ALGO != 0) + // When in 1/2 rate data, we are working on 14 SID frames (instead + // of 12 otherwise), so we need to increment length of the histogram + // filling period from 36 to 42. + if (channel_mode != TCH_HS_MODE) + l1_mode=DEDIC_MODE_HALF_DATA; + else + l1_mode=l1a_l1s_com.mode; + + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1_mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1_mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING == 1) + ,0 +#endif + ); + #endif + + } + #endif + } // if(((channel_mode == TCH_HS_MODE) && (subchannel == 0) && + else + { + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(0,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); + + // Dedicated mode serving cell measurement reading, full set only. + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + + #if (AMR == 1) + } // if (channel_mode != TCH_AHS_MODE) + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev) + #endif + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + + // Compute FN % 13 % 4 + //OMAPS00090550 fn_report_mod13_mod4 = (l1s.actual_time.fn_mod13) % 4; + // Compute normalised FN % 13 %4 = (((FN-subchannel)+ 13) %13) %4 + normalised_fn_report_mod13_mod4 = ((l1s.actual_time.fn - subchannel + 13) % 13) % 4; + // Compute normalised FN %26 = ((FN - subchannel)+ 26) %26 + normalised_fn_report_mod26 = (l1s.actual_time.fn - subchannel + 26) % 26; + + if((normalised_fn_report_mod26 == 16)|| + (normalised_fn_report_mod26 == 24)|| + (normalised_fn_report_mod26 == 7)) + // It is time to get FACCH/H data block. + { + // FACCH: Check A_FD information block. + //------------------------------------- + + UWORD8 temp; + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + #if ((REL99) && (AMR == 1)) + #if FF_EMR + emr_params.amr_facch_fire1 = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_FIRE1; + #endif + #endif + + if(b_blud == TRUE) + { + // Read FACCH DL data block from DSP, pass it to L2. + #if ( FF_REPEATED_DL_FACCH == 1 ) + #if (TRACE_TYPE == 1 || TRACE_TYPE == 4) + trace_info.facch_dl_count_all++; + #endif + // if the current block is a repetition reports NULL to L2 otherwise reports the current block + l1s_read_dcch_dl((API*)l1s_repeated_facch_check(l1s_dsp_com.dsp_ndb_ptr->a_fd), task); + #else + l1s_read_dcch_dl(l1s_dsp_com.dsp_ndb_ptr->a_fd, task); + #endif + + #if (AMR == 1) + if (channel_mode != TCH_AHS_MODE) + { + #endif + + // RXQUAL_SUB : In case of data taffic channels, accumulate number of + // estimated errors, this value is contained in a_fd[2] field, only + // for SID TDMA frames received as FACCH frames. (GSM 5.08 $8.4) + if (((fn_mod_104==59) && (channel_mode==TCH_HS_MODE) && (subchannel==0)) || + ((fn_mod_104==73) && (channel_mode==TCH_HS_MODE) && (subchannel==1)) || + ((fn_mod_104==76) && ((channel_mode==TCH_48H_MODE)|| + (channel_mode==TCH_24H_MODE)) && (subchannel==0)) || + ((fn_mod_104==86) && ((channel_mode==TCH_48H_MODE)|| + (channel_mode==TCH_24H_MODE)) && (subchannel==1))) + // last SID TDMA frame received as FACCH frames. + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_fd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_F_D_BLEN; + } + + #if (AMR == 1) + } // if (channel_mode != TCH_AHS_MODE) + else + { + // Indicate to AMR specific processing that burst was a FACCH + facch_present = TRUE; + #if ((REL99) && (AMR == 1)) + #if FF_EMR + emr_params.amr_facch_present = facch_present; + #endif + #endif + + + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + + // Dedicated mode serving cell measurement reading, indicate "FULL". + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + #endif + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_fd[2] field, for each TCHT block. + // The same for AMR + #if (AMR == 1) + // in AMR, l1s.dtx_amr_dl_on is FALSE if DTX mode is off + // in non AMR TCH, l1s.dtx_amr_dl_on is always FALSE + // In AMR DTX, DSP patch sometimes reports FACCH blocks which ARE NOT FACCH blocks + // therefore they shouldn't be taken into account in the RXQUALL_FULL computation + if(l1s.dtx_amr_dl_on==FALSE) + #endif + { + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_fd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_F_D_BLEN; + } + + // Reset A_FD header. + // B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 + l1s_dsp_com.dsp_ndb_ptr->a_fd[0] = (1<a_fd[2] = 0xffff; + + // Rem: when FACCH is received, we must reset A_DD_0 header also. + // Reset A_DD_0 header in NDB. +#if (AMR == 1) + if ((channel_mode==TCH_AHS_MODE) && (subchannel==0)) + { + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] &= (API)(RX_TYPE_MASK); + } + else +#endif + { + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + } + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + + // Rem: when FACCH is received, we must reset A_DD_1 header also. + // Reset A_DD_0 header in NDB. +#if (AMR == 1) + if ((channel_mode==TCH_AHS_MODE) && (subchannel==1)) + { + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] &= (API)(RX_TYPE_MASK); + } + else +#endif + { + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] = 0; + } + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + + } // if(b_blud == TRUE) + + else + // No FACCH received at FACCH boundary frame. Nevertheless, need to read dummy + // FACCH DL data block. + { + // Dummy: Read FACCH DL data block from DSP, pass it to L2. + // Rem: this is an upper layer requirement to call this + // function at every FACCH DL boundary. + l1s_read_dcch_dl(NULL, task); + } + } // if((normalised_fn_report_mod26 == 16)|| ... + + // else we are not at FACCH boundary frame + // We must check for the presence of a TCH/H block (even if it does fall on a FACCH boundary) + // We use the b_blud bit to confirm presence of TCH/H (or FACCH) + if((normalised_fn_report_mod13_mod4 == 3) && (channel_mode==TCH_HS_MODE)) + // It is time to get TCH/HS data block. + { + #if TRACE_TYPE==3 + if (l1_stats.type == PLAY_UL && + (channel_mode == TCH_HS_MODE)) + play_trace(); + #endif + + // Check A_DD_0 information block only if no FACCH. + if (subchannel==0) + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + else + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_BLUD; + + if(b_blud == TRUE) + { + if (subchannel==0) + { + // RXQUAL_SUB : In case of speech traffic channels, accumulate number of + // estimated errors, this value is contained in a_dd_0[2] field, only + // for SID TDMA frames. (GSM 5.08 $8.4) + if (fn_mod_104==59) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_HS_BLEN; + } + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } // if (subchannel==0) + else + { + // RXQUAL_SUB : In case of speech traffic channels, accumulate number of + // estimated errors, this value is contained in a_dd_1[2] field, only + // for SID TDMA frames. (GSM 5.08 $8.4) + if (fn_mod_104==73) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_HS_BLEN; + } + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + // Reset A_DD_1 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + } + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_HS_BLEN; + } // if(b_blud == TRUE) + } // if((normalised_fn_report_mod13_mod4 == 3) && (channel_mode==TCH_HS_MODE)) + + #if (AMR == 1) + if(((normalised_fn_report_mod26 == 20) || + (normalised_fn_report_mod26 == 3) || + (normalised_fn_report_mod26 == 11)) && + ((channel_mode == TCH_48H_MODE) || + (channel_mode == TCH_24H_MODE))) + #else + if(((normalised_fn_report_mod26 == 20) || + (normalised_fn_report_mod26 == 3) || + (normalised_fn_report_mod26 == 11)) && (channel_mode!=TCH_HS_MODE)) + #endif + // It is time to get TCH/H4.8 or TCH/H2.4 data block. + { + // Check A_DD_0 information block only if no FACCH. + if (subchannel==0) + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + else + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_BLUD; + + if(b_blud == TRUE) + { + if (subchannel==0) + { + // RXQUAL_SUB : In case of speech traffic channels, accumulate number of + // estimated errors, this value is contained in a_dd_0[2] field, only + // for SID TDMA frames. (GSM 5.08 $8.4) + if (fn_mod_104==76) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_F_D_BLEN; + } + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } + else + { + // RXQUAL_SUB : In case of speech traffic channels, accumulate number of + // estimated errors, this value is contained in a_dd_1[2] field, only + // for SID TDMA frames. (GSM 5.08 $8.4) + if (fn_mod_104==86) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_F_D_BLEN; + } + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + // Reset A_DD_1 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + } + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_1[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_F_D_BLEN; + + // WARNING: sequence number is not implemented in DATA half rate + // TO BE DEFINED...... + } // if(b_blud == TRUE) + } // if(((normalised_fn_report_mod26 == 20) || ... + #if (AMR == 1) + if ((channel_mode == TCH_AHS_MODE) && (facch_present == FALSE)) + { + // the channel is a TCH/AHS and it's time to receive a new block + if (subchannel == 0) + { + // Load the bit to check if the block is valid + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + } + else // subchannel 1 + { + // Load the bit to check if the block is valid + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & (1<> B_BLUD; + } + + b_ratscch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & (1<> B_BLUD; + + // All frames except NO_DATA (b_blud = FALSE) and FACCH, i.e AMR speech/SID block or a RATSCCH block + if(b_ratscch_blud==TRUE) + { + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_ratscch_dl[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[2] & 0xffff; + + // Reset the A_RATSCCH_DL header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[2] = 0xffff; + + // RXQUAL_FULL : the number of bits examined for errors on serving cell depends on + // the block received. + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += RATSCCH_BLEN; + + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + else if(b_blud==TRUE) + { + if (subchannel == 0) + { + // Load the type of the block received + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + + // Load the type of vocoder currently used + voco_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & VOCODER_TYPE_MASK) >> VOCODER_TYPE_SHIFT; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(rx_type, l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2], voco_type); + #endif + + // RXQUAL_SUB : In case of adaptative traffic channel, accumulate number of estimated errors + // is contained in the a_dd_0[2] value but the accumulation is made with SID_UPDATE frame only. + if((rx_type==SID_UPDATE) || (rx_type==SID_BAD)) + + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += SID_UPDATE_BLEN; + } + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + + + + + + + + + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] &= (API)(RX_TYPE_MASK); + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } + else // subchannel ==1 + { + // Load the type of the block received + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + + // Load the type of vocoder currently used + voco_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] & VOCODER_TYPE_MASK) >> VOCODER_TYPE_SHIFT; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(rx_type, l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2], voco_type); + #endif + + // RXQUAL_SUB : In case of adaptative traffic channel, accumulate number of estimated errors + // is contained in the a_dd_1[2] value but the accumulation is made with SID_UPDATE block only. + if((rx_type==SID_UPDATE) || (rx_type==SID_BAD)) + + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += SID_UPDATE_BLEN; + } + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_1[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + + // Reset A_DD_1 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] &= (API)(RX_TYPE_MASK); + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + } // subchannel == 1 + + + + + + // RXQUAL_FULL : the number of bits examined for errors on serving cell depends on + // the block received. +if((rx_type==SPEECH_GOOD) || (rx_type==SPEECH_DEGRADED) || (rx_type==SPEECH_BAD)) + { + // The block length depens on the vocoder type + switch (voco_type) + { + case AMR_CHANNEL_7_95: + { + // TCH-AHS 7.95 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_7_95_BLEN; + } + break; + case AMR_CHANNEL_7_4: + { + // TCH-AHS 7.4 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_7_4_BLEN; + } + break; + case AMR_CHANNEL_6_7: + { + // TCH-AHS 6.7 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_6_7_BLEN; + } + break; + case AMR_CHANNEL_5_9: + { + // TCH-AHS 5.9 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_5_9_BLEN; + } + break; + case AMR_CHANNEL_5_15: + { + // TCH-AHS 5.15 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_5_15_BLEN; + } + break; + case AMR_CHANNEL_4_75: + { + // TCH-AHS 4.75 + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_4_75_BLEN; + } + break; + } // switch + } // if ( (rx_type == SPEECH_GOOD) || ... + else + if((rx_type == SID_UPDATE) || (rx_type == SID_BAD)) + + { + // the block is a SID UPDATE + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += SID_UPDATE_BLEN; + } + + + + + + + + // AGC, TOA update for AMR... SUB FIFO only for SID_UPDATE frame + if((rx_type == SID_UPDATE) || (rx_type == SID_BAD)) + + { + IL_for_rxlev = l1ctl_dpagc_amr(1,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 1, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + #if (TOA_ALGO != 0) + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING == 1) + ,0 +#endif + ); + #endif + } + #endif + } + else + { + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + } // if (b_blud == TRUE) + // simple burst or NO_DATA frame + else + { + // NO_DATA is considered a bad frame + if (normalised_fn_report_mod13_mod4 == 3) + { + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AHS_4_75_BLEN; + if (subchannel == 0) + { + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(AMR_NO_DATA, l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2], 0); + #endif + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] &= (API)(RX_TYPE_MASK); + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } + else + { + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] & 0xffff; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(AMR_NO_DATA, l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2], 0); + #endif + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] &= (API)(RX_TYPE_MASK); + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + } + } + // Update AGC: Call DPAGC AMR algorithm in order to fill the G_all buffer + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); + + // Dedicated mode serving cell measurement reading, full set only. + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + } // if ((channel_mode == TCH_AHS_MODE) && (facch_present == FALSE)) + #endif + + // task is completed, make it INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + } + break; + + case TCHTF: + /*---------------------------------------------------*/ + /* Dedicated mode: TCHTF receive task. */ + /* FULL RATE */ + /*---------------------------------------------------*/ + { + UWORD8 IL_for_rxlev = 0; //omaps00090550 + UWORD32 b_blud; + + UWORD8 channel_mode; + //OMAPS00090550 UWORD8 channel_type; + UWORD32 fn_mod_104; + //OMAPS00090550 UWORD32 fn_mod_52; + UWORD32 fn_report_mod13_mod4; + #if (AMR == 1) + UWORD8 rx_type; + UWORD8 b_ratscch_blud,b_facch_blud; + BOOL facch_present = FALSE; + #endif + + #if TESTMODE + xSignalHeaderRec *msg; + #endif + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + + l1_check_pm_error(pm, task); + pm = pm >> 5; + + #if TRACE_TYPE==3 + stats_samples_tch(toa,pm,angle,snr); + #endif + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(TCHTF); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq,l1a_l1s_com.mode); + #endif + } + #endif + + // Check SID frame subset... + channel_mode = l1a_l1s_com.dedic_set.aset->achan_ptr->mode; + //OMAPS00090550 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; + fn_mod_104 = l1s.actual_time.fn % 104; + //OMAPS00090550 fn_mod_52 = l1s.actual_time.fn % 52; + + #if (AMR == 1) + // Check if we're in AMR DTX mode + if(channel_mode==TCH_AFS_MODE && (l1s.actual_time.fn_mod13 % 4)==0) // AFS: block is decoded on DSP side at fn%13%4=3 + { + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + b_ratscch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & (1<> B_BLUD; + b_facch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + + // Check if AMR DTX mode is on + if((((rx_type==SID_FIRST) || (rx_type==SID_UPDATE) || (rx_type==SID_BAD)) && b_blud==TRUE) || + (rx_type==AMR_NO_DATA && b_blud==FALSE)) + { + l1s.dtx_amr_dl_on=TRUE; + } + else if(b_ratscch_blud==FALSE && b_facch_blud==FALSE) + { + l1s.dtx_amr_dl_on=FALSE; + } + } + #endif + + #if REL99 + #if FF_EMR + emr_params.channel_mode = channel_mode; +// emr_params.fn_mod13_mod4 = l1s.actual_time.fn_mod13_mod4; + #if (AMR == 1) + emr_params.amr_facch_present = FALSE; + emr_params.amr_facch_fire1 = FALSE; + #endif + #endif + #endif + + // Increment number of burst not sent due to DTX. + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_u & 0xffff) == TCH_DTX_UL) + { + l1a_l1s_com.Smeas_dedic.dtx_used++; + l1s.dtx_ul_on = TRUE; + } + else + { + // Some bursts are always sent in DTX mode. d_task_u does not give DTX_UL + // so we must keep previous value of dtx_on + if (! ((fn_mod_104 > 52) && (fn_mod_104 <= 60)) ) + l1s.dtx_ul_on = FALSE; + } + + #if FF_L1_IT_DSP_DTX + // Currently used for TCH-AFS only + if (l1s.actual_time.fn_mod13_mod4 == 0) // FN%13 = 4, 8 and 12 (no TCH/F Read on FN%13=0) + { + // Latch TX activity status if DTX allowed + if ((l1a_l1s_com.dedic_set.aset->dtx_allowed == FALSE) || // No DTX allowed + (l1s_dsp_com.dsp_ndb_ptr->d_fast_dtx_enc_data) || // DTX allowed but not used + (l1a_apihisr_com.dtx.fast_dtx_ready == FALSE)) // Fast DTX status is invalid + l1a_apihisr_com.dtx.tx_active = TRUE; + else + l1a_apihisr_com.dtx.tx_active = FALSE; + } + #endif + + #if (AMR == 1) + if (channel_mode != TCH_AFS_MODE) + { + // This AGC and TOA update isn't applied to the adaptative full rate mode + #endif + + if((fn_mod_104 > 52) && (fn_mod_104 <= 60)) + // Current results are from the TDMA frame subset always received (GSM05.08, $8.3). + // -> pwr meas. must be used for SUB set result. + // -> TOA filtering can be fed with SNR/TOA. + // This DTX is only applied to the mode EFR, FR and data. + { + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(1,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + + // Dedicated mode serving cell measurement reading, indicate "SUB". + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 1, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + //Feed TOA histogram. + #if (TOA_ALGO != 0) + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING == 1) + ,0 +#endif + ); + #endif + } + #endif + } + else + { + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(0,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); + + // Dedicated mode serving cell measurement reading, full set only. + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + #if (AMR == 1) + } // if (channel_mode != TCH_AFS_MODE) + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev) + #endif + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + + // Compute FN in reporting period % 13 % 4. + fn_report_mod13_mod4 = (l1s.actual_time.fn_mod13) % 4; + + if(fn_report_mod13_mod4 == 0) + // It is time to get FACCH/F or TCH/F2.4 or TCH/(E)FS data block. + { + UWORD8 temp; + #if TRACE_TYPE==3 + if (l1_stats.type == PLAY_UL && + (channel_mode == TCH_FS_MODE || channel_mode == TCH_24F_MODE + || channel_mode == TCH_EFR_MODE)) + play_trace(); + #endif + + // FACCH: Check A_FD information block. + //------------------------------------- + + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_BLUD; + #if ((REL99) && (AMR == 1)) + #if FF_EMR + emr_params.amr_facch_fire1 = (l1s_dsp_com.dsp_ndb_ptr->a_fd[0] & (1<> B_FIRE1; + #endif + #endif + + if(b_blud == TRUE) + { + // Read FACCH DL data block from DSP, pass it to L2. + #if ( FF_REPEATED_DL_FACCH == 1 ) + #if (TRACE_TYPE == 1 || TRACE_TYPE == 4) + trace_info.facch_dl_count_all++; + #endif + /* if the current block is a repetition reports NULL to L2 otherwise reports the current block */ + l1s_read_dcch_dl((API*)l1s_repeated_facch_check(l1s_dsp_com.dsp_ndb_ptr->a_fd), task); + #else + /* UWORD8 error_flag =*/ l1s_read_dcch_dl(l1s_dsp_com.dsp_ndb_ptr->a_fd, task); + #endif /* ( FF_REPEATED_DL_FACCH == 1 ) */ + + #if (AMR == 1) + // Non AMR FACCH handling + if (channel_mode != TCH_AFS_MODE) + { + #endif + + // RXQUAL_SUB : In case of data taffic channels, accumulate number of + // estimated errors, this value is contained in a_fd[2] field, only + // for SID TDMA frames received as FACCH frames. (GSM 5.08 $8.4) + if (fn_mod_104==60) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_fd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_F_D_BLEN; + } + + #if (AMR == 1) + } + else + { + // AGC, RXLEV_FULL + + // Indicate to AMR specific processing that burst was a FACCH + facch_present = TRUE; + #if ((REL99) && (AMR == 1)) + #if FF_EMR + emr_params.amr_facch_present = facch_present; + #endif + #endif + + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + + // Dedicated mode serving cell measurement reading, indicate "FULL". + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + #endif + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_fd[2] field, for each TCHT block. + #if (AMR == 1) + // in AMR, l1s.dtx_amr_dl_on is FALSE if DTX mode is off + // in non AMR TCH, l1s.dtx_amr_dl_on is always FALSE + // In AMR DTX, DSP patch sometimes reports FACCH blocks which ARE NOT FACCH blocks + // therefore they shouldn't be taken into account in the RXQUALL_FULL computation + if(l1s.dtx_amr_dl_on==FALSE) + #endif + { + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_fd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_F_D_BLEN; + } + + + + + + + + + + // Reset A_FD header. + // B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 + l1s_dsp_com.dsp_ndb_ptr->a_fd[0] = (1<a_fd[2] = 0xffff; + + // Rem: when FACCH is received, we must reset A_DD_0 header also. + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + + // Rem: when FACCH is received, we must reset A_DD_1 header also. + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_1[2] = 0xffff; + + #if TESTMODE + if (l1_config.TestMode) + { + pm_fullres = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); // F26.6 + + // Allocate result message. + msg = os_alloc_sig(sizeof(T_TMODE_TCH_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = TMODE_TCH_INFO; + + ((T_TMODE_TCH_INFO *)(msg->SigP))->pm_fullres = pm_fullres; // F26.6 + ((T_TMODE_TCH_INFO *)(msg->SigP))->snr = snr; + ((T_TMODE_TCH_INFO *)(msg->SigP))->toa = toa; + ((T_TMODE_TCH_INFO *)(msg->SigP))->angle = (WORD16) angle; // signed + ((T_TMODE_TCH_INFO *)(msg->SigP))->qual_full = l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + ((T_TMODE_TCH_INFO *)(msg->SigP))->qual_nbr_meas_full = TCH_FS_BLEN; + + // send TMODE_TCH_INFO message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + #endif + } // if (b_blud == TRUE) + + else // (if (b_blud == TRUE) FACCH + { + // No FACCH received. + + // Dummy: Read FACCH DL data block from DSP, pass it to L2. + // Rem: this is an upper layer requirement to call this + // function at every FACCH DL boundary. + l1s_read_dcch_dl(NULL, task); + + #if (AMR == 1) + if (channel_mode != TCH_AFS_MODE) + { + #endif + + // Check A_DD_0 information block for TCH/F2.4 or TCH/FS. + // TCH/F2.4 or TCH/FS: Check A_DD_0 information block. + //---------------------------------------------------- + + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + if(b_blud == TRUE) + { + // RXQUAL_SUB : In case of speech traffic channels, accumulate number of + // estimated errors, this value is contained in a_dd_0[2] field, only + // for SID TDMA frames. (GSM 5.08 $8.4) + if (fn_mod_104==60) + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += TCH_FS_BLEN; + } + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_FS_BLEN; + + #if TESTMODE + if (l1_config.TestMode) + { + pm_fullres = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); // F26.6 + + // Allocate result message. + msg = os_alloc_sig(sizeof(T_TMODE_TCH_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = TMODE_TCH_INFO; + + ((T_TMODE_TCH_INFO *)(msg->SigP))->pm_fullres = pm_fullres; // F26.6 + ((T_TMODE_TCH_INFO *)(msg->SigP))->snr = snr; + ((T_TMODE_TCH_INFO *)(msg->SigP))->toa = toa; + ((T_TMODE_TCH_INFO *)(msg->SigP))->angle = (WORD16) angle; // signed + ((T_TMODE_TCH_INFO *)(msg->SigP))->qual_full = l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + ((T_TMODE_TCH_INFO *)(msg->SigP))->qual_nbr_meas_full = TCH_FS_BLEN; + + // send TMODE_TCH_INFO message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + #endif + + if(channel_mode == TCH_24F_MODE) + { + #if IDS + // Integrated Data Services implementation + { + dll_data_dl(l1s_dsp_com.dsp_ndb_ptr->a_data_buf_dl, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_act, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_statd); + } + #else + { + // DATA traffic. + // Pass data block to DATA ADAPTOR. + // REM: Data packet is always given to the DATA ADAPTOR. + // There is no RX quality check !! + { + rx_tch_data(&l1s_dsp_com.dsp_ndb_ptr->a_dd_0[3], channel_mode, 0); + } + } + #endif + } + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } // if(b_blud == TRUE) + #if (AMR == 1) + } // if (channel_mode != TCH_AFS_MODE) + #endif + } // if (b_blud == TRUE) FACCH (else) + #if (FF_REPEATED_DL_FACCH == 1) +#if 1 + temp=l1s.repeated_facch.counter_candidate; + l1s.repeated_facch.counter_candidate=l1s.repeated_facch.counter; + l1s.repeated_facch.counter=temp; +#else +if (l1s.repeated_facch.counter_candidate == 1) + l1s.repeated_facch.counter_candidate = 0 ; +else if (l1s.repeated_facch.counter_candidate == 0 ) + l1s.repeated_facch.counter_candidate = 0 ; + + l1s.repeated_facch.counter++ ; +if (l1s.repeated_facch.counter == 4) +{ +l1s.repeated_facch.counter = 0; +l1s.repeated_facch.pipeline[0].buffer_empty=l1s.repeated_facch.pipeline[1].buffer_empty=TRUE; +} +#endif + #endif/*(FF_REPEATED_DL_FACCH == 1)*/ +/* FACCH Full rate */ + } // if(fn_report_mod13_mod4 == 0) + + else // if(fn_report_mod13_mod4 == 0) + #if (AMR == 1) + if ((fn_report_mod13_mod4 == 2) && (channel_mode != TCH_AFS_MODE)) + #else + if(fn_report_mod13_mod4 == 2) + #endif + // It is time to get TCH/F4.8 or TCH/F9.6 data block. + { + #if TRACE_TYPE==3 + if (l1_stats.type == PLAY_UL && + (channel_mode == TCH_48F_MODE || channel_mode == TCH_96_MODE || channel_mode == TCH_144_MODE)) + play_trace(); + #endif + + // Check A_DD_0 information block only if no FACCH. + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + if(b_blud == TRUE) + { + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_F_D_BLEN; + + if((channel_mode == TCH_48F_MODE) || (channel_mode == TCH_96_MODE) || (channel_mode == TCH_144_MODE)) + { + #if IDS + // Integrated Data Services implementation + { + dll_data_dl(l1s_dsp_com.dsp_ndb_ptr->a_data_buf_dl, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_act, + &l1s_dsp_com.dsp_ndb_ptr->d_ra_statd); + } + #else + { + // DATA traffic. + // Pass data block to DATA ADAPTOR. + // REM: Data packet is always given to the DATA ADAPTOR. + // There is no RX quality check !! + { + UWORD8 sequence_number; + UWORD8 fn_report_mod26 = l1s.actual_time.fn_in_report % 26; + + // Catch sequence number. This is used in TCH/F4.8 to distinguish + // data blocks (see GSM 5.02) received on B0,B2,B4 (sequence number 0) + // and data blocks received on B1,B2,B3 (sequence number 1). + if((fn_report_mod26 == 23) || (fn_report_mod26 == 6) || (fn_report_mod26 == 15)) + sequence_number = 0; + else + sequence_number = 1; + rx_tch_data(&l1s_dsp_com.dsp_ndb_ptr->a_dd_0[3], channel_mode, sequence_number); + } + } + #endif + } + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } // if(b_blud == TRUE) + } // if(fn_report_mod13_mod4 == 2) + + #if (AMR == 1) + if ((channel_mode == TCH_AFS_MODE) && (facch_present == FALSE)) + { + // Load the bit to check if the block is valid + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & (1<> B_BLUD; + + // Load the bit to check if the block is a RATSCCH in case of rx_type = NO_DATA + b_ratscch_blud = (l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] & (1<> B_BLUD; + + // All detected AMR frames except NO_DATA (b_blud = 0) and FACCH are handled here, i.e. speech/SID/RATSCCH + if(b_ratscch_blud==TRUE) + { + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_ratscch_dl[2] field, for each TCHT block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[2] & 0xffff; + + // Reset the A_RATSCCH_DL header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_ratscch_dl[2] = 0xffff; + + // RXQUAL_FULL : the number of bits examined for errors on serving cell depends on + // the block received. + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += RATSCCH_BLEN; + + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + else if(b_blud==TRUE) + { + // Load the type of the block received + rx_type = (l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] & RX_TYPE_MASK) >> RX_TYPE_SHIFT; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(rx_type, l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2], 0); + #endif + + // RXQUAL_SUB : In case of adaptative traffic channel, accumulate number of estimated errors + // is contained in the a_dd_0[2] value but the accumulation is made with SID_UPDATE frame only. + // Note: SID_UPDATE frame corresponds to rx_type SID_UPDATE (b_ratscch_blud = FALSE) or SID_BAD (See Memo) + if((rx_type==SID_UPDATE) || (rx_type==SID_BAD)) + + { + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += SID_UPDATE_BLEN; + } + + // RXQUAL_FULL : accumulate number of estimated errors, this value is + // contained in a_dd_0[2] field, for each TCHT block. + + + + + // Frames, which have no class1 bit (so no quality meas is possible), have d_nerr = 0 + // so we can add them + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + + + + + + // RXQUAL_FULL : the number of bits examined for errors on serving cell depends on + // the block received. + if((rx_type==SPEECH_GOOD) || (rx_type==SPEECH_DEGRADED) || (rx_type==SPEECH_BAD)) + { + // It's a speech block + // Note: in AFS, the d_nerr value doesn't depend on the vocoder currently use + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AFS_BLEN; + } + else if((rx_type==SID_UPDATE) || (rx_type==SID_BAD)) + + + { + // the block is a SID UPDATE frame + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += SID_UPDATE_BLEN; + } + + + + + + + + // AGC, TOA, RXLEV for AMR. SUB queues only for SID_UPDATE frames + if((rx_type==SID_UPDATE) || (rx_type==SID_BAD)) + + { + IL_for_rxlev = l1ctl_dpagc_amr(1,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 1, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + #if (TOA_ALGO != 0) + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING == 1) + ,0 +#endif + ); + #endif + } + #endif + } + else + { + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm, radio_freq, IL_info_ptr); + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + } // if(b_blud==TRUE) + // NO_DATA block detected or simple burst + else + { + if (fn_report_mod13_mod4 == 0) + { + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += TCH_AFS_BLEN; + + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(AMR_NO_DATA, l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2], 0); + #endif + + // Reset A_DD_0 header in NDB. + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[0] = 0; + l1s_dsp_com.dsp_ndb_ptr->a_dd_0[2] = 0xffff; + } + + // Update AGC: Call DPAGC AMR algorithm in order to fill the G_all buffer + IL_for_rxlev = l1ctl_dpagc_amr(0,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); + + // Dedicated mode serving cell measurement reading, full set only. + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 0, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 0); + #endif + } + } // if ((channel_mode == TCH_AFS_MODE) && (facch_present == FALSE)) + #endif + + // task is completed, make it INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + } + break; + + case TCHA: + /*---------------------------------------------------*/ + /* Dedicated mode: SACCH receive task. */ + /*---------------------------------------------------*/ + { + UWORD8 IL_for_rxlev; + UWORD32 b_blud; + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + toa = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_TOA] & 0xffff; + pm = (l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_PM] & 0xffff); + angle = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_ANGLE] & 0xffff; + snr = l1s_dsp_com.dsp_db_r_ptr->a_serv_demod[D_SNR] & 0xffff; + + #if TESTMODE + if (l1_config.TestMode && l1_config.tmode.rf_params.down_up == TMODE_UPLINK) + { + // For UL-only tasks, TCHA is scheduled in every frame. TCH_INFO message is only + // used to count loops; no stats are collected. + + xSignalHeaderRec *msg; + // Allocate result message. + msg = os_alloc_sig(sizeof(T_TMODE_TCH_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = TMODE_TCH_INFO; + // send TMODE_TCH_INFO message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + // WARNING! + // Don't trace PM=0 during UL-only in TestMode. The DSP is not working + // in that case so it is normal. However, if tracing happens the CPU overloads + if (l1_config.TestMode && l1_config.tmode.rf_params.down_up & TMODE_DOWNLINK) + #endif + { + l1_check_pm_error(pm, task); + } + pm = pm >> 5; + + #if TRACE_TYPE==3 + stats_samples_tch_sacch(toa,pm,angle,snr); + #endif + + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(task); + #endif + + // Update AGC: Call DPAGC algorithm + IL_for_rxlev = l1ctl_dpagc(1,beacon,(UWORD8)pm,radio_freq,IL_info_ptr); // dtx_on = 1 + + // Dedicated mode serving cell measurement reading, indicate "SUB". + #if REL99 + #if FF_EMR + l1s_read_dedic_scell_meas(IL_for_rxlev, 1, &emr_params); + #endif + #else + l1s_read_dedic_scell_meas(IL_for_rxlev, 1); + #endif + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, radio_freq,l1a_l1s_com.mode); + #endif + } + #endif + + //Feed TOA histogram. + #if (TOA_ALGO != 0) + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + UWORD32 snr_temp; + snr_temp = (IL_for_rxlev < IL_FOR_RXLEV_SNR)? snr: 0; + #if (TOA_ALGO == 2) + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa, &l1s.toa_update, &l1s.toa_period_count +#if (FF_L1_FAST_DECODING == 1) + ,0 +#endif + ); + #endif + + } + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev) + #endif + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev); + #endif + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + + if(l1s.actual_time.fn_in_report == 91) + // It's time to read a SACCH DL result from DSP. + { + // Check A_CD information block. + b_blud = (l1s_dsp_com.dsp_ndb_ptr->a_cd[0] & (1<> B_BLUD; + if(b_blud == TRUE) + { + #if W_A_DSP1 + // Temporary correction to fix a known DSP problem. SACCH deinterleaver not + // initialized on HO. + // + if (old_sacch_DSP_bug == TRUE) + { + // Invalidate the current sacch block - indicate it cannot be decoded + l1s_dsp_com.dsp_ndb_ptr->a_cd[0] = (1<a_cd, task); + + // RXQUAL_FULL/RXQUAL_SUB : Accumulate number of estimated errors, this value + // is contained in a_cd[2] field, for every SACCH block. + l1a_l1s_com.Smeas_dedic.qual_acc_full += l1s_dsp_com.dsp_ndb_ptr->a_cd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full += A_D_BLEN; + l1a_l1s_com.Smeas_dedic.qual_acc_sub += l1s_dsp_com.dsp_ndb_ptr->a_cd[2] & 0xffff; + l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub += A_D_BLEN; + + // TEMPORARY : reset buffers and flags in NDB ... + // reset nerr.... + // reset A_CD contents....... + l1s_dsp_com.dsp_ndb_ptr->a_cd[0] = (1<a_cd[2] = 0xffff; + } + } + #if W_A_DSP1 + else if (l1s.actual_time.fn_in_report == 13) // TF 5/8/98 - DSP fix + { + // As this is the first SACCH burst the known DSP bug cannot occur on a new channel. + old_sacch_DSP_bug = FALSE; + } + #endif + + // task is completed, make it INACTIVE. + l1s.task_status[task].current_status = INACTIVE; + } + break; + } // End switch... + + l1ddsp_read_iq_dump(task); + // Flag the use of the MCU/DSP dual page read interface. + // ****************************************************** + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +/*-------------------------------------------------------*/ +/* l1s_read_tx_result() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1s_read_tx_result(UWORD8 task, UWORD8 burst_id) +{ + /*--------------------------------------------------------*/ + /* READ TRANSMIT TASK RESULTS... */ + /*--------------------------------------------------------*/ + + #if (TRACE_TYPE!=0) + if(task==RAACC) + { + if((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_ra & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) + trace_fct(CST_UL_TASKS_DO_NOT_CORRESPOND, 1);//OMAPS00090550 + } + else + { + if(((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_u & 0xffff) != (UWORD32)DSP_TASK_CODE[task]) && + ((UWORD32)(l1s_dsp_com.dsp_db_r_ptr->d_task_u & 0xffff) != TCH_DTX_UL)) + trace_fct(CST_UL_TASKS_DO_NOT_CORRESPOND, 1);//OMAPS00090550 + } + #endif + + l1_check_com_mismatch(task); + + switch(task) + { + case RAACC: + /*---------------------------------------------------*/ + /* Serving Cell: Random Access TX task. */ + /*---------------------------------------------------*/ + // Rem: confirmation message is sent at "CTRL" to be able to give FN%42432. + { + // Send confirmation msg to L1A. + // ****************************** + + // For ACCESS phase, a confirmation msg is sent to L1A. + xSignalHeaderRec *msg; + + // send L1C_RA_DONE to L1A... + msg = os_alloc_sig(sizeof(T_MPHC_RA_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + if (l1s.actual_time.fn == 0) + ((T_MPHC_RA_CON *)(msg->SigP))->fn = MAX_FN - 1; + else + ((T_MPHC_RA_CON *)(msg->SigP))->fn = l1s.actual_time.fn - 1; + + ((T_MPHC_RA_CON *)(msg->SigP))->channel_request = l1a_l1s_com.ra_info.channel_request; + msg->SignalCode = L1C_RA_DONE; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Desactivate the RAACC task. + l1s.task_status[task].current_status = INACTIVE; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_RA, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + break; + + case DUL: + /*---------------------------------------------------*/ + /* Serving Cell: SDCCH up link. */ + /*---------------------------------------------------*/ + { + // Desactivate UL task. + if(burst_id == BURST_4) + { + l1s.task_status[task].current_status = INACTIVE; + + #if (TRACE_TYPE == 5) // in simulation only the 4th burst is traced + trace_fct(CST_L1S_READ_TX_NB__DUL, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_TX_NB__DUL, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + break; + + case AUL: + /*---------------------------------------------------*/ + /* Serving Cell: SACCH up link. */ + /*---------------------------------------------------*/ + { + // Desactivate UL task. + if(burst_id == BURST_4) + { + l1s.task_status[task].current_status = INACTIVE; + + #if (TRACE_TYPE == 5) // in simulation only the 4th burst is traced + trace_fct(CST_L1S_READ_TX_NB__AUL, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_TX_NB__AUL, l1a_l1s_com.Scell_info.radio_freq); + #endif + + } + break; + + case TCHA: + case TCHTF: + /*---------------------------------------------------*/ + /* Serving Cell: TCH link. */ + /*---------------------------------------------------*/ + { + #if (TRACE_TYPE==5) + if(burst_id == BURST_4) // in simulation only the 4th burst is traced + trace_fct(CST_L1S_READ_TX_NB__TCHF, l1a_l1s_com.Scell_info.radio_freq); + #endif + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_TX_NB__TCHF, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + break; + + case TCHTH: + /*---------------------------------------------------*/ + /* Serving Cell: TCH link. */ + /*---------------------------------------------------*/ + { + #if (TRACE_TYPE==5) + if(burst_id == BURST_2) // in simulation only lates burst is traced + trace_fct(CST_L1S_READ_TX_NB__TCHH, l1a_l1s_com.Scell_info.radio_freq); + #endif + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1S_READ_TX_NB__TCHH, l1a_l1s_com.Scell_info.radio_freq); + #endif + } + break; + } + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; +} + +/*-------------------------------------------------------*/ +/* l1s_read_dedic_scell_meas() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ + +#if REL99 +#if FF_EMR +void l1s_read_dedic_scell_meas(UWORD8 input_level, UWORD8 sub_flag, T_EMR_PARAMS *emr_params) +{ + UWORD8 task; + UWORD8 burst_id; + UWORD8 b_blud; + UWORD8 counter; + UWORD8 bfi; // band frame indicator + UWORD8 channel_mode; // current channel type + //OMAPS00090550 UWORD8 fn_report_mod_26; + UWORD8 subchannel; // half rate sub channel + UWORD8 sid_present; // indication for sid block + UWORD16 rx_type; + UWORD32 normalised_fn_mod13_mod4; + + UWORD16 mean_bep_lsb = 0; //l1s_dsp_com.dsp_ndb_ptr->d_mean_bep_block_lsb; + UWORD16 mean_bep_msb = 0; //l1s_dsp_com.dsp_ndb_ptr->d_mean_bep_block_msb; + UWORD32 mean_bep = 0; //((mean_bep_msb<> MEAN_BEP_FORMAT; + UWORD16 cv_bep = 0; //(l1s_dsp_com.dsp_ndb_ptr->d_cv_bep_block) >> CV_BEP_FORMAT; + + static WORD16 last_corr_decoded_burst[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + static UWORD16 cv_bep_tch4_8f_144[2] = {0, 0}; + static UWORD32 mean_bep_tch4_8f_144[2] = {0, 0}; + + WORD16 rxlev = l1s_encode_rxlev(input_level); + + if (l1s_dsp_com.dsp_r_page == 1) + { + cv_bep = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_0[D_CV_BEP]; + mean_bep_msb = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_0[D_MEAN_BEP_MSW]; + mean_bep_lsb = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_0[D_MEAN_BEP_LSW]; + } + else + { + cv_bep = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_1[D_CV_BEP]; + mean_bep_msb = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_1[D_MEAN_BEP_MSW]; + mean_bep_lsb = l1s_dsp_com.dsp_ndb_ptr->a_mean_cv_bep_page_1[D_MEAN_BEP_LSW]; + } + + mean_bep = ((mean_bep_msb<> MEAN_BEP_FORMAT; + cv_bep = cv_bep >> CV_BEP_FORMAT; + + // EMR : Copy of Legacy code begins + // Measurement must be rejected if channel is hopping, hopped on + // the beacon frequency and PWRC is TRUE (see GSM05.08, $8.1.3). + if(!((l1a_l1s_com.dedic_set.pwrc == TRUE) && + (l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->chan_sel.h == TRUE) && + (l1a_l1s_com.dedic_set.radio_freq_dd == l1a_l1s_com.Scell_info.radio_freq))) + { + // Add to FULL set meas. + l1a_l1s_com.Scell_info.meas.nbr_meas++; + l1a_l1s_com.Scell_info.meas.acc += rxlev; + + if(sub_flag == TRUE) + { + // Add to SUB set meas. + l1a_l1s_com.Smeas_dedic.nbr_meas_sub++; + l1a_l1s_com.Smeas_dedic.acc_sub += rxlev; + } // if(sub_flag == TRUE) + // EMR : Copy of Legacy code ends + } // if(!((l1a_l1s_com.dedic_set.pwrc == TRUE) && .... + + // new rxlev is received. remove the oldest rxlev. + for(counter=0;counter<=6;counter++) + last_corr_decoded_burst[counter] = last_corr_decoded_burst[counter+1]; + + // store new rxlev. + last_corr_decoded_burst[7] = rxlev; + + task = emr_params->task; + burst_id = emr_params->burst_id; + channel_mode = emr_params->channel_mode; + normalised_fn_mod13_mod4 = emr_params->normalised_fn_mod13_mod4; + + // TCH FS and TCH EFR + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 0) && + ((channel_mode == TCH_FS_MODE) || + (channel_mode == TCH_EFR_MODE) || + (channel_mode == SIG_ONLY_MODE))) + { + if(emr_params->facch_present == TRUE) + { + // FACCH + if(emr_params->facch_fire1 == FALSE) + { + // FACCH correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + if(channel_mode == SIG_ONLY_MODE) + // accumulation of correctly decoded blocks excluding SACCH and SID frames FACCH only for sig only mode + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + + } // if(facch_fire1 == FALSE) + } // if(facch_present == TRUE ) + else + { + // NOT FACCH, + if (emr_params->a_dd_0_blud == TRUE) + { + if (emr_params->a_dd_0_bfi == FALSE) + { + // speech correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + if (emr_params->sid_present_sub0 == FALSE) + { + // accumulation of correctly decoded blocks excluding SACCH FACCH and SID frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if(sid_present == FALSE) + } // if(bfi == FALSE) + } // if(b_blud == TRUE) + } // else part of if(facch_present == TRUE ) + } // TCH FS and TCH EFR + + // TCH 2.4F + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 0) && + (channel_mode == TCH_24F_MODE)) + { + if(emr_params->facch_present == TRUE) + { + if(emr_params->facch_fire1 == FALSE) + { + // FACCH correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } + } // if(facch_present == TRUE) + else + { + // NOT FACCH check whether the data buffer is updated!! + if(emr_params->a_dd_0_blud == TRUE) + { + // Check if transparent data or not + if(emr_params->b_ce == TRUE)// Non Transparent + { + //check if correctly decoded or not + if(emr_params->a_ntd == FALSE)//good frame detected + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + // accumulation of correctly decoded blocks excluding SACCH FACCH frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if(a_ntd == FALSE) + } // if(b_ce == TRUE) + else + { + // 2.4F transperent data (always considered as correctly decoded) + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // accumulation of decoded blocks excluding SACCH FACCH and SID frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if(b_ce == TRUE) + } // if(b_blud == TRUE) + } // else part of if(facch_present == TRUE) + } // TCH 2.4F + + // TCH 9.6F + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 0) && + (channel_mode == TCH_96_MODE)) + { + if(emr_params->facch_present == TRUE) + { + if(emr_params->facch_fire1 == FALSE) + { + // FACCH correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } //if(fire1 == FALSE) + } //if(facch_present == TRUE) + } // if(fn_mod13_mod4 == 0) + + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 2) && + (channel_mode == TCH_96_MODE)) + { + if(emr_params->a_dd_0_blud == TRUE) + { + // Check if transparent data or not + if(emr_params->b_ce == TRUE)// Non Transparent + { + //check if correctly decoded or not + if(emr_params->a_ntd == FALSE)//good frame detected + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // accumulation of correctly decoded blocks excluding SACCH FACCH frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if(a_ntd == FALSE) + } // if(b_ce == TRUE) + else + { + // transparent data (always correctly decoded) + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // accumulation of decoded blocks excluding SACCH FACCH frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // transparent data + } // if(b_blud == TRUE) + } // TCH F9.6 + + // TCH 4.8F/14.4F + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 0) && + ((channel_mode == TCH_48F_MODE) || (channel_mode == TCH_144_MODE)) ) + { + if(emr_params->facch_present == TRUE) + { + if(emr_params->facch_fire1 == FALSE) + { + // FACCH correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4;// 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } //if(fire1 == FALSE) + } //if(facch_present == TRUE) + } // if(fn_mod13_mod4 == 0) + + if((task == TCHTF) && + (l1s.actual_time.fn_mod13_mod4 == 2) && + ((channel_mode == TCH_48F_MODE) || (channel_mode == TCH_144_MODE)) ) + { + // block end add new value of mean_bep and cv_bep value to mean_bep_tch4_8f_144 and + // cv_bep_tch4_8f_144. remove the oldest value. + mean_bep_tch4_8f_144[0] = mean_bep_tch4_8f_144[1]; + cv_bep_tch4_8f_144[0] = cv_bep_tch4_8f_144[1]; + mean_bep_tch4_8f_144[1] = mean_bep; + cv_bep_tch4_8f_144[1] = cv_bep; + + if ( ((emr_params->a_dd_0_blud == TRUE) && (emr_params->b_m1) && (channel_mode == TCH_144_MODE)) || + ((emr_params->a_dd_0_blud == TRUE) && (emr_params->b_f48blk_dl) && (channel_mode == TCH_48F_MODE)) ) + { + // Check if transparent data or not + if(emr_params->b_ce == TRUE) // Non transparent + { + //check if correctly decoded or not. Accumulate last 8 slots + if(emr_params->a_ntd == FALSE) //good frame detected + { + // two blocks are accumulated at a time, increment by 2. + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas+=8; // 8 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep_tch4_8f_144[0] + mean_bep_tch4_8f_144[1]; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep_tch4_8f_144[0] + cv_bep_tch4_8f_144[1]; + + // two blocks are accumulated at a time, increment by 2. + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num += 2; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num+=2; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[0] + + last_corr_decoded_burst[1] + + last_corr_decoded_burst[2] + + last_corr_decoded_burst[3] + + last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // accumulation of correctly decoded blocks excluding SACCH FACCH frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks +=2; + } // if(a_ntd == FALSE) + } // if(b_ce == TRUE) + else + { + // transparent data + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=8; // 8 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep_tch4_8f_144[0] + mean_bep_tch4_8f_144[1]; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep_tch4_8f_144[0] + cv_bep_tch4_8f_144[1]; + + // two blocks are accumulated at a time, increment by 2. + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num+=2; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num += 2; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[0] + + last_corr_decoded_burst[1] + + last_corr_decoded_burst[2] + + last_corr_decoded_burst[3] + + last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // accumulation of correctly decoded blocks excluding SACCH FACCH frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks +=2; + } // Transparent data + } // if(b_blud == TRUE) + } // TCH 4.8F/14.4 + + + // TCH HS + if((task == TCHTH) && + ((channel_mode == TCH_HS_MODE)||(channel_mode == SIG_ONLY_MODE))&& + (normalised_fn_mod13_mod4 == 3) ) + { + UWORD8 norm_fn_mod26; + + subchannel = emr_params->subchannel; + norm_fn_mod26 = ((l1s.actual_time.fn - subchannel + 26) % 26); + + if(subchannel == 0) + { + b_blud = emr_params->a_dd_0_blud; + bfi = emr_params->a_dd_0_bfi; // 3rd bit tells the BAD frame. + sid_present = emr_params->sid_present_sub0; // find out whether sid1 is 0/1, 1 mean + } + else + { + b_blud = emr_params->a_dd_1_blud; + bfi = emr_params->a_dd_1_bfi; // 3rd bit tells the BAD frame. + sid_present = emr_params->sid_present_sub1; // find out whether sid1 is 0/1, 1 mean + } + + if(norm_fn_mod26 == 7 || norm_fn_mod26 == 16|| norm_fn_mod26 == 24 ) + { + // FACCH: Check A_FD information block. + if(emr_params->facch_present == TRUE) + { + // FACCH correctly decoded + if(emr_params->facch_fire1 == FALSE) + { + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + if((channel_mode == SIG_ONLY_MODE)) + // accumulation of correctly decoded blocks excluding SACCH + // and SID frames FACCH only for sig only mode + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } //if(fire1 == FALSE) + } //if(facch_present ==....) + else + { + // No Facch at this positions 7,16,24 + if (b_blud == TRUE) + { + if(bfi == FALSE) + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[7] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[4] ; + + //as per standard 05.08 section 8.3 + //sid_present can become true only at (fn modulo 26) == 6 + //sid_present will be false at all other points + + if(sid_present == FALSE) + // accumulation of correctly decoded blocks excluding SACCH + // FACCH and SID frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if(bfi == FALSE) + } // if (b_blud == TRUE) + } // else facch_present + } //if(norm_fn_report_mod26 == 7 || norm_fn_report_mod26 == 16|| norm_fn_report_mod26 == 24 ) + else + { + //norm_fn_report_mod26 == 3 || norm_fn_report_mod26 == 11|| norm_fn_report_mod26 == 20 + if (b_blud == TRUE) + { + if(bfi == FALSE) + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[7] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[4] ; + + //as per standard 05.08 section 8.3 + //sid_present can become true only at (fn modulo 26) == 6 + //sid_present will be false at all other points + + if(sid_present == FALSE) + // accumulation of correctly decoded blocks excluding SACCH + // FACCH and SID frames + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } //if(bfi == FALSE) + } // if (b_blud == TRUE) + } //else + }//task == TCHTH..... + + // SACCH of TCH + if((task == TCHA)) + { + //unconditionnal accumulation of rxlev_val + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas++; + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += rxlev; + if(l1s.actual_time.fn_in_report == 91) + { + // Set detection flag. + if(emr_params->a_cd_fire1 == FALSE) + { + // rec 05.08 8.2.3: BEP value need to be accumulated on correctly received blocks + // rec 05.08 8.4.8.2 : for SACCH of TCH, no accumulation for CV_BEP and nbr_rcvd_blocks + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + } // if(fire1 == FALSE) + } // if(l1s.actual_time.fn_in_report == 91) + } // // SACCH of TCH + + // SDCCH and SACCH of SDCCH + if (((task == DDL) || (task == ADL)) && (burst_id == BURST_4)) + { + //unconditional accumulation of Rxlev_val + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + // rec 05.08 8.2.3: in SDCCH, BEP value need to be accumulated on correctly received blocks + if(emr_params->a_cd_fire1 == FALSE) + { + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + } + } // SDCCH + + //AMR FS + #if (AMR == 1) + if((task == TCHTF) && + (channel_mode == TCH_AFS_MODE) && + (l1s.actual_time.fn_mod13_mod4 == 0)) + { + if(emr_params->amr_facch_present == TRUE) + { + // FACCH present + // FACCH correctly decoded ? + if(emr_params->amr_facch_fire1 == FALSE) + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } // if(fire1 == FALSE) + } // if(facch_present == TRUE) + else + { + // NOT FACCH + if ((emr_params->b_ratscch_blud == TRUE) && (emr_params->ratscch_rxtype == RATSCCH_GOOD)) + { + //RATSCCH correctly decoded + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } // if(b_ratscch_blud == TRUE) + else if(emr_params->a_dd_0_blud == TRUE) + { + // Good speech frame. + if((emr_params->amr_rx_type_sub0 == SPEECH_GOOD) || + (emr_params->amr_rx_type_sub0 == SPEECH_DEGRADED) || + (emr_params->amr_rx_type_sub0 == SID_UPDATE)) + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc += mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc += cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + + if ((emr_params->amr_rx_type_sub0 == SPEECH_GOOD) || (emr_params->amr_rx_type_sub0 == SPEECH_DEGRADED)) + //Number of correctly decoded blocks excluding SACCH FACCH RATSCCH and SID frames. + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } // if((rx_type == SPEECH_GOOD) || (rx_type == SID_UPDATE)) + } // else if(b_blud == TRUE) + } // else of if(facch_present == TRUE) + } //AMR FS + + //AMR HS + //TCH AHS + if((task == TCHTH) && + (channel_mode == TCH_AHS_MODE)&& + (normalised_fn_mod13_mod4 == 3)) + { + UWORD8 norm_fn_mod26; + subchannel = emr_params->subchannel; + + if (subchannel == 0) + { + // Load the bit to check if the block is valid + b_blud = emr_params->a_dd_0_blud; + rx_type = emr_params->amr_rx_type_sub0; + } + else // subchannel 1 + { + // Load the bit to check if the block is valid + b_blud = emr_params->a_dd_1_blud; + rx_type = emr_params->amr_rx_type_sub1; + } + + norm_fn_mod26 = (l1s.actual_time.fn - subchannel +26) % 26; + + if(norm_fn_mod26 == 7 || + norm_fn_mod26 == 16|| + norm_fn_mod26 == 24 ) + { + // FACCH: Check A_FD information block. + if(emr_params->amr_facch_present == TRUE) + { + // FACCH present + // FACCH correctly decoded ? + if(emr_params->amr_facch_fire1 == FALSE) + { + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc +=mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc +=cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc += last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + } // if(fire1 == FALSE) + } // if(facch_present == TRUE) + else + { + // NOT FACCH + // Load the bit to check if the block is a RATSCCH in caseof rx_type = NO_DATA + //In half rate, there are 2 consecutive frames called RATSCCH_MARKER and + //RATSCCH_DATA, MARKER doesn't contain any CRC. So we cannot make a decision + //whether RATSCCH_MARKER is correctly decoded. Hence ratscch_rxtype_prev + //is not valid. Hence the inner check has to be based only on ratscch_rxtype. + //ratscch_rxtype is updated based on the CRC of RATSCCH_DATA. + //The following are the decisions on the outer check "if (b_ratscch_blud == TRUE).... + //b_ratscch_blud is updated based on RATSCCH_DATA. Hence it is a valid check + //b_ratscch_blud_prev would have been accumulated based on RATSCCH_MARKER. + //The assumption here is that when RATSCCH_MARKER is detected, the b_blud bit of + //a_ratscch_dl will be updated. + + if ( ((emr_params->b_ratscch_blud == TRUE) && (emr_params->ratscch_rxtype == RATSCCH_GOOD)) || + ((b_blud==TRUE) && (rx_type == SID_UPDATE)) || + ((b_blud == TRUE)&&(rx_type == SPEECH_DEGRADED)) || + ((b_blud == TRUE)&&(rx_type == SPEECH_GOOD)) ) + { + //RATSCCH or SID Update or Speech block correctly decoded, increment the counter + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc +=mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc +=cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc +=last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + if (((rx_type == SPEECH_GOOD) || (rx_type == SPEECH_DEGRADED)) && (emr_params->ratscch_rxtype != RATSCCH_GOOD)) + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } + } // else part of if(facch_present == TRUE) + }//fnmod26 == 7||16 || 24 + else + { + //if (norm_fn_mod26 ==3 || norm_fn_mod26 == 11 || + //norm_fn_mod26 == 20) + + if ( ((emr_params->b_ratscch_blud == TRUE) && (emr_params->ratscch_rxtype == RATSCCH_GOOD)) || + ((b_blud==TRUE) && (rx_type == SID_UPDATE)) || + ((b_blud == TRUE)&&(rx_type == SPEECH_DEGRADED)) || + ((b_blud == TRUE)&&(rx_type == SPEECH_GOOD)) ) + { + //RATSCCH or SID Update or Speech block correctly decoded, increment the counter + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas +=4; // 4 bursts are accumulated + + // Accumulate BEP + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc +=mean_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc +=cv_bep; + l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num++; + l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num++; + + //accumulation of the correctly decoded block + l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc +=last_corr_decoded_burst[4] + + last_corr_decoded_burst[5] + + last_corr_decoded_burst[6] + + last_corr_decoded_burst[7]; + if (((rx_type == SPEECH_GOOD) || (rx_type == SPEECH_DEGRADED)) && (emr_params->ratscch_rxtype != RATSCCH_GOOD)) + l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks++; + } + } //else fn = 3,11,20 + }//task == TCHTH..... + #endif //(AMR == 1) +} +#endif //FF_EMR +#else //REL99 + +void l1s_read_dedic_scell_meas(UWORD8 input_level, UWORD8 sub_flag) +{ + WORD16 rxlev = l1s_encode_rxlev(input_level); + + // Measurement must be rejected if channel is hopping, hopped on + // the beacon frequency and PWRC is TRUE (see GSM05.08, $8.1.3). + if(!((l1a_l1s_com.dedic_set.pwrc == TRUE) && + (l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->chan_sel.h == TRUE) && + (l1a_l1s_com.dedic_set.radio_freq_dd == l1a_l1s_com.Scell_info.radio_freq))) + { + // Add to FULL set meas. + l1a_l1s_com.Scell_info.meas.nbr_meas++; + l1a_l1s_com.Scell_info.meas.acc += rxlev; + + if(sub_flag == TRUE) + { + // Add to SUB set meas. + l1a_l1s_com.Smeas_dedic.nbr_meas_sub++; + l1a_l1s_com.Smeas_dedic.acc_sub += rxlev; + } + } +} +#endif //REL99 +/*-------------------------------------------------------*/ +/* l1s_dedic_reporting() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1s_dedic_reporting() +{ + xSignalHeaderRec *msg; + UWORD8 i; + UWORD32 nbr_carrier = l1a_l1s_com.ba_list.nbr_carrier; + + // Allocate L1C_MEAS_DONE message... + msg = os_alloc_sig(sizeof(T_MPHC_MEAS_REPORT)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = L1C_MEAS_DONE; + + // Fill miscelaneous parameters + //============================= + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->ba_id = l1a_l1s_com.ba_list.ba_id; + + //timing_advance... + //txpwr... + //meas_valid... + + // Fill msg for Neighbor Cells + //============================ + + for(i=0;iSigP))->ncell_meas.A[i].bcch_freq = ba_ptr->radio_freq; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->ncell_meas.A[i].rxlev_acc = ba_ptr->acc; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->ncell_meas.A[i].rxlev_nbr_meas = ba_ptr->nbr_meas; + + // Reset BA. + ba_ptr->acc = 0; + ba_ptr->nbr_meas = 0; + } + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->no_of_ncell_meas = nbr_carrier; + + // Fill msg for Serving Cell + //========================== + + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_full_acc = l1a_l1s_com.Scell_info.meas.acc; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_full_nbr_meas = l1a_l1s_com.Scell_info.meas.nbr_meas; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_sub_acc = l1a_l1s_com.Smeas_dedic.acc_sub; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_sub_nbr_meas = l1a_l1s_com.Smeas_dedic.nbr_meas_sub; + + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxqual_full_acc_errors = l1a_l1s_com.Smeas_dedic.qual_acc_full; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxqual_full_nbr_bits = l1a_l1s_com.Smeas_dedic.qual_nbr_meas_full; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxqual_sub_acc_errors = l1a_l1s_com.Smeas_dedic.qual_acc_sub; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxqual_sub_nbr_bits = l1a_l1s_com.Smeas_dedic.qual_nbr_meas_sub; + + #if REL99 + #if FF_EMR + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_val_acc = l1a_l1s_com.Smeas_dedic_emr.rxlev_val_acc; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->rxlev_val_nbr_meas = l1a_l1s_com.Smeas_dedic_emr.rxlev_val_nbr_meas; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->nbr_rcvd_blocks = l1a_l1s_com.Smeas_dedic_emr.nbr_rcvd_blocks; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->mean_bep_block_acc = l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_acc; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->cv_bep_block_acc = l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_acc; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->mean_bep_block_num = l1a_l1s_com.Smeas_dedic_emr.mean_bep_block_num; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->cv_bep_block_num = l1a_l1s_com.Smeas_dedic_emr.cv_bep_block_num; + #endif + #endif + + if(l1a_l1s_com.dedic_set.aset->dtx_allowed == TRUE) + // Set "dtx_used" flag according to DSP transmit report result only if + // DTX is allowed. + { + if(l1a_l1s_com.Smeas_dedic.dtx_used > 0) + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->dtx_used = TRUE; + // Set the dtx_used flag in the case of TCHF/ no signaling + else if ((l1a_l1s_com.dedic_set.aset->chan1.mode == SIG_ONLY_MODE) + &&(l1a_l1s_com.dedic_set.aset->chan1.desc.channel_type==TCH_F)) + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->dtx_used = TRUE; + else + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->dtx_used = FALSE; + } + else + { + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->dtx_used = FALSE; + } + + // Reset Serving Cell measurement variables. + l1s_reset_dedic_serving_meas(); + + + // Give miscellaneous info to L3 (just for indication/debug). + //=========================================================== + + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->timing_advance = l1a_l1s_com.dedic_set.aset->timing_advance; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->txpwr_used = l1s.reported_txpwr; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->facch_dl_count = trace_info.facch_dl_count; + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->facch_ul_count = trace_info.facch_ul_count; + #if (FF_REPEATED_DL_FACCH == 1) + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->facch_dl_combined_good_count = trace_info.facch_dl_combined_good_count; /* No of good blocks after combining */ + ((T_MPHC_MEAS_REPORT*)(msg->SigP))->facch_dl_repetition_block_count = trace_info.facch_dl_repetition_block_count; + #endif/* (FF_REPEATED_DL_FACCH == 1) */ + trace_info.facch_dl_fail_count_trace = trace_info.facch_dl_fail_count; + trace_info.facch_dl_count = 0; + trace_info.facch_ul_count = 0; + trace_info.facch_dl_fail_count = 0; + #if ( FF_REPEATED_DL_FACCH == 1 ) /* Reseting the values */ + trace_info.facch_dl_combined_good_count = 0; + trace_info.facch_dl_repetition_block_count = 0; + #endif/* (FF_REPEATED_DL_FACCH == 1) */ + #endif + + // send L1C_MEAS_DONE message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_read_fb() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : this function sends L1C_FB_INFO to L1A*/ +/*-------------------------------------------------------*/ +void l1s_read_fb(UWORD8 task, UWORD32 fb_flag, UWORD32 toa, UWORD32 attempt, + UWORD32 pm, UWORD32 angle, UWORD32 snr) +{ + xSignalHeaderRec *msg; + WORD32 modif_toa = 0; + WORD32 ntdma =0 ; //omaps000090550 + UWORD32 fn_offset =0 ; //omaps000090550 ; + + // For detail of the here below equation cf. BUG1558 + #define MAX_TOA_FOR_SB (D_NSUBB_DEDIC*48)+DL_ABB_DELAY/4-(SB_BURST_DURATION+DL_ABB_DELAY+SB_MARGIN)/4-2 + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dspres(dltsk_trace[task].name); + #endif + + #if (TRACE_TYPE!=0) + switch(task) + { + case FBNEW: trace_fct(CST_L1S_READ_FB, l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq);break; + case FB51: trace_fct(CST_L1S_READ_FB51, l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq);break; + case FB26: trace_fct(CST_L1S_READ_FB26, l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq);break; + default: trace_fct(CST_UNKNOWN_FB, l1a_l1s_com.nsync.list[0].radio_freq);break; + } + #endif + + if(fb_flag == TRUE) + { + switch (task) + { + case FBNEW: + case FB51: + // Compute NTDMA & TOA taking into account the 23 bit guard for next SB receive window. + { + modif_toa = toa - (SB_MARGIN/4); // Rem: unit is "BIT". + } + break; + + case FB26: + // Compute TOA taking into account the 23 bit guard for next SB receive window + // and the time diff. between a the fb search and a normal serving RX slot.. + // Rem: TOA cannot be less than "SB_MARGIN/4". + { + // Saturate TOA to MAX_TOA_FOR_SB since it is the last position compatible with the + // SB26 tpu programming. MAX_TOA_FOR_SB + 1 would reject the TCHT/frame0 one frame later due + // to an overlap of TPU scenarios. + if(toa >= MAX_TOA_FOR_SB) toa = MAX_TOA_FOR_SB; + + modif_toa = toa + ((l1_config.params.fb26_anchoring_time + PROVISION_TIME - START_RX_FB)/4) - (SB_MARGIN/4); // Rem: unit is "BIT". + } + break; + } // End of switch. + + if(modif_toa < 0) + { + modif_toa = (modif_toa + (TPU_CLOCK_RANGE/4)) * 4; // Unit is changed from bit to qbit. + ntdma = - 1; + } + else + { + ntdma = modif_toa / (TPU_CLOCK_RANGE/4); + modif_toa = (modif_toa - ntdma * (TPU_CLOCK_RANGE/4)) * 4; // Unit is changed from bit to qbit. + } + + switch (task) + { + case FBNEW: + // Compute NTDMA & TOA taking into account the 23 bit guard for next SB receive window. + { + // "fn_offset" loaded with serving frame number corresponding to FB. + // Keep a %51 format to prepare SB scheduling. + fn_offset = (l1s.actual_time.fn - attempt + ntdma + MAX_FN) % 51; + } + break; + + case FB51: + // Compute NTDMA & TOA taking into account the 23 bit guard for next SB receive window. + { + // "fn_offset" loaded with serving frame number corresponding to FB. + // Keep a full frame number to allow scheduling of SB, 2 MF51 later. + fn_offset = (l1s.actual_time.fn - attempt + ntdma + MAX_FN) % MAX_FN; + } + break; + + case FB26: + { + // "fn_offset" loaded with serving frame number corresponding to CTL(SB26). + fn_offset = (l1s.actual_time.fn + 52 - 3) % MAX_FN; + + if(ntdma == 1) // 2nd frame... + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].sb26_offset = 1; + else + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].sb26_offset = 0; + } + break; + } // End of switch. + + } // End if. + + // Store TOA and FN offset in neighbor cell structure. + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].time_alignmt = modif_toa; + l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].fn_offset = fn_offset; + + // Create message T_L1C_FB_INFO. + msg = os_alloc_sig(sizeof(T_L1C_FB_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = L1C_FB_INFO; + + // Fill msg fields. + ((T_L1C_FB_INFO *) (msg->SigP))->fb_flag = fb_flag; + ((T_L1C_FB_INFO *) (msg->SigP))->ntdma = ntdma; + ((T_L1C_FB_INFO *) (msg->SigP))->neigh_id = l1a_l1s_com.nsync.active_fb_id; + // Debug info or testmode + ((T_L1C_FB_INFO *) (msg->SigP))->pm = pm; + ((T_L1C_FB_INFO*)(msg->SigP))->toa = toa; + ((T_L1C_FB_INFO*)(msg->SigP))->angle = angle; + ((T_L1C_FB_INFO*)(msg->SigP))->snr = snr; + ((T_L1C_FB_INFO *) (msg->SigP))->radio_freq = l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_fb_id].radio_freq; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_read_sb() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : this function sends L1C_SB_INFO to L1A*/ +/*-------------------------------------------------------*/ +void l1s_read_sb(UWORD8 task, UWORD32 flag, API *data, UWORD32 toa, UWORD8 attempt, + UWORD32 pm, UWORD32 angle, UWORD32 snr) +{ + xSignalHeaderRec *msg; + UWORD8 bsic=0; + UWORD32 sb; + WORD32 modif_toa = 0; + UWORD32 fn_offset = 0; + WORD32 time_alignmt = 0; + T_NCELL_SINGLE *cell_ptr = NULL; //omaps00090550 NULL; + UWORD32 SignalCode=0; + UWORD8 fn_delay = 2; // SB result read with 2 frames delay. + UWORD8 neigh_id=0; + UWORD32 fn; + + switch(task) + { + case SB2 : + case SB51 : + case SB26 : + // Get Neighbour cell ptr. + cell_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sb_id]; + neigh_id = l1a_l1s_com.nsync.active_sb_id; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_SB, cell_ptr->radio_freq); + #endif + + SignalCode = L1C_SB_INFO; + if(task == SB26) fn_delay = 3 - l1a_l1s_com.nsync.list[neigh_id].sb26_offset; + break; + + case SBCONF : + case SBCNF51 : + case SBCNF26 : + // Get Neighbour cell ptr. + cell_ptr = &l1a_l1s_com.nsync.list[l1a_l1s_com.nsync.active_sbconf_id]; + neigh_id = l1a_l1s_com.nsync.active_sbconf_id; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_SBCONF, cell_ptr->radio_freq); + #endif + + SignalCode = L1C_SBCONF_INFO; + if(task == SBCNF26) fn_delay = 3 - l1a_l1s_com.nsync.list[neigh_id].sb26_offset; + break; + } + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dspres(dltsk_trace[task].name); + #endif + + // Compute NTDMA & TOA taking into account the 23 bit guard for next SB receive window. + modif_toa = (toa - (SB_MARGIN/4)) * 4; // Rem: unit is "QBIT". + + // Read SB content,. + sb = data[0] & 0xffff | ((data[1] & 0xffff) << 16); + + if (flag == TRUE) + // SB has been found... + // We synchronized with a NEIGHBOUR cell. + { + UWORD32 t1, t2, t3, t3p; + + // extract BSIC, T1, T2, T3. Compute FN. + // bsic contains NCC & BCC (GSM05.02, p9) + bsic = (UWORD8) ((sb & 0x000000fc) >> 2); + + t1 = ((sb & 0x00800000) >> 23 | // t1 low + (sb & 0x0000ff00) >> 7 | // t1 midle + (sb & 0x00000003) << 9); // t1 high + t2 = (sb & 0x007c0000) >> 18; + t3p = ((sb & 0x01000000) >> 24 | // t3p low + (sb & 0x00030000) >> 15); // t3p high + t3 = (10*(t3p) +1); + fn = (51 * ((t3 - t2 + 26) % 26) + t3 + (26 * 51 * t1)); + + // Due to pipeline effect (CTRL.WORK.WORK.READ), sb content is taken into account + // "fn_delay" TDMA later: that's why we use "fn + fn_delay..." in the offset computation. + // + // NEIGHBOUR DOMAIN: + // ----------------- + // | |<----- 1 TDMA ----->| SB | | + // | | |XXXX | | + // | | | | | + // | | | FN_neighbour(SB) | FN_neighbour(SB)+1 | FN_neighbour(SB)+2 + // | | | | | + // offset | + // + | + // BOB | + // |<----------->| + // MS DOMAIN: | + // ---------- | | | | + // | CTRL | WORK | WORK | READ | + // | | | | | + // + // offset = FN_neighbour(SB)+ fn_delay - FN_serving(READ). + // Bob: fine timing difference between the Neighbour timing and the MS internal timing. + // + fn_offset = (fn + fn_delay + MAX_FN - l1s.actual_time.fn) % MAX_FN; + + // "time_alignmt" must be corrected (use "modif_toa" from the SB read). + // Check that "time_alignmt" do not become bigger than "TPU_CLOCK_RANGE". + // If so, "fn_offset" must be decremented. + if(cell_ptr != NULL)//OMAPS00090550 + time_alignmt = cell_ptr->time_alignmt + modif_toa; + if(time_alignmt >= TPU_CLOCK_RANGE) + { + time_alignmt -= TPU_CLOCK_RANGE; // qbp for sim. Normal value is 1250; + fn_offset -= 1; // WARNING....to be checked!!!!!! + } + else + if(time_alignmt < 0) + { + time_alignmt += TPU_CLOCK_RANGE; // qbp for sim. Normal value is 1250; + fn_offset += 1; // WARNING....to be checked!!!!!! + } + } + + #if L1_RECOVERY + if(flag) + { + // recovery flag is reseted because the system works fine + // this check is performed in all modes. + l1a_l1s_com.recovery_flag = FALSE; + + // Reset error flags and counter + l1s.recovery.frame_count = 0; + } + #endif + + // In all mode send result message to L1 Async. + msg = os_alloc_sig(sizeof(T_MPHC_NCELL_SYNC_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = SignalCode; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->sb_flag = flag; + if(cell_ptr != NULL)//OMAPS00090550 + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->radio_freq = cell_ptr->radio_freq; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->bsic = bsic; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->fn_offset = fn_offset; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->time_alignmt = time_alignmt; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->neigh_id = neigh_id; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->attempt = attempt; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->pm = pm; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->toa = toa; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->angle = angle; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->snr = snr; + + + #if (L1_EOTD == 1) + // In EOTD mode read additional results + if (l1a_l1s_com.nsync.eotd_meas_session == TRUE) + { + UWORD8 i; + WORD16 d_eotd_first; + WORD16 d_eotd_max; + UWORD32 d_eotd_nrj; + API *data = &(l1s_dsp_com.dsp_ndb_ptr->a_eotd_crosscor[0]); + UWORD32 fn_sb_neigh; + + d_eotd_first = l1s_dsp_com.dsp_ndb_ptr->d_eotd_first & 0xffff; + + d_eotd_max = l1s_dsp_com.dsp_ndb_ptr->d_eotd_max & 0xffff; + + fn_sb_neigh = (l1s.actual_time.fn - fn_delay + MAX_FN) % MAX_FN; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->fn_sb_neigh = fn_sb_neigh; + + d_eotd_nrj = (l1s_dsp_com.dsp_ndb_ptr->d_eotd_nrj_low & 0xffff) | + ((l1s_dsp_com.dsp_ndb_ptr->d_eotd_nrj_high & 0x00ff) << 16); + + // L1 SW : + // CPS Cursor expects the accumulated signal level of the cross + // correlation (d_eotd_nrj) to be 16bit format. The DSP reports + // it as 24bit format (lsb aligned in a 32bit word). + // We scale the DSP result by right shifting by 8, hence preserving + // the MSBs + + d_eotd_nrj >>= 8; + + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->eotd_data_valid = TRUE; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->d_eotd_first = d_eotd_first; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->d_eotd_max = d_eotd_max; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->d_eotd_nrj = d_eotd_nrj; + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->fn_in_SB = fn; + for (i=0; i<18; i++) + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->a_eotd_crosscor[i] = data[i] & 0xffff;; + + if(task == SBCNF26) + { + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->toa_correction = + l1a_l1s_com.nsync.eotd_cache_toa_tracking; + } + else + { + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->toa_correction = 0; + } + + } + else + ((T_MPHC_NCELL_SYNC_IND*)(msg->SigP))->eotd_data_valid = FALSE; +#endif + + + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +#if (MOVE_IN_INTERNAL_RAM == 0) // Must be followed by the pragma used to duplicate the funtion in internal RAM +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +/*-------------------------------------------------------*/ +/* l1s_read_fbsb() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : sends L1C_FBSB_INFO to L1A */ +/*-------------------------------------------------------*/ +#if ((REL99 == 1) && (FF_BHO == 1)) +void l1s_read_fbsb(UWORD8 task, UWORD8 attempt, BOOL fb_flag, BOOL sb_flag, API *data, UWORD32 toa, UWORD32 pm, UWORD32 angle, UWORD32 snr) +{ + xSignalHeaderRec *msg; + UWORD8 bsic = 0; + UWORD32 fn_offset = 0; + UWORD32 time_alignmt = 0; + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dspres(dltsk_trace[task].name); + #endif + + #if (TRACE_TYPE!=0) + // trace_fct(CST_L1S_READ_FBSB, l1a_l1s_com.nsync_fbsb.radio_freq); + #endif + + if ((fb_flag == TRUE) && (sb_flag == TRUE)) + { + UWORD32 toa_qbit, sb, fn, fn2, t1, t2, t3, t3p; + UWORD8 ntdma; + + // Read SB content,. + sb = data[0] & 0xffff | ((data[1] & 0xffff) << 16); + + // extract BSIC, T1, T2, T3. Compute FN. + // bsic contains NCC & BCC (GSM05.02, p9) + bsic = (UWORD8) ((sb & 0x000000fc) >> 2); + + t1 = ((sb & 0x00800000) >> 23 | // t1 low + (sb & 0x0000ff00) >> 7 | // t1 midle + (sb & 0x00000003) << 9); // t1 high + t2 = (sb & 0x007c0000) >> 18; + t3p = ((sb & 0x01000000) >> 24 | // t3p low + (sb & 0x00030000) >> 15); // t3p high + t3 = (10*(t3p) +1); + fn = (51 * ((t3 - t2 + 26) % 26) + t3 + (26 * 51 * t1)); + + // _|-----------------------------------|___ : TPU WINDOW + // |FB| |SB| + // _|---------------->|--------->|->| + // toa_fb 1 frame toa_sb + // + // we also need to take into account the 23 bit guard for SB receive window. + + toa_qbit = (l1a_l1s_com.nsync_fbsb.fb_toa + toa) * 4 + TPU_CLOCK_RANGE - SB_MARGIN; + + ntdma = toa_qbit / TPU_CLOCK_RANGE; + + fn_offset = (fn - l1s.actual_time.fn + attempt - ntdma + (2 * MAX_FN))% MAX_FN; + + time_alignmt = toa_qbit - (ntdma * TPU_CLOCK_RANGE); + } + + // Create message T_L1C_FBSB_INFO. + msg = os_alloc_sig(sizeof(T_L1C_FB_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = L1C_FBSB_INFO; + + // Fill msg fields. + ((T_L1C_FBSB_INFO *) (msg->SigP))->fb_flag = fb_flag; + ((T_L1C_FBSB_INFO *) (msg->SigP))->sb_flag = sb_flag; + ((T_L1C_FBSB_INFO *) (msg->SigP))->bsic = bsic; + ((T_L1C_FBSB_INFO *) (msg->SigP))->fn_offset = fn_offset; + ((T_L1C_FBSB_INFO *) (msg->SigP))->time_alignmt = time_alignmt; + ((T_L1C_FBSB_INFO *) (msg->SigP))->pm = pm; + ((T_L1C_FBSB_INFO *) (msg->SigP))->toa = toa; + ((T_L1C_FBSB_INFO *) (msg->SigP))->angle = angle; + ((T_L1C_FBSB_INFO *) (msg->SigP))->snr = snr; + + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} +#endif // #if ((REL99 == 1) && (FF_BHO == 1)) +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +#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 + +/*-------------------------------------------------------*/ +/* l1s_read_l3frm() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : reads NB data */ +/* and formate MPHC_DATA_IND message */ +/*-------------------------------------------------------*/ +void l1s_read_l3frm(UWORD8 pwr_level, API *info_address, UWORD32 task_rx) +{ + xSignalHeaderRec *msg; + UWORD32 i,j; + UWORD32 word32; + UWORD32 rx_fail_flag; + //OMAPS00090550 UWORD32 b_fire0; + UWORD32 b_fire1; + UWORD8 tc = l1s.actual_time.tc; // Default: tc loaded with current serving TC. + UWORD16 radio_freq = l1a_l1s_com.Scell_info.radio_freq; // Default: radio_freq load with serving cell + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dspres(dltsk_trace[task_rx].name); + #endif + + // Allocate result message. + + #if (GSM_IDLE_RAM == 1) // GPF not modified for GSM_IDLE_RAM -> enable Traffic Controller in L1S + if (!READ_TRAFFIC_CONT_STATE) + CSMI_TrafficControllerOn(); + #endif + + msg = os_alloc_sig(sizeof(T_MPHC_DATA_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + + switch(task_rx) + { + case NP: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__NP, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1C_NP_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_PCH; + break; + + case EP: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__EP, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1C_EP_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_EPCH; + break; + + case NBCCHS: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__NBCCHS, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1C_BCCHS_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_NBCCH; + break; + + case EBCCHS: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__EBCCHS, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1C_BCCHS_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_EBCCH; + break; + + case BCCHN: + #if L1_GPRS + case BCCHN_TRAN: + #endif + case BCCHN_TOP: + #if (TRACE_TYPE!=0) + if (task_rx == BCCHN) + trace_fct(CST_L1S_READ_L3FRM__BCCHN, l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_norm].radio_freq); + else // BCCHN_TRAN and BCCHN_TOP tasks + trace_fct(CST_L1S_READ_L3FRM__BCCHN, l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_top].radio_freq); + #endif + + // Fill msg signal code, L2 channel and get neighbour TC. + msg->SignalCode = L1C_BCCHN_INFO; + + // Save neighbour ID. + // With TC and Neighbour ID, L1A can manage the remaining BCCH requests. + if (task_rx == BCCHN) + { + ((T_MPHC_DATA_IND *)(msg->SigP))->neigh_id = l1a_l1s_com.bcchn.active_neigh_id_norm; + tc = l1a_l1s_com.bcchn.active_neigh_tc_norm; + radio_freq = l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_norm].radio_freq; + } + else // BCCHN_TRAN and BCCHN_TOP tasks + { + ((T_MPHC_DATA_IND *)(msg->SigP))->neigh_id = l1a_l1s_com.bcchn.active_neigh_id_top; + tc = l1a_l1s_com.bcchn.active_neigh_tc_top; + radio_freq = l1a_l1s_com.bcchn.list[l1a_l1s_com.bcchn.active_neigh_id_top].radio_freq; + } + + if(tc >= 8) + { + // Reading Extended BCCH. + tc -= 8; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_EBCCH; + } + else + { + // Reading Normal BCCH. + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_NBCCH; + } + + break; + + case ALLC: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__ALLC, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code, L2 channel and get neighbour TC. + msg->SignalCode = L1C_ALLC_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_CCCH; + break; + + case SMSCB: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1S_READ_L3FRM__CB, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code, L2 channel and get neighbour TC. + msg->SignalCode = L1C_CB_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_CBCH; + break; + + #if L1_GPRS + + case PNP: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__PNP, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1P_PNP_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PPCH; + tc = l1pa_l1ps_com.pbcchs.rel_pos_to_report; + break; + + case PEP: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__PEP, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1P_PEP_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PEPCH; + tc = l1pa_l1ps_com.pbcchs.rel_pos_to_report; + break; + + case PALLC: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__PALLC, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1P_PALLC_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PCCCH; + tc = l1pa_l1ps_com.pbcchs.rel_pos_to_report; + break; + + case PBCCHS: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__PBCCHS, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1P_PBCCHS_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PBCCH; + tc = l1pa_l1ps_com.pbcchs.rel_pos_to_report; + break; + + case PBCCHN_IDLE: + case PBCCHN_TRAN: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__PBCCHN, l1pa_l1ps_com.pbcchn.bcch_carrier); + #endif + + // Fill msg signal code and L2 channel. + msg->SignalCode = L1P_PBCCHN_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PBCCH; + tc = l1pa_l1ps_com.pbcchn.relative_position; + radio_freq = l1pa_l1ps_com.pbcchn.bcch_carrier; + break; + + case SINGLE: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__SINGLE, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill L2 channel. + msg->SignalCode = L1P_PACCH_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_PCHANNEL_PACCH; + tc = l1pa_l1ps_com.pbcchs.rel_pos_to_report; + break; + + #endif + + // WARNING !!! to be removed (for CBCH debugging). + default: + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_L3FRM__UNKNOWN, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Fill msg signal code, L2 channel and get neighbour TC. + msg->SignalCode = L1C_CB_INFO; + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_channel = L2_CHANNEL_CCCH; + } + + #if L1_GPRS + if (l1a_l1s_com.dsp_scheduler_mode == GSM_SCHEDULER) + #endif + { + // Compute detection flag. + //OMAPS00090550 b_fire0 = ((info_address[0] & 0xffff) & (1<> B_FIRE0; + b_fire1 = ((info_address[0] & 0xffff) & (1<> B_FIRE1; + if(b_fire1 != 1) + rx_fail_flag = FALSE; // information block received successfully. + else + rx_fail_flag = TRUE; // information block reception failled. + + // Get 23 bytes info. from DSP. + for (j=0, i=0; i<11; i++) + { + word32 = info_address[3 + i]; // Get info word, rem: skip info. header. + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x000000ff); + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x0000ff00) >> 8; + } + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_frame.A[22] = (info_address[14] & 0x000000ff); + + // reset buffers and flags in NDB ... + // B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 + info_address[0] = (1<> 8); + + // Get 24 bytes info. from DSP: CS1 meaningful block is of size 12 UWORD16 data. + // !!! WARNING: word32 type is for compatibility with chipset == 0. + // Can be word16 if only chipset == 2 is used. + for (j=0, i=0; i<12; i++) + { + // Data downloaded from a_dd_gprs[0][]... + word32 = info_address[4 + i]; // Get info word, rem: skip info. header. + if(j<23) + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x000000ff); + if(j<23) + ((T_MPHC_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x0000ff00) >> 8; + } + + // reset buffers and flags in NDB ... + // reset CS_TYPE + info_address[0] = CS_NONE_TYPE; + } + #endif + + // Report detection flag. + if((l1s_dsp_com.dsp_db_r_ptr->d_debug & 0xffff ) != (l1s.debug_time & 0xffff )) // in case of COM error the block is false + ((T_MPHC_DATA_IND *)(msg->SigP))->error_flag = TRUE; + else + ((T_MPHC_DATA_IND *)(msg->SigP))->error_flag = rx_fail_flag; + + // be careful: radio_freq is setted at the beging of the code and may be modified inside the "case" + ((T_MPHC_DATA_IND *)(msg->SigP))->radio_freq = radio_freq; + + // be careful: tc is setted at the beging of the code and may be modified inside the "case" + ((T_MPHC_DATA_IND *)(msg->SigP))->tc = tc; + + // convert in ETSI format and send it back to L3 + ((T_MPHC_DATA_IND *)(msg->SigP))->ccch_lev = l1s_encode_rxlev(pwr_level); + +#if (FF_L1_FAST_DECODING == 1) + // Update the fn according to the number of the last decoded burst (2, 3 or 4) in case of fast paging: alignment with a block boudary + if(l1a_l1s_com.last_fast_decoding == 0) + // fast decoding was not not used + ((T_MPHC_DATA_IND *)(msg->SigP))->fn = l1s.actual_time.fn; + else + // fast decoding done, fn is incremented up to 2 frames (if fast decoding with 2 bursts), 0 if fast decoding with 4 bursts (normal decoding) + ((T_MPHC_DATA_IND *)(msg->SigP))->fn = l1s.actual_time.fn + BURST_4 + 1 - l1a_l1s_com.last_fast_decoding; +#else + ((T_MPHC_DATA_IND *)(msg->SigP))->fn = l1s.actual_time.fn; +#endif + // send message... + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif +/*-------------------------------------------------------*/ +/* l1s_read_sacch_dl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : reads NB data */ +/*-------------------------------------------------------*/ +void l1s_read_sacch_dl(API *info_address, UWORD32 task_rx) +{ + xSignalHeaderRec *msg; + UWORD32 i,j; + UWORD32 word32; + UWORD32 rx_fail_flag; + //OMAPS00090550 UWORD32 b_fire0; + UWORD32 b_fire1; + #if (FF_REPEATED_SACCH == 1) + BOOL b_joint= 0; /* The flag to read the DSP response on combining */ + static BOOL prevfail = 0; + #endif /* (FF_REPEATED_SACCH == 1) */ + + // Traces. + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dspres(dltsk_trace[task_rx].name); + #endif + + #if (TRACE_TYPE!=0) + if(task_rx == ADL) trace_fct(CST_L1S_READ_SACCH_DL__ADL, l1a_l1s_com.dedic_set.radio_freq_dd); + if(task_rx == TCHA) trace_fct(CST_L1S_READ_SACCH_DL__TCHA, l1a_l1s_com.dedic_set.radio_freq_dd); + #endif + + #if (((TRACE_TYPE==1) || (TRACE_TYPE==4)) && ((FF_REPEATED_SACCH == 1))) + trace_info.repeat_sacch.dl_count ++; /* It is a SACCH downlink block */ + + #endif + // Compute detection flag. + //OMAPS00090550 b_fire0 = ((info_address[0] & 0xffff) & (1<> B_FIRE0; + b_fire1 = ((info_address[0] & 0xffff) & (1<> B_FIRE1; + if(b_fire1 != 1) + rx_fail_flag = FALSE; // information block received successfully. + else + rx_fail_flag = TRUE; // information block reception failled. + +#if (FF_REPEATED_SACCH == 1) + b_joint = (BOOL)(((info_address[0] & 0xffff) & (1<> B_JOINT); + +#endif /* (FF_REPEATED_SACCH == 1) */ + // Clear 1st word of header. + info_address[0] = 0; + + #if ((TESTMODE) && ((FF_REPEATED_SACCH == 1)) ) + if(l1_config.repeat_sacch_enable != REPEATED_SACCH_ENABLE) + { + l1s.repeated_sacch.srr = 0; + #if (TRACE_TYPE == 1 || TRACE_TYPE == 4) + trace_info.repeat_sacch.dl_buffer_empty = TRUE; + #endif /* TRACE_TYPE*/ + } + else + { + #endif /* ((TESTMODE) && ((FF_REPEATED_SACCH == 1))) */ + + + #if (FF_REPEATED_SACCH == 1) + + if( (b_joint==TRUE) || (rx_fail_flag==TRUE )) + { + /* chase combining occurred or the current block was unsuccessfully decoded.*/ + l1s.repeated_sacch.srr = 1; + + } + else + { + l1s.repeated_sacch.srr = 0; // debug + + } + + + #endif /* (FF_REPEATED_SACCH == 1) */ + #if ((TESTMODE) && ((FF_REPEATED_SACCH == 1)) ) + } /* end else l1_config.repeat_sacch_enable */ + #endif /* ((TESTMODE) && ((FF_REPEATED_SACCH == 1))) */ + + #if ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) + trace_info.repeat_sacch.srr = l1s.repeated_sacch.srr; + if(b_joint == TRUE && b_fire1!=1) + { + trace_info.repeat_sacch.dl_combined_good_count ++; + if (prevfail == 1) + trace_info.repeat_sacch.dl_error_count--; + } + #endif /* ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) */ + +#if ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) + trace_info.repeat_sacch.srr = l1s.repeated_sacch.srr; + if( rx_fail_flag == TRUE) /* Information reception failed */ + { + trace_info.repeat_sacch.dl_error_count ++; + } + +#endif /* ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) */ + + #if TESTMODE + // Continunous mode: the SAACH data aren't valid. Therefore don't send to L1A. + if ((!l1_config.TestMode) || ((l1_config.TestMode) && + (l1_config.tmode.rf_params.tmode_continuous == TM_NO_CONTINUOUS))) + #endif + { + // Allocate result message. + msg = os_alloc_sig(sizeof(T_PH_DATA_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = L1C_SACCH_INFO; + ((T_PH_DATA_IND *)(msg->SigP))->l2_channel_type = L2_CHANNEL_SACCH; + + // Catch L1 Header if SACCH/DL data block successfully received. + if(rx_fail_flag == FALSE) + { + UWORD8 supplied_txpwr = info_address[3] & 0x0000001f; + UWORD8 supplied_ta = (info_address[3] & 0x00007f00) >> 8; + + #if (FF_REPEATED_SACCH == 1) + //Set SRO parameter to transmit to the UL + l1s.repeated_sacch.sro = (info_address[3] & 0x00000040) >> 6; + /* + 7 | 6 | 5 | 4 3 2 1 0 + Spare | SRO| FPC EPC | Ordered MS power level + | Ordered timing advance + + */ + #endif /* (FF_REPEATED_SACCH == 1) */ + // Check max transmit power (min txpwr) according to powerclass. + supplied_txpwr = l1a_clip_txpwr(supplied_txpwr,l1a_l1s_com.dedic_set.radio_freq); + + #if TESTMODE + // Update txpwr and ta only during Normal Mode + if (!l1_config.TestMode) + #endif + { + l1a_l1s_com.dedic_set.aset->new_target_txpwr = supplied_txpwr; + + // Check if supplied TA is valid, if not keep previous value. + if(supplied_ta < 64) + l1a_l1s_com.dedic_set.aset->new_timing_advance = supplied_ta; + } + #if ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) + l1s_check_sacch_dl_block(info_address); + trace_info.repeat_sacch.sro = l1s.repeated_sacch.sro; + #endif /* ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) */ + } /* end if rx_fail_flag */ + else + { + #if ((TRACE_TYPE==1 || TRACE_TYPE == 4) && (FF_REPEATED_SACCH)) + trace_info.repeat_sacch.dl_buffer_empty = TRUE; + #endif + } + + // Get 23 bytes info. from DSP. + for (j=0, i=0; i<11; i++) + { + word32 = info_address[3 + i]; // Get info word, rem: skip info. header. + ((T_PH_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x000000ff); + ((T_PH_DATA_IND *)(msg->SigP))->l2_frame.A[j++] = (word32 & 0x0000ff00) >> 8; + } + ((T_PH_DATA_IND *)(msg->SigP))->l2_frame.A[22] = (info_address[14] & 0x000000ff); + + // Fill msg header... + ((T_PH_DATA_IND *)(msg->SigP))->rf_chan_num = l1a_l1s_com.Scell_info.radio_freq; + ((T_PH_DATA_IND *)(msg->SigP))->error_cause = rx_fail_flag; + ((T_PH_DATA_IND *)(msg->SigP))->bsic = l1a_l1s_com.Scell_info.bsic; + ((T_PH_DATA_IND *)(msg->SigP))->tc = l1s.actual_time.tc; + + // send message... + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + trace_info.sacch_d_nerr = info_address[2] & 0x00ff; + #endif + #if (FF_REPEATED_SACCH == 1) + prevfail= rx_fail_flag ; + #endif /* (FF_REPEATED_SACCH == 1) */ + } +} + +/*-------------------------------------------------------*/ +/* l1s_read_dcch_dl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : reads FACCH DL data block. */ +/*-------------------------------------------------------*/ +void l1s_read_dcch_dl(API *info_address, UWORD32 task_rx) +{ + UWORD8 rx_valid_flag = FALSE; + UWORD8 timing_advance = 255; + BOOL b_joint ; /* DSP indicator to Chase Combining */ + #if (L1_SAGEM_INTERFACE == 1) + UWORD8 channel_type = l1a_l1s_com.dedic_set.aset->achan_ptr->desc_ptr->channel_type; + #endif + + #if (FF_REPEATED_DL_FACCH == 1) + b_joint = (BOOL) (((info_address[0] & 0xffff) & (1<> B_JOINT); + + #if TESTMODE + if(l1_config.repeat_facch_dl_enable != REPEATED_FACCHDL_ENABLE) /* repeated FACCH mode is disabled */ + b_joint = FALSE; + #endif /* TESTMODE */ + + #endif /* (FF_REPEATED_DL_FACCH == 1) */ + + + if(info_address != NULL) + // A data block must be passed to L2. + { + UWORD32 b_fire1; + + #if (TRACE_TYPE!=0) + if(task_rx == DDL) trace_fct(CST_L1S_READ_DCCH_DL__DDL, l1a_l1s_com.dedic_set.radio_freq_dd); + if(task_rx == TCHTF) trace_fct(CST_L1S_READ_DCCH_DL__TCHTF, l1a_l1s_com.dedic_set.radio_freq_dd); + if(task_rx == TCHTH) trace_fct(CST_L1S_READ_DCCH_DL__TCHTH, l1a_l1s_com.dedic_set.radio_freq_dd); + #endif + + // Set detection flag. + b_fire1 = ((info_address[0] & 0xffff) & (1<> B_FIRE1; + if(b_fire1 != 1) + rx_valid_flag = TRUE; // information block received successfully. + else + rx_valid_flag = FALSE; // information block reception failled. + + if((rx_valid_flag == TRUE) && (l1a_l1s_com.dedic_set.aset->t3124 != 0)) + // T3124 running... + // Check for PHYSICAL INFORMATION message from FACCH. + { + UWORD32 message_type = info_address[5] & 0x00ff; + + if(message_type == 0x2D) + // FACCH message is a PHYSICAL INFORMATION message. + { + // Catch TIMING ADVANCE information. + timing_advance = (UWORD8)((info_address[5] & 0xff00) >> 8); + l1a_l1s_com.dedic_set.aset->new_timing_advance = timing_advance; + l1a_l1s_com.dedic_set.aset->timing_advance = timing_advance; + + // Reset T3124. + l1a_l1s_com.dedic_set.aset->t3124 = 0; + + // Stop sending Handover Access burst. + l1a_l1s_com.dedic_set.aset->ho_acc_to_send = 0; + + // Handover access procedure is completed. + // -> send L1C_HANDOVER_FINISHED message with "cause = COMPLETED" to L1A. + l1s_send_ho_finished(HO_COMPLETE); + } + } + + // Clear 1st word of header. + info_address[0] = 0; + + // Shift data block pointer to skip DSP header. + info_address = &(info_address[3]); + + if (rx_valid_flag == TRUE) + { + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + trace_info.facch_dl_count ++; + #endif + #if (FF_REPEATED_DL_FACCH == 1) /*Fire code is correct and information recieved successfully */ + l1s_store_facch_buffer(l1s.repeated_facch, info_address); + #endif + + /* trace for FER calculation (Repeated FACCH mode): */ + /* nb of DL FACCH blocks correctly decoded which is not a repetition */ + + #if ((TRACE_TYPE==1|| TRACE_TYPE==4) && (FF_REPEATED_DL_FACCH)) + trace_info.facch_dl_good_block_reported++; + if(b_joint == TRUE) /* The combined block is successfully decoded */ + trace_info.facch_dl_combined_good_count++; + #endif /* ((TRACE_TYPE==1|| TRACE_TYPE==4) && (FF_REPEATED_DL_FACCH)) */ + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(FACCH_GOOD, l1s_dsp_com.dsp_ndb_ptr->a_fd[2], 0); + #endif + } + else + { + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + trace_info.facch_dl_fail_count ++; + #endif + #if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1) + Trace_dedic_tch_block_stat(FACCH_BAD, l1s_dsp_com.dsp_ndb_ptr->a_fd[2], 0); + #endif + } + } + #if (FF_REPEATED_DL_FACCH == 1) + if(rx_valid_flag == FALSE) + { + l1s.repeated_facch.pipeline[l1s.repeated_facch.counter_candidate].buffer_empty=TRUE; + } + #endif /* (FF_REPEATED_DL_FACCH == 1) */ + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + RTTL1_FILL_DL_DCCH(rx_valid_flag, timing_advance) + #endif + + // Pass data block to L2. +#if (SEND_FN_TO_L2_IN_DCCH==1) +#if (L1_SAGEM_INTERFACE == 1) + dll_dcch_downlink(info_address, rx_valid_flag, l1s.actual_time.fn, channel_type); +#else + dll_dcch_downlink(info_address, rx_valid_flag, l1s.actual_time.fn); +#endif +#else +#if (L1_SAGEM_INTERFACE == 1) + dll_dcch_downlink(info_address, rx_valid_flag, channel_type); +#else + dll_dcch_downlink(info_address, rx_valid_flag); +#endif +#endif + +} + +/*-------------------------------------------------------*/ +/* l1s_reset_tx_ptr() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : Reset the TX data pointer for DRP */ +/* after ABORT */ +/*-------------------------------------------------------*/ + +#define L1_DRP_TX_PTR_RESET_SET (0x00000020) +#define L1_DRP_TX_PTR_RESET_RESET (~(L1_DRP_TX_PTR_RESET_SET)) + +void l1s_reset_tx_ptr(UWORD8 param1, UWORD8 param2) +{ +#if (CHIPSET==15) + volatile UWORD32 *ptr_drp_init32; + ptr_drp_init32 = (UWORD32 *) (DRP_API_BASE_ADDRESS + DRP_REG_SRM_CW_ADDR); //0xFFFF1E00; + + // Set the TX_PTR_RESET bit to 1 to reset TX RD and WR pointers + (*ptr_drp_init32) = (*ptr_drp_init32)|(L1_DRP_TX_PTR_RESET_SET); + + // Reset the bit to zero as aslong as the bit is 1, pointers are in reset state + (*ptr_drp_init32) = (*ptr_drp_init32)&(L1_DRP_TX_PTR_RESET_RESET); +#endif +} +