FreeCalypso > hg > fc-tourmaline
view src/cs/layer1/cmacs/macs.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/************* 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 <stdlib.h> #include <stdio.h> #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 <stddef.h> #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;i<NBR_SHARED_BUFFER_RLC;i++) macs.rlc_dbl_buffer[i].d_rlcmac_rx_no_gprs = 0xff; #endif /* General TBF parameters processed by MAC-S */ /*********************************************/ macs.sti_block_id = 0; /* Ressources allocated by MAC-S */ /*********************************************/ macs.rx_allocation = 0; macs.tx_allocation = 0; macs.tx_prach_allocation = 0; macs.tx_data = 0; macs.pwr_allocation = 0xff; macs.last_rx_alloc = 0; #if FF_L1_IT_DSP_USF macs.dsp_usf_interrupt = 0; #endif macs.rx_blk_period = NO_DL_BLK; macs.rlc_blocks_sent = 0; macs.rx_no = 0; macs.last_poll_response = 0; macs.usf_good = 0; macs.usf_vote_enable = 0; macs.tra_gap = 8; macs.fix_alloc_exhaust = FALSE; macs.next_usf_mon_block[0] = macs.next_usf_mon_block[1] = 0; for (i = 0; i < TS_NUMBER; i ++) { macs.ul_buffer_index[i] = INVALID; } #if L1_EDA for (i = 0; i < 4; i++) { macs.monitored_ts[i] = INVALID; } macs.rx_monitored = 0; macs.last_rx_monitored = 0; macs.lowest_poll_ts = INVALID; #endif #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) // Reset PDTCH trace structure for(i=0; i<8; i++) { trace_info.pdtch_trace.dl_status[i] = 0; trace_info.pdtch_trace.ul_status[i] = 0; trace_info.pdtch_trace.blk_status = 0; } #endif } /* End of l1ps_macs_init */ /*-----------------------------------------------------------*/ /* l1ps_macs_ctrl() */ /*-----------------------------------------------------------*/ /* Parameters:global l1ps_macs_com changed */ /* global l1s unchanged */ /* global l1a_l1s_com unchanged */ /* global l1ps_dsp_com changed */ /* */ /* Return: */ /* */ /* Description: MAC_S manages the timeslot allocation for */ /* downlink and uplink transfer and assign a */ /* measurement gap according to the MS class, */ /* the frame number when it's called and the */ /* allocation information given by Layer 1. */ /* It also program the corresponding tasks on */ /* the DSP and asks the RLC layer for uplink */ /* blocks */ /*-----------------------------------------------------------*/ void l1ps_macs_ctrl(void) { #define NDB_PTR l1ps_dsp_com.pdsp_ndb_ptr #define SET_PTR l1pa_l1ps_com.transfer.aset #if MACS_STATUS // No error l1ps_macs_com.macs_status.nb = 0; #endif /***********************************************************/ /* USF values updating in dynamic mode (first frames of */ /* block periods) */ /***********************************************************/ if ((SET_PTR->allocated_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<<L1_DYN_TRACE_CONDENSED_PDTCH) trace_info.pdtch_trace.ul_status[tn + RXTX_DELAY] = 0; #endif #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) RTTL1_FILL_MACS_STATUS(TX_CANCELLED_USF, tn) #endif } } } // End if "USF vote enabled on this timeslot" } // End for /* 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); #else //#if !L1_EDA UWORD8 i = 0; //for all timeslots that need to be monitored while ((macs.monitored_ts[i] != INVALID) && (i <= 3)) { // If USF vote was enabled on this timeslot if(macs.usf_vote_enable & (MASK_SLOT0 >> 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<Trb --> 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<Ttb --> 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<<L1_DYN_TRACE_CONDENSED_PDTCH) trace_info.pdtch_trace.ul_status[ts] |= 0x4; #endif } /* End if Tx = 1 */ } /* End for */ /* Rx and Tx MS class parameters are updated */ if (lowest_dl_ts != INVALID) rx = (UWORD8) (highest_dl_ts - lowest_dl_ts + 1); if (lowest_ul_ts != INVALID) tx = (UWORD8) (highest_ul_ts - lowest_ul_ts + 1); #if MACS_STATUS // If the Trb parameter isn't respected at the end of // the TDMA frame --> 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<<L1_DYN_TRACE_UL_NO_TA) if ((SET_PTR->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<<L1_DYN_TRACE_RLC_PARAM) { UWORD32 cs_type = 0; //Get the cs_type from the UL buffer API header //The cs_type format: byte0 (LSByte) -indicates the CS type of TS0 //byte1- CS type of TS1 //byt2 - CS type of TS2 //byte3(MSBye) - CS type of TS3 for (i=0;i<tx_no;i++) { cs_type |= ((((UWORD8) NDB_PTR->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<<L1_DYN_TRACE_RLC_PARAM) { Trace_rlc_ul_param(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 (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_CONDENSED_PDTCH) { trace_info.pdtch_trace.ul_status[poll_resp_ts] |= cs_type << 4; trace_info.pdtch_trace.ul_status[poll_resp_ts] |= 1; } #endif } // End if the poll response is processed /* If the poll response isn't processed */ /*--------------------------------------*/ else { // All allocation parameters that may have been modified to map // this poll response are restored macs.tx_allocation = tx_allocation_s; macs.rx_allocation = rx_allocation_s; macs.tx_data = tx_data_s; highest_ul_ts = highest_ul_ts_s; lowest_ul_ts = lowest_ul_ts_s; #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH) trace_info.pdtch_trace.blk_status |= 0x01; #endif #if MACS_STATUS l1ps_macs_com.macs_status.id[l1ps_macs_com.macs_status.nb]= POLL_ERROR_MS_CLASS; l1ps_macs_com.macs_status.nb ++; #endif #if (TRACE_TYPE == 1) || (TRACE_TYPE == 4) RTTL1_FILL_MACS_STATUS(POLL_REJECT, poll_resp_ts) #endif } // End if the poll response isn't processed //The trace for poll response #if FF_TBF #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_POLL_PARAM) { Trace_rlc_poll_param ( poll, //Indicate whether L1 is going to transmit poll resp or not: 0-no, 1-yes l1s.next_time.fn, //next frm on whih poll resp will be sent poll_resp_ts, //Timseslot for poll response macs.tx_allocation, (UWORD32)macs.tx_data, macs.rx_allocation, (UWORD32)macs.last_poll_response, ((NDB_PTR->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_CONDENSED_PDTCH) { //Bits7,6,5,4 (cs_type)of ul_status should all be zeros trace_info.pdtch_trace.ul_status[ts] &= 0x0f; //Make the payload as NA trace_info.pdtch_trace.ul_status[ts] |= 0x03; } #endif #endif } /* Else: uplink RLC/MAC data block transfer processing */ /*-----------------------------------------------------*/ else { #if ((TRACE_TYPE == 1) || (TRACE_TYPE == 4)) if (trace_info.current_config->l1_dyn_trace & 1<<L1_DYN_TRACE_CONDENSED_PDTCH) { trace_info.pdtch_trace.ul_status[ts] |= ((UWORD8) cs_type) << 4; trace_info.pdtch_trace.ul_status[ts] |= 2; } #endif /* A data block is assigned to timeslot ts */ tx_data_s &= (UWORD8) (~(MASK_SLOT0 >> 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<<L1_DYN_TRACE_CONDENSED_PDTCH) { trace_info.pdtch_trace.dl_status[macs.rx_no] |= tfi_result << 4; #if FF_TBF crc_error = NDB_PTR->a_dd_gprs[macs.rx_no][0] & (1<<B_CRC_BLOCK_ERROR); //In the case of GPRS b_cs_type is 4bit info. cs_type = NDB_PTR->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<<B_CRC_BLOCK_ERROR)) { trace_info.pdtch_trace.dl_status[macs.rx_no] |= 0x01; } else { // No CRC error. Good Block //dl_cs_type used only for BINARY TRACE. We put the following limitation so that //in the case of EGPRS with MCS we don't enter here. if ((cs_type > 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<<L1_DYN_TRACE_DL_PDTCH_CRC)) { BOOL crc_error=0; UWORD8 i; for(i=0;i<macs.rx_no;i++) crc_error |= ((NDB_PTR->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<<L1_DYN_TRACE_CONDENSED_PDTCH) { trace_info.pdtch_trace.dl_status[rx_no] |= payload << 6; // RRBP + S/P trace trace_info.pdtch_trace.dl_status[rx_no] |= (mac_header[0] & (0x38)) >> 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<<L1_DYN_TRACE_DL_PDTCH_CRC)) { BOOL crc_error=0; UWORD8 i; #if L1_EGPRS if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS) { for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++) crc_error |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> (1+i)); } else #endif { for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++) crc_error |= ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_gprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> (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<<L1_DYN_TRACE_IR)) && (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS)) { UWORD8 j ; // Clear ir trace variables trace_info.ir_trace.crc = 0; trace_info.ir_trace.mcs = 0; trace_info.ir_trace.status_ir_tfi = 0; trace_info.ir_trace.puncturing = 0; for(j=0;j<MS_CLASS[MAX_CLASS].rx;j++) { trace_info.ir_trace.bsn[j] = 0; trace_info.ir_trace.cv_bep_egprs[j]= 0; trace_info.ir_trace.mean_bep_egprs[j] = 0; } // Retrieve IR info from every PDCH for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;i++) { UWORD16 crc; UWORD16 bsn1, bsn2; UWORD8 mcs; UWORD8 cps; UWORD8 k; // retrieve coding scheme mcs = (macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & CS_EGPRS_MASK); j = k = 0 ; // retrieve BSN switch (mcs) { case CS1_TYPE_POLL: case CS1_TYPE_DATA: case CS2_TYPE: case CS3_TYPE: case CS4_TYPE: // GPRS data block if ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) || (mcs == CS1_TYPE_POLL)) bsn1 = 0xffff; else bsn1 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][SIZE_DSP_HEADER_EGPRS + 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<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;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 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & (1 << B_CRC_BLOCK_ERROR)) >> B_CRC_BLOCK_ERROR); if (crc_error_bler == TRUE) l1tm.tmode_stats.bler_crc[i]++; } } else #endif { for(i=0;i<macs.rlc_dbl_buffer[macs.dl_buffer_index].d_rlcmac_rx_no_gprs;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 = ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.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 } } // 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<<L1_DYN_TRACE_RLC_PARAM) && (rlc_buffer != NULL)) { UWORD8 i; UWORD16 dl_blk_status[4] = {0,0,0,0}; for (i=0;i<macs.rx_no;i++) { #if (L1_EGPRS) if (l1ps_macs_com.rlc_downlink_bufferize_param.tbf_mode == TBF_MODE_EGPRS) { dl_blk_status[i] = A_DD_XGPRS[TBF_MODE_EGPRS][i][0]; } else { #endif dl_blk_status[i] = (((UWORD8) NDB_PTR->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<<L1_DYN_TRACE_CONDENSED_PDTCH) { // If some RX have been received or some TX have been programmed if ((macs.last_rx_alloc != 0) || (macs.tx_allocation != 0)) { // Send trace Trace_condensed_pdtch(macs.last_rx_alloc, macs.tx_allocation); } // Reset PDTCH trace structure for(i=0; i<8; i++) { trace_info.pdtch_trace.dl_status[i] = 0; trace_info.pdtch_trace.ul_status[i] = 0; } trace_info.pdtch_trace.dl_cs_type = 0; trace_info.pdtch_trace.blk_status = 0; } #endif // Last_poll_error processing //--------------------------- // All slots allocated for poll response transmission (allocated in tx_allocation // but not in tx_data) are set to 0 (no error) in last_poll_response macs.last_poll_response &= (UWORD8) (~(macs.tx_allocation) | macs.tx_data); /* last_poll_response correspondance with network timeslot numbers */ i = macs.old_synchro_ts - RXTX_DELAY; if (i > 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<<L1_DYN_TRACE_RLC_PARAM) { Trace_rlc_dl_param(l1ps.read_param.assignment_id, l1s.actual_time.fn, (UWORD32) &(NDB_PTR->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<<L1_DYN_TRACE_CONDENSED_PDTCH) { // If some RX have been received or some TX have been programmed if ((macs.last_rx_alloc != 0) || (macs.tx_allocation != 0)) { // Send trace Trace_condensed_pdtch(macs.last_rx_alloc, macs.tx_allocation); } // Reset PDTCH trace structure for(i=0; i<8; i++) { trace_info.pdtch_trace.dl_status[i] = 0; trace_info.pdtch_trace.ul_status[i] = 0; } trace_info.pdtch_trace.dl_cs_type = 0; trace_info.pdtch_trace.blk_status = 0; } #endif // Last_poll_error processing //--------------------------- /* All slots allocated for poll response transmission (allocated in tx_allocation but not in tx_data) are set to 0 (no error) in last_poll_response */ macs.last_poll_response &= (UWORD8) (~(macs.tx_allocation) | macs.tx_data); /* last_poll_response correspondance with network timeslot numbers */ i = macs.old_synchro_ts - RXTX_DELAY; if (i > 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<NBR_BUFFER_GPRS;i++) { memcpy((char*) &macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_gprs[i][0], (char*) A_DD_XGPRS[TBF_MODE_GPRS][i], SIZE_GPRS_DL_BUFF * sizeof(API)); } } // EGPRS mode #if L1_EGPRS else { // Parse every expected block for (i = 0; i < macs.rx_no; i++) { // If not already copied if ((macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0] & CS_EGPRS_MASK) == CS_NONE_TYPE) { // New block available in API if (A_DD_XGPRS[TBF_MODE_EGPRS][i][0] & (1 << B_BLK_READY)) { // Copy block from API to SRAM memcpy((char*) &macs.rlc_dbl_buffer[macs.dl_buffer_index].buffer.a_dd_egprs[i][0], (char*) A_DD_XGPRS[TBF_MODE_EGPRS][i], SIZE_EGPRS_DL_BUFF * sizeof(API)); // Acknowledge DSP A_DD_XGPRS[TBF_MODE_EGPRS][i][0] &= ~(1 << B_BLK_READY); } else missing_payload = TRUE; } } } // TBF mode #endif // Store "missing payload" flag used for TDMA3 limit case. macs.dl_missing_payload = missing_payload; } // Buffer is allocated else { // No buffer allocated yet if (allocation_needed) // RLC Buffer exhaustion - abort missing_payload = FALSE; else // No buffer allocated yet as no block present missing_payload = TRUE; // Still some buffer expected macs.dl_missing_payload = TRUE; } } // Not in ISR TDMA 0,1,2, or ISR from TDMA 3 else if ((macs.tdma_delay >= 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