# HG changeset patch # User Mychaela Falconia # Date 1509421355 0 # Node ID 0740b5ff15f69dae0954acb70fa451331498515a # Parent a963c5c35f8d1898d4122e2817fc283d2b612a16 reconstructed L1_GPRS source imported from tcs211-l1-reconst diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/cmacs/macs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/cmacs/macs.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,3164 @@ +/************* Revision Control System Header ************* + * GSM Layer 1 software + * MACS.C + * + * Filename macs.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Control System Header *************/ + + +//---Configuration flags--------------------------------------------------- + +#define TFI_FILTERING 1 // TFI FILTERING activated if set to 1 +//------------------------------------------------------------------------- + + +#include +#include + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#include "l1_types.h" +#include "l1_const.h" + +#if TESTMODE + #include "l1tm_defty.h" + #include "l1tm_varex.h" +#endif +#if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" +#endif +#if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" +#endif +#if (L1_MP3 == 1) + #include "l1mp3_defty.h" +#endif +#if (L1_MIDI == 1) + #include "l1midi_defty.h" +#endif +#include "l1_defty.h" +#include "l1_varex.h" +#include "l1_signa.h" + +#include "l1p_cons.h" +#include "l1p_msgt.h" +#include "l1p_deft.h" +#include "l1p_vare.h" +#include "l1p_sign.h" + +#include "macs_def.h" +#include "macs_cst.h" +#include "macs_var.h" + +#if FF_TBF + #include "l1_trace.h" + #if (CODE_VERSION == SIMULATION) + #include "sim_cons.h" + #include "sim_def.h" + #include "sim_var.h" + #endif +#endif +/**********************************************************/ +/* MACS-S Prototypes */ +/**********************************************************/ + +void l1ps_macs_meas (void); // Measurement gap processing +void l1ps_macs_header_decoding (UWORD8 rx_no, + UWORD8 *tfi_result, + UWORD8 *pr); // MAC header decoding +void l1ps_macs_read (UWORD8 pr_table[8]); // MAC-S control tasks processing +void l1ps_macs_ctrl (void); // MAC-S read tasks processing +void l1ps_macs_init (void); // MAC-S initialization + +#if FF_TBF +void l1ps_macs_rlc_uplink_info (void); +#endif + +/**********************************************************/ +/* EXTERNAL Prototypes */ +/**********************************************************/ + +void l1pddsp_transfer_mslot_ctrl(UWORD8 burst_nb, + UWORD8 dl_bitmap, + UWORD8 ul_bitmap, + UWORD8 *usf_table, + UWORD8 mac_mode, + UWORD8 *ul_buffer_index, + UWORD8 tsc, + UWORD16 radio_freq, + UWORD8 synchro_timeslot, + #if FF_L1_IT_DSP_USF + UWORD8 dsp_usf_interrupt + #else + UWORD8 usf_vote_enable + #endif + ); + +/* RLC interface for uplink RLC/MAC blocks */ +/*-----------------------------------------*/ + +void rlc_uplink( + UWORD8 assignment_id, + UWORD8 tx_data_no, // Number of timeslot that can be used + // for uplink data block transfer + UWORD32 fn, // Next frame number + UWORD8 timing_advance_value, // Timing advance (255 if unknown) + API *ul_poll_response, // Pointer on a_pu_gprs (NDB): poll response blocks + API *ul_data, // Pointer on a_du_gprs (NDB): uplink data blocks + BOOL allocation_exhausted // Set to 1 if fixed allocation exhausted + ); + +#if TESTMODE +void l1tm_rlc_uplink(UWORD8 tx, API *ul_data); +#endif + +/* RLC interface for downlink RLC/MAC blocks */ +/*-------------------------------------------*/ +#if FF_TBF + +void rlc_downlink_data( + UWORD8 assignment_id, + UWORD32 fn, // Actual frame number + API *dl // Pointer on a_dd_gprs (NDB): downlink blocks + ); +void rlc_uplink_info( + UWORD8 assignment_id, + UWORD32 fn, + UWORD8 rlc_blocks_sent, // Number of uplink blocks that was transmitted + // during the last block period + UWORD8 last_poll_response // Status of the poll responses of + ); // the last block period + +UWORD8 rlc_downlink_copy_buffer(UWORD8 isr); + + +#else + +void rlc_downlink( + UWORD8 assignment_id, + UWORD32 fn, // Actual frame number + API *dl, // Pointer on a_dd_gprs (NDB): downlink blocks + UWORD8 rlc_blocks_sent, // Number of uplink blocks that was transmitted + // during the last block period + UWORD8 last_poll_response // Status of the poll responses of + // the last block period + ); + +#endif + +#if (TRACE_TYPE==1) || (TRACE_TYPE==4) + #include "l1_trace.h" +#endif + + +#if FF_TBF + #include + + #if (CODE_VERSION == SIMULATION) + API* const A_DD_XGPRS[1][4] = + { + {&buf.ndb_gprs.a_dd_gprs[0][0], &buf.ndb_gprs.a_dd_gprs[1][0], &buf.ndb_gprs.a_dd_gprs[2][0], &buf.ndb_gprs.a_dd_gprs[3][0]}, + }; + + API* const A_DU_XGPRS[1][4] = + { + {&buf.ndb_gprs.a_du_gprs[0][0], &buf.ndb_gprs.a_du_gprs[1][0], &buf.ndb_gprs.a_du_gprs[2][0], &buf.ndb_gprs.a_du_gprs[3][0]} + }; + + #else + API* const A_DD_XGPRS[1][4] = + { + { + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[0][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[1][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[2][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS, a_dd_gprs[3][0])) + } + }; + + API* const A_DU_XGPRS[1][4] = + { + { + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[0][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[1][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[2][0])), + (API*)(NDB_ADR_GPRS + offsetof(T_NDB_MCU_DSP_GPRS,a_du_gprs[3][0])) + } + }; + #endif + +#endif +/*-----------------------------------------------------------*/ +/* l1ps_macs_init() */ +/*-----------------------------------------------------------*/ +/* Parameters: */ +/* */ +/* Return: */ +/* */ +/* Description: This function initializes MAC-S variables */ +/* and must be called before the first call */ +/* of MAC-S */ +/*-----------------------------------------------------------*/ +void l1ps_macs_init(void) +{ + UWORD8 i; + + #if FF_TBF + macs.dl_buffer_index = INVALID; + for (i=0;iallocated_tbf == UL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF)) + { + #if L1_EDA + if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC)) + #else + if (SET_PTR->mac_mode == DYN_ALLOC) + #endif + { + // Test if the USF must be read in the current frame + // Concern the first frames of each block period (useful when + // some USF values weren't valid the frame before) + // FN 13 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ---------------------------------------------------------- + // || B0 || B1 || B2 || I || + // || | | | || | X | | || | X | | || || + // ---------------------------------------------------------- + // X:USF Reading + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status == USF_IT_DSP) + #else + if ( (l1s.next_time.fn_mod13 == 5) + || (l1s.next_time.fn_mod13 == 9)) + #endif + { + // USF values are read + // Uplink timeslots whose USF was INVALID the frame before are de-allocated + // if their USF value is now BAD + + UWORD8 tn; + + // Reading of the d_usf_updated_gprs value + API usf_updated = NDB_PTR->d_usf_updated_gprs; + + #if !L1_EDA + // For each timeslot that can be allocated in uplink... + for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn ++) + { + // If USF vote was enabled on this timeslot + if(macs.usf_vote_enable & (MASK_SLOT0 >> tn)) + { + // Clear the USF vote flag + macs.usf_vote_enable &= ~(MASK_SLOT0 >> tn); + + // Read USF value + if (((usf_updated >> ((MAX_TS_NB - tn) * 2)) & MASK_2SLOTS) == USF_GOOD) + { + // This timeslot is valid and good + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (tn + 3)); + macs.next_usf_mon_block[tn - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + } + else + { + // This timeslot is bad or invalid + // If the slot was allocated for data + if (macs.tx_data & (MASK_SLOT0 >> (tn + RXTX_DELAY))) + { + // rlc_blocks_sent decremented + macs.rlc_blocks_sent --; + + #if FF_L1_IT_DSP_USF + // If next timeslot is also a data block: + // Shift data block to next TX opportunity. For MS class 12 + // with dynamic allocation, 2 TX data max and they are + // contiguous (optimization). + if (macs.tx_data & (MASK_SLOT0 >> (tn + 1 + RXTX_DELAY))) + { + macs.ul_buffer_index[tn + 1 + RXTX_DELAY] = macs.ul_buffer_index[tn + RXTX_DELAY]; + + } + + // Cancel burst + macs.ul_buffer_index[tn + RXTX_DELAY] = INVALID; + + #endif // FF_L1_IT_DSP_USF + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<> macs.monitored_ts[i])) + { + // Clear the USF vote flag + macs.usf_vote_enable &= ~(MASK_SLOT0 >> macs.monitored_ts[i]); + + // Read USF value + if ((((usf_updated >> ((MAX_TS_NB - macs.monitored_ts[i]) * 2)) & MASK_2SLOTS) == USF_GOOD) + && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i]))) + { + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + //RX timeslots to monitor have to be updated upon USF status receipt (only first ts with + //good USF has to be considered) + if ((macs.monitored_ts[i] <= macs.lowest_poll_ts) || + ((MASK_SLOT0 >> macs.monitored_ts[i]) & macs.rx_allocation)) + macs.rx_monitored |= (UWORD8) (MASK_SLOT0 >> macs.monitored_ts[i]); + + // Clear the USF vote flag + macs.usf_vote_enable = 0; + + //if the USF value is GOOD all remaining timelots that needed to be monitored + //have to be considered as having GOOD USFs + while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) + { + // Update good USFs bitmap + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + i++; + } + macs.next_usf_mon_block[0] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + break; + } + else + { + // This timeslot is valid and good + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + } + } + else //USF is BAD or INVALID + { + //The TDMA before USF status was not known so USF was supposed to be GOOD but + // now it turns out to be BAD or INVALID so block is deallocated. + if (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY))) + { + UWORD8 j; + + // rlc_blocks_sent decremented + macs.rlc_blocks_sent --; + + tn = macs.monitored_ts[i]; + + #if FF_L1_IT_DSP_USF + //For all monitored ts (beginning with last one), if the timeslot is a data block then + //data block is shifted to next monitored ts. + j=3; + while (macs.monitored_ts[j] != tn) + { + if ((macs.monitored_ts[j] != INVALID) && + (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[j] + RXTX_DELAY)))) + { + macs.ul_buffer_index[macs.monitored_ts[j] + RXTX_DELAY] = macs.ul_buffer_index[macs.monitored_ts[j-1] + RXTX_DELAY]; + #if L1_EGPRS + macs.tx_modulation &= ~(MASK_SLOT0 >> (macs.monitored_ts[j] + RXTX_DELAY)); + macs.tx_modulation |= ((macs.tx_modulation & + (MASK_SLOT0 >> (macs.monitored_ts[j-1] + RXTX_DELAY))) + >> (macs.monitored_ts[j]-macs.monitored_ts[j-1])); + #endif // L1_EGPRS + } + j--; + } + + // Cancel burst + macs.ul_buffer_index[tn + RXTX_DELAY] = INVALID; + #if L1_EGPRS + macs.tx_modulation &= ~(MASK_SLOT0 >> (tn + RXTX_DELAY)); + #endif // L1_EGPRS + #endif // FF_L1_IT_DSP_USF + }//if (macs.tx_data & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY))) + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + //USF for current timeslot is BAD so it has to be monitored for next USF + //period + if ((macs.monitored_ts[i] <= macs.lowest_poll_ts) || + ((MASK_SLOT0 >> macs.monitored_ts[i]) & macs.rx_allocation)) + macs.rx_monitored |= (UWORD8) (MASK_SLOT0 >> macs.monitored_ts[i]); + } + } + }//if(macs.usf_vote_enable & (MASK_SLOT0 >> macs.monitored_ts[i])) + i++; + }//while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) + + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + // Downlink monitoring is updated depending on USF status + macs.rx_allocation |= macs.rx_monitored; + } + + // Uplink resources de-allocated by the DSP are de-allocated by MAC-S + macs.tx_allocation &= (UWORD8) (macs.usf_good | ~macs.tx_data); + macs.tx_data &= (UWORD8) (macs.usf_good | ~macs.tx_data); + #endif //#if !L1_EDA + + // Measurement gap processing + l1ps_macs_meas(); + + } // End if FN13 = 4 OR 8 + } // End if dynamic allocation mode + } // End if uplink TBF + + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + #endif + + /************************************************************/ + /***** RESSOURCE ALLOCATION FOR THE NEXT BLOCK PERIOD *****/ + /************************************************************/ + + // If the next frame is the first of a block period + // FN 13 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ---------------------------------------------------------- + // || B0 || B1 || B2 || I || + // || X | | | || X | | | || X | | | || || + // ---------------------------------------------------------- + + if ( (l1s.next_time.fn_mod13 == 4) + || (l1s.next_time.fn_mod13 == 8) + || (l1s.next_time.fn_mod13 == 0)) + { + UWORD8 tx = 0; // MS class Tx parameter checked + UWORD8 rx = 0; // MS class Rx parameter checked + UWORD8 tx_no; // Number of allocated uplink timeslots + UWORD8 highest_ul_ts; // Highest numbered allocated uplink resource + UWORD8 lowest_ul_ts; // Lowest numbered allocated uplink resource + UWORD8 highest_dl_ts; // Highest numbered allocated uplink resource + UWORD8 lowest_dl_ts; // Lowest numbered allocated uplink resource + UWORD8 tra_before_frame; // Number of free Tx slots at the end of the + // previous frame + + + /***********************************************************/ + /* New allocated ressources */ + /***********************************************************/ + + /*---------------------------------------------------------*/ + /* New assignment or synchronization change */ + /*---------------------------------------------------------*/ + + if ( (l1ps_macs_com.new_set != FALSE) + || (l1a_l1s_com.dl_tn != macs.old_synchro_ts)) + { + UWORD8 tn; + UWORD8 fn_mod13; + UWORD32 fn_div13; + + /* Fixed allocation mode initialization */ + /*--------------------------------------*/ + + if (SET_PTR->mac_mode == FIX_ALLOC_NO_HALF) + { + if (((SET_PTR->assignment_command == UL_TBF) || (SET_PTR->assignment_command == BOTH_TBF)) && + (l1ps_macs_com.new_set)) + { + // Starting time block ID processing + fn_div13 = (UWORD32) (SET_PTR->tbf_sti.absolute_fn / 13); // FN / 13 + fn_mod13 = (UWORD8) (SET_PTR->tbf_sti.absolute_fn - (fn_div13 * 13)); // FN mod 13 + macs.sti_block_id = (UWORD32) ( (3 * (UWORD32) fn_div13) // Block ID + + (fn_mod13 / 4)); + + // Starting time not aligned on a block period + if ((fn_mod13 != 0) && (fn_mod13 != 4) && (fn_mod13 != 8) && (fn_mod13 != 12)) + macs.sti_block_id ++; + + // Reset the fixed allocation bitmap exhaustion flag only in case of a new assignment + macs.fix_alloc_exhaust = FALSE; + } + + } // End of fixed mode initialization + else + + #if L1_EDA + /* Extended Dynamic/Dynamic allocation mode initialization */ + /*------------------------------------------*/ + + if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC)) + #else + /* Dynamic allocation mode initialization */ + /*------------------------------------------*/ + + if (SET_PTR->mac_mode == DYN_ALLOC) + #endif + { + if ((SET_PTR->assignment_command == UL_TBF) || (SET_PTR->assignment_command == BOTH_TBF) || + (l1a_l1s_com.dl_tn != macs.old_synchro_ts)) + { + // USF value aren't kept + macs.usf_good = 0; + macs.usf_vote_enable = 0; // No USF vote + macs.rx_blk_period = NO_DL_BLK; + + if (l1ps_macs_com.new_set) + // USF monitoring block set to current block to immediately enable + // the USF monitoring in case of new UL TBF + macs.next_usf_mon_block[0] = macs.next_usf_mon_block[1] = l1s.next_time.block_id; + + // First and last allocated Tx number updating + macs.first_monitored_ts = INVALID; + macs.last_monitored_ts = INVALID; + + tn = 0; + // Search of the lowest timeslot allocated in uplink + while ( !(SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> tn)) + && (tn < TS_NUMBER)) + tn ++; + + if (tn != TS_NUMBER) + { + macs.first_monitored_ts = tn - l1a_l1s_com.dl_tn; + tn = MAX_TS_NB; + + // Search of the highest timeslot allocated in uplink + while (!(SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> tn))) + tn --; + macs.last_monitored_ts = tn - l1a_l1s_com.dl_tn; + #if L1_EDA + //Extended Dynamic or Dynamic Allocation has been set + { + UWORD8 i=0; + macs.rx_monitored = 0; + //Search among the timeslots allocated in uplink, the timeslots that are really + //allocated (macs.first_monitored_ts and macs.last_monitored_ts are for sure + //allocated but the allocation can have holes inbetween) + for (i = 0; i < 4; i++) + { + macs.monitored_ts[i] = INVALID; + } + i = 0; + for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn++) + { + //Find the ts that are allocated and need therefore to be monitored + if (((SET_PTR->ul_tbf_alloc->timeslot_alloc & (MASK_SLOT0 >> (tn + l1a_l1s_com.dl_tn))) && (SET_PTR->mac_mode == EXT_DYN_ALLOC)) + || (SET_PTR->mac_mode == DYN_ALLOC)) + { + macs.monitored_ts[i]= tn; + i++; + } + } + } + #endif //#if L1_EDA + } + } + #if L1_EDA + if((SET_PTR->mac_mode == EXT_DYN_ALLOC)) + l1ps_macs_com.fb_sb_task_detect = TRUE; + else + l1ps_macs_com.fb_sb_task_detect = FALSE; + #endif + } // End of dynamic mode initialization + + /* Reset of new_set */ + /*------------------*/ + + l1ps_macs_com.new_set = FALSE; + + } // End of new allocation + + /*---------------------------------------------------------*/ + /* Resource initialization */ + /*---------------------------------------------------------*/ + + macs.pwr_allocation = 0; // Power measurements + macs.rx_allocation = 0; // Rx allocation + macs.tx_allocation = 0; // Tx allocation + macs.tx_data = 0; // Tx data allocation + macs.tx_prach_allocation = 0; // Tx PRACH allocation + #if FF_L1_IT_DSP_USF + macs.dsp_usf_interrupt = 0; // DSP interrupt for USF decoding needed + #endif + + /***********************************************************/ + /* Downlink TBF processing */ + /***********************************************************/ + + if ((SET_PTR->allocated_tbf == DL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF)) + { + /* Downlink resources are allocated */ + macs.rx_allocation = (UWORD8) ( SET_PTR->dl_tbf_alloc.timeslot_alloc + << l1a_l1s_com.dl_tn); + } /* End if downlink TBF processing */ + + /***********************************************************/ + /* Uplink TBF processing */ + /***********************************************************/ + + if ((SET_PTR->allocated_tbf == UL_TBF) || (SET_PTR->allocated_tbf == BOTH_TBF)) + { + + /*---------------------------------------------------------*/ + /* Dynamic allocation mode */ + /*---------------------------------------------------------*/ + + #if L1_EDA + if ((SET_PTR->mac_mode == DYN_ALLOC) || (SET_PTR->mac_mode == EXT_DYN_ALLOC)) + #else + if (SET_PTR->mac_mode == DYN_ALLOC) + #endif + { + UWORD8 i; + UWORD8 tn; + API usf_updated; + + #if !L1_EDA + /* Downlink resource monitoring */ + /*------------------------------*/ + + macs.rx_allocation |= (UWORD8) ( SET_PTR->ul_tbf_alloc->timeslot_alloc + << l1a_l1s_com.dl_tn); + + /* USF values reading */ + /*--------------------*/ + + // An uplink timeslot is allocated by MAC-S if it's allocated by the network and + // - USF is updated and good + // OR - USF isn't updated + + // Reading of the d_usf_updated_gprs value + usf_updated = NDB_PTR->d_usf_updated_gprs; + + // For each timeslot that can be allocated in uplink... + for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn ++) + { + UWORD8 tn_usf; + WORD32 delta; + + // Remaining blocks before a new USF reading + delta = (WORD8) (macs.next_usf_mon_block[tn - macs.first_monitored_ts] - l1s.next_time.block_id); + + // MAX_FN modulo + if (delta <= 0) delta += MAX_BLOCK_ID; + + if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]) + { + // USF no more usable + // Clear USF in good USFs bitmap + macs.usf_good &= (UWORD8) ~(MASK_SLOT0 >> (tn + 3)); + + // Clear USF vote + macs.usf_vote_enable &= (UWORD8) ~(MASK_SLOT0 >> tn); + + // If downlink blocks were entirely received during the last block period + if (macs.rx_blk_period == l1s.next_time.block_id) + { + // Read USF + tn_usf = (UWORD8) ((usf_updated >> ((MAX_TS_NB - tn) << 1)) & MASK_2SLOTS); + + if (tn_usf == USF_GOOD) + { + // Update good USFs bitmap + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (tn + 3)); + macs.next_usf_mon_block[tn - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + } + else + if ((tn_usf == USF_INVALID) && (l1s.next_time.fn_mod13 != 0)) + { + // Unknown USF: + // - TPU is programmed to tranmit a block on timeslot tn + // - DSP will set the TX PWR to 0 for this timeslot is USF is bad + // (USF vote mechanism) + + macs.tx_allocation |= (MASK_SLOT0 >> (tn + 3)); + macs.usf_vote_enable |= (MASK_SLOT0 >> tn); + } + } // End if "downlink block entirely received" + } // End if "USF no more usable" + } // End for + + #else //#if !L1_EDA + { + UWORD8 tn_usf; + WORD32 delta; + UWORD8 i=0; + + if (SET_PTR->mac_mode == DYN_ALLOC) + { + /* Downlink resource monitoring */ + /*------------------------------*/ + + macs.rx_allocation |= (UWORD8) ( SET_PTR->ul_tbf_alloc->timeslot_alloc + << l1a_l1s_com.dl_tn); + + macs.last_rx_monitored = macs.rx_allocation; + } + else + { + // Remaining blocks before a new USF reading + delta = (WORD8) (macs.next_usf_mon_block[0] - l1s.next_time.block_id); + + // MAX_FN modulo + if (delta <= 0) delta += MAX_BLOCK_ID; + + //Save last rx_monitored timeslots + macs.last_rx_monitored = macs.rx_monitored; + + //for all timeslots to monitor (timeslots allocated in UL) + for (tn = macs.first_monitored_ts; tn <= macs.last_monitored_ts; tn++) + { + //All possible timeslots to monitor have to be monitored + // (USF validity period exhausted) + if (macs.monitored_ts[i] != INVALID) + macs.rx_monitored |= (MASK_SLOT0 >> macs.monitored_ts[i]); + i++; + } + + //USF validity period is exhausted + if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]) + { + //USF need to be evaluated for next block period + macs.usf_good = 0; + } + else + { + //Set monitored ts again if poll occured on one ts during a block granularity period = 4 + //note: macs.usf_good is always different from 0 + i=0; + while (!(macs.usf_good & (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)))) + i++; + macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]); + } + } + + // Reading of the d_usf_updated_gprs value + usf_updated = NDB_PTR->d_usf_updated_gprs; + + i=0; + //for all possible timeslots to monitor + while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) + { + if (SET_PTR->mac_mode == DYN_ALLOC) + { + // Remaining blocks before a new USF reading + delta = (WORD8) (macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] - l1s.next_time.block_id); + + // MAX_FN modulo + if (delta <= 0) delta += MAX_BLOCK_ID; + } + + //USF validity period is exhausted + if (delta >= USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]) + { + if (SET_PTR->mac_mode == DYN_ALLOC) + { + // USF no more usable + // Clear USF in good USFs bitmap + macs.usf_good &= (UWORD8) ~(MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + + // Clear USF vote + macs.usf_vote_enable &= (UWORD8) ~(MASK_SLOT0 >> macs.monitored_ts[i]); + } + + if ((macs.rx_blk_period == l1s.next_time.block_id) && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i]))) + { + + #if L1_EGPRS + // EGPRS switched radio loopback sub mode on: dynamic allocation + // but USF are always deemed to be good + if (l1ps_macs_com.loop_param.sub_mode == TRUE) + tn_usf = USF_GOOD; + else + #endif + // Read USF + tn_usf = (UWORD8) ((usf_updated >> ((MAX_TS_NB - macs.monitored_ts[i]) << 1)) & MASK_2SLOTS); + + if (tn_usf == USF_GOOD) + { + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + //Deallocate monitored ts + macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]); + + //As USF is good for current monitored ts, all subsequent monitored ts have + //to be deallocated and the associated USF set to USF_GOOD + while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) + { + //Update good USFs bitmap + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + i++; + } + macs.next_usf_mon_block[0] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + break; + } + else + { + // Update good USFs bitmap + macs.usf_good |= (UWORD8) (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + macs.next_usf_mon_block[macs.monitored_ts[i] - macs.first_monitored_ts] = l1s.next_time.block_id + USF_BLOCK_GRANULARITY[SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_granularity]; + } + } + else + if ((tn_usf == USF_INVALID) && (l1s.next_time.fn_mod13 != 0)) + { + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + //Deallocate monitored ts + macs.rx_monitored &= (UWORD8) ~(MASK_ALL_SLOTS >> macs.monitored_ts[i+1]); + + //As USF is invalid (status of USF not yet known) for current monitored ts, the USF is + //supposed to be good and therefore Tx is allocated and all subsequent monitored ts + //have to be deallocated. Vote mechanism is also enabled for these latter timeslots. + while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) + { + macs.tx_allocation |= (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + macs.usf_vote_enable |= (MASK_SLOT0 >> macs.monitored_ts[i]); + i++; + } + break; + } + else + { + // Unknown USF: + // - TPU is programmed to tranmit a block on timeslot tn + // - DSP will set the TX PWR to 0 for this timeslot is USF is bad + // (USF vote mechanism) + + macs.tx_allocation |= (MASK_SLOT0 >> (macs.monitored_ts[i] + RXTX_DELAY)); + macs.usf_vote_enable |= (MASK_SLOT0 >> macs.monitored_ts[i]); + } + } + }//if ((macs.rx_blk_period == l1s.next_time.block_id) && (macs.last_rx_monitored & (MASK_SLOT0 >> macs.monitored_ts[i]))) + } + i++; + }//while ((tn != INVALID) && (i <= 3)) + }//if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + + /* Downlink resource monitoring */ + /*------------------------------*/ + macs.rx_allocation |= macs.rx_monitored; + #endif //#if !L1_EDA + /* Uplink resources allocation according to USF values */ + /*-----------------------------------------------------*/ + + i = l1a_l1s_com.dl_tn - RXTX_DELAY; + if (i < TS_NUMBER) + { + macs.tx_allocation |= (UWORD8) ( macs.usf_good + & (SET_PTR->ul_tbf_alloc->timeslot_alloc << i)); + } + else + { + macs.tx_allocation |= (UWORD8) ( macs.usf_good + & (SET_PTR->ul_tbf_alloc->timeslot_alloc >> (-i))); + } + + #if L1_EDA + //if FB/SB activity detected in comming idle frame, some TX burst have to be deallocated + //to allow opening of FB/SB window (no TX activity should be scheduled in slots 6 and 7) + if (l1ps_macs_com.fb_sb_task_enabled && l1ps_macs_com.fb_sb_task_detect) + { + macs.tx_allocation &= ~(MASK_SLOT0 >> 6); + } + #endif + + #if FF_L1_IT_DSP_USF + // UL or BOTH TBF with dynamic allocation in use. DSP has to generate + // an interrupt for USF validity for the block to be received if it + // is either RBN (radio block number) % 3 = 0 or 1. + + if ( (l1s.next_time.fn_mod13 == 0) + || (l1s.next_time.fn_mod13 == 4)) + + macs.dsp_usf_interrupt = 1; + #endif + + } /* end if dynamic allocation mode */ + + /*---------------------------------------------------------*/ + /* Fixed allocation mode */ + /*---------------------------------------------------------*/ + + if (SET_PTR->mac_mode == FIX_ALLOC_NO_HALF) + { + UWORD8 i; + UWORD32 blk_id = l1s.next_time.block_id; + + /* Allocation bitmap isn't exhausted */ + /*-----------------------------------*/ + + if(macs.fix_alloc_exhaust == FALSE) + { + + // Allocation exhaustion detection + //--------------------------------- + + // + // 0 current_fn End of allocation STI FN_MAX + // |-----|---------|--------------------------------------|----|| + // |.....|.........| |....|| + // |-----|---------|--------------------------------------|----|| + // + // In this case, the Starting time is elapsed but current_fn < STI + // ---> We must have (current block_ID - STI_block_ID) > 0 + // + if (blk_id < macs.sti_block_id) + { + blk_id += MAX_BLOCK_ID; // MAX_BLOCK_ID is the block ID obtained when fn = FN_MAX + + } // End of FN MAX modulo management + + #if TESTMODE + // Never let exhaust the UL allocation in test mode packet transfer operation + if (l1_config.TestMode) + blk_id = macs.sti_block_id; + #endif + + /* Allocation bitmap isn't exhausted */ + if (blk_id < (macs.sti_block_id + SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap_length)) + { + + // Uplink allocation + //------------------ + + // Resources are allocated according to the allocation bitmap or ts_override + macs.tx_allocation = (UWORD8) + ( SET_PTR->ul_tbf_alloc->timeslot_alloc + & ( SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap[blk_id - macs.sti_block_id] + | SET_PTR->ts_override)); + // Delay + i = l1a_l1s_com.dl_tn - RXTX_DELAY; + if (i > MAX_TS_NB) + macs.tx_allocation >>= (-i); + else + macs.tx_allocation <<= i; + + // Monitoring + //----------- + + if ((l1s.next_time.fn_mod13 == 0) || (macs.rx_blk_period != l1s.next_time.block_id)) + { + // Last frame was an idle frame or was used for another task --> considered as a free frame + tra_before_frame = 8; + } + else + { + tra_before_frame = macs.tra_gap; // Tra gap of last TDMA frame is saved + } + + // DOWNLINK CONTROL TIMESLOT ALLOCATION + + if ( SET_PTR->ul_tbf_alloc->timeslot_alloc + & (MASK_SLOT0 >> SET_PTR->ul_tbf_alloc->fixed_alloc.ctrl_timeslot)) + { + // Tra and Ttb met --> allocates the downlink control timeslot + macs.rx_allocation |= (UWORD8) + (MASK_SLOT0 >> ( SET_PTR->ul_tbf_alloc->fixed_alloc.ctrl_timeslot + - l1a_l1s_com.dl_tn)); + } + + // UPLINK PDCH MONITORING + else + { + // The control timeslot has been released + + // Allocates uplink TBF timeslots for monitoring + macs.rx_allocation |= (UWORD8) ( SET_PTR->ul_tbf_alloc->timeslot_alloc + << l1a_l1s_com.dl_tn); + } + + // If Ttb or Tra not respected, the problem comes from uplink TBF + // monitored timeslots + // If Ttb not respected, downlink resources are removed + for(i = 0; i <= MS_CLASS[SET_PTR->multislot_class].ttb; i++) + macs.rx_allocation &= (~((UWORD8)(macs.tx_allocation << i))); + + // Tra respect according to the current allocation + for(i = 0; i <= MS_CLASS[SET_PTR->multislot_class].tra; i++) + macs.rx_allocation &= (~((UWORD8)(macs.tx_allocation << (8-i)))); + + // Tra respect according to the last allocation + if (tra_before_frame < MS_CLASS[SET_PTR->multislot_class].tra) + { + macs.rx_allocation &= MASK_ALL_SLOTS >> (MS_CLASS[SET_PTR->multislot_class].tra - tra_before_frame); + } + + #if MACS_STATUS + if (macs.rx_allocation == 0) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = NO_RX_MONITORED; + l1ps_macs_com.macs_status.nb ++; + } + #endif + + // Last block of the allocation bitmap... next block will use new settings + // for timeslot monitoring + if ((blk_id + 1) == (macs.sti_block_id + SET_PTR->ul_tbf_alloc->fixed_alloc.bitmap_length)) + { + macs.fix_alloc_exhaust = TRUE; + // Informs L1S + l1ps_macs_com.fix_alloc_exhaust_flag = TRUE; + } + + + } // End if "allocation bitmap isn't exhausted" + else + + // Allocation bitmap has exhausted + { + macs.fix_alloc_exhaust = TRUE; + // Informs L1S + l1ps_macs_com.fix_alloc_exhaust_flag = TRUE; + + // Allocates uplink TBF timeslots for monitoring + macs.rx_allocation |= (UWORD8) ( SET_PTR->ul_tbf_alloc->timeslot_alloc + << l1a_l1s_com.dl_tn); + + } + + } // End if "allocation bitmap not exhausted" + + /* Allocation bitmap is exhausted */ + /*--------------------------------*/ + else + { + // Allocates uplink TBF timeslots for monitoring + macs.rx_allocation |= (UWORD8) ( SET_PTR->ul_tbf_alloc->timeslot_alloc + << l1a_l1s_com.dl_tn); + + } // End if fixed allocation exhausted + + } // End of fixed allocation processing + + } // End of uplink TBF processing + + /***********************************************************/ + /* Allocation parameters checking and updating */ + /***********************************************************/ + { + UWORD8 ts; + BOOL rx_ts; + BOOL tx_ts; + + #if MACS_STATUS + UWORD8 time = INVALID; /* Timeslot counter */ + #endif + + tx_no = 0; + highest_ul_ts = INVALID; + lowest_ul_ts = INVALID; + highest_dl_ts = INVALID; + lowest_dl_ts = INVALID; + + /*---------------------------------------------------------*/ + /* Trb, Ttb parameters verification and Rx, Tx number, Sum */ + /* and highest_ul_ts parameters processing */ + /*---------------------------------------------------------*/ + + /* We verifies all allocated uplink and downlink timeslots */ + for (ts = 0; ts < TS_NUMBER; ts ++) + { + rx_ts = (UWORD8) (macs.rx_allocation & (MASK_SLOT0 >> ts)); + tx_ts = (UWORD8) (macs.tx_allocation & (MASK_SLOT0 >> ts)); + + #if MACS_STATUS + + /* If Rx(ts) = 0 and Tx(ts) = 0 */ + /*------------------------------*/ + + if ((!rx_ts) && (!tx_ts)) + { + /* time is incremented */ + /* If time was invalid, it becomes active */ + if (time < TS_NUMBER) + time ++; + if ((time == RX_SLOT)||(time == TX_SLOT)) + time = 1; + } /* End if Rx = 0 and Tx = 0 */ + + /* If Rx(ts) = 1 and Tx(ts) = 1 */ + /*------------------------------*/ + + if ((rx_ts) && (tx_ts)) + { + /* error (only type 1 mobiles are supported) */ + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR; + l1ps_macs_com.macs_status.nb ++; + } /* End if Rx = 1 and Tx = 1 */ + #endif + + /* If Rx(ts) = 1 */ + /*---------------*/ + + if (rx_ts) + { + highest_dl_ts = ts; + #if MACS_STATUS + /* If time is valid (invalid=0xFF) and time error */ + if ((time < MS_CLASS[SET_PTR->multislot_class].trb) || (time == TX_SLOT)) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR; + l1ps_macs_com.macs_status.nb ++; + } + time = RX_SLOT; + #endif + /* First Rx updating */ + if (lowest_dl_ts == INVALID) + lowest_dl_ts = ts; + + } /* End if Rx = 1 */ + + /* If Tx(ts) = 1 */ + /*---------------*/ + + if (tx_ts) + { + /* Number of Tx is incremented and highest_ul_ts is updated */ + tx_no ++; + highest_ul_ts = ts; + #if MACS_STATUS + /* If time is valid (invalid=0xFF) and time error */ + if ( (time < MS_CLASS[SET_PTR->multislot_class].ttb) + || (time == RX_SLOT)) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR; + l1ps_macs_com.macs_status.nb ++; + } + time = TX_SLOT; + #endif + /* First Tx updating */ + if (lowest_ul_ts == INVALID) + lowest_ul_ts = ts; + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1< MS Class isn't suported + // Note: we considered that the first slot of the next TDMA is always a RX + if (time < MS_CLASS[SET_PTR->multislot_class].trb) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_TIME_ERROR; + l1ps_macs_com.macs_status.nb ++; + } + + /*---------------------------------------------------------*/ + /* Sum, Rx and Tx parameters verification */ + /*---------------------------------------------------------*/ + + if ( ((rx + tx) > MS_CLASS[SET_PTR->multislot_class].sum) + ||(rx > MS_CLASS[SET_PTR->multislot_class].rx) + ||(tx > MS_CLASS[SET_PTR->multislot_class].tx)) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_SUM_ERROR; + l1ps_macs_com.macs_status.nb ++; + } + + // If all downlink timeslots are before the first uplink timeslot or after + // the last uplink timeslot, Rx and Tx parameters are met + if ( ( (highest_dl_ts > lowest_ul_ts) + || (lowest_dl_ts > lowest_ul_ts)) + && ( (highest_dl_ts < highest_ul_ts) + || (lowest_dl_ts < highest_ul_ts))) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = MS_CLASS_SUM_ERROR; + l1ps_macs_com.macs_status.nb ++; + } + + #endif + + } /* End of allocation parameters checking and updating */ + + + /***********************************************************/ + /* Uplink RLC/MAC blocks management (RLC - DSP interfaces) */ + /* PACCH/U placement (Poll response processing) */ + /***********************************************************/ + + { + BOOL poll; // TRUE if the poll response is processed + UWORD8 highest_ul_data; // Highest uplink timeslot assigned for data transfer + UWORD8 tx_allocation_s; // Used for saving of macs.tx_allocation + UWORD8 rx_allocation_s; // Used for saving of macs.rx_allocation + UWORD8 tx_data_s; // Used for saving of macs.tx_data + UWORD8 highest_ul_ts_s; // Used for saving of highest_ul_ts + UWORD8 lowest_ul_ts_s; // Used for saving of lowest_ul_ts + UWORD8 poll_resp_ts; // Timeslot on which the MS must transmit a poll response + UWORD8 ts; + UWORD8 i; + #if L1_EDA + UWORD8 rx_monitored_s; // Used for saving of rx_monitored + #endif + + /*---------------------------------------------------------*/ + /* Uplink buffer indexes initialization */ + /*---------------------------------------------------------*/ + + macs.ul_buffer_index[0] = macs.ul_buffer_index[1] = macs.ul_buffer_index[2] = + macs.ul_buffer_index[3] = macs.ul_buffer_index[4] = macs.ul_buffer_index[5] = + macs.ul_buffer_index[6] = macs.ul_buffer_index[7] = INVALID; + + // Reset all uplink blocks CS-TYPE in order to disable the validity of blocks not sent + for(i=0; i<4; i++) + { + NDB_PTR->a_du_gprs[i][0] = CS_NONE_TYPE; + NDB_PTR->a_pu_gprs[i][0] = CS_NONE_TYPE; + } + + /*---------------------------------------------------------*/ + /* Uplink RLC/MAC blocks request to RLC (RLC_UPLINK) */ + /*---------------------------------------------------------*/ + + /* All allocated uplink resources are used for data */ + macs.tx_data = macs.tx_allocation; + highest_ul_data = highest_ul_ts; + + /* RLC UPLINK CALL */ + /*-----------------*/ + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<packet_ta.ta == 255) && (macs.tx_allocation != 0)) + Trace_uplink_no_TA(); + #endif + + #if TESTMODE + if (l1_config.TestMode) + { + l1tm_rlc_uplink (tx_no, (API*) NDB_PTR->a_du_gprs); + } + else + #endif + { + rlc_uplink(SET_PTR->assignment_id, // Assignment ID + tx_no, // Number of timeslot that can be used + // for uplink data block transfer + l1s.next_time.fn, // Next frame number + SET_PTR->packet_ta.ta, // Timing advance value + (API*) NDB_PTR->a_pu_gprs, // Pointer on poll response struct + (API*) NDB_PTR->a_du_gprs, // Pointer on uplink block struct + macs.fix_alloc_exhaust // Set to 1 if fixed allocation exhausted + ); + } + + #if FF_TBF + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<a_du_gprs[i][0]) & CS_GPRS_MASK) << (8*i)); + + } + Trace_rlc_ul_param(SET_PTR->assignment_id, // Assignment ID + l1s.next_time.fn, // Next frame number + tx_no, // Number of UL timeslot that can be used + SET_PTR->packet_ta.ta, // Timing advance value + macs.fix_alloc_exhaust, + cs_type ); + } + #endif + #else + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<assignment_id, // Assignment ID + tx_no, // Number of timeslot that can be used + // for uplink data block transfer + l1s.next_time.fn, // Next frame number + SET_PTR->packet_ta.ta, // Timing advance value + (UWORD32) NDB_PTR->a_pu_gprs, // Pointer on poll response struct + (UWORD32) NDB_PTR->a_du_gprs, // Pointer on uplink block struct + macs.fix_alloc_exhaust); + } + #endif + #endif + + i = 0; + + /*---------------------------------------------------------*/ + /* Poll responses processing */ + /*---------------------------------------------------------*/ + #if L1_EDA + macs.lowest_poll_ts = INVALID; + #endif + + /* While a poll response is requested */ + while ( ( ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS1_TYPE_POLL) + || ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS_PAB8_TYPE) + || ((((UWORD8) NDB_PTR->a_pu_gprs[i][0]) & 0xF) == CS_PAB11_TYPE)) + && (i < 4)) + { + poll = TRUE; + + // The number of the timeslot on which the poll response is requested is converted to + // become relative to L1 synchronization + poll_resp_ts = (UWORD8) NDB_PTR->a_pu_gprs[i][1] + - l1a_l1s_com.dl_tn + + RXTX_DELAY; + + // All timeslots on which a poll is requested are set in last_poll_response. + // last_poll_response will be updated in FN13 = 2, 6 and 10, when the 4th control + // task will be processed for the current block period --> we'll be sure the poll + // responses are entirely transmitted (no BCCH monitoring) + macs.last_poll_response |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts); + + // Allocations are saved: it's useful to restore uplink slots that were removed + // for mapping a poll response that is finally not processed + tx_allocation_s = macs.tx_allocation; + rx_allocation_s = macs.rx_allocation; + tx_data_s = macs.tx_data; + lowest_ul_ts_s = lowest_ul_ts; + highest_ul_ts_s = highest_ul_ts; + #if L1_EDA + rx_monitored_s = macs.rx_monitored; + #endif + #if L1_EDA + //In the case of concurrent TBFs in extended dynamic mode, poll response can be canceled + //if response is not done on concurrent timeslots + if (((SET_PTR->allocated_tbf == BOTH_TBF) && (SET_PTR->mac_mode == EXT_DYN_ALLOC)) && + (!((SET_PTR->dl_tbf_alloc.timeslot_alloc) & (SET_PTR->ul_tbf_alloc->timeslot_alloc) + & (MASK_SLOT0 >> NDB_PTR->a_pu_gprs[i][1])))) + { + // Poll response not done + poll = FALSE; + } + else + #endif + /* If the requested timeslot is allocated for data transfer */ + /*----------------------------------------------------------*/ + + if (macs.tx_data & (MASK_SLOT0 >> poll_resp_ts)) + { + /* The slot is removed in tx_data */ + /* No allocation modification */ + macs.tx_data &= (UWORD8) (~(MASK_SLOT0 >> poll_resp_ts)); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MACS_STATUS(TX_CANCELLED_POLL, poll_resp_ts) + #endif + + } /* End if slot allocated for data */ + + /* If the poll response is requested on an invalid timeslot */ + /* i.e: */ + /* - Timeslot > 7 or < 0 */ + /* - Timeslot that avoid the RX on the first timeslot */ + /* according to Ttb */ + /*-------------------------------------------------------------*/ + + else + if ((poll_resp_ts > 7) || (poll_resp_ts <= MS_CLASS[SET_PTR->multislot_class].ttb)) + { + // Poll response not done + poll = FALSE; + } + + /* If the Tra parameter isn't respected */ + /*--------------------------------------*/ + + #if L1_EDA + //Tra does not always apply with EDA. + else + if (( (MASK_SLOT0 >> poll_resp_ts) + & ( macs.rx_allocation + >> (TS_NUMBER - MS_CLASS[SET_PTR->multislot_class].tra)) && (SET_PTR->mac_mode != EXT_DYN_ALLOC)) + || ((poll_resp_ts == 6) && (l1ps_macs_com.fb_sb_task_enabled))) + #else + else + if ( (MASK_SLOT0 >> poll_resp_ts) + & ( macs.rx_allocation + >> (TS_NUMBER - MS_CLASS[SET_PTR->multislot_class].tra))) + + #endif + { + // Poll response not done + poll = FALSE; + } + + /* Ttb and Tra respected */ + /* Poll on a slot not already allocated for uplink data transfer */ + /*---------------------------------------------------------------*/ + + else + { + /* If Ttb parameter isn't respected */ + /*-----------------------------------*/ + + // If one or several downlink timeslots are allocated between: + // - Ttb timeslots before the timeslot to use for poll response + // - AND the last slot of the frame (optimization) + // --> Ttb parameter isn't respected if the poll response is transmitted + // so the RX resources are removed + + macs.rx_allocation &= ~((UWORD8) ( macs.rx_allocation + & ( MASK_ALL_SLOTS + >> ( poll_resp_ts + - MS_CLASS[SET_PTR->multislot_class].ttb)))); + + #if L1_EDA + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + UWORD8 only_monitored_ts; + + only_monitored_ts = ~((UWORD8)(SET_PTR->dl_tbf_alloc.timeslot_alloc << l1a_l1s_com.dl_tn)) & macs.rx_monitored; + macs.rx_allocation &= ~(only_monitored_ts & (MASK_ALL_SLOTS >> (poll_resp_ts + 1 - RXTX_DELAY))); + macs.rx_monitored &= macs.rx_allocation; + } + #endif + /* The requested slot is allocated */ + macs.tx_allocation |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts); + + /* Lowest, highest numbered uplink timeslot and Tx parameter are updated */ + + if (poll_resp_ts < lowest_ul_ts) + lowest_ul_ts = poll_resp_ts; + + if ((poll_resp_ts > highest_ul_ts) || (highest_ul_ts == INVALID)) + highest_ul_ts = poll_resp_ts; + + tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1); + + /* Tx and Sum parameters checking */ + /*--------------------------------*/ + + /* While Tx or Sum parameter isn't respected and the poll response hasn't */ + /* already been removed */ + while ( ( (tx > MS_CLASS[SET_PTR->multislot_class].tx) + || ((rx + tx) > MS_CLASS[SET_PTR->multislot_class].sum)) + && (poll == TRUE)) + { + /* If no uplink timeslot is used for data */ + if (macs.tx_data == 0) + { + /* The poll response isn't processed */ + poll = FALSE; + } + else + { + /* Highest uplink PDTCH is removed */ + macs.tx_allocation &= (UWORD8) (~(MASK_SLOT0 >> highest_ul_data)); + macs.tx_data &= (UWORD8) (~(MASK_SLOT0 >> highest_ul_data)); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MACS_STATUS(TX_CANCELLED_POLL, highest_ul_data) + #endif + + /* Lowest, highest numbered uplink timeslot and Tx parameter are updated */ + + lowest_ul_ts = INVALID; + highest_ul_ts = INVALID; + highest_ul_data = INVALID; + + for (ts = 0; ts < TS_NUMBER; ts ++) + { + if (macs.tx_allocation & (MASK_SLOT0 >> ts)) + { + if (lowest_ul_ts == INVALID) + lowest_ul_ts = ts; + highest_ul_ts = ts; + if (macs.tx_data & (MASK_SLOT0 >> ts)) + highest_ul_data = ts; + } + } + + tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1); + + } + } /* End while Tx or Sum parameter not met */ + } /* End of case "poll on a timeslot not already allocated for uplink data transfer" + " Tra and Ttb respected " */ + + /* If the poll response is done */ + /*------------------------------*/ + if (poll == TRUE) + { + // Note: Power measurement always found because Tra met + + UWORD8 cs_type; + UWORD16 prach_info; + #if L1_EDA + UWORD8 only_monitored_ts; + #endif + + cs_type = (UWORD8) ((NDB_PTR->a_pu_gprs[i][0]) & 0xF); + prach_info = (UWORD16) l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2]; + + if(cs_type == CS_PAB8_TYPE) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2] = ((API)(l1a_l1s_com.Scell_info.bsic << 2)) | + ((API)(prach_info) << 8); + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][3] = 0; + + // macs.tx_prach_allocation is updated + macs.tx_prach_allocation |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts); + } + else + if(cs_type == CS_PAB11_TYPE) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][2] = ((API)(prach_info) << 5); + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[i][3] = ((API)(l1a_l1s_com.Scell_info.bsic << 10)); + + // macs.tx_prach_allocation is updated + macs.tx_prach_allocation |= (UWORD8) (MASK_SLOT0 >> poll_resp_ts); + } + + #if L1_EDA + only_monitored_ts = ~((UWORD8)(SET_PTR->dl_tbf_alloc.timeslot_alloc << l1a_l1s_com.dl_tn)) & (SET_PTR->ul_tbf_alloc->timeslot_alloc<< l1a_l1s_com.dl_tn); + //lowest_poll_ts variable is used to remove only monitored ts above a ts + //used for a poll. + if (SET_PTR->mac_mode == EXT_DYN_ALLOC) + { + if ((poll_resp_ts - RXTX_DELAY) < macs.lowest_poll_ts) + macs.lowest_poll_ts = (poll_resp_ts - RXTX_DELAY); + } + #endif + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_PDTCH(cs_type, tx_allocation_s & (0x80 >> poll_resp_ts), poll_resp_ts + l1a_l1s_com.dl_tn) + #endif + + // a_ul_buffer_gprs updating + macs.ul_buffer_index[poll_resp_ts] = i + 8; + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<l1_dyn_trace & 1<l1_dyn_trace & 1<a_pu_gprs[i][0]) & CS_GPRS_MASK)); + + } + #endif + #endif + i ++; + + } /* End while a poll response is requested and can be mapped */ + + /*---------------------------------------------------------*/ + /* Uplink RLC/MAC data blocks processing */ + /*---------------------------------------------------------*/ + + i = 0; + ts = 0; + macs.rlc_blocks_sent = 0; + + // tx_data_s represents here the remaining timeslots that must be associated + // with a RLC/MAC data block + tx_data_s = macs.tx_data; + + /* While a timeslot is available to transmit an uplink RLC/MAC data block */ + while (tx_data_s != 0) + { + /* If slot is allocated for data transfer */ + if (macs.tx_data & (MASK_SLOT0 >> ts)) + { + UWORD8 cs_type = (((UWORD8) NDB_PTR->a_du_gprs[i][0]) & 0xF); + + /* If no RLC/MAC block is sent by RLC */ + /*------------------------------------*/ + + if (cs_type == CS_NONE_TYPE) + { + // All uplink timeslots used for data and situated after this timeslot + // (inluding this timeslot) are removed + macs.tx_allocation &= (UWORD8) (~( macs.tx_data & (MASK_ALL_SLOTS >> ts))); + macs.tx_data &= (UWORD8) (~(MASK_ALL_SLOTS >> ts)); + tx_data_s = 0; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MACS_STATUS(TX_ALLOWED_NO_BLK, ts) + #if FF_TBF + //Update the ul_status fileds for cond PDTCH trace + //Since this blcok doesn't have any valid CS scheme, cs_type=0 and payload=11 + if (trace_info.current_config->l1_dyn_trace & 1<l1_dyn_trace & 1<> ts)); + /* rlc_blocks_sent value processed */ + macs.rlc_blocks_sent ++; + /* Uplink buffer index stored in ul_buffer_index */ + macs.ul_buffer_index[ts] = i; + + /* Next data block */ + i ++; + } + + } /* End if slot allocated for data transfer */ + + /* Next timeslot */ + ts ++; + } /* End while */ + + } /* End of poll responses / uplink blocks processing */ + + /***********************************************************/ + /* Measurement gap allocation */ + /***********************************************************/ + + l1ps_macs_meas(); + + #if MACS_STATUS + if (macs.pwr_allocation == 0) + { + l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb] = NO_MEAS_MAPPED; + l1ps_macs_com.macs_status.nb ++; + } + #endif + + // Initialize the reception block period + macs.rx_blk_period = NO_DL_BLK; + + } /* End if next frame is the first of a block period */ + + /***********************************************************/ + /* RLC_DOWNLINK call enabling for uplink PDCH status */ + /***********************************************************/ + + // FN 13 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ---------------------------------------------------------- + // || B0 || B1 || B2 || I || + // || | | | || X | | | || X | | | || X || + // ---------------------------------------------------------- + + if ( (l1s.actual_time.fn_mod13 == 4) + || (l1s.actual_time.fn_mod13 == 8) + || (l1s.actual_time.fn_mod13 == 12)) + { + #if (FF_TBF) + l1ps_macs_rlc_uplink_info(); + #else + l1ps_macs_com.rlc_downlink_call = TRUE; + #endif + + // RTT: trace UL PDTCH blocks + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + if (SELECTED_BITMAP(RTTL1_ENABLE_UL_PDTCH)) + { + UWORD8 i,j = 0; + + for(i=2; i < 8; i++) + { + if (macs.tx_data & (0x80 >> i)) + { + RTTL1_FILL_UL_PDTCH((((UWORD8) NDB_PTR->a_du_gprs[j][0]) & 0xF), 1, i) + j++; + } + } + } + #endif + } + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif // FF_L1_IT_DSP_USF + + + /***********************************************************/ + /* MAC-S control result for LAYER 1 */ + /***********************************************************/ + + /* We update allocation structures in Layer 1 - MAC-S interface */ + l1ps_macs_com.rx_allocation = macs.rx_allocation; + l1ps_macs_com.tx_nb_allocation = macs.tx_allocation & (~macs.tx_prach_allocation); + l1ps_macs_com.tx_prach_allocation = macs.tx_prach_allocation; + l1ps_macs_com.pwr_allocation = macs.pwr_allocation; + + + #if FF_L1_IT_DSP_USF + // When dynamic allocation is in use for uplink TBF, notifies L1S about + // USF uncertainty for FN%13=3 and 7 + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + if (macs.usf_vote_enable) + l1ps_macs_com.usf_status = USF_AWAITED; + else + l1ps_macs_com.usf_status = USF_AVAILABLE; + } + #endif // FF_L1_IT_DSP_USF + + /***********************************************************/ + /* DSP programming */ + /***********************************************************/ + + // Write uplink blocks - timeslots correspondance in a_ul_buffer_gprs + // MAC mode in d_sched_mode_gprs and the USF table in a_usf_gprs (Each frame) + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + #endif // FF_L1_IT_DSP_USF + + l1pddsp_transfer_mslot_ctrl + (l1s.next_time.fn_mod13_mod4, // Burst number (0 to 3) + macs.rx_allocation, // DL Bitmap + macs.tx_allocation, // UL Bitmap + SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_table, // USF table + SET_PTR->mac_mode, // MAC mode + macs.ul_buffer_index, // UL buffer index + SET_PTR->tsc, // Training sequence code + l1a_l1s_com.dedic_set.radio_freq, // Radio Freq. used for I/Q swap. + l1a_l1s_com.dl_tn, // DL Transfer Sync. TN. + #if FF_L1_IT_DSP_USF + macs.dsp_usf_interrupt // USF interrupt activation + #else + macs.usf_vote_enable // USF vote activation + #endif + ); + + + /*****************************************************************/ + /* TBF parameters saving and updating */ + /* last_rx_allocation, TFI, rlc_blocks_sent and last_poll_error */ + /*****************************************************************/ + + // FN 13 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ---------------------------------------------------------- + // || B0 || B1 || B2 || I || + // || | | | X || | | | X || | | | X || || + // ---------------------------------------------------------- + + if ( (l1s.next_time.fn_mod13 == 3) + || (l1s.next_time.fn_mod13 == 7) + || (l1s.next_time.fn_mod13 == 11)) + { + // Downlink blocks to report to RLC + macs.last_rx_alloc = macs.rx_allocation; + macs.rx_blk_period = l1s.next_time.block_id + 1; + if (macs.rx_blk_period > MAX_BLOCK_ID) + macs.rx_blk_period -= (UWORD32) (MAX_BLOCK_ID + 1); + + // Synchronization memorization for synchro. change detection + macs.old_synchro_ts = l1a_l1s_com.dl_tn; + + macs.tx_allocation = 0; + macs.tx_prach_allocation = 0; + } /* End if FN13 = 2, 6 OR 10 */ + +} /* END OF L1PS_MACS_CTRL() */ + +/*-----------------------------------------------------------*/ +/* l1ps_macs_read() */ +/*-----------------------------------------------------------*/ +/* Parameters: global l1ps_macs_com unchanged */ +/* global l1s unchanged */ +/* global l1a_l1s_com unchanged */ +/* global l1ps_dsp_com changed */ +/* */ +/* Return: */ +/* */ +/* Description: l1ps_macs_read checks the last received */ +/* downlink blocks. It checks if the TFI field */ +/* is present and good in the block header and */ +/* write in the NDB the number of received */ +/* received blocks and on which timeslot was */ +/* received each data block and how much block. */ +/* Then the RLC layer is called (rlc_downlink) */ +/*-----------------------------------------------------------*/ +void l1ps_macs_read(UWORD8 pr_table[8]) +{ + #define NDB_PTR l1ps_dsp_com.pdsp_ndb_ptr + + /***********************************************************/ + /* Downlink RLC/MAC block management */ + /***********************************************************/ + + // If we are in the first frame after a block period */ + // FN 13 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ---------------------------------------------------------- + // || B0 || B1 || B2 || I || + // || | | | || X | | | || X | | | || X || + // ---------------------------------------------------------- + // X: Received downlink RLC/MAC block management + if ( (l1s.actual_time.fn_mod13 == 4) + ||(l1s.actual_time.fn_mod13 == 8) + ||(l1s.actual_time.fn_mod13 == 12)) + { + UWORD8 ts; // Timeslot pointer + BOOL tfi_result; // Set to 1 if the TFI field is present and good + #if FF_TBF + UWORD8 cs_type; + BOOL crc_error = 0; + #endif + + /* For each radio block allocated for downlink transfer in the last block period */ + for (ts = 0; ts < TS_NUMBER; ts ++) + { + if (macs.last_rx_alloc & (MASK_SLOT0 >> ts)) + { + l1ps_macs_header_decoding(macs.rx_no, &tfi_result, &(pr_table[ts])); + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<a_dd_gprs[macs.rx_no][0] & (1<a_dd_gprs[macs.rx_no][0] & CS_GPRS_MASK; + #if L1_EGPRS + } + #endif + //If the blcok received is in CRC error, update the bit0 of dl_status as 1 + if (crc_error == (1< CS1_TYPE_DATA) && (cs_type <= CS4_TYPE)) + { + trace_info.pdtch_trace.dl_cs_type |= ((cs_type - 3) & 3) << (macs.rx_no * 2); + } + } + #else + if (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[macs.rx_no][0] & 0x0100) // CRC error + trace_info.pdtch_trace.dl_status[macs.rx_no] = 1; + else + { + // CS type + UWORD8 cs_type = NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0xf; + + if (cs_type != CS1_TYPE_DATA) + trace_info.pdtch_trace.dl_cs_type |= ((cs_type - 3) & 3) << macs.rx_no; + } + #endif + } + #endif + + // TFI filtering result stored in the downlink block buffer header + NDB_PTR->a_dd_gprs[macs.rx_no][0] &= (API) (TFI_BIT_MASK); + NDB_PTR->a_dd_gprs[macs.rx_no][0] |= (API) (tfi_result << TFI_BIT_SHIFT); + + /*---------------------------------------------------------*/ + /* Timeslot and Rx_no values updating */ + /*---------------------------------------------------------*/ + + // Timeslot number (relative to the network) on which the block was received is + // stored in the downlink block buffer header + + NDB_PTR->a_dd_gprs[macs.rx_no][1] = ts + l1a_l1s_com.dl_tn; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_PDTCH((UWORD8) (NDB_PTR->a_dd_gprs[macs.rx_no][4]), \ + tfi_result, \ + NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0x0100 >> 8, \ + NDB_PTR->a_dd_gprs[macs.rx_no][0] & 0x000f, \ + ts + l1a_l1s_com.dl_tn) + #endif + + macs.rx_no ++; + + } /* End if timeslot was allocated in downlink for the last block period */ + } /* Next timeslot (FOR statement) */ + + #if FF_TBF + //The "rlc_downlink_bufferize_param" structure is used to memorize parameters + //over a block period in order to cope with spreading issue. + // + // C|W R | + // |C W R | + // | C W R| TBF 1 + // | C W|R <------------ + //---------------------- + // | C|W R <-------------- + // | |C W R + // | | C W R TBF 2 + // | | C W R + // ^ + // | + // worst case where the rlc_downlink() function can be called + // when spreading occurs + + //the case above depicts a new TBF assignment without change of the synchronization: + //as the call to the rlc_downlink() function (that needs among other the assignment id parameter) + //can be delayed due to spreading, the assignment id of TBF 1 should be memorized + //until the call of the rlc_downlink() function that handles the last block of TBF 1 + + l1ps_macs_com.rlc_downlink_bufferize_param.allocated_tbf = l1ps.read_param.allocated_tbf; + l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id = l1ps.read_param.assignment_id; + #if L1_EGPRS + l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode = l1ps.read_param.tbf_mode; + #endif + + // New buffer to be allocated + macs.dl_buffer_index = INVALID; + // Initialize spreading counter + macs.tdma_delay = 0; + + // rlc_uplink_info() invokation in case of block skipped due to resynchro + // See L1_MCU-CHG-17924 + if (l1s.task_status[PDTCH].current_status != RE_ENTERED) + l1ps_macs_rlc_uplink_info(); + #endif + /***********************************************************/ + /* RLC_DOWNLINK call enabling for downlink PDCH status */ + /***********************************************************/ + l1ps_macs_com.rlc_downlink_call = TRUE; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + #if L1_BINARY_TRACE == 0 + if (trace_info.current_config->l1_dyn_trace & (1<a_dd_gprs[i][0] & 0x0100) >> (1+i)); + + Trace_Packet_Transfer(crc_error); // Previous RX blocks CRC_ERROR summary + } + #endif + #endif + + } /* End if first frame after a block period */ + +} /* END OF L1PS_MACS_READ */ + +/*-----------------------------------------------------------*/ +/* l1ps_macs_meas() */ +/*-----------------------------------------------------------*/ +/* Parameters: global l1ps_macs_com unchanged */ +/* global l1a_l1s_com unchanged */ +/* static macs.rx_allocation unchanged */ +/* static macs.tx_allocation unchanged */ +/* static macs.pwr_allocation changed */ +/* Return: */ +/* */ +/* Description: This function processes the power measurement*/ +/* gap according to the MS class and timeslots */ +/* allocated in macs.tx_allocation and */ +/* macs.rx_allocation fields. */ +/*-----------------------------------------------------------*/ +void l1ps_macs_meas() +{ + #define SET_PTR l1pa_l1ps_com.transfer.aset + + WORD8 ts = 7; // Timeslot pointer + UWORD8 gap = 0; // Gap size counter + UWORD8 meas = 0; // Temporary gap processing + UWORD8 bitmap_rx, bitmap_tx; + + macs.pwr_allocation = 0; + bitmap_rx = macs.rx_allocation; + bitmap_tx = macs.tx_allocation; + + // Searching of the last allocated timeslot + // Note: Layer 1 always synchronize on a RX event, so the Tra gap will always + // be found after the last allocated timeslot of a frame + + while ( (ts >= 0) + && ((bitmap_rx & 0x01) == 0) + && ((bitmap_tx & 0x01) == 0)) + { + // Memorization of the timeslot + meas |= (UWORD8) (MASK_SLOT0 >> ts); + // Gap is incremented + gap ++; + + bitmap_rx >>= 1; + bitmap_tx >>= 1; + ts --; + } + + // Last allocated timeslot: ts + // Power gap size: gap + + // Save the "tra gap" at the end of the frame + macs.tra_gap = gap; + + // If Tra respected before the first Rx of the frame after + // Here we consider that L1 is ALWAYS synchronized on a RX timeslot + if (gap >= MS_CLASS[SET_PTR->multislot_class].tra) + { + // The gap is allocated + macs.pwr_allocation |= meas; + } + else + // If the first slot of the next frame is free and permit to respect the Tra parameter + // in fixed mode + // Notes: + // - if Tra not respected and the current slot 0 isn't allocated --> the slot 0 of + // the next frame will not be allocated (only possible in Fixed mode) + // - in all cases, only one timeslot need to be removed + if ( (gap + 1 >= MS_CLASS[SET_PTR->multislot_class].tra) + && (!(macs.rx_allocation & MASK_SLOT0))) + { + // The gap is allocated + macs.pwr_allocation |= meas; + } + +#if L1_EDA + //if in extended dynamic allocation and if no power measurement is set in Tra gap (Tra not fulfilled) + //then power measurement is set in Tta gap if MS class supports it. + if ((SET_PTR->mac_mode == EXT_DYN_ALLOC) && (!macs.pwr_allocation)) + { + UWORD8 i = MAX_TS_NB; + + //compute tta + while (!(macs.rx_allocation & (MASK_SLOT0 >> i))) + i--; + + i++; + gap = 0; + meas = 0; + while (!(macs.tx_allocation & (MASK_SLOT0 >> i))) + { + gap++; + meas |= (UWORD8) (MASK_SLOT0 >> i); + i++; + } + + if (gap <= MS_CLASS[SET_PTR->multislot_class].tta) + macs.pwr_allocation |= meas; + } +#endif //#if L1_EDA +} /* End of l1ps_macs_meas */ + +/*-----------------------------------------------------------*/ +/* l1ps_macs_header_decoding() */ +/*-----------------------------------------------------------*/ +/* Parameters: */ +/* */ +/* Return: */ +/* */ +/* Description: This function process the TFI filtering and */ +/* decode the PR value in the MAC header of the */ +/* block stored in buffer rx_no. */ +/*-----------------------------------------------------------*/ +void l1ps_macs_header_decoding(UWORD8 rx_no, UWORD8 *tfi_result, UWORD8 *pr) +{ + UWORD8 payload; // Payload type value in the RLC/MAC header + UWORD8 tfi; // TFI value + UWORD16 mac_header[2]; // Downlink block MAC header + + *pr = 0; + + // DSP Driver + // Downlink block MAC header reading + + mac_header[0] = NDB_PTR->a_dd_gprs[rx_no][4]; + mac_header[1] = NDB_PTR->a_dd_gprs[rx_no][5]; + + *tfi_result = TFI_NOT_FILTERED; + +#if TFI_FILTERING + + /*---------------------------------------------------------*/ + /* TFI Filtering */ + /*---------------------------------------------------------*/ + + *tfi_result = TFI_BAD; + + /* Payload reading in the block header */ + /*-------------------------------------*/ + + payload = (UWORD8) (((mac_header[0]) >> PAYLOAD_SHIFT) & PAYLOAD_MASK); + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<> 2; + } + #endif + + /* If the payload time isn't "RESERVED" */ + if (payload != RESERVED) + { + /* Data block case, processed if a downlink TBF is assigned */ + /*----------------------------------------------------------*/ + + if (payload == DATA_BLOCK) + { + *pr = (UWORD8) ((mac_header[0] >> DATA_PR_SHIFT) & PR_MASK); + + if ((l1ps.read_param.allocated_tbf == DL_TBF) || (l1ps.read_param.allocated_tbf == BOTH_TBF)) + { + // TFI value reading + tfi = (UWORD8) ((mac_header[0] & DATA_TFI_MASK) >> DATA_TFI_SHIFT); + + // Downlink TFI control + if (tfi == l1ps.read_param.dl_tfi) + { + *tfi_result = TFI_GOOD; + } + } // End if "downlink TBF enabled" + + } /* End of data block case */ + + /* Control block case */ + /*--------------------*/ + + else + { + /* Optionnal field is no present */ + if (payload == CTRL_NO_OPTIONAL) + *tfi_result = TFI_NOT_PRESENT; + + /* Optionnal field is present */ + if (payload == CTRL_OPTIONAL) + { + *pr = (UWORD8) ((mac_header[1] >> CTRL_PR_SHIFT) & PR_MASK); + + /* AC = 1 : TFI is present */ + if (mac_header[0] & AC_MASK) + { + // TFI value reading + tfi = (UWORD8) ((mac_header[1] & CTRL_TFI_MASK) >> CTRL_TFI_SHIFT); + + /* If direction is downlink TBF (D = 1) and a downlink TBF is in progress */ + if ( mac_header[1] & MASK_D) + { + if ( (l1ps.read_param.allocated_tbf == DL_TBF) + || (l1ps.read_param.allocated_tbf == BOTH_TBF)) + { + // Downlink TFI value is checked + if (tfi == l1ps.read_param.dl_tfi) + { + *tfi_result = TFI_GOOD; + } + } + } /* End if direction is downlink */ + + /* If direction is uplink TBF (D = 0) and an uplink TBF is in progress */ + else if ( (l1ps.read_param.allocated_tbf == UL_TBF) + || (l1ps.read_param.allocated_tbf == BOTH_TBF)) + { + // Uplink TFI value is checked + if (tfi == l1ps.read_param.ul_tfi) + { + *tfi_result = TFI_GOOD; + } + + } /* End if direction is uplink */ + + } /* End if AC = 1 */ + + /* AC = 0 : TFI is no present */ + else + *tfi_result = TFI_NOT_PRESENT; + + } // End if control block with optionnal field + + } // End of control block case + + } // End if PAYLOAD != "RESERVED" + +#endif + + /*---------------------------------------------------------*/ + /* pr_table updating */ + /*---------------------------------------------------------*/ + + if(l1ps.read_param.dl_pwr_ctl.p0 == 255) + *pr = 0; // PR unused in "No power control" mode + else + *pr = PR_CONVERSION[l1ps.read_param.dl_pwr_ctl.bts_pwr_ctl_mode][*pr]; + + // If TFI isn't good + if (*tfi_result != TFI_GOOD) + { + // Set bit 7 to 1 + *pr |= 0x80; + } + +} + +/*-----------------------------------------------------------*/ +/* l1ps_macs_rlc_downlink_call() */ +/*-----------------------------------------------------------*/ +/* Parameters: */ +/* */ +/* Return: */ +/* */ +/* Description: This function is called at the end of L1S */ +/* execution if RLC_DOWNLINK must be called. */ +/* */ +/*-----------------------------------------------------------*/ +void l1ps_macs_rlc_downlink_call(void) +{ + UWORD8 i; + #if FF_TBF + UWORD32 fn; + BOOL rlc_dl_call = FALSE; + API* rlc_buffer; + API* dummy_rlc_buffer = NULL; + + //correct reporting of FN to L3 should be TDMA 4, 8 or 12 of MF13 + fn=l1s.actual_time.fn-l1s.actual_time.fn_mod13_mod4; + + //when fn is in first block of the MF13 (which value is not a correct value + //to report to upper layer) then fn should be decremented so that fn%13 = 12 + if(l1s.actual_time.fn_mod13 <= 3) + fn--; + + //to cope with border case +// if (fn < 0) //OMAPS00090550 +// fn += MAX_FN - 1; //OMAPS00090550 + + // Retrieve decoded blocks from API. All payload decoded check. + if (!rlc_downlink_copy_buffer(FALSE)) + { + // Flag RLC call + rlc_dl_call = TRUE; + + // RLC buffer exhaustion check + if ((macs.dl_buffer_index == INVALID) || (l1a_l1s_com.recovery_flag)) + { + if (macs.tdma_delay >= 3) + { + // No block reported ever by DSP + // #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + // l1_trace_egprs(NO_BLOCKS_PASSED_TO_L3); + // #endif + + #if (TRACE_TYPE==5) + trace_fct_simu("MACS ERROR: No RLC blocks passed to L3 on current frame", 0); + sprintf(errormsg,"MACS ERROR: No RLC blocks passed to L3 on current frame"); + log_sim_error(ERR); + #endif + } + else + { + // No RLC buffer available + + #if (TRACE_TYPE==5) + trace_fct_simu("MACS ERROR: No free buffer to copy RLC blocks on current frame", 0); + //sprintf(errormsg,"MACS ERROR: No free buffer to copy RLC blocks on current frame"); + //log_sim_error(ERR); + #endif + } + + // Dummy buffer to be reported + rlc_buffer = (API*) dummy_rlc_buffer; + } + // RLC buffer has been succesfully allocated + else + { + // RLC buffer to be reported + rlc_buffer = (API*) &(macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs); + + #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4) + #if L1_BINARY_TRACE == 0 + if (trace_info.current_config->l1_dyn_trace & (1<> (1+i)); + } + else + #endif + { + for(i=0;i> (1+i)); + } + Trace_Packet_Transfer(crc_error); // Previous RX blocks CRC_ERROR summary + } + #endif + #endif + #if L1_EGPRS + // IR testing specific trace + #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4) + if ((trace_info.current_config->l1_dyn_trace & (1<> 1) & 0x7f); + bsn2 = 0; + + crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_BLOCK_ERROR))); + crc = (crc >> B_CRC_HEADER_ERROR); + break; + + case MCS1_TYPE: + case MCS2_TYPE: + case MCS3_TYPE: + case MCS4_TYPE: + // rlc mac header type 3 + cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1]) >> 9) & 0x0F ; + j = 255 ; // cps is set + case MCS5_TYPE: + case MCS6_TYPE: + // rlc mac header type 2 + if (j != 255) + { + cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1]) >> 9) & 0x07 ; + } + do + { + if (cps == CPS_value1_6[k][mcs-MCS1_TYPE]) + { // set puncturing scheme for payload 1 and 2: 0x01 PS1 0x10 PS2 0x11 PS3 related to time slot i + trace_info.ir_trace.puncturing |= (((k+1) << 2) << (4*(3-i))) ; + break ; + } + k++; + } while (k < 3) ; + + // EGPRS data block, Header Type 2 and 3 + if (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_HEADER_ERROR)) + bsn1 = 0xffff; + else + { + bsn1 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 0] >> 14) & 0x03); + bsn1 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] & 0x1ff) << 2); + } + bsn2 = 0; + + crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_BLOCK_ERROR))); + crc = (crc >> B_CRC_HEADER_ERROR); + break; + + case MCS7_TYPE: + case MCS8_TYPE: + case MCS9_TYPE: + // rlc mac header type 1 + cps = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 2]) >> 3) & 0x1F ; + do + { + if (cps == CPS_value7_9[j][k][mcs-MCS7_TYPE]) + { // set puncturing scheme for payload 1 and 2: 0x01 PS1 0x10 PS2 0x11 PS3 related to time slot i + trace_info.ir_trace.puncturing |= ((((j+1) << 2) | (k+1)) << (4*(3-i))) ; + break ; + } + k++; + if (k == 3) + { + k = 0; + j++ ; + } + } while (j < 3) ; + + // EGPRS data block, Header Type 1 + if (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_HEADER_ERROR)) + { + bsn1 = 0xffff; + bsn2 = 0xffff; + } + else + { + bsn1 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 0] >> 14) & 0x03); + bsn1 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] & 0x1ff) << 2); + + bsn2 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 1] >> 9) & 0x7f); + bsn2 |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 2] & 0x07) << 7); + bsn2 += bsn1; + if (bsn2 >= 2048) + bsn2 -= 2048; + } + + crc = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_PAYLOAD2_ERROR) + (1 << B_CRC_BLOCK_ERROR))); + crc = (crc >> B_CRC_HEADER_ERROR); + break; + + default: + bsn1 = 0xffff; + bsn2 = 0xffff; + crc = ((1 << B_CRC_HEADER_ERROR) + (1 << B_CRC_PAYLOAD1_ERROR) + (1 << B_CRC_PAYLOAD2_ERROR) + (1 << B_CRC_BLOCK_ERROR)); + crc = (crc >> B_CRC_HEADER_ERROR); + break; + } + + // Update IR info from current PDCH + trace_info.ir_trace.crc |= (crc << ((3-i)*8)); + trace_info.ir_trace.bsn[i] = ((bsn1 << 16) | bsn2); + trace_info.ir_trace.mcs |= ((mcs << ((3-i)*8))); + + /* we take only the msb of cv_bep and mean_bep */ + trace_info.ir_trace.cv_bep_egprs[i] = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][2]) >> 8) ; + trace_info.ir_trace.mean_bep_egprs[i] = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][3]) ; + if (((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & TFI_BIT_MASK) >> TFI_BIT_SHIFT) == TFI_BAD) + trace_info.ir_trace.status_ir_tfi |= (0x1 << (3-i)) ; /* set tfi flag to 1 if block is not for MS */ + } + + trace_info.ir_trace.fn = l1s.actual_time.fn ; + trace_info.ir_trace.status_ir_tfi |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status & (1 << IR_OUT_OF_MEMORY))<<(7-IR_OUT_OF_MEMORY)) ; + + // Output trace + Trace_IR (&trace_info.ir_trace) ; + } + #endif //(TRACE_TYPE == 1)||(TRACE_TYPE == 4) + #endif //L1_EGPRS + #if TESTMODE + if (l1_config.TestMode) + { + BOOL crc_error_bler; //Local var used for accumulating BLER + UWORD8 i; + + l1tm.tmode_stats.bler_total_blocks++; + #if L1_EGPRS + if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS) + { + for(i=0;i> B_CRC_BLOCK_ERROR); + if (crc_error_bler == TRUE) + l1tm.tmode_stats.bler_crc[i]++; + } + } + else + #endif + { + for(i=0;i> B_CRC_BLOCK_ERROR); + if (crc_error_bler == TRUE) + l1tm.tmode_stats.bler_crc[i]++; + } + } + } + #endif + } + } + // Payload still awaited + else // (!rlc_downlink_copy_buffer(FALSE) + { + // Check spreading limit not exceeded + if ((macs.tdma_delay >= 3) || (l1a_l1s_com.recovery_flag)) + { + // Free RLC buffer + macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs = RLC_BLOCK_ACK; + + // Flag RLC call + rlc_dl_call = TRUE; + + // Dummy buffer to be reported + rlc_buffer = (API*) dummy_rlc_buffer; + + // No block reported ever by DSP + + #if (TRACE_TYPE==5) + trace_fct_simu("MACS ERROR: No RLC blocks passed to L3 on current frame", 0); + sprintf(errormsg,"MACS ERROR: No RLC blocks passed to L3 on current frame"); + log_sim_error(ERR); + #endif + } + else + // Increment spreading counter + macs.tdma_delay++; + } // (!rlc_downlink_copy_buffer(FALSE) + + // Function RLC_DOWNLINK_DATA() to be invoked + if (rlc_dl_call) + { + + rlc_downlink_data( l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id, // Assignment ID + fn, // Frame number + rlc_buffer // Pointer on the DL structure + ); + + // Add the RLC_D traces in the case of EGPRS also + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if ((trace_info.current_config->l1_dyn_trace & 1<a_dd_gprs[i][0]) & 0x070F); + #if (L1_EGPRS) + } + #endif + } + Trace_rlc_dl_param(l1ps_macs_com.rlc_downlink_bufferize_param.assignment_id, + l1s.actual_time.fn, + macs.rx_no, + macs.rlc_blocks_sent, + macs.last_poll_response, + (dl_blk_status[1]<<16) |dl_blk_status[0], //dl_blk_status for TS1 and TS0 + (dl_blk_status[3]<<16) |dl_blk_status[2]);//dl_blk_status for TS3 and TS2 + } + #endif + macs.rx_no = 0; + l1ps_macs_com.rlc_downlink_call = FALSE; + } + + #else + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1< MAX_TS_NB) + { + macs.last_poll_response <<= (-i); + } + else + { + macs.last_poll_response >>= i; + } + + // Store number of RX within NDB for RLC + //-------------------------------------- + + NDB_PTR->d_rlcmac_rx_no_gprs = macs.rx_no; + + #if L1_RECOVERY + // blocks get a CRC error in case of COM error + if (l1a_l1s_com.recovery_flag == TRUE) + { + // force bad CRC for 4 RX slots + NDB_PTR->a_dd_gprs[0][0] |= 0x0100; + NDB_PTR->a_dd_gprs[1][0] |= 0x0100; + NDB_PTR->a_dd_gprs[2][0] |= 0x0100; + NDB_PTR->a_dd_gprs[3][0] |= 0x0100; + } + #endif + /******************/ + + // Call RLC_DOWNLINK + //------------------ + + rlc_downlink( l1ps.read_param.assignment_id, // Assignment ID + l1s.actual_time.fn, // Frame number + (API*) &(NDB_PTR->d_rlcmac_rx_no_gprs), // Pointer on the DL structure + macs.rlc_blocks_sent, // ID of the last transmitted uplink + // data block + macs.last_poll_response // Status of the poll responses of + ); // the last block period + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<d_rlcmac_rx_no_gprs), + (UWORD8) NDB_PTR->d_rlcmac_rx_no_gprs, + macs.rlc_blocks_sent, + macs.last_poll_response); + } + #endif + + /* FreeCalypso TCS211 reconstruction */ + #if 0 //TESTMODE + if (l1_config.TestMode) + { + BOOL crc_error_bler; //Local var used for accumulating BLER + UWORD8 i; + + l1tm.tmode_stats.bler_total_blocks++; + + for(i=0; i < macs.rx_no; i++) + { + //bler_total_blocks gives the total number of blocks for computing BLER + //The block error is assigned to crc_error_bler. + //If the block is in error bler_crc is incremented. + crc_error_bler = ( (NDB_PTR->a_dd_gprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> B_CRC_BLOCK_ERROR); + if (crc_error_bler == TRUE) + l1tm.tmode_stats.bler_crc[i]++; + } + } + #endif + + // Clear parameters + //----------------- + + /* All downlink blocks were processed */ + macs.last_rx_alloc = 0; + macs.rx_no = 0; + macs.rlc_blocks_sent = 0; + macs.last_poll_response = 0; + + l1ps_macs_com.rlc_downlink_call = FALSE; + + // Reset CS type. + //--------------- + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39) + NDB_PTR->a_dd_gprs[0][0] = NDB_PTR->a_dd_gprs[1][0] = NDB_PTR->a_dd_gprs[2][0] = + NDB_PTR->a_dd_gprs[3][0] = NDB_PTR->a_dd_gprs[4][0] = NDB_PTR->a_dd_gprs[5][0] = + NDB_PTR->a_dd_gprs[6][0] = NDB_PTR->a_dd_gprs[7][0] = CS_NONE_TYPE; + #else + NDB_PTR->a_dd_gprs[0][0] = NDB_PTR->a_dd_gprs[1][0] = NDB_PTR->a_dd_gprs[2][0] = + NDB_PTR->a_dd_gprs[3][0] = CS_NONE_TYPE; + #endif +#endif +}//void l1ps_macs_rlc_downlink_call(void) +#if FF_TBF +/*-----------------------------------------------------------*/ +/* l1ps_macs_rlc_uplink_info() */ +/*-----------------------------------------------------------*/ +/* Parameters: */ +/* */ +/* Return: */ +/* */ +/* Description: This function is called in the */ +/* l1ps_macs_ctrl() function on TDMA 4, 8 or 12 */ +/* of MF13 */ +/* */ +/*-----------------------------------------------------------*/ +void l1ps_macs_rlc_uplink_info(void) +{ + UWORD8 i; + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1< MAX_TS_NB) + { + macs.last_poll_response <<= (-i); + } + else + { + macs.last_poll_response >>= i; + } + + #if L1_EGPRS + //sub_mode is ON + if (l1ps_macs_com.loop_param.sub_mode == TRUE) + { + macs.rlc_blocks_sent = 0; + macs.last_poll_response = 0; + } + #endif + + rlc_uplink_info(l1ps.read_param.assignment_id, + l1s.actual_time.fn, + macs.rlc_blocks_sent, + macs.last_poll_response); + + //While the initialization of these variables is performed in the + //l1ps_macs_rlc_downlink_call() for GPRS, for EGPRS the initialization + //is done here below. Note that it is still performed on frame index 0 + //of MF13 in the l1s_end_manager() function whether in EGPRS or GPRS mode. + //The variable below is set in the l1ps_macs_ctrl() function on frame index 2 of MF13 + //and stores the rx allocation. This allocation is used later in the l1ps_macs_read() + //function to pass the blocks that were received in the previous block period. + macs.last_rx_alloc = 0; + macs.rlc_blocks_sent = 0; + macs.last_poll_response = 0; +} + +/*-----------------------------------------------------------*/ +/* rlc_downlink_copy_buffer() */ +/*-----------------------------------------------------------*/ +/* Parameters: isr: flag that indicates whether the call */ +/* of this function is performed at the */ +/* beginning of the hisr() function */ +/* (hisr = TRUE) or not. */ +/* */ +/* Return: missing_payload: flag that indicates if still*/ +/* payloads are missing after */ +/* the copy */ +/* */ +/* Description: This function is called in the hisr() */ +/* function with hisr = TRUE and in the */ +/* l1ps_macs_rlc_downlink_call() function */ +/* with hisr = FALSE */ +/*-----------------------------------------------------------*/ + UWORD8 rlc_downlink_copy_buffer(UWORD8 isr) + { + BOOL missing_payload = FALSE; + BOOL allocation_needed = FALSE; + + UWORD32 i,j; + + // Downlink blocks expected + if (l1ps_macs_com.rlc_downlink_call) + { + // Not in TDMA3 unless we are in ISR so we may have blocks to copy + if ( ((macs.tdma_delay < 3) && (!isr)) // No logical XOR in C + || ((macs.tdma_delay >= 3) && (isr)) + ) + + { + // Test buffer allocation requirement if not already allocated + if (macs.dl_buffer_index == INVALID) + { + allocation_needed = TRUE; + } + + // Look for an available buffer and initialize it + if (allocation_needed) + { + for (i = 0; i < NBR_SHARED_BUFFER_RLC; i++) + { + //as soon as one free block is found + if (macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs == RLC_BLOCK_ACK) + { + // Store buffer index + macs.dl_buffer_index = i; + // Store number of blocks in buffer passed to RLC + macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs = macs.rx_no; + break; + } + } + } + + // Copy available blocks if buffer allocated + if (macs.dl_buffer_index != INVALID) + { + // GPRS mode, no spreading + #if L1_EGPRS + if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_GPRS) + #endif + { + // Copy whole bunch of blocks (4 downlink, worst case) + for (i=0;i= 3) && (!isr)) + { + // End of L1S in TDMA3, we need to report the status from ISR call. + missing_payload = macs.dl_missing_payload; + } + + // IR status reporting (relevant for EGPRS only) + //---------------------------------------------- + + // RLC buffer allocated, all blocks received + if ((macs.dl_buffer_index != INVALID) && (!missing_payload)) + { + #if L1_EGPRS + if ( (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS) + && (l1ps_dsp_com.edsp_ndb_ptr->d_modem_status_egprs & (1 << B_IR_OUT_OF_MEM)) ) + { + // EGPRS TBF mode, IR out of memory status flag is set + macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status |= (1 << IR_OUT_OF_MEMORY); + } + else + #endif + { + // GPRS TBF mode or EGPRS but IR out of memory not detected + macs.rlc_dbl_buffer[macs.dl_buffer_index].dl_status &= (~(1 << IR_OUT_OF_MEMORY)); + } + } + } // if (l1ps_macs_com.rlc_downlink_call) + + // Return blocks receipt completion status + return missing_payload; +} + +#endif //FF_TBF + +#if TESTMODE + //=========================================================================== + // Function called instead of l1ps_macs_ctrl if CMU200 loop mode is selected + //=========================================================================== + + void l1ps_tmode_macs_ctrl(void) + { + #define NDB_PTR l1ps_dsp_com.pdsp_ndb_ptr + #define SET_PTR l1pa_l1ps_com.transfer.aset + + NDB_PTR->a_du_gprs[0][0] = l1_config.tmode.tx_params.coding_scheme; + + /* Enable loop */ + NDB_PTR->d_sched_mode_gprs |= (1<<6); + + // Force single slot allocation for CMU loop: 1RX, 1TX + macs.rx_allocation = 0x80; + macs.tx_allocation = 0x10; + macs.tx_prach_allocation = 0; + macs.pwr_allocation = 0; + + macs.ul_buffer_index[0] = 0xFF; // UL buffer index + macs.ul_buffer_index[1] = 0xFF; + macs.ul_buffer_index[2] = 0xFF; + macs.ul_buffer_index[3] = 0; + macs.ul_buffer_index[4] = 0xFF; + macs.ul_buffer_index[5] = 0xFF; + macs.ul_buffer_index[6] = 0xFF; + macs.ul_buffer_index[7] = 0xFF; + + /* Disable USF management in the DSP */ + macs.usf_vote_enable = 0; + + /***********************************************************/ + /* MAC-S control result for LAYER 1 */ + /***********************************************************/ + + /* We update allocation structures in Layer 1 - MAC-S interface */ + l1ps_macs_com.rx_allocation = macs.rx_allocation; + l1ps_macs_com.tx_nb_allocation = macs.tx_allocation & (~macs.tx_prach_allocation); + l1ps_macs_com.tx_prach_allocation = macs.tx_prach_allocation; + l1ps_macs_com.pwr_allocation = macs.pwr_allocation; + + /***********************************************************/ + /* DSP programming */ + /***********************************************************/ + + // Write uplink blocks - timeslots correspondance in a_ul_buffer_gprs + // MAC mode in d_sched_mode_gprs and the USF table in a_usf_gprs (Each frame) + + l1pddsp_transfer_mslot_ctrl + (l1s.next_time.fn_mod13_mod4, // Burst number (0 to 3) + macs.rx_allocation, // DL Bitmap + macs.tx_allocation, // UL Bitmap + SET_PTR->ul_tbf_alloc->dynamic_alloc.usf_table, // USF table + SET_PTR->mac_mode, // MAC mode + macs.ul_buffer_index, // UL buffer index + SET_PTR->tsc, // Training sequence code + l1a_l1s_com.dedic_set.radio_freq, // Radio Freq. used for I/Q swap. + l1a_l1s_com.dl_tn, // DL Transfer Sync. TN. + #if FF_L1_IT_DSP_USF + macs.dsp_usf_interrupt // USF interrupt activation + #else + macs.usf_vote_enable // USF vote activation + #endif + ); + + //NDB_PTR->a_ctrl_ched_gprs[0] = CS1_TYPE_DATA; + NDB_PTR->a_ctrl_ched_gprs[0] = NDB_PTR->a_du_gprs[0][0]; + + } +#endif +#endif // L1_GPRS diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_afun.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_afun.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,404 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_AFUN.C + * + * Filename l1p_afun.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1P_AFUN_C + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#if (CODE_VERSION == SIMULATION) + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_varex.h" + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + + #include "l1_msgty.h" + #include "l1_proto.h" + +#else + + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_varex.h" + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + + #include "l1_msgty.h" + #include "l1_proto.h" + +#endif + +// Internal prototypes +T_TRANSFER_SET *l1pa_get_free_transfer_set (UWORD8 new_tbf); +int l1pa_sort (const void *a, const void *b); +void l1pa_reset_cr_freq_list (); +T_CRES_LIST_PARAM *l1pa_get_free_cres_list_set(); +void l1pa_send_int_meas_report (UWORD32 SignalCode, + T_L1P_ITMEAS_IND *last_l1s_msg, + T_L1A_INT_MEAS_PARAM *first_meas_ptr); +void l1pa_send_confirmation (UWORD32 SignalCode, UWORD8 id); + +/*-------------------------------------------------------*/ +/* l1pa_get_free_transfer_set() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +T_TRANSFER_SET *l1pa_get_free_transfer_set(UWORD8 new_tbf) +{ + T_TRANSFER_SET *transfer_set; + + #define clear_and_new(i, tbf) \ + switch(tbf) \ + { \ + case UL_TBF: \ + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = DL_TBF; \ + break; \ + \ + case DL_TBF: \ + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = UL_TBF; \ + break; \ + } + + // If new_tbf is to replace an existing one, we must return + // the considered free set. + if(new_tbf == BOTH_TBF) + { + if(l1pa_l1ps_com.transfer.fset[0]->allocated_tbf == NO_TBF) + transfer_set = l1pa_l1ps_com.transfer.fset[1]; + else + transfer_set = l1pa_l1ps_com.transfer.fset[0]; + } + else + if(l1pa_l1ps_com.transfer.fset[0]->allocated_tbf == new_tbf) + transfer_set = l1pa_l1ps_com.transfer.fset[0]; + else + if(l1pa_l1ps_com.transfer.fset[1]->allocated_tbf == new_tbf) + transfer_set = l1pa_l1ps_com.transfer.fset[1]; + else + if(l1pa_l1ps_com.transfer.fset[0]->allocated_tbf == BOTH_TBF) + { + clear_and_new(0, new_tbf); + transfer_set = l1pa_l1ps_com.transfer.fset[1]; + } + else + if(l1pa_l1ps_com.transfer.fset[1]->allocated_tbf == BOTH_TBF) + { + clear_and_new(1, new_tbf); + transfer_set = l1pa_l1ps_com.transfer.fset[0]; + } + else + if(l1pa_l1ps_com.transfer.fset[0]->allocated_tbf == NO_TBF) + transfer_set = l1pa_l1ps_com.transfer.fset[0]; + else + transfer_set = l1pa_l1ps_com.transfer.fset[1]; + + transfer_set->SignalCode = NULL; + transfer_set->dl_tbf_synchro_timeslot = 0; + transfer_set->ul_tbf_synchro_timeslot = 0; + transfer_set->transfer_synchro_timeslot = 0; + + // No init of "allocated_tbf" + + transfer_set->assignment_command = NO_TBF; + transfer_set->multislot_class = 0; + transfer_set->packet_ta.ta = 255; // Not present + transfer_set->packet_ta.ta_index = 255; // Not present + transfer_set->packet_ta.ta_tn = 255; // Not present + transfer_set->tsc = 0; + + transfer_set->freq_param.chan_sel.h = 0; + transfer_set->freq_param.chan_sel.rf_channel.single_rf.radio_freq = 0; + transfer_set->freq_param.chan_sel.rf_channel.hopping_rf.maio = 0; + transfer_set->freq_param.chan_sel.rf_channel.hopping_rf.hsn = 0; + transfer_set->freq_param.freq_list.rf_chan_cnt = 0; + + transfer_set->tbf_sti.present = FALSE; + + transfer_set->dl_pwr_ctl.p0 = 255; + transfer_set->dl_pwr_ctl.bts_pwr_ctl_mode = 0; + transfer_set->dl_pwr_ctl.pr_mode = 0; + + transfer_set->ts_override = 0; + transfer_set->pc_meas_chan = 0; + + // No init of "ul_tbf_alloc" and "ul_tbf_alloc", mac_mode is enought + + return(transfer_set); +} + +/*-------------------------------------------------------*/ +/* l1pa_sort() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +int l1pa_sort(const void *a, const void *b) +{ + UWORD8 entry1, entry2; + + entry1 = *((UWORD8*) a); + entry2 = *((UWORD8*) b); + + if (entry1 < entry2 ) + return(-1); + else if (entry1 == entry2) + return(0); + else + return(1); +} + +/*-------------------------------------------------------*/ +/* l1pa_reset_cr_freq_list() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function resets parameters used in Frequency */ +/* list task */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_reset_cr_freq_list() +{ + UWORD8 i; + + for(i=0; inb_carrier = 0; + flist->list_id = 0; + + // Reset fifo used in AGC algo => NEED MORE INVESTIGATION. + + + return(flist); +} + +/*-------------------------------------------------------*/ +/* l1pa_send_int_meas_report() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function builds and sends the Interf. Meas. */ +/* report to L3 */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_send_int_meas_report(UWORD32 SignalCode, + T_L1P_ITMEAS_IND *last_l1s_msg, + T_L1A_INT_MEAS_PARAM *first_meas_ptr) +{ + xSignalHeaderRec *msg; + UWORD8 i,j,k; + UWORD8 bit_mask = 0x80; + + // Allocate report msg and fill signal code. + msg = os_alloc_sig(sizeof(T_MPHP_INT_MEAS_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = SignalCode; + + // Save measurement results + //------------------------- + for(i = 0, j = 0, k = 0; i < 8; i++, bit_mask >>= 1) + { + // Fill 1st measurement report + //---------------------------- + // If a measurement was done on timeslot i + if(first_meas_ptr->meas_bitmap & bit_mask) + { + // The result is stored in the msg. + ((T_MPHP_INT_MEAS_IND *) (msg->SigP))->int_meas[i].rxlev[0] = first_meas_ptr->rxlev[j]; + + // Next measurement value + j++; + } + else + { + // No measurement processed on timeslot i (0x80 value) + ((T_MPHP_INT_MEAS_IND *) (msg->SigP))->int_meas[i].rxlev[0] = (WORD8)NO_MEAS; //omaps00090550 + } + + // Fill 2nd measurement report + //---------------------------- + // If a measurement was done on timeslot i + if(last_l1s_msg->meas_bitmap & bit_mask) + { + // The result is stored in the msg. + ((T_MPHP_INT_MEAS_IND *) (msg->SigP))->int_meas[i].rxlev[1] = last_l1s_msg->rxlev[k]; + + // Next measurement value + k++; + } + else + { + // No measurement processed on timeslot i (0x80 value) + ((T_MPHP_INT_MEAS_IND *) (msg->SigP))->int_meas[i].rxlev[1] = (WORD8)NO_MEAS; + } + } + + // Set ID in the report message + ((T_MPHP_INT_MEAS_IND *) (msg->SigP))->id = first_meas_ptr->id; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + l1_trace_message(msg); + #endif + + os_send_sig(msg, GRRM1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} + +/*-------------------------------------------------------*/ +/* l1pa_send_confirmation() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pa_send_confirmation(UWORD32 SignalCode, UWORD8 id) +{ + xSignalHeaderRec *msg_con; + + msg_con = os_alloc_sig(sizeof(T_MPHP_ASSIGNMENT_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg_con->SignalCode = SignalCode; + + ((T_MPHP_ASSIGNMENT_CON *) msg_con->SigP)->assignment_id = id; + + #if (TRACE_TYPE==1) || (TRACE_TYPE==4) + l1_trace_message(msg_con); + #endif + + os_send_sig(msg_con, GRRM1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} + + +/*-------------------------------------------------------*/ +/* l1pa_send_tbf_release_con() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pa_send_tbf_release_con(UWORD32 SignalCode, UWORD8 tbf_type) +{ + xSignalHeaderRec *conf_msg; + + // Send the confirmation message with the TBF type to L3 + // Allocate confirmation message... + conf_msg = os_alloc_sig( sizeof(T_MPHP_TBF_RELEASE_CON)); + DEBUGMSG(status,NU_ALLOC_ERR); + + //Fill the message + conf_msg->SignalCode = SignalCode; + ((T_MPHP_TBF_RELEASE_CON *)(conf_msg->SigP))->tbf_type = tbf_type; + + // Send the confirmation message... + os_send_sig(conf_msg, GRRM1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) +} +#endif //L1_GPRS diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_asyn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_asyn.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,3113 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_ASYN.C + * + * Filename l1p_asyn.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + #include "l1_macro.h" + #include "l1_confg.h" +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END + +#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM !=0)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM enabled +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise + +#define L1P_ASYN_C + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END // KEEP IN EXTERNAL MEM otherwise +#endif + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#if (CODE_VERSION == SIMULATION) + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_signa.h" + #include "l1_proto.h" + #include "l1_time.h" + #include "l1_ctl.h" + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_tabs.h" + #include "l1p_sign.h" + #include "l1p_mfta.h" + #include "l1p_macr.h" + + #include "macs_def.h" + #include "macs_cst.h" +#else + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_signa.h" + #include "l1_proto.h" + #include "l1_time.h" + #include "l1_ctl.h" + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_tabs.h" + #include "l1p_sign.h" + #include "l1p_mfta.h" + #include "l1p_macr.h" + + #include "macs_def.h" + #include "macs_cst.h" +#endif + +T_TRANSFER_SET *l1pa_get_free_transfer_set (UWORD8 new_tbf); +void l1pa_transfer_process (xSignalHeaderRec *msg); +void l1pa_access_process (xSignalHeaderRec *msg); +void l1pa_idle_packet_polling_process (xSignalHeaderRec *msg); +void l1pa_idle_paging_process (xSignalHeaderRec *msg); +void l1pa_cr_meas_process (xSignalHeaderRec *msg); +void l1pa_serving_cell_pbcch_read_process (xSignalHeaderRec *msg); +void l1pa_neighbor_cell_pbcch_read_process (xSignalHeaderRec *msg); +int l1pa_sort (const void *a, const void *b); +void l1pa_reset_cr_freq_list (void); +void l1pa_tcr_meas_process (xSignalHeaderRec *msg); +T_CRES_LIST_PARAM *l1pa_get_free_cres_list_set (void); +void l1pa_idle_interference_meas_process (xSignalHeaderRec *msg); +void l1pa_transfer_interference_meas_process (xSignalHeaderRec *msg); +void l1pa_idle_smscb_process (xSignalHeaderRec *msg); + +// External prototype +void l1pa_send_int_meas_report(UWORD32 SignalCode, + T_L1P_ITMEAS_IND *last_l1s_msg, + T_L1A_INT_MEAS_PARAM *first_meas_ptr); +void l1pa_send_confirmation(UWORD32 SignalCode, UWORD8 id); +void l1pa_send_tbf_release_con(UWORD32 SignalCode, UWORD8 tbf_type); + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END + +#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2 +//#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise + + +/*-------------------------------------------------------*/ +/* l1pa_task() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* L1PA (Layer 1 Asynchronous) task function. This */ +/* function manages the GPRS interface between L3 and L1.*/ +/* It is composed with a set of state machine, each */ +/* machine handles a particular GSM functionality. When */ +/* a message is received in L1_C1 message queue, it is */ +/* submitted to every state machine. The one which are */ +/* impacted by the message process it. At the end of */ +/* "l1pa_task()" function, a balance routine is called, */ +/* it enables L1S tasks consequently to the state machine*/ +/* requests. */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_task(xSignalHeaderRec *msg) +{ + UWORD8 process; + + // Clear L1PA "enable meas and tasks" variables. + //--------------------------------------------- + for(process=0; processSignalCode != L1P_PNP_INFO) && (msg->SignalCode != L1P_PEP_INFO)) + + #if (GSM_IDLE_RAM > 1) // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM + { + #endif + l1s.gsm_idle_ram_ctl.l1s_full_exec = TRUE; + #endif // GSM_IDLE_RAM + + // Serving Cell Packet System Information Reading + l1pa_serving_cell_pbcch_read_process(msg); + + // Neighbor Cell Packet System Information Reading + l1pa_neighbor_cell_pbcch_read_process(msg); + + #if (GSM_IDLE_RAM <= 1) // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM + { + // Serving Cell Packet Paging Reading + l1pa_idle_paging_process(msg); + } + #endif + // Cell reselection measurement process + l1pa_cr_meas_process(msg); + + // Packet access proccess + l1pa_access_process(msg); + + // Packet polling process + l1pa_idle_packet_polling_process(msg); + + // Packet transfer process. + l1pa_transfer_process(msg); + + // Neighbour Cell Measurement in Packet Transfer mode + l1pa_tcr_meas_process(msg); + + // Intererence measurements in packet idle mode + l1pa_idle_interference_meas_process(msg); + + // Intererence measurements in packet transfer mode + l1pa_transfer_interference_meas_process(msg); + + #if (GSM_IDLE_RAM > 1) // GPF modified for GSM_IDLE_RAM -> SW still running in Internal RAM + }else + { + // Serving Cell Packet Packet Idle Paging Reading + l1pa_idle_paging_process(msg); + } + #endif +} + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END // KEEP IN EXTERNAL MEM otherwise +#endif + +/*-------------------------------------------------------*/ +/* l1pa_access_process() */ +/*-------------------------------------------------------*/ +/* Description : This state machine handles the packet */ +/* access to the network while in PACKET IDLE mode. */ +/* */ +/* Starting messages: MPHP_RA_REQ */ +/* */ +/* Subsequent messages: MPHP_RA_REQ */ +/* */ +/* Result messages (input): L1P_PRA_DONE */ +/* */ +/* Result messages (output): MPHP_RA_CON */ +/* */ +/* Reset message (input): MPHP_RA_STOP_REQ */ +/* */ +/* Reset message (input): MPHP_RA_STOP_CON */ +/*-------------------------------------------------------*/ +void l1pa_access_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_RESULT = 2 + }; + + UWORD8 *state = &l1pa.state[P_ACC]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_INIT; + + // Reset PRACH process. + l1a_l1s_com.l1s_en_task[PRACH] = TASK_DISABLED; // Clear PRACH task enable flag. + l1pa_l1ps_com.pra_info.prach_alloc = 0; + } + break; + + + case WAIT_INIT: + { + if(SignalCode == MPHP_RA_REQ) + // 1st Random access request message. + //----------------------------------- + { + + // Download Transmit power configuration. + // Given value must be used on 1st TX. + // TXPWR value supplied by L3 is the max. TX power level the MS may use in the given band + l1s.applied_txpwr = ((T_MPHP_RA_REQ *)(msg->SigP))->txpwr; + + + #if L1_R99 + // Init PRACH process. + // "rand" parameter chosen by protocol in range [1..4] for R99 + l1pa_l1ps_com.pra_info.rand = ((T_MPHP_RA_REQ *)(msg->SigP))->rand; + #else + // "rand" parameter from msg is not used for the 1st PRACH. + l1pa_l1ps_com.pra_info.rand = 1; // First PRACH has to be sent immediately + #endif + l1pa_l1ps_com.pra_info.channel_request_data = ((T_MPHP_RA_REQ *)(msg->SigP))->channel_request_data; + l1pa_l1ps_com.pra_info.bs_prach_blks = ((T_MPHP_RA_REQ *)(msg->SigP))->bs_prach_blks; + l1pa_l1ps_com.access_burst_type = ((T_MPHP_RA_REQ *)(msg->SigP))->access_burst_type; + + // Increment rand parameter by 4 in order to avoid conflict between SYNCHRO and + // PRACH tasks when MPHP_START_PCCCH_REQ and MPHP_RA_REQ are + // sent at the same time by L3 + l1pa_l1ps_com.pra_info.rand+=4; + + if ((l1pa_l1ps_com.pra_info.bs_prach_blks == 0) || // no blocks allocated + (l1pa_l1ps_com.pra_info.bs_prach_blks > 12)) // invalid number of blocks + l1pa_l1ps_com.pra_info.prach_alloc = DYN_PRACH_ALLOC; + + // step in state machine. + *state = WAIT_RESULT; + + // Change mode to connection establishment part 1. + l1a_l1s_com.mode = CON_EST_MODE1; + + // Activate PRACH task (no semaphore for UL tasks). + l1a_l1s_com.l1s_en_task[PRACH] = TASK_ENABLED; // Set PRACH task enable flag. + + } + + // end of process. + end_process = 1; + } + break; + + case WAIT_RESULT: + { + if(SignalCode == L1P_RA_DONE) + // Random access acknowledge message: PRACH sent. + //----------------------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_RA_CON, msg, GRRM1_QUEUE); + + // Change mode to connection establishment part 2. + l1a_l1s_com.mode = CON_EST_MODE2; + + // end of process. + return; + } + + else + if(SignalCode == MPHP_RA_REQ) + // Random access message. + //----------------------- + { + // REM: rand is added the msg content since its current content is the already + // spent "slots" from the last PRACH sending. + l1pa_l1ps_com.pra_info.rand += ((T_MPHP_RA_REQ *)(msg->SigP))->rand + 1; + l1pa_l1ps_com.pra_info.channel_request_data = ((T_MPHP_RA_REQ *)(msg->SigP))->channel_request_data; + l1pa_l1ps_com.pra_info.bs_prach_blks = ((T_MPHP_RA_REQ *)(msg->SigP))->bs_prach_blks; + l1pa_l1ps_com.access_burst_type = ((T_MPHP_RA_REQ *)(msg->SigP))->access_burst_type; + + if ((l1pa_l1ps_com.pra_info.bs_prach_blks == 0) || // no blocks allocated + (l1pa_l1ps_com.pra_info.bs_prach_blks > 12)) // invalid number of blocks + l1pa_l1ps_com.pra_info.prach_alloc = DYN_PRACH_ALLOC; +// else +// l1pa_l1ps_com.pra_info.prach_alloc = FIX_PRACH_ALLOC; + else + l1pa_l1ps_com.pra_info.prach_alloc = 0; //must be reset for each burst sent + + + // Activate PRACH task (no semaphore for UL tasks). + l1a_l1s_com.l1s_en_task[PRACH] = TASK_ENABLED; // Set PRACH task enable flag. + + // end of process. + return; + } + + else + if(SignalCode == MPHP_RA_STOP_REQ) + // Request to STOP the LINK ACCESS procedure. + //------------------------------------------- + { + UWORD8 i; + + // send confirmation + l1a_send_confirmation(MPHP_RA_STOP_CON,GRRM1_QUEUE); + + // Store MAX TXPWR value to be used for first Tx PDCH blocks + for(i = 0; i < 8; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = l1s.applied_txpwr; + } + + // This process must be reset. + *state = RESET; + } + + else + if(SignalCode == MPHP_POLLING_RESPONSE_REQ) + // Stop packet access when packet polling initiated. + //-------------------------------------------------- + { + // Unacknowledged + + // This process must be reset. + *state = RESET; + } + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + end_process = 1; + } + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + +/*-------------------------------------------------------*/ +/* l1pa_cr_meas_process() */ +/*-------------------------------------------------------*/ +/* Description : This state machine handles periodic */ +/* signal strength monitoring on carriers specified */ +/* in a frequency list: BA(GPRS), NC_FREQUENCY_LIST, */ +/* EXT_FREEQUENCY_LIST (respectively: cell reselection */ +/* Network Control and Extended measurements. */ +/* */ +/* Starting messages: MPHP_CR_MEAS_REQ */ +/* ------------------ */ +/* L1 starts then the periodic FREQUENCY list receive */ +/* level monitoring. */ +/* */ +/* Subsequent messages: MPHP_CR_MEAS_REQ */ +/* -------------------- */ +/* The frequency list is updated only when measures */ +/* on all the carriers of the current list are */ +/* performed. */ +/* */ +/* Result messages (input): L1P_RXLEV_PERIODIC_DONE */ +/* ------------------------ */ +/* This is a message reported to L1A from L1S. */ +/* Reporting is done when last carrier of the frequency */ +/* list is read. */ +/* */ +/* Result messages (output): MPHP_CR_MEAS_IND */ +/* ------------------------- */ +/* This is the periodic reporting message to L3. */ +/* */ +/* Reset messages (input): MPHP_CR_MEAS_STOP_REQ */ +/* ----------------------- */ +/* Frequency list measurement process is stopped by */ +/* this message. */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_cr_meas_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_RESULT = 2 + + }; + + UWORD8 *state = &l1pa.state[CR_MEAS]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // step in state machine. + *state = WAIT_INIT; + + // Reset P_CRMS_MEAS process. + l1pa_l1ps_com.l1ps_en_meas &= P_CRMS_MEAS_MASK; // Reset Packet Cell Reselection Measurement enable flag. + } + break; + + case WAIT_INIT: + { + if(SignalCode == MPHP_CR_MEAS_REQ) + // We receive the Frequency list to be monitored. + //---------------------------------------------- + { + UWORD8 i; + T_CRES_LIST_PARAM *free_list; + + // Set parameter synchro semaphore for P_CRMS_MEAS task. + l1pa_l1ps_com.meas_param |= P_CRMS_MEAS; + + // Reset the frequency list structure. + l1pa_reset_cr_freq_list(); + + // Get Ptr to the free Neighbour meas list. + // The number of carriers in the list and the list + // identification are initialized. + free_list = l1pa_get_free_cres_list_set(); + + // Set number of carrier in the frequency list. + free_list->nb_carrier = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->nb_carrier; + + // Store ARFCN list in the Packet Cell Reselection structure. + for(i=0;inb_carrier;i++) + free_list->freq_list[i] = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i]; + + // Download Frequency list identifier. + free_list->list_id = ((T_MPHP_CR_MEAS_REQ *)(msg->SigP))->list_id; + + // Set "flist" with new set of frequency list parameter + l1pa_l1ps_com.cres_freq_list.flist = free_list; + + // Enable Packet Cell Reselection measurement task. + l1pa.l1pa_en_meas[CR_MEAS] |= P_CRMS_MEAS; + + // step in state machine. + *state = WAIT_RESULT; + } + + // End of process. + end_process = 1; + } + break; + + case WAIT_RESULT: + { + if(SignalCode == L1P_CR_MEAS_DONE) + // One set of measurement has been completed. + //--------------------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_CR_MEAS_IND, msg, GRRM1_QUEUE); + + // End of process. + end_process = 1; + } + + else + if((SignalCode == MPHP_CR_MEAS_STOP_REQ) || + (SignalCode == L1P_TRANSFER_DONE) || + (SignalCode == L1C_DEDIC_DONE)) + // Request to STOP this activity. + //------------------------------- + { + // send confirmation message + l1a_send_confirmation(MPHP_CR_MEAS_STOP_CON,GRRM1_QUEUE); + // This process must be reset. + *state = RESET; + } + + else + if (SignalCode == MPHP_CR_MEAS_REQ) + { + // This process must be reset. + *state = RESET; + } + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + end_process = 1; + } + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + +#if !((MOVE_IN_INTERNAL_RAM == 1) && (GSM_IDLE_RAM > 1)) // MOVE TO INTERNAL MEM IN CASE GSM_IDLE_RAM == 2 +//#pragma GSM_IDLE2_DUPLICATE_FOR_INTERNAL_RAM_START // KEEP IN EXTERNAL MEM otherwise + +/*-------------------------------------------------------*/ +/* l1pa_idle_paging_process() */ +/*-------------------------------------------------------*/ +/* */ +/*-------------------------------------------------------*/ +void l1pa_idle_paging_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_MSG = 2 + }; + + enum pg_mode + { + NORM_PG = 0, + EXT_PG = 1, + REORG_PG = 2 + }; + + UWORD8 *state = &l1pa.state[PI_SCP]; + UWORD32 SignalCode = msg->SignalCode; + UWORD16 imsimod; + UWORD16 split_pg_cycle; + UWORD16 kcn; + UWORD8 page_mode; + + BOOL end_process = 0; + + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_INIT; + + // Disable serving cell tasks. + l1a_l1s_com.l1s_en_task[PALLC] = TASK_DISABLED; // Reset PALLC (reorg) task enable flag. + l1a_l1s_com.l1s_en_task[PNP] = TASK_DISABLED; // Reset PNP task enable flag. + l1a_l1s_com.l1s_en_task[PEP] = TASK_DISABLED; // Reset PEP task enable flag. + + // No Paging => no gauging => no Deep sleep + l1s.pw_mgr.enough_gaug = FALSE; // forbid Deep sleep + + } + break; + + case WAIT_INIT: + { + if(SignalCode == MPHP_START_PCCCH_REQ) + { + // Set semaphores for any PCCCH reading tasks. + l1a_l1s_com.task_param[PALLC] = SEMAPHORE_SET; + l1a_l1s_com.task_param[PNP] = SEMAPHORE_SET; + l1a_l1s_com.task_param[PEP] = SEMAPHORE_SET; + + // Request to enter in PACKET PAGING REORGANIZATION or NORMAL mode. + //---------------------------------------------------------------- + // The initial page mode in the Mobile Station shall be set to paging Reorganization + // cf 04.08 section 3.3.2.1.1. however current implementation allows to init the Paging + // procedure either in Reorganization or in Normal paging mode. + + // Download the PAGING PARAMETERS from the command message. + page_mode = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->page_mode; + imsimod = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->imsimod; + kcn = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->kcn; + split_pg_cycle = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->split_pg_cycle; + l1pa_l1ps_com.pccch.bs_pag_blks_res = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->bs_pag_blks_res; + l1pa_l1ps_com.pccch.bs_pbcch_blks = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->bs_pbcch_blks; + l1pa_l1ps_com.pccch.frequency_list = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->frequency_list; + l1pa_l1ps_com.pccch.packet_chn_desc = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->packet_chn_desc; + l1a_l1s_com.Scell_info.pb = ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1 + + // Number of paging blocks "available" on one PCCCH = number of ppch blocks per MF52 * 64 + // = (12 - BS_PAG_BLKS_RES - BS_PBCCH_BLKS)*64 + l1pa_l1ps_com.pccch.nb_ppch_per_mf52 = (12 - l1pa_l1ps_com.pccch.bs_pag_blks_res - (l1pa_l1ps_com.pccch.bs_pbcch_blks + 1)); + + // Compute M. + l1pa_l1ps_com.pccch.pg_blks_avail = l1pa_l1ps_com.pccch.nb_ppch_per_mf52 * 64; + + // (IMSI mod 1000) div (KC*N) (Note: N = 1 for PCCCH) + l1pa_l1ps_com.pccch.pg_offset = imsimod / kcn; + + // First Paging Group value: PAGING_GROUP = ((IMSI mod 1000) div ((KC*N)*N)) (for m = 0) + l1pa_l1ps_com.pccch.first_pg_grp = (l1pa_l1ps_com.pccch.pg_offset % l1pa_l1ps_com.pccch.pg_blks_avail); + + // Split Paging computation = min (pg_blks_avail, SPLIT_PG_CYCLE) + l1pa_l1ps_com.pccch.split_pg_value = Min(l1pa_l1ps_com.pccch.pg_blks_avail, split_pg_cycle); + + // Paging Period computation + l1pa_l1ps_com.pccch.pnp_period = (64*52) / l1pa_l1ps_com.pccch.split_pg_value; + + // Rem: changing the paging parameters changes the place where "Periodic Packet + // Measurement" task must be executed. It implies to set semaphore for P_CRMS task. + l1pa_l1ps_com.meas_param |= P_CRMS_MEAS; + + // Layer 1 internal mode is set to IDLE MODE. + l1a_l1s_com.mode = I_MODE; + + // In order to keep tn_difference and dl_tn consistent, we need to avoid + // the execution of the SYNCHRO task with tn_difference updated and + // dl_tn not yet updated (this can occur if we go in the HISR just after + // the update of tn_difference). To do this the solution is to use the Semaphore + // associated to the SYNCHRO task. SYNCHRO task will be schedule only if its + // associated Semaphore is reset. + // Note: Due to the specificity of the SYNCHRO task which can be enabled + // by L1A state machines as by L1S processes, the semaphore can't followed + // the generic rules of the Semaphore shared between L1A and L1S. + // We must shift the mobile time setting to the timeslot provided by + // ((T_MPHP_START_PCCCH_REQ *)(msg->SigP))->packet_chn_desc.timeslot_no parameter. + // tn_difference -> loaded with the number of timeslot to shift. + // dl_tn -> loaded with the new timeslot. + l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_SET; + { + l1a_l1s_com.tn_difference += l1pa_l1ps_com.pccch.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.pccch.packet_chn_desc.timeslot_no; + + // Select GPRS DSP Scheduler. + l1a_l1s_com.dsp_scheduler_mode = GPRS_SCHEDULER; + + // Timing must be shifted to a new timeslot, enables SYNCHRO task.. + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + l1a_l1s_com.task_param[SYNCHRO] = SEMAPHORE_RESET; + // Note: The using of the semaphore associated to the SYNCHRO task can't be done + // as it is for the other semaphores. This is due to the specificity of the SYNCHRO + // task both touch by L1A and L1S. Here above the semaphore is set prior to touching + // the SYNCHRO parameters and reset after. In L1S this semaphore is checked. If it's + // seen SET then L1S will not execute SYNCHRO task nor modify its parameters. + + // Step in state machine. + *state = WAIT_MSG; + + if(page_mode == REORG_PG) + // Paging Reorganization mode... + { + // Enable Packet Paging Reorganisation tasks. + l1a_l1s_com.l1s_en_task[PALLC] = TASK_ENABLED; + l1a_l1s_com.l1s_en_task[PNP] = TASK_ENABLED; + + // End of process. + end_process = 1; + } + else + if(page_mode == NORM_PG) + // Normal Paging mode... + { + // Enable Packet Paging tasks in mode "NORMAL". + l1a_l1s_com.l1s_en_task[PNP] = TASK_ENABLED; + + // End of process. + end_process = 1; + } + else + // Extended Paging mode... + { + // Initialize Paging State for PAGING_GROUP computation (L1S part) + l1pa_l1ps_com.pccch.epg_computation = PPCH_POS_NOT_COMP; + + // Enable Packet Paging tasks in mode "EXTENDED". + l1a_l1s_com.l1s_en_task[PNP] = TASK_ENABLED; + l1a_l1s_com.l1s_en_task[PEP] = TASK_ENABLED; + + // End of process. + end_process = 1; + } + + } // end of test on SignalCode == MPHP_START_PCCCH_REQ + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + end_process = 1; + } + + } // end of case WAIT_INIT + break; + + case WAIT_MSG: + { + if((SignalCode == L1P_PNP_INFO) || + (SignalCode == L1P_PALLC_INFO) || + (SignalCode == L1P_PEP_INFO)) + // Paging Task results + { + // Forward result message to L3. + l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE); + + // End of process. + return; + } + + else + if(SignalCode == MPHP_START_PCCCH_REQ) + // New PCCCH configuration is provided. + //-------------------------------------------------------- + { + // Step in state machine + *state = RESET; + } + + else + if((SignalCode == MPHP_STOP_PCCCH_REQ) || + (SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1C_DEDIC_DONE)) + // Request to STOP any serving cell Packet Paging activity, OR + // Packet Transfer has just started. + // In both cases, PCCCH reading must be stopped. + //-------------------------------------------------------- + { + // Send confirmation message to L3. + l1a_send_confirmation(MPHP_STOP_PCCCH_CON,GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + } + + else + if((SignalCode == L1P_SINGLE_BLOCK_CON) || + (SignalCode == MPHP_SINGLE_BLOCK_CON)) + // If Two Phase Access is ongoing: Packet Resource Request + // msg has been sent to the network. PCCCH reading must be + // stopped to let PDCH reading going. + // REM: we must check both L1P/MPHP messages since an other + // process could have renamed L1P into MPHP. + //-------------------------------------------------------- + { + if(((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose == TWO_PHASE_ACCESS) + { + // This process must be reset. + *state = RESET; + } + else + { + // End of process. + return; + } + } + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + return; + } + + } // end of case WAIT_MSG + break; + } // end of switch + } // end of while +} // end of procedure + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END +#endif + +/*-------------------------------------------------------*/ +/* l1pa_idle_packet_polling_process() */ +/*-------------------------------------------------------*/ +/* Description : . */ +/* This state machine handles packet polling after */ +/* initiation of the packet acces procedure, when a */ +/* packet queuing notification is sent by the network */ +/* */ +/* Starting messages: MPHP_POLLING_RESPONSE_REQ */ +/* */ +/* Subsequent messages: */ +/* */ +/* Result messages (input): L1P_PRA_DONE */ +/* */ +/* Result messages (output): MPHP_POLLING_IND */ +/* */ +/* Reset message (input): */ +/* */ +/* Reset message (input): */ +/*-------------------------------------------------------*/ +void l1pa_idle_packet_polling_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_RESULT = 2 + }; + + UWORD8 *state = &l1pa.state[P_POLL]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_INIT; + + // Reset POLL process. + l1a_l1s_com.l1s_en_task[POLL] = TASK_DISABLED; // Clear RAACC task enable flag. + } + break; + + + case WAIT_INIT: + { + if(SignalCode == MPHP_POLLING_RESPONSE_REQ) + // Polling response request for access procedure. + //----------------------------------------------- + { + UWORD8 i; + + // Init POLL process. + l1pa_l1ps_com.poll_info.pol_resp_type = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->pol_resp_type; + l1pa_l1ps_com.poll_info.fn = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->fn; + + // TXPWR value supplied by L3 is the max. TX power level the MS may use in the given band + l1s.applied_txpwr = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->txpwr; + + // 1 RLC/MAC block is sent: + // This is a special case, only possible if the MS has a valid TA available from a pending + // assignment and is pooled for an RLC/MAC block. + if (l1pa_l1ps_com.poll_info.pol_resp_type == CS1_TYPE_POLL) + { + for (i=0; i<24; i++) + { + // download 24 bytes from message + l1pa_l1ps_com.poll_info.chan_req.cs1_data[i] = + ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[i]; + } + l1pa_l1ps_com.poll_info.timing_advance = ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->timing_advance; + + // Store MAX TXPWR value to be used for first POLL RESPONSE + // if not already done by Packet Access process... + for(i = 0; i < 8; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = l1s.applied_txpwr; + } + } + // 4 identical PRACH are sent + else + { + // UWORD16 = data[1]<<8 | data[0] + l1pa_l1ps_com.poll_info.chan_req.prach_data[0] = + ((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[0]; + l1pa_l1ps_com.poll_info.chan_req.prach_data[0] |= + (((T_MPHP_POLLING_RESPONSE_REQ *)(msg->SigP))->channel_request_data[1] << 8); + + l1pa_l1ps_com.poll_info.timing_advance = 0; + } + + // step in state machine. + *state = WAIT_RESULT; + + // Change mode to connection establishment part 1. + l1a_l1s_com.mode = CON_EST_MODE1; + + // Activate POLL task (no semaphore for UL tasks). + // Enable Paging Reorg and Normal paging tasks. + l1a_l1s_com.l1s_en_task[POLL] = TASK_ENABLED; // Set PRACH task enable flag. + } + + // end of process. + end_process = 1; + } + break; + + case WAIT_RESULT: + { + if(SignalCode == L1P_POLL_DONE) + // Random access acqnowledge message. + //----------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_POLLING_IND, msg, GRRM1_QUEUE); + + // Change mode to connection establishment part 2. + l1a_l1s_com.mode = CON_EST_MODE2; + + // This state machine has to be reset + *state = RESET; + + // end of process. + end_process = 1; + } + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + end_process = 1; + } + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + + +/*-------------------------------------------------------*/ +/* l1pa_transfer_process() */ +/*-------------------------------------------------------*/ +/* Description: */ +/* ------------ */ +/* */ +/* Starting messages: */ +/* ------------------ */ +/* */ +/* Subsequent messages: */ +/* -------------------- */ +/* */ +/* Result messages (input): */ +/* ------------------------ */ +/* */ +/* Result messages (output): */ +/* ------------------------- */ +/* */ +/* Reset messages (input): */ +/* ----------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_transfer_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_MSG = 1 + }; + + UWORD8 *state = &l1pa.state[TRANSFER]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_MSG; + + // Rise transfert parameter semaphore. + l1pa_l1ps_com.transfer.semaphore = TRUE; + } + break; + + case WAIT_MSG: + { + switch(SignalCode) + // switch on input message. + //------------------------- + { + case MPHP_SINGLE_BLOCK_REQ: + // Repeat fixed allocation. + //------------------------- + { + T_TRANSFER_SET *free_set; + UWORD8 purpose; + UWORD8 i; + + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + purpose = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->purpose; + + // Get Ptr to the free dedicated parameter set. + // All important fields are initialised. + free_set = l1pa_get_free_transfer_set(purpose); + + // Fill Transfer mode generic parameters. + free_set->assignment_id = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->assignment_id; + free_set->assignment_command = purpose; + free_set->allocated_tbf = purpose; + free_set->packet_ta = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->packet_ta; + + if((purpose == SINGLE_BLOCK_DL)||(purpose == SINGLE_BLOCK_UL)) + { + free_set->packet_ta.ta_index = 255; + free_set->packet_ta.ta_tn = 255; + } + + free_set->dl_pwr_ctl = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->dl_pwr_ctl; + if (free_set->dl_pwr_ctl.p0 != 255) + free_set->dl_pwr_ctl.p0 <<= 2; // P0 format 7.1 + free_set->tsc = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->tsc; + free_set->freq_param = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->freq_param; + free_set->tbf_sti = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->tbf_sti; + free_set->pc_meas_chan = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->pc_meas_chan; + + // Download access_burst_type + l1pa_l1ps_com.transfer.psi_param.access_burst_type = ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->access_burst_type; + // Keep the same Pb factor + l1pa_l1ps_com.transfer.psi_param.Scell_pb = l1a_l1s_com.Scell_info.pb; + // Enable PSI param updating in order to update access_burst_type in L1S + l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE; + + // Fill single block specific parameters. + for(i=0;i<23;i++) + { + l1pa_l1ps_com.transfer.single_block.data_array[i] = + ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->data_array[i]; + } + l1pa_l1ps_com.transfer.single_block.tn = + ((T_MPHP_SINGLE_BLOCK_REQ *)(msg->SigP))->timeslot_number; + + l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore = l1a_l1s_com.dl_tn; + + // Fill "synchro_timeslot" which will be the frame synchro slot. + free_set->ul_tbf_synchro_timeslot = l1pa_l1ps_com.transfer.single_block.tn; + free_set->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.single_block.tn; + + // Step in state machine. + *state = WAIT_MSG; + + // Store signalcode. + free_set->SignalCode = MPHP_SINGLE_BLOCK_REQ; + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case MPHP_ASSIGNMENT_REQ: + // Assignement message. + //--------------------- + { + static int count =0; + + T_TRANSFER_SET *free_set; + UWORD8 assignment_command; + UWORD8 timeslot_alloc; + UWORD8 timeslot; /* TCS211 reconstruction, =0 in TCS3 */ + + // TBF_changes + + #if FF_TBF + + BOOL pseudo_tbf_two_phase_acc; + + // Special case for two phase access (single or multi allocation): + // It is handled as a pseudo UL TBF using a fixed allocation. + // Still needs to be flagged to preempt TBF establishment switch in + // transfer manager. + if (((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command == TWO_PHASE_ACCESS) + { + ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command = UL_TBF; + pseudo_tbf_two_phase_acc = TRUE; + } + else + pseudo_tbf_two_phase_acc = FALSE; + #endif + count++ ; + + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + assignment_command = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_command; + + // Get Ptr to the free dedicated parameter set. + // All important fields are initialised. + free_set = l1pa_get_free_transfer_set(assignment_command); + + // Download message containt. + free_set->assignment_id = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->assignment_id; + free_set->assignment_command = assignment_command; + free_set->multislot_class = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->multislot_class; + free_set->dl_pwr_ctl = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_pwr_ctl; + if (free_set->dl_pwr_ctl.p0 != 255) + free_set->dl_pwr_ctl.p0 <<= 2; // P0 format 7.1 + free_set->packet_ta = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->packet_ta; + free_set->tsc = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->tsc; + free_set->freq_param = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->freq_param; + free_set->mac_mode = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->mac_mode; + free_set->tbf_sti = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->tbf_sti; + free_set->interf_meas_enable = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->interf_meas_enable; + free_set->pc_meas_chan = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->pc_meas_chan; + +// TBF_changes + + #if FF_TBF + // Two phase access condition is stored in FSET structure to be + // transfered in ASET for transfer mode manager use. + free_set->pseudo_tbf_two_phase_acc = pseudo_tbf_two_phase_acc; + #endif + + // Download access_burst_type + l1pa_l1ps_com.transfer.psi_param.access_burst_type = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->access_burst_type; + // Keep the same Pb factor + l1pa_l1ps_com.transfer.psi_param.Scell_pb = l1a_l1s_com.Scell_info.pb; + // Enable PSI param updating in order to update access_burst_type in L1S + l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE; + + switch(assignment_command) + { + case DL_TBF: + { + free_set->dl_tbf_alloc = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_ressource_alloc; + + if((free_set->allocated_tbf == UL_TBF) || + (free_set->allocated_tbf == BOTH_TBF)) + free_set->allocated_tbf = BOTH_TBF; + else + free_set->allocated_tbf = DL_TBF; + + // Look for 1st allocated timeslot. + // MSB=TS0...LSB=TS7 + timeslot_alloc = free_set->dl_tbf_alloc.timeslot_alloc; + timeslot = 0; + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + + // Fill "synchro_timeslot" which will be the frame synchro slot. + free_set->dl_tbf_synchro_timeslot = timeslot; + free_set->transfer_synchro_timeslot = timeslot; + } + break; + + case UL_TBF: + { + *(free_set->ul_tbf_alloc) = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->ul_ressource_alloc; + + if((free_set->allocated_tbf == DL_TBF) || + (free_set->allocated_tbf == BOTH_TBF)) + free_set->allocated_tbf = BOTH_TBF; + else + free_set->allocated_tbf = UL_TBF; + + // Look for 1st allocated timeslot. + // MSB=TS0...LSB=TS7 + + // Dynamic mode: the uplink PDCH are always monitored + // The 1st allocated timeslot is a RX on the lowest numbered + // timeslot allocated in uplink + #if L1_EDA + if((free_set->mac_mode == DYN_ALLOC) || (free_set->mac_mode == EXT_DYN_ALLOC)) + #else + if(free_set->mac_mode == DYN_ALLOC) + #endif + { + timeslot_alloc = free_set->ul_tbf_alloc->timeslot_alloc; + + timeslot = 0; + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + } + else + + // Fixed mode: the 1st allocated timeslot is the downlink control + // timeslot allocated by the network, which is a timeslot allocated + // in uplink + if(free_set->mac_mode == FIX_ALLOC_NO_HALF) + { + timeslot = free_set->ul_tbf_alloc->fixed_alloc.ctrl_timeslot; + } + + // Fill "synchro_timeslot" which will be the frame synchro slot. + free_set->ul_tbf_synchro_timeslot = timeslot; + free_set->transfer_synchro_timeslot = timeslot; + } + break; + + case BOTH_TBF: + { + free_set->dl_tbf_alloc = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->dl_ressource_alloc; + *(free_set->ul_tbf_alloc) = ((T_MPHP_ASSIGNMENT_REQ *)(msg->SigP))->ul_ressource_alloc; + free_set->allocated_tbf = BOTH_TBF; + + // Process the downlink TBF first allocated timeslot + timeslot_alloc = free_set->dl_tbf_alloc.timeslot_alloc; + timeslot = 0; + + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + + free_set->dl_tbf_synchro_timeslot = timeslot; + + // Process the uplink TBF first allocated timeslot + + // Dynamic mode: the uplink PDCH are always monitored + // The 1st allocated timeslot is a RX on the lowest numbered + // timeslot allocated in uplink + #if L1_EDA + if((free_set->mac_mode == DYN_ALLOC) || (free_set->mac_mode == EXT_DYN_ALLOC)) + #else + if(free_set->mac_mode == DYN_ALLOC) + #endif + { + timeslot_alloc = free_set->ul_tbf_alloc->timeslot_alloc; + + timeslot = 0; + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + } + else + + // Fixed mode: the 1st allocated timeslot is the downlink control + // timeslot allocated by the network, which is a timeslot allocated + // in uplink + if(free_set->mac_mode == FIX_ALLOC_NO_HALF) + { + timeslot = free_set->ul_tbf_alloc->fixed_alloc.ctrl_timeslot; + } + + free_set->ul_tbf_synchro_timeslot = timeslot; + + // Fill "synchro_timeslot" which will be the frame synchro slot. + if (free_set->dl_tbf_synchro_timeslot > free_set->ul_tbf_synchro_timeslot) + { + free_set->transfer_synchro_timeslot = free_set->ul_tbf_synchro_timeslot; + } + else + { + free_set->transfer_synchro_timeslot = free_set->dl_tbf_synchro_timeslot; + } + + } + break; + } + + // Cancel any pending release on the assigned TBF + if (l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd == TRUE) + { + // If pending released TBF = assigned TBF or assigned TBF = BOTH + if ((assignment_command == l1pa_l1ps_com.transfer.tbf_release_param.released_tbf) || + (assignment_command == BOTH_TBF)) + { + /* + * FreeCalypso TCS211 reconstruction: in the LoCosto version + * the call to l1pa_send_tbl_release_con() came first, + * but in the TCS211 object it comes after the two + * assignments. + */ + + // Cancel the TBF release order + l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = FALSE; + l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = NO_TBF; + + // Send a "TBF Release confirmation" msg to L3 : CQ 46842 + l1pa_send_tbf_release_con(MPHP_TBF_RELEASE_CON,l1pa_l1ps_com.transfer.tbf_release_param.released_tbf); + } + // If BOTH TBF release order pending and no BOTH TBF assigned + else if (l1pa_l1ps_com.transfer.tbf_release_param.released_tbf == BOTH_TBF) + { + // Keep the release of the TBF which is not assigned by this message + if (assignment_command == DL_TBF) + l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = UL_TBF; + else + l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = DL_TBF; + } + } + + // Step in state machine. + *state = WAIT_MSG; + + // Store signalcode. + free_set->SignalCode = MPHP_ASSIGNMENT_REQ; + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case L1P_TRANSFER_DONE: + // Switch to TRANSFER mode has been done. Send a Assignment confirmation + // msg to L3. + { + l1pa_send_confirmation(MPHP_ASSIGNMENT_CON, + ((T_L1P_TRANSFER_DONE *) msg->SigP)->assignment_id); + + // End of process. + end_process = 1; + } + break; + + case MPHP_TBF_RELEASE_REQ: + // TBF Release. + //------------- + { + UWORD8 i; + + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // Cumulate with a possible TBF release request received during the same block period + if (l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd == TRUE) + { + if (l1pa_l1ps_com.transfer.tbf_release_param.released_tbf != ((T_MPHP_TBF_RELEASE_REQ *)(msg->SigP))->tbf_type) + { + l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = BOTH_TBF; + } + } + else + { + // Enables the TBF release processing in L1S. + l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = TRUE; + + // Download msg info into L1PA_L1PS_COM. + l1pa_l1ps_com.transfer.tbf_release_param.released_tbf = ((T_MPHP_TBF_RELEASE_REQ *)(msg->SigP))->tbf_type; + } + + // Disable all pending TBFs those type is the same as the released TBF + for(i = 0; i < 2; i++) + { + // Pending assignment + if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_ASSIGNMENT_REQ) + { + #if !FF_TBF + switch(l1pa_l1ps_com.transfer.tbf_release_param.released_tbf) + #else + UWORD8 released_tbf; + + // Special case if we got a request to release a two phase access TBF: + // It is registered within FSET structure as an uplink TBF. If current + // structure is pseudo TBF for two phase access, we process the request + // like an uplink release, otherwise we skip it. + + released_tbf = l1pa_l1ps_com.transfer.tbf_release_param.released_tbf; + + if (released_tbf == TWO_PHASE_ACCESS) + { + if (l1pa_l1ps_com.transfer.fset[i]->pseudo_tbf_two_phase_acc) + released_tbf = UL_TBF; + else + released_tbf = NO_TBF; + } + + switch(released_tbf) + #endif // FF_TBF + { + case UL_TBF: + { + if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == UL_TBF) + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } + if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == BOTH_TBF) + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = DL_TBF; + } + } break; + + case DL_TBF: + { + if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == DL_TBF) + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } + if (l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == BOTH_TBF) + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = UL_TBF; + } + } break; + + case BOTH_TBF: + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } break; + + } // End of switch "tbf_release" + } // End if SignalCode = MPHP_ASSIGNMENT_REQ or MPHP_REPEAT_UL_FIXED_ALLOC + } // End "for" + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case L1P_TBF_RELEASED: + // TBF has been release by L1S. Send a "TBF Release confirmation" + // msg to L3 + { + // Send confirmation message to L3. + l1pa_send_tbf_release_con(MPHP_TBF_RELEASE_CON,((T_L1P_TBF_RELEASED *)(msg->SigP))->tbf_type); + + // End of process. + end_process = 1; + } + break; + + case MPHP_STOP_SINGLE_BLOCK_REQ: + // Stop SINGLE block activity. + //---------------------------- + { + UWORD8 i; + + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // Disable SINGLE task. + l1a_l1s_com.l1s_en_task[SINGLE] = TASK_DISABLED; + + // No more TBF... + // Disable PDTCH task. + l1a_l1s_com.l1s_en_task[PDTCH] = TASK_DISABLED; + + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + // Free the active set. + l1pa_l1ps_com.transfer.aset->allocated_tbf = NO_TBF; + + // Send confirmation message to L3. + l1a_send_confirmation(MPHP_STOP_SINGLE_BLOCK_CON,GRRM1_QUEUE); + + // disable all pending TBF those type is a single block + for(i = 0; i < 2; i++) + { + // check for pending single block req (MPHP_SINGLE_BLOCK_REQ) + if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_SINGLE_BLOCK_REQ) + { + // disable the fset corresponding to single blocks + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } + } + + // This process must be reset. + *state = RESET; + + // end of process. + end_process = 1; + } + break; + + case MPHP_PDCH_RELEASE_REQ: + // PDCH Release. + //-------------- + { + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // Enables the PDCH release processing in L1S. + l1pa_l1ps_com.transfer.pdch_release_param.pdch_release_cmd = TRUE; + + // Download msg info into L1PA_L1PS_COM. + l1pa_l1ps_com.transfer.pdch_release_param.timeslot_available = ((T_MPHP_PDCH_RELEASE_REQ *)(msg->SigP))->timeslot_available; + l1pa_l1ps_com.transfer.pdch_release_param.assignment_id = ((T_MPHP_PDCH_RELEASE_REQ *)(msg->SigP))->assignment_id; + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case L1P_PDCH_RELEASED: + // PDCHs have been release by L1S. Send a "PDCH Release confirmation" + // msg to L3 + { + // Send confirmation message to L3. + l1pa_send_confirmation(MPHP_PDCH_RELEASE_CON, + ((T_L1P_PDCH_RELEASE_CON *) msg->SigP)->assignment_id); + + // End of process. + end_process = 1; + } + break; + + case MPHP_TIMING_ADVANCE_REQ: + // TA configuration. + //------------------ + { + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // Enables the timing advance update in L1S. + l1pa_l1ps_com.transfer.ptcch.ta_update_cmd = TRUE; + + // Download message content. + l1pa_l1ps_com.transfer.ptcch.packet_ta = ((T_MPHP_TIMING_ADVANCE_REQ *)(msg->SigP))->packet_ta; + l1pa_l1ps_com.transfer.ptcch.assignment_id = ((T_MPHP_TIMING_ADVANCE_REQ *)(msg->SigP))->assignment_id; + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case L1P_TA_CONFIG_DONE: + // TA configuration done. + //----------------------- + { + // Send confirmation message to L3. + l1pa_send_confirmation(MPHP_TIMING_ADVANCE_CON, + ((T_MPHP_TIMING_ADVANCE_CON *) msg->SigP)->assignment_id); + + // end of process. + end_process = 1; + } + break; + + case MPHP_UPDATE_PSI_PARAM_REQ: + // Update PSI Parameters. + //---------------------- + { + // Download msg content + l1pa_l1ps_com.transfer.psi_param.Scell_pb = ((T_MPHP_UPDATE_PSI_PARAM_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1 + l1pa_l1ps_com.transfer.psi_param.access_burst_type = ((T_MPHP_UPDATE_PSI_PARAM_REQ *)(msg->SigP))->access_burst_type; + + l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = TRUE; + + // send confirmation message + l1a_send_confirmation(MPHP_UPDATE_PSI_PARAM_CON,GRRM1_QUEUE); + + // end of process. + end_process = 1; + } + break; + + case L1P_PACCH_INFO: + // Two Phase Access is ongoing: Packet Resource Request + // msg has been sent to the network. CCCH reading must be + // stopped to let PDCH reading going. + //-------------------------------------------------------- + { + // Forward result message to RR. + l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE); + + // end of process. + end_process = 1; + } + break; + + case L1P_SINGLE_BLOCK_CON: + // Two Phase Access is ongoing: Packet Resource Request + // msg has been sent to the network. CCCH reading must be + // stopped to let PDCH reading going. + //-------------------------------------------------------- + { + // Forward result message to RR. + l1a_send_result(MPHP_SINGLE_BLOCK_CON, msg, GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + + // end of process. + end_process = 1; + } + break; + + case MPHP_REPEAT_UL_FIXED_ALLOC_REQ: + // Repeat uplink fixed mode allocation bitmap + //------------------------------------------- + { + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // If an UL TBF is running... + if ((l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) || + (l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF)) + { + // Download info. from message + l1pa_l1ps_com.transfer.repeat_alloc = *((T_MPHP_REPEAT_UL_FIXED_ALLOC_REQ *) msg->SigP); + } + + // Send confirmation if this message was a repeat allocation cancelling + if (!((T_MPHP_REPEAT_UL_FIXED_ALLOC_REQ *) msg->SigP)->repeat_allocation) + { + l1a_send_confirmation(MPHP_REPEAT_UL_FIXED_ALLOC_CON,GRRM1_QUEUE); + } + else + { + UWORD8 i; + + // Disable all pending UL TBF + for(i = 0; i < 2; i++) + { + // Pending assignment + if (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_ASSIGNMENT_REQ) + { + switch(l1pa_l1ps_com.transfer.fset[i]->allocated_tbf) + { + // Remove pending UL TBF + case UL_TBF: + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } + break; + + // Change pending BOTH_TBF in pending DL_TBF + case BOTH_TBF: + { + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = DL_TBF; + } + break; + + } // End of switch "allocated_tbf" + } // End if SignalCode = MPHP_ASSIGNMENT_REQ + } // End "for" + } + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // end of process. + end_process = 1; + } + break; + + case L1P_REPEAT_ALLOC_DONE: + { + // Send confirmation message to L3. + l1a_send_confirmation(MPHP_REPEAT_UL_FIXED_ALLOC_CON,GRRM1_QUEUE); + + // end of process. + end_process = 1; + } + break; + + default: + // End of process. + //---------------- + { + return; + } + } // end of switch(SignalCode) + } // end of case WAIT_CONFIG. + } // end of "switch". + } // end of "while" +} // end of procedure. + +/*-------------------------------------------------------*/ +/* l1pa_serving_cell_pbcch_read_process() */ +/*-------------------------------------------------------*/ +/* Description : This state machine handles Packet */ +/* serving cell PBCCH reading. */ +/* */ +/* Starting messages: MPHP_SCELL_PBCCH_REQ */ +/* ------------------ */ +/* */ +/* L1 continuously reads the serving cell PBCCH */ +/* as requested by the scheduling info (PSI1 repeat */ +/* period and relative position. */ +/* */ +/* Result messages (input): L1C_PBCCHS_INFO */ +/* ------------------------ */ +/* System information data block from L1S. */ +/* */ +/* Reset messages (input): MPHP_SCELL_PBCCH_STOP_REQ */ +/* ----------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_serving_cell_pbcch_read_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_PBCCHS_CONFIG = 1, + WAIT_PBCCHS_RESULT = 2, + PBCCHS_CONFIG = 3 + }; + + UWORD8 *state = &l1pa.state[SCPB]; + UWORD32 SignalCode = msg->SignalCode; + + #define PbcchS l1pa_l1ps_com.pbcchs + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_PBCCHS_CONFIG; + + // Reset PBCCHS process. + l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_DISABLED; // Clear PBCCHS task enable flag. + } + break; + + case WAIT_PBCCHS_CONFIG: + { + // Request to read Normal BCCH from serving cell. + if(SignalCode == MPHP_SCELL_PBCCH_REQ) + { + #define MAX_PSI1_PERIOD 16 + + UWORD8 i; + + // Set semaphores for Serving Cell PBCCH reading task. + l1a_l1s_com.task_param[PBCCHS] = SEMAPHORE_SET; + + // Download message content. + //-------------------------- + PbcchS.nbr_psi = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->nbr_psi; + PbcchS.bs_pbcch_blks = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->bs_pbcch_blks; + PbcchS.packet_chn_desc = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->packet_chn_desc; + PbcchS.frequency_list = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->frequency_list; + l1a_l1s_com.Scell_info.pb = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1 + PbcchS.psi1_repeat_period = ((T_MPHP_SCELL_PBCCH_REQ *)(msg->SigP))->psi1_repeat_period; + + // PBCCH Period is: MF52 * psi1_repeat_period + PbcchS.pbcch_period = 52L * PbcchS.psi1_repeat_period; + + if(PbcchS.nbr_psi == 0) + // Full PBCCH reading: Emulated throw "relative positions". + //--------------------------------------------------------- + { + // Emulate full PBCCH reading throw "relative positions" and a repeat period + // of 1 MF52. + // bs_pbcch_blks= 0 -> Read B0 + // bs_pbcch_blks= 1 -> Read B0,B6 + // bs_pbcch_blks= 2 -> Read B0,B6,B3 + // bs_pbcch_blks= 3 -> Read B0,B6,B3,B9 + + PbcchS.nbr_psi = PbcchS.bs_pbcch_blks+1; + PbcchS.read_all_psi = TRUE; + + for(i=0;iSigP))->relative_position_array[i] = i; + } + } + + else + // PBCCH reading: use provided "relative positions". + //-------------------------------------------------- + { + PbcchS.read_all_psi = FALSE; + } + + // Compute FN offset for each PSI. + //-------------------------------- + for(i=0;iSigP))->relative_position_array[i]; + + nbr_mf52 = relative_position / (PbcchS.bs_pbcch_blks+1); + nbr_rest = relative_position % (PbcchS.bs_pbcch_blks+1); + + // Block B0 is a special case since CTRL phase occurs during + // the MF52 before. + if(nbr_rest == 0) + { + nbr_mf52 -= 1; + + // Set psi_period to 1 when all PSI have to be read (nbr_psi = 0) + if(PbcchS.read_all_psi) + psi_period = 1; + else + psi_period = PbcchS.psi1_repeat_period; + + if(nbr_mf52 < 0) + nbr_mf52 += psi_period; + } + + PbcchS.offset_array[i] = (nbr_mf52 * 52L) + PBCCH_POSITION[PbcchS.bs_pbcch_blks][nbr_rest]; + PbcchS.relative_position_array[i] = relative_position; + } + + // Step in state machine. + *state = PBCCHS_CONFIG; + } + + // No action in this machine for other messages. + else + { + // End of process. + return; + } + } + break; + + case PBCCHS_CONFIG: + { + WORD8 tn_pbcch; + + // If PBCCH TS is inferior to L1 synchronization TS, the PBCCH reading + // control must be done one frame in advance + if (PbcchS.packet_chn_desc.timeslot_no < l1a_l1s_com.dl_tn) + PbcchS.control_offset = TRUE; + else + PbcchS.control_offset = FALSE; + + // Set "change_synchro" flag to trigger L1S to change the synchro on fly + // within PBCCHS and to restore current synchro when PBCCHS task is completed. + if(((PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn + 8) % 8) >=4) + { + // L1S will make a intra PBCCHS task synchro to current TS + 4. + PbcchS.change_synchro = TRUE; + tn_pbcch = PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn - 4; + } + else + { + // L1S will NOT make the intra PBCCHS task synchro. + PbcchS.change_synchro = FALSE; + tn_pbcch = PbcchS.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn; + } + + if(tn_pbcch < 0) + PbcchS.tn_pbcch = tn_pbcch + 8; + else + PbcchS.tn_pbcch = tn_pbcch; + + // Enable PBCCHS task. + l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_ENABLED; + + + // Step in state machine. + *state = WAIT_PBCCHS_RESULT; + + // End of process. + end_process = 1; + } + break; + + case WAIT_PBCCHS_RESULT: + { + if(SignalCode == L1P_PBCCHS_INFO) + // Serving cell BCCH reading result. + //---------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_DATA_IND, msg, GRRM1_QUEUE); + + // End of process. + return; + } + + else + if(SignalCode == MPHP_SCELL_PBCCH_REQ) + // Request to re-configure PBCCH reading. + //-------------------------------------- + { + // Step in state machine. + *state = WAIT_PBCCHS_CONFIG; + } + + else + if(SignalCode == MPHP_SCELL_PBCCH_STOP_REQ) + // Request to STOP any serving cell pbcch activity. + //------------------------------------------------ + { + // Send confirmation message to L3. + l1a_send_confirmation(MPHP_SCELL_PBCCH_STOP_CON,GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + } + + else + // End of packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released + if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)) + { + // This process must be reset. + *state = RESET; + } + + else + if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_TBF_RELEASED) || //change of Time Slot + (SignalCode == L1P_REPEAT_ALLOC_DONE) || (SignalCode == L1P_ALLOC_EXHAUST_DONE)) + { + // Clear PBCCHS task enable flag. + l1a_l1s_com.l1s_en_task[PBCCHS] = TASK_DISABLED; + + // Set semaphores for Serving Cell PBCCH reading task. + l1a_l1s_com.task_param[PBCCHS] = SEMAPHORE_SET; + + // l1a_l1s_com.dl_tn was changed. Check if a change synchro is needed + *state = PBCCHS_CONFIG; // Step in state machine. + } + + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + return; + } + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + + +/*-------------------------------------------------------*/ +/* l1pa_neighbor_cell_pbcch_read_process() */ +/*-------------------------------------------------------*/ +/* Description : This state machine handles Packet */ +/* neighbor cell PBCCH reading. */ +/* */ +/* Starting messages: MPHP_NCELL_PBCCH_REQ */ +/* ------------------ */ +/* */ +/* L1 continuously reads the neighbor cell PBCCH */ +/* as requested by the scheduling info (PSI1 repeat */ +/* period and relative position. */ +/* */ +/* Result messages (input): L1C_PBCCHN_INFO */ +/* ------------------------ */ +/* System information data block from L1S. */ +/* */ +/* Reset messages (input): MPHP_NCELL_PBCCH_STOP_REQ */ +/* ----------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_neighbor_cell_pbcch_read_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_PBCCHN_CONFIG = 1, + WAIT_PBCCHN_RESULT = 2, + PBCCHN_CONFIG = 3 + }; + + UWORD8 *state = &l1pa.state[NCPB]; + UWORD32 SignalCode = msg->SignalCode; + + #define PbcchN l1pa_l1ps_com.pbcchn + + static WORD32 fn_offset_mem; + static WORD32 time_alignmt_mem; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_PBCCHN_CONFIG; + + // Reset PBCCHS process. + l1a_l1s_com.l1s_en_task[PBCCHN_IDLE] = TASK_DISABLED; // Clear PBCCHN task enable flag used in IDLE mode + l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_DISABLED; // Clear PBCCHN task enable flag used in Transfer Packet mode + } + break; + + case WAIT_PBCCHN_CONFIG: + { + // Request to read Normal PBCCH from neighbor cell. + if(SignalCode == MPHP_NCELL_PBCCH_REQ) + { + #define MAX_PSI1_PERIOD 16 + + // Set semaphores for Neighbor Cell PBCCH reading task. + l1a_l1s_com.task_param[PBCCHN_IDLE] = SEMAPHORE_SET; + l1a_l1s_com.task_param[PBCCHN_TRAN] = SEMAPHORE_SET; + + // Download message content. + //-------------------------- + PbcchN.bcch_carrier = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->bcch_carrier; + PbcchN.bs_pbcch_blks = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->bs_pbcch_blks; + PbcchN.packet_chn_desc = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->packet_chn_desc; + PbcchN.frequency_list = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->frequency_list; + PbcchN.psi1_repeat_period = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->psi1_repeat_period; + PbcchN.relative_position = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->relative_position; + fn_offset_mem = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->fn_offset; + time_alignmt_mem = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->time_alignment; + PbcchN.pb = ((T_MPHP_NCELL_PBCCH_REQ *)(msg->SigP))->pb << 2; // Pb format 7.1 + + // PBCCH Period is: MF52 * psi1_repeat_period + PbcchN.pbcch_period = 52L * PbcchN.psi1_repeat_period; + + // Compute FN offset. + //------------------ + { + WORD8 nbr_mf52; // Range 0..MAX_PSI1_PERIOD (can be negative along its estimation) + UWORD8 nbr_rest; // Range 0..3 + UWORD8 relative_position; // Range 0..4*MAX_PSI1_PERIOD + + relative_position = PbcchN.relative_position; + + // number of PBCCH blocs + nbr_mf52 = relative_position / (PbcchN.bs_pbcch_blks+1); + nbr_rest = relative_position % (PbcchN.bs_pbcch_blks+1); + + // Block B0 is a special case since CTRL phase occurs during the MF52 before. + if(nbr_rest == 0) + { + nbr_mf52 -= 1; + + if(nbr_mf52 < 0) + nbr_mf52 += PbcchN.psi1_repeat_period; + } + + PbcchN.offset = (nbr_mf52 * 52L) + PBCCH_POSITION[PbcchN.bs_pbcch_blks][nbr_rest]; + + // In case of idle mode + if (l1a_l1s_com.mode != PACKET_TRANSFER_MODE) + { + PbcchN.offset -= 2 ; // because of the 2 frames for the measurement windows + // note: PbcchN.offset can not be negative (PbcchN.offset > 12). + } + } + // Step in state machine. + *state = PBCCHN_CONFIG; + } + + // No action in this machine for other messages. + else + { + // End of process. + return; + } + } + break; + + case PBCCHN_CONFIG: + { + //================================================================================== + // choose a relative base time in the neighbor cell in order to simplify the L1S scheduling. + //================================================================================== + PbcchN.fn_offset = fn_offset_mem; + PbcchN.time_alignmt = time_alignmt_mem; + + //the new relative base time is set in order to have the Neighbor burst in position 0. + //update with the burts position of the neighor cell : PbcchN.packet_chn_desc.timeslot_no + //update according to the current serving cell synchro : l1a_l1s_com.dl_tn + PbcchN.time_alignmt += (PbcchN.packet_chn_desc.timeslot_no - l1a_l1s_com.dl_tn ) * TN_WIDTH; + + // PbcchN.time_alignmt is in [-7TS..+16TS[. + // more than 1 frame between the serving cell and the neighbor burst + if ( PbcchN.time_alignmt >= 8*TN_WIDTH) + { + PbcchN.time_alignmt -= 8*TN_WIDTH; + PbcchN.fn_offset --; + } + else + if ( PbcchN.time_alignmt < 0) + { + PbcchN.time_alignmt += 8*TN_WIDTH; + PbcchN.fn_offset ++; + } + + // Set "change_synchro" flag to trigger L1S to change the synchro on fly + // within PBCCHN and to restore current synchro when PBCCHN task is completed. + if (PbcchN.time_alignmt >= 4 * TN_WIDTH) + { + PbcchN.time_alignmt -= 4 * TN_WIDTH; + PbcchN.change_synchro = TRUE; + } + else + PbcchN.change_synchro = FALSE; + + // In case of packet transfer mode + if (l1a_l1s_com.mode == PACKET_TRANSFER_MODE) + { + // Enable Packet Transfer PBCCHN task + l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_ENABLED; + + } + // in case of Idle mode + else + { + // Enable IDLE PBCCHN task + l1a_l1s_com.l1s_en_task[PBCCHN_IDLE] = TASK_ENABLED; + } + + // Step in state machine. + *state = WAIT_PBCCHN_RESULT; + + // End of process. + end_process = 1; + } + break; + + case WAIT_PBCCHN_RESULT: + { + if(SignalCode == L1P_PBCCHN_INFO) + // Serving cell BCCH reading result. + //---------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_NCELL_PBCCH_IND, msg, GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + } + + else + if(SignalCode == MPHP_NCELL_PBCCH_REQ) + // Request to re-configure PBCCH reading. + //-------------------------------------- + { + // Step in state machine. + *state = WAIT_PBCCHN_CONFIG; + } + + else + if(SignalCode == MPHP_NCELL_PBCCH_STOP_REQ) + // Request to STOP any serving cell pbcch activity. + //------------------------------------------------ + { + // Send confirmation message to L3. + l1a_send_confirmation(MPHP_NCELL_PBCCH_STOP_CON,GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + } + else + // End of packet transfer mode: test PDTCH to be sure that TBF downlink and uplink are released + if((SignalCode == L1P_TBF_RELEASED) && (((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all)) + { + // This process must be reset. + *state = RESET; + } + else + if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_TBF_RELEASED) || //change of Time Slot + (SignalCode == L1P_REPEAT_ALLOC_DONE) || (SignalCode == L1P_ALLOC_EXHAUST_DONE)) + { + // We consider only the case: packet Transfer => packet Transfer,the serving TS may be changed + // For other cases such as Idle -> Transfer... decision not yet taken. + + // update the PBCCHN parameters + // Clear PBCCHN_TRAN task disable flag. + l1a_l1s_com.l1s_en_task[PBCCHN_TRAN] = TASK_DISABLED; + + // Set semaphores for Neighbor Cell PBCCH reading task. + l1a_l1s_com.task_param[PBCCHN_TRAN] = SEMAPHORE_SET; + + // update the PBCCHN parameters + *state = PBCCHN_CONFIG;// Step in state machine. + } + else + // No action in this machine for other messages. + //---------------------------------------------- + { + // End of process. + return; + } + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + + + +/*-------------------------------------------------------*/ +/* l1pa_tcr_meas_process() */ +/*-------------------------------------------------------*/ +/* Description : This state machine handles Neigbor cell */ +/* measurement process in Packet Transfer mode. */ +/* Measurement are made on a specified frequency list. */ +/* The process is started automatically by L1 (on receipt*/ +/* of a L1P_TRANSFER_DONE message from L1S) and doesn't */ +/* need to receive any message from L3. */ +/* In order to update the frequency list, a */ +/* MHPC_TCR_MEAS_REQ msg will be sent from L3 to L1 */ +/* */ +/* Starting messages: L1P_TRANSFER_DONE */ +/* ------------------ */ +/* L1 starts then measures on carriers specified in the */ +/* frequency list. Measures are performed on every */ +/* frames with the occurence of 1 measure per frame */ +/* */ +/* Subsequent messages: MPHP_TCR_MEAS_REQ */ +/* -------------------- */ +/* The update is not done asap but postponed until the */ +/* end of the reporting period. Frequency list is */ +/* updated with the new list. */ +/* */ +/* Result messages (input): L1P_TRANSFER_MEAS_DONE */ +/* ------------------------ */ +/* This is the periodic reporting message sent by L1S. */ +/* The reporting is done every "reporting period". */ +/* The beguining of the reporting period is arbitrary */ +/* and starts when the Neigh Meas task is enabled. */ +/* */ +/* Result messages (output): MPHP_TCR_MEAS_IND */ +/* ------------------------- */ +/* This is the periodic reporting message to L3. */ +/* */ +/* Reset messages (input): MPHP_TCR_MEAS_STOP_REQ */ +/* ----------------------- */ +/* Frequency list neigbor cell measurement process in */ +/* Packet Transfer mode is stopped by this message. */ +/* */ +/*-------------------------------------------------------*/ +void l1pa_tcr_meas_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_RESULT = 3 + + }; + + UWORD8 *state = &l1pa.state[TCR_MEAS]; + UWORD32 SignalCode = msg->SignalCode; + UWORD8 i; + UWORD8 list_size; + T_CRES_LIST_PARAM *free_list; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // step in state machine. + *state = WAIT_INIT; + + // Reset TCR_MEAS process. + l1pa_l1ps_com.l1ps_en_meas &= P_TCRMS_MEAS_MASK; // Disable Neighbour Measurement task. + } + break; + + case WAIT_INIT: + { + if(SignalCode == L1P_TRANSFER_DONE) + // We enter in Packet Transfer mode. + //--------------------------------- + { +#if 0 /* FreeCalypso: the following code is not present in TCS211 */ + #if (CODE_VERSION != SIMULATION) + //no meas when entering in Transfer if no BA list initialized + //stay in this state and wait for a MPHP_TCR_MEAS_REQ from L3 + if((l1pa_l1ps_com.cres_freq_list.alist->nb_carrier == 0) && + (l1pa_l1ps_com.tcr_freq_list.new_list_present == FALSE) && (l1a_l1s_com.ba_list.nbr_carrier == 0)) + return; + #endif +#endif + // Set parameter synchro semaphore for P_TCRMS_MEAS task. + l1pa_l1ps_com.meas_param |= P_TCRMS_MEAS; + + // Reset Neighbour Cell measurement parameters. + l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl = 0; + l1pa_l1ps_com.tcr_freq_list.tcr_next_to_read = 0; + l1pa_l1ps_com.tcr_freq_list.last_stored_tcr_to_read = 0; + l1pa_l1ps_com.tcr_freq_list.first_pass_flag = TRUE; + + // Initialize counter used to report measurements + l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0; + + + // If no Packet Idle phase has been done and no BA(GPRS) list has been + // downloaded, init BA(GPRS) list with BA list used in CS Idle mode. + if((l1pa_l1ps_com.cres_freq_list.alist->nb_carrier == 0) && + (l1pa_l1ps_com.tcr_freq_list.new_list_present == FALSE)) + { + // Get Ptr to the free Neighbour meas list. + // The number of carriers in the list and the list + // identification are initialized. + free_list = l1pa_get_free_cres_list_set(); + + // Download new list within T_CRES_LIST_PARAM structure. + free_list->nb_carrier = l1a_l1s_com.ba_list.nbr_carrier; + + for(i = 0; i < free_list->nb_carrier; i++) + { + free_list->freq_list[i] = l1a_l1s_com.ba_list.A[i].radio_freq; + } + + free_list->list_id = l1a_l1s_com.ba_list.ba_id; + + // Set "flist" with Circuit Swithed BA frequency list parameters + l1pa_l1ps_com.cres_freq_list.alist = free_list; + } + + // Reset flags. + l1pa_l1ps_com.tcr_freq_list.ms_ctrl = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd = 0; + + // Reset measures made on beacon frequency. + l1pa_l1ps_com.tcr_freq_list.beacon_meas = 0; + + // Enable Packet Transfer Neighbour Measurement task. + l1pa.l1pa_en_meas[TCR_MEAS] |= P_TCRMS_MEAS; + + // step in state machine. + *state = WAIT_RESULT; + } + else + if(SignalCode == MPHC_RXLEV_PERIODIC_REQ) + // We receive the BA list to be monitored in Idle mode + //---------------------------------------------------- + { + // When enter in Transfer the Idle list must be used + // =>reset the packet Transfert list in order to use the Idle list + l1pa_l1ps_com.cres_freq_list.alist->nb_carrier = 0; + l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE; + } +#if 0 /* FreeCalypso: the following code is not present in TCS211 */ + else + if(SignalCode == MPHP_TCR_MEAS_REQ) + // Restart Packet Transfer measurement in TBF after + // MPHP_TCR_MEAS_STOP_REQ + // ### Check reason why was missing (s921_bis note)... + //---------------------------------------------------- + { + + // Set parameter synchro semaphore for P_TCRMS_MEAS task. + l1pa_l1ps_com.meas_param |= P_TCRMS_MEAS; + + free_list = l1pa_get_free_cres_list_set(); + + + // Download new list within T_CRES_LIST_PARAM structure. + free_list->nb_carrier = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->nb_carrier; + + for(i = 0; i < free_list->nb_carrier; i++) + { + free_list->freq_list[i] = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i]; + } + + free_list->list_id = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->list_id; + + // Set "flist" with Circuit Swithed BA frequency list parameters + l1pa_l1ps_com.cres_freq_list.alist = free_list; + + // Reset Neighbour Cell measurement parameters. + l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl = 0; + l1pa_l1ps_com.tcr_freq_list.tcr_next_to_read = 0; + l1pa_l1ps_com.tcr_freq_list.last_stored_tcr_to_read = 0; + l1pa_l1ps_com.tcr_freq_list.first_pass_flag = TRUE; + + // Initialize counter used to report measurements + l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0; + + // Reset flags. + l1pa_l1ps_com.tcr_freq_list.ms_ctrl = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd = 0; + + // Reset measures made on beacon frequency. + l1pa_l1ps_com.tcr_freq_list.beacon_meas = 0; + + // Enable Packet Transfer Neighbour Measurement task. + l1pa.l1pa_en_meas[TCR_MEAS] |= P_TCRMS_MEAS; + + // step in state machine. + *state = WAIT_RESULT; + } +#endif + + // End of process. + end_process = 1; + } + break; + + case WAIT_RESULT: + { + switch(SignalCode) + { + case L1P_TCR_MEAS_DONE: + // One reporting period has been completed. A set of measures is forward to L3. + //----------------------------------------------------------------------------- + { + // Forward result message to L3. + l1a_send_result(MPHP_TCR_MEAS_IND, msg, GRRM1_QUEUE); + + // End of process. + end_process = 1; + } + break; + + case MPHP_TCR_MEAS_REQ: + // Update of the parameters are postponed until end of the reporting period. + // Parameters are saved in a double buffer. + { + // Reset present flag to avoid to mix 2 updates in case of + // an update already pending within "l1pa_l1ps_com.cres_freq_list.flist". + l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE; + + // Get Ptr to the free Neighbour meas list. + // The number of carriers in the list and the list + // identification are initialized. + free_list = l1pa_get_free_cres_list_set(); + + + // Download new list within T_CRES_LIST_PARAM structure. + list_size = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->nb_carrier; + free_list->nb_carrier = list_size; + + for(i = 0; i < list_size; i++) + { + free_list->freq_list[i] = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->radio_freq_no[i]; + } + + free_list->list_id = ((T_MPHP_TCR_MEAS_REQ *)(msg->SigP))->list_id; + + // Set "flist" with new set of frequency list parameter + l1pa_l1ps_com.cres_freq_list.flist = free_list; + + // Set present flag only when the list has been downloaded. + l1pa_l1ps_com.tcr_freq_list.new_list_present = TRUE; + + // End of process. + end_process = 1; + } + break; + + case L1P_TBF_RELEASED: + { + // Test if all TBF have been released + // Then stop Neighbour Measurement process + if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all) + { + // This process must be reset. + *state = RESET; + } + else + { + return; + } + } + break; + + case MPHP_TCR_MEAS_STOP_REQ: + // Note: A TBF stop do not imply a stop of the Neighbour Measurement process. + // L3 has to send a MPHP_TCR_MEAS_STOP message to stop the measurement process. + { + // send confirmation message + l1a_send_confirmation(MPHP_TCR_MEAS_STOP_CON,GRRM1_QUEUE); + + // This process must be reset. + *state = RESET; + } + break; + + default: + // No action in this machine for other messages. + // Note: No action is performed on receipt of a L1P_TRANSFER_DONE + // message. However a SYNCHRO task is programmed, which implies + // a reset of measures related to the Serving Cell (cf. L1S). + //-------------------------------------------------------------- + { + return; + } + } // end of switch(SignalCode) + } + break; + } // end of "switch". + } // end of "while" +} // end of procedure. + +/*-------------------------------------------------------*/ +/* l1pa_idle_interference_meas_process() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* */ +/* Starting messages: MPHP_INT_MEAS_REQ */ +/* */ +/* This message requests signal strength measurements */ +/* on several channels of a specific carrier. */ +/* Measurements must be done on one search frame and one */ +/* PTCCH frame. */ +/* */ +/* Result messages (input): L1PS_ITMEAS_IND */ +/* */ +/* This message is reported to L1A when signal strength */ +/* has been measured on one idle frame (PTCCH or search) */ +/* */ +/* Result messages (output): MPHP_INT_MEAS_IND */ +/* */ +/* This message is reported to L3 when measurements have */ +/* been done on two contiguous idle frames */ +/* */ +/* Reset message (input): MPHP_INT_MEAS_STOP_REQ */ +/* */ +/* Interference measurement processing is stopped by */ +/* this message */ +/*-------------------------------------------------------*/ +void l1pa_idle_interference_meas_process(xSignalHeaderRec *msg) +{ + enum states + { + RESET = 0, + WAIT_INIT = 1, + WAIT_1ST_RESULT = 2, + WAIT_2ND_RESULT = 3 + }; + + static T_L1A_INT_MEAS_PARAM int_meas_param; + UWORD8 *state = &l1pa.state[PI_INT_MEAS]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_INIT; + + // Reset ITMEAS process. + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_DISABLED; // Clear ITMEAS task enable flag. + } + break; + + case WAIT_INIT: + { + // Interference measurement request + //--------------------------------- + if (SignalCode == MPHP_INT_MEAS_REQ) + { + UWORD8 bitmap,i; + + // Set semaphore + l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET; + + // Download message content + l1pa_l1ps_com.itmeas.packet_intm_freq_param = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->packet_intm_freq_param; + l1pa_l1ps_com.itmeas.multislot_class = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->multislot_class; + int_meas_param.id = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->carrier_id; + + // Processing of the 2 possible measurement bitmaps + //------------------------------------------------- + + // 1- Without Rx on the frame before + + l1pa_l1ps_com.itmeas.idle_tn_no_rx = ((T_MPHP_INT_MEAS_REQ *)(msg->SigP))->tn; + + // Trb respect after measurements + // We consider that the timeslot on which the Layer 1 is synchronized is + // always allocated on the frame after the idle frame. + // For the Trb multi-slot class parameter respect, we must clear the bits at + // the right of the interference measurement bitmap + l1pa_l1ps_com.itmeas.idle_tn_no_rx &= (UWORD8) + ~( 0xFF + >> ( 8 + l1a_l1s_com.dl_tn + - MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb)); + + // 2- With a Rx programmed on the frame before + // Note: This Rx is always on the dl_tn + + l1pa_l1ps_com.itmeas.idle_tn_rx = l1pa_l1ps_com.itmeas.idle_tn_no_rx; + + // Trb respect before measurements + // The timeslot on which the Layer 1 is synchronized is allocated on the frame + // before the idle frame. + // For the Trb multi-slot class parameter respect, we must clear the bits at + // the left of the interference measurement bitmap + bitmap = 0x80; + + i = 8 - l1a_l1s_com.dl_tn - MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb; + if (i > 8) + bitmap >>= (-i); + else + bitmap <<= i; + + for (i = 1; i<= MS_CLASS[l1pa_l1ps_com.itmeas.multislot_class].trb; i++) + { + l1pa_l1ps_com.itmeas.idle_tn_rx &= (UWORD8) ~bitmap; + bitmap <<= 1; + } + + // Initialize parameters + l1pa_l1ps_com.itmeas.position = ANY_IDLE_FRAME; // First measurement on any idle frame + + // Enable synchronous task + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED; + + // Step in state machine + *state = WAIT_1ST_RESULT; + + // End of process + end_process = 1; + } + + // No action in this machine for other messages. + else + { + // End of process. + end_process = 1; + } + } + break; + + case WAIT_1ST_RESULT: + { + // Reporting of 1st measurement session + //------------------------------------- + if (SignalCode == L1P_ITMEAS_IND) + { + UWORD8 i; + + // Set semaphore + l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET; + + // Save interference measurements + for(i=0; i<8; i++) + int_meas_param.rxlev[i] = ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i]; + + // Save bitmap + int_meas_param.meas_bitmap = ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap; + + // Save reported fn + int_meas_param.fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn; + + // Position = complement of reported position + if (((T_L1P_ITMEAS_IND *)(msg->SigP))->position == PTCCH_FRAME) + l1pa_l1ps_com.itmeas.position = SEARCH_FRAME; + else + l1pa_l1ps_com.itmeas.position = PTCCH_FRAME; + + // Enable ITMEAS + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED; + + // Step in state machine + *state = WAIT_2ND_RESULT; + + // End of process + return; + } + + else + if (SignalCode == MPHP_INT_MEAS_STOP_REQ) + { + // Send confirmation + l1a_send_confirmation(MPHP_INT_MEAS_STOP_CON,GRRM1_QUEUE); + + // Reset process + *state = RESET; + } + + // No action in this machine for other messages. + else + { + // End of process + return; + } + } + break; + + case WAIT_2ND_RESULT: + { + // Reporting subsequent measurement session + //----------------------------------------- + if (SignalCode == L1P_ITMEAS_IND) + { + // At least one measurement session has already been reported + //----------------------------------------------------------- + UWORD32 reported_fn; + + // Check fn + // The two measurement sessions must be done in two contiguous idle frames + + // Modulo + if (((T_L1P_ITMEAS_IND *)(msg->SigP))->fn < int_meas_param.fn) + { + reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn + MAX_FN; + } + else + { + reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn; + } + + // The two last measurement sessions are enough close + if ((reported_fn - int_meas_param.fn) == 13) + { + // Build and send result msg to L3. + l1pa_send_int_meas_report(MPHP_INT_MEAS_IND, + ((T_L1P_ITMEAS_IND *)(msg->SigP)), + &int_meas_param); + + // Only one measurement session per request + *state = RESET; + } + + // The two last measurement sessions aren't enough close + else + { + // 1st measurement result is no more valid, second result + // must replace it: this is achieved by WAIT_1ST_RESULT state!!! + + // Step in state machine + *state = WAIT_1ST_RESULT; + } + } + + else + if (SignalCode == MPHP_INT_MEAS_STOP_REQ) + { + // Send confirmation + l1a_send_confirmation(MPHP_INT_MEAS_STOP_CON,GRRM1_QUEUE); + + // Reset process + *state = RESET; + } + + // No action in this machine for other messages. + else + { + // End of process + return; + } + } + break; + + } // End of "switch" + } // End of "while" +} // End of "procedure" + +/*-------------------------------------------------------*/ +/* l1pa_transfer_interference_meas_process() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* */ +/* Starting messages: L1P_TRANFSER_DONE */ +/* */ +/* Interference measurement processing starts each time */ +/* a new starting time occurs if the interference */ +/* measurements are enabled */ +/* Measurements must be done on one search frame and one */ +/* PTCCH frame. */ +/* */ +/* Result messages (input): L1PS_ITMEAS_IND */ +/* */ +/* This message is reported to L1A when signal strength */ +/* has been measured on one idle frame (PTCCH or search) */ +/* */ +/* Result messages (output): MPHP_TINT_MEAS_IND */ +/* */ +/* This message is reported to L3 when measurements have */ +/* been done on two idle frames as close as possible */ +/* */ +/* Reset message (input): L1P_TBF_RELEASED */ +/* */ +/* Interference measurement processing is stopped when */ +/* all TBF are released */ +/*-------------------------------------------------------*/ +void l1pa_transfer_interference_meas_process(xSignalHeaderRec *msg) +{ + /* Bitmaps used for the processing of full_allocation */ + /*----------------------------------------------------*/ + const UWORD8 FULL_ALLOCATION[9]= +{ + 0x00, + 0x80, + 0xc0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xfe, + 0xff + }; + + enum states + { + RESET = 0, + WAIT_INIT = 1, + CONFIG = 2, + WAIT_1ST_RESULT = 3, + WAIT_2ND_RESULT = 4 + }; + + static T_L1A_INT_MEAS_PARAM int_meas_param; + UWORD8 *state = &l1pa.state[PT_INT_MEAS]; + UWORD32 SignalCode = msg->SignalCode; + + BOOL end_process = 0; + while(!end_process) + { + switch(*state) + { + case RESET: + { + // Step in state machine. + *state = WAIT_INIT; + + // Reset ITMEAS process. + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_DISABLED; // Clear ITMEAS task enable flag. + } + break; + + case WAIT_INIT: + { + // New channel assignment + //----------------------- + if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) || + (SignalCode == L1P_ALLOC_EXHAUST_DONE)) + { + *state = CONFIG; + } + + // No action in this machine for other messages. + else + { + // End of process. + return; + } + } + break; + + case CONFIG: + { + // Rise transfert parameter semaphore to prevent L1S to use partial configuration. + l1pa_l1ps_com.transfer.semaphore = TRUE; + + // If the interference measurements are disabled + if (l1pa_l1ps_com.transfer.aset->interf_meas_enable == FALSE) + { + *state = WAIT_INIT; + } + else + { + // Set semaphore + l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET; + + // Initialize parameters + l1pa_l1ps_com.itmeas.position = ANY_IDLE_FRAME; // First measurement on any idle frame + + // Save assignment ID for the interference measurements reporting message + int_meas_param.id = l1pa_l1ps_com.transfer.aset->assignment_id; + + // Processing of the measurement bitmap + l1pa_l1ps_com.itmeas.meas_bitmap = (UWORD8) + FULL_ALLOCATION[MS_CLASS[l1pa_l1ps_com.transfer.aset->multislot_class].rx] >> + l1a_l1s_com.dl_tn; + + // Enable synchronous task + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED; + + // Step in state machine + *state = WAIT_1ST_RESULT; + } + + // Clear transfer parameter semaphore to let L1S use the new parameters. + l1pa_l1ps_com.transfer.semaphore = FALSE; + + // End of process. + end_process = 1; + } + break; + + case WAIT_1ST_RESULT: + { + // Reporting of 1st measurement session + //------------------------------------- + if (SignalCode == L1P_ITMEAS_IND) + { + UWORD8 i; + + // Set semaphore + l1a_l1s_com.task_param[ITMEAS] = SEMAPHORE_SET; + + // Save interference measurements + for(i=0; i<8; i++) + int_meas_param.rxlev[i] = ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i]; + + // Save bitmap + int_meas_param.meas_bitmap = ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap; + + // Save reported fn + int_meas_param.fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn; + + // Position = complement of reported position + if (((T_L1P_ITMEAS_IND *)(msg->SigP))->position == PTCCH_FRAME) + l1pa_l1ps_com.itmeas.position = SEARCH_FRAME; + else + l1pa_l1ps_com.itmeas.position = PTCCH_FRAME; + + // Enable ITMEAS + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_ENABLED; + + // Step in state machine + *state = WAIT_2ND_RESULT; + + // End of process + return; + } + + else + if (SignalCode == L1P_TRANSFER_DONE) + // The starting time of a new TBF occurs + { + // Reset process + *state = RESET; + } + + else + if (SignalCode == L1P_TBF_RELEASED) + // A TBF has been released + { + // No remaining TBF + if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all) + { + // Reset process + *state = RESET; + } + else + { + // Enable a new measurement session + *state = CONFIG; + } + } + + else + if (SignalCode == L1P_PDCH_RELEASED) + // PDCH have been released + { + // Enable a new measurement session + *state = CONFIG; + } + + // No action in this machine for other messages. + else + { + // End of process + return; + } + } + break; + + case WAIT_2ND_RESULT: + { + // Reporting subsequent measurement session + //----------------------------------------- + if (SignalCode == L1P_ITMEAS_IND) + { + // At least one measurement session has already been reported + //----------------------------------------------------------- + UWORD32 reported_fn; + + // Check fn + // The two measurement sessions must be done in two contiguous idle frames + + // Modulo + if (((T_L1P_ITMEAS_IND *)(msg->SigP))->fn < int_meas_param.fn) + { + reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn + MAX_FN; + } + else + { + reported_fn = ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn; + } + + // The two last measurement sessions are enough close + if ((reported_fn - int_meas_param.fn) <= 104) + { + // Build and send result msg to L3. + l1pa_send_int_meas_report(MPHP_TINT_MEAS_IND, + ((T_L1P_ITMEAS_IND *)(msg->SigP)), + &int_meas_param); + + // Enable a new measurement session + *state = CONFIG; + } + + // The two last measurement sessions aren't enough close + else + { + // 1st measurement result is no more valid, second result + // must replace it: this is achieved by WAIT_1ST_RESULT state!!! + + // Step in state machine + *state = WAIT_1ST_RESULT; + } + } + + else + + // New channel assignment + //----------------------- + if ((SignalCode == L1P_TRANSFER_DONE) || (SignalCode == L1P_REPEAT_ALLOC_DONE) || + (SignalCode == L1P_ALLOC_EXHAUST_DONE)) + { + // Reset process + *state = RESET; + } + + else + if (SignalCode == L1P_TBF_RELEASED) + // A TBF has been released + { + // No remaining TBF + if(((T_L1P_TBF_RELEASED *)(msg->SigP))->released_all) + { + // Reset process + *state = RESET; + } + else + { + // Enable a new measurement session + *state = CONFIG; + } + } + + else + if (SignalCode == L1P_PDCH_RELEASED) + // PDCH have been released + { + // Enable a new measurement session + *state = CONFIG; + } + + // No action in this machine for other messages. + else + { + // End of process + return; + } + } + break; + + } // End of "switch" + } // End of "while" +} // End of "procedure" +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START +#endif +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_cmpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_cmpl.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,3886 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_CMPL.C + * + * Filename l1p_cmpl.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1P_CMPL_C + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS +#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" + #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 + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_proto.h" + #include "l1_tabs.h" + #include "l1_trace.h" + #if L2_L3_SIMUL + #include "l2_l3.h" + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" + + #if TESTMODE + #include "l1tm_msgty.h" + #include "l1tm_signa.h" + #endif + + #include "macs_def.h" + #include "macs_cst.h" + + #include "sim_cons.h" + #include "sim_def.h" + extern T_hw FAR hw; + +#else + #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" + #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 + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_proto.h" + #include "l1_tabs.h" + #include "l1_trace.h" + + #if L2_L3_SIMUL + #include "l2_l3.h" + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" + + #if TESTMODE + #include "l1tm_msgty.h" + #include "l1tm_signa.h" + #endif + + #include "macs_def.h" + #include "macs_cst.h" +#endif + +#if(RF_FAM == 61) + #include "l1_rf61.h" + #include "tpudrv61.h" +#endif + +#include "l1_ctl.h" + +/*-------------------------------------------------------*/ +/* 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 + ); +#if (L1_MADC_ON == 1) +#if (RF_FAM == 61) +void l1dmacro_rx_nb (UWORD16 arfcn, UWORD8 adc_active, UWORD8 csf_filter_choice +#if (NEW_SNR_THRESHOLD == 1) + ,UWORD8 saic_flag +#endif /* NEW_SNR_THRESHOLD */ + ); +#endif /* RF_FAM == 61*/ +#else /* L1_MADC_ON == 1*/ +void l1dmacro_rx_nb (UWORD16 arfcn); +#endif /* L1_MADC_ON == 1*/ + +void l1dmacro_afc (UWORD16 afc_value, UWORD8 win_id); +#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 */ + ); + + void l1pdtpu_serv_rx_nb (UWORD16 radio_freq, WORD8 agc, BOOL lna_off, + UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx, + UWORD8 rx_group_id, BOOL rx_done_flag, + 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*/ +#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); + +void l1pdtpu_serv_rx_nb (UWORD16 radio_freq, WORD8 agc, BOOL lna_off, + UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx, + UWORD8 rx_group_id, BOOL rx_done_flag,UWORD8 adc_active); +#endif +void l1pdtpu_serv_tx (UWORD16 radio_freq, UWORD8 timing_advance, + UWORD32 offset_serv, UWORD8 tx_id, UWORD8 num_tx, + UWORD8 tx_group_id, UWORD8 switch_flag, BOOL burst_type, + BOOL rx_flag,UWORD8 adc_active); +UWORD8 l1pdtpu_interf_meas (UWORD16 radio_freq, + WORD8 agc, + UWORD8 lna_off, + UWORD8 meas_bitmap, + UWORD32 offset_serv, + UWORD16 win_id, + UWORD8 synchro_ts + #if(RF_FAM == 61) + ,UWORD8 if_ctl + #endif + ); + +void l1s_read_l3frm (UWORD8 pwr_level, API *info_address, UWORD32 task_rx); +void l1ps_macs_read (UWORD8 pr_table[8]); +void l1ps_macs_ctrl (void); +#if TESTMODE + void l1ps_tmode_macs_ctrl (void); +#endif +void l1pddsp_transfer_mslot_power (UWORD8 *txpwr, UWORD16 radio_freq, UWORD8 ul_bitmap); + +void l1pddsp_single_tx_block (UWORD8 burst_nb, UWORD8 *data, UWORD8 tsc, + UWORD16 radio_freq); +void l1pddsp_idle_prach_data (BOOL polling, UWORD8 cs_type, UWORD16 channel_request_data, + UWORD8 bsic, UWORD16 radio_freq); +void l1pddsp_idle_prach_power (UWORD8 txpwr, UWORD16 radio_freq, UWORD8 ts); +#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 + +void l1pddsp_ul_ptcch_data (UWORD8 cs_type, UWORD16 channel_request_data, UWORD8 bsic, UWORD16 radio_freq, UWORD8 timeslot_no); +void l1ps_tcr_ctrl (UWORD8 pm_position); +void l1pd_afc (void); +void l1pddsp_interf_meas_ctrl (UWORD8 nb_meas_req); +void l1pddsp_meas_ctrl (UWORD8 nbmeas, UWORD8 pm_pos); +void maca_power_control (UWORD8 assignment_id, BOOL crc_error, WORD8 bcch_level, UWORD16 *radio_freq, WORD8 *burst_level, UWORD8 *pch); +WORD16 l1s_encode_rxlev (UWORD8 inlevel); + +void l1pctl_pagc_ctrl (WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq,UWORD8 serving_cell); +UWORD8 l1pctl_pagc_read (UWORD8 pm, UWORD16 radio_freq); +void l1pctl_transfer_agc_ctrl (WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq); +void l1pctl_npc_agc_read (UWORD8 calibrated_IL[8], + T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr); +void l1pctl_dpcma_agc_read (UWORD8 calibrated_IL[8], + T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, + UWORD8 pr_table[8]); +void l1pctl_dpcmb_agc_read (UWORD8 calibrated_IL[8], + T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, + UWORD8 pr_table[8]); +void l1ps_macs_header_decoding (UWORD8 rx_no, UWORD8 *tfi_result, UWORD8 *pr); +void l1ps_update_read_set_parameters(void); +void l1ps_bcch_meas_ctrl (UWORD8 ts); + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END + + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_single() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_ctrl_single(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 radio_freq; + T_INPUT_LEVEL *IL_info_ptr; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; + #endif + #if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; + #endif /* NEW_SNR_THRESHOLD */ + // needs to be defined for maca_power_control() function call + #define DL_pwr_ctrl l1pa_l1ps_com.transfer.dl_pwr_ctrl + + 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. + { + // Catch ARFCN. + // ************* + + // Get ARFCN to be used for current control. + 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) + if (l1pa_l1ps_com.transfer.single_block.activity & (SINGLE_DL | SINGLE_UL)) // trace only if a window is programmed + trace_fct(CST_L1PS_CTRL_SINGLE, radio_freq); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + /**************************************************************************/ + /* Program DSP for mulstislot operation... */ + /**************************************************************************/ + /*===============*/ + /* Downlink */ + /*===============*/ + if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL) + { + // Programs DSP. + #if FF_L1_IT_DSP_USF + l1pddsp_idle_rx_nb(burst_id, + l1pa_l1ps_com.transfer.aset->tsc, + radio_freq, + 0, + FALSE, + FALSE); + #else + l1pddsp_idle_rx_nb(burst_id, + l1pa_l1ps_com.transfer.aset->tsc, + radio_freq, + 0, + FALSE); + #endif + + // Flag DSP programmation. + // Set "CTRL_RX" flag in the controle flag registers. + l1s.dsp_ctrl_reg |= CTRL_RX; + } + + /*===============*/ + /* Uplink */ + /*===============*/ + if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_UL) + { + // Pgme DSP for Single block TX on TS=3. + l1pddsp_single_tx_block (burst_id, + l1pa_l1ps_com.transfer.single_block.data_array, + l1pa_l1ps_com.transfer.aset->tsc, + radio_freq); + + // TXPWR control needs to take into account ALPHA, GAMMA and C values, not only TXPWR MAX + // => maca_power_control() needs to be called + // Initialization of txpwr control values for all time slots + { + UWORD8 txpwr[8]; + UWORD8 i; + + // Call Uplink Transmit Power level algorithm +#if 0 /* LoCosto version */ + maca_power_control(l1pa_l1ps_com.transfer.aset->assignment_id, +#else /* TCS211 reconstruction */ + maca_power_control(DL_pwr_ctrl.assignment_id, +#endif + DL_pwr_ctrl.crc_error, + DL_pwr_ctrl.bcch_level, + DL_pwr_ctrl.radio_freq_tbl, + DL_pwr_ctrl.burst_level, + txpwr); + + for(i = 0; i < 8; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = txpwr[i]; + } + } + + // Pgme DSP for Transmit power on TS=3. + l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, 0x80 >> 3); + + // Flag DSP programmation. + // Set "CTRL_TX" flag in the controle flag registers. + l1s.dsp_ctrl_reg |= CTRL_TX; + } + + /**************************************************************************/ + /* Program TPU for single slot operation... */ + /**************************************************************************/ + + /*===============*/ + /* Downlink */ + /*===============*/ + if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL) + { + WORD8 agc; + UWORD8 lna_off; + + // Update AGC + l1pctl_transfer_agc_ctrl(&agc, &lna_off, radio_freq); + + + #if (RF_FAM == 61) + // Locosto DCO + + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + l1a_l1s_com.Scell_used_IL.input_level , + radio_freq, if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // the l1pctl_transfer_agc_ctrl above + 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... + l1pdtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + 0, + l1s.tpu_offset, + 1, + 1, + TRUE, + INACTIVE, + csf_filter_choice, + if_ctl + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /* NEW_SNR_THRESHOLD */ + ); + #endif /* RF_FAM == 61*/ + #if (RF_FAM != 61) + // tpu pgm... + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // the l1pctl_transfer_agc_ctrl above + l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,task + #endif + ); + #endif + + + l1pdtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + 0, + l1s.tpu_offset, + 1, + 1, + TRUE, + INACTIVE); + #endif + + // Set tpu window identifier for Synthesizer and + // according to last RX group position. + l1s.tpu_win = l1_config.params.rx_synth_load_split + RX_SPLIT_TABLE[0]; + + // Flag TPU programmation. + // Set "CTRL_RX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_RX; + } + + /*===============*/ + /* Uplink */ + /*===============*/ + if(l1pa_l1ps_com.transfer.single_block.activity & SINGLE_UL) + { + // Program single block UL slot. + // ****************************** + l1pdtpu_serv_tx(radio_freq, + l1pa_l1ps_com.transfer.aset->packet_ta.ta, + l1s.tpu_offset, + 3, + 1, + 1, + 0, + TX_NB_BURST, + l1pa_l1ps_com.transfer.single_block.activity & SINGLE_DL, + INACTIVE); + + // Set tpu window identifier for Synthesizer and + // according to last TX group position. + l1s.tpu_win =(UWORD16)( (l1_config.params.rx_synth_load_split) + + ((UWORD16)3 * BP_SPLIT) + l1_config.params.tx_nb_load_split); + + // Flag TPU programmation. + // Set "CTRL_TX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_TX; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1pa_l1ps_com.transfer.aset->packet_ta.ta, l1s.applied_txpwr) + #endif + } + + /*===============*/ + /* General */ + /*===============*/ + if(burst_id == BURST_4) + { + // Single block UL is now complete, reset its activity flag. + l1pa_l1ps_com.transfer.single_block.activity &= SINGLE_UL_MASK; + + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == SINGLE_BLOCK_DL) + { + // Single block UL is now complete. + l1pa_l1ps_com.transfer.single_block.activity &= SINGLE_DL_MASK; + } + } + } // End if(task enabled and semaphore false) + + else + // When the task is aborted, we must continue to make dummy + // DSP programming to avoid communication mismatch due + // to C/W/R pipelining. + { + // Flag dummy DSP programmation. + // Set "CTRL_TX" flag in the controle flag registers. + l1s.dsp_ctrl_reg |= CTRL_TX; + } +} + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_prach() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_ctrl_prach(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 radio_freq; + UWORD8 txpwr; + UWORD8 adc_active = INACTIVE; + + // Get ARFCN to be used for current control. + // ****************************************** + + radio_freq = l1pa_l1ps_com.p_idle_param.radio_freq; + + // Get TXPWR value + txpwr = l1s.applied_txpwr; + + // 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 + + #if FF_L1_IT_DSP_USF + // Whenever the USF status is unknown then the PRACH control execution + // has to be postponed until DSP USF interrupt fires. + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif // FF_L1_IT_DSP_USF + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + #if FF_L1_IT_DSP_USF + // TPU and DSP have to be programmed for transmission only if the USF is + // good otherwise this is not a valid opportunity. If there was no USF + // uncertainty then the test is void. + if ( (l1ps_macs_com.usf_status != USF_IT_DSP) + || (((l1ps_dsp_com.pdsp_ndb_ptr->d_usf_updated_gprs >> ((7-0)*2)) & 0x0003) == USF_GOOD)) + { + // Flags PRACH burst was controlled to TPU/DSP (not cancelled due to USF) + l1pa_l1ps_com.pra_info.prach_controlled = TRUE; + #endif // FF_L1_IT_DSP_USF + + #if (CODE_VERSION!=SIMULATION) + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + L1_trace_string("PRA"); + #endif + #endif + + // Programs DSP for required task. + // ******************************** + { + UWORD8 cs_type; + + if (l1pa_l1ps_com.access_burst_type == ACC_BURST_8) + cs_type = CS_PAB8_TYPE; + else + cs_type = CS_PAB11_TYPE; + + // ACCESS PRACH dsp control. + l1pddsp_idle_prach_data(FALSE, + cs_type, + l1pa_l1ps_com.pra_info.channel_request_data, + l1a_l1s_com.Scell_info.bsic, + radio_freq); + } + + l1pddsp_idle_prach_power(txpwr, + radio_freq, + 3); + + // ADC measurement + // *************** + + // check if during the RACH an ADC measurement must be performed + if (l1a_l1s_com.adc_mode & ADC_EACH_RACH) // perform ADC on each burst + adc_active = ACTIVE; + + // Programs TPU for required task. + // ******************************** + + // tpu pgm... + l1dtpu_serv_tx_ra(radio_freq, l1s.tpu_offset, 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; + + // Store frame number to report to L3 + l1pa_l1ps_com.pra_info.fn_to_report = l1s.next_time.fn; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_AB(task,txpwr) + #endif + + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_TX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_PRACH; + l1s.dsp_ctrl_reg |= CTRL_TX; + + #if FF_L1_IT_DSP_USF + }// if ((l1ps_macs_com.usf_status != USF_IT_DSP) || USF_GOOD) + else + { + // PRACH has been cancelled because USF not FREE. Hence Read is skipped. + l1pa_l1ps_com.pra_info.prach_controlled = FALSE; + } + #endif + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_AWAITED) + #endif +} + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_poll() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_ctrl_poll(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 radio_freq; + + // Get ARFCN to be used for current control. + // ****************************************** + if(l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED) + radio_freq = l1a_l1s_com.dedic_set.radio_freq; + else + radio_freq = l1pa_l1ps_com.p_idle_param.radio_freq; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_CTRL_POLL, 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("PRA"); + #endif + #endif + + // Programs DSP for required task. + // ******************************** + { + UWORD8 cs_type; + + cs_type = l1pa_l1ps_com.poll_info.pol_resp_type; + + if ((cs_type == CS_PAB8_TYPE) || (cs_type == CS_PAB11_TYPE)) + { + // IDLE POLLING PRACH dsp control. + l1pddsp_idle_prach_data(TRUE, + cs_type, + l1pa_l1ps_com.poll_info.chan_req.prach_data[0], + l1a_l1s_com.Scell_info.bsic, + radio_freq); + + l1pddsp_idle_prach_power(l1s.applied_txpwr, + radio_freq, + 3); + + // Programs TPU for required task. + // ******************************** + // tpu pgm... + l1dtpu_serv_tx_ra(radio_freq, l1s.tpu_offset, l1s.applied_txpwr,INACTIVE); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_AB(task,l1s.applied_txpwr) + #endif + } + else + { + UWORD8 tsc; + + if(l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED) + tsc = l1pa_l1ps_com.transfer.aset->tsc; + else + tsc = l1pa_l1ps_com.pccch.packet_chn_desc.tsc; + + // Pgm DSP for Poll Response TX NB on TS=3. + l1pddsp_single_tx_block (burst_id, + l1pa_l1ps_com.poll_info.chan_req.cs1_data, + tsc, + radio_freq); + + // Pgm DSP for Transmit power. + l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, 0x80>>3); + + // Programs TPU for required task. + // ******************************** + // tpu pgm... + l1dtpu_serv_tx_nb(radio_freq, + l1pa_l1ps_com.poll_info.timing_advance, + l1s.tpu_offset, + l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[3],INACTIVE); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_NB(task, l1pa_l1ps_com.poll_info.timing_advance, l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[3]) + #endif + } + } + + + // Set tpu window identifier for Power meas if any. + l1s.tpu_win = (3 * BP_SPLIT) + l1_config.params.tx_nb_load_split + l1_config.params.rx_synth_load_split; + + // Store frame number to report to L3 + if (burst_id == BURST_4) + l1pa_l1ps_com.poll_info.fn_to_report = l1s.next_time.fn; + + // 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_pdtch() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: This is the control function for Multislot Rx/Tx */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ + +/*-------------------------------------------------------*/ +void l1ps_ctrl_pdtch(UWORD8 task, UWORD8 burst_id) +{ + 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. + { + UWORD16 radio_freq; + #if (RF_FAM == 61) + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; + #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[PDTCH].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Catch channel description and ARFCN. + // ************************************* + + // 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 (TRACE_TYPE==5) // in simulation trace only one time by frame + trace_fct(CST_L1PS_CTRL_PDTCH, radio_freq); + #endif + + /**************************************************************************/ + /* Program DSP for mulstislot operation... */ + /**************************************************************************/ + { + UWORD8 tx_allocation; + + #if TESTMODE + if (l1_config.TestMode && (l1_config.tmode.tx_params.burst_data == 11)) + // Call dummy MACS for CMU200 loopback mode + l1ps_tmode_macs_ctrl(); + else + #endif + { + // Call MACS for Medium control, DATA control and RLC-MACS management + l1ps_macs_ctrl(); + } + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif + // Compute tx_allocation mixing NB and RA allocations. + tx_allocation = l1ps_macs_com.tx_nb_allocation | l1ps_macs_com.tx_prach_allocation; + + // Pgme TXPWR only if any UL. + if(tx_allocation) + { + // Pgme DSP for Transmit power. + // !!! Warning: This function must be called before l1pdtpu_serv_tx() + // !!! a_ctrl_abb_gprs is partly overwritten by l1pdtpu_serv_tx() + l1pddsp_transfer_mslot_power(l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr, radio_freq, tx_allocation); + } + #if FF_L1_IT_DSP_USF + } + #endif + } + + + /**************************************************************************/ + /* Program TPU for mulstislot operation... */ + /**************************************************************************/ + { + WORD8 ts = 0; + UWORD8 rx_group_id = 0; + UWORD8 tx_group_id = 0; + BOOL pwr_programmed = FALSE; + UWORD8 bit_mask = 0x80; + WORD8 agc; + UWORD8 lna_off; + BOOL rx_done_flag; + BOOL adc_done = FALSE; + UWORD8 adc_active = INACTIVE; + + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD16 dco_algo_ctl_pw = 0; + UWORD8 if_ctl =0; //omaps00090550; + UWORD8 tot_num_rx = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + #endif + + // AGC and LNA_OFF processing + //--------------------------- + + #if FF_L1_IT_DSP_USF + #if L1_EDA + if (l1ps_macs_com.usf_status != USF_AWAITED) + #else + if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif + #endif + // Same AGC is used for all timeslots + l1pctl_transfer_agc_ctrl(&agc, &lna_off, radio_freq); + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // the l1pctl_transfer_agc_ctrl above + 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 + + while(ts < 8) + { + + #if FF_L1_IT_DSP_USF + #if L1_EDA + //Depending on USF status got from DSP, RX allocation may change after + //receiving the USF interrupt due to USF status updates + if ((l1ps_macs_com.rx_allocation & bit_mask) + && (l1ps_macs_com.usf_status != USF_AWAITED)) + #else + if ((l1ps_macs_com.rx_allocation & bit_mask) + && (l1ps_macs_com.usf_status != USF_IT_DSP)) + #endif + #else + if(l1ps_macs_com.rx_allocation & bit_mask) + #endif + { + // We have detected the 1st RX slot number for a new RX group. + + UWORD8 rx_id = ts; // Save 1st RX timeslot number. + UWORD8 num_rx = 1; // 1 RX in the RX group for the moment. + + // Increment the RX group ID. + rx_group_id++; + + #if (RF_FAM == 61) + //Increment the total number of RX slots + tot_num_rx++; + #endif + + // Increment TS. + ts++; + + // Jump on next timeslot to keep looking for contiguous RX slots. + bit_mask >>= 1; + + // Look for more contiguous RX slots. + while((l1ps_macs_com.rx_allocation & bit_mask) && (ts < 8)) + { + ts++; + num_rx++; + #if (RF_FAM == 61) + tot_num_rx++; + #endif + bit_mask >>= 1; + } + + // Check if more RX bursts follow + if((l1ps_macs_com.rx_allocation << (ts+1)) & 0xFF) + rx_done_flag = FALSE; + else + rx_done_flag = TRUE; + + #if (RF_FAM == 61) // Locosto DCO + if(rx_group_id == 1) + { + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + l1a_l1s_com.Scell_used_IL.input_level, radio_freq,if_threshold); + } + + if(rx_done_flag == TRUE) + { + //dco_algo_ctl has 0000 00ZL + dco_algo_ctl_nb *= 0x55; // replicate 0000 00zL as ZLZL ZLZL + // ZLZLZLZL >> 2*(4-tot_num_rx) where i is the tot_num_rx would produce the + // desired dco_algo_ctl_nb For Eg if tot_num_rx is 2 the desired pattern is + // 0000 ZLZL + dco_algo_ctl_nb = dco_algo_ctl_nb >> (2*( 4 - tot_num_rx)); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + } + #endif + // ADC measurement + // *************** + if (adc_done == FALSE) + { + // check if during the PDTCH 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; + adc_done = TRUE; + 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.actual_time.fn_mod104 == 10) //periodic with each PDTCH burst in frame 11 (frame with the lowest CPU load) + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_traffic_period) // wait for the period + { + adc_active = ACTIVE; + adc_done = TRUE; + l1a_l1s_com.adc_cpt = 0; + } + } + + // update the TPU with the new TOA if necessary + if (rx_group_id == 1) // only if synchro performed + l1ctl_update_TPU_with_toa(); + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_PDTCH_DL_BURST0 + burst_id, radio_freq); + #endif + + // Program RX scenario. + l1pdtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + rx_id, + l1s.tpu_offset, + num_rx, + rx_group_id, + rx_done_flag,adc_active + #if (RF_FAM == 61) + ,csf_filter_choice + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif + ); + + adc_active = INACTIVE; // ADC performed only on the first RX burst + + // Set tpu window identifier for Synthesizer and + // according to last RX group position. + l1s.tpu_win = (l1_config.params.rx_synth_load_split) + + ((UWORD16)rx_id * BP_SPLIT) + RX_SPLIT_TABLE[num_rx-1]; + + + // Set "CTRL_RX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + } + + else + #if FF_L1_IT_DSP_USF + if ((l1ps_macs_com.tx_nb_allocation & bit_mask) + && (l1ps_macs_com.usf_status != USF_AWAITED)) + #else + if(l1ps_macs_com.tx_nb_allocation & bit_mask) + #endif + { + // We have detected the 1st TX NB slot number for a new TX group. + + UWORD8 tx_id = ts; // Save 1st TX timeslot number. + UWORD8 num_tx = 1; // 1 RX in the TX group for the moment. + UWORD8 switch_flag; + + // Increment the TX group ID. + tx_group_id++; + + // Increment TS. + ts++; + + // Jump on next timeslot to keep looking for contiguous TX slots. + bit_mask >>= 1; + + // Look for more contiguous TX slots. + while((l1ps_macs_com.tx_nb_allocation & bit_mask) && (ts < 8)) + { + ts++; + num_tx++; + bit_mask >>= 1; + } + + // Detect special case: TX NB followed by PRACH. + if(l1ps_macs_com.tx_prach_allocation & bit_mask) + { + switch_flag = 1; + } + else + { + switch_flag = 0; + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_PDTCH_UL, radio_freq); + #endif + + // Program TN NB scenario. + l1pdtpu_serv_tx(radio_freq, + l1pa_l1ps_com.transfer.aset->packet_ta.ta, + l1s.tpu_offset, + tx_id, + num_tx, + tx_group_id, + switch_flag, + 0, // Driver called for Normal Burst. + TRUE,INACTIVE);// Flag RX in same frame as TX + + // Set tpu window identifier for Synthesizer and + // according to last TX group position. + // TX offset = tx_id * BP_SPLIT + // TX load = (num_tx-1) * BP_SPLIT + l1_config.params.tx_load_split + l1s.tpu_win = (l1_config.params.rx_synth_load_split) + + ((UWORD16)tx_id * BP_SPLIT) + + ((UWORD16)(num_tx -1) * BP_SPLIT) + + l1_config.params.tx_nb_load_split; + + // Set "CTRL_TX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; + } + + else + #if FF_L1_IT_DSP_USF + if ((l1ps_macs_com.tx_prach_allocation & bit_mask) + && (l1ps_macs_com.usf_status != USF_AWAITED)) + #else + if(l1ps_macs_com.tx_prach_allocation & bit_mask) + #endif + { + // We have detected a TX RA. + + UWORD8 switch_flag; + + // Increment the TX group ID. + tx_group_id++; + + // Jump on next timeslot. + bit_mask >>= 1; + + // Detect special case: PRACH followed by TX NB. + if(l1ps_macs_com.tx_nb_allocation & bit_mask) + { + switch_flag = 1; + } + // Detect special case: PRACH followed by PRACH + else if (l1ps_macs_com.tx_prach_allocation & bit_mask) + { + // Solution with DSP patch supporting PRACH|PRACH + switch_flag = 2; + } + else + { + switch_flag = 0; + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_PDTCH_RA, radio_freq); + #endif + + // Program TX RA scenario. + l1pdtpu_serv_tx(radio_freq, + l1pa_l1ps_com.transfer.aset->packet_ta.ta, + l1s.tpu_offset, + ts, + 1, // Driver is called for each PRACH. + tx_group_id, + switch_flag, + TX_RA_BURST, // Driver called for PRACH Burst. + TRUE,INACTIVE); // Flag RX in same frame as TX + + // Set tpu window identifier for Synthesizer and + // according to last TX group position. + // TX offset = ts * BP_SPLIT + // TX load = l1_config.params.tx_nb_load_split + // original value of TX load (RACH) replaced by TX NB to take into account TX_NB|PRACH with max. TA + l1s.tpu_win = (l1_config.params.rx_synth_load_split) + + ((UWORD16)ts * BP_SPLIT) + + l1_config.params.tx_nb_load_split; + + + // Increment TS. + ts++; + + // Set "CTRL_TX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; + } + + else + #if FF_L1_IT_DSP_USF + if ((l1ps_macs_com.pwr_allocation & bit_mask) + && (pwr_programmed == 0) + && (l1ps_macs_com.usf_status != USF_AWAITED)) + #else + if((l1ps_macs_com.pwr_allocation & bit_mask) && (pwr_programmed == 0)) + #endif + { + // We have detected a PWR allocation and no PWR programmed in current frame. + if((l1pa_l1ps_com.transfer.aset->pc_meas_chan == FALSE) && + ((l1s.actual_time.t2 == 1) || (l1s.actual_time.t2 == 9) + || (l1s.actual_time.t2 == 18))) + { + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_CTRL_PC_MEAS_CHAN, (UWORD32)(-1)); + #endif + + // Measurement on the beacon (PC_MEAS_CHAN = 0) + l1ps_bcch_meas_ctrl(ts); + } + else + if(l1pa_l1ps_com.l1ps_en_meas & P_TCRMS_MEAS) + { + // Neighbour Measurement CTRL Phase + + // Note: Test on l1s.forbid_meas can't be done from the fact that at this + // level, l1s.forbid_meas is not set. + // l1ps_ctrl_pdtch is called before CTRL of FB26/SB26/SBCNF26. + if(!((l1s.actual_time.t2 == 23) && + ((l1s.task_status[FB26].current_status != INACTIVE) || + (l1s.task_status[SB26].current_status != INACTIVE) || + (l1s.task_status[SBCNF26].current_status != INACTIVE)))&& + !(l1pa_l1ps_com.tcr_freq_list.new_list_present && + ((l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 0) || + (l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 103)))) + { + if(!(l1pa_l1ps_com.meas_param & P_TCRMS_MEAS)) + { + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_CTRL_TCR_MEAS_1, (UWORD32)(-1)); + #endif + + l1ps_tcr_ctrl((UWORD8)ts); + } + } + } // End of CTRL PDTCH phase + + // Increment TS. + ts++; + + // Flag that a PWR as been programmed for current frame. + pwr_programmed = TRUE; + + // Jump on next timeslot. + bit_mask >>= 1; + + // Call PWR control function + + } + + else + { + // Increment TS. + ts++; + + // Jump on next timeslot. + bit_mask >>= 1; + } + + } // End of "while(ts < 8)" + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + #endif + // Update of AFC + l1pd_afc(); + } + } // End if(task enabled and semaphore false) + + else + // When the task is aborted, we must continue to make dummy + // DSP programming to avoid communication mismatch due + // to C/W/R pipelining. + { + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_PDTCH_DUMMY, (UWORD32)(-1)); + #endif + + // Flag dummy DSP programmation. + // Set "CTRL_TX" flag in the controle flag registers. + l1s.dsp_ctrl_reg |= CTRL_TX; + } + +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + + +/*-------------------------------------------------------*/ +/* l1s_read_single() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_read_single(UWORD8 task, UWORD8 burst_id) +{ + 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. + { + // Read param updating... + if (l1ps.read_param.new_set == TRUE) + { + // If it's the first Read phase of the block (first of the new TBF) + if (burst_id == BURST_1) + { + // Update the "read_param" structure + l1ps_update_read_set_parameters(); + } + } + + /*--------------------------------------------------------*/ + /* READ TRANSMIT TASK RESULTS... */ + /*--------------------------------------------------------*/ + + l1_check_com_mismatch(task); + + // check PM error only in case of downlink single block + if(l1ps.read_param.allocated_tbf == SINGLE_BLOCK_DL) + { + UWORD32 pm; + pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[0] & 0xffff) >> 5; + l1_check_pm_error(pm,task); + } + + + // Two phase access: downlink PDCH reading + if((l1ps.read_param.allocated_tbf == TWO_PHASE_ACCESS)&& + (l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & (0x80 >> 0))) + { + UWORD8 IL_for_rxlev[8]; + UWORD8 pr_table[8]; + + if (burst_id == BURST_4) + l1ps_macs_header_decoding(0, &(IL_for_rxlev[0]), &(pr_table[0])); + + // Update AGC and extract IL for RXLEV + //------------------------------------ + if (l1ps.read_param.dl_pwr_ctl.p0 == 255) + { + // No power control mode AGC algorithm + l1pctl_npc_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr); + } + else + { + // Downlink power control AGC algorithms + if (l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.bts_pwr_ctl_mode == 0) + { + // BTS Power control mode A + l1pctl_dpcma_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table); + } + else + { + // BTS power control mode B + l1pctl_dpcmb_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table); + } + } // End of "AGC algorithm" + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE !=5) + trace_fct(CST_L1PS_READ_SINGLE, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + if(burst_id == BURST_4) + { + xSignalHeaderRec *msg; + + #if (TRACE_TYPE==5) // in simulation trace only the 4th burst + trace_fct(CST_L1PS_READ_SINGLE, l1a_l1s_com.Scell_info.radio_freq); + #endif + + if(l1ps.read_param.allocated_tbf == TWO_PHASE_ACCESS) + // 2 phase ACCESS. + { + if((l1ps_dsp_com.pdsp_db_r_ptr->d_task_u_gprs & (0x80 >> 3)) && + (l1s.task_status[POLL].current_status == INACTIVE)) + // UL block sent... + { + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_MPHP_SINGLE_BLOCK_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + // Return "Single block" purpose. + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose = + l1pa_l1ps_com.transfer.aset->assignment_command; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->assignment_id = + l1pa_l1ps_com.transfer.aset->assignment_id; + + // Return status and CRC error (CRC error not applicable). + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status = SINGLE_UL_DONE; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = 0; + + // MSG is sent to L1A to stop PCCCH or CCCH/BCCH reading. + msg->SignalCode = L1P_SINGLE_BLOCK_CON; + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + + if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & (0x80 >> 0)) + // DL block received... + { + UWORD16 pwr_level; + +#if (L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif /*(L1_FF_MULTIBAND == 1)*/ + + // this bloc doesn't compute the burst input level, so the last_input_level is used. + +#if (L1_FF_MULTIBAND == 0) + + pwr_level = l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq].input_level; + +#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); + pwr_level = l1a_l1s_com.last_input_level[operative_radio_freq].input_level; + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + // Read L3 frame block and send msg to L1A. + l1s_read_l3frm(pwr_level, &(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]), task); + } + } + else + { + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + //---------------- + // Synchro back + //---------------- + // Save the "timeslot difference" between new and old configuration + // in "tn_difference". + // tn_difference -> loaded with the number of timeslot to shift. + // dl_tn -> loaded with the new timeslot. + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore - + l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.single_block.dl_tn_to_restore; + + // Select DSP Scheduler used in packet Idle (can be CCCH or PCCCH). + if((l1a_l1s_com.l1s_en_task[ALLC] == TASK_ENABLED) + || (l1a_l1s_com.l1s_en_task[NP] == TASK_ENABLED) + || (l1a_l1s_com.l1s_en_task[EP] == TASK_ENABLED)) + { + // We are in CS Idle on CCCH. + l1a_l1s_com.dsp_scheduler_mode = GSM_SCHEDULER; + } + + // Enable SYNCHRO task. + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + + //------------------ + // Confirmation msg + //------------------ + // Common part... + { + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_MPHP_SINGLE_BLOCK_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose = + l1pa_l1ps_com.transfer.aset->assignment_command; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->assignment_id = + l1pa_l1ps_com.transfer.aset->assignment_id; + + msg->SignalCode = L1P_SINGLE_BLOCK_CON; + + // Disable SINGLE task. + l1s.task_status[task].current_status = INACTIVE; + l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED; + } + + // Differentiated part... + + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == SINGLE_BLOCK_UL) + // SINGLE UL task is complete. + { + // Return status and CRC error (CRC error not applicable). + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status = SINGLE_UL_DONE; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = 0; + } + else + if(l1ps.read_param.allocated_tbf == SINGLE_BLOCK_DL) + // SINGLE DL task is complete. + { + API *info_address; + UWORD32 i,j; + UWORD32 word32; + + info_address = &(l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[0][0]); + + // Return status and CRC error + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status = SINGLE_DL_DONE; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->dl_error_flag = ((*info_address & 0x0100) >> 8); + + // Download data from API to message. + + // 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++) + { + word32 = info_address[4 + i]; // Get info word, rem: skip info. header. + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->data_array[j++] = (word32 & 0x000000ff); + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->data_array[j++] = (word32 & 0x0000ff00) >> 8; + } + } + + // send message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + } // End else (!TWO_PHASE_ACCESS) + } + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; + + } // End if(task enabled and semaphore false) + + else + // When the task is aborted, we must continue to make dummy + // DSP/TPU programming to avoid communication mismatch due + // to C/W/R pipelining. Dummy MCU/DSP reading is also done. + { + // 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 + +/*-------------------------------------------------------*/ +/* l1ps_read_pdtch() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_read_pdtch(UWORD8 task, UWORD8 burst_id) +{ + 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. + { + BOOL beacon; + T_INPUT_LEVEL *IL_info_ptr; + UWORD16 radio_freq; + WORD8 ts = 0; + UWORD8 bit_mask = 0x80; + WORD8 bcch_level; + UWORD8 rx_no = 0; + BOOL first_valid_block = TRUE; + BOOL crc_error = TRUE; + UWORD8 i; + UWORD32 best_snr = 0; + UWORD32 best_angle = 0; + UWORD32 best_pm = 0; + UWORD8 IL_for_rxlev[8], pr_table[8]; + WORD16 best_rxlev_accu = 0; + + + static BOOL crc_error_tbl[8] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}; + static WORD16 rxlev_accu[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + static WORD8 burst_level[4] = {(WORD8)0x80, (WORD8)0x80, (WORD8)0x80, (WORD8)0x80}; + static UWORD16 radio_freq_tbl[4]; + static UWORD32 toa_val[4] = {0, 0, 0, 0}; + static UWORD32 snr_val[4] = {0, 0, 0, 0}; + + #if TESTMODE + xSignalHeaderRec *msg; + static UWORD32 tm_pm_fullres = 0; + static UWORD32 tm_snr = 0; + static UWORD32 tm_toa = 0; + static WORD16 tm_angle = 0; + #endif + + + #define burst_number l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs + #define DL_pwr_ctrl l1pa_l1ps_com.transfer.dl_pwr_ctrl + + // Read parameters updating + // ************************* + + // *********** + // * WARNING * + // *********** + + // Because of the STI implementation, the parameters under the "l1pa_l1ps_com.transfer.aset" + // structure mustn't be used in the Read PDTCH functions + // This is due to the following case that may happen: + // + // C|W R | + // |C W R | + // | C W R| TBF 1 + // | C W|R <--------------------------- (2) This "read phase" must use the TBF 1 parameters while "aset" has already been updated + //---------------------- so the read_param structure is used + // | C|W R <------------------------- (3) The read_param is updated with TBF 2 parameters + // | |C W R at the beguining of the first Read of TBF 2 + // | | C W R TBF 2 so when (l1ps.read_param.new_set = TRUE and burst_id = BURST_1) + // | | C W R + // ^ + // (1) TBF 2 starting time detected on this frame (no SYNCHRO change needed between TBF1 and TBF 2) + // --> aset parameters updated to TBF 2 + // --> l1ps.read_param.new_set set to TRUE + + // If a new TBF has been enabled... + if (l1ps.read_param.new_set == TRUE) + { + // If it's the first Read phase of the block (first of the new TBF) + if (burst_id == BURST_1) + { + // Update the "read_param" structure + l1ps_update_read_set_parameters(); + } + } + + // Traces and debug. + // ****************** + + l1_check_com_mismatch(task); + + radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd; + + if(l1ps.read_param.pc_meas_chan) + { + radio_freq_tbl[burst_number] = radio_freq; + } + else + { + radio_freq_tbl[burst_number] = l1a_l1s_com.Scell_info.radio_freq; + } + + 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; + } + + // Call maca_power_control() in order to get TXPWR value + if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 2) + { + UWORD8 txpwr[8]; + UWORD8 i; + + // Due to the CWR pipeleine, maca_power_control() has to be called before the + // CTRL of the first PDTCH i.e. in l1ps_ctrl_pdtch(). It means that crc_error, + // radio_freq_tbl[], burst_level[] and bcch_level information are stored on + // burst4 of READ phase ("l1ps_ctrl_pdtch()") to be used on burst4 of CTRL phase. + + // Call Uplink Transmit Power level algorithm +#if 0 /* LoCosto version */ + maca_power_control(l1ps.read_param.assignment_id, +#else /* TCS211 reconstruction */ + maca_power_control(DL_pwr_ctrl.assignment_id, +#endif + DL_pwr_ctrl.crc_error, + DL_pwr_ctrl.bcch_level, + DL_pwr_ctrl.radio_freq_tbl, + DL_pwr_ctrl.burst_level, + txpwr); + + #if TESTMODE + if(!l1_config.TestMode) + #endif + { + for(i = 0; i < 8; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.txpwr[i] = txpwr[i]; + } + } + } + + + if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3) + /*---------------------------------------------------*/ + /* Complete PDTCH DL block has been processed by DSP */ + /*---------------------------------------------------*/ + { + #if (TRACE_TYPE == 5) // in simulation trace only the latest burst + trace_fct(CST_L1PS_READ_PDTCH, radio_freq); + #endif + + // Call MACS... + l1ps_macs_read(pr_table); + } + + // Update AGC and extract IL for RXLEV + //------------------------------------ + if (l1ps.read_param.dl_pwr_ctl.p0 == 255) + { + // No power control mode AGC algorithm + l1pctl_npc_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr); + } + else + { + // Downlink power control AGC algorithms + if (l1ps.read_param.dl_pwr_ctl.bts_pwr_ctl_mode == 0) + { + // BTS Power control mode A + l1pctl_dpcma_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table); + } + else + { + // BTS power control mode B + l1pctl_dpcmb_agc_read(IL_for_rxlev, l1ps_dsp_com.pdsp_db_r_ptr, l1ps_dsp_com.pdsp_ndb_ptr, pr_table); + } + } // End of "AGC algorithm" + + // TOA algorithm is called with toa/snr pair from last block (N-1) + // Feed TOA histogram with values from good bursts (crc_error = FALSE) + // otherwise input snr = 0. + #if (TOA_ALGO != 0) + // Good block, TOA from TS=0 + #if (TOA_ALGO == 2) + if(l1s.toa_var.toa_snr_mask == 0) + #else + if(l1s.toa_snr_mask == 0) + #endif + { + #if (TOA_ALGO == 2) + { + UWORD32 snr_temp; + snr_temp = (crc_error_tbl[0] == FALSE) ? snr_val[burst_id] : 0; + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa_val[burst_id]); + } + #else + { + /* FreeCalypso TCS211 reconstruction */ + if (crc_error_tbl[0] == FALSE) + { + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, + snr_val[burst_id], toa_val[burst_id], + &l1s.toa_update, &l1s.toa_period_count + #if (FF_L1_FAST_DECODING == 1) + ,0 + #endif + ); + } + else + { + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, + 0, toa_val[burst_id], + &l1s.toa_update, &l1s.toa_period_count + #if (FF_L1_FAST_DECODING == 1) + ,0 + #endif + ); + } + } + #endif + } + #endif + + /*---------------------------------------------------*/ + /* Read burst demodulation info for control algos */ + /* Use all burst results to feed the algos. */ + /*---------------------------------------------------*/ + while(ts < 8) + { + if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & bit_mask) + { + UWORD32 toa; + UWORD32 pm; + UWORD32 angle; + UWORD32 snr; + WORD8 rxlev; + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + toa = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_toa_gprs[ts] & 0xffff; + pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff)>>5; + angle = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_angle_gprs[ts] & 0xffff; + snr = l1ps_dsp_com.pdsp_db_r_ptr->a_burst_snr_gprs[ts] & 0xffff; + + #if (TRACE_TYPE != 0) && (TRACE_TYPE != 5) // for debug trace all bursts + trace_fct(CST_L1PS_READ_PDTCH_BURST, (UWORD32)(-1)); + #endif + + l1_check_pm_error(pm,task); + + #if TESTMODE + // Test mode stats + if (l1_config.TestMode) + { + if (bit_mask & l1_config.tmode.stats_config.stat_gprs_slots) + { + tm_pm_fullres += (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff); + tm_snr += snr; + tm_toa += toa; + tm_angle += (WORD16) angle; // signed + } + } + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_BURST(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts]) + #endif + #if 0 //(TRACE_TYPE == 1) || (TRACE_TYPE == 4) // TCS211 reconstruction + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts]); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, IL_for_rxlev[ts]); + #endif + + //Look for the pairs angle, snr with the maximum snr + if (snr > best_snr) + { + best_snr = snr; + best_angle = angle; + best_pm = pm; + } + + // store toa value from first TS + if (ts==0) + { + toa_val[burst_id] = toa; + snr_val[burst_id] = snr; + } + + // Store Received Signal Level to be used in Uplink Transmit Power Algorithm. + + // Compute RXLEV + rxlev = l1s_encode_rxlev(IL_for_rxlev[ts]); + + // Find first correct PDTCH, save RXLEV and CRC + if(!crc_error_tbl[ts] && first_valid_block) + { + if(l1ps.read_param.pc_meas_chan) + { + burst_level[burst_number] = rxlev; + } + else + { + burst_level[burst_number] = (WORD8)0x80; + } + + // Measures on first valid block have been performed. Reset flag. + first_valid_block = FALSE; + + // Save crc_error + crc_error = crc_error_tbl[ts]; + + } // End of measurements storage + + // If All PDTCH are incorrect (bad CRC) save RXLEV and CRC of the best PDTCH + if(first_valid_block) + { + rxlev_accu[ts] += rxlev; + + if(rxlev_accu[ts] > best_rxlev_accu) + { + best_rxlev_accu = rxlev_accu[ts]; + crc_error = crc_error_tbl[ts]; + + if(l1ps.read_param.pc_meas_chan) + { + burst_level[burst_number] = rxlev; + } + else + { + burst_level[burst_number] = (WORD8)0x80; + } + } + } + + // Determine first valid block to be used in next radio block + if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3) + /*---------------------------------------------------*/ + /* Complete PDTCH DL block has been processed by DSP */ + /*---------------------------------------------------*/ + { + crc_error_tbl[ts] = ((l1ps_dsp_com.pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100) >> 8); + + // Increment Rx burst number + rx_no++; + } + + #if TRACE_TYPE==3 + stats_samples_nb(toa,pm,angle,snr,burst_id,task); + #endif + + } // End of if(l1ps_dsp_com.pdsp_db_r_ptr->d_task_d_gprs & bit_mask) + + // Increment timeslot + ts++; + + // Shift Mask. + bit_mask >>= 1; + + } // End of while(ts < 8) + + // AFC control algorithm is called with values retrieved from + // burst with max. snr + // AFC algorithm is called on bursts 0 and 2: this is sufficient to + // have a correct behavior and this permits to gain CPU + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + #if TESTMODE + if (l1_config.afc_enable) + #endif + { + if((burst_id == 0) || (burst_id == 2)) + #if (VCXO_ALGO == 0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)best_angle, best_snr, radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)best_angle, best_snr, radio_freq,l1a_l1s_com.mode); + #endif + } + #endif + + #if (TRACE_TYPE == 1)||(TRACE_TYPE == 4) + if (trace_info.current_config->l1_dyn_trace & 1<> burst_id; + } + #endif + + if(l1ps_dsp_com.pdsp_db_r_ptr->d_burst_nb_gprs == 3) + /*---------------------------------------------------*/ + /* Complete PDTCH DL block has been processed by DSP */ + /*---------------------------------------------------*/ + { + + l1pa_l1ps_com.transfer.dl_pwr_ctrl.crc_error = crc_error; + /* + * FreeCalypso TCS211 reconstruction: the following line + * has been taken from the TSM30 source. + */ + l1pa_l1ps_com.transfer.dl_pwr_ctrl.assignment_id = l1ps.read_param.assignment_id; + + if(l1ps.read_param.pc_meas_chan) + { + + // Due to the CWR pipeleine, maca_power_control() has to be called before the + // CTRL of the first PDTCH i.e. in l1ps_ctrl_pdtch(). It means that crc_error, + // radio_freq_tbl[], burst_level[] and bcch_level information are stored on + // burst4 of READ phase to be used on burst4 of CTRL phase. + + l1pa_l1ps_com.transfer.dl_pwr_ctrl.bcch_level = (WORD8)0x80; + + for(i = 0; i < 4; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.radio_freq_tbl[i] = radio_freq_tbl[i]; + l1pa_l1ps_com.transfer.dl_pwr_ctrl.burst_level[i] = burst_level[i]; + } + + } + else + { + // Measures have been performed on BCCH Serving Cell. "burst_level" table is + // not applicable. + + // Download measures made on BCCH Serving Cell. + l1pa_l1ps_com.transfer.dl_pwr_ctrl.bcch_level = l1pa_l1ps_com.tcr_freq_list.beacon_meas; + + for(i = 0; i < 4; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.radio_freq_tbl[i] = radio_freq_tbl[i]; + l1pa_l1ps_com.transfer.dl_pwr_ctrl.burst_level[i] = (WORD8)0x80; + } + + // Measures on BCCH Serving Cell are only performed every 40ms while + // maca_power_control() is called every 20ms. "beacon_meas" must then + // be set to invalid (0x80) until next Serving Cell measure. + l1pa_l1ps_com.tcr_freq_list.beacon_meas = (WORD8)0x80; + + } + + #if TESTMODE + // Test mode stats + if (l1_config.TestMode) + { + // Allocate result message. + msg = os_alloc_sig(sizeof(T_TMODE_PDTCH_INFO)); + DEBUGMSG(status,NU_ALLOC_ERR) + msg->SignalCode = TMODE_PDTCH_INFO; + + ((T_TMODE_PDTCH_INFO *)(msg->SigP))->pm_fullres = tm_pm_fullres; // F26.6 + ((T_TMODE_PDTCH_INFO *)(msg->SigP))->snr = tm_snr; + ((T_TMODE_PDTCH_INFO *)(msg->SigP))->toa = tm_toa; + ((T_TMODE_PDTCH_INFO *)(msg->SigP))->angle = tm_angle; // signed + for (i=0;i<8;i++) + ((T_TMODE_PDTCH_INFO *)(msg->SigP))->crc_error_tbl[i] = crc_error_tbl[i]; + + // send TMODE_TCH_INFO message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // reset static TM variables for stats collection + tm_pm_fullres = 0; + tm_snr = 0; + tm_toa = 0; + tm_angle = 0; + } + #endif + } + + } //end of test "if((en_task) && !(task_param))" + + // End of task -> task must become INACTIVE. + // PDTCH can be pipelined and therefore must stay active if + // it has already reentered the flow. + if(burst_id == BURST_4) + { + 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 0 /* FreeCalypso TCS211 reconstruction */ + l1ddsp_read_iq_dump(task); + #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; +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +/*-------------------------------------------------------*/ +/* l1ps_read_pra_result() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_read_pra_result(UWORD8 task, UWORD8 burst_id) +{ + /*--------------------------------------------------------*/ + /* READ TRANSMIT TASK RESULTS... */ + /*--------------------------------------------------------*/ + + /*---------------------------------------------------*/ + /* Packet Access task. */ + /*---------------------------------------------------*/ + // Rem: confirmation message is sent at "CTRL" to be able to give FN%42432. + BOOL confirm_flag = TRUE; // Default is: confirmation message is sent. + + // Desactivate the PRACH task. + l1s.task_status[task].current_status = INACTIVE; + + l1_check_com_mismatch(task); + + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_PRA, l1pa_l1ps_com.p_idle_param.radio_freq); + #endif + + #if FF_L1_IT_DSP_USF + // Check PRACH was controlled + if (l1pa_l1ps_com.pra_info.prach_controlled) + { + #endif + + // Check USF in case of Dynamic Allocation. + if(l1pa_l1ps_com.pra_info.prach_alloc != FIX_PRACH_ALLOC) + { + API cs_type = l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][0]; + + if(cs_type != CS_NONE_TYPE) + confirm_flag = FALSE; + } + + if (confirm_flag == TRUE) + { + // 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_MPHP_RA_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + ((T_MPHP_RA_CON *)(msg->SigP))->fn = l1pa_l1ps_com.pra_info.fn_to_report; + ((T_MPHP_RA_CON *)(msg->SigP))->channel_request_data = l1pa_l1ps_com.pra_info.channel_request_data; + msg->SignalCode = L1P_RA_DONE; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + } + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; + + #if FF_L1_IT_DSP_USF + } // if (l1pa_l1ps_com.pra_info.prach_controlled) + #endif +} + +/*-------------------------------------------------------*/ +/* l1ps_read_poll_result() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_read_poll_result(UWORD8 task, UWORD8 burst_id) +{ + /*--------------------------------------------------------*/ + /* READ TRANSMIT TASK RESULTS... */ + /*--------------------------------------------------------*/ + + l1_check_com_mismatch(task); + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) // in debug trace all reads + trace_fct(CST_L1PS_READ_POLL, l1pa_l1ps_com.p_idle_param.radio_freq); + #endif + + /*--------------------------------------------------------*/ + /* POLL task (4xPRACH) upon packet queueing notification. */ + /*--------------------------------------------------------*/ + + // Deactivate the PRACH task. + if(burst_id == BURST_4) + { + // POLL is a 'one shot' task --> disable task + l1a_l1s_com.l1s_en_task[task] = TASK_DISABLED; + + l1s.task_status[task].current_status = INACTIVE; + + #if (TRACE_TYPE==5) // in simulation trace only the latest burst + trace_fct(CST_L1PS_READ_POLL, l1pa_l1ps_com.p_idle_param.radio_freq); + #endif + + // Send confirmation msg to L1A. + // ****************************** + // For PACKET POLLING, a confirmation msg is sent to L1A. + { + xSignalHeaderRec *msg; + + // send L1C_RA_DONE to L1A... + msg = os_alloc_sig(sizeof(T_MPHP_POLLING_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + + ((T_MPHP_POLLING_IND *)(msg->SigP))->fn = l1pa_l1ps_com.poll_info.fn_to_report; + msg->SignalCode = L1P_POLL_DONE; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + } + + #if 0 /* FreeCalypso TCS211 reconstruction */ + l1ddsp_read_iq_dump(task); + #endif + // 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 == 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 + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_snb_dl() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* packet serving cell normal burst reading tasks: PNP, */ +/* PEP, PALLC. This function is the control function for */ +/* reading a normal burst on the packet serving cell. */ +/* It programs the DSP and the TPU for reading a */ +/* normal burst. This function flags the reading of the */ +/* Packet Normal paging burst which flag is used in */ +/* measurement manager procedure. */ +/* Here below 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 Packet Normal Paging */ +/* burst. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "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. */ +/* */ +/* "task" */ +/* PNP, Packet Normal paging reading task. */ +/* PEP, Packet Extended paging reading task. */ +/* PALLC, All Packet serving cell PCCCH 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.Scell_info" */ +/* Serving cell information structure. */ +/* .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 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: */ +/* --------------------------------- */ +/* "pnp_ctrl" */ +/* Flag set when a packet normal paging burst reading */ +/* is controled. This flag is used by the packet */ +/* measurement manager procedure, at the end of L1S, */ +/* in order to scheduling the neighbor cell */ +/* measurements. */ +/* -> set to 1. */ +/* */ +/* */ +/* "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 l1ps_ctrl_snb_dl(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 Scell_radio_freq; + UWORD8 tsc; + WORD8 agc; + UWORD8 lna_off; + UWORD8 adc_active = INACTIVE; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; + #endif + + #if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag = 0; + #endif /* NEW_SNR_THRESHOLD */ + + +#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. + { + Scell_radio_freq = l1a_l1s_com.Scell_info.radio_freq; + + // Catch training sequence code from serving cell BCC (part of BSIC). + tsc = l1pa_l1ps_com.pccch.packet_chn_desc.tsc; + + // Packet PAGC Algorithm + // ********************** + + // for PCCCH serving blocks (PPCH, PEPCH, all PCCCH) we use + // PAGC algorithm. Reference is serving cell. + l1pctl_pagc_ctrl(&agc, &lna_off, l1pa_l1ps_com.p_idle_param.radio_freq,TRUE); + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL.input_level, + l1pa_l1ps_com.p_idle_param.radio_freq, if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // the function l1pctl_pagc_ctrl + 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 + + // Debug. + // ****************** + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; +#if (FF_L1_FAST_DECODING == 1) + l1ddsp_load_fast_dec_task(task,burst_id); +#endif + + // Programs DSP Rx Packet Idle burst, still on Timeslot number = 0 + // due to previous synchro. + #if FF_L1_IT_DSP_USF + { + BOOL usf_it = FALSE; + + // Force IT USF interrupt during PCCCH reorg for Fast USF usage during + // Packet Access. Switch to PA could happen any time during PCCCH reorg. + // Only relevant for RBN%3 = 0 and 1 + if (l1a_l1s_com.l1s_en_task[PALLC] == TASK_ENABLED) + { + if (/*(l1s.next_time.fn_mod13 >= 0) && omaps00090550*/(l1s.next_time.fn_mod13 <= 7)) + usf_it = TRUE; + } + + l1pddsp_idle_rx_nb(burst_id, tsc, l1pa_l1ps_com.p_idle_param.radio_freq, 0, FALSE, usf_it); + } + #else + l1pddsp_idle_rx_nb(burst_id, tsc, l1pa_l1ps_com.p_idle_param.radio_freq, 0, FALSE); + #endif + + // ADC measurement + // *************** + // check if during the 1st burst of the bloc an ADC measurement must be performed + if ((burst_id == BURST_1) && (task == PNP)) + { + if (l1a_l1s_com.l1s_en_task[PALLC] == TASK_DISABLED) // no reorg mode + { + if (l1a_l1s_com.adc_mode & ADC_NEXT_NORM_PAGING) // perform ADC only one time + { + adc_active = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_IDLE; // reset in order to have only one ADC measurement in Idle + } + else + { + if (l1a_l1s_com.adc_mode & ADC_EACH_NORM_PAGING) // perform ADC on each "period" x bloc + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_idle_period) // wait for the period + { + adc_active = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + } + } + else // ADC measurement in reorg mode + { + if (l1a_l1s_com.adc_mode & ADC_NEXT_NORM_PAGING_REORG) // perform ADC only one time + { + adc_active = ACTIVE; + l1a_l1s_com.adc_mode &= ADC_MASK_RESET_IDLE; // reset in order to have only one ADC measurement in Idle + } + else + { + if (l1a_l1s_com.adc_mode & ADC_EACH_NORM_PAGING_REORG) // perform ADC on each "period" x bloc + if ((++l1a_l1s_com.adc_cpt)>=l1a_l1s_com.adc_idle_period) // wait for the period + { + adc_active = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + } + } + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_SNB_DL, -1); + #endif + + // Programs TPU for required task. + // ******************************** + + // update the TPU with the new TOA if necessary + l1ctl_update_TPU_with_toa(); + + // tpu pgm... + l1dtpu_serv_rx_nb(l1pa_l1ps_com.p_idle_param.radio_freq, + agc, + lna_off, + l1s.tpu_offset, + l1s.tpu_offset, + FALSE,adc_active + #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 the reading of a Normal Packet Paging burst. + // ************************************************* + + // Set PNP controlled flag, used in l1s_meas_manager() to generate measurement only + // if we are not receiving a PPCH. + if((task == PNP) || (task == PEP) || (task == PALLC)) + l1pa_l1ps_com.cr_freq_list.pnp_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; + +} // end of procedure + +/*-------------------------------------------------------*/ +/* l1ps_read_nb_dl() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: PNP,PEP,PALLC. */ +/* */ +/* 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" */ +/* PNP, Packet Normal paging reading task. */ +/* PEP, Packet Extended paging reading task. */ +/* PALLC, All packet serving cell PCCCH 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: */ +/* ------------------------------ */ +/* "l1pa_l1ps_com.task_param[NBR_DL_L1S_TASKS]" */ +/* packet task semaphore table. 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[NBR_DL_L1S_TASKS]" */ +/* L1S task enable. */ +/* */ +/* 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 l1ps_read_nb_dl(UWORD8 task, UWORD8 burst_id) +{ + UWORD32 toa=0; //omaps00090550 + UWORD32 pm=0; //omaps00090550; + UWORD32 angle =0; //omaps00090550 + UWORD32 snr =0; //omaps00090550 + BOOL en_task; + BOOL task_param; + UWORD16 scell_radio_freq; + static UWORD16 pwr_level; + +#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. + // ****************** + l1_check_com_mismatch(task); + + // Read control results and feed control algorithms. + // ************************************************** + if ((task != PBCCHN_TRAN) && (task != PBCCHN_IDLE)) + { + // From the fact that PBCCHS can be read in CS mode, + // Idle mode and Packet Idle mode, a check on the current active DSP scheduler mode + // has to be performed. + // Read control information. + // We keep compatibility with (chipset == 0) imply mask with 0xffff. + // If only (chipset == 2) is used, mask can be removed. + 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) >> 5; + 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)>>5; + 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; + } + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_READ_NB_DL, -1); + #endif + + l1_check_pm_error(pm,task); + + // Update AGC: Call PAGC algorithm + l1a_l1s_com.Scell_IL_for_rxlev = l1pctl_pagc_read((UWORD8)pm, l1pa_l1ps_com.p_idle_param.radio_freq_dd); + +#if (FF_L1_FAST_DECODING == 1) + if (skipped_bursts>0) + { + l1ctl_pagc_missing_bursts(skipped_bursts); + } +#endif /* if (FF_L1_FAST_DECODING == 1) */ + + // Update AFC: Call AFC control function (KALMAN filter). + #if AFC_ALGO + { + WORD16 old_afc = l1s.afc; + WORD16 old_count= l1s.afc_frame_count; + + scell_radio_freq = l1a_l1s_com.Scell_info.radio_freq; + #if (VCXO_ALGO==0) + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, scell_radio_freq); + #else + l1s.afc = l1ctl_afc(AFC_CLOSED_LOOP, &l1s.afc_frame_count, (WORD16)angle, snr, scell_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 + #endif + } + #endif + + // Feed TOA histogram only when the TOA result is used in the task CTRL function + if (task != PBCCHS) + { + //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 + { + #if (TOA_ALGO == 2) + UWORD32 snr_temp; + snr_temp = (l1a_l1s_com.Scell_IL_for_rxlev < IL_FOR_RXLEV_SNR) ? snr: 0; + l1s.toa_var.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr_temp, toa); + #else + /* FreeCalypso TCS211 reconstruction */ + if (l1a_l1s_com.Scell_IL_for_rxlev < IL_FOR_RXLEV_SNR) + { + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, snr, toa, + &l1s.toa_update, + &l1s.toa_period_count + #if (FF_L1_FAST_DECODING == 1) + ,0 + #endif + ); + } + else + { + l1s.toa_shift = l1ctl_toa(TOA_RUN, l1a_l1s_com.mode, 0, 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, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb) + #endif + #if 0 //(TRACE_TYPE == 1) || (TRACE_TYPE == 4) // TCS211 reconstruction + l1_trace_burst_param(angle, snr, l1s.afc, task, pm, toa, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb); + #endif + #if (BURST_PARAM_LOG_ENABLE == 1) + l1_log_burst_param(angle, snr, l1s.afc, task, pm, toa, l1a_l1s_com.Scell_IL_for_rxlev + l1a_l1s_com.Scell_info.pb); + #endif + // compute the Data bloc Power. + // ****************************** + if(burst_id == BURST_1) + pwr_level = 0; + + // add the burst power + pwr_level += l1a_l1s_com.Scell_IL_for_rxlev; + + + // Read downlink DATA block from MCU/DSP interface. + // ************************************************* + #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 */ + { + #if (TRACE_TYPE==2 ) || (TRACE_TYPE==3) + uart_trace(task); + #endif +#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*/ + + // Read L3 frame block and send msg to L1A. +#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 (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); + + } // End if... + + } //end of test "if((en_task) && !(task_param))" + + // Disactivate task. + // ****************** + + // End of task -> task must become INACTIVE. + // Rem: some TASKS (PALLC, PNP (with SPLIT > M)) can be pipelined and therefore + // must stay active if they have already reentered the flow. +#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 /* #if (FF_L1_FAST_DECODING == 1) #else*/ + { +#if (FF_L1_FAST_DECODING == 1) + if(task == PNP) + { + 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; + } + } /*task == PNP */ +#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) + { + 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) */ + } + + #if 0 /* FreeCalypso TCS211 reconstruction */ + l1ddsp_read_iq_dump(task); + #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; + +} // end of procedure + +//#pragma GSM_IDLE_DUPLICATE_FOR_INTERNAL_RAM_END // KEEP IN EXTERNAL MEM otherwise +#endif +/*-------------------------------------------------------*/ +/* l1ps_ctrl_pbcch() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* tasks: neighbor cell PBCCH. */ +/* This function is the control function */ +/* for reading a PBCCH burst on the neighbor cell. */ +/* This control function: */ +/* a) shifts the OFFSET register to match the normal */ +/* burst received task with the PBCCH timeslot number.*/ +/* */ +/* b) programs a normal burst reading and restores the */ +/* OFFSET to the serving cell timeslot. On the last */ +/* control (4th burst), the SYNCHRO/OFFSET registers */ +/* are shifted back to the normal idle mode PCCH */ +/* reading setting. Here is a summary of the */ +/* execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Programs DSP for PBCCH task, reading 1 burst. */ +/* - Programs TPU for PBCCH task, reading 1 burst. */ +/* - Shift TPU SYNCHRO/OFFSET registers back to the */ +/* PACKET PAGING TASK timeslot. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* "task" */ +/* PBCCH_TRA or PBCCH_IDLE or PBCCHS */ +/* Serving Cell PBCCH reading task. */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1pa_l1ps_com.pbcch " */ +/* Neigh/serv Cell PBCCH description structure. */ +/* */ +/* "l1a_l1s_com.Scell_info.radio_freq" */ +/* BSIC of the serving cell. It is used here to pass */ +/* the training sequence number (part of BSIC) to the */ +/* DSP. */ +/* */ +/* "l1a_l1s_com.offset_tn0" */ +/* value to load in the OFFSET register to shift then */ +/* any receive task to the timeslot 0 of the neighbor */ +/* cell or PBCCH timeslot number . */ +/* */ +/* "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 PBCCH 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 l1ps_ctrl_pbcch(UWORD8 task, UWORD8 burst_id) +{ + UWORD16 rx_radio_freq; + UWORD32 offset_pbcch; + WORD8 agc; + UWORD8 lna_off; + UWORD32 dsp_task; + UWORD8 tsc; + UWORD8 serving_cell; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb=0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + // By default we choose the hardware filter + UWORD8 csf_filter_choice = L1_SAIC_HARDWARE_FILTER; + #endif + #if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; + #endif /* NEW_SNR_THRESHOLD */ + static WORD32 new_tpu_offset; + static BOOL change_synchro; + + #define PbcchS l1pa_l1ps_com.pbcchs + #define PbcchN l1pa_l1ps_com.pbcchn + + #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 (task == PBCCHS) + { + tsc = PbcchS.packet_chn_desc.tsc; + offset_pbcch = (PbcchS.tn_pbcch * TN_WIDTH); + serving_cell = TRUE; + } + else + { + tsc = PbcchN.packet_chn_desc.tsc; + offset_pbcch = PbcchN.time_alignmt; + serving_cell = FALSE; + } + + 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 = l1pa_l1ps_com.p_idle_param.radio_freq; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[task].name); + #endif + + #if (TRACE_TYPE!=0) + if (task == PBCCHS) + trace_fct(CST_L1PS_CTRL_PBCCHS, l1a_l1s_com.Scell_info.radio_freq); + else + trace_fct(CST_L1PS_CTRL_PBCCHN, PbcchN.bcch_carrier); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + // Programs DSP for PBCCHN task according to the DSP scheduler used + // ***************************************************************** + 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,tsc); + break; + + // dsp pgm is made using GPRS scheduler... + case GPRS_SCHEDULER: + #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; + } + + // Check if "Synchro" change is needed. + // ************************************* + // If so the synchro is changed by 4 timeslots. + if(burst_id == BURST_1) + { + if (task == PBCCHS) + change_synchro = PbcchS.change_synchro; + else + change_synchro = PbcchN.change_synchro; + + 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(SWITCH_TIME, new_tpu_offset); + } + else + { + new_tpu_offset = l1s.tpu_offset; + } + } + + // TPU pgm... + //----------- + offset_pbcch += new_tpu_offset; + if (offset_pbcch >= TPU_CLOCK_RANGE) + offset_pbcch -= TPU_CLOCK_RANGE; + + // add for debug TPU simu + #if (CODE_VERSION == SIMULATION) + if (task == PBCCHS) // PBCCH serving, compute Ts related to the L1 synchro on the serving + hw.rx_id[tpu_w_page][0]=((TPU_CLOCK_RANGE-new_tpu_offset+offset_pbcch)%TPU_CLOCK_RANGE)/TN_WIDTH; + else // PBCCH Neighbor -> special value for PBCCHN detection in the DSP task + hw.rx_id[tpu_w_page][0]=10; + #endif + + // agc is set with the input_level computed from PAGC algo + l1pctl_pagc_ctrl(&agc, &lna_off, rx_radio_freq, serving_cell); + +#if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL.input_level , rx_radio_freq, if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); +#endif + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // l1pctl_pagc_ctrl + if(task == PBCCHS) + { + // Call SAIC only for PBCCHS, not for PBCCHN_TRAN or PBCCHN_IDLE + 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 + + l1dmacro_offset (offset_pbcch, l1_config.params.rx_change_offset_time); // Slide offset to cope with PBCCHN in the new sychro. + l1dmacro_rx_synth(rx_radio_freq); // load SYNTH. + l1dmacro_agc (rx_radio_freq,agc, lna_off + #if(RF_FAM == 61) + ,if_ctl + #endif + ); // load AGC. +#if (L1_MADC_ON == 1) +#if (RF_FAM == 61) + l1dmacro_rx_nb (rx_radio_freq,INACTIVE, csf_filter_choice +#if (NEW_SNR_THRESHOLD == 1) + ,saic_flag +#endif /* NEW_SNR_THRESHOLD */ + ); // RX window for NB. +#endif /* RF_FAM == 61*/ +#else /* L1_MADC_ON == 1*/ + l1dmacro_rx_nb (rx_radio_freq); // RX window for NB. +#endif + + if (task == PBCCHS) + { + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + l1ddsp_load_afc(l1s.afc); // Loading the afc value in DB,Flag the presence of a new afc value to send + #endif + #if (RF_FAM == 61) + l1dtpu_load_afc(l1s.afc); + #endif + } + l1dmacro_offset (new_tpu_offset, IMM); // Restore offset. + } // 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 PCCCH one). + // ************************************************************************************** + // When the PBCCHN or PBCCHS reading control is completed , + // the SYNCHRO/OFFSET registers are shifted back to the normal idle + // 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) + { + // 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; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + trace_fct(CST_L1S_ADJUST_TIME, -1); + #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. + if((burst_id == BURST_1) && (task != PBCCHN_IDLE)) + { + // In PBCCHN_IDLE task, l1s.forbid_meas is set by the AGC ctrl + 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 + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_ptcch() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_ctrl_ptcch(UWORD8 param1, UWORD8 param2) +{ + UWORD16 radio_freq; + UWORD8 burst_nb; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_nb = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + #endif + #if (NEW_SNR_THRESHOLD == 1) + UWORD8 saic_flag=0; + #endif /* NEW_SNR_THRESHOLD*/ + + if(!(l1a_l1s_com.task_param[PTCCH] == 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. + { + WORD8 ts; + + radio_freq = l1pa_l1ps_com.transfer.ptcch.radio_freq; + + // Traces and debug. + // ****************** + #if (TRACE_TYPE!=0) + if(l1pa_l1ps_com.transfer.ptcch.activity && (PTCCH_DL || PTCCH_UL ) == 0) // trace only if a window is programmed. + trace_fct(CST_L1PS_CTRL_PTCCH_EMPTY, radio_freq); + #endif + + #if (TRACE_TYPE==5) && FLOWCHART + trace_flowchart_dsp_tpu(dltsk_trace[PTCCH].name); + #endif + + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + switch (l1s.next_time.fn_mod104) + { + case 12: burst_nb=0; break; + case 38: burst_nb=1; break; + case 64: burst_nb=2; break; + case 90: burst_nb=3; break; + default: burst_nb=0; break; + } + + // Compute timeslot number referenced to current camp timeslot. + ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn; + if(ts < 0) ts += 8; + else if(ts >= 8) ts -= 8; + + if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL) + // PTCCH DL activity bit is set: PTCCH DL programmation is required. + { + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_CTRL_PTCCH_DL_BURST0 + burst_nb, radio_freq); + #endif + + // Programs DSP for PTCCH/DL. + // *************************** + { + #if FF_L1_IT_DSP_USF + l1pddsp_idle_rx_nb(burst_nb, + l1pa_l1ps_com.transfer.aset->tsc, + radio_freq, + ts, + TRUE, + FALSE); + #else + l1pddsp_idle_rx_nb(burst_nb, + l1pa_l1ps_com.transfer.aset->tsc, + radio_freq, + ts, + TRUE); + #endif + } + + + // Programs TPU for PTCCH/DL task. + // ******************************** + { + WORD8 agc; + UWORD8 lna_off; + + // AGC updating + //------------- + l1pctl_pagc_ctrl(&agc, &lna_off, radio_freq,TRUE); + + #if(RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_nb, &if_ctl, (UWORD8) L1_IL_VALID, + l1a_l1s_com.Scell_used_IL.input_level , radio_freq, if_threshold); + l1ddsp_load_dco_ctl_algo_nb(dco_algo_ctl_nb); + #endif + + #if (L1_SAIC != 0) + // If SAIC is enabled, call the low level SAIC control function + // NOTE: l1a_l1s_com.Scell_used_IL.input_level is updated within + // the function l1pctl_pagc_ctrl + l1ctl_saic(l1a_l1s_com.Scell_used_IL.input_level,l1a_l1s_com.mode + #if (NEW_SNR_THRESHOLD == 1) + ,PTCCH + ,&saic_flag + #endif + ); + #endif + + // Compute timeslot number referenced to current camp timeslot. + // Rem: COULD BE DONE ASYNCHRONOUSLY changing ta_tn definition!!! + ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn; + if(ts < 0) ts += 8; + else if(ts >= 8) ts -= 8; + + // Program RX Normal Burst scenario. + l1pdtpu_serv_rx_nb(radio_freq, + agc, + lna_off, + ts, + l1s.tpu_offset, + 1, + 1, + TRUE,INACTIVE + #if(RF_FAM == 61) + ,L1_SAIC_HARDWARE_FILTER + ,if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /* NEW_SNR_THRESHOLD */ + ); + + // Set "CTRL_RX" flag in the controle flag registers. + l1s.tpu_ctrl_reg |= CTRL_RX; + l1s.dsp_ctrl_reg |= CTRL_RX; + } + } + + if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_UL) + // PTCCH UL activity bit is set: PTCCH UL programmation required. + { + UWORD8 adc_active = INACTIVE; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_CTRL_PTCCH_UL, radio_freq); + #endif + + // Programs DSP for PTCCH/UL. + // *************************** + { + UWORD8 cs_type; + UWORD16 ptcch_ul_data; + + // Access burst type ? + if (l1pa_l1ps_com.access_burst_type == ACC_BURST_8) + { + // PRACH 8 bits: data = (0111 1111)b + cs_type = CS_PAB8_TYPE; + ptcch_ul_data = 0x7F; + } + else + { + // PRACH 11 bits: data = (111 1111 1111)b + cs_type = CS_PAB11_TYPE; + ptcch_ul_data = 0x7FF; + } + + // "As" IDLE POLLING PRACH dsp control. + l1pddsp_ul_ptcch_data(cs_type, + ptcch_ul_data, + l1a_l1s_com.Scell_info.bsic, + radio_freq, + ts+3); + + l1pddsp_idle_prach_power(l1s.applied_txpwr, + radio_freq, + ts+3); + } + + // 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 = 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 = ACTIVE; + l1a_l1s_com.adc_cpt = 0; + } + } + // Programs TPU for PTCCH/UL task. + // ******************************** + { + // Program TX RA scenario. + l1pdtpu_serv_tx(radio_freq, + 0, // TA=0. + l1s.tpu_offset, + ts+3, // tx_id. + 1, // 1 PRACH. + 1, // tx_group_id. + 0, // No switch NB->RA + 1, // Driver called for PRACH Burst. + l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL,adc_active); + // Flag RX in same frame as TX + } + + // PTCCH/UL has been executed, + // -> PTCCH/DL is then requested for schedule. + // -> PTCCH/UL activity flag must be reset. + l1pa_l1ps_com.transfer.ptcch.request_dl = TRUE; + l1pa_l1ps_com.transfer.ptcch.activity ^= PTCCH_UL; + + // Set "CTRL_TX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_TX; + l1s.dsp_ctrl_reg |= CTRL_TX; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_UL_AB(PTCCH,l1s.applied_txpwr) + #endif + + } // End of PTCCH UL programmation + } // End of if(...semaphore...) + + // 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[PTCCH].size; +} +//#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_ptcch() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* */ +/* Modified parameters from globals: */ +/* --------------------------------- */ +/* */ +/*-------------------------------------------------------*/ +void l1ps_read_ptcch(UWORD8 param1, UWORD8 param2) +{ + // Traces and debug. + // ****************** + + l1_check_com_mismatch(PTCCH); + + if(l1pa_l1ps_com.transfer.ptcch.activity & PTCCH_DL) + // PTCCH/DL has been executed, + { + UWORD32 pm; + WORD8 ts; + + // Compute timeslot number referenced to current camp timeslot. + ts = l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn - l1a_l1s_com.dl_tn; + if(ts < 0) ts += 8; + else if(ts >= 8) ts -= 8; + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_PTCCH_DL, l1pa_l1ps_com.transfer.ptcch.radio_freq); + #endif + + // Read control results and feed control algorithms. + // ************************************************** + + // Read control information. + pm = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff) >> 5; + l1_check_pm_error(pm,PTCCH); + + if(l1s.actual_time.fn_mod104 == 91) + // Read PTCCH/DL data block from DSP/MCU interface, a_dd_md_gprs[]. + { + BOOL crc; + UWORD8 ordered_ta; + + crc = (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[0] & 0x0100) >> 8; + + if(!crc) + // Block correct, we extract new TA... + { + UWORD8 word_position = 4+ (l1pa_l1ps_com.transfer.aset->packet_ta.ta_index >> 1); + UWORD8 byte_position = l1pa_l1ps_com.transfer.aset->packet_ta.ta_index & 0x01; + + // Download ordered TA... + // IF byte_position + // Upper byte contains TA... + // ELSE + // Lower byte contains TA... + // (see GSM04.04) + + ordered_ta = (l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[word_position] >> (8*byte_position)) & 0x7f; + + if (ordered_ta < 64) + { + // PTCCH/DL contains a valid TA for MS: update TA + l1pa_l1ps_com.transfer.aset->packet_ta.ta = ordered_ta; + + // PTCCH/DL activity bit must reset when new TA has been successfully received. + l1pa_l1ps_com.transfer.ptcch.activity ^= PTCCH_DL; + } + } + + #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) + if (trace_info.current_config->l1_dyn_trace & 1<packet_ta.ta_index, + l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn, + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[4], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[5], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[6], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[7], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[8], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[9], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[10], + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[11]); + } + #endif + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_DL_PTCCH(crc, ordered_ta) // Replace with ordered TA + #endif + + // Reset CS type. + l1ps_dsp_com.pdsp_ndb_ptr->a_dd_md_gprs[0] = CS_NONE_TYPE; + } + } + else + { + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_PTCCH_UL, l1pa_l1ps_com.transfer.ptcch.radio_freq); + #endif + } + + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; + + // End of task -> task must become INACTIVE. + l1s.task_status[PTCCH].current_status = INACTIVE; +} +//#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 + +/*-------------------------------------------------------*/ +/* l1ps_ctrl_itmeas() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is a "COMPLEX" function used by the L1S */ +/* task ITMEAS. */ +/* This function is the control function for measuring */ +/* the signal strength on several specified timeslots (on*/ +/* which it's possible according to the multi-slot class)*/ +/* of an indicated carrier. */ +/* It programs the DSP and the TPU for doing these */ +/* measurements */ +/* Here below is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low. */ +/* - Traces and debug. */ +/* - Determines on which timeslots measurements can */ +/* be done */ +/* - Programs DSP for required task. */ +/* - Programs TPU for required task. */ +/* - Flag DSP and TPU programmation. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1pa_l1ps_com.itmeas" */ +/* Interference measurement parameters structure */ +/* */ +/* "l1a_l1s_com.dl_tn" */ +/* Timeslot on which L1 is synchronized */ +/* */ +/* "l1pa_l1ps_com.transfer.aset->multislot_class" */ +/* Multi-slot class in Packet transfer */ +/* */ +/* 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 l1ps_ctrl_itmeas(UWORD8 param1, UWORD8 param2) +{ + +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_pw = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; + UWORD8 ts = 0; +#endif + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE==5) + trace_fct(CST_L1PS_CTRL_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq); + #endif + + // Timeslots selection + // ******************** + + // Packet transfer mode <-> PDTCH task enabled: condition to check !!!! + //--------------------- + + // Timeslots already selected in l1p_asyn.c + + // Packet idle mode + //----------------- + if (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_DISABLED) + { + // If a RX has been programmed on this frame + if (l1s.dsp_ctrl_reg & CTRL_RX) + { + // The pre-processed bitmap with Rx taken into account is taken + l1pa_l1ps_com.itmeas.meas_bitmap = l1pa_l1ps_com.itmeas.idle_tn_rx; + } + else + { + // The pre-processed bitmap without Rx taken into account is taken + l1pa_l1ps_com.itmeas.meas_bitmap = l1pa_l1ps_com.itmeas.idle_tn_no_rx; + } + + } // End if 'packet idle mode' + + l1pa_l1ps_com.itmeas.dsp_r_page_switch_req = FALSE; + + // If some measurements can be done + if (l1pa_l1ps_com.itmeas.meas_bitmap != 0) + { + UWORD8 nbmeas; + + // DSP read page switched or not during the ITMEAS read phase ? + + if (l1s.dsp_ctrl_reg == NO_CTRL) + { + // A control task hasn't already been done in this frame --> Read page switch + l1pa_l1ps_com.itmeas.dsp_r_page_switch_req = TRUE; + } + + // Traces and debug. + // ****************** + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_L1PS_CTRL_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq); + #endif + + +#if(RF_FAM == 61) // Locosto DCO + #if (PWMEAS_IF_MODE_FORCE == 0) + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw, &if_ctl, (UWORD8) L1_IL_INVALID , + 0, l1pa_l1ps_com.itmeas.radio_freq, if_threshold); + #else + if_ctl = IF_120KHZ_DSP; + dco_algo_ctl_pw = DCO_IF_0KHZ; + #endif + + + +#endif + + // Program TPU + // ************ +#if (RF_FAM != 61) + nbmeas = l1pdtpu_interf_meas(l1pa_l1ps_com.itmeas.radio_freq, + l1_config.params.high_agc, + 0, + l1pa_l1ps_com.itmeas.meas_bitmap, + l1s.tpu_offset, + l1s.tpu_win, + l1a_l1s_com.dl_tn); +#endif + +#if (RF_FAM == 61) + nbmeas = l1pdtpu_interf_meas(l1pa_l1ps_com.itmeas.radio_freq, + l1_config.params.high_agc, + 0, + l1pa_l1ps_com.itmeas.meas_bitmap, + l1s.tpu_offset, + l1s.tpu_win, + l1a_l1s_com.dl_tn, + if_ctl); +#endif + + + // Program DSP + // ************ + + l1pddsp_interf_meas_ctrl(nbmeas); + +#if(RF_FAM == 61) // TBD + // Reproduce the DCO control for all the power measurement + dco_algo_ctl_pw = dco_algo_ctl_pw * 0x55; // Replicate ZLZLZLZL + dco_algo_ctl_pw = dco_algo_ctl_pw >> (2*(4 - nbmeas)); // reduce to ZLs of Nbr + if(l1s.tcr_prog_done==1) + { + dco_algo_ctl_pw=((dco_algo_ctl_pw<<2)|(l1s_dsp_com.dsp_db_common_w_ptr->d_dco_algo_ctrl_pw&0x3)); + } + l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw); + // of Meas Programmed +#endif + // Flag DSP and TPU programmation. + // ******************************** + + // Set "CTRL_RX" flag in the controle flag register. + l1s.tpu_ctrl_reg |= CTRL_MS; + l1s.dsp_ctrl_reg |= CTRL_MS; + + } // End if 'nbmeas != 0' + + // 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. + l1s.forbid_meas = TASK_ROM_MFTAB[ITMEAS].size; +} +//#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 + +/*-------------------------------------------------------*/ +/* l1ps_read_itmeas() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* */ +/* This function is a "COMPLEX" function used for the */ +/* L1S ITMEAS task. */ +/* */ +/* Here is a summary of the execution: */ +/* */ +/* - If SEMAPHORE(task) is low and task still enabled. */ +/* - Traces and debug. */ +/* - Read interference measurement results in NDB */ +/* - Fill and send reporting message */ +/* - Disactivate task. */ +/* - Flag the use of the MCU/DSP dual page read */ +/* interface if needed. */ +/* */ +/* Input parameters: */ +/* ----------------- */ +/* */ +/* Input parameters from globals: */ +/* ------------------------------ */ +/* "l1pa_l1ps_com.itmeas" */ +/* Interference measurement parameters structure */ +/* */ +/* 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 only if no other task was controlled */ +/* in the same frame as ITMEAS */ +/* */ +/* 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. */ +/*-------------------------------------------------------*/ +void l1ps_read_itmeas(UWORD8 param1, UWORD8 param2) +{ + xSignalHeaderRec *msg; + UWORD8 i; + WORD8 delta1_freq, delta2_freq; + UWORD16 g_magic; + + if(!(l1a_l1s_com.task_param[ITMEAS]) && + (l1a_l1s_com.l1s_en_task[ITMEAS])) + { + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) + trace_fct(CST_L1PS_READ_ITMEAS, l1pa_l1ps_com.itmeas.radio_freq); + #endif + + // Allocate result message. + // ************************ + + msg = os_alloc_sig(sizeof(T_L1P_ITMEAS_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + + // Fill msg signal code + msg->SignalCode = L1P_ITMEAS_IND; + + // Fill msg contents + // ****************** + + ((T_L1P_ITMEAS_IND *)(msg->SigP))->fn = l1s.actual_time.fn; + // Report measurement bitmap + ((T_L1P_ITMEAS_IND *)(msg->SigP))->meas_bitmap = l1pa_l1ps_com.itmeas.meas_bitmap; + + // Read result from DSP + g_magic = l1ctl_get_g_magic(l1pa_l1ps_com.itmeas.radio_freq); + delta1_freq = l1ctl_encode_delta1(l1pa_l1ps_com.itmeas.radio_freq); + delta2_freq = l1ctl_encode_delta2(l1pa_l1ps_com.itmeas.radio_freq); + + for (i = 0; i < 8; i++) + { + UWORD8 pm; + WORD16 IL_for_rxlev; + + pm = (l1ps_dsp_com.pdsp_ndb_ptr->a_interf_meas_gprs[i] & 0xffff) >> 5; + + // IL processing + if (pm == 0) + { + ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i] = (WORD8)0x80; + } + else + { + IL_for_rxlev = -(pm - (l1_config.params.high_agc << 1) - g_magic) - delta1_freq - delta2_freq; + + + ((T_L1P_ITMEAS_IND *)(msg->SigP))->rxlev[i] = l1s_encode_rxlev(IL_for_rxlev); + } + } + + // If the Read phase is done during fn_mod26 = 13 --> measurements have been done + // during a PTCCH frame + if (l1s.actual_time.t2 == 13) + { + ((T_L1P_ITMEAS_IND *)(msg->SigP))->position = PTCCH_FRAME; + } + else // Measurements done during a search frame + { + ((T_L1P_ITMEAS_IND *)(msg->SigP))->position = SEARCH_FRAME; + } + + // send message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // ITMEAS is a 'one shot' task --> disable task + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_DISABLED; + } // End if "task enabled and semaphore false" + + // End of task -> task must become INACTIVE. + l1s.task_status[ITMEAS].current_status = INACTIVE; + + // Switch DSP read page if needed + if(l1pa_l1ps_com.itmeas.dsp_r_page_switch_req) + { + // Set flag used to change the read page at the end of "l1_synch". + l1s_dsp_com.dsp_r_page_used = TRUE; + } +} + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START +#endif +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_ctl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_ctl.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,1742 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_CTL.C + * + * Filename l1p_ctl.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS +#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" + #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 + #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_ctl.h" + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" +#if (OP_L1_STANDALONE == 1) + #ifdef _INLINE + #define INLINE static inline // Inline functions when -v option is set + #else // when the compiler is ivoked. + #define INLINE + #endif +#endif //0maps00090550 +#else + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + #include "l1_signa.h" + + #if (RF_FAM == 61) + #include "tpudrv61.h" + #endif + + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_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_ctl.h" + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_sign.h" + #if (OP_L1_STANDALONE == 1) + #ifdef _INLINE + #define INLINE static inline // Inline functions when -v option is set + #else // when the compiler is ivoked. + #define INLINE + #endif +#endif //omaps00090550 +#endif + +#if(RF_FAM == 61) + #include "l1_rf61.h" +#endif + + +// Macro definition +//----------------- +#define min(value1,value2) \ + value1 < value2 ? value1 : value2 + +// External prototypes +//-------------------- + +WORD8 l1ctl_encode_delta1(UWORD16 radio_freq); + +/*********************************************************/ +/* GPRS AGC Algorithms */ +/*********************************************************/ + +/*-------------------------------------------------------*/ +/* l1pctl_pagc_ctrl() */ +/*-------------------------------------------------------*/ +/* Description: */ +/* =========== */ +/* Based on the same principle as the one used for PAGC */ +/* algorithm except that we also feed the beacon FIFO */ +/* with IL measured on other carriers (Pb parameter is */ +/* applied) */ +/* This function is used in the control phase of PCCCH, */ +/* serving PBCCH and PTCCH reading tasks to determine */ +/* which AGC and lna_off must apply */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/*-------------------------------------------------------*/ +void l1pctl_pagc_ctrl(WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq, UWORD8 serving_cell) +{ + UWORD8 pb; + WORD16 input_level, new_calibrated_IL; + WORD32 freq_index; + UWORD16 beacon_frequency; + UWORD8 *lna_off_ptr; + UWORD8 curve_id; + + // We memorize the LNA state used for other serving frequencies that can be used + // in Packet idle mode + static UWORD8 lna_off_others = 0; + + if (serving_cell == TRUE) + { + beacon_frequency = l1a_l1s_com.Scell_info.radio_freq; + pb = l1a_l1s_com.Scell_info.pb; + lna_off_ptr = &lna_off_others; + curve_id = MAX_ID; + } + else + { + beacon_frequency = l1pa_l1ps_com.pbcchn.bcch_carrier; + pb = l1pa_l1ps_com.pbcchn.pb; + lna_off_ptr = lna_off; + curve_id = AV_ID; + } + +#if(L1_FF_MULTIBAND == 0) + freq_index = beacon_frequency - l1_config.std.radio_freq_index_offset; +#else + freq_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(beacon_frequency); +#endif + + + // If the downlink channel is decoded on the beacon frequency + if (radio_freq == beacon_frequency) + { + // Downlink task on the serving beacon: process AGC according to the "beacon IL" + input_level = l1a_l1s_com.last_input_level[freq_index].input_level; + + // lna_off already processed in the read phase + *lna_off = l1a_l1s_com.last_input_level[freq_index].lna_off; + } + + // If the downlink channel is decoded on a frequency other than the beacon + else + { + + // Process AGC according to "beacon IL + Pb" + input_level = (WORD16) (l1a_l1s_com.last_input_level[freq_index].input_level + pb); + + // IL_2_AGC_xx array size + if (input_level>INDEX_MAX) + input_level = INDEX_MAX; + + // lna_off must be processed in the control phase because input_level + // depends on last_input_level and Pb, and last_input_level or pb can have changed + // at any time + + // New calibrated IL to reach on radio freq other than beacon + new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(radio_freq) + - l1ctl_encode_delta2(radio_freq)); + + // IL_2_AGC_xx array size + if (new_calibrated_IL>INDEX_MAX) + new_calibrated_IL = INDEX_MAX; + + // lna_off computing... + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), + lna_off_ptr, + radio_freq); + + *lna_off = *lna_off_ptr; + } // End if "radio_freq != beacon_frequency" + + // Process AGC to apply + *agc = Cust_get_agc_from_IL(radio_freq, + input_level >> 1, + curve_id); + + // Store lna_off and input_level field used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL.input_level = (UWORD8)input_level; + l1a_l1s_com.Scell_used_IL.lna_off = *lna_off; + +} // End of "l1pctl_pagc_ctrl" + +/*-------------------------------------------------------*/ +/* l1pctl_pagc_read() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* Based on the same principle as the one used for PAGC */ +/* algorithm except that we also feed the beacon FIFO */ +/* with IL measured on other carriers (Pb parameter is */ +/* applied) */ +/* This function is used in the read phase of PCCCH and */ +/* serving PBCCH reading tasks to determine the IL value */ +/* store it in the FIFO and find the next IL to use */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/*-------------------------------------------------------*/ +UWORD8 l1pctl_pagc_read(UWORD8 pm, UWORD16 radio_freq) +{ + UWORD8 i, new_IL; + WORD8 delta1_freq, delta2_freq; + WORD16 delta_drp_gain=0; + UWORD16 lna_value; + WORD16 used_agc, current_IL, new_calibrated_IL, current_calibrated_IL; + WORD32 serving_index; +#if (RF_FAM == 61) + UWORD16 arfcn; +#endif + UWORD8 lna_off; + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; +#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION) + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; +#endif + +#if (L1_FF_MULTIBAND == 0) + serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset; + +#else + serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); +#endif /*if (L1_FF_MULTIBAND == 0)*/ + + + // Calibration factors + delta1_freq = l1ctl_encode_delta1(radio_freq); + delta2_freq = l1ctl_encode_delta2(radio_freq); + + // AGC used in the control phase (format F7.1) + used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1; + + // LNA attenuation + lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq); + +#if (RF_FAM == 61) + // DRP correction +#if (L1_FF_MULTIBAND == 0) + arfcn = Convert_l1_radio_freq(radio_freq); +#else + arfcn=radio_freq; +#endif + + #if (CODE_VERSION != SIMULATION) + + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL_dd.input_level, + radio_freq,if_threshold); + lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off; + delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc); // F7.1 format + if(if_ctl == IF_100KHZ_DSP){ + delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ; + } + else{ /* i.e. if_ctl = IF_120KHZ_DSP*/ + delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ; + } + + #endif +#endif + + // current_IL processing + + if (0==pm) // Check and filter illegal pm value by using last valid IL + { + current_IL = l1a_l1s_com.last_input_level[serving_index].input_level - lna_value; + } + else + { + current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq)); + + // IL normalization to beacon (ILnorm = IL - Pb) + if (radio_freq != l1a_l1s_com.Scell_info.radio_freq) + current_IL -= l1a_l1s_com.Scell_info.pb; + } + + // Calibrated IL processing + // NOTE: calibrated_IL is normalized to beacon. This is needed for the + // pccch_lev processing + current_calibrated_IL = (WORD16) (current_IL - delta1_freq - delta2_freq); + + // Protect IL stores against overflow + if (current_calibrated_IL>INDEX_MAX) + current_calibrated_IL=INDEX_MAX; + if (current_IL>INDEX_MAX) + current_IL=INDEX_MAX; + + // FIFO management + for (i=3;i>0;i--) + l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1]; + l1a_l1s_com.Scell_info.buff_beacon[0] = (UWORD8)current_IL; + + // Find min IL in FIFO + new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon, 4); + + // Input levels are always stored with lna_on + new_calibrated_IL = (WORD16) (new_IL - delta1_freq - delta2_freq); + + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna( (UWORD8)(new_calibrated_IL>>1), + &(l1a_l1s_com.last_input_level[serving_index].lna_off), + radio_freq ); + + l1a_l1s_com.last_input_level[serving_index].input_level = new_IL + + l1a_l1s_com.last_input_level[serving_index].lna_off * l1ctl_get_lna_att(radio_freq); + + return((UWORD8)current_calibrated_IL); +} // End of "l1pctl_pagc_read" + +/*-------------------------------------------------------*/ +/* l1pctl_transfer_agc_init() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* Packet transfer AGC algorithm initialization */ +/*-------------------------------------------------------*/ +void l1pctl_transfer_agc_init() +{ + WORD16 calibrated_IL; + UWORD16 radio_freq; + WORD32 serving_index; + WORD16 input_level; + +#if (L1_FF_MULTIBAND ==0) + serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset; + +#else + serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); +#endif /*if L1_FF_MULTIBAND*/ + + + // Daughter frequencies input level initialization + //------------------------------------------------ + if (l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0 == 255) + { + // No power control mode AGC algorithm + input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level + l1a_l1s_com.Scell_info.pb); + + // Set fn_select to current_fn + l1ps.fn_select = l1s.actual_time.fn; + // Initialize algorithm in "SEARCH" phase + l1ps.phase = SEARCH; + } + else + { + // Downlink power control AGC algorithms + if (l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.bts_pwr_ctl_mode == 0) + { + // BTS Power control mode A + input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level + + l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0 + 10); + + } + else + { + // BTS power control mode B + input_level = (WORD16) (l1a_l1s_com.last_input_level[serving_index].input_level + + l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0); + + // Initialization: PR = P0 + l1ps.last_PR_good = l1pa_l1ps_com.transfer.aset->dl_pwr_ctl.p0; + } + } + + if (input_level>INDEX_MAX) input_level = INDEX_MAX; + l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level; + + + // Daughter frequencies lna_off processing + //---------------------------------------- + + // We need to know on which frequency band we work + if (!l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.h) + { + // Single frequency + radio_freq = l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.rf_channel.single_rf.radio_freq; + } + else + { + // Frequency hopping: all frequencies of the frequency list are on the same band + // We take the first frequency of the list + radio_freq = l1pa_l1ps_com.transfer.aset->freq_param.freq_list.rf_chan_no.A[0]; + } + + calibrated_IL = (WORD16) (l1a_l1s_com.Scell_info.transfer_meas.input_level + - l1ctl_encode_delta1(radio_freq) - l1ctl_encode_delta2(radio_freq) + - l1a_l1s_com.last_input_level[serving_index].lna_off * l1ctl_get_lna_att(radio_freq)); + + if (calibrated_IL>INDEX_MAX) calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), radio_freq); + +} // End of "l1pctl_transfer_agc_init" + +/*-------------------------------------------------------*/ +/* l1pctl_transfer_agc_ctrl() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* This function is used in the control phase of PDTCH/D */ +/* to determine which AGC and lna_off must apply */ +/*-------------------------------------------------------*/ +void l1pctl_transfer_agc_ctrl(WORD8 *agc, UWORD8 *lna_off, UWORD16 radio_freq) +{ + T_INPUT_LEVEL *selected_IL; +#if(L1_FF_MULTIBAND == 1) + UWORD16 operative_radio_freq; +#endif + + + // input_level selection + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + // Beacon frequency input_level used for AGC processing +#if(L1_FF_MULTIBAND == 0) + selected_IL = &l1a_l1s_com.last_input_level[l1a_l1s_com.Scell_info.radio_freq + - l1_config.std.radio_freq_index_offset]; + +#else // L1_FF_MULTIBAND = 1 below + + operative_radio_freq = + l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); + selected_IL = &(l1a_l1s_com.last_input_level[operative_radio_freq]); + + +#endif // #if(L1_FF_MULTIBAND == 0) else + + } + else + { + // Daughter frequency input_level used for AGC processing + selected_IL = &l1a_l1s_com.Scell_info.transfer_meas; + } + *agc = Cust_get_agc_from_IL(radio_freq,selected_IL->input_level >> 1, MAX_ID); + *lna_off = selected_IL->lna_off; + + // Store lna_off and input_level field used for current CTRL in order to be able + // to build IL from pm in READ phase. + l1a_l1s_com.Scell_used_IL.input_level = selected_IL->input_level; + l1a_l1s_com.Scell_used_IL.lna_off = *lna_off; + +} + +/*-------------------------------------------------------*/ +/* l1pctl_npc_agc_read() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* AGC algorithm in packet transfer used when */ +/* NO POWER CONTROL is done by the BTS. */ +/* This function is used during the read phase of PDTCH: */ +/* 1- to determine the IL value for each timeslot in each*/ +/* TDMA */ +/* 2- to find the IL value to use for the next PDCH */ +/* block */ +/* */ +/* Algorithm */ +/* --------- */ +/* For each timeslot i used for PDCH */ +/* IL(i) = fct(used AGC, pm) */ +/* if (beacon) */ +/* ILmax_beacon = max(ILmax_beacon, IL(i)) */ +/* else */ +/* ILmax_others(i) = max(IL(i), ILmax_others(i)) */ +/* */ +/* If (burst_nb == 3) */ +/* If (ILmax_beacon was found during the block) */ +/* FIFO[beacon] updated with ILmax_beacon */ +/* transfer_meas = max(FIFO[beacon]) */ +/* Reset ILmax_beacon */ +/* */ +/* For each timeslot i used for PDCH */ +/* if (CRC good) */ +/* ILmax_correct = max(ILmax_correct, */ +/* ILmax_others(i)) */ +/* else */ +/* ILmax_not_correct = max(ILmax_not_correct, */ +/* ILmax_others(i)) */ +/* */ +/* If (no ILmax_correct was found) */ +/* ILselected = ILmax_correct */ +/* FNselected = current FN */ +/* else */ +/* DeltaFN = (current FN - FNselected) % MAX_FN */ +/* */ +/* if (DeltaFN < 78) */ +/* ILweighted = ILselected * (1 - DeltaFN/78) */ +/* - 120 * DeltaFN /78 */ +/* */ +/* if (ILweighted < -120) ILweighted = -120 */ +/* if (ILmax_not_correct > ILweighted) */ +/* ILselected = ILmax_not_correct */ +/* FNselected = current FN */ +/* else */ +/* ILselected = -120 */ +/* FNselected = current FN */ +/* */ +/* Reset ILmax_others[8] */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/* */ +/* Parameters */ +/* ---------- */ +/* "calibrated_IL[8]" */ +/* contains the IL found on timeslots */ +/* used for PDCH/D. These ILs can be used to process */ +/* RXLEV values. */ +/* */ +/* "*pdsp_db_r_ptr" */ +/* Pointer on the DSP DB Read page, used to extract */ +/* pm values, burst number and timeslot allocated */ +/* for downlink PDCH */ +/* */ +/* "*pdsp_ndb_ptr" */ +/* Pointer on the DSP NDB page, used to extract the */ +/* CRC value for each decoded burst */ +/* */ +/* Global parameters */ +/* ----------------- */ +/* "l1a_l1s_com.Scell_info.transfer_meas.input_level" */ +/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off" */ +/* Used to store the ILselected and the associated */ +/* lna_off value. */ +/* */ +/* "l1a_l1s_com.Scell_info.fn_select" */ +/* Used to store the FNselected value. */ +/* */ +/* "l1a_l1s_com.last_input_level[freq index] */ +/* .input_level */ +/* .lna_off" */ +/* Used to store the beacon input level and */ +/* the associated lna_off value. */ +/* */ +/* "l1ps.transfer_beacon_buf[4]" */ +/* FIFO[beacon] */ +/* */ +/* "l1ps.ILmin_beacon" */ +/* "l1ps.ILmin_others[8]" */ +/*-------------------------------------------------------*/ +void l1pctl_npc_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr) +{ + UWORD8 ts; + UWORD8 rx_no = 0; + UWORD8 bit_mask = 0x80; + UWORD8 ILmin_correct = 255; + UWORD8 ILmin_not_correct = 255; + WORD8 delta1_freq, delta2_freq; + WORD16 delta_drp_gain=0; + UWORD16 radio_freq, lna_value; + WORD16 used_agc; + WORD32 serving_index; +#if (RF_FAM == 61) + UWORD16 arfcn; +#endif + UWORD8 lna_off; + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; +#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION) + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; +#endif + +#if(L1_FF_MULTIBAND == 0) + serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset; + +#else + serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); +#endif + + + // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH + // *************************************************************************** + + // Get radio_freq on which the downlink block was received + radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd; + + // Compute calibration factors + delta1_freq = l1ctl_encode_delta1(radio_freq); + delta2_freq = l1ctl_encode_delta2(radio_freq); + + // AGC used in the control phase (format F7.1) + used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1; + + // LNA attenuation + lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq); + + // Burst 0: Reset ILmin_beacon and ILmin_others + if(pdsp_db_r_ptr->d_burst_nb_gprs == 0) + { + l1ps.ILmin_beacon = 255; // Not valid + + for (ts = 0; ts < 8; ts++) + { + l1ps.ILmin_others[ts] = (UWORD8) l1_config.params.il_min; + } + } // End if "burst 0" + + // IL processing for each received burst + // ************************************** + + // For each timeslot on which a burst was received + for(ts = 0; ts < 8; ts ++) + { + if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask) + { + WORD16 current_IL, current_calibrated_IL; + UWORD8 pm; + + // IL = fct(pm, last_known_agc, lna_value, g_magic) + //------------------------------------------------- + + pm = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff) >> 5); + + // current_IL processing + if (0==pm) // Check and filter illegal pm value by using last valid IL + { + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + current_IL = l1a_l1s_com.last_input_level[serving_index].input_level + - lna_value; + else + current_IL = l1a_l1s_com.Scell_info.transfer_meas.input_level + - lna_value; + } + else + { + +#if (RF_FAM == 61) + // DRP correction +#if (L1_FF_MULTIBAND == 0) + arfcn = Convert_l1_radio_freq(radio_freq); +#else + arfcn=radio_freq; +#endif + + #if (CODE_VERSION != SIMULATION) + + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL_dd.input_level, + radio_freq,if_threshold); + lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off; + delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc); // F7.1 format + if(if_ctl == IF_100KHZ_DSP){ + delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ; + } + else{ /* i.e. if_ctl = IF_120KHZ_DSP*/ + delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ; + } + + #endif +#endif + + current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq)); + } + + // Calibrated IL processing + current_calibrated_IL = current_IL - delta1_freq - delta2_freq; + + // Protect IL stores against overflow + if(current_calibrated_IL>INDEX_MAX) + current_calibrated_IL=INDEX_MAX; + if (current_IL>INDEX_MAX) + current_IL=INDEX_MAX; + + calibrated_IL[ts] = (UWORD8)(current_calibrated_IL); + + // Keep ILmax + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + // Beacon frequency + l1ps.ILmin_beacon = min((UWORD8) current_IL, l1ps.ILmin_beacon); + } + else + { + // Daughter frequency + l1ps.ILmin_others[ts] = min((UWORD8) current_IL,l1ps.ILmin_others[ts]); + } + + // Input Level selection among ILmax found on each timeslot during the block (when burst = 3) + // ******************************************************************************************* + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + // If CRC good + if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100)) + { + // Find the min found IL for blocks that were correctly received + ILmin_correct = min(l1ps.ILmin_others[ts],ILmin_correct); + } + // If CRC bad + else + { + // Find the min found IL for blocks that were not correctly received + ILmin_not_correct = min(l1ps.ILmin_others[ts],ILmin_not_correct); + } + } // End if "burst = 3" + + // Next downlink block + rx_no ++; + + } // End if "timeslot used for downlink PDCH" + + // Next timeslot + bit_mask >>= 1; + } // End for "each timeslot...." + + + // IL selection for the next block if burst = 3 + // ********************************************** + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + WORD16 new_calibrated_IL; + + // Beacon frequency input level updating + //-------------------------------------- + + // If a PDCH has been received on the beacon + if (l1ps.ILmin_beacon != 255) + { + UWORD8 i, new_IL; + + // FIFO management + for (i=3;i>0;i--) + l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1]; + l1a_l1s_com.Scell_info.buff_beacon[0] = l1ps.ILmin_beacon; + + // Find min IL in FIFO + new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon, 4); + + // Input levels are always stored with lna_on + + // lna_off processing + new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq)); + + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), + &(l1a_l1s_com.last_input_level[serving_index].lna_off), + l1a_l1s_com.Scell_info.radio_freq); + + l1a_l1s_com.last_input_level[serving_index].input_level = new_IL + + l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq); + + } // End of "beacon frequency input level updating" + + // Daughter frequencies input level updating + //------------------------------------------ + + // If at least one block was correctly received + // (Note: ILs truncated to 240 so 255 isn't valid) + if (ILmin_correct != 255) + { + // Select the min input level found on correctly received blocks + l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_correct; + l1ps.fn_select = l1s.actual_time.fn; + + // Algorithm switch to "TRACK" phase if it was in "SEARCH" phase + l1ps.phase = TRACK; + } + + // No block was correctly received + else + { + UWORD8 input_level_ref = l1a_l1s_com.Scell_info.transfer_meas.input_level + - l1a_l1s_com.Scell_info.transfer_meas.lna_off * + l1ctl_get_lna_att(radio_freq); + // SEARCH phase + if (l1ps.phase == SEARCH) + { + // If measured level superior to currently tracket level, switch to TRACK mode + if (input_level_ref > ILmin_not_correct) + l1ps.phase = TRACK; + + // Select the min input level found on badly received blocks + l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_not_correct; + l1ps.fn_select = l1s.actual_time.fn; + } + + // TRACK phase + else + { + // If the IL found on incorrect block is lower than current wanted IL + if (ILmin_not_correct < input_level_ref) + { + // Select the new IL + l1a_l1s_com.Scell_info.transfer_meas.input_level = ILmin_not_correct; + l1ps.fn_select = l1s.actual_time.fn; + } + + // If the IL found on incorrect block is higher than current wanted IL + else + { + UWORD32 delta_fn; + + // delta_fn processing for IL selection forgetting factor + delta_fn = l1s.actual_time.fn - l1ps.fn_select; + + // MAX_FN modulo management + if (l1s.actual_time.fn < l1ps.fn_select) + delta_fn += MAX_FN; + + // If the last selected IL is more recent than 72 frames + // + // |....|R...............................C|....| + // ^ ^ + // fn_selected IL reset to -120 + // <--------------------------------------> + // 312 + // 306 = 312 - 4 (block_size) - 1 (Read phase fn delay) - 1 (Control phase fn advance) + if (delta_fn > 306) + { + WORD16 input_level; + + // IL initialized to "beacon level - Pb" + input_level = (WORD16) + ((l1a_l1s_com.last_input_level[serving_index].input_level + + l1a_l1s_com.Scell_info.pb) - + (l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq))); + + if (input_level>INDEX_MAX) input_level = INDEX_MAX; + l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level; + + l1ps.fn_select = l1s.actual_time.fn; + // Returns to "SEARCH" phase + l1ps.phase = SEARCH; + } + else + { + WORD16 input_level; + + input_level = l1a_l1s_com.Scell_info.transfer_meas.input_level - + l1a_l1s_com.Scell_info.transfer_meas.lna_off * + l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna); + + if (input_level>INDEX_MAX) input_level = INDEX_MAX; + + l1a_l1s_com.Scell_info.transfer_meas.input_level = (UWORD8)input_level; + } + } // End if the IL found on incorrect block is higher than current wanted IL + } // End of "track phase" + } // End if no block correctly received + + // lna_off processing + new_calibrated_IL = (WORD16) (l1a_l1s_com.Scell_info.transfer_meas.input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna)); + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna); + + l1a_l1s_com.Scell_info.transfer_meas.input_level += + l1a_l1s_com.Scell_info.transfer_meas.lna_off * + l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna); + } // End if "burst = 3" + +} // End of "l1pctl_npc_agc_read" + +/*-------------------------------------------------------*/ +/* l1pctl_dpcma_agc_read() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* AGC algorithm in packet transfer used when the BTS */ +/* use DOWNLINK POWER CONTROL mode A. */ +/* This function is used during the read phase of PDTCH: */ +/* 1- to determine the IL value for each timeslot in each*/ +/* TDMA */ +/* 2- to find the IL value to use for the next PDCH */ +/* block */ +/* */ +/* Algorithm */ +/* --------- */ +/* For each timeslot i used for PDCH */ +/* IL(i) = fct(used AGC, pm) */ +/* if (beacon) */ +/* ILmax_beacon = max(ILmax_beacon, IL(i)) */ +/* else */ +/* ILmax_others(i) = max(IL(i), ILmax_others(i)) */ +/* */ +/* If (burst_nb == 3) */ +/* */ +/* For each timeslot i used for PDCH */ +/* if (CRC good) and */ +/* ((PR_MODE A) or (PR_MODE B and TFI good)) */ +/* ILmax = max(ILmax, ILmax_others(i) + P0 + PR(i))*/ +/* */ +/* ILmax=max(ILmax, ILmax_beacon) */ +/* FIFO[beacon] updated with ILmax */ +/* last_input_level[serving beacon] = max(FIFO[beacon])*/ +/* transfer_meas = max(FIFO[beacon]) - P0 - 5 */ +/* */ +/* Reset ILmax_others[8] and ILmax_beacon */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/* */ +/* Parameters */ +/* ---------- */ +/* "calibrated_IL[8]" */ +/* contains the IL found on timeslots */ +/* used for PDCH/D. These ILs can be used to process */ +/* RXLEV values. */ +/* */ +/* "*pdsp_db_r_ptr" */ +/* Pointer on the DSP DB Read page, used to extract */ +/* pm values, burst number and timeslot allocated */ +/* for downlink PDCH */ +/* */ +/* "*pdsp_ndb_ptr" */ +/* Pointer on the DSP NDB page, used to extract the */ +/* CRC value for each decoded burst */ +/* */ +/* Global parameters */ +/* ----------------- */ +/* "l1a_l1s_com.Scell_info.transfer_meas.input_level" */ +/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off" */ +/* Used to store the ILselected and the associated */ +/* lna_off value. */ +/* */ +/* "l1a_l1s_com.last_input_level[freq. index] */ +/* .input_level */ +/* .lna_off" */ +/* Used to store the beacon input level and */ +/* the associated lna_off value. */ +/* */ +/* "l1ps.transfer_beacon_buf[4]" */ +/* FIFO[beacon] */ +/* */ +/* "l1ps.ILmin_beacon" */ +/* "l1ps.ILmin_others[8]" */ +/*-------------------------------------------------------*/ +void l1pctl_dpcma_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, UWORD8 pr_table[8]) +{ + UWORD8 ts = 0; + UWORD8 rx_no = 0; + UWORD8 bit_mask = 0x80; + UWORD8 IL_norm_min = 255; + WORD8 delta1_freq, delta2_freq; + WORD16 delta_drp_gain=0; + UWORD16 radio_freq, lna_value; + WORD16 used_agc; + WORD32 serving_index; +#if (RF_FAM == 61) + UWORD16 arfcn; +#endif + UWORD8 lna_off; + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; +#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION) + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; +#endif + +#if(L1_FF_MULTIBAND == 0) + serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset; + +#else + serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); +#endif + + + // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH + // *************************************************************************** + + // Get radio_freq on which the downlink block was received + radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd; + + // Compute calibration factors + delta1_freq = l1ctl_encode_delta1(radio_freq); + delta2_freq = l1ctl_encode_delta2(radio_freq); + + // Last known AGC (format F7.1) + used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1; + + // LNA attenuation + lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq); + + // Burst 0: Reset ILmin_beacon and ILmin_others + if(pdsp_db_r_ptr->d_burst_nb_gprs == 0) + { + l1ps.ILmin_beacon = 255; // Not valid + + for (ts = 0; ts < 8; ts++) + { + l1ps.ILmin_others[ts] = 255; // Not valid + } + } + + // IL processing for each received burst + // ************************************** + +#if (RF_FAM == 61) + // DRP correction +#if (L1_FF_MULTIBAND == 0) + arfcn = Convert_l1_radio_freq(radio_freq); +#else + arfcn=radio_freq; +#endif + + #if (CODE_VERSION != SIMULATION) + + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL_dd.input_level, + radio_freq, if_threshold); + lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off; + delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc); // F7.1 format + + if(if_ctl == IF_100KHZ_DSP){ + delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ; + } + else{ /* i.e. if_ctl = IF_120KHZ_DSP*/ + delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ; + } + + #endif +#endif + + // For each timeslot on which a burst was received + for(ts = 0; ts < 8; ts ++) + { + if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask) + { + WORD16 current_IL, current_calibrated_IL; + UWORD8 pm; + + // IL = fct(pm, last_known_agc, lna_value, g_magic) + //------------------------------------------------- + + pm = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff) >> 5); + + // current_IL processing + if (0==pm) // Check and filter illegal pm value by using last valid IL + { + current_IL = l1a_l1s_com.last_input_level[serving_index].input_level + - lna_value; + + if (radio_freq != l1a_l1s_com.Scell_info.radio_freq) + current_IL += (l1ps.read_param.dl_pwr_ctl.p0 + 10); + } + else + { + current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq)); + } + + // Calibrated IL processing + current_calibrated_IL = current_IL - delta1_freq - delta2_freq; + + // Protect IL stores against overflow + if(current_calibrated_IL>INDEX_MAX) + current_calibrated_IL=INDEX_MAX; + if (current_IL>INDEX_MAX) + current_IL=INDEX_MAX; + + calibrated_IL[ts] = (UWORD8)(current_calibrated_IL); + + // Keep the minimum IL + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + // Beacon frequency + l1ps.ILmin_beacon = min((UWORD8) current_IL,l1ps.ILmin_beacon); + } + else + { + // Daughter frequency + l1ps.ILmin_others[ts] = min((UWORD8) current_IL, l1ps.ILmin_others[ts]); + } + + // Input Level selection among ILmax found on each timeslot during the block (when burst = 3) + //------------------------------------------------------------------------------------------- + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + // If CRC good + if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100)) + { + // If ((PR_MODE A and TFI good) or (PR_MODE B)) AND PR != 0 [Not usable]) + if (((l1ps.read_param.dl_pwr_ctl.pr_mode != 0) || (!(pr_table[ts] & 0x80))) + && ((pr_table[ts] & 0x1f) != 0)) + { + if (l1ps.ILmin_others[ts] != 255) + { + UWORD8 IL_norm; + + // IL normalization to beacon (ILnorm = ILmax_others(ts) - P0 - PR) + IL_norm = l1ps.ILmin_others[ts] - l1ps.read_param.dl_pwr_ctl.p0 - ((pr_table[ts] & 0x1f) << 1); + + // Update IL_min with the minimum found IL + IL_norm_min = min(IL_norm, IL_norm_min); + } + } + } // End if "CRC good" + + } // End if "burst = 3" + + // Next downlink block + rx_no ++; + + } // End if "timeslot used for downlink PDCH" + + // Next timeslot + bit_mask >>= 1; + + } // End for "each timeslot...." + + + // IL selection for the next block if burst = 3 + // ********************************************** + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + UWORD8 i, new_IL; + UWORD16 input_level; + WORD16 new_calibrated_IL; + + // Select the minimum IL between minimum IL found on daughter frequencies (normalized to beacon) + // and minimum IL found on the beacon + IL_norm_min = min(IL_norm_min, l1ps.ILmin_beacon); + + // If a valid IL has been found + if (IL_norm_min != 255) + { + // FIFO management + for (i=3;i>0;i--) + l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1]; + + l1a_l1s_com.Scell_info.buff_beacon[0] = IL_norm_min; + + // last_input_level[serving beacon] updating + //------------------------------------------ + + // Find min IL in FIFO + new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4); + + // Input levels are always stored with lna_on + + // lna_off processing + new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq)); + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL >> 1), + &(l1a_l1s_com.last_input_level[serving_index].lna_off), + l1a_l1s_com.Scell_info.radio_freq); + + l1a_l1s_com.last_input_level[serving_index].input_level = new_IL + + l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq); + } + + // transfer_meas updating + //----------------------- + + // IL = (min IL in FIFO) + P0 + 10 (PR = 5 format 7.1) + // Input levels are always stored with lna_on + input_level = l1a_l1s_com.last_input_level[serving_index].input_level + - l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq) + + l1ps.read_param.dl_pwr_ctl.p0 + 10; + + // IL_2_AGC_xx array size + if (input_level>INDEX_MAX) input_level = INDEX_MAX; + + // lna_off processing + new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna)); + + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna); + + l1a_l1s_com.Scell_info.transfer_meas.input_level = input_level + + l1a_l1s_com.Scell_info.transfer_meas.lna_off * + l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna); + } // End if "burst = 3" + +} // End of "l1pctl_dpcma_agc_read" + +/*-------------------------------------------------------*/ +/* l1pctl_dpcmb_agc_read() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* =========== */ +/* AGC algorithm in packet transfer used when the BTS */ +/* use DOWNLINK POWER CONTROL mode B. */ +/* This function is used during the read phase of PDTCH: */ +/* 1- to determine the IL value for each timeslot in each*/ +/* TDMA */ +/* 2- to find the IL value to use for the next PDCH */ +/* block */ +/* */ +/* Algorithm */ +/* --------- */ +/* For each timeslot i used for PDCH */ +/* IL(i) = fct(used AGC, pm) */ +/* if (beacon) */ +/* ILmax_beacon = max(ILmax_beacon, IL(i)) */ +/* else */ +/* ILmax_others(i) = max(IL(i), ILmax_others(i)) */ +/* */ +/* If (burst_nb == 3) */ +/* */ +/* For each timeslot i used for PDCH */ +/* if (CRC good) */ +/* if (TFI good) last_PR_good = PR(i) */ +/* if ((PR_MODE A) or (PR_MODE B and TFI good)) */ +/* ILmax = max(ILmax, ILmax_others(i) */ +/* + P0 + PR(i)) */ +/* */ +/* ILmax=max(ILmax, ILmax_beacon) */ +/* FIFO[beacon] updated with ILmax */ +/* last_input_level[serving beacon] = max(FIFO[beacon])*/ +/* transfer_meas = max(FIFO[beacon]) - last_PR_good */ +/* */ +/* Reset ILmax_others[8] and ILmax_beacon */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/* */ +/* Parameters */ +/* ---------- */ +/* "calibrated_IL[8]" */ +/* contains the IL found on timeslots */ +/* used for PDCH/D. These ILs can be used to process */ +/* RXLEV values. */ +/* */ +/* "*pdsp_db_r_ptr" */ +/* Pointer on the DSP DB Read page, used to extract */ +/* pm values, burst number and timeslot allocated */ +/* for downlink PDCH */ +/* */ +/* "*pdsp_ndb_ptr" */ +/* Pointer on the DSP NDB page, used to extract the */ +/* CRC value for each decoded burst */ +/* */ +/* Global parameters */ +/* ----------------- */ +/* "l1a_l1s_com.Scell_info.transfer_meas.input_level" */ +/* "l1a_l1s_com.Scell_info.transfer_meas.lna_off" */ +/* Used to store the ILselected and the associated */ +/* lna_off value. */ +/* */ +/* "l1a_l1s_com.last_input_level[freq. index] */ +/* .input_level */ +/* .lna_off" */ +/* Used to store the beacon input level and */ +/* the associated lna_off value. */ +/* */ +/* "l1ps.transfer_beacon_buf[4]" */ +/* FIFO[beacon] */ +/* */ +/* "l1ps.ILmin_beacon" */ +/* "l1ps.ILmin_others[8]" */ +/*-------------------------------------------------------*/ +void l1pctl_dpcmb_agc_read(UWORD8 calibrated_IL[8], T_DB_DSP_TO_MCU_GPRS *pdsp_db_r_ptr, + T_NDB_MCU_DSP_GPRS *pdsp_ndb_ptr, UWORD8 pr_table[8]) +{ + UWORD8 ts = 0; + UWORD8 rx_no = 0; + UWORD8 bit_mask = 0x80; + UWORD8 IL_norm_min = 255; + WORD8 delta1_freq, delta2_freq; + WORD16 delta_drp_gain=0; + UWORD16 radio_freq, lna_value; + WORD16 used_agc; + WORD32 serving_index; +#if (RF_FAM == 61) + UWORD16 arfcn; +#endif + UWORD8 lna_off; + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; +#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION) + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; +#endif + +#if(L1_FF_MULTIBAND == 0) + serving_index = l1a_l1s_com.Scell_info.radio_freq - l1_config.std.radio_freq_index_offset; +#else + serving_index = l1_multiband_radio_freq_convert_into_operative_radio_freq(l1a_l1s_com.Scell_info.radio_freq); +#endif + + + // Control phase parameters: same AGC, radio_freq, lna_off used for all PDTCH + // *************************************************************************** + + // Get radio_freq on which the downlink block was received + radio_freq = l1a_l1s_com.dedic_set.radio_freq_dd; + + // Compute calibration factors + delta1_freq = l1ctl_encode_delta1(radio_freq); + delta2_freq = l1ctl_encode_delta2(radio_freq); + + // Last known AGC (format F7.1) + used_agc = (Cust_get_agc_from_IL(radio_freq, l1a_l1s_com.Scell_used_IL_dd.input_level >> 1, MAX_ID)) << 1; + + // LNA attenuation + lna_value = l1a_l1s_com.Scell_used_IL_dd.lna_off * l1ctl_get_lna_att(radio_freq); + + // Burst 0: Reset ILmin_beacon and ILmin_others + if(pdsp_db_r_ptr->d_burst_nb_gprs == 0) + { + l1ps.ILmin_beacon = 255; // Not valid + + for (ts = 0; ts < 8; ts++) + { + l1ps.ILmin_others[ts] = 255; // Not valid + } + } + + // IL processing for each received burst + // ************************************** + + // For each timeslot on which a burst was received + for(ts = 0; ts < 8; ts ++) + { + if(pdsp_db_r_ptr->d_task_d_gprs & bit_mask) + { + WORD16 current_IL, current_calibrated_IL; + UWORD8 pm; + + // IL = fct(pm, last_known_agc, lna_value, g_magic) + //------------------------------------------------- + + pm = (UWORD8) ((pdsp_db_r_ptr->a_burst_pm_gprs[ts] & 0xffff) >> 5); + + // current_IL processing + if (0==pm) // Check and filter illegal pm value by using last valid IL + { + current_IL = l1a_l1s_com.last_input_level[serving_index].input_level + - lna_value; + + if (radio_freq != l1a_l1s_com.Scell_info.radio_freq) + current_IL += (l1ps.last_PR_good); + } + else + { + +#if (RF_FAM == 61) + // DRP correction +#if (L1_FF_MULTIBAND == 0) + arfcn = Convert_l1_radio_freq(radio_freq); +#else + arfcn=radio_freq; +#endif + + #if (CODE_VERSION != SIMULATION) + + + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + l1a_l1s_com.Scell_used_IL_dd.input_level, + radio_freq, if_threshold); + lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off; + delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc); // F7.1 format + + if(if_ctl == IF_100KHZ_DSP){ + delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ; + } + else{ /* i.e. if_ctl = IF_120KHZ_DSP*/ + delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ; + } + + + #endif +#endif + + current_IL = -(pm - ( used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq)); + } + + // Calibrated IL processing + current_calibrated_IL = current_IL - delta1_freq - delta2_freq; + + // Protect IL stores against overflow + if(current_calibrated_IL>INDEX_MAX) + current_calibrated_IL=INDEX_MAX; + if (current_IL>INDEX_MAX) + current_IL=INDEX_MAX; + + calibrated_IL[ts] = (UWORD8)(current_calibrated_IL); + + // Keep the minimum IL + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + // Beacon frequency + l1ps.ILmin_beacon = min((UWORD8) current_IL,l1ps.ILmin_beacon); + } + else + { + // Daughter frequency + l1ps.ILmin_others[ts] = min((UWORD8) current_IL, l1ps.ILmin_others[ts]); + } + + // Input Level selection among ILmax found on each timeslot during the block (when burst = 3) + //------------------------------------------------------------------------------------------- + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + // If CRC good + if (!(pdsp_ndb_ptr->a_dd_gprs[rx_no][0] & 0x0100)) + { + // If ((PR_MODE A and TFI good) or (PR_MODE B)) + if ((l1ps.read_param.dl_pwr_ctl.pr_mode != 0) || (!(pr_table[ts] & 0x80))) + { + + // If TFI good + if (!(pr_table[ts] & 0x80)) + { + // Memorize decoded PR + l1ps.last_PR_good = ((pr_table[ts] & 0x1f) << 1); + } + + if (l1ps.ILmin_others[ts] != 255) + { + UWORD8 IL_norm; + + // IL normalization to beacon (ILnorm = ILmax_others(ts) - PR) + IL_norm = l1ps.ILmin_others[ts] - ((pr_table[ts] & 0x1f) << 1); + + // Update IL_min with the minimum found IL + IL_norm_min = min(IL_norm, IL_norm_min); + } + } + } // End if "CRC good" + + } // End if "burst = 3" + + // Next downlink block + rx_no ++; + + } // End if "timeslot used for downlink PDCH" + + // Next timeslot + bit_mask >>= 1; + + } // End for "each timeslot...." + + + // IL selection for the next block if burst = 3 + // ********************************************** + + if(pdsp_db_r_ptr->d_burst_nb_gprs == 3) + { + UWORD8 i, new_IL; + UWORD16 input_level; + WORD16 new_calibrated_IL; + + // Select the minimum IL between minimum IL found on daughter frequencies (normalized to beacon) + // and minimum IL found on the beacon + IL_norm_min = min(IL_norm_min, l1ps.ILmin_beacon); + + // If a valid IL has been found + if (IL_norm_min != 255) + { + // FIFO management + for (i=3;i>0;i--) + l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1]; + + l1a_l1s_com.Scell_info.buff_beacon[0] = IL_norm_min; + + // last_input_level[serving beacon] updating + //------------------------------------------ + + // Find min IL in FIFO + new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4); + + // Input levels are always stored with lna_on + + // lna_off processing + new_calibrated_IL = (WORD16) (new_IL - l1ctl_encode_delta1(l1a_l1s_com.Scell_info.radio_freq) - l1ctl_encode_delta2(l1a_l1s_com.Scell_info.radio_freq)); + + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL >> 1), + &(l1a_l1s_com.last_input_level[serving_index].lna_off), + l1a_l1s_com.Scell_info.radio_freq); + + l1a_l1s_com.last_input_level[serving_index].input_level = new_IL + + l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq); + } + + // transfer_meas updating + //----------------------- + + // IL = (min IL in FIFO) + PR (Middle of the range specified by the last decoded PR with CRC and TFI good) + // Input levels are always stored with lna_on + input_level = l1a_l1s_com.last_input_level[serving_index].input_level + - l1a_l1s_com.last_input_level[serving_index].lna_off * + l1ctl_get_lna_att(l1a_l1s_com.Scell_info.radio_freq) + + l1ps.last_PR_good; + + // IL_2_AGC_xx array size + if (input_level>INDEX_MAX) input_level = INDEX_MAX; + + // lna_off processing + new_calibrated_IL = (WORD16) (input_level - l1ctl_encode_delta1(l1ps.read_param.radio_freq_for_lna)); + + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), &(l1a_l1s_com.Scell_info.transfer_meas.lna_off), l1ps.read_param.radio_freq_for_lna); + + l1a_l1s_com.Scell_info.transfer_meas.input_level = input_level + + l1a_l1s_com.Scell_info.transfer_meas.lna_off * + l1ctl_get_lna_att(l1ps.read_param.radio_freq_for_lna); + + } // End if "burst = 3" + +} // End of "l1pctl_dpcmb_agc_read" + +/*-------------------------------------------------------*/ +/* l1pctl_pgc() */ +/*-------------------------------------------------------*/ +/* Description : */ +/* ============= */ +/* This function is used in packet transfer mode for the*/ +/* Read phase of power measurements. It permits to: */ +/* - Process the IL value in function of the Pm and AGC */ +/* used */ +/* - Update the FIFO[beacon] used in packet transfer AGC*/ +/* algorithms */ +/* - Update last_input_level */ +/* */ +/* WARNING: in the layer 1 code, input levels IL(l1) use */ +/* format 7.1: */ +/* ********************* */ +/* * IL(l1) = - 2 x IL * */ +/* ********************* */ +/* -> Reversed sign, reversed test conditions */ +/* -> max replaced by min */ +/* ex: if IL -120 dBm, IL(l1) = 240 */ +/*-------------------------------------------------------*/ +UWORD8 l1pctl_pgc(UWORD8 pm, UWORD8 last_known_il, UWORD8 lna_off, UWORD16 radio_freq) +{ + UWORD8 i, new_IL; + WORD8 delta1_freq, delta2_freq; + WORD16 delta_drp_gain=0; + UWORD16 lna_value; + WORD16 used_agc, current_IL, current_calibrated_IL, new_calibrated_IL; + WORD32 index; +#if (RF_FAM == 61) + UWORD16 arfcn; +#endif + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; +#if (RF_FAM == 61) && (CODE_VERSION != SIMULATION) + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GPRS; +#endif + + // Calibration factors + delta1_freq = l1ctl_encode_delta1(radio_freq); + delta2_freq = l1ctl_encode_delta2(radio_freq); + + // initialize index +#if(L1_FF_MULTIBAND == 0) + index = radio_freq - l1_config.std.radio_freq_index_offset; + +#else + index = l1_multiband_radio_freq_convert_into_operative_radio_freq(radio_freq); +#endif + + + // LNA attenuation + lna_value = lna_off * l1ctl_get_lna_att(radio_freq); + + // Used AGC in the control phase (format F7.1) + used_agc = (Cust_get_agc_from_IL(radio_freq, last_known_il >> 1, PWR_ID)) << 1; + + +#if (RF_FAM == 61) + // DRP correction +#if (L1_FF_MULTIBAND == 0) + arfcn = Convert_l1_radio_freq(radio_freq); +#else + arfcn=radio_freq; +#endif + + #if (CODE_VERSION != SIMULATION) + + +#if (PWMEAS_IF_MODE_FORCE == 0) + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + last_known_il, + radio_freq, if_threshold); + #else + if_ctl = IF_120KHZ_DSP; + dco_algo_ctl_pw_temp = DCO_IF_0KHZ; + #endif + + lna_off = l1a_l1s_com.Scell_used_IL_dd.lna_off; + delta_drp_gain = drp_gain_correction(arfcn, lna_off, used_agc); // F7.1 format + + if(if_ctl == IF_100KHZ_DSP){ + delta_drp_gain += SCF_ATTENUATION_LIF_100KHZ; + } + else{ /* i.e. if_ctl = IF_120KHZ_DSP*/ + delta_drp_gain += SCF_ATTENUATION_LIF_120KHZ; + } + + + #endif +#endif + + if (0==pm) // Check and filter illegal pm value by using last valid IL + current_IL = l1a_l1s_com.last_input_level[index].input_level - lna_value; + else + current_IL = -(pm - (used_agc - delta_drp_gain) + lna_value - l1ctl_get_g_magic(radio_freq)); + + // Calibrated IL processing + current_calibrated_IL = current_IL - delta1_freq - delta2_freq; + + // Protect IL stores against overflow + if (current_calibrated_IL>INDEX_MAX) + current_calibrated_IL=INDEX_MAX; + if (current_IL>INDEX_MAX) + current_IL=INDEX_MAX; + + // if radio freq is the serving beacon + //------------------------------------ + if (radio_freq == l1a_l1s_com.Scell_info.radio_freq) + { + // FIFO management + for (i=3;i>0;i--) + l1a_l1s_com.Scell_info.buff_beacon[i] = l1a_l1s_com.Scell_info.buff_beacon[i-1]; + l1a_l1s_com.Scell_info.buff_beacon[0] = (UWORD8) current_IL; + + // Find min IL in FIFO + new_IL = l1ctl_find_max(l1a_l1s_com.Scell_info.buff_beacon,4); + + // lna_off processing + new_calibrated_IL = (WORD16) (new_IL - delta1_freq - delta2_freq); + if (new_calibrated_IL>INDEX_MAX) new_calibrated_IL = INDEX_MAX; + + l1ctl_encode_lna((UWORD8)(new_calibrated_IL>>1), + &(l1a_l1s_com.last_input_level[index].lna_off), + radio_freq); + + l1a_l1s_com.last_input_level[index].input_level = new_IL + + l1a_l1s_com.last_input_level[index].lna_off * + l1ctl_get_lna_att(radio_freq); + } + + // if radio freq is a neighbor beacon + //----------------------------------- + else + { + // Update last_input_level (IL with LNA ON) + l1ctl_encode_lna((UWORD8)(current_calibrated_IL>>1), + &(l1a_l1s_com.last_input_level[index].lna_off), + radio_freq); + + l1a_l1s_com.last_input_level[index].input_level = current_IL + + l1a_l1s_com.last_input_level[index].lna_off * + l1ctl_get_lna_att(radio_freq); + } + + return((UWORD8)current_calibrated_IL); + +} // End of "l1pctl_pgc" +#endif diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_driv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_driv.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,1580 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_DRIVE.C + * + * Filename l1p_driv.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1P_DRIVE_C + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS +#if (CODE_VERSION == SIMULATION) + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "l1_varex.h" + #include "cust_os.h" + #include "l1_msgty.h" + #if L2_L3_SIMUL + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_tabs.h" + + #include "sim_cons.h" + #include "sim_def.h" + extern T_hw FAR hw; + #include "l1_proto.h" + +#else + + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "l1_varex.h" + #include "cust_os.h" + #include "l1_msgty.h" + #if L2_L3_SIMUL + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_tabs.h" + + #include "l1_proto.h" + #include "tpudrv.h" + +#endif + +#if(RF_FAM == 61) +#include "l1_rf61.h" +#include "tpudrv61.h" +#include "l1_ctl.h" +#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_afc (UWORD16 afc_value, UWORD8 win_id); + +#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61) ) + UWORD16 Cust_get_pwr_data(UWORD8 txpwr, UWORD16 radio_freq + #if(REL99 && FF_PRF) + ,UWORD8 number_uplink_timeslot + #endif + ); +#endif +void Cust_get_ramp_tab(API *a_ramp, UWORD8 txpwr_ramp_up, UWORD8 txpwr_ramp_down, UWORD16 radio_freq); + +BOOL l1ps_swap_iq_ul (UWORD16 radio_freq); +BOOL l1ps_swap_iq_dl (UWORD16 radio_freq); +#if (L1_MADC_ON == 1) +#if (RF_FAM == 61) +void l1pdmacro_rx_up (UWORD16 radio_freq,UWORD8 adc_active, UWORD8 csf_filter_choice +#if (NEW_SNR_THRESHOLD == 1) + ,UWORD8 saic_flag +#endif /* NEW_SNR_THRESHOLD == 1*/ + ); +#endif +#else /* RF_FAM == 61*/ +void l1pdmacro_rx_up (UWORD16 radio_freq); +#endif +void l1pdmacro_rx_down (UWORD16 radio_freq, UWORD8 num_rx, BOOL rx_done_flag); +void l1pdmacro_tx_up (UWORD16 radio_freq); +void l1pdmacro_tx_down (UWORD16 radio_freq, WORD16 time, BOOL tx_flag, UWORD8 timing_advance,UWORD8 adc_active); +void l1pdmacro_tx_synth(UWORD16 radio_freq); +void l1pdmacro_anchor (WORD16 time); + +void l1dmacro_rx_synth(UWORD16 radio_freq); +void l1dmacro_agc(UWORD16 radio_freq, WORD8 agc_value, UWORD8 lna_off + #if (RF_FAM == 61) + ,UWORD8 if_ctl + #endif + ); +#if (CODE_VERSION == SIMULATION) + void l1dmacro_rx_ms (UWORD16 arfcn, BOOL rxnb_select); +#else +#if (L1_MADC_ON == 1) +#if (RF_FAM == 61) + void l1dmacro_rx_ms (UWORD16 arfcn,UWORD8 adc_active); +#endif +#else + void l1dmacro_rx_ms (UWORD16 arfcn); +#endif +#endif +void l1pdmacro_it_dsp_gen(WORD16 time); + +/*-------------------------------------------------------*/ +/* Prototypes of functions defined in this file. */ +/*-------------------------------------------------------*/ +// TPU Drivers... + + +// DSP Drivers... +void l1pddsp_synchro (UWORD8 switch_mode, UWORD8 camp_timeslot); +void l1pddsp_idle_prach_data (BOOL polling, UWORD8 cs_type, UWORD16 channel_request_data, + UWORD8 bsic, UWORD16 radio_freq); +void l1pddsp_idle_prach_power (UWORD8 txpwr, UWORD16 radio_freq, UWORD8 ts); +void l1pddsp_single_tx_block (UWORD8 burst_nb, UWORD8 *data, UWORD8 tsc, + UWORD16 radio_freq); +#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 +void l1pddsp_transfer_mslot_ctrl (UWORD8 burst_nb, UWORD8 dl_bitmap, UWORD8 ul_bitmap, + UWORD8 *usf_table, UWORD8 mac_mode, UWORD8 *ul_buffer_index, + UWORD8 tsc, UWORD16 radio_freq, UWORD8 synchro_timeslot, + #if FF_L1_IT_DSP_USF + UWORD8 dsp_usf_interrupt + #else + UWORD8 usf_vote_enable + #endif + ); +void l1pddsp_transfer_mslot_power (UWORD8 *txpwr, UWORD16 radio_freq, UWORD8 ul_bitmap); +void l1pddsp_ul_ptcch_data (UWORD8 cs_type, UWORD16 channel_request_data, UWORD8 bsic, + UWORD16 radio_freq, UWORD8 timeslot_no); +void l1pddsp_interf_meas_ctrl (UWORD8 nb_meas_req); +void l1pddsp_transfer_meas_ctrl (UWORD8 meas_position); + +/*-------------------------------------------------------*/ +/* l1pd_afc() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pd_afc(void) +{ + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + l1ddsp_load_afc(l1s.afc); + #endif + #if (RF_FAM == 61) + l1dtpu_load_afc(l1s.afc); + #endif +} + +/*-------------------------------------------------------*/ +/* l1pdtpu_interf_meas() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +UWORD8 l1pdtpu_interf_meas(UWORD16 radio_freq, + WORD8 agc, + UWORD8 lna_off, + UWORD8 meas_bitmap, + UWORD32 offset_serv, + UWORD16 win_id, + UWORD8 synchro_ts + #if (RF_FAM == 61) + ,UWORD8 if_ctl + #endif + ) +{ + UWORD8 bit_mask = 0x80; + UWORD8 ts; + BOOL rf_programmed = FALSE; + UWORD8 count = 0; + + if(!win_id) + { + // Nothing programmed yet, we must avoid Mirror effect in Ctrl phase. + l1pdmacro_anchor(l1_config.params.rx_change_offset_time); + } + + for (ts=0; ts<8; ts++) + { + // the bitmap corresponds to that of the idle frame of the network!!! + #if ((CHIPSET==3)||(CHIPSET == 4)) + // limitation of 5 measurements for SAMSON (TPU RAM size limitation) + if((meas_bitmap & bit_mask)&&(count <= 4)) + #else + if(meas_bitmap & bit_mask) + #endif + { + UWORD16 local_win_id; + UWORD16 offset; + WORD16 when; + UWORD16 offset_chg; + + if((ts>synchro_ts) && (count==0)) + { + // The 1st Work does not contain any Interf meas. + // We must ovoid a possible Mirror effect for the rest of TS. + l1pdmacro_anchor(l1_config.params.rx_change_offset_time); + } + + // Increment nbr of meas. programmed. + count++; + + local_win_id = (8 - synchro_ts + ts) * BP_SPLIT; + if(local_win_id >= (BP_SPLIT * 8)) local_win_id -= BP_SPLIT * 8; // Modulo. + + // Compute offset + offset_chg = ((local_win_id * BP_DURATION) >> BP_SPLIT_PW2); + offset = offset_serv + offset_chg; + if(offset >= TPU_CLOCK_RANGE) offset -= TPU_CLOCK_RANGE; + + if(!rf_programmed) + { + // Compute offset change timing + when = offset_chg + + PROVISION_TIME - + l1_config.params.rx_synth_setup_time - + EPSILON_OFFS; + + if(when < 0) when += TPU_CLOCK_RANGE; + + // Program TPU scenario + l1dmacro_offset (offset, when); // change TPU offset according to win_id + l1dmacro_rx_synth (radio_freq); // pgme SYNTH. + #if (RF_FAM !=61) + l1dmacro_agc (radio_freq, agc,lna_off); // pgme AGC. + #endif + + #if (RF_FAM == 61) + l1dmacro_agc (radio_freq, agc,lna_off, if_ctl); // pgme AGC. + #endif + + rf_programmed = TRUE; + } + else + { + // Compute offset change timing + when = offset_chg - BP_DURATION + PROVISION_TIME + PW_ACQUIS_DURATION + 20; + if(when < 0) when += TPU_CLOCK_RANGE; + + // Program TPU scenario + l1dmacro_offset (offset, when); // change TPU offset according to win_id + } + + #if (CODE_VERSION == SIMULATION) + l1dmacro_rx_ms (radio_freq, 1); // pgm PWR acquisition. + #else + #if (L1_MADC_ON == 1) + #if (RF_FAM == 61) + l1dmacro_rx_ms (radio_freq,INACTIVE); // pgm PWR acquisition. + #endif + #else + l1dmacro_rx_ms (radio_freq); // pgm PWR acquisition. + #endif + #endif + + l1dmacro_offset (offset_serv, IMM); // restore offset + } + + bit_mask >>= 1; + + } // for(ts... + + return(count); +} + +/*-------------------------------------------------------*/ +/* l1dtpu_serv_rx() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* rx_id: range 0-7, first slot of RX group */ +/* rx_group_id: used in case |RX| |RX| */ +/* */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pdtpu_serv_rx_nb(UWORD16 radio_freq, UWORD8 agc, UWORD8 lna_off, + UWORD8 rx_id, UWORD32 offset_serv, UWORD8 num_rx, + UWORD8 rx_group_id, BOOL rx_done_flag,UWORD8 adc_active + #if (RF_FAM == 61) + ,UWORD8 csf_filter_choice + ,UWORD8 if_ctl + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,UWORD8 saic_flag + #endif /* NEW_SNR_THRESHOLD*/ + ) +{ + UWORD16 offset; + + #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][rx_group_id-1]=rx_id; + hw.num_rx[tpu_w_page][rx_group_id-1]=num_rx; + hw.rx_group_id[tpu_w_page]=rx_group_id; + #endif + + offset = offset_serv + (rx_id * BP_DURATION); + if(offset >= TPU_CLOCK_RANGE) offset -= TPU_CLOCK_RANGE; + + if (rx_group_id == 1) + { + // Time tracking. + l1dmacro_synchro (l1_config.params.rx_change_synchro_time, offset_serv); // Adjust serving OFFSET. + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET) + buffer_trace(3, 0x43, offset_serv, l1s.actual_time.fn, 0); + #endif + #endif + + // Change offset to align on RX. + l1dmacro_offset(offset, IMM); + + // Program Synth. + // Program ADC measurement + // Program AGC. + l1dmacro_rx_synth(radio_freq); + if(adc_active == ACTIVE) + l1dmacro_adc_read_rx(); + + l1dmacro_agc (radio_freq, agc, lna_off + #if (RF_FAM == 61) + ,if_ctl + #endif + ); + } + else + { + // Change offset to align on RX. + l1dmacro_offset(offset, IMM); // Change offset to align on RX. + } + + l1pdmacro_rx_up (radio_freq + #if (RF_FAM == 61) + ,adc_active + ,csf_filter_choice + #endif + #if (NEW_SNR_THRESHOLD == 1) + ,saic_flag + #endif /* NEW_SNR_THRESHOLD*/ + + ); // RX window opened. + l1pdmacro_rx_down(radio_freq, num_rx, rx_done_flag); // RX window closed. + + // Restore offset to synchro value. + l1dmacro_offset (offset_serv, IMM); +} + +/*-------------------------------------------------------*/ +/* l1dtpu_serv_tx() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + #ifndef ABB_RAMP_UP_TIME //Flexi ABB Delays defines it in tpudrvXX.h + #define ABB_RAMP_UP_TIME 32 // maximum time for ramp up + #endif + + #ifndef ABB_RAMP_DELAY//Flexi ABB Delays defines it in tpudrvXX.h + #define ABB_RAMP_DELAY 6 // minimum ramp delay APCDEL + #endif + +#ifndef ABB_BULON_HOLD_TIME //Flexi ABB Delays defines it in tpudrvXX.h + #define ABB_BULON_HOLD_TIME 32 // min. hold time for BULON after BULENA down +#endif + + +#endif +void l1pdtpu_serv_tx(UWORD16 radio_freq, + UWORD8 timing_advance, + UWORD32 offset_serv, + UWORD8 tx_id, + UWORD8 num_tx, + UWORD8 tx_group_id, + UWORD8 switch_flag, + BOOL burst_type, + BOOL rx_flag, + UWORD8 adc_active) +{ + WORD16 time; + UWORD32 offset_tx; + UWORD32 timing_advance_in_qbit = (UWORD32)timing_advance << 2; + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61)) + UWORD16 apcdel1_data, apcdel1_data_up; + #endif + UWORD8 i; + static UWORD8 static_switch_flag = 0; + + #if (CODE_VERSION == SIMULATION) + UWORD32 tpu_w_page; + + if (hw.tpu_r_page==0) + tpu_w_page=1; + else + tpu_w_page=0; + + hw.tx_id[tpu_w_page][tx_group_id-1]=tx_id; + hw.num_tx[tpu_w_page][tx_group_id-1]=num_tx; + hw.tx_group_id[tpu_w_page]=tx_group_id; + #endif + + // Reset timing advance if TA_ALGO not enabled. + #if !TA_ALGO + timing_advance_in_qbit = 0; + #endif + + // In case another group of TX bursts is called, the previous slot was a hole + // An IT has to be generated to the DSP so that ramps and power level are reloaded + // This does not apply to combinations of PRACH and TX NB + if ((tx_group_id > 1) && (!static_switch_flag)) + { + // exact timing for generation of IT during hole not required but + // time > time of previous ramp down (BULENA -> BULON down = 32 qb) + margin (10 qb) + #if (RF_FAM != 61) + time = TX_TABLE[tx_id-1] + PROVISION_TIME + ABB_BULON_HOLD_TIME + 10 + - l1_config.params.prg_tx_gsm; + #endif + + #if (RF_FAM == 61) + time = TX_TABLE[tx_id-1] + PROVISION_TIME + APC_RAMP_DOWN_TIME + 10 + - l1_config.params.prg_tx_gsm; + #endif + + if (burst_type == TX_NB_BURST) + time -= timing_advance_in_qbit; // time can never be negative here + + l1pdmacro_it_dsp_gen(time); + } + + + if (tx_group_id == 1) + { + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + //MS TX, set ABB in MS mode + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) + // ABB set to MS mode if |TX|TX|.., |TX|PRACH|, |PRACH|TX| or |PRACH|PRACH| + // switch_flag is set for the first burst of TX/PRACH or PRACH/PRACH combinations + // MS mode in ABB must be maintained for second burst (static_switch_flag) + if ((num_tx > 1) || (switch_flag) || (static_switch_flag)) + l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl | B_MSLOT; + else + l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl; + #endif + #endif + } + else + { + // handle special case |TX| |TX|TX| + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + //MS TX, set ABB in MS mode + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) + if ((num_tx > 1) || (switch_flag) || (static_switch_flag)) + l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl | B_MSLOT; + #endif + #endif + } + + // Compute offset value for TX. + // PRG_TX has become variable, no longer contained in TIME_OFFSET_TX ! + if ((burst_type == TX_NB_BURST) || (switch_flag==1)) + { + offset_tx = offset_serv + TX_TABLE[tx_id] + PROVISION_TIME + - l1_config.params.prg_tx_gsm - timing_advance_in_qbit; + } + else + { + offset_tx = offset_serv + TX_TABLE[tx_id] + PROVISION_TIME + - l1_config.params.prg_tx_gsm; + } + + // offset_tx mod 5000 + if (offset_tx >= TPU_CLOCK_RANGE) + offset_tx -= TPU_CLOCK_RANGE; + + if(rx_flag == TRUE) + { + time = offset_tx - + l1_config.params.tx_synth_setup_time - + EPSILON_OFFS + - offset_serv; + if ((burst_type == TX_NB_BURST) || (switch_flag==1)) + time += timing_advance_in_qbit - TA_MAX; + } + else + time = TPU_CLOCK_RANGE - EPSILON_SYNC; + + if (time < 0) + time += TPU_CLOCK_RANGE; + + if (!static_switch_flag) + l1dmacro_offset (offset_tx, (WORD32) time); // load OFFSET for TX before each burst. + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET) + buffer_trace(2, offset_tx,l1s.actual_time.fn,0,0); + #endif + #endif + + time=0; + + // program PLL only if no TX control carried out in same frame: |TX| |TX|TX| possible + // |PRACH|TX|, |TX|PRACH| or |PRACH|PRACH| also possible + if (tx_group_id == 1) + { + l1pdmacro_tx_synth(radio_freq); // load SYNTH. + } + + if (!static_switch_flag) // window opened for previous time slot (TX/PRACH or PRACH/PRACH) + l1pdmacro_tx_up(radio_freq); // TX window opened + + + #if (CODE_VERSION == SIMULATION) + if (burst_type == TX_RA_BURST) + { + time += l1_config.params.tx_ra_duration; + } + else + { + if (num_tx > 1) + // num_tx * BP_DURATION + time += TX_TABLE[num_tx - 1] + l1_config.params.tx_nb_duration; + else + time += l1_config.params.tx_nb_duration; + } + #else + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + // Read APCDEL1 register DELU(4:0): delay of ramp up start, DELD (9:5) delay of ramp down start + // This value is used for computations in MS TX or TX/PRACH combinations + // This value is not modified by the computations + apcdel1_data = (l1s_dsp_com.dsp_ndb_ptr->d_apcdel1 >> 6) & 0x03ff; + apcdel1_data_up = apcdel1_data & 0x001f; //delay of ramp up start + #endif + +#if (RF_FAM == 61) + // Read APCDEL1 register DELU(4:0): delay of ramp up start, DELD (9:5) delay of ramp down start + // This value is used for computations in MS TX or TX/PRACH combinations + // This value is not modified by the computations + apcdel1_data = (l1s_dsp_com.dsp_ndb_ptr->d_apcdel1) & 0x03ff; + apcdel1_data_up = apcdel1_data & 0x001f; //delay of ramp up start +#endif + + if (!switch_flag) + { + if (burst_type == TX_NB_BURST) + { + // If PRACH precedes TX normal burst(s) we have to add BP_DURATION + if (static_switch_flag) + time += BP_DURATION; + + // generate DSP IT for each TX slot after ramp up + // Margin: + // ABB_RAMP_DELAY = 4*1.5bits internal ABB delay BULENA ON -> ramp up + // apcdel1_data_up = additional delay BULENA ON -> ramp up + // ABB_RAMP_UP_TIME: maximum time for ramp up: 16 coeff. + // 10 qbits of additional margin + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + for (i=0; i 1) + // (num_tx - 1) * BP_DURATION + normal burst duration + time += TX_TABLE[num_tx - 1] + l1_config.params.tx_nb_duration - (num_tx - 1); + else + time += l1_config.params.tx_nb_duration; + } + else //PRACH + { + // If TX NB precedes PRACH we have to add BP_DURATION and TA (in qbits) + if (static_switch_flag == 1) + { + if (timing_advance_in_qbit > 240) // clip TA, cf. comment below + timing_advance_in_qbit = 240; + time += BP_DURATION + timing_advance_in_qbit; + } + // If PRACH precedes PRACH we have to add BP_DURATION + else if (static_switch_flag == 2) + time += BP_DURATION ; + + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10); + #endif + + #if (RF_FAM == 61) + l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10); + #endif + + time += l1_config.params.tx_ra_duration; + } + + } + else if (switch_flag == 1) // |TX|PRACH| or |PRACH|TX| + { + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39) + // => ABB windows are opened as for TX_NB in MS mode + // => Ramp up start of PRACH is delayed inside this window by the TA of the TX_NB + // => DSP inserts dummy bits such that ramp and modulation match + // Rem.: the TA passed for the PRACH is the one for the following TX_NB!!! + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) || (RF_FAM == 61) + // In combinations of TX_NB and PRACH apcdel1_bis and apcdel2_bis apply to the PRACH + UWORD16 apcdel1_bis_data, apcdel1_bis_data_up, apcdel2_bis_data_up, prach_delay; + API d_ctrl_abb_gprs; + + // clip TA (in qbit): max. TA supported = BP_DURATION - PRACH duration - max. ramp time + // = 625 - 88*4 - 32 = 241 + if (timing_advance_in_qbit > 240) + timing_advance_in_qbit = 240; + + prach_delay = apcdel1_data_up + timing_advance_in_qbit; + apcdel1_bis_data_up = prach_delay & 0x001f; + apcdel2_bis_data_up = (prach_delay >> 5) & 0x001f; + + // For ramp down delay we need to keep the original value from APCDEL1 (bits 9:5) + // APCDEL2 default value is '0' + apcdel1_bis_data = apcdel1_bis_data_up | (apcdel1_data & 0x03e0); + + #if(RF_FAM != 61) + l1s_dsp_com.dsp_ndb_ptr->d_apcdel1_bis = (apcdel1_bis_data << 6) | 0x04; + l1s_dsp_com.dsp_ndb_ptr->d_apcdel2_bis = (apcdel2_bis_data_up << 6) | 0x34; + #else + l1s_dsp_com.dsp_ndb_ptr->d_apcdel1_bis = (apcdel1_bis_data ); + l1s_dsp_com.dsp_ndb_ptr->d_apcdel2_bis = (apcdel2_bis_data_up); + #endif + + if (burst_type == TX_RA_BURST) // |PRACH|TX| + { + + #if(RF_FAM != 61) + l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + prach_delay + 10); + #else + l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + prach_delay + 10); + #endif + // apcdel1_bis, apcdel2_bis must be programmed for the current ts (PRACH) + // here we need to overwrite (mask) bits for APCDEL1, APCDEL2 programming done in l1pddsp_transfer_mslot_power() + d_ctrl_abb_gprs = l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id]; + d_ctrl_abb_gprs |= ((1 << B_BULRAMPDEL_BIS) | (1 << B_BULRAMPDEL2_BIS)); + d_ctrl_abb_gprs &= ~((1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id] = d_ctrl_abb_gprs; + } + else // |TX|PRACH| + { + #if(RF_FAM != 61) + l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10); + #else + l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10); + #endif + + // apcdel1_bis, apcdel2_bis must be programmed for the next ts (PRACH) + d_ctrl_abb_gprs = l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id + 1]; + d_ctrl_abb_gprs |= ((1 << B_BULRAMPDEL_BIS) | (1 << B_BULRAMPDEL2_BIS)); + d_ctrl_abb_gprs &= ~((1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[tx_id + 1] = d_ctrl_abb_gprs; + } + #endif // ANALOG + + static_switch_flag = 1; + + #endif // DSP == 33 || DSP == 34 || (DSP == 36) || (DSP == 37) + } + else if (switch_flag == 2) // |PRACH|PRACH| + // Combination handled by programming ABB with MS mode = 1 + // => first burst length of first PRACH = BP_DURATION + { + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + l1pdmacro_it_dsp_gen(time + ABB_RAMP_DELAY + ABB_RAMP_UP_TIME + apcdel1_data_up + 10); + #endif + + #if (RF_FAM == 61) + l1pdmacro_it_dsp_gen(time + APC_RAMP_DELAY + APC_RAMP_UP_TIME + apcdel1_data_up + 10); + #endif + + static_switch_flag = 2; + } + #endif //Codeversion + + // In case of combinations TX_NB/PRACH or PRACH/PRACH the TX window is kept open + if (!switch_flag) + { + l1pdmacro_tx_down(radio_freq, time, switch_flag, timing_advance_in_qbit,adc_active); // TX window closed + + l1dmacro_offset (offset_serv, IMM); // Restore offset with serving value. + + static_switch_flag = 0; + } + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET) + buffer_trace(2, offset_serv,l1s.actual_time.fn,0,0); + #endif + #endif +} + +/*-------------------------------------------------------*/ +/* l1pddsp_synchro() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_synchro(UWORD8 switch_mode, UWORD8 camp_timeslot) +{ + // Set "b_abort" to TRUE. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= (1 << B_TASK_ABORT); + + // Set switch mode within "b_switch_to_gprs" & "b_switch_to_gms" + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs = (switch_mode << B_SWITCH); + + // In case of a switch to GPRS_SCHEDULER, last_used_txpwr is set to "NO_TXPWR" + // in order to force GSM ramp programming when the MS will switch back to + // GSM_SCHEDULER + // Moreover, the d_win_start_gprs register must be initialized only during the + // GSM->GPRS switch too. + if(switch_mode == GPRS_SCHEDULER) + { + l1s.last_used_txpwr = NO_TXPWR; + + // Set camp timeslot. + l1ps_dsp_com.pdsp_ndb_ptr->d_win_start_gprs = camp_timeslot; + } +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_idle_prach_data() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_idle_prach_data(BOOL polling, + UWORD8 cs_type, + UWORD16 channel_request_data, + UWORD8 bsic, + UWORD16 radio_freq) +{ + UWORD16 swap_bit; // 16 bit wide to allow shift left. + + // UL on TS=3. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> 3; + + // Swap I/Q management. + swap_bit = l1ps_swap_iq_ul(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15; + + // Load UL buffer according to "polling" bit. + if(polling) + { + // Select first UL polling buffer. + l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 8; + + // Store CS type. + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][0] = cs_type; + + // Store UL data block. + if(cs_type == CS_PAB8_TYPE) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2] = ((API)(bsic << 2)) | + ((API)(channel_request_data) << 8); + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][3] = 0; + } + else + { + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2] = ((API)(channel_request_data) << 5); + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][3] = ((API)(bsic << 10)); + } + } + else + { + // Set "b_access_prach" to indicate 1 Prach only to DSP. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= (1 << B_ACCESS_PRACH); + + // Select first UL data buffer. + l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 0; + + // Store CS type. + l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][0] = cs_type; + + // Store UL data block. + if(cs_type == CS_PAB8_TYPE) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][1] = ((API)(bsic << 2)) | + ((API)(channel_request_data) << 8); + l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][2] = 0; + } + else + { + l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][1] = ((API)(channel_request_data) << 5); + l1ps_dsp_com.pdsp_ndb_ptr->a_du_gprs[0][2] = ((API)(bsic << 10)); + } + + if (l1pa_l1ps_com.pra_info.prach_alloc == FIX_PRACH_ALLOC) + { + // Set fix alloc bit. + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs |= (2 << B_MAC_MODE); + } + else + { + // Reset MAC mode to dynamic allocation + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= ~(3 << B_MAC_MODE); + + #if !FF_L1_IT_DSP_USF + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39) + // Enable USF vote on timeslot 0 + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = 0x80; + #endif + #endif + } + } +} + +/*-------------------------------------------------------*/ +/* l1pddsp_idle_prach_power() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_idle_prach_power(UWORD8 txpwr, + UWORD16 radio_freq, + UWORD8 ts) +{ + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61)) + UWORD16 pwr_data; + #endif + + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) ) + // Force FIXED transmit power if requested. + if(l1_config.tx_pwr_code == 0) + { + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = l1_config.params.fixed_txpwr; + + // Control bitmap: update RAMP, use RAMP[5][..]. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = + ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. + #if (CODE_VERSION != SIMULATION) + Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[5], + 0, /* not used */ + 0, /* not used */ + 1 /* arbitrary value for arfcn */ ); + #endif + } + else + { + // Get H/W value corresponding to txpwr command. + pwr_data = Cust_get_pwr_data(txpwr, radio_freq + #if(REL99 && FF_PRF) + ,1 + #endif + ); + + // Store Transmit power. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = ((pwr_data << 6) | 0x12); + + // Control bitmap: update RAMP, use RAMP[5][..]. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. + #if (CODE_VERSION != SIMULATION) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[5][0]), txpwr, txpwr, radio_freq); + #endif + } + #endif + + #if (RF_FAM == 61) + // Force FIXED transmit power if requested. + if(l1_config.tx_pwr_code == 0) + { + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = l1_config.params.fixed_txpwr; + + // Control bitmap: update RAMP, use RAMP[5][..]. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = + ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. + #if (DSP ==38) || (DSP == 39) + Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[5], + 0, /* not used */ + 0, /* not used */ + 1 /* arbitrary value for arfcn */ ); + #endif + } + else + { + // Get H/W value corresponding to txpwr command. + pwr_data = Cust_get_pwr_data(txpwr, radio_freq + #if(REL99 && FF_PRF) + ,1 + #endif + ); + + // Store Transmit power. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[ts] = (API) (pwr_data); + + // Control bitmap: update RAMP, use RAMP[5][..]. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[ts] = ((1 << B_RAMP_GPRS) | (5 << B_RAMP_NB_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. + #if(DSP == 38) || (DSP == 39) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[5][0]), txpwr, txpwr, radio_freq); + #endif + } + #endif //RF_FAM == 61 + +} + +/*-------------------------------------------------------*/ +/* l1pddsp_single_block() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_single_tx_block(UWORD8 burst_nb, + UWORD8 *data, + UWORD8 tsc, + UWORD16 radio_freq) +{ + UWORD16 swap_bit; // 16 bit wide to allow shift left. + + // Burst number within a block. + l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb; + + // UL on TS=3. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> 3; + + // Swap I/Q management. + swap_bit = l1ps_swap_iq_ul(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15; + + // Select first UL polling buffer. + l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[3] = 8; + + // Store CS type: CS1 for Polling. + l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][0] = CS1_TYPE_POLL; + + if(burst_nb == BURST_1) + // Store UL data block. + { + API *ul_block_ptr = &(l1ps_dsp_com.pdsp_ndb_ptr->a_pu_gprs[0][2]); + UWORD8 i,j; + + // Copy first 22 bytes in the first 11 words after header. + for (i=0, j=0; j<11; j++) + { + ul_block_ptr[j] = ((API)(data[i])) | ((API)(data[i+1]) << 8); + i += 2; + } + // Copy last UWORD8 (23rd) in the 12th word after header. + ul_block_ptr[11] = data[22]; + } + + // Training sequence. + // Rem: bcch_freq_ind is set within Hopping algo. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ; +} + +/*-------------------------------------------------------*/ +/* l1pddsp_idle_rx_nb() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +#if FF_L1_IT_DSP_USF +void l1pddsp_idle_rx_nb(UWORD8 burst_nb, + UWORD8 tsc, + UWORD16 radio_freq, + UWORD8 timeslot_no, + BOOL ptcch_dl, + BOOL usf_interrupt) +#else +void l1pddsp_idle_rx_nb(UWORD8 burst_nb, + UWORD8 tsc, + UWORD16 radio_freq, + UWORD8 timeslot_no, + BOOL ptcch_dl) +#endif +{ + UWORD16 swap_bit; // 16 bit wide to allow shift left. + + // DL on TS=0. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= 0x80 >> timeslot_no; + + // Swap I/Q management. + swap_bit = l1ps_swap_iq_dl(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= swap_bit << 15; + + if(ptcch_dl) + { + // PTCCH/DL case must be flagged to DSP. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= (1 << B_PTCCH_DL); + } + + // Burst number within a block. + l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb; + + // Channel coding is forced to CS1. + l1ps_dsp_com.pdsp_ndb_ptr->a_ctrl_ched_gprs[timeslot_no] = CS1_TYPE_DATA; + + // pass information to DSP which good USF value is to be expected + l1ps_dsp_com.pdsp_ndb_ptr->a_usf_gprs[0] = (API) 0x07; + + #if FF_L1_IT_DSP_USF + // In case of connection establishment mode with dynamic or fixed + // allocation scheme we need to request the DSP USF interrupt for PRACH + // scheduling. Latched by DSP during Work3 + if (burst_nb == 3) + { + if (usf_interrupt) + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable |= (1 << B_USF_IT); + else + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable &= ~(1 << B_USF_IT); + } + #endif + + // RIF receiver algorithm: select 156.25. + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= 0xFFFF ^ (1 << B_RIF_RX_MODE); + + // Training sequence. + // Rem: bcch_freq_ind is set within Hopping algo. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ; + +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_transfer_mslot_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_transfer_mslot_ctrl(UWORD8 burst_nb, + UWORD8 dl_bitmap, + UWORD8 ul_bitmap, + UWORD8 *usf_table, + UWORD8 mac_mode, + UWORD8 *ul_buffer_index, + UWORD8 tsc, + UWORD16 radio_freq, + UWORD8 synchro_timeslot, + #if FF_L1_IT_DSP_USF + UWORD8 dsp_usf_interrupt + #else + UWORD8 usf_vote_enable + #endif + ) +{ + UWORD8 i; + UWORD16 swap_bit; // 16 bit wide to allow shift left. + + // Burst number within a block. + l1ps_dsp_com.pdsp_db_w_ptr->d_burst_nb_gprs = burst_nb; + + // DL bitmap. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs = dl_bitmap; + + // UL bitmap. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs = ul_bitmap; + + // Swap I/Q management for DL. + swap_bit = l1ps_swap_iq_dl(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_d_gprs |= swap_bit << 15; + + // Swap I/Q management for UL. + swap_bit = l1ps_swap_iq_ul(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15; + + if(burst_nb == 0) + { + // Store USF table + for(i=0;i<(8 - synchro_timeslot);i++) + l1ps_dsp_com.pdsp_ndb_ptr->a_usf_gprs[i] = usf_table[i+synchro_timeslot]; + + // Automatic CS detection. + for(i=0;i<8;i++) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_ctrl_ched_gprs[i] = CS_AUTO_DETECT; + + // Select first UL polling buffer. + l1ps_dsp_com.pdsp_ndb_ptr->a_ul_buffer_gprs[i] = ul_buffer_index[i]; + } + + #if !FF_L1_IT_DSP_USF + // USF vote enable programming + + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) || (DSP == 38) || (DSP == 39) + // Multislot TX allowed and usf_vote_enable suported: programs usf_vote_enable + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = usf_vote_enable; + #else + // Single slot TX only and usf_vote_enable not supported + // Modify MAC mode + if (usf_vote_enable) + // USF vote enabled --> Set MAC mode to dynamic mode + mac_mode = DYN_ALLOC; + else + // USF vote disabled --> Set MAC mode to fixed mode + mac_mode = FIX_ALLOC_NO_HALF; + #endif + + #endif // !FF_L1_IT_DSP_USF + + // MAC mode. + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= ~(3 << B_MAC_MODE); + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs |= mac_mode << B_MAC_MODE; + } + + #if FF_L1_IT_DSP_USF + if(burst_nb == 3) + { + // Program DSP to generate an interrupt once USF available if + // required. Latched by DSP during Work3. + if (dsp_usf_interrupt) + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = (1 << B_USF_IT); + else + l1ps_dsp_com.pdsp_ndb_ptr->d_usf_vote_enable = 0; + } + #endif + + // RIF receiver algorithm: select 156.25. + l1ps_dsp_com.pdsp_ndb_ptr->d_sched_mode_gprs &= 0xFFFF ^ (1 << B_RIF_RX_MODE); + + // d_fn + // ---- + // bit [0..7] -> b_fn_report, unused for GPRS + // bit [8..15] -> b_fn_sid , FN%104 + l1s_dsp_com.dsp_db_w_ptr->d_fn = ((l1s.next_time.fn_mod104)<<8); + + // Training sequence. + // Rem: bcch_freq_ind is set within Hopping algo. + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsc << B_TSQ; + +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_transfer_mslot_power() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_transfer_mslot_power(UWORD8 *txpwr, + UWORD16 radio_freq, + UWORD8 ul_bitmap) +{ + #define NO_TX 100 + + UWORD16 i; // 16 bit needed for shifting pupose. + UWORD8 last_TX = NO_TX; + UWORD8 txpwr_ramp_up; + UWORD8 txpwr_ramp_down; + UWORD8 cpt_TX = 0; + UWORD8 ts_mask; + + #if (REL99 && FF_PRF) + UWORD8 number_uplink_timeslot = 0 ; // number of uplink timeslot for power reduction feature + #endif + + + #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3) || (RF_FAM == 61)) + UWORD16 pwr_data; + UWORD16 d_ramp_idx; + WORD16 ts_conv; + #endif + +//Locosto #if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3)) + + // This function is called with an ul_bitmap which represents the abolute + // position of any Tx bursts in this frame. This bitmap has already + // absorbed any synchro change (in dl_tn), hence we need to do some + // processing to recover the actual Tx timeslot number which is used + // as an index into the txpwr array. + // + // Example : MS Class 8 with 4 Rx and 1 Tx : + // + // + // dl_ts_alloc : 0x0f 0 0 0 0 R R R R + // ul_ts_alloc : 0x02 0 0 0 0 0 0 T 0 + // shift + combine : 0 0 0 0 R R R R 0 T + // set dl_tn=4 : R R R R 0 T 0 0 + // ul_bitmap : 0x04 0 0 0 0 0 1 0 0 + // i : 5 + // + // Example : MS Class 8 with 1 Rx and 1 Tx on TS=7 + // + // dl_ts_alloc : 0x01 0 0 0 0 0 0 0 R + // ul_ts_alloc : 0x01 0 0 0 0 0 0 0 T + // shift + combine : 0 0 0 0 0 0 0 R 0 0 T + // set dl_tn=7 : R 0 0 T 0 0 0 0 + // ul_bitmap : 0x10 0 0 0 1 0 0 0 0 + // i : 3 + // + // We recover the actual timeslot from the ul_bitmap by the following + // method : + // + // ts = (i + dl_tn) - 3 + // + // Where i is the loopindex usd to detect "1" in the ul_bitmap. + // This works for MS class 8 because (3 <= i <= 5) if the + // multislot class is respected. + + #if (REL99 && FF_PRF)// power reduction feature + for (i=0; i<8; i++) + { + // computed number of uplink timeslot in order to determine uplink power reduction + ts_mask = (0x80>>i); + if (ul_bitmap & ts_mask) + number_uplink_timeslot++; + } + #endif + + + ts_conv = l1a_l1s_com.dl_tn - 3; + + // Index of the programmed ramps + d_ramp_idx = 0; + + for(i=0;i<8;i++) + { + // Program Transmit power and ramp for allocated timeslots. + if(ul_bitmap & (0x80>>i)) + { + // Fixe transmit power. + if(l1_config.tx_pwr_code == 0) + { + // Store Transmit power. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = l1_config.params.fixed_txpwr; + + // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..]. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] = + ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. +#if (RF_FAM == 61) + #if (DSP ==38) || (DSP == 39) + Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx++], + 0, /* not used */ + 0, /* not used */ + 1 /* arbitrary value for arfcn */ ); + #endif +#else + #if (CODE_VERSION != SIMULATION) + Cust_get_ramp_tab(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx++], + 0, /* not used */ + 0, /* not used */ + 1 /* arbitrary value for arfcn */ ); +#endif + #endif + } + else + { + // count the number of TX windows + cpt_TX ++; + + // Get power amplifier data. + #if(REL99 && FF_PRF) + pwr_data = Cust_get_pwr_data(txpwr[i+ts_conv], radio_freq, number_uplink_timeslot); + #else + pwr_data = Cust_get_pwr_data(txpwr[i+ts_conv], radio_freq); + #endif + + + // Store Transmit power. + #if(RF_FAM == 61) + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = (pwr_data); + #else + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_power_gprs[i] = ((pwr_data << 6) | 0x12); + #endif + + // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..] for slot i. + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] = ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_BULRAMPDEL) | (1 << B_BULRAMPDEL2)); + + // Store Ramp. + // ========== + // for the 1st TX the RAMP is: RAMP_UP_TX1 / RAMP_DOWN_TX1 + // for the 2nd TX the RAMP is: RAMP_UP_TX2 / RAMP_DOWN_TX1 + // for the 3rd TX the RAMP is: RAMP_UP_TX3 / RAMP_DOWN_TX2 + // (...) + // for the (i)th TX the RAMP is: RAMP_UP_TX_(i) / RAMP_DOWN_TX_(i-1) + // for the additionnal RAMP : xxxx / RAMP_DOWN_TX_last + + txpwr_ramp_up = txpwr[i+ts_conv]; // the ramp up is the current TX + + if(last_TX == NO_TX) // specific case of the first TX + txpwr_ramp_down = txpwr[i+ts_conv]; // the ramp down is the current TX + else + txpwr_ramp_down = txpwr[last_TX+ts_conv]; // the ramp down is the previous TX + + #if(RF_FAM == 61) + #if(DSP == 38) || (DSP == 39) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx++][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq); + #endif + #else + #if (CODE_VERSION != SIMULATION) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx++][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq); + #endif + #endif + } + + // memorize the last TX window + last_TX = i; + } + else + { + // program an interrupt in the TS following + // the last TX window and needed by the DSP + + // Is it the TS following a TX window ? +#if 0 /* original LoCosto code */ + if((i == last_TX+1) && (i<8)) +#else /* FreeCalypso TCS211 reconstruction */ + if (i == last_TX+1) +#endif + { + // program the interrupt + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[i] = (1 << B_MS_RULE); + } + } + } + + // in a multi-TX case an additionnal ramp down must be set + if(cpt_TX > 1) + { + // Control bitmap: update RAMP, use RAMP[d_ramp_idx][..] for slot i and set the interrupt +#if 0 /* FreeCalypso TCS211 reconstruction */ + if((last_TX+1) <= 7) +#endif + l1ps_dsp_com.pdsp_db_w_ptr->a_ctrl_abb_gprs[last_TX+1] = ((d_ramp_idx << B_RAMP_NB_GPRS) | (1 << B_RAMP_GPRS) | (1 << B_MS_RULE)); + + // Store Ramp. + // ========== + txpwr_ramp_up = txpwr[last_TX+ts_conv]; // this ramp up is unused (default: set to last_TX) + txpwr_ramp_down = txpwr[last_TX+ts_conv]; // the ramp down is the last TX + + #if(RF_FAM == 61) + #if(DSP ==38) || (DSP == 39) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_drp_ramp2_gprs[d_ramp_idx][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq); + #endif + #else + #if (CODE_VERSION != SIMULATION) + Cust_get_ramp_tab(&(l1ps_dsp_com.pdsp_ndb_ptr->a_ramp_gprs[d_ramp_idx][0]), txpwr_ramp_up, txpwr_ramp_down, radio_freq); + #endif + #endif + } + // #endif Locosto +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_ul_ptcch_data() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_ul_ptcch_data(UWORD8 cs_type, + UWORD16 channel_request_data, + UWORD8 bsic, + UWORD16 radio_freq, + UWORD8 timeslot_no) +{ + UWORD16 swap_bit; // 16 bit wide to allow shift left. + + // UL on TS=timeslot_no. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= 0x80 >> timeslot_no; + + // Swap I/Q management. + swap_bit = l1ps_swap_iq_ul(radio_freq); + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= swap_bit << 15; + + // Set "b_ptcch_ul" to indicate PTCCH/UL to DSP. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_u_gprs |= (1 << B_PTCCH_UL); + + // Store CS type. + l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[0] = cs_type; + + // Store UL data block. + if(cs_type == CS_PAB8_TYPE) + { + l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[1] = ((API)(bsic << 2)) | + ((API)(channel_request_data) << 8); + l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[2] = 0; + } + else + { + l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[1] = ((API)(channel_request_data) << 5); + l1ps_dsp_com.pdsp_ndb_ptr->a_ptcchu_gprs[2] = ((API)(bsic << 10)); + } +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_interf_meas_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +void l1pddsp_interf_meas_ctrl(UWORD8 nb_meas_req) +{ + // Interference measurement task set as a monitoring task within GSM interface. + // 101 means 1 meas, 102 means 2 meas ... + // Rem: swap I/Q is not managed for power measurements. + l1s_dsp_com.dsp_db_w_ptr->d_task_md = INTERF_DSP_TASK + nb_meas_req; +} + + +/*-------------------------------------------------------*/ +/* l1pddsp_transfer_meas_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_transfer_meas_ctrl(UWORD8 meas_position) +{ + // Store measurement position. + // Rem: This is a L1S filtered information giving the position of the meas. as a + // bitmap. + // Rem: swap I/Q is not managed for power measurements. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_pm_gprs = meas_position; +} + +/*-------------------------------------------------------*/ +/* l1pddsp_meas_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_meas_ctrl(UWORD8 nbmeas, UWORD8 pm_pos) +{ + // Request Signal level measurement task to DSP. A bit map is passed + // to DSP in order to specify the position of the measurement. + // Note: MSB is TN = 0 and LSB is TN = 7. + // Rem: swap I/Q is not managed for power measurements. + // Note: currently a maximum of four Pm can be performed / TDMA. This would + // be modified in a near futur. + // Note: If a Rx is programmed i.e. pm_pos = 1, only a maximum + // of 3 Pm is requested to DSP and position of the Pm are right shifted (Rx on TN = 0). + // Remark: In packet Idle mode Rx are still on TN = 0. This implies three Pm + // always after the Rx. + l1ps_dsp_com.pdsp_db_w_ptr->d_task_pm_gprs = ((UWORD8) (0xff << (8 - nbmeas))) >> pm_pos; +} + +/*-------------------------------------------------------*/ +/* l1pddsp_meas_read() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_meas_read(UWORD8 nbmeas, UWORD8 *a_pm) +{ + UWORD8 i = 0; + UWORD8 j; + UWORD8 bit_mask = 0x80; + + // Looks for first PM position + while ((i < 8) && (l1ps_dsp_com.pdsp_db_r_ptr->d_task_pm_gprs & bit_mask) == 0) + { + i++; + bit_mask >>= 1; + } + + // Read 'nbmeas' contiguous PM levels from the first PM position + // Note: PM are always programmed on contiguous timeslots +#if 0 /* original LoCosto code */ + for (j = 0; ((j < nbmeas)&&(i < 8)); j++) +#else /* FreeCalypso TCS211 reconstruction */ + for (j = 0; j < nbmeas; j++) +#endif + { + // Download PM from DSP/MCU memory interface + a_pm[j] = (l1ps_dsp_com.pdsp_db_r_ptr->a_burst_pm_gprs[i] & 0xffff) >> 5; + + // Read next PM on following TN + i++; + } +} + +/*-------------------------------------------------------*/ +/* l1pddsp_load_bcchn_task() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1pddsp_load_bcchn_task(UWORD8 tsq,UWORD16 radio_freq ) +{ + UWORD16 swap_bit = l1ps_swap_iq_dl(radio_freq); + + l1s_dsp_com.dsp_db_w_ptr->d_task_md = NBN_DSP_TASK | (swap_bit << 15); // Load BCCHN task + l1s_dsp_com.dsp_db_w_ptr->d_ctrl_system |= tsq << B_TSQ; +} +#endif diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_func.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_func.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,566 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_FUNC.C + * + * Filename l1p_func.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1P_FUNC_C + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#if (CODE_VERSION == SIMULATION) + #include "stddef.h" +#endif + +#include "l1_types.h" +#include "sys_types.h" +#include "l1_const.h" + + +#if TESTMODE + #include "l1tm_defty.h" +#endif +#if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" +#endif +#if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" +#endif +#if (L1_MP3 == 1) + #include "l1mp3_defty.h" +#endif +#if (L1_MIDI == 1) + #include "l1midi_defty.h" +#endif +#include "l1_defty.h" +#include "l1_varex.h" + +#include "cust_os.h" +#include "l1_msgty.h" +#include "l1_time.h" + +#include "l1p_cons.h" +#include "l1p_msgt.h" +#include "l1p_deft.h" +#include "l1p_vare.h" +#include "l1p_sign.h" + +#if(RF_FAM == 61) + #include "l1_rf61.h" + #include "tpudrv61.h" +#endif + +#if (CODE_VERSION == SIMULATION) + #include "l1_rf2.h" +#endif + +/*-------------------------------------------------------*/ +/* Prototypes of external functions used in this file. */ +/*-------------------------------------------------------*/ + +void l1pddsp_meas_ctrl (UWORD8 nbmeas, UWORD8 pm_pos); +void l1dtpu_meas (UWORD16 radio_freq,WORD8 agc,UWORD8 lna_off, + UWORD16 win_id,UWORD16 tpu_synchro, UWORD8 adc_active +#if (RF_FAM == 61) + ,UWORD8 afc_mode + ,UWORD8 if_ctl +#endif + ); +WORD8 Cust_get_agc_from_IL (UWORD16 radio_freq, UWORD16 agc_index, UWORD8 table_id); +void l1ps_macs_init (void); + +/*-------------------------------------------------------*/ +/* initialize_l1pvar() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* ------------- */ +/* Return : */ +/* ------------- */ +/* Description : */ +/* ------------- */ +/* This routine is used to initialize the l1pa, l1ps and */ +/* l1pa_l1ps_com global structures. */ +/*-------------------------------------------------------*/ +void initialize_l1pvar(void) +{ + UWORD8 i; + + //++++++++++++++++++++++++++++++++++++++++++ + // Reset "l1ps" structure. + //++++++++++++++++++++++++++++++++++++++++++ + + l1ps.last_PR_good = 0; + l1ps.ILmin_beacon = 255; +#if 0 /* FreeCalypso TCS211 reconstruction */ + l1ps.read_param.assignment_id = 0xFF; /* do not return non initialized value to RLC */ +#endif + + for(i = 0; i < 8; i++) + l1ps.ILmin_others[i] = l1_config.params.il_min; + + //++++++++++++++++++++++++++++++++++++++++++ + // Reset "l1pa" structure. + //++++++++++++++++++++++++++++++++++++++++++ + + for(i=0;inb_carrier = 0; + l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE; + + l1pa_l1ps_com.transfer.semaphore = TRUE; + l1pa_l1ps_com.transfer.aset = &(l1pa_l1ps_com.transfer.set[0]); + l1pa_l1ps_com.transfer.fset[0] = &(l1pa_l1ps_com.transfer.set[1]); + l1pa_l1ps_com.transfer.fset[1] = &(l1pa_l1ps_com.transfer.set[2]); + + // Initialize Downlink Power Control Struture. Set CRC to BAD, bcch_level + // and burst_level[] to INVALID. + l1pa_l1ps_com.transfer.dl_pwr_ctrl.crc_error = TRUE; + l1pa_l1ps_com.transfer.dl_pwr_ctrl.bcch_level = (WORD8)0x80;//omaps00090550 + + for(i = 0; i < 4; i++) + { + l1pa_l1ps_com.transfer.dl_pwr_ctrl.burst_level[i] = (WORD8)0x80;//omaps00090550 + } + + l1pa_l1ps_com.transfer.set[0].ul_tbf_alloc = &(l1pa_l1ps_com.transfer.ul_tbf_alloc[0]); + l1pa_l1ps_com.transfer.set[1].ul_tbf_alloc = &(l1pa_l1ps_com.transfer.ul_tbf_alloc[1]); + l1pa_l1ps_com.transfer.set[2].ul_tbf_alloc = &(l1pa_l1ps_com.transfer.ul_tbf_alloc[2]); + + for(i=0;i<3;i++) + { + l1pa_l1ps_com.transfer.set[i].SignalCode = 0; + l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot = 0; + l1pa_l1ps_com.transfer.set[i].dl_tbf_synchro_timeslot = 0; + l1pa_l1ps_com.transfer.set[i].transfer_synchro_timeslot = 0; + l1pa_l1ps_com.transfer.set[i].allocated_tbf = NO_TBF; + l1pa_l1ps_com.transfer.set[i].assignment_command = NO_TBF; + l1pa_l1ps_com.transfer.set[i].multislot_class = 0; + + l1pa_l1ps_com.transfer.set[i].packet_ta.ta = 255; + l1pa_l1ps_com.transfer.set[i].packet_ta.ta_index = 255; + l1pa_l1ps_com.transfer.set[i].packet_ta.ta_tn = 255; + + l1pa_l1ps_com.transfer.set[i].tsc = 0; + + l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel.h = 0; + l1pa_l1ps_com.transfer.set[i].freq_param.chan_sel. + rf_channel.single_rf.radio_freq = 0; + + l1pa_l1ps_com.transfer.set[i].tbf_sti.present = FALSE; + + l1pa_l1ps_com.transfer.set[i].mac_mode = 0; + + l1pa_l1ps_com.transfer.set[i].ul_tbf_alloc->tfi = 255; + l1pa_l1ps_com.transfer.set[i].dl_tbf_alloc.tfi = 255; + + l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.p0 = 255; + l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.bts_pwr_ctl_mode = 0; + l1pa_l1ps_com.transfer.set[i].dl_pwr_ctl.pr_mode = 0; + } + + //++++++++++++++++++++++++++++++++++++++++++ + // Reset "l1pa_macs_com" structure. + //++++++++++++++++++++++++++++++++++++++++++ + + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + l1ps_macs_com.rlc_downlink_call = FALSE; + #if FF_L1_IT_DSP_USF + l1ps_macs_com.usf_status = USF_AVAILABLE; + #endif + #if L1_EDA + l1ps_macs_com.fb_sb_task_enabled = FALSE; + l1ps_macs_com.fb_sb_task_detect = FALSE; + #endif + + //++++++++++++++++++++++++++++++++++++++++++ + // Reset MAC-S static structure. + //++++++++++++++++++++++++++++++++++++++++++ + l1ps_macs_init(); + + //++++++++++++++++++++++++++++++++++++++++++ + // Reset packet transfer mode commands. + //++++++++++++++++++++++++++++++++++++++++++ + + l1pa_l1ps_com.transfer.ptcch.ta_update_cmd = FALSE; + l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = FALSE; + l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = FALSE; + l1pa_l1ps_com.transfer.pdch_release_param.pdch_release_cmd = FALSE; + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; +} + +/*-------------------------------------------------------*/ +/* l1ps_reset_db_mcu_to_dsp() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_reset_db_mcu_to_dsp(T_DB_MCU_TO_DSP_GPRS *page_ptr) +{ + API i; + API size = sizeof(T_DB_MCU_TO_DSP_GPRS) / sizeof(API); + API *ptr = (API *)page_ptr; + + // Clear all locations. + for(i=0; ia_sch[0] = (1<= l1_config.std.first_radio_freq_band2)) + { + swap_iq = l1_config.std.swap_iq_band2; + } + else + { + swap_iq = l1_config.std.swap_iq_band1; + } + +#else // L1_FF_MULTIBAND = 1 below + + UWORD16 physical_band_id; + physical_band_id = + l1_multiband_radio_freq_convert_into_physical_band_id(radio_freq); + swap_iq = rf_band[physical_band_id].swap_iq; + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + switch(swap_iq) + { + case 0: /* No swap at all. */ + case 2: /* DL, no swap. */ + swap_flag = FALSE; + break; + case 1: /* DL I/Q swap. */ + case 3: /* DL I/Q swap. */ + swap_flag = TRUE; + break; + } + return(swap_flag); +} + +/*-------------------------------------------------------*/ +/* l1ps_swap_iq_ul() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +BOOL l1ps_swap_iq_ul(UWORD16 radio_freq) +{ + UWORD8 swap_iq; + BOOL swap_flag; + +#if (L1_FF_MULTIBAND == 0) + + if(((l1_config.std.id == DUAL) || (l1_config.std.id == DUALEXT) || (l1_config.std.id == DUAL_US)) && + (radio_freq >= l1_config.std.first_radio_freq_band2)) + { + swap_iq = l1_config.std.swap_iq_band2; + } + else + { + swap_iq = l1_config.std.swap_iq_band1; + } + +#else // L1_FF_MULTIBAND = 1 below + + UWORD16 physical_band_id = 0; + physical_band_id = + l1_multiband_radio_freq_convert_into_physical_band_id(radio_freq); + swap_iq = rf_band[physical_band_id].swap_iq; + +#endif // #if (L1_FF_MULTIBAND == 0) else + + switch(swap_iq) + { + case 0: /* No swap at all. */ + case 1: /* UL, no swap. */ + swap_flag = FALSE; + break; + case 2: /* UL I/Q swap. */ + case 3: /* UL I/Q swap. */ + swap_flag = TRUE; + break; + } + return(swap_flag); +} + +/*-------------------------------------------------------*/ +/* l1ps_tcr_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_tcr_ctrl(UWORD8 pm_position) +{ + UWORD16 radio_freq_ctrl; + UWORD8 lna_off; + WORD8 agc; + + UWORD8 mode = PACKET_TRANSFER; + UWORD8 input_level; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_pw = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; + #endif + + radio_freq_ctrl = l1pa_l1ps_com.cres_freq_list.alist->freq_list[l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl]; + + // Get AGC according to the last known IL. + + input_level = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + agc = Cust_get_agc_from_IL(radio_freq_ctrl, input_level >> 1, PWR_ID); + lna_off = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].lna_off; + + #if (RF_FAM == 61) // Locosto DCO + #if (PWMEAS_IF_MODE_FORCE == 0) + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw, &if_ctl, (UWORD8) L1_IL_VALID , + input_level, + l1pa_l1ps_com.p_idle_param.radio_freq, if_threshold); + #else + if_ctl = IF_120KHZ_DSP; + dco_algo_ctl_pw = DCO_IF_0KHZ; + #endif + + + l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw); + l1s.tcr_prog_done=1; + #endif + + // Memorize the IL and LNA used for AGC setting. + l1pa_l1ps_com.tcr_freq_list.used_il_lna.il = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + l1pa_l1ps_com.tcr_freq_list.used_il_lna.lna = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].lna_off; + + // tpu pgm: 1 measurement only. + l1dtpu_meas(radio_freq_ctrl, + agc, + lna_off, + 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); + + // increment carrier counter for next measurement... + if(++l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl >= l1pa_l1ps_com.cres_freq_list.alist->nb_carrier) + l1pa_l1ps_com.tcr_freq_list.tcr_next_to_ctrl = 0; + + // Program DSP, in order to performed 1 measure. + // Second argument specifies PW position. + l1pddsp_meas_ctrl(1, pm_position); + + #if (TRACE_TYPE!=0) + //trace_fct(CST_CTRL_TRANSFER_MEAS, radio_freq_ctrl); + #endif + + // Update d_debug timer + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + + // Flag measurement control. + // ************************** + + // Set flag "ms_ctrl" to nb_meas_to_perform. + // It will be used as 2 tdma delayed to trigger Read phase. + l1pa_l1ps_com.tcr_freq_list.ms_ctrl = 1; + + // 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; + +} + +/*-------------------------------------------------------*/ +/* l1ps_bcch_meas_ctrl() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_bcch_meas_ctrl(UWORD8 ts) +{ + UWORD8 lna_off; + WORD8 agc; + + UWORD8 mode = PACKET_TRANSFER; + UWORD8 input_level; + #if (RF_FAM == 61) + UWORD16 dco_algo_ctl_pw =0; + UWORD8 if_ctl=0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; + #endif + + + if ((l1s.dsp_ctrl_reg & CTRL_ABORT) == 0) + { + #define radio_freq_ctrl l1a_l1s_com.Scell_info.radio_freq + + // Get AGC according to the last known IL. + input_level = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + agc = Cust_get_agc_from_IL(radio_freq_ctrl, input_level >> 1, PWR_ID); + lna_off = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].lna_off; + // Memorize the IL and LNA used for AGC setting. + // Note: the same structure as for TCR meas is used for PC_MEAS_CHAN measurements + l1pa_l1ps_com.tcr_freq_list.used_il_lna.il = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + l1pa_l1ps_com.tcr_freq_list.used_il_lna.lna = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].lna_off; + + + #if (RF_FAM == 61) // Locosto DCO + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw, &if_ctl, (UWORD8) L1_IL_VALID, + input_level, + radio_freq_ctrl,if_threshold); + + l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw); + #endif + + + // tpu pgm: 1 measurement only. + l1dtpu_meas(radio_freq_ctrl, + agc, + lna_off, + 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); + + // Program DSP, in order to performed 1 measure. + // Second argument specifies PW position. + l1pddsp_meas_ctrl(1, (UWORD8)ts); + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + //trace_fct(CST_CTRL_SCELL_TRANSFER_MEAS, radio_freq_ctrl); + #endif + + // Update d_debug timer + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + + // Flag measurement control. + // ************************** + + l1ps.pc_meas_chan_ctrl = TRUE; + + // 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; + } +} + +/*-------------------------------------------------------*/ +/* l1ps_update_read_set_parameters() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : Updating of the "Read_param" structure*/ +/* usefull in case the aset structure has been updated */ +/* before the last read of the current block */ +/*-------------------------------------------------------*/ +void l1ps_update_read_set_parameters(void) +{ + #define READ_PARAM l1ps.read_param + #define ASET l1pa_l1ps_com.transfer.aset + + // Copy of the "aset" parameters in the "read_param" structure +#if 0 /* FreeCalypso TCS211 reconstruction */ + READ_PARAM.dl_tn = l1a_l1s_com.dl_tn; +#endif + READ_PARAM.new_set = 0; + READ_PARAM.assignment_id = ASET->assignment_id; + READ_PARAM.allocated_tbf = ASET->allocated_tbf; + READ_PARAM.dl_tfi = ASET->dl_tbf_alloc.tfi; + READ_PARAM.ul_tfi = ASET->ul_tbf_alloc->tfi; + READ_PARAM.dl_pwr_ctl = ASET->dl_pwr_ctl; + READ_PARAM.pc_meas_chan = ASET->pc_meas_chan; + + // We need to know on which frequency band we work for LNA state processing + if (!l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.h) + { + // Single frequency + READ_PARAM.radio_freq_for_lna = l1pa_l1ps_com.transfer.aset->freq_param.chan_sel.rf_channel.single_rf.radio_freq; + } + else + { + // Frequency hopping: all frequencies of the frequency list are on the same band + // We take the first frequency of the list + READ_PARAM.radio_freq_for_lna = l1pa_l1ps_com.transfer.aset->freq_param.freq_list.rf_chan_no.A[0]; + } +} +#endif diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/p_cfile/l1p_sync.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/p_cfile/l1p_sync.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,2675 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * L1P_SYNC.C + * + * Filename l1p_sync.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#define L1P_SYNC_C + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#if (CODE_VERSION == SIMULATION) + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + #include + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_signa.h" + #include "l1_proto.h" + + #if L2_L3_SIMUL + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_prot.h" + #include "l1p_mfta.h" + #include "l1p_sign.h" + #include "l1p_macr.h" + #include "l1p_proto.h" +#else + #include + #include "l1_types.h" + #include "sys_types.h" + #include "l1_const.h" + #include "l1_time.h" + + #if TESTMODE + #include "l1tm_defty.h" + #endif + #if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" + #endif + #if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" + #endif + #if (L1_MP3 == 1) + #include "l1mp3_defty.h" + #endif + #if (L1_MIDI == 1) + #include "l1midi_defty.h" + #endif + #include "l1_defty.h" + #include "cust_os.h" + #include "l1_msgty.h" + #include "l1_varex.h" + #include "l1_signa.h" + #include "l1_proto.h" + #include "l1_trace.h" + + #if L2_L3_SIMUL + #include "hw_debug.h" + #endif + + #include "l1p_cons.h" + #include "l1p_msgt.h" + #include "l1p_deft.h" + #include "l1p_vare.h" + #include "l1p_prot.h" + #include "l1p_mfta.h" + #include "l1p_sign.h" + #include "l1p_macr.h" +#endif + +#if(RF_FAM == 61) + #include "l1_rf61.h" + #include "tpudrv61.h" +#endif + +#if (GSM_IDLE_RAM !=0) + #if (OP_L1_STANDALONE == 0) + #include "csmi/sleep.h" + #else + #include "csmi_simul.h" + #endif +#endif + +/*-------------------------------------------------------*/ +/* Prototypes of external functions used in this file. */ +/*-------------------------------------------------------*/ +void l1ps_tcr_ctrl (UWORD8 pm_position); +void l1pddsp_meas_ctrl (UWORD8 nbmeas, UWORD8 pm_pos); +void l1pddsp_meas_read (UWORD8 nbmeas, UWORD8 *pm_read); +void l1pctl_transfer_agc_init(); +UWORD8 l1pctl_pgc (UWORD8 pm, UWORD8 last_known_il, UWORD8 lna_off, UWORD16 radio_freq); +void l1ps_bcch_meas_ctrl (UWORD8 ts); + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END + + +#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 + +/*-------------------------------------------------------*/ +/* l1ps_transfer_mode_manager() */ +/*-------------------------------------------------------*/ +/* Parameters : */ +/* Return : */ +/* Functionality : */ +/*-------------------------------------------------------*/ +void l1ps_transfer_mode_manager() +{ + BOOL block_boundary = TRUE; + UWORD8 current_assignment_command = NO_TBF; + #if FF_TBF + BOOL tbf_update_synchro_forced = FALSE; + #endif + + //==================================== + // NEW configuration management + //==================================== + + if(!l1pa_l1ps_com.transfer.semaphore) + // IF Transfer parameter structure protected, + // No action within L1S. + { + WORD8 i; + UWORD8 min_synchro_ts = 7; + BOOL new_tbf_installed = FALSE; + T_PACKET_TA *current_ta_config; + + // In packet transfer mode, we only detect STI at block boundaries in order to udpate the + // ASET structure after the last Control of the previous TBF + if (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) + { + if ((l1s.next_time.fn_mod13 != 0)&&(l1s.next_time.fn_mod13 != 4)&& + (l1s.next_time.fn_mod13 != 8)) + { + block_boundary = FALSE; + } + } + // Delay STI detection when a poll response hasn't already been answered + // for transition to Packet transfer mode + else if (l1a_l1s_com.l1s_en_task[POLL] == TASK_ENABLED) + { + block_boundary = FALSE; + } + + // LOOK FOR NEW ASSIGNMENT... + //=========================== + + // Consider both FREE SET... + for(i=0;i<2;i++) + { + // Is there a new transfer channel provided in "fset[i]"? + if(((l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_ASSIGNMENT_REQ) && (block_boundary == TRUE)) || + (l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_SINGLE_BLOCK_REQ)) + { + if(l1pa_l1ps_com.transfer.fset[i]->tbf_sti.present) + // Starting time present. + // Rem: starting time detected 1 frame in advance, this frame is used by + // SYNCHRO task. + { + WORD32 time_diff; + WORD8 frame_shift=0; + WORD8 tn_diff; + + + // In packet idle mode, L1 must detect if the synchronization change will happen + // from a timeslot N to a timeslot M < N because in this case, a frame is skipped + // and the MS is ready two frames after the synchronization change... a radio + // block can be missed... + // In packet transfer, the SYNCHRO task will always been executed on BURST 1, that let + // 2 frames before the new TBF starts + if (l1a_l1s_com.l1s_en_task[PDTCH] != TASK_ENABLED) + { + frame_shift -= 1; + + tn_diff = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot - + l1a_l1s_com.dl_tn; + + if(tn_diff < 0) + frame_shift -= 1; + } +//TBF_changes + + #if FF_TBF + // PDTCH task is enabled + else + { + // Pseudo TBF for Two phase access, new TBF configuration has to + // be installed for Starting Time taking into account that a + // SYNCHRO task has to be scheduled before. + if ((l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) && + (l1pa_l1ps_com.transfer.aset->pseudo_tbf_two_phase_acc)) + { + // Note: We are at block boundary. + if ((l1s.next_time.fn_mod13 == 0) || (l1s.next_time.fn_mod13 == 4)) + frame_shift -= 4; + else // i.e. (l1s.next_time.fn_mod13 == 8) + frame_shift -= 5; + } + + // Two phase access establishment on PACCH (therefore there is an + // ongoing uplink TBF). + if ((l1pa_l1ps_com.transfer.fset[i]->allocated_tbf == UL_TBF) && + (l1pa_l1ps_com.transfer.fset[i]->pseudo_tbf_two_phase_acc)) + { + // Make sure single/multi block allocation + // if a synchro task has to be inserted i.e. : + // -> we are currently in EGPRS mode + // -> and/or we change synchronization timeslot + if ( (l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot != l1a_l1s_com.dl_tn) + #if L1_EGPRS + || (l1pa_l1ps_com.transfer.aset->egprs_param.tbf_mode == TBF_MODE_EGPRS) + #endif + ) + { + // Note: We are at block boundary. + if ((l1s.next_time.fn_mod13 == 0) || (l1s.next_time.fn_mod13 == 4)) + frame_shift -= 4; + else // i.e. (l1s.next_time.fn_mod13 == 8) + frame_shift -= 5; + } + } + } + #endif + + + time_diff = ( (l1pa_l1ps_com.transfer.fset[i]->tbf_sti.absolute_fn) + + frame_shift - (l1s.next_time.fn % 42432) + 2*42432) % 42432; + + if((time_diff >= (32024)) && (time_diff <= (42431))) + // Starting time has been passed... + //--------------------------------- + { + // For SINGLE BLOCK case, an error must be reported to L3. + if(l1pa_l1ps_com.transfer.fset[i]->SignalCode == MPHP_SINGLE_BLOCK_REQ) + { + xSignalHeaderRec *msg; + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_MPHP_SINGLE_BLOCK_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->purpose = + l1pa_l1ps_com.transfer.fset[i]->assignment_command; + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->assignment_id = + l1pa_l1ps_com.transfer.fset[i]->assignment_id; + + ((T_MPHP_SINGLE_BLOCK_CON *)(msg->SigP))->status = SINGLE_STI_PASSED; + + msg->SignalCode = L1P_SINGLE_BLOCK_CON; + + // send message... + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Do not reset "tbf_sti.present". + + // Ignore the SINGLE BLOCK requested. + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + } + else + { + // Reset "tbf_sti.present" flag to take into account the new + // configuration. + l1pa_l1ps_com.transfer.fset[i]->tbf_sti.present = FALSE; + } + } + else + if(time_diff == 0) + // Starting time corresponds to current frame... + //---------------------------------------------- + { + // Reset "tbf_sti.present" flag to take into account the new + // configuration. + l1pa_l1ps_com.transfer.fset[i]->tbf_sti.present = FALSE; + } + else + // Starting time hasn't already been reached... + //--------------------------------------------- + { + // time_to_next_l1s_task updated with time to sti + Select_min_time(time_diff, l1a_l1s_com.time_to_next_l1s_task); + } + } + + // Do we switch to a new transfer configuration? + // We have to switch if, new set STI is passed. + if(!l1pa_l1ps_com.transfer.fset[i]->tbf_sti.present) + { + // Install new configuration immediately. + // Rem: the new channel will start at a block boundary because by construction + // PDTCH task is started every block boundary. + T_TRANSFER_SET *transfer_set; + + // STI has been passed, we must switch to the new config. + + #if (TRACE_TYPE!=0) + // Trace "starting time" on log file and screen. + trace_fct(CST_STI_PASSED, l1a_l1s_com.Scell_info.radio_freq); + #endif + + #if FF_TBF + // Forces a SYNCHRO task prior to new TBF configuration if + // -> Coming from 2 phases access TBF + // -> Coming from (Packet) Idle + if (((l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) && + (l1pa_l1ps_com.transfer.aset->pseudo_tbf_two_phase_acc)) + || (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_DISABLED) + ) + { + // Can not be merged with test above evaluated only when a + // starting time is present in the message. + tbf_update_synchro_forced = TRUE; + } + #endif + if (current_assignment_command == NO_TBF) + current_assignment_command = l1pa_l1ps_com.transfer.fset[i]->assignment_command; + else if ((current_assignment_command == UL_TBF) || + (current_assignment_command == DL_TBF)) + current_assignment_command = BOTH_TBF; + + // Check if anything to keep from previous configuration. + // Select the best timeslot for timebase synchro. + + if(l1pa_l1ps_com.transfer.aset->allocated_tbf != NO_TBF) + { + UWORD8 synchro_ts; + + // Check if required to take TA from previous packet assignment + // if TA not valid in new assignment command + if ( l1pa_l1ps_com.transfer.fset[i]->packet_ta.ta == 255) + { + // new TA value to be taken from previous packet TA + l1pa_l1ps_com.transfer.fset[i]->packet_ta.ta = l1pa_l1ps_com.transfer.aset->packet_ta.ta; + } + + switch(l1pa_l1ps_com.transfer.fset[i]->assignment_command) + { + case DL_TBF: + { + // If any, keep the UL allocation from previous set. + if((l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) || + (l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF)) + { + T_UL_RESSOURCE_ALLOC *ul_ptr; + + // Swap the pointers on UL parameter structures + ul_ptr = l1pa_l1ps_com.transfer.fset[i]->ul_tbf_alloc; + l1pa_l1ps_com.transfer.fset[i]->ul_tbf_alloc = + l1pa_l1ps_com.transfer.aset->ul_tbf_alloc; + l1pa_l1ps_com.transfer.aset->ul_tbf_alloc = ul_ptr; + + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = BOTH_TBF; + l1pa_l1ps_com.transfer.fset[i]->ul_tbf_synchro_timeslot = + l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + + // Chose min synchro timeslot from UL and DL TBFs. + if(l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot < + l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot) + { + synchro_ts = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + } + else + { + synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + } + } + + // No UL TBF running, select the new DL TBF synchro timeslot. + else + { + synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + } + } + break; + + case UL_TBF: + { + // If any, keep the DL allocation from previous set. + + if((l1pa_l1ps_com.transfer.aset->allocated_tbf == DL_TBF) || + (l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF)) + { + l1pa_l1ps_com.transfer.fset[i]->dl_tbf_alloc = + l1pa_l1ps_com.transfer.aset->dl_tbf_alloc; + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = BOTH_TBF; + l1pa_l1ps_com.transfer.fset[i]->dl_tbf_synchro_timeslot = + l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + + // Chose min synchro timeslot from UL and DL TBFs. + if(l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot < + l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot) + { + synchro_ts = l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + } + else + { + synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + } + } + + // No DL TBF running, select the new UL TBF synchro timeslot. + else + { + synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + } + + // Reset Repeat allocation starting time checking + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; + // Reset Allocation Exhaustion detection flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + } + break; + + case BOTH_TBF: + case NO_TBF: + default: + { + // Nothing to keep, everything (UL & DL) is replaced. + synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + + // Reset Repeat allocation starting time checking + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; + // Reset Allocation Exhaustion detection flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + } + break; + + } // end of switch(...assignment_command) + + if(synchro_ts < min_synchro_ts) + min_synchro_ts = synchro_ts; + + } // end of if(...allocated_tbf != NO_TBF) + + else + { + min_synchro_ts = l1pa_l1ps_com.transfer.fset[i]->transfer_synchro_timeslot; + } + + // New set becomes active and old becomes free. + + // Save a pointer on currently used PTCCH parameters + current_ta_config = &l1pa_l1ps_com.transfer.aset->packet_ta; + + transfer_set = l1pa_l1ps_com.transfer.aset; + l1pa_l1ps_com.transfer.aset = l1pa_l1ps_com.transfer.fset[i]; + l1pa_l1ps_com.transfer.fset[i] = transfer_set; + l1pa_l1ps_com.transfer.fset[i]->allocated_tbf = NO_TBF; + + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = min_synchro_ts; + + // Set local flag. + new_tbf_installed = TRUE; + + if(l1pa_l1ps_com.transfer.aset->SignalCode == MPHP_ASSIGNMENT_REQ) + // Assignement confirmation message is sent + { + xSignalHeaderRec *msg; + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_L1P_TRANSFER_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_TRANSFER_DONE; + + ((T_L1P_TRANSFER_DONE *) (msg->SigP))->assignment_id = + l1pa_l1ps_com.transfer.aset->assignment_id; + + // Insert "t_difference" information in L1P_TRANSFER_DONE msg + // will be used in Ncell Dedic6 state machine to request a reset + // or not of the state machine + ((T_L1P_TRANSFER_DONE *) (msg->SigP))->tn_difference = + min_synchro_ts - l1a_l1s_com.dl_tn; + + + // detect the Transition IDLE -> Transfer + if (l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) + ((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update = TRUE; + else + ((T_L1P_TRANSFER_DONE *) (msg->SigP))->Transfer_update = FALSE; + + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + + // New config has been acknowledeged, clear SignalCode... + l1pa_l1ps_com.transfer.fset[i]->SignalCode = NULL; + l1pa_l1ps_com.transfer.aset->SignalCode = NULL; + + } // end if(...tbf_sti.present) + } // end of if(...SignalCode == MPHP_ASSIGNMENT_REQ) + } + + if(new_tbf_installed == TRUE) + { + // Start the new configuration + //---------------------------- + + // Enable PACKET tasks. + { + // Set assignment_command to the last enabled TBF type. + // This permits MAC-S to correctly manage TBF boundary conditions. + l1pa_l1ps_com.transfer.aset->assignment_command = current_assignment_command; + + // Flag the new configuration to MACS. + l1ps_macs_com.new_set = TRUE; + + // Flag the new configuration in order to update the Read set parameters + // in the first Read phase of the new TBF + // This permits to start using the new aset parameters for the first Control of + // the first block of the new TBF and to keep the parameters needed for the + // last read phase of the last block of the previous TBF. + l1ps.read_param.new_set = TRUE; + +// TBF_changes + #if !FF_TBF + // We need to detect that we just leaving CS/P Idle mode to enter + // in Packet Transfer mode. Then we have to enable SYNCHRO task on dectection + // of a mode change (Idle or Packet idle -> Packet transfer). + // Note: This check can't be gathered with the one done a little bit later + // on tn_difference and SINGLE task from the fact that the allocated_tbf + // is checked and PDTCH enabled. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + if(l1a_l1s_com.l1s_en_task[PDTCH] == TASK_DISABLED) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + l1a_l1s_com.dsp_scheduler_mode = GPRS_SCHEDULER; + } + } + #endif + + // Disable interference measurements + l1a_l1s_com.l1s_en_task[ITMEAS] = TASK_DISABLED; + + // Check for Continuous Timing advance procedure. + // Enable PTCCH task if required. + if((l1pa_l1ps_com.transfer.aset->packet_ta.ta_index != 255) && + (l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn != 255)) + { + // No action when the configuration is the same as the current one. + if((l1pa_l1ps_com.transfer.aset->packet_ta.ta_index != current_ta_config->ta_index) || + (l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn != current_ta_config->ta_tn) || + (l1a_l1s_com.l1s_en_task[PTCCH] == TASK_DISABLED)) + // The configuration is different than the current one or no PTCCH is currently running + // (for example in packet idle) + { + // Reset PTCCH execution variables. + l1pa_l1ps_com.transfer.ptcch.activity = 0; + l1pa_l1ps_com.transfer.ptcch.request_dl = FALSE; + + // Enable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_ENABLED; + } + } + else + // PTCCH is not configured. + { + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + } + + // Transfer AGC initialization + l1pctl_transfer_agc_init(); + + switch(l1pa_l1ps_com.transfer.aset->allocated_tbf) + { + case SINGLE_BLOCK_UL: + { + // Set SINGLE execution variables. + l1pa_l1ps_com.transfer.single_block.activity = SINGLE_UL; // UL enabled + + // Enable SINGLE task. + l1a_l1s_com.l1s_en_task[SINGLE] = TASK_ENABLED; + } + break; + + case SINGLE_BLOCK_DL: + { + // Set SINGLE execution variables. + l1pa_l1ps_com.transfer.single_block.activity = SINGLE_DL; // DL enabled + + // Enable SINGLE task. + l1a_l1s_com.l1s_en_task[SINGLE] = TASK_ENABLED; + } + break; + + case TWO_PHASE_ACCESS: + { + // Set SINGLE execution variables. + l1pa_l1ps_com.transfer.single_block.activity |= SINGLE_DL; // DL enabled + l1pa_l1ps_com.transfer.single_block.activity |= SINGLE_UL; // UL enabled + + // Enable SINGLE task. + l1a_l1s_com.l1s_en_task[SINGLE] = TASK_ENABLED; + } + break; + + default: + { + /* + * FreeCalypso: removal of the following line is + * TCS211 reconstruction + */ + //if(l1a_l1s_com.l1s_en_task[PDTCH] == TASK_ENABLED) + //In case of transition idle to transfer the Packet transfer mode is set when synchro is executed + // Layer 1 internal mode is set to PACKET TRANSFER MODE. + l1a_l1s_com.mode = PACKET_TRANSFER_MODE; + + // Enable PDTCH task. + l1a_l1s_com.l1s_en_task[PDTCH] = TASK_ENABLED; + + // Need to disable SINGLE task for two phase access case + l1a_l1s_com.l1s_en_task[SINGLE] = TASK_DISABLED; + } + break; + } // End switch() + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + // Save the "timeslot difference" between new and old configuration + // in "tn_difference". + // tn_difference -> loaded with the number of timeslot to shift. + // dl_tn -> loaded with the new timeslot. + l1a_l1s_com.tn_difference += min_synchro_ts - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = min_synchro_ts; + + #if !FF_TBF + // Enable SYNCHRO task only if lowest allocated timeslot changed + // or if each time the SINGLE task is enabled + // In the specific case of the SINGLE task, the GPRS_SCHEDULER + // has to be selected. + if((l1a_l1s_com.tn_difference != 0) || + (l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED)) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + l1a_l1s_com.dsp_scheduler_mode = GPRS_SCHEDULER; + } + #else + // Enable SYNCHRO task if at least one of these conditions fulfilled: + // -> Change in the timeslot synhronization + // -> Change of the ongoing TBF mode (synchro_forced) + // -> Exit of two phase access (synchro_forced) + // -> Coming from (Packet) Idle (synchro forced) + // -> SINGLE task enabled + if((l1a_l1s_com.tn_difference != 0) || + (tbf_update_synchro_forced) || + (l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED)) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + + l1a_l1s_com.dsp_scheduler_mode = GPRS_SCHEDULER; + } + #endif + } + else + {}// L1A is touching dl_tn, tn_difference and dsp_scheduler_mode parameters... + } + } + + // LOOK FOR TIMING AVANCE UPDATE + //=============================== + + if(l1pa_l1ps_com.transfer.ptcch.ta_update_cmd == TRUE) + { + #define CURRENT_TA_CONFIG l1pa_l1ps_com.transfer.aset->packet_ta + #define NEW_TA_CONFIG l1pa_l1ps_com.transfer.ptcch.packet_ta + + // Only update if the assignment_id of the running TBF matches with the assignment_id + // given in the MPHP_TIMING_ADVANCE_REQ message + if (l1pa_l1ps_com.transfer.ptcch.assignment_id == l1pa_l1ps_com.transfer.aset->assignment_id) + { + xSignalHeaderRec *msg; + + // Immediate Update of PACKET TA structure. + //----------------------------------------- + + // Update TA value only if a new value is provided. + if(NEW_TA_CONFIG.ta != 255) + CURRENT_TA_CONFIG.ta = NEW_TA_CONFIG.ta; + + if((NEW_TA_CONFIG.ta_index != 255) && + (NEW_TA_CONFIG.ta_tn != 255)) + // There is a New PTCCH configuration. + { + // No action when the configuration is the same as the current one. + + if((NEW_TA_CONFIG.ta_index != CURRENT_TA_CONFIG.ta_index) || + (NEW_TA_CONFIG.ta_tn != CURRENT_TA_CONFIG.ta_tn)) + // The configuration is different than the current one. + { + // Download the new configuration. + CURRENT_TA_CONFIG.ta_index = NEW_TA_CONFIG.ta_index; + CURRENT_TA_CONFIG.ta_tn = NEW_TA_CONFIG.ta_tn; + + // Reset PTCCH execution variables. + l1pa_l1ps_com.transfer.ptcch.activity = 0; + l1pa_l1ps_com.transfer.ptcch.request_dl = FALSE; + + // Enable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_ENABLED; + } + } + else + // PTCCH is not configured. + { + // Diable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + } + + // Send confirmation message to L3. + msg = os_alloc_sig(sizeof(T_MPHP_TIMING_ADVANCE_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_TA_CONFIG_DONE; + ((T_MPHP_TIMING_ADVANCE_CON *) msg->SigP)->assignment_id = + l1pa_l1ps_com.transfer.aset->assignment_id; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + } // End if "assignment_id of the running TBF matches" + + // Reset Control code. + l1pa_l1ps_com.transfer.ptcch.ta_update_cmd = FALSE; + + } // End if(...ta_update_cmd == TRUE) + + // LOOK FOR PSI PARAMETERS UPDATE + //=============================== + + if(l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd == TRUE) + { + // Update parameters + l1a_l1s_com.Scell_info.pb = l1pa_l1ps_com.transfer.psi_param.Scell_pb; + l1pa_l1ps_com.access_burst_type = l1pa_l1ps_com.transfer.psi_param.access_burst_type; + + // Reset Control code. + l1pa_l1ps_com.transfer.psi_param.psi_param_update_cmd = FALSE; + } + + /***********************************************************/ + /* TBF release, PDCH release, Repeat allocation, Fixed */ + /* allocation exhaustion */ + /***********************************************************/ + + // These events are only taken into account on block boundaries + // in order to keep the "aset" structure unchanged for all the control phases + // of the last block before modification + + if(block_boundary) + { + // LOOK FOR TBF TO BE RELEASED... + //=============================== + + if(l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd == TRUE) + { + xSignalHeaderRec *msg; + +//TBF_changes + #if !FF_TBF + switch(l1pa_l1ps_com.transfer.tbf_release_param.released_tbf) + #else + UWORD8 released_tbf; + + // Special case if we got a request to release a two phase access TBF: + // It is registered within ASET structure as an uplink TBF. If we are + // currently in pseudo TBF for two phase access, we process the request + // like an uplink release, otherwise we skip it and just send the + // L1P_TBF_RELEASED to L1A. + + released_tbf = l1pa_l1ps_com.transfer.tbf_release_param.released_tbf; + + if (released_tbf == TWO_PHASE_ACCESS) + { + if (l1pa_l1ps_com.transfer.aset->pseudo_tbf_two_phase_acc) + released_tbf = UL_TBF; + else + released_tbf = NO_TBF; + } + + switch(released_tbf) + #endif + { + case UL_TBF: + { + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == UL_TBF) + { + // Disable PDTCH task. + l1a_l1s_com.l1s_en_task[PDTCH] = TASK_DISABLED; + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + // Free the active set. + l1pa_l1ps_com.transfer.aset->allocated_tbf = NO_TBF; + } + else + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF) + { + // Still DL_TBF running. + // We must synchro to the 1st timeslot of DL_TBF. + + // REM: the new configuration is not flagged to MACS via "l1ps_macs_com.new_set" + // since MACS will detect the alloc change. + + // Active set becomes DL TBF. + l1pa_l1ps_com.transfer.aset->allocated_tbf = DL_TBF; + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + + // Enable SYNCHRO task only when camp timeslot is changed. + if(l1a_l1s_com.tn_difference != 0) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + } + + // Diable PTCCH if timeslot doesn't match with the remaining DL TBF allocation + if (!((0x80 >> l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn) & + l1pa_l1ps_com.transfer.aset->dl_tbf_alloc.timeslot_alloc)) + { + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_ptcch_disable(); + #endif + } + + } + + // Reset Repeat allocation starting time checking + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; + // Reset Allocation Exhaustion detection flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + #if L1_EDA + // Disable FB/SB task detection mechanism for MS class 12 + l1ps_macs_com.fb_sb_task_detect = FALSE; + #endif + } + break; + + case DL_TBF: + { + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == DL_TBF) + { + // Disable PDTCH task. + l1a_l1s_com.l1s_en_task[PDTCH] = TASK_DISABLED; + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + // Free the active set. + l1pa_l1ps_com.transfer.aset->allocated_tbf = NO_TBF; + } + else + if(l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF) + { + // Still UL_TBF running. + // We must synchro to the 1st timeslot of UL_TBF. + + // REM: the new configuration is not flagged to MACS via "l1ps_macs_com.new_set" + // since MACS will detect the alloc change. + + // Active set becomes UL TBF. + l1pa_l1ps_com.transfer.aset->allocated_tbf = UL_TBF; + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + + // Enable SYNCHRO task only when camp timeslot is changed. + if(l1a_l1s_com.tn_difference != 0) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + } + + // Diable PTCCH if timeslot doesn't match with the remaining UL TBF allocation + if (!((0x80 >> l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn) & + l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc)) + { + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_ptcch_disable(); + #endif + } + + } + } + break; + + case BOTH_TBF: + { + // No more TBF... + // Disable PDTCH task. + l1a_l1s_com.l1s_en_task[PDTCH] = TASK_DISABLED; + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + // Free the active set. + l1pa_l1ps_com.transfer.aset->allocated_tbf = NO_TBF; + + // Reset Repeat allocation starting time checking + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; + // Reset Allocation Exhaustion detection flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + #if L1_EDA + // Disable FB/SB task detection mechanism for MS class 12 + l1ps_macs_com.fb_sb_task_detect = FALSE; + #endif + } + break; + + } + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_L1P_TBF_RELEASED)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_TBF_RELEASED; + + // initialize the TBF type for the confirmation msg + ((T_L1P_TBF_RELEASED *) msg->SigP)->tbf_type = l1pa_l1ps_com.transfer.tbf_release_param.released_tbf; + + if (l1pa_l1ps_com.transfer.aset->allocated_tbf == NO_TBF) + { + /* + * FreeCalypso: removal of the following line is + * TCS211 reconstruction + */ + //l1ps.read_param.assignment_id = 0x01; /* default non initialised value for next tbf */ + + ((T_L1P_TBF_RELEASED *) msg->SigP)->released_all = TRUE; + + #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36) || (DSP == 37) + // Correction of BUG1041: reset of multislot bit in d_bbctrl_gprs + // when leaving patcket transfer. + l1ps_dsp_com.pdsp_ndb_ptr->d_bbctrl_gprs = l1_config.params.bbctrl; + #endif + } + else + { + ((T_L1P_TBF_RELEASED *) msg->SigP)->released_all = FALSE; + } + + // Insert "tn_difference" information in L1P_TBF_RELEASED msg + // will be used in Ncell Dedic6 state machine to request a reset + // or not of the state machine. + ((T_L1P_TBF_RELEASED *) (msg->SigP))->tn_difference = l1a_l1s_com.tn_difference; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Flag the new configuration in order to update the Read set parameters + // with the "aset" structure modifications in the first PDTCH Read phase + // after configuration change + l1ps.read_param.new_set = TRUE; + + // Reset Control code. + l1pa_l1ps_com.transfer.tbf_release_param.tbf_release_cmd = FALSE; + } + + // LOOK FOR PDCH TO BE RELEASED... + //================================ + + if(l1pa_l1ps_com.transfer.pdch_release_param.pdch_release_cmd == TRUE) + { + xSignalHeaderRec *msg; + UWORD8 timeslot,timeslot_alloc; + + // PDCH Release only apply if the assignement_id of the running TBF matches + // with the assignment_id included in the MPHP_PDCH_RELEASE_REQ message + if (l1pa_l1ps_com.transfer.pdch_release_param.assignment_id == l1pa_l1ps_com.transfer.aset->assignment_id) + { + + // Update timeslot allocation bitmaps + l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc &= l1pa_l1ps_com.transfer.pdch_release_param.timeslot_available; + l1pa_l1ps_com.transfer.aset->dl_tbf_alloc.timeslot_alloc &= l1pa_l1ps_com.transfer.pdch_release_param.timeslot_available; + + // Process the downlink TBF first allocated timeslot + timeslot_alloc = l1pa_l1ps_com.transfer.aset->dl_tbf_alloc.timeslot_alloc; + timeslot = 0; + + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + + l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot = timeslot; + + // Process the uplink TBF first allocated timeslot + timeslot_alloc = l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc; + timeslot = 0; + #if L1_EDA + // Dynamic allocation mode or Extended Dynamic allocation mode + if((l1pa_l1ps_com.transfer.aset->mac_mode == DYN_ALLOC) || (l1pa_l1ps_com.transfer.aset->mac_mode == EXT_DYN_ALLOC)) + #else + // Dynamic allocation mode + if(l1pa_l1ps_com.transfer.aset->mac_mode == DYN_ALLOC) + #endif + { + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + } + else + // Fixed allocation mode + if(l1pa_l1ps_com.transfer.aset->mac_mode == FIX_ALLOC_NO_HALF) + { + // If the control timeslot hasn't been released + if (l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc & + (0x80 >> l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->fixed_alloc.ctrl_timeslot)) + { + // The first allocated timeslot is the control timeslot + timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->fixed_alloc.ctrl_timeslot; + } + else + { + // The first allocated timeslot is found in the allocation bitmap + while((timeslot<7) && !(timeslot_alloc & (0x80>>timeslot))) + { + timeslot++; + } + } + } + + l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot = timeslot; + + // Fill "synchro_timeslot" which will be the frame synchro slot. + switch(l1pa_l1ps_com.transfer.aset->allocated_tbf) + { + case(DL_TBF): + { + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + } + break; + + case(UL_TBF): + { + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + } + break; + + case(BOTH_TBF): + { + if (l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot > l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot) + { + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + } + else + { + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + } + } + break; + } + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + // New synchronization + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot; + + // REM: the new configuration is not flagged to MACS via "l1ps_macs_com.new_set" + // since MACS will detect the alloc change. + + // Enable SYNCHRO task only when camp timeslot is changed. + if(l1a_l1s_com.tn_difference != 0) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + } + + // Disable PTCCH if timeslot doesn't match with the remaining PDCH allocation + if (!((0x80 >> l1pa_l1ps_com.transfer.aset->packet_ta.ta_tn) & + l1pa_l1ps_com.transfer.pdch_release_param.timeslot_available)) + { + // Disable PTCCH task. + l1a_l1s_com.l1s_en_task[PTCCH] = TASK_DISABLED; + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + l1_trace_ptcch_disable(); + #endif + } + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_L1P_PDCH_RELEASE_CON)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_PDCH_RELEASED; + + ((T_L1P_PDCH_RELEASE_CON *) msg->SigP)->assignment_id = l1pa_l1ps_com.transfer.pdch_release_param.assignment_id; + + // Insert "tn_difference" information in T_L1P_PDCH_RELEASE_CON msg + // will be used in Ncell Dedic6 state machine to request a reset + // or not of the state machine + ((T_L1P_PDCH_RELEASE_CON *) (msg->SigP))->tn_difference = l1a_l1s_com.tn_difference; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Flag the new configuration in order to update the Read set parameters + // with the "aset" structure modifications in the first PDTCH Read phase + // after configuration change + l1ps.read_param.new_set = TRUE; + + } // End if "assignment_id matches with the running TBF" + + // Reset Control code. + l1pa_l1ps_com.transfer.pdch_release_param.pdch_release_cmd = FALSE; + } + + // LOOK FOR REPEAT ALLOCATION ... + //================================ + + if(l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation) + { + UWORD8 timeslot,timeslot_alloc; + + // Starting time checking... + //-------------------------- + + if(l1pa_l1ps_com.transfer.repeat_alloc.tbf_sti.present) + // Starting time present. + // Rem: starting time detected 1 frame in advance, this frame is used by + // SYNCHRO task. + { + WORD32 time_diff; + + // If synchro change occurs, it's always from a timeslot N to N + 1 + time_diff = ( (l1pa_l1ps_com.transfer.repeat_alloc.tbf_sti.absolute_fn - 1) + - (l1s.next_time.fn % 42432) + 2*42432) % 42432; + + // Starting time has been passed... + if(((time_diff >= (32024)) && (time_diff <= (42431))) || (time_diff == 0)) + { + l1pa_l1ps_com.transfer.repeat_alloc.tbf_sti.present = FALSE; + } + } // End if "starting time present" + + // Starting time passed... + //------------------------ + + // If the repeat allocation starts on this frame... + if (!l1pa_l1ps_com.transfer.repeat_alloc.tbf_sti.present) + { + #if (TRACE_TYPE!=0) + // Trace "starting time" on log file and screen. + trace_fct(CST_STI_PASSED, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Update ts_override and starting time + l1pa_l1ps_com.transfer.aset->ts_override = l1pa_l1ps_com.transfer.repeat_alloc.ts_override; + l1pa_l1ps_com.transfer.aset->tbf_sti.absolute_fn = l1pa_l1ps_com.transfer.repeat_alloc.tbf_sti.absolute_fn; + + // Lowest allocated timeslot for the UL TBF + + // If the downlink control timeslot hasn't been released: it's the downlink control timeslot + // Else no change + if ( l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc + & (0x80 >> l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->fixed_alloc.ctrl_timeslot)) + { + // Synchronization on the downlink control timeslot + l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->fixed_alloc.ctrl_timeslot; + } + + // Synchronization + + // If a downlink TBF is enabled + if ( l1pa_l1ps_com.transfer.aset->allocated_tbf == BOTH_TBF) + { + // Synchronization on the downlink TBF lowest allocated timeslot ? + if (l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot > l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot) + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->dl_tbf_synchro_timeslot; + else + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + } + // Else: synchronization on the uplink TBF lowest allocated timeslot + else + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot; + + // Enable SYNCHRO task only when camp timeslot is changed. + if(l1a_l1s_com.tn_difference != 0) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + } + + // Set assignment_command to the last enabled TBF type. + // This permits MAC-S to correctly manage TBF boundary conditions. + if ((current_assignment_command == NO_TBF) || (current_assignment_command == UL_TBF)) + l1pa_l1ps_com.transfer.aset->assignment_command = UL_TBF; + else + l1pa_l1ps_com.transfer.aset->assignment_command = BOTH_TBF; + + // Flag the new configuration to MACS. + l1ps_macs_com.new_set = TRUE; + + // Flag the new configuration in order to update the Read set parameters + // with the "aset" structure modifications in the first PDTCH Read phase + // after configuration change + l1ps.read_param.new_set = TRUE; + + // Reset Repeat allocation starting time checking + l1pa_l1ps_com.transfer.repeat_alloc.repeat_allocation = FALSE; + // Reset Allocation Exhaustion detection flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + + // Send confirmation + { + xSignalHeaderRec *msg; + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_L1P_REPEAT_ALLOC_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_REPEAT_ALLOC_DONE; + + // Insert "tn_difference" information in T_L1P_REPEAT_ALLOC_DONE msg + // will be used in Ncell Dedic6 state machine to request a reset + // or not of the state machine + ((T_L1P_REPEAT_ALLOC_DONE *) (msg->SigP))->tn_difference = l1a_l1s_com.tn_difference; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + + } // End if "Repeat allocation starts this frame..." + } // End of "Repeat allocation starting time checking" + + // LOOK FOR FIXED MODE ALLOCATION BITMAP EXHAUSTION ... + //================================================== + + if(l1ps_macs_com.fix_alloc_exhaust_flag) + { + #if (TRACE_TYPE!=0) + // Trace "starting time" on log file and screen. + trace_fct(CST_ALLOC_EXHAUSTION, l1a_l1s_com.Scell_info.radio_freq); + #endif + + // Update uplink TBF synchronization timeslot + { + UWORD8 timeslot = 0; + UWORD8 bitmap = 0x80; + + while (!(l1pa_l1ps_com.transfer.aset->ul_tbf_alloc->timeslot_alloc & bitmap)) + { + timeslot ++; + bitmap >>= 1; + } + + // Synchronization on the lowest allocated timeslot for uplink tranfer + l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot = timeslot; + } + + // New synchronization only done on a timeslot inferior to current synchronization + // - if a DL TBF is present: the DL TBF synchronization is taken into account + // - an UL TBF is present: synchronization can only be done on a timeslot number inferior or + // equal to the current synchronization + if (l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot < + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot) + { + l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot = l1pa_l1ps_com.transfer.aset->ul_tbf_synchro_timeslot; + } + + // SYNCHRO task is not schedule if we are in the specific case: + // L1A is touching SYNCHRO parameters (tn_difference, dl_tn and dsp_scheduler_mode) + // and leave L1A to go in HISR (L1S) in middle of the update (cf. BUG1339) + // Note: tn_difference has to be accumulated in order to cope with the + // specific case: L1A has just updated tn_difference, dl_tn and dsp_scheduler_mode + // parameters and we enter in the HISR after the reset of the SYNCHRO Semaphore. + if(l1a_l1s_com.task_param[SYNCHRO] == SEMAPHORE_RESET) + { + l1a_l1s_com.tn_difference += l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot - l1a_l1s_com.dl_tn; + l1a_l1s_com.dl_tn = l1pa_l1ps_com.transfer.aset->transfer_synchro_timeslot; + + // Enable SYNCHRO task only when camp timeslot is changed. + if(l1a_l1s_com.tn_difference != 0) + { + l1a_l1s_com.l1s_en_task[SYNCHRO] = TASK_ENABLED; + } + } + + // Send signal to L1A + { + xSignalHeaderRec *msg; + + // Send confirmation msg to L3/MACA. + msg = os_alloc_sig(sizeof(T_L1P_ALLOC_EXHAUST_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + + msg->SignalCode = L1P_ALLOC_EXHAUST_DONE; + + // Insert "tn_difference" information in T_L1P_ALLOC_EXHAUST_DONE msg + // will be used in Ncell Dedic6 state machine to request a reset + // or not of the state machine + ((T_L1P_ALLOC_EXHAUST_DONE *) (msg->SigP))->tn_difference = l1a_l1s_com.tn_difference; + + os_send_sig(msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + } + + // Flag the new configuration in order to update the Read set parameters + // with the "aset" structure modifications in the first PDTCH Read phase + // after configuration change + l1ps.read_param.new_set = TRUE; + + // Reset flag + l1ps_macs_com.fix_alloc_exhaust_flag = FALSE; + + } // End if "fixed mode allocation bitmap has exhausted" + } // End of "block_boundary" + } // end of if(!l1pa_l1ps_com.transfer.semaphore) +} +//#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 + +/*-------------------------------------------------------*/ +/* l1ps_meas_manager() */ +/*-------------------------------------------------------*/ +/* */ +/* Description: */ +/* ------------ */ +/* This function is the tasks manager for Packet Cell */ +/* Reselection. */ +/* The followings tasks are handled: */ +/* */ +/* FSMS_MEAS: */ +/* */ +/* P_CRMS_MEAS: Packet Cell Reselection measurement */ +/* in Idle mode. The task includes: */ +/* o BA(GPRS) measurement */ +/* o Network controlled meas. */ +/* o Extended measurement */ +/* Occurrences are performed in order to satisfy the */ +/* following ETSI constraints: */ +/* 1. At least one measure of each BA BCCH carrier shall */ +/* be taken for each paging block, */ +/* 2. A minimum of one measure for each BA BCCH carrier */ +/* for every 4 second must be performed, */ +/* 3. MS is not required to take more than one sample */ +/* per second for each BCCH carrier, */ +/* 4. At least 5 measures per BA BCCH carrier are */ +/* required for a valid received level average value */ +/* (RLA_P), */ +/* 5. RLA_P shall be based on samples collected over a */ +/* period of 5s to Max{5s, five consecutive PPCH */ +/* blocks dedicated to the MS}, */ +/* 6. Samples allocated to each carrier shall as far */ +/* as possible be uniformly distributed over the */ +/* evaluation period. */ +/* */ +/* A TI condition is include: */ +/* 7. In order to save power consumption, it will be */ +/* necessary to use as far as possible the PPCH */ +/* blocks to perform a maximum of measurements during */ +/* these frames. */ +/* */ +/* From the previous constraints, it appears that */ +/* Paging block period needs to be considered to fit */ +/* ETSI consideration. */ +/* Tow case are considered: */ +/* o PPCH period >= 1s */ +/* o PPCH period < 1s */ +/* */ +/* Once all carriers of the frequency list have been */ +/* measured, a reporting message L1P_CR_MEAS_DONE is */ +/* built and sent to L1A. */ +/*-------------------------------------------------------*/ +void l1ps_meas_manager() +{ + enum states + { + NULL_MEAS = 0, + PCHTOTAL = 1, + TOTAL = 2, + MEAS = 3, + MEASTOTAL = 4 + }; + + UWORD8 IL_for_rxlev; + BOOL init_meas = FALSE; +#if (RF_FAM == 61) + UWORD16 dco_algo_ctl_pw = 0; + UWORD16 dco_algo_ctl_pw_temp = 0; + UWORD8 if_ctl = 0; + UWORD8 if_threshold = C_IF_ZERO_LOW_THRESHOLD_GSM; +#endif + #define cr_list_size l1pa_l1ps_com.cres_freq_list.alist->nb_carrier + + static WORD8 remain_carrier; + static UWORD8 nbr_meas; + static BOOL schedule_trigger; + static xSignalHeaderRec *cr_msg = NULL; + static WORD16 time_to_wake_up; + static WORD16 time_to_4s; + static WORD16 time_to_1s; + static UWORD32 fn_update; + static UWORD16 session_done; // Did a session of measures performed in the 4s period + static UWORD16 session_done_1s; // Did a session of measures performed in the 1s period + static UWORD8 state; + static UWORD32 reporting_period; // Parameter used in "reporting_period" computation + +#if (FF_L1_FAST_DECODING == 1) + if (l1a_apihisr_com.fast_decoding.deferred_control_req == TRUE) + { + /* Do not execute l1s_meas_manager if a fast decoding IT is scheduled */ + return; + } +#endif /*#if (FF_L1_FAST_DECODING == 1)*/ + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + #endif + + + //==================================================== + // RESET MEASUREMENT MACHINES WHEN ABORT EXECUTED. + //==================================================== + if(l1s.dsp_ctrl_reg & CTRL_ABORT) + // ABORT task has been controlled, which reset the MCU/DSP communication. + // We must rewind any measurement activity. + { + // Aborted measurements have to be rescheduled + nbr_meas += l1pa_l1ps_com.cr_freq_list.ms_ctrl_d + l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd; + + // Rewind "next_to_ctrl" counter to come back to the next carrier to + // measure. + l1pa_l1ps_com.cr_freq_list.next_to_ctrl = l1pa_l1ps_com.cr_freq_list.next_to_read; + + // Reset flags. + l1pa_l1ps_com.cr_freq_list.ms_ctrl = 0; + l1pa_l1ps_com.cr_freq_list.ms_ctrl_d = 0; + l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd = 0; + } + +#if (GSM_IDLE_RAM != 1) + // Test if task is disabled and cr_msg != NULL, then de-allocate memory + if (!(l1pa_l1ps_com.l1ps_en_meas & P_CRMS_MEAS) && !(l1pa_l1ps_com.meas_param & P_CRMS_MEAS)) + { + if(cr_msg != NULL) + { + // Cell reselection measurement process has been stopped by L3 + // Deallocate memory for the received message if msg not forwarded to L3. + // ---------------------------------------------------------------------- + os_free_sig(cr_msg); + DEBUGMSG(status,NU_DEALLOC_ERR) + + cr_msg = NULL; + } + } +#endif + + if((l1pa_l1ps_com.l1ps_en_meas & P_CRMS_MEAS) && (l1pa_l1ps_com.meas_param & P_CRMS_MEAS)) + // Some changes occured on the Frequency list or the PAGING PARAMETERS have + // changed. + { + // Reset Packet Cell Reselection semaphore. + l1pa_l1ps_com.meas_param &= P_CRMS_MEAS_MASK; + + // Paging process has been interrupted by a L3 message + // Deallocate memory for the received message if msg not forwarded to L3. + // ---------------------------------------------------------------------- + + //Update Frequency list pointer + l1pa_l1ps_com.cres_freq_list.alist = l1pa_l1ps_com.cres_freq_list.flist; + + // Rewind frequency list counters to come back to the first carrier of this + // aborted session. + l1pa_l1ps_com.cr_freq_list.next_to_read = 0; + l1pa_l1ps_com.cr_freq_list.next_to_ctrl = 0; + + // Reset flags. + l1pa_l1ps_com.cr_freq_list.ms_ctrl = 0; + l1pa_l1ps_com.cr_freq_list.ms_ctrl_d = 0; + l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd = 0; + + // Initialize timer + time_to_wake_up = 0; + time_to_4s = 866; + time_to_1s = 216; + fn_update = l1s.actual_time.fn; + + // Initialize Reporting Period + reporting_period = l1s.actual_time.fn; + + // Initialize Cell reselection state machine and parameters + state = NULL_MEAS; + session_done = 0; + session_done_1s = 0; + schedule_trigger = TRUE; + nbr_meas = 0; + init_meas = TRUE; + } + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif + + // Packet Idle Cell Relselection Power Measurements fonction if P_CRMS_MEAS task still enabled. + // In case L1S has switched in GPRS packet transfer mode and L1S_TRANSFER_DONE message hasn't been processed yet + // by L1A, no control or read task shall be done. + + if ((l1pa_l1ps_com.l1ps_en_meas & P_CRMS_MEAS) && !(l1pa_l1ps_com.meas_param & P_CRMS_MEAS) + && (l1a_l1s_com.l1s_en_task[PDTCH] != TASK_ENABLED)) + { + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + #endif + // Update P_CRMS_MEAS timers + { + UWORD16 fn_diff; + #define current_fn l1s.actual_time.fn + + // Compute Frame Number increment since last L1S activity + if(current_fn >= fn_update) + fn_diff = current_fn - fn_update; + else + fn_diff = (current_fn + MAX_FN) - fn_update; + + // Update timer + time_to_4s -= fn_diff; + + if(time_to_4s <= 0) + { + time_to_4s += 866; + session_done = 0; + } + + time_to_1s -= fn_diff; + + if(time_to_1s <= 0) + { + time_to_1s += 216; + session_done_1s = 0; + } + + // Note: time to next meas position is negative during the meas. + // session period + time_to_wake_up -= fn_diff; + + fn_update = current_fn; + } + + if(time_to_wake_up == 0) + { + // Schedule CR meas position for "PNP period >= 1s" case + if(l1pa_l1ps_com.pccch.pnp_period >= 216) + { + switch (state) + { + case PCHTOTAL: + case TOTAL: + { + nbr_meas = cr_list_size; + + // Measures is going to start, set "session_done" flag. + // "session_done" flag must be set at the begining of a meas. session + // in order to be able to detect crossing of the 4s boundary + session_done = 1; + } + break; + + case NULL_MEAS: + { + nbr_meas = 0; + } + break; + } + } + // Schedule CR meas position for "PNP period < 1s" case + else + { + switch (state) + { + case NULL_MEAS: + { + nbr_meas = 0; + } + break; + + case MEAS: + { + UWORD8 max_nbmeas; + WORD16 tpu_win_rest; + UWORD16 power_meas_split; + + // Compute how many BP_SPLIT remains for cr list meas + // Rem: we take into account the SYNTH load for 1st RX in next frame. + // WARNING: only one RX activity is considered in next paging block !!! + tpu_win_rest = FRAME_SPLIT - (RX_LOAD + l1_config.params.rx_synth_load_split); + + power_meas_split = (l1_config.params.rx_synth_load_split + PWR_LOAD); + max_nbmeas = 0; + + while(tpu_win_rest >= power_meas_split) + { + max_nbmeas ++; + tpu_win_rest -= power_meas_split; + } + + if (max_nbmeas > NB_MEAS_MAX_GPRS) max_nbmeas = NB_MEAS_MAX_GPRS; + + // There is no more PPCH block before end of 1s period. + // End remaining carriers. + nbr_meas = Min(remain_carrier, 4*max_nbmeas); + + // Measures is going to start, set "session_done" flag. + // "session_done_1s" flag must be set at the begining of a meas. session + // in order to be able to detect crossing of the 1s boundary + session_done_1s = 1; + + } + break; + + case MEASTOTAL: + { + nbr_meas = remain_carrier; + + // Measures is going to start, set "session_done" flag. + // "session_done_1s" flag must be set at the begining of a meas. session + // in order to be able to detect crossing of the 1s boundary + session_done_1s = 1; + + } + break; + } + } // End of else ("PNP period < 1s" case) + } + + /* --------------------------------------------------------------------*/ + /* CTRL and READ phase carrying out. "nbr_meas" measures are performed */ + /* --------------------------------------------------------------------*/ + + // ******************** + // READ task if needed + // ******************** + if(l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd) + // Background measurements.... + // A measure CTRL was performed 2 tdma earlier, read result now. + { + UWORD16 radio_freq_read; + UWORD8 pm_read[NB_MEAS_MAX_GPRS]; + UWORD8 i; + + #define next_to_read l1pa_l1ps_com.cr_freq_list.next_to_read + + // When a READ is performed we set dsp_r_page_used flag to + // switch the read page. + l1s_dsp_com.dsp_r_page_used = TRUE; + + l1_check_com_mismatch(CR_MEAS_ID); + + // Read power measurement result from DSP/MCU GPRS interface + l1pddsp_meas_read(l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd, pm_read); + + for(i=0; ifreq_list[next_to_read]; + + // Traces and debug. + // ****************** + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_READ_CR_MEAS, radio_freq_read); + #endif + + l1_check_pm_error(pm_read[i], CR_MEAS_ID); + + // Get Input level corresponding to the used IL and pm result. + IL_for_rxlev = l1pctl_pgc(((UWORD8)(pm_read[i])), + l1pa_l1ps_com.cr_freq_list.used_il_lna_dd[i].il, + l1pa_l1ps_com.cr_freq_list.used_il_lna_dd[i].lna, + radio_freq_read); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MON_MEAS(pm_read[i], IL_for_rxlev, CR_MEAS_ID, radio_freq_read) + #endif + + // Check that cr_msg hasn't been erased. + if (cr_msg == NULL) + { + cr_msg = os_alloc_sig(sizeof(T_L1P_CR_MEAS_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + cr_msg->SignalCode = L1P_CR_MEAS_DONE; + } + + #if (GSM_IDLE_RAM != 1) + // Fill reporting message. + ((T_L1P_CR_MEAS_DONE*)(cr_msg->SigP))-> + ncell_meas[next_to_read].rxlev = l1s_encode_rxlev(IL_for_rxlev); + #else + // Fill reporting message. + l1ps.ncell_meas_rxlev[next_to_read] = (WORD8) l1s_encode_rxlev(IL_for_rxlev); + #endif + // Increment "next_to_read" field for next measurement... + if(++next_to_read >= cr_list_size) + next_to_read = 0; + }//end for + + // ********** + // Reporting + // ********** + if(next_to_read == 0) + { + #if (GSM_IDLE_RAM == 1) + // Check if memory for L1P_CR_MEAS_DONE msg is allocated + if (cr_msg == NULL) + { + if (!READ_TRAFFIC_CONT_STATE) + CSMI_TrafficControllerOn(); + cr_msg = os_alloc_sig(sizeof(T_L1P_CR_MEAS_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + cr_msg->SignalCode = L1P_CR_MEAS_DONE; + } + + for(i=0; iSigP))->ncell_meas[i].rxlev = l1ps.ncell_meas_rxlev[i]; + // Fill reporting message. + } + #endif + + // Fill BA identifier field. + ((T_L1P_CR_MEAS_DONE*)(cr_msg->SigP))->list_id = l1pa_l1ps_com.cres_freq_list.alist->list_id; + + ((T_L1P_CR_MEAS_DONE*)(cr_msg->SigP))->nmeas = cr_list_size; + + // Compute and Fill reporting period value + if(l1s.actual_time.fn > reporting_period) + reporting_period = l1s.actual_time.fn - reporting_period; + else + reporting_period = l1s.actual_time.fn - reporting_period + MAX_FN; + + ((T_L1P_CR_MEAS_DONE*)(cr_msg->SigP))->reporting_period = (UWORD16)reporting_period; + + reporting_period = l1s.actual_time.fn; + + // send L1P_CR_MEAS_DONE message... + os_send_sig(cr_msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Reset pointer for debugg. + cr_msg = NULL; + } + + // Trigger measurement scheduler when meas. session is completed. + // Note: A meas. session includes all carriers of the list "PNP period >= 1s case" + // or only a sub-set of the CR freq list "PNP period < 1s case" + if(!(l1pa_l1ps_com.cr_freq_list.ms_ctrl) && !(l1pa_l1ps_com.cr_freq_list.ms_ctrl_d)) + schedule_trigger = TRUE; + }// end of READ + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif + + // ********** + // CTRL task + // ********** + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif + + if (nbr_meas > 0) + { + if(l1s.forbid_meas < 2) + { + UWORD8 max_nbmeas; + UWORD8 nb_meas_to_perform; + UWORD16 radio_freq_ctrl; + UWORD8 i; + UWORD8 pw_position = 0; // indicates first time slot in frame available for PM + WORD16 tpu_win_rest; + UWORD16 power_meas_split; + + #define next_to_ctrl l1pa_l1ps_com.cr_freq_list.next_to_ctrl + + // Compute how many BP_SPLIT remains for cr list meas + // Rem: we take into account the SYNTH load for 1st RX in next frame. + tpu_win_rest = FRAME_SPLIT - l1s.tpu_win; + power_meas_split = (l1_config.params.rx_synth_load_split + PWR_LOAD); + max_nbmeas = 0; + + while(tpu_win_rest >= power_meas_split) + { + max_nbmeas ++; + tpu_win_rest -= power_meas_split; + } + + // Compute number of PM allowed in the Frame + // Test if we are on a Paging frame + if(l1pa_l1ps_com.cr_freq_list.pnp_ctrl > 0) pw_position = 1; + + // Test if PRACH controlled in the same frame + if(l1s.tpu_win >= ((3 * BP_SPLIT) + l1_config.params.tx_ra_load_split + + l1_config.params.rx_synth_load_split)) + { + pw_position = 4; + } + + // Compute Number of measures to perform + nb_meas_to_perform = cr_list_size - next_to_ctrl; + + if(nb_meas_to_perform > max_nbmeas) + nb_meas_to_perform = max_nbmeas; + + if(nb_meas_to_perform > NB_MEAS_MAX_GPRS) + nb_meas_to_perform = NB_MEAS_MAX_GPRS; + + if (nb_meas_to_perform > nbr_meas) + nb_meas_to_perform = nbr_meas; + + for(i=0; ifreq_list[next_to_ctrl]; + +#if (L1_FF_MULTIBAND == 0) + + // Get AGC according to the last known IL. + input_level = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + agc = Cust_get_agc_from_IL(radio_freq_ctrl,input_level >> 1, PWR_ID); + lna_off = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].lna_off; + + + // Memorize the IL and LNA used for AGC setting. + //l1pa_l1ps_com.cr_freq_list.used_il_lna[i] = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset]; + l1pa_l1ps_com.cr_freq_list.used_il_lna[i].il = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset].input_level; + l1pa_l1ps_com.cr_freq_list.used_il_lna[i].lna = l1a_l1s_com.last_input_level[radio_freq_ctrl - 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(radio_freq_ctrl); + + 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_ctrl,input_level >> 1, PWR_ID); + + // Memorize the IL and LNA used for AGC setting. + //l1pa_l1ps_com.cr_freq_list.used_il_lna[i] = l1a_l1s_com.last_input_level[radio_freq_ctrl - l1_config.std.radio_freq_index_offset]; + l1pa_l1ps_com.cr_freq_list.used_il_lna[i].il = + l1a_l1s_com.last_input_level[operative_radio_freq].input_level; + l1pa_l1ps_com.cr_freq_list.used_il_lna[i].lna = + l1a_l1s_com.last_input_level[operative_radio_freq].lna_off; + +#endif // #if (L1_FF_MULTIBAND == 0) else + + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_CTRL_CR_MEAS, -1); + #endif + +#if(RF_FAM == 61) // Locosto DCO +#if (PWMEAS_IF_MODE_FORCE == 0) + cust_get_if_dco_ctl_algo(&dco_algo_ctl_pw_temp, &if_ctl, (UWORD8) L1_IL_VALID , + input_level, + radio_freq_ctrl, if_threshold); + #else + if_ctl = IF_120KHZ_DSP; + dco_algo_ctl_pw_temp = DCO_IF_0KHZ; + #endif + + dco_algo_ctl_pw |= ( (dco_algo_ctl_pw_temp & 0x03)<< (i*2)); +#endif + + + // tpu pgm: 1 measurement only. + l1dtpu_meas(radio_freq_ctrl, + agc, + lna_off, + l1s.tpu_win, + l1s.tpu_offset,INACTIVE + #if(RF_FAM == 61) + ,L1_AFC_SCRIPT_MODE + ,if_ctl + #endif + ); + + // increment carrier counter for next measurement... + if(++next_to_ctrl >= cr_list_size) + next_to_ctrl = 0; + + #if L2_L3_SIMUL + #if (DEBUG_TRACE == BUFFER_TRACE_OFFSET_NEIGH) + buffer_trace(4, l1s.actual_time.fn, radio_freq_ctrl, + l1s.tpu_win, 0); + #endif + #endif + + // Increment tpu window identifier. + l1s.tpu_win += (l1_config.params.rx_synth_load_split + PWR_LOAD); + + } // End for(...nb_meas_to_perform) + + #if(RF_FAM == 61) + l1ddsp_load_dco_ctl_algo_pw(dco_algo_ctl_pw); + #endif + + + // Program DSP, in order to performed nb_meas_to_perform measures + // Second argument specifies if a Rx burst will be received in this frame + l1pddsp_meas_ctrl(nb_meas_to_perform, pw_position); + + // Update d_debug timer + l1s_dsp_com.dsp_db_w_ptr->d_debug = (l1s.debug_time + 2) ; + + + // Flag measurement control. + // ************************** + + // Set flag "ms_ctrl" to nb_meas_to_perform. + // It will be used as 2 tdma delayed to trigger Read phase. + l1pa_l1ps_com.cr_freq_list.ms_ctrl = nb_meas_to_perform; + + // 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; + + // Update nbr_meas + nbr_meas -= nb_meas_to_perform; + + // Update remainig measurements to performed according meas done + //remain_carrier -= nb_meas_to_perform; + + } // End of test on is PBCCHS, FB/SB or BCCHN task active + } //end ctrl + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_AWAITED) + + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + #endif + + // If it's time, update time to next measures position and state + // Two cases are considered: "pnp_period >= 1s" and "pnp_period < 1s" + + if(schedule_trigger) + { + BOOL condition = FALSE; + + schedule_trigger = FALSE; + + // Compute time to next session of measures for "PNP period >= 1s" case + if(l1pa_l1ps_com.pccch.pnp_period >= 216) + { + while(!condition) + { + switch(state) + { + case NULL_MEAS: + { + #if (GSM_IDLE_RAM != 1) + // Check if memory for L1P_CR_MEAS_DONE msg is allocated + if (cr_msg == NULL) + { + cr_msg = os_alloc_sig(sizeof(T_L1P_CR_MEAS_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + cr_msg->SignalCode = L1P_CR_MEAS_DONE; + } + #endif + + if((l1pa_l1ps_com.pccch.time_to_pnp > ((866 * session_done) + time_to_4s)) && + (l1pa_l1ps_com.pccch.pnp_period >= 866)) + { + state = TOTAL; + time_to_wake_up = (433 + time_to_4s * session_done); + condition = TRUE; + } + else + { + state = PCHTOTAL; + time_to_wake_up = l1pa_l1ps_com.pccch.time_to_pnp; + condition = TRUE; + } + } + break; + + case TOTAL: + case PCHTOTAL: + state = NULL_MEAS; + break; + } + } + } // End of "PNP period >= 1s" case + else + // Compute time to next session of measures for "PNP period < 1s" case + { + while(!condition) + { + switch(state) + { + case NULL_MEAS: + { + // Let's assume a small frequency list size + // and a PNP period such that PM are performed + // on first PPCH block and then stopped. PM activity + // must be re-scheduled at the end of PPCH block. + if((l1pa_l1ps_com.pccch.time_to_pnp < time_to_1s) && !(init_meas)) + { + time_to_wake_up = l1pa_l1ps_com.pccch.time_to_pnp; + schedule_trigger = TRUE; + condition = TRUE; + } + else + { + #if (GSM_IDLE_RAM == 0) + // Check if memory for L1P_CR_MEAS_DONE msg is allocated + if (cr_msg == NULL) + { + cr_msg = os_alloc_sig(sizeof(T_L1P_CR_MEAS_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + cr_msg->SignalCode = L1P_CR_MEAS_DONE; + } + #endif + + state = MEAS; + time_to_wake_up = l1pa_l1ps_com.pccch.time_to_pnp; + remain_carrier = (WORD8)cr_list_size; + condition = TRUE; + } + } + break; + + case MEAS: + { + UWORD8 max_nbmeas; + WORD16 tpu_win_rest; + UWORD16 power_meas_split; + + // Compute how many BP_SPLIT remains for cr list meas + // Rem: we take into account the SYNTH load for 1st RX in next frame. + // WARNING: only one RX activity is considered in next paging block !!! + tpu_win_rest = FRAME_SPLIT - (RX_LOAD + l1_config.params.rx_synth_load_split); + + power_meas_split = (l1_config.params.rx_synth_load_split + PWR_LOAD); + max_nbmeas = 0; + + while(tpu_win_rest >= power_meas_split) + { + max_nbmeas ++; + tpu_win_rest -= power_meas_split; + } + + if (max_nbmeas > NB_MEAS_MAX_GPRS) max_nbmeas = NB_MEAS_MAX_GPRS; + + // Update number of remaining carrier to measure. + // Note: std.nbmeas provides max nbr of PM / TDMA + remain_carrier -= 4 * max_nbmeas; + + if(remain_carrier <= 0) + state = NULL_MEAS; + else + { + if((l1pa_l1ps_com.pccch.time_to_pnp >= time_to_1s) || !(session_done_1s)) + { + state = MEASTOTAL; + time_to_wake_up = 1; + condition = TRUE; + } + else + { + time_to_wake_up = l1pa_l1ps_com.pccch.time_to_pnp; + condition = TRUE; + } + } + } + break; + + case MEASTOTAL: + { + #if (GSM_IDLE_RAM != 1) + // Check if memory for L1P_CR_MEAS_DONE msg is allocated + if (cr_msg == NULL) + { + cr_msg = os_alloc_sig(sizeof(T_L1P_CR_MEAS_DONE)); + DEBUGMSG(status,NU_ALLOC_ERR) + cr_msg->SignalCode = L1P_CR_MEAS_DONE; + } + #endif + + state = MEAS; + time_to_wake_up = l1pa_l1ps_com.pccch.time_to_pnp; + remain_carrier = (WORD8)cr_list_size; + condition = TRUE; + } + break; + } + } // End of while + } // End of else ("PNP period < 1s" case) + } // End of if(schedule_trigger) + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif + + // Update time to next L1S task + if((l1pa_l1ps_com.cr_freq_list.ms_ctrl) || + (l1pa_l1ps_com.cr_freq_list.ms_ctrl_d)) + { + // Still some measurement results to get from DSP + l1a_l1s_com.time_to_next_l1s_task = 0; + } + else + { + // No more measurements to read, next session of meas must + // be at time_to_wake_up + Select_min_time(time_to_wake_up, l1a_l1s_com.time_to_next_l1s_task); + } + + // Clear controlled flag pnp_ctrl. + //------------------------------- + l1pa_l1ps_com.cr_freq_list.pnp_ctrl = 0; + + // C W R pipeline management. + //--------------------------- + l1pa_l1ps_com.cr_freq_list.ms_ctrl_dd = l1pa_l1ps_com.cr_freq_list.ms_ctrl_d; + l1pa_l1ps_com.cr_freq_list.ms_ctrl_d = l1pa_l1ps_com.cr_freq_list.ms_ctrl; + l1pa_l1ps_com.cr_freq_list.ms_ctrl = 0; + + // C W R pipeline management. + //--------------------------- + { + UWORD8 i; + + for(i=0; i 103) + l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0; + + // Check if it's first time, Neighbour Measurement process is launched. + // Then initialize fn_report counter and reset semaphore. + if(l1pa_l1ps_com.meas_param & P_TCRMS_MEAS) + { + // Initialize counter used to report measurements + l1pa_l1ps_com.tcr_freq_list.cres_meas_report = 0; + + // Reset Neighbour Measurements semaphore + l1pa_l1ps_com.meas_param &= P_TCRMS_MEAS_MASK; + } + + //==================================================== + // RESET MEASUREMENT MACHINES WHEN SYNCHRO EXECUTED. + //==================================================== + if(l1s.tpu_ctrl_reg & CTRL_SYNC) + // SYNCHRO task has been executed. + // -> Reset measures made on serving cell, + // -> Rewind pointer used in Neighbour Cell measurement, + // -> return. + { + + // Reset Neighbour Cell measurement machine. + // Rewind "next_to_ctrl" counter to come back to the next carrier to + // measure. + tcr_next_to_ctrl = tcr_next_to_read; + + // Reset flags. + l1pa_l1ps_com.tcr_freq_list.ms_ctrl = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd = 0; + + // Reset measures made on beacon frequency. + l1pa_l1ps_com.tcr_freq_list.beacon_meas = 0; + } + + // ******************* + // Message Allocation + // ******************* + // The reporting message must be allocated before READ phase. + + if(l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 2) + { + // Memory allocation + if (tcr_msg == NULL) + { + // alloc L1P_TCR_MEAS_DONE message... + tcr_msg = os_alloc_sig(sizeof(T_MPHP_TCR_MEAS_IND)); + DEBUGMSG(status,NU_ALLOC_ERR) + tcr_msg->SignalCode = L1P_TCR_MEAS_DONE; + } + + l1pa_l1ps_com.tcr_freq_list.first_pass_flag = TRUE; + } + + //------------------------------------------------------ + // READ and CTRL phase of the Neighbour Measurement task + //------------------------------------------------------ + + //----------- + // READ phase + //----------- + + // Test if Measurment has been removed (ms_ctrl_d forced to 0) during + // previous frame, then switch DSP read page. + if (tcr_meas_removed) + { + l1s_dsp_com.dsp_r_page_used = TRUE; + tcr_meas_removed = FALSE; + } + + // Background measurements.... + // A measurement controle was performed 2 tdma earlier, read result now!! + if(l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd != 0) + { + UWORD16 radio_freq_read; + UWORD8 pm_read; + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_READ_TCR_MEAS, (UWORD32)(-1)); + #endif + + l1_check_com_mismatch(TCR_MEAS_ID); + + // When a read is performed, we set dsp_r_page_used flag to + // switch the read page + l1s_dsp_com.dsp_r_page_used = TRUE; + + // Read power measurement result from DSP/MCU GPRS interface + l1pddsp_meas_read(l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd, &pm_read); + + l1_check_pm_error(pm_read, TCR_MEAS_ID); + + radio_freq_read = l1pa_l1ps_com.cres_freq_list.alist->freq_list[tcr_next_to_read]; + + // Get Input level corresponding to the used IL and pm result. + IL_for_rxlev = l1pctl_pgc(((UWORD8) (pm_read)), + l1pa_l1ps_com.tcr_freq_list.used_il_lna_dd.il, + l1pa_l1ps_com.tcr_freq_list.used_il_lna_dd.lna, + radio_freq_read); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MON_MEAS(pm_read, IL_for_rxlev, TCR_MEAS_ID, radio_freq_read) + #endif + + + if(l1pa_l1ps_com.tcr_freq_list.first_pass_flag) + { + // Fill reporting message: Store RXLEV + ((T_L1P_TCR_MEAS_DONE*)(tcr_msg->SigP))->acc_level[tcr_next_to_read] = + l1s_encode_rxlev(IL_for_rxlev); + + ((T_L1P_TCR_MEAS_DONE*)(tcr_msg->SigP))->acc_nbmeas[tcr_next_to_read] = 1; + } + else + { + // Fill reporting message: Accumulate RXLEV + ((T_L1P_TCR_MEAS_DONE*)(tcr_msg->SigP))->acc_level[tcr_next_to_read] += + l1s_encode_rxlev(IL_for_rxlev); + + ((T_L1P_TCR_MEAS_DONE*)(tcr_msg->SigP))->acc_nbmeas[tcr_next_to_read] += 1; + + } + + // Increment "next_to_read" field for next measurement... + if(++tcr_next_to_read >= l1pa_l1ps_com.cres_freq_list.alist->nb_carrier) + { + tcr_next_to_read = 0; + } + + // First pass has been completed on all BA list, reset "first_pass_flag" + if(tcr_next_to_read == last_stored_tcr_to_read) + l1pa_l1ps_com.tcr_freq_list.first_pass_flag = FALSE; + + } // End of READ phase + + + // ************************ + // Reporting & List Update + // ************************ + if(l1pa_l1ps_com.tcr_freq_list.cres_meas_report == 1) + { + if(tcr_msg != NULL) + { + // Fill TCR list identifier field. + ((T_L1P_TCR_MEAS_DONE*)(tcr_msg->SigP))->list_id = l1pa_l1ps_com.cres_freq_list.alist->list_id; + + // send L1P_TCR_MEAS_DONE message... + os_send_sig(tcr_msg, L1C1_QUEUE); + DEBUGMSG(status,NU_SEND_QUEUE_ERR) + + // Reset pointer for debugg. + tcr_msg = NULL; + } + + // Update Frequency list pointer and reset new list flag + if(l1pa_l1ps_com.tcr_freq_list.new_list_present) + { + //Update Frequency list pointer + l1pa_l1ps_com.cres_freq_list.alist = l1pa_l1ps_com.cres_freq_list.flist; + + // Test if a Meas has been controlled in previous frame + // Then set tcr_meas_removed flag in order to switch DSP read page in next frame + if(l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d != 0) + { + tcr_meas_removed = TRUE; + } + + // Reset pointer + tcr_next_to_ctrl = 0; + tcr_next_to_read = 0; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d = 0; + + // Reset New list flag + l1pa_l1ps_com.tcr_freq_list.new_list_present = FALSE; + } + + // While reporting, save Last "tcr_next_to_read" value to know when reset "first_pass_flag" + last_stored_tcr_to_read = tcr_next_to_read; + } + + //----------- + // CTRL phase + //----------- + + // CTRL phase is divided in two parts according measures allocated by MACS. + // CTRL phase must then be exported in CTRL PDTCH function except for the Idle + // frame where no PDTCH are programmed. + // A measure can be performed during the idle frame, only if FB/SB/PTCCH + // and Interference Measurement task is not active. + if(!(l1pa_l1ps_com.meas_param & P_TCRMS_MEAS)) + { + if((l1s.actual_time.t2 == 24) || (l1s.actual_time.t2 == 11)) + { + if(l1s.forbid_meas == 0) + { + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_CTRL_TCR_MEAS_2,(UWORD32)(-1)); + #endif + + l1ps_tcr_ctrl(0); + } + } + } + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif + + // Pipe Manager + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_dd = l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl_d = l1pa_l1ps_com.tcr_freq_list.ms_ctrl; + l1pa_l1ps_com.tcr_freq_list.ms_ctrl = 0; + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_AWAITED) + #endif + + } // End of if(l1pa_l1ps_com.l1ps_en_meas & P_TCRMS_MEAS) + + /*****************************/ + /* PC_MEAS_CHAN measurements */ + /*****************************/ + + // If PC_MEAS_CHAN = 1, then BCCH serving cell carrier must be + // measured at least 6 times per MF52. + // CTRL of Serving Cell Carrier is performed two TDMA earlier. + if(l1pa_l1ps_com.transfer.aset->pc_meas_chan == FALSE) + { + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_IT_DSP) + { + #endif + + if(l1s.tpu_ctrl_reg & CTRL_SYNC) + // SYNCHRO task has been executed. + { + l1ps.pc_meas_chan_ctrl = FALSE; + } + + //----------- + // READ phase + //----------- + + if ((l1ps.pc_meas_chan_ctrl == TRUE) && + ((l1s.actual_time.t2 == 3) || (l1s.actual_time.t2 == 11) + || (l1s.actual_time.t2 == 20))) + { + UWORD8 pm_read; + + l1_check_com_mismatch(PC_MEAS_CHAN_ID); + + // When a read is performed, we set dsp_r_page_used flag to + // switch the read page + l1s_dsp_com.dsp_r_page_used = TRUE; + + // Read power measurement result from DSP/MCU GPRS interface + l1pddsp_meas_read(1, &pm_read); + + + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_READ_PC_MEAS_CHAN,(UWORD32)(-1)); + #endif + + l1_check_pm_error(pm_read, PC_MEAS_CHAN_ID); + + l1ps.pc_meas_chan_ctrl = FALSE; + + // Get Input level corresponding to the used IL and pm result. + IL_for_rxlev = l1pctl_pgc(((UWORD8 )(pm_read)), + l1pa_l1ps_com.tcr_freq_list.used_il_lna_dd.il, + l1pa_l1ps_com.tcr_freq_list.used_il_lna_dd.lna, + l1a_l1s_com.Scell_info.radio_freq); + + #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) + RTTL1_FILL_MON_MEAS(pm_read, IL_for_rxlev, PC_MEAS_CHAN_ID, l1a_l1s_com.Scell_info.radio_freq) + #endif + + if (l1a_l1s_com.mode == PACKET_TRANSFER_MODE) + // Store RXLEV, before to pass it to maca_power_control() function.. + l1pa_l1ps_com.tcr_freq_list.beacon_meas = l1s_encode_rxlev(IL_for_rxlev); + } + + //----------- + // CTRL phase + //----------- + + // In two phase access, PC_MEAS_CHAN measurements can be done... + if((l1a_l1s_com.l1s_en_task[SINGLE] == TASK_ENABLED) && + (l1pa_l1ps_com.transfer.aset->allocated_tbf == TWO_PHASE_ACCESS)) + if (l1s.task_status[NP].current_status != ACTIVE) // avoid conflict with Normal Paging + if (l1s.task_status[EP].current_status != ACTIVE) // avoid conflict with Extended Paging + { + // Measurement on the beacon + if((l1s.actual_time.t2 == 1) || (l1s.actual_time.t2 == 9) || + (l1s.actual_time.t2 == 18)) + { + // Measurement programming + // ts 4 is specified for DSP interface ONLY because the power activity + // must be programmed after RX and/or TX activity (no multislot) + #if (TRACE_TYPE!=0) && (TRACE_TYPE!=5) + trace_fct(CST_CTRL_PC_MEAS_CHAN, (UWORD32)(-1)); + #endif + + l1ps_bcch_meas_ctrl(4); + } + } + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_IT_DSP) + #endif + + } // End of Meas made on BCCH serving cell + + #if FF_L1_IT_DSP_USF + if (l1ps_macs_com.usf_status != USF_AWAITED) + { + #endif + + if((l1pa_l1ps_com.l1ps_en_meas & P_TCRMS_MEAS) || (l1ps.pc_meas_chan_ctrl == TRUE)) + { + // C W R pipeline management. + //--------------------------- + l1pa_l1ps_com.tcr_freq_list.used_il_lna_dd = l1pa_l1ps_com.tcr_freq_list.used_il_lna_d; + l1pa_l1ps_com.tcr_freq_list.used_il_lna_d = l1pa_l1ps_com.tcr_freq_list.used_il_lna; + } + + #if FF_L1_IT_DSP_USF + } // if (l1ps_macs_com.usf_status != USF_AWAITED) + #endif + +} +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END +#endif // MOVE_IN_INTERNAL_RAM + +//#pragma DUPLICATE_FOR_INTERNAL_RAM_START +#endif +//#pragma DUPLICATE_FOR_INTERNAL_RAM_END diff -r a963c5c35f8d -r 0740b5ff15f6 src/cs/layer1/tpu_drivers/p_source0/p_tpudr12.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/layer1/tpu_drivers/p_source0/p_tpudr12.c Tue Oct 31 03:42:35 2017 +0000 @@ -0,0 +1,151 @@ +/************* Revision Controle System Header ************* + * GSM Layer 1 software + * + * Filename p_tpudr12.c + * Copyright 2003 (C) Texas Instruments + * + ************* Revision Controle System Header *************/ + +#include "l1_macro.h" +#include "l1_confg.h" + +#if L1_GPRS + +#include "sys_types.h" +#include "iq.h" +#include "l1_const.h" +#include "l1_types.h" + +#if TESTMODE + #include "l1tm_defty.h" +#endif + +#if (AUDIO_TASK == 1) + #include "l1audio_const.h" + #include "l1audio_cust.h" + #include "l1audio_defty.h" +#endif + +#if (L1_GTT == 1) + #include "l1gtt_const.h" + #include "l1gtt_defty.h" +#endif + +#if (L1_MP3 == 1) + #include "l1mp3_defty.h" +#endif + +#if (L1_MIDI == 1) + #include "l1midi_defty.h" +#endif + +#if (L1_AAC == 1) + #include "l1aac_defty.h" +#endif + +#include "l1_defty.h" +#include "l1_time.h" +#include "tpudrv.h" +#include "tpudrv12.h" +#include "armio.h" + + +// external function prototypes + +void l1dmacro_rx_up (void); +void l1dmacro_rx_down (WORD32 t); + +void l1dmacro_tx_up (void); +void l1dmacro_tx_down (WORD32 time, BOOL tx_flag, UWORD8 adc_active); + +// external variables and tables +extern SYS_UWORD16 *TP_Ptr; + + +/**************************************************************************/ +/**************************************************************************/ +/* EXTERNAL FUNCTIONS CALLED BY LAYER1 */ +/* COMMON TO L1 and TOOLKIT */ +/**************************************************************************/ +/**************************************************************************/ + +/*------------------------------------------*/ +/* l1dmacro_tx_synth */ +/*------------------------------------------*/ +/* programs RF synth for transmit */ +/* programs OPLL for transmit */ +/*------------------------------------------*/ +void l1pdmacro_tx_synth(SYS_UWORD16 radio_freq) +{ + l1dmacro_tx_synth(radio_freq); +} + +/*------------------------------------------*/ +/* l1pdmacro_rx_up */ +/*------------------------------------------*/ +/* Open window for normal burst reception */ +/*------------------------------------------*/ +void l1pdmacro_rx_up (SYS_UWORD16 radio_freq) +{ + l1dmacro_rx_up(); +} + +/*------------------------------------------*/ +/* l1pdmacro_rx_down */ +/*------------------------------------------*/ +/* Close window for normal burst reception */ +/*------------------------------------------*/ +void l1pdmacro_rx_down (SYS_UWORD16 radio_freq, UWORD8 num_rx, BOOL rx_done_flag) +{ + l1dmacro_rx_down (RX_DOWN_TABLE[num_rx - 1]); +} + +/*------------------------------------------*/ +/* l1pdmacro_tx_up */ +/*------------------------------------------*/ +/* Open transmission window for normal burst*/ +/*------------------------------------------*/ +void l1pdmacro_tx_up (SYS_UWORD16 radio_freq) +{ + l1dmacro_tx_up(); +} + +/*-------------------------------------------*/ +/* l1pdmacro_tx_down */ +/*-------------------------------------------*/ +/* Close transmission window for normal burst*/ +/*-------------------------------------------*/ +void l1pdmacro_tx_down (SYS_UWORD16 radio_freq, WORD16 time, BOOL tx_flag, UWORD8 timing_advance,UWORD8 adc_active) +{ + l1dmacro_tx_down (time, tx_flag, adc_active); +} + +/*---------------------------------------------*/ +/* l1pdmacro_it_dsp_gen */ +/*---------------------------------------------*/ +/* Generate IT to DSP */ +/*---------------------------------------------*/ +void l1pdmacro_it_dsp_gen(WORD16 time) +{ + // WARNING: 'time' must always be included between 0 and TPU_CLOCK_RANGE !!! + + *TP_Ptr++ = TPU_FAT (time); + *TP_Ptr++ = TPU_MOVE (TPU_IT_DSP_PG,0x0001); +} + +// TEMPORARY !!!!! + +/*---------------------------------------------*/ +/* l1pdmacro_anchor */ +/*---------------------------------------------*/ +/* Temporary macro used to program a TPU */ +/* scenario executed on the correct frame */ +/*---------------------------------------------*/ +void l1pdmacro_anchor(WORD16 time) +{ + // WARNING: 'time' must always be included between 0 and TPU_CLOCK_RANGE !!! + + *TP_Ptr++ = TPU_FAT (time); +} + +#endif