U8, U16, U32 data type changes
[o-du/l2.git] / src / 5gnrsch / rg_sch_drx.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17 *******************************************************************************/
18
19 /************************************************************************
20  
21      Name:     LTE-MAC layer
22   
23      Type:     C source file
24   
25      Desc:     C source code for DRX realted functions 
26   
27      File:     rg_sch_drx.c
28   
29 **********************************************************************/
30
31 /** @file rg_sch_drx.c
32 @brief This file implements the DRX processing .
33 */
34
35 static const char* RLOG_MODULE_NAME="MAC";
36 static int RLOG_MODULE_ID=4096;
37 static int RLOG_FILE_ID=163;
38
39 /* header include files -- defines (.h) */
40 #include "common_def.h"
41 #include "lrg.h"
42 #include "rgr.h"
43 #include "rgm.h"
44 #include "tfu.h"
45 #include "rg_env.h"
46 #include "rg_sch_inf.h"
47 #ifdef LTEMAC_PH3_HDFDD
48 #include "rg_sch_hdfdd.h"
49 #endif /*LTEMAC_PH3_HDFDD*/
50 #include "rg_sch.h"
51 #include "rg_sch_err.h"
52 #include "rg_sch_cmn.h"
53 #include "rl_interface.h"
54 #include "rl_common.h"
55
56 /* header/extern include files (.x) */
57 #include "tfu.x"           /* TFU types */
58 #include "lrg.x"           /* layer management typedefs for MAC */
59 #include "rgr.x"           /* layer management typedefs for MAC */
60 #include "rgm.x"           /* layer management typedefs for MAC */
61 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
62 #ifdef LTEMAC_PH3_HDFDD
63 #include "rg_sch_hdfdd.x"
64 #endif /*LTEMAC_PH3_HDFDD*/
65
66 #include "rg_sch.x"        /* typedefs for Scheduler */
67 #include "rg_sch_cmn.x"
68
69  /**
70  *  @file rg_sch_drx.c This file gives the describes the design for DRX feature. 
71  *
72  * DRX is Discontinuous Reception i.e. the UE in order to save some battery
73  * would not monitor (decode) PDCCHs at all times. Instead the UE is configured
74  * with a periodically occuring duration wherein it shall monitor PDCCHs. The UE
75  * can be called ACTIVE at this time, this time is a minimum of a configurable
76  * value - onDuration and a maximum of Infinity. 
77  *
78  * ACTIVE time  MIN (onDuration)  MAX (infinity)
79  *
80  * A sample configuration is periodicity of 10 subframes (ms) and an offset
81  * value of 3. This can be represented as the diagram given below. The portion
82  * marked as ACTIVE is the onDuration and the UE monitors PDCCHs. 
83  *
84  * @code
85  *
86  *          <-ACTIVE-><---IN-ACTIVE------><-ACTIVE-><---IN-ACTIVE--
87  * 
88  * |__|__|__|--------|__|__|__|__|__|__|__|--------|__|__|__|__|__|
89  *  0   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
90  *
91  * @endcode
92  */
93 #ifdef LTE_TDD
94 /******************************************************************************
95  *                         Structure definitions for TDD                      *
96  ******************************************************************************/
97
98 /** @brief : No of DL subframes in a particular TDD configuration
99  *
100  *  @details : Special subframes in TDD can carry PDCCH if configured
101  *             for DwPTS. For normal CP with subframe configruation (0-8)
102  *             & extended CP with subframe configuration (0-6), Special
103  *             Subframes can carry PDCCH and are represented in row 0.
104  *             Extended CP with subframe configuraton (7-8), which do 
105  *             not carry PDCCH are represented in row 1. 
106  *             rgSchDrxDlSfTddCfg[1][2] represent number of DL subframes
107  *             in TDD config 2 where DwPTS can carry PDCCH and 
108  *             rgSchDrxDlSfTddCfg[0][2] represent number of DL subframes
109  *             in TDD config 2 where no DwPTS exits.
110  */
111
112 PRIVATE uint8_t rgSchDrxDlSfTddCfg[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG] = 
113 {
114    {2,4,6,6,7,8,3},
115    {4,6,8,7,8,9,5}
116 };
117
118 /** @brief : No of DL subframes till next SFN from a particular subframe 
119  *
120  *  @details :For a given Special subframe config
121  *            (refer rgSchDrxDlSfTddCfg for an explanation) and given
122  *            TDD config, how many DL subframes till Next SFN from this
123  *            subframe onwards.
124  *   
125  */
126
127 PRIVATE uint8_t rgSchDrxDLSfTillNxtSFN[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
128                             [RGSCH_NUM_SUB_FRAMES]= 
129 {
130    {
131       {2,1,1,1,1,1,0,0,0,0},
132       {4,3,3,3,3,2,1,1,1,1},
133       {6,5,5,5,4,3,2,2,2,1},
134       {6,5,5,5,5,5,4,3,2,1},
135       {7,6,6,6,6,5,4,3,2,1},
136       {8,7,7,7,6,5,4,3,2,1},
137       {3,2,2,2,2,2,1,1,1,1}
138
139    },
140    { 
141       {4,3,2,2,2,2,1,0,0,0},
142       {6,5,4,4,4,3,2,1,1,1},
143       {8,7,6,6,5,4,3,2,1,1},
144       {7,6,5,5,5,5,4,3,2,1},
145       {8,7,6,6,6,5,4,3,2,1},
146       {9,8,7,7,6,5,4,3,2,1},
147       {5,4,3,3,3,3,2,1,1,1}
148    }
149 }; /*rgSchDrxDLSfTillNxtSFN*/
150
151
152 /** @brief : Lookup table for DL subframe given the number of subframes 
153  *
154  *  @details :For a given Special subframe config
155  *            (refer rgSchDrxDlSfTddCfg for an explanation) and given
156  *            TDD config, the DL subframe index given the number of subframes 
157  *   
158  */
159
160 PRIVATE uint8_t rgSchDrxDLSftoDLSfIdx[RGSCH_MAX_SFCFG][RGSCH_MAX_TDD_CFG]
161                          [RGSCH_NUM_SUB_FRAMES]= 
162 {
163    {
164       {5,0},
165       {9,0,4,5},
166       {9,0,3,4,5,8},
167       {9,0,5,6,7,8},
168       {9,0,4,5,6,7,8},
169       {9,0,3,4,5,6,7,8},
170       {9,0,5}
171    },
172    { 
173       {6,0,1,5},
174       {9,0,1,4,5,6},
175       {9,0,1,3,4,5,6,8},
176       {9,0,1,5,6,7,8},
177       {9,0,1,4,5,6,7,8},
178       {9,0,1,3,4,5,6,7,8},
179       {9,0,1,5,6}
180    }
181 };/* rgSchdrxDLSftoDLSfIdx*/
182 /* ccpu00134196-[Add]-DRX retx timer changes */
183 /* The k+4 th subframe in TDD at which HARQ RTT expires may be an Uplink SF.
184    In such case, the drx retx timer may start at the next pdcch sf instead
185    of at k+4 itself */
186 uint8_t rgSchDrxHarqRetxFirstPsf[RGSCH_MAX_TDD_CFG][RGSCH_NUM_SUB_FRAMES] = {
187   {0, 0, 4, 0, 6, 0, 0, 4, 0, 6}, 
188   {0, 0, 4, 6, 0, 0, 0, 4, 6, 0}, 
189   {0, 0, 4, 0, 0, 0, 0, 4, 0, 0}, 
190   {0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, 
191   {0, 0, 4, 4, 0, 0, 0, 0, 0, 0}, 
192   {0, 0, 4, 0, 0, 0, 0, 0, 0, 0}, 
193   {0, 0, 4, 6, 5, 0, 0, 4, 7, 0}, 
194 };
195 #endif  /* LTE_TDD */
196
197 /******************************************************************************
198  *                         Start of Function declarations                     *
199  ******************************************************************************/
200 PRIVATE Void rgSCHDrxTtiHdlOnDurUl ARGS((
201 RgSchCellCb        *cell,
202 uint16_t                ulIndex
203 ));
204 PRIVATE Void rgSCHDrxTtiHdlOnDurDl ARGS((
205 RgSchCellCb    *cell,
206 uint16_t                dlIndex
207 ));
208 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT ARGS((
209 RgSchCellCb          *cell,
210 uint16_t                   dlIndex
211 ));
212 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT ARGS((
213 RgSchCellCb          *cell,
214 uint16_t                   ulIndex
215 ));
216  PRIVATE S16 rgSCHDrxTtiHdlOnDur ARGS((RgSchCellCb *cellCb, uint16_t dlIndex, 
217                                         uint16_t ulIndex));
218  PRIVATE S16 rgSCHDrxTtiHdlInActv ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
219                                         uint16_t ulIndex));
220  PRIVATE S16 rgSCHDrxTtiHdlShortCycle ARGS((RgSchCellCb *cell, uint16_t dlIndex, 
221                                        uint16_t ulIndex));
222  PRIVATE S16 rgSCHDrxTtiHdlDlHarq ARGS((RgSchCellCb *cellCb, uint16_t dlIndex,
223                                        uint16_t ulIndex));
224  PRIVATE S16 rgSCHDrxCpyUeCfg ARGS((RgSchDrxUeCb *drxCb,
225                                      RgrUeDrxCfg* ueDrxCfg));
226  
227  PRIVATE S16 rgSCHDrxGetNxtOnDur ARGS((RgSchCellCb* cell,RgSchDrxUeCb* drxCb,
228                                        CmLteTimingInfo* nxtOnDur,
229                                        uint8_t delta));
230  
231 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc ARGS((RgSchCellCb* cell,
232                                            RgSchUeCb* ue,
233                                            uint16_t      idx,
234                                            Bool    calcFrmOffst));
235 #ifdef LTE_TDD
236 PRIVATE Void rgSCHDrxCalcNxtTmrExpry ARGS((RgSchCellCb     *cell,
237                                            RgSchUeCb       *ue,
238                                            uint16_t              delta,
239                                            uint32_t              tmrLen,
240                                            S16             *distance,
241                                            uint16_t             *idx
242                                           ));
243 PRIVATE S16 rgSCHDrxGetNxtTmrExpry ARGS((RgSchCellCb *cell,uint16_t curTime,
244                                           uint32_t duration, 
245                                          CmLteTimingInfo* tmrExpryIdx));
246 #endif /* LTE_TDD */
247 #ifdef EMTC_ENABLE
248 EXTERN S16 rgSCHEmtcDrxCpyUeCfg
249 (
250  RgSchUeCb     *ueCb,
251  RgrUeDrxCfg   *drxCfg
252 );
253 EXTERN S16 rgSCHDrxTtiHdlUlHarq 
254 (
255 RgSchCellCb          *cell,
256 uint16_t                   dlIndex,
257 uint16_t                   ulIndex
258 );
259 EXTERN Void rgSCHDrxUeUlHqReset
260 (
261 RgSchCellCb   *cell,
262 RgSchUeCb     *ue,
263 RgUeUlHqCb   *hqE
264 );
265
266 #endif
267
268 /** @brief This function handles the per TTI handling of the DRX module. 
269  *   Invoked by rgSCHTti @sa rgSCHTti. 
270  *
271  * @details This function goes through the drxQ and marks the UE as ACTIVE or
272  * INACTIVE based on the timers and thier status.
273  *
274  *     Function: rgSCHDrxTtiInd 
275  *
276  *         Processing steps:
277  *         - Processing is divided into respective timer handling. 
278  *         - Calculate the DL and UL indices as follows 
279  *         @code
280  *             dlIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
281  *                   RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
282  *
283  *             ulIndex = (cell->crntTime.sfn * 10 + cell->crntTime.slot +
284  *                   RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
285  *         @endcode
286  *         - Call rgSCHDrxTtiHdlOnDur to handle onDurationTimer handling
287  *         - Call rgSCHDrxTtiHdlInActv to handle drx-InactivityTimer handling
288  *         - Call rgSCHDrxTtiHdlShortCycle  to handle Short cycle timer.
289  *         - Call rgSCHDrxTtiHdlDlHarq  to handle HARQ RTT and drx-retransmission
290  *         timers.
291  *         - Call rgSchDrxTtiHdlUlHarq to handle Uplink HARQ processing -
292  *         related to ACTIVITY when a UE is expecting a grant for an uplink
293  *         re-transmissions.
294  *         - Post this processing the ueCb->dlInactvMask's DRX Bit shall be set
295  *         or reset to denote ACTIVITY or INACTIVITY respectively.
296  *         - Post this processing the ueCb->ulInactvMask's DRX Bit shall be set
297  *         or reset to denote ACTIVITY or INACTIVITY respectively.
298  *         - Add the UE to the list of Active/inactive UEs.
299  *
300  * @param RgSchCellCb *cell
301  * @param [out] CmLListCp *dlInactvLst List to which the DL in-active UEs are 
302  *                            added*
303  * @return 
304  */
305 #ifdef ANSI
306 Void rgSCHDrxTtiInd 
307 (
308 RgSchCellCb  *cell
309 )
310 #else
311 Void rgSCHDrxTtiInd (cell)
312 RgSchCellCb  *cell;
313 #endif
314 {
315    uint16_t dlIndex;
316    uint16_t ulIndex;
317
318    dlIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
319          RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
320
321    ulIndex = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G + cell->crntTime.slot +
322          RG_SCH_DRX_UL_DELTA) % RG_SCH_MAX_DRXQ_SIZE; 
323
324 #ifdef LTEMAC_R9
325    rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
326    /* checks the Ul-Retransmission timer */
327 #ifdef EMTC_ENABLE
328    if(cell->emtcEnable)
329    {
330       rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
331    }
332 #endif 
333    rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
334    
335    /*Process Short cycle expiry before On duration timer so that long cycles
336     * On Duration can be processed if timer has expired*/
337    rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
338    rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
339
340 #else /*LTEMAC_R9*/
341    rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex);
342    rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex);
343    /* checks the Ul-Retransmission timer */
344 #ifdef EMTC_ENABLE
345    if(cell->emtcEnable)
346    {
347       rgSCHDrxTtiHdlUlHarq (cell, dlIndex, ulIndex);
348    }
349 #endif
350    rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex);
351    rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex);
352
353 #endif /*LTEMAC_R9*/
354
355    return;
356
357 }/*rgSCHDrxTtiInd*/
358
359 /** @brief This function is called to handle onDurationTimer per TTI processing.
360  *
361  * @details
362  *    Invoked by - rgSCHDrxTtiInd 
363  *
364  *     Function:  rgSCHDrxTtiHdlOnDur
365  *
366  *         Processing steps:
367  *
368  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
369  *
370  *           - For Downlink we shall look at an index that is 
371  *             n + RG_SCH_DRX_DL_DELTA. 
372  *
373  *
374  *             - For Uplink we shall look at an index that is 
375  *               n + RG_SCH_DRX_UL_DELTA as
376  *             we are concerned with the PDCCH and not the actual PUSCH.
377  *
378  *
379  * @param  RgSchCellCb  *cellCb
380  * @param  uint16_t          dlIndex
381  * @param  uint16_t          ulIndex
382  * @return ROK/RFAILED 
383  */
384
385 #ifdef ANSI
386 PRIVATE S16 rgSCHDrxTtiHdlOnDur
387 (
388 RgSchCellCb*  cell,
389 uint16_t           dlIndex,
390 uint16_t           ulIndex
391 )
392 #else
393 PRIVATE S16 rgSCHDrxTtiHdlOnDur(cell, dlIndex, ulIndex)
394 RgSchCellCb*  cell;
395 uint16_t           dlIndex;
396 uint16_t           ulIndex;
397 #endif
398 {
399
400 #if ( ERRCLASS & ERRCLS_INT_PAR )
401    if ( cell == (RgSchCellCb* )NULLP )
402    {
403       return RFAILED;
404    }
405 #endif
406
407    rgSCHDrxTtiHdlOnDurDl(cell,dlIndex);
408   
409    rgSCHDrxTtiHdlOnDurUl(cell, ulIndex);
410
411    return ROK;
412
413 }/*rgSCHDrxTtiHdlOnDur*/
414
415
416 /** @brief This function handles the processing for drxInactityTimer per TTI
417  *
418  * @details
419  * Invoked by - rgSCHDrxTtiInd 
420  *
421  *     Function: rgSCHDrxTtiHdlInActv
422  *
423  *         Processing steps:
424  *
425  *         - For Downlink we shall look at an index that is 
426  *             n + RG_SCH_DRX_DL_DELTA of the drxQ. 
427  *
428  *         - MARK UE AS INACTIVE BASED ON DRX-INACTIVITY TIMER EXPIRY
429  *
430  *
431  *            - For Uplink we shall look at an index that is 
432  *              n + RG_SCH_DRX_UL_DELTA as
433  *             we are concerned with the PDCCH and not the actual PUSCH.
434  *
435  *
436  * @param  RgSchCellCb *cellCb
437  * @param  uint16_t          dlIndex
438  * @param  uint16_t          ulIndex
439  * @return ROK/RFAILED 
440  */
441
442 #ifdef ANSI
443 S16 rgSCHDrxTtiHdlInActv
444 (
445 RgSchCellCb  *cell,
446 uint16_t dlIndex,
447 uint16_t ulIndex
448 )
449 #else
450 S16 rgSCHDrxTtiHdlInActv(cell, dlIndex, ulIndex)
451 RgSchCellCb  *cell;
452 uint16_t dlIndex;
453 uint16_t ulIndex;
454 #endif
455 {
456    CmLList           *node;
457    RgSchDRXCellCb    *drxCell=NULLP;
458    RgSchUeCb         *ue=NULLP;
459    RgSchDrxUeCb      *drxUe=NULLP;
460    uint16_t                shrtCycleExpIndx;
461    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
462    CmLListCp         ulInactvLst; /* list of UE's becoming UL-inactive */
463    RgSchCmnCell      *cellSch = NULLP;
464    Bool              delInUlScan = FALSE;
465
466 #if ( ERRCLASS & ERRCLS_INT_PAR )   
467    if ( cell == (RgSchCellCb* )NULLP) 
468    {
469       return RFAILED;
470    }
471 #endif
472
473
474    drxCell     = (cell->drxCb);
475    delInUlScan = drxCell->delInUlScan;
476   
477   
478    /***********************************************************
479     *    Scanning inActvitiyQ in DL
480     ***********************************************************/
481
482    /* The DL loop will scan for UE's whose inactivity timer has
483     * expired. It will switch the cycle to short or long based
484     * on the cycle configured.
485     * Furhter,if !delInUlScan, then will remove the UE from the
486     * inactivity q. 
487     */
488
489    node = drxCell->drxQ[dlIndex].inActvTmrQ.first;
490
491    /* Initialize DL inactive list */
492    cmLListInit(&dlInactvLst);
493    
494    /* Initialize UL inactive list */
495    cmLListInit(&ulInactvLst);
496    
497    while (node)
498    {
499       ue    = (RgSchUeCb*)node->node;
500       node  = node->next;
501       drxUe = RG_SCH_DRX_GET_UE(ue);
502
503       if ( delInUlScan == TRUE)
504       {
505          drxUe->drxInactDistance--;
506       }
507
508       if ( drxUe->drxInactDistance != DRX_TMR_EXPRD ) 
509       {
510          continue;
511       }
512
513       /* UE is inactive as inactivity timer has expired */
514       drxUe->drxDlInactvMask  |= RG_SCH_DRX_INACTVTMR_BITMASK;
515
516
517       /* update the ue mask only if no condition in drx
518        * is keeping ue active
519        */
520       if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
521       {
522          /* set the UE has DRX inactive */
523          ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
524
525          /* Add to DL inactive list */
526          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
527          ue->dlDrxInactvLnk.node = (PTR)ue;
528       }
529
530       /*Remove from the queue if !delInUlScan */
531       if( delInUlScan == FALSE )
532       {
533          cmLListDelFrm(&(drxCell->drxQ[dlIndex].inActvTmrQ), 
534                &(drxUe->inActvTmrEnt));
535
536          drxUe->drxInactvIndx = DRX_INVALID;
537
538       }/* if (delInUlScan == FALSE) */
539
540       if (drxUe->isShortCycleCfgd)
541       {
542          /* add shorty cycle expirty */
543          drxUe->isLongCycle = FALSE;
544
545          shrtCycleExpIndx = (dlIndex + (drxUe->shortCycleTmrLen *
546                   drxUe->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE;
547
548          drxUe->drxShortCycleDistance = (drxUe->shortCycleTmrLen *
549                drxUe->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
550
551          /*Remove the UE from existing index*/
552          if (drxUe->shortCycleIndx != DRX_INVALID)
553          {
554             cmLListDelFrm(&(drxCell->drxQ[drxUe->shortCycleIndx].shortCycleQ),
555                   &(drxUe->shortCycleEnt));
556          }
557
558          cmLListAdd2Tail(&(drxCell->drxQ[shrtCycleExpIndx].shortCycleQ),
559                &(drxUe->shortCycleEnt));
560
561          drxUe->shortCycleEnt.node = (PTR)ue;
562          drxUe->shortCycleIndx     = shrtCycleExpIndx;
563
564          /*Calculate onDuration again & move the
565           * ueCb to the next Onduration occurence
566           */
567
568          /*we maybe at any position in the RF timeline,
569           * need to calculate onDuration from the starting
570           * offset
571           */
572          rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
573
574       }/*isShortCycleCfgd */
575       else
576       {
577          /* use the long cycle */
578          drxUe->isLongCycle = TRUE;
579       }/*isLongCycle*/
580    }/*while(node) */
581
582
583
584    /***********************************************************
585     *    Scanning inActvitiyQ in UL
586     ***********************************************************/
587
588    /* The UL loop will scan for UE's whose inactivity timer has
589     * expired and mark the UE's UL inactive.
590     * Furhter,if delInUlScan, then will remove the UE from the
591     * inactivity q. 
592     */
593
594    /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
595       we are concerned with the PDCCH and not the actual PUSCH.*/
596
597
598
599    node = drxCell->drxQ[ulIndex].inActvTmrQ.first;
600
601
602    while (node)
603    {
604       ue    = (RgSchUeCb*)node->node;
605       node  = node->next;
606       drxUe = RG_SCH_DRX_GET_UE(ue);
607
608       if ( delInUlScan == FALSE)
609       {
610          drxUe->drxInactDistance--;
611       }
612       
613       if ( drxUe->drxInactDistance != DRX_TMR_EXPRD ) 
614       {
615         continue;
616       }
617
618       /* Need to mark the UE as inactive due to expiry of
619        * DRX inactivity timer */
620
621       /* UE is inactive as inactivity timer has expired */
622       drxUe->drxUlInactvMask  |= RG_SCH_DRX_INACTVTMR_BITMASK;
623
624       /* update the ue mask only if no other condition in
625        * drx is keeping ue active */
626
627       if (!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
628       {
629          /* set the inactivity bit */
630          ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
631
632          /* Add to Ul inactive list */
633          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
634          ue->ulDrxInactvLnk.node = (PTR)ue;
635       }
636
637       if ( delInUlScan == TRUE)
638       {
639          /* remove from queue */
640          cmLListDelFrm(&(drxCell->drxQ[ulIndex].inActvTmrQ), 
641                &(drxUe->inActvTmrEnt));
642
643          drxUe->drxInactvIndx = DRX_INVALID;
644          
645       }/* if ( delInUlScan == TRUE) */
646    }/*while(node) for uplink */
647
648    
649    /* Send the list to the scheduler to mark UE as inactive in UL*/
650     cellSch = RG_SCH_CMN_GET_CELL(cell);
651     cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
652    
653    /* Send the DL inactive list to the scheduler to mark UE as inactive */
654    cellSch = RG_SCH_CMN_GET_CELL(cell);
655    cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
656
657       return ROK;
658 }/*rgSCHDrxTtiHdlInActv*/
659
660  /** @brief This function handles the per TTI processing for DRX short cycle
661   * timer.
662   *
663   * @details
664   * Invoked by - rgSCHDrxTtiInd 
665   *
666   *     Function: rgSCHDrxTtiHdlShortCycle
667   *
668   *         Processing steps:
669   *         -  For downlink
670   *
671  *             in addition we have to mark the ues based on drx short cycle
672  *             expiry
673  *
674  *
675  * @param  RgSchCellCb    *cell
676  * @param  uint16_t          dlIndex
677  * @param  uint16_t          ulIndex
678  * @return ROK/RFAILED 
679  */
680
681 #ifdef ANSI
682 S16 rgSCHDrxTtiHdlShortCycle 
683 (
684 RgSchCellCb  *cell,
685 uint16_t           dlIndex,
686 uint16_t           ulIndex
687 )
688 #else
689 S16 rgSCHDrxTtiHdlShortCycle (cell, dlIndex, ulIndex)
690 RgSchCellCb  *cell;
691 uint16_t           dlIndex;
692 uint16_t           ulIndex;
693 #endif
694 {
695    CmLList           *node;
696    RgSchDRXCellCb    *drxCell=NULLP;
697    RgSchUeCb         *ue=NULLP;
698    RgSchDrxUeCb      *drxUe=NULLP;
699
700 #if ( ERRCLASS & ERRCLS_INT_PAR )
701    if ( cell == (RgSchCellCb* )NULLP )
702    {
703       return RFAILED;
704    }
705 #endif
706
707    UNUSED(ulIndex);
708
709
710    drxCell = RG_SCH_DRX_GET_CELL(cell);
711
712    node = drxCell->drxQ[dlIndex].shortCycleQ.first;
713
714    while (node)
715    {
716       ue    = (RgSchUeCb*)node->node;
717       node  = node->next;
718       drxUe = RG_SCH_DRX_GET_UE(ue);
719
720       if ( --drxUe->drxShortCycleDistance != DRX_TMR_EXPRD)
721       {
722          continue;
723       }
724       
725       /* mark the UE's current cycle to be long */
726       drxUe->isLongCycle = TRUE;
727
728       /* remove from the shortCycleQ */
729
730       cmLListDelFrm(&(drxCell->drxQ[dlIndex].shortCycleQ), 
731             &(drxUe->shortCycleEnt));
732       drxUe->shortCycleIndx = DRX_INVALID;
733
734       /* Remove from onDuration queue inserted based on short cycle
735        * and calculate onDuration based on long cycle.*/
736       rgSCHDrxMvToNxtOnDurOcc(cell,ue,RG_SCH_DRX_DL_DELTA,TRUE);
737    }/*while(node)...*/
738
739    return ROK;
740 }/*rgSCHDrxTtiHdlShortCycle*/
741
742
743  /** @brief This function handles the HARQ timer's processing per TTI.
744   *
745   * @details
746   * Invoked by - rgSCHDrxTtiInd 
747   *
748   *     Function: rgSCHDrxTtiHdlDlHarq 
749   *
750   *         Processing steps:
751   *         - In addition per TTI DRX module must look at Downlink HARQ queues
752  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
753  *             Every TTI at the scheduling index we shall check these queues and
754  *             process accordingly. 
755  *
756  *
757  *             - Though these timers are related to downlink HARQ processing, they
758  *             have an impact on uplink scheduling. The reason is that the UE,
759  *             if active for downlink scheduling implies that it is reading
760  *             PDCCHs i.e. we can still send uplink allocations to the UE. Hence
761  *             every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
762  *
763  *
764  *
765  * @param  RgSchCellCb *cellCb
766  * @param  uint16_t          dlIndex
767  * @param  uint16_t          ulIndex
768   * @return ROK/RFAILED 
769   */
770
771 #ifdef ANSI
772 PRIVATE S16 rgSCHDrxTtiHdlDlHarq 
773 (
774 RgSchCellCb          *cell,
775 uint16_t                   dlIndex,
776 uint16_t                   ulIndex
777 )
778 #else /* ANSI */
779 PRIVATE S16 rgSCHDrxTtiHdlDlHarq (cell, dlIndex, ulIndex)
780 RgSchCellCb          *cell;
781 uint16_t                   dlIndex;
782 uint16_t                   ulIndex;
783 #endif /* ANSI */
784 {
785
786 #if ( ERRCLASS & ERRCLS_INT_PAR)
787    if ( cell == (RgSchCellCb *)NULLP )
788    {
789       return RFAILED;
790    }
791 #endif /*ERRCLASS & ERRCLS_INT_PAR*/
792
793
794    rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex);
795
796    rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex);
797
798    return ROK;
799 }
800
801  /** @brief This function is called by the common scheduler as part of
802   * finalization of allocations in downlink.
803   *
804   * @details
805   * Invoked by - 
806   *
807   *     Function: rgSchDrxStrtInActvTmr
808   *     
809   *     This function is responsible to starting drx-InactivityTimer 
810   *
811   *         Processing steps:
812   *
813   *
814   * @param  RgSchCellCb *cell
815   * @param  CmLListCp   *ueUlLst
816   * @param  uint8_t           direction 
817   * @return Void 
818   */
819
820 #ifdef ANSI
821 Void rgSCHDrxStrtInActvTmr
822 (
823 RgSchCellCb  *cell,
824 CmLListCp    *ueLst,
825 uint8_t            direction
826 )
827 #else
828 Void rgSCHDrxStrtInActvTmr(cell, ueLst, direction)
829 RgSchCellCb  *cell;
830 CmLListCp    *ueLst;
831 uint8_t            direction;
832 #endif
833 {
834    CmLList         *node;
835    CmLList         *delNode;
836    RgSchUeCb       *ueCb;
837    RgSchDrxUeCb    *ueDrxCb;
838 #ifndef LTE_TDD
839    uint16_t             index1;
840 #endif
841    uint16_t             inActvTmrExpIndx;
842 #ifndef LTE_TDD
843    uint16_t             curTimeInSf; /* current time in number of subframes */
844 #endif
845 #ifdef LTE_TDD
846    uint16_t             delta;
847 #endif /*LTE_TDD*/
848    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
849    CmLListCp         ulInactvLst; /* list of UE's becoming UL-inactive */
850    RgSchCmnCell      *cellSch = NULLP;
851    Bool              delInUlScan = FALSE;
852
853    if ( direction == RG_SCH_DRX_UL)
854    {
855 #ifndef LTE_TDD
856       curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
857          (cell->crntTime.slot) +RG_SCH_DRX_UL_DELTA;
858 #endif
859
860 #ifdef LTE_TDD
861       delta = RG_SCH_DRX_UL_DELTA;
862 #endif /*LTE_TDD */
863    }
864    else
865    {
866 #ifndef LTE_TDD
867       curTimeInSf = (cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
868          (cell->crntTime.slot) + RG_SCH_DRX_DL_DELTA; 
869 #endif
870
871 #ifdef LTE_TDD
872       delta = RG_SCH_DRX_DL_DELTA;
873 #endif /*LTE_TDD */
874    }
875
876
877    /* Initialize DL inactive list */
878    cmLListInit(&dlInactvLst);
879
880    /* Initialize UL inactive list */
881    cmLListInit(&ulInactvLst);
882    
883    delInUlScan = cell->drxCb->delInUlScan; 
884
885 #ifndef LTE_TDD
886    index1 = (curTimeInSf) % RG_SCH_MAX_DRXQ_SIZE;
887 #endif
888
889    node = ueLst->first;
890
891    while(node)
892    {
893       ueCb    = (RgSchUeCb *)node->node;
894       ueDrxCb = ueCb->drxCb;
895
896       /* Stop inactivity timer */
897       if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
898       {
899          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
900                &(ueDrxCb->inActvTmrEnt));
901       }
902 #ifdef LTE_TDD
903
904       rgSCHDrxCalcNxtTmrExpry(cell,
905             ueCb,
906             delta,
907             ueDrxCb->inactvtyTmrLen,
908             &(ueDrxCb->drxInactDistance),
909             &inActvTmrExpIndx
910             );
911
912 #else /*LTE_TDD*/
913       inActvTmrExpIndx = (index1 + ueDrxCb->inactvtyTmrLen) 
914          % RG_SCH_MAX_DRXQ_SIZE;
915
916       ueDrxCb->drxInactDistance = ueDrxCb->inactvtyTmrLen 
917          / RG_SCH_MAX_DRXQ_SIZE;
918 #endif /*LTE_TDD*/
919
920       cmLListAdd2Tail(&(cell->drxCb->drxQ[inActvTmrExpIndx].inActvTmrQ),
921             &(ueDrxCb->inActvTmrEnt));
922
923       ueDrxCb->inActvTmrEnt.node = (PTR)ueCb;
924
925       ueDrxCb->drxInactvIndx     = inActvTmrExpIndx;
926
927       /* Update DRX InActive both masks */
928       ueDrxCb->drxUlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
929       ueDrxCb->drxDlInactvMask &= ~RG_SCH_DRX_INACTVTMR_BITMASK;
930
931       /* Update UE's Inactive masks */
932       ueCb->ul.ulInactvMask &= ~RG_DRX_INACTIVE;
933       ueCb->dl.dlInactvMask &= ~RG_DRX_INACTIVE;
934
935       if ( delInUlScan == TRUE) 
936       {
937          if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF)
938          {
939             ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
940             ueDrxCb->drxDlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
941
942             /* if no other condition is keeping ue inactive,
943              * inactivate ue 
944              */
945             if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
946             {
947                ueCb->dl.dlInactvMask |= RG_DRX_INACTIVE;
948
949                /* Add to DL inactive list */
950                cmLListAdd2Tail(&dlInactvLst,&(ueCb->dlDrxInactvLnk));
951                ueCb->dlDrxInactvLnk.node = (PTR)ueCb;
952             }
953          }/*if ( ueDrxCb->inactvyTmrLen...*/
954
955       }/*delInUlScan==TRUE*/
956       else
957       {
958          if ( ueDrxCb->inactvtyTmrLen == RGR_DRX_PRD_1PSF ) 
959          {
960             ueDrxCb->drxInactDistance = DRX_TMR_EXPRD;
961             ueDrxCb->drxUlInactvMask |= RG_SCH_DRX_INACTVTMR_BITMASK;
962             /* if no other condition is keeping ue inactive,
963              * inactivate ue 
964              */
965             if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(ueDrxCb) )
966             {
967                ueCb->ul.ulInactvMask |= RG_DRX_INACTIVE;
968
969                if ( !RG_SCH_CMN_UL_IS_UE_ACTIVE(ueCb))
970                {
971                   /* Add to UL inactive list */
972                   cmLListAdd2Tail(&ulInactvLst,&(ueCb->ulDrxInactvLnk));
973                   ueCb->ulDrxInactvLnk.node = (PTR)ueCb;
974                }
975             }/*if ( !RG_SCH_DRX....)*/
976          }/*if (ueDrxCb->inactv...*/
977       }
978
979       /* move the link list forward */
980       delNode = node;
981       node = node->next;
982
983       cmLListDelFrm(ueLst, delNode);
984       delNode->node = NULLP;
985
986    }/*node*/
987
988    /* Send the list to the scheduler to mark UE as inactive in UL*/
989    cellSch = RG_SCH_CMN_GET_CELL(cell);
990    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
991
992    /* Send the DL inactive list to the scheduler to mark UE as inactive */
993    cellSch = RG_SCH_CMN_GET_CELL(cell);
994    cellSch->apisDl->rgSCHDlInactvtUes(cell,&dlInactvLst);
995
996    return; 
997 }/*rgSCHDrxStrtInActvTmr*/
998
999  /** @brief This function is called by the downlink HARQ module on receiving a
1000   * negative feedback from the UE for a PDSCH transmission. 
1001   *
1002   * @details
1003   * Invoked by - rgSCHDhmHqTrnsFail
1004   *
1005   *     Function: rgSCHDrxStartHarqRTTTmr
1006   *
1007   *         Processing steps:
1008  *
1009   *
1010   * @param  RgSchCellCb       *cell
1011   * @param  RgSchDlHqProcCb   *dlHq
1012   * @param  uint8_t                tbCnt
1013   * @return Void 
1014   */
1015 #ifdef ANSI
1016 Void rgSCHDrxStartHarqRTTTmr
1017 (
1018 RgSchCellCb            *cell,
1019 RgSchDlHqProcCb        *hqP,
1020 uint8_t                     tbCnt
1021 )
1022 #else
1023 Void rgSCHDrxStartHarqRTTTmr(cell, hqP, tbCnt)
1024 RgSchCellCb             *cell;
1025 RgSchDlHqProcCb         *hqP;
1026 uint8_t                      tbCnt;
1027 #endif
1028 {
1029    RgSchDRXCellCb      *drxCell =NULLP;
1030    RgSchDrxDlHqProcCb  *drxHq   =NULLP;
1031    uint16_t                  harqRTTExpIndx;
1032    uint8_t                   fdbkDelta;
1033 #ifdef LTE_TDD   
1034    uint8_t                   firstDlTxOcassion;
1035    uint8_t                   drxRetxTmrStartSf;
1036 #endif    
1037
1038    drxCell = RG_SCH_DRX_GET_CELL(cell);
1039    drxHq   = RG_SCH_DRX_GET_DL_HQ(hqP);
1040
1041 #ifdef LTE_TDD
1042     /* ccpu00134196-[Add]-DRX retx timer changes */
1043    firstDlTxOcassion = rgSchDrxHarqRetxFirstPsf[cell->ulDlCfgIdx]
1044                            [hqP->tbInfo[tbCnt].fdbkTime.subframe];
1045                             
1046    harqRTTExpIndx = ((hqP->tbInfo[tbCnt].fdbkTime.sfn * 10) +
1047          hqP->tbInfo[tbCnt].fdbkTime.subframe + firstDlTxOcassion)
1048       % RG_SCH_MAX_DRXQ_SIZE;
1049
1050    fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime,  hqP->tbInfo[tbCnt].fdbkTime);
1051 #else /*LTE_TDD*/
1052
1053    /* For FDD HARQ RTT expiry index is 8 subframes from the time 
1054     * corresponding PDSCH was scheduled. We are adding 1 subframe 
1055     * so that UE is scheduled for retransmission in the next subframe*/
1056    /* ccpu00134196-[Add]-DRX retx timer changes */
1057    harqRTTExpIndx = ((hqP->tbInfo[tbCnt].timingInfo.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1058          hqP->tbInfo[tbCnt].timingInfo.slot + RG_SCH_MIN_HARQ_RTT)
1059       % RG_SCH_MAX_DRXQ_SIZE;
1060
1061    fdbkDelta = RGSCH_CALC_SF_DIFF(cell->crntTime,  hqP->tbInfo[tbCnt].timingInfo);
1062 #endif /*LTE_TDD*/
1063    /* ccpu00134196-[Add]-DRX retx timer changes */ 
1064    /* ensure that the insertion into the queue happens at an index
1065       greater than the dl index, ie, do +1 */
1066    /* Instead of depending on TTI details of current time and HARQ RTT Expire 
1067     * time, Handling this check with deltas, because with TTIs it is not possible
1068     * to handle wrap-around condition*/
1069 #ifdef LTE_TDD
1070    if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= firstDlTxOcassion)
1071    {
1072       /* The retx timer length should be reduced.  
1073          This means based on the platforms delta between the DL HARQ 
1074          processing and DL scheduling, drx retx timer lengths of 1ms/2ms 
1075          may not be possible */ 
1076       drxRetxTmrStartSf = (hqP->tbInfo[tbCnt].fdbkTime.subframe + 
1077                                  firstDlTxOcassion) % RGSCH_NUM_SUB_FRAMES;
1078       uint8_t i;
1079       /* We are here because the Retx Timer start is moved by atleast one 
1080          position. Hence the timer will be reduced by minimum one */ 
1081       drxHq->retxTmrReduction = 1;
1082
1083       /* Now check the consecutive subframes starting from the actual 
1084          starting position of the retx tmr till the new position. Reduce the
1085          timer value only if the sf is a Pdcch sf */
1086       for(i = 1; i <= fdbkDelta + RG_SCH_DRX_DL_DELTA-firstDlTxOcassion+ 1; i++)
1087       {
1088          if (rgSchTddUlDlSubfrmTbl[cell->ulDlCfgIdx]
1089                     [(drxRetxTmrStartSf+i)%RGSCH_NUM_SUB_FRAMES] 
1090                   != RG_SCH_TDD_UL_SUBFRAME)
1091           {
1092              drxHq->retxTmrReduction++;
1093           }
1094       }
1095 #else                  
1096    if(fdbkDelta + RG_SCH_DRX_DL_DELTA >= RG_SCH_MIN_HARQ_RTT)
1097    {
1098       drxHq->retxTmrReduction = 
1099          fdbkDelta + RG_SCH_DRX_DL_DELTA - RG_SCH_MIN_HARQ_RTT+ 1;
1100 #endif      
1101       /* KW_FIX */
1102       harqRTTExpIndx = (harqRTTExpIndx + drxHq->retxTmrReduction) % 
1103          RG_SCH_MAX_DRXQ_SIZE;
1104    }
1105    else
1106    {
1107       drxHq->retxTmrReduction = 0;
1108    }
1109    cmLListAdd2Tail (&(drxCell->drxQ[harqRTTExpIndx].harqRTTQ),
1110          &(drxHq->harqRTTEnt));
1111
1112    drxHq->harqRTTEnt.node = (PTR)hqP;
1113    drxHq->rttIndx         = harqRTTExpIndx;
1114
1115    return;
1116
1117 }/*rgSCHDrxStartHarqRTTTmr*/
1118
1119
1120 /** @brief This function is called by the Configuration module to give a
1121  * trigger to DRX module for UE configuration. 
1122  *
1123  * @details
1124  *
1125  *     Function: rgSCHDrxUeCfg 
1126  *
1127  *         Processing steps:
1128  *         - Copy configuration information into drxUe structure.
1129  *         - Calculate the first occurance of onDuration based on values
1130  *         provided in the configuration structure. 
1131  *         - Append the UE to the onDurationQ at that index. 
1132  *         - The UE must be appened to the list based on the timing calculated
1133  *         above (nxtSfn, nxtSubframe). 
1134  *
1135  * @param  RgSchCellCb  *cell Cell control block.
1136  * @param  RgSchUeCb    *ue   UE control block.
1137  * @param  RgrUeCfg     *ueCfg RGR UE configuration information.
1138  * @return 
1139  * -# ROK
1140  * -# RFAILED
1141  */
1142 #ifdef ANSI
1143 S16 rgSCHDrxUeCfg 
1144 (
1145  RgSchCellCb *cell,
1146  RgSchUeCb   *ue,
1147  RgrUeCfg    *ueCfg
1148  )
1149 #else
1150 S16 rgSCHDrxUeCfg (cell, ue, ueCfg)
1151  RgSchCellCb *cell;
1152  RgSchUeCb   *ue;
1153  RgrUeCfg    *ueCfg;
1154 #endif
1155 {
1156    S16               ret       = ROK;
1157    RgSchDrxUeCb      *ueDrxCb;
1158    CmLteTimingInfo   nxtOnDur;
1159    uint16_t               onDurIndx;
1160    uint16_t               nxtOnDurTime;
1161    uint16_t               curTime;
1162    uint8_t                cellIdx;
1163
1164
1165 #if ( ERRCLASS & ERRCLS_INT_PAR )   
1166    if ( cell == (RgSchCellCb* )NULLP) 
1167    {
1168       return RFAILED;
1169    }
1170
1171    if ((ue == (RgSchUeCb* )NULLP)
1172          ||
1173          (ueCfg == (RgrUeCfg* )NULLP))
1174    {
1175       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId, "rgSCHDrxUeCfg():"
1176                "Invalid params.cell or ue or ueCfg is NULL ");
1177       return RFAILED;
1178    }
1179 #endif
1180
1181
1182    /* allocate and initialize drxCb */
1183    ret = rgSCHUtlAllocSBuf(cell->instIdx, (Data**)&ue->drxCb, 
1184          (sizeof(RgSchDrxUeCb)));
1185
1186    if(ret != ROK)
1187    {
1188       RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1189                "Memory allocation FAILED for DRX UECB CRBTI:%d",ue->ueId);
1190       return (ret);
1191    }
1192
1193    ueDrxCb = ue->drxCb;
1194
1195    /* initialize the masks */
1196    ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1197    ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1198    ue->dl.dlInactvMask     |= RG_DRX_INACTIVE;
1199    ue->ul.ulInactvMask     |= RG_DRX_INACTIVE;
1200
1201    for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1202    {
1203       ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1204       ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1205    }   
1206
1207    /* Copy the configuration values into the UE's DRX CB. */
1208    rgSCHDrxCpyUeCfg (ueDrxCb, &ueCfg->ueDrxCfg);
1209 #ifdef EMTC_ENABLE
1210    if(ue->isEmtcUe)
1211    {
1212       rgSCHEmtcDrxCpyUeCfg(ue ,&ueCfg->ueDrxCfg);
1213    }
1214 #endif
1215
1216    /* set all indexes to default values */
1217    ueDrxCb->onDurIndx       = DRX_INVALID;
1218    ueDrxCb->onDurExpIndx    = DRX_INVALID;
1219    ueDrxCb->drxInactvIndx   = DRX_INVALID;
1220    ueDrxCb->shortCycleIndx  = DRX_INVALID;
1221
1222    /* set all distances to timer expiry */
1223    ueDrxCb->onDurExpDistance      = DRX_TMR_EXPRD;
1224    ueDrxCb->drxInactDistance      = DRX_TMR_EXPRD;
1225    ueDrxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1226    ueDrxCb->distance              = DRX_TMR_EXPRD;
1227
1228    /* Mark the UE in long/short  cycle initially  as per configuration*/
1229    if(FALSE == ueDrxCb->isShortCycleCfgd)
1230    {
1231       ueDrxCb->isLongCycle = TRUE;
1232    }
1233    else
1234    {
1235       ueDrxCb->isLongCycle = FALSE;
1236    }
1237
1238    /* Calculate the next occurance from this point */
1239    rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1240
1241
1242    nxtOnDurTime = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot);
1243    curTime      = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1244                      cell->crntTime.slot);
1245
1246    onDurIndx         = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1247    
1248    ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1249    if (ueDrxCb->distance < 0)
1250    {
1251       RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
1252          "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1253    }
1254    //printf("The onduartion index is: %d\n",(int)onDurIndx);
1255    cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ), 
1256          &(ueDrxCb->onDurationEnt));
1257
1258    ueDrxCb->onDurationEnt.node = (PTR)ue;
1259    ueDrxCb->onDurIndx          = onDurIndx;
1260
1261    /* Starting Short Cycle Timer */
1262    if(TRUE == ueDrxCb->isShortCycleCfgd)
1263    {
1264       ueDrxCb->drxShortCycleDistance = (ueDrxCb->shortCycleTmrLen *
1265                ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1266       ueDrxCb->shortCycleIndx  = (curTime + (ueDrxCb->shortCycleTmrLen *
1267                ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE; 
1268       cmLListAdd2Tail(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1269                &(ueDrxCb->shortCycleEnt));
1270       ueDrxCb->shortCycleEnt.node = (PTR)ue;
1271    }
1272
1273    return (ret);
1274 } /* end of rgSCHDrxUeCfg */
1275
1276 /** @brief This function gets the next occurance of onDurationTimer from the
1277  * current time. 
1278  *
1279  * @details rgSCHDrxGetNxtOnDur
1280  *
1281  *     Function: rgSCHDrxGetNxtOnDur
1282  *
1283  *         Processing steps: -
1284  *         Calculation of first occurance of onDuration is to be done as
1285  *         follows. 
1286  *         Assume DRX configuration came at subframe (x, y) the periodicity is
1287  *         offset = (perd, offset). 
1288  *         The (sfn, subframe) satisfying the following condition is the first
1289  *         occurance from this point. 
1290  *
1291  *         (sfn * 10  + subframe) mod perd = offset 
1292  *
1293           - 
1294  *
1295  *
1296  * @param  RgSchCellCb     *cell
1297  * @param  RgSchDrxUeCb    *drxCb
1298  * @param  CmLteTimingInfo *nxtOnDur
1299  * @param  uint8_t              delta
1300  * @return ROK/RFAILED 
1301  */
1302 #ifdef ANSI
1303 PRIVATE S16 rgSCHDrxGetNxtOnDur
1304 (
1305  RgSchCellCb         *cell,
1306  RgSchDrxUeCb        *drxCb,
1307  CmLteTimingInfo     *nxtOnDur,
1308  uint8_t                   delta
1309  )
1310 #else
1311 PRIVATE S16 rgSCHDrxGetNxtOnDur (cell, drxCb, nxtOnDur, delta)
1312  RgSchCellCb         *cell;
1313  RgSchDrxUeCb        *drxCb;
1314  CmLteTimingInfo     *nxtOnDur;
1315  uint8_t                   delta;
1316 #endif
1317 {
1318    uint16_t               curTime;
1319    uint16_t               curDist;
1320    uint16_t               cycleLen;
1321    uint32_t               numOfCycles;
1322    uint32_t               nxtDist;
1323
1324
1325 #if ( ERRCLASS & ERRCLS_INT_PAR ) 
1326    if ( cell == (RgSchCellCb* )NULLP ) 
1327    {
1328       return RFAILED;
1329    }
1330
1331    if( (drxCb == (RgSchDrxUeCb* )NULLP)
1332            ||
1333        (nxtOnDur == (CmLteTimingInfo* )NULLP)
1334       )
1335    {
1336       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1337                         "rgSCHDrxGetNxOnDur():Invalid params."
1338                         "cell/drxCb/nxtOnDur is NULL");
1339       return RFAILED;
1340    }
1341 #endif
1342
1343    
1344    if (TRUE == drxCb->isLongCycle)
1345    {
1346       cycleLen = drxCb->longDrxCycle;
1347    }
1348    else
1349    {
1350       cycleLen = drxCb->shortDrxCycle;
1351    }
1352
1353    curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) + cell->crntTime.slot); 
1354
1355    curTime  += delta;  /*TODO: see if we need to take care of wrap arounds */
1356
1357    if ( curTime <= drxCb->drxStartOffset )
1358    {
1359       /* offset is the nextOnDur */
1360       nxtOnDur->sfn = drxCb->drxStartOffset / RGSCH_NUM_SUB_FRAMES_5G;
1361       nxtOnDur->slot = (uint8_t)(drxCb->drxStartOffset % RGSCH_NUM_SUB_FRAMES_5G);
1362       nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot); 
1363    }
1364    else
1365    {
1366       curDist = curTime - drxCb->drxStartOffset;
1367       
1368       numOfCycles = curDist / cycleLen;
1369
1370       if (0 == (curDist % cycleLen))
1371       {
1372          /* Perfect match pick up the current time */
1373          /*nxtOnDur should be set to equal to currentTime + DELTA */
1374          nxtOnDur->sfn      = (uint16_t)curTime / RGSCH_NUM_SUB_FRAMES_5G;
1375          nxtOnDur->slot = (uint16_t)curTime % RGSCH_NUM_SUB_FRAMES_5G;
1376          nxtDist = ((nxtOnDur->sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur->slot); 
1377
1378       }
1379       else
1380       {
1381          nxtDist            = drxCb->drxStartOffset + (numOfCycles + 1) * 
1382                               cycleLen;
1383          nxtOnDur->sfn      = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1384          nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1385
1386       }
1387    }
1388
1389    /*If next On Duration is less than DL DELTA ahead, we will miss it and
1390     * hence need to move to the On-Duration after that.*/
1391    if((nxtDist - (curTime - delta)) <= RG_SCH_DRX_MAX_DELTA)
1392    {
1393       nxtDist = nxtDist + cycleLen;
1394       nxtOnDur->sfn      = (uint16_t)nxtDist / RGSCH_NUM_SUB_FRAMES_5G;
1395       nxtOnDur->slot = (uint16_t)nxtDist % RGSCH_NUM_SUB_FRAMES_5G;
1396    }
1397    return ROK;
1398 } /* end of rgSCHDrxGetNxtOnDur */ 
1399
1400 /** @brief This function is a utility function to copy the UE configuration from
1401  * the RGR structure to the UE control block. 
1402  *
1403  * @details
1404  *   -Invoked by rgSCHDrxUeCfg
1405  *
1406  *     Function: rgSCHDrxCpyUeCfg
1407  *
1408  *         Processing steps:
1409  *         - Copies configuration values
1410  *
1411  * @param  RgSchDrxUeCb *ueCb
1412  * @param  RgrUeDrxCfg  *drxCfg
1413  * @return ROK/RFAILED 
1414  */
1415 #ifdef ANSI
1416 PRIVATE S16 rgSCHDrxCpyUeCfg
1417 (
1418  RgSchDrxUeCb  *ueCb,
1419  RgrUeDrxCfg   *drxCfg
1420 )
1421 #else
1422 PRIVATE S16 rgSCHDrxCpyUeCfg (ueCb, drxCfg)
1423  RgSchDrxUeCb  *ueCb;
1424  RgrUeDrxCfg   *drxCfg;
1425 #endif
1426 {
1427
1428 #if ( ERRCLASS & ERRCLS_INT_PAR ) 
1429    if ( (ueCb == (RgSchDrxUeCb* )NULLP ) 
1430            ||
1431         (drxCfg == (RgrUeDrxCfg* )NULLP)
1432       )
1433    {
1434       return RFAILED;
1435    }
1436 #endif
1437
1438       
1439    /* Copy all values to UE control block */
1440 #ifdef LTEMAC_R9
1441    ueCb->cqiMask              = drxCfg->cqiMask;
1442 #endif /*LTEMAC_R9*/
1443    ueCb->onDurTmrLen          = drxCfg->drxOnDurTmr;
1444    ueCb->inactvtyTmrLen       = drxCfg->drxInactvTmr;
1445    ueCb->drxRetransTmrLen     = drxCfg->drxRetxTmr;
1446    ueCb->longDrxCycle         = drxCfg->drxLongCycleOffst.longDrxCycle;
1447    ueCb->drxStartOffset       = drxCfg->drxLongCycleOffst.drxStartOffst;
1448    ueCb->isShortCycleCfgd     = drxCfg->drxShortDrx.pres;
1449    ueCb->shortDrxCycle        = drxCfg->drxShortDrx.shortDrxCycle;
1450    ueCb->shortCycleTmrLen     = drxCfg->drxShortDrx.drxShortCycleTmr;
1451    
1452    return ROK;
1453 } /* end of rgSCHDrxCpyUeCfg */ 
1454
1455 #ifdef RGR_V2
1456 /** @brief This function is called by the configuration module when a UE is
1457  * reconfigured for DRX parameters. 
1458  *
1459  * @details
1460  * Invoked By - rgSCHCfgRgrUeCfg
1461  *
1462  * Function: rgSCHDrxUeReCfg 
1463  * As per MAC specifications the new values of timers shall be applied only once
1464  * they are restarted, hence no processing is required for modified timer values. 
1465  *
1466  *         Processing steps:
1467  *         - if offset and/or drxCycleLenght changes then recalculate the next
1468  *         onDurationIndex
1469  *          - remove the UE from current index
1470  *          - add the UE to the new index. 
1471  *         - if short cycle is enabled 
1472  *          - set isShortCycleCfgd = TRUE
1473  *
1474  * @param   RgSchCellCb    *cell
1475  * @param   RgSchUeCb      *ue
1476  * @param   RgrUeRecfg     *ueReCfg
1477  * @return  ROK/RFAILED
1478  */
1479 #ifdef ANSI
1480 S16 rgSCHDrxUeReCfg 
1481 (
1482  RgSchCellCb *cell, 
1483  RgSchUeCb   *ue, 
1484  RgrUeRecfg  *ueReCfg
1485  )
1486 #else
1487 S16 rgSCHDrxUeReCfg (cell, ue, ueReCfg)
1488  RgSchCellCb *cell; 
1489  RgSchUeCb   *ue; 
1490  RgrUeRecfg  *ueReCfg;
1491 #endif
1492 {
1493       /* DRX_INFI_LOOP */
1494    RgSchCmnCell      *cellSch = NULLP;
1495    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
1496
1497    S16               ret       = ROK;
1498    Inst              instIdx   = cell->instIdx;
1499    RgSchDrxUeCb      *ueDrxCb;
1500    CmLteTimingInfo   nxtOnDur;
1501    uint16_t               nxtOnDurTime;
1502    uint16_t               onDurIndx;
1503    uint16_t               curTime;
1504    uint16_t               shrtCycleExpIndx;
1505    uint16_t               onDurExpTime;
1506    uint16_t               cycleLen;
1507    uint16_t               curIndx;
1508    uint8_t                cellIdx;
1509
1510
1511   /* drx was disabled but now enabled for this ue */ 
1512   if ( (ue->isDrxEnabled == FALSE) 
1513              &&
1514        (ueReCfg->ueDrxRecfg.isDrxEnabled == TRUE)
1515      )
1516   {
1517      /* allocated and initialize drxCb */
1518      ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&ue->drxCb,
1519                               (sizeof(RgSchDrxUeCb)));
1520
1521      if ( ret != ROK )
1522      {
1523         RLOG_ARG1(L_ERROR,DBG_CELLID,cell->cellId,
1524            "rgSCHdrxUeReCfg():""Memory allocation FAILED for DRX UE Cb CRNTI:%d",
1525                   ue->ueId);
1526         return (ret);
1527      }
1528
1529      ue->isDrxEnabled = TRUE;    /* sachin */
1530      /* initialize the masks */
1531      ue->drxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1532      ue->drxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1533      ue->dl.dlInactvMask     |= RG_DRX_INACTIVE;
1534      ue->ul.ulInactvMask     |= RG_DRX_INACTIVE;
1535
1536      for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1537      {
1538         ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1539         ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1540      }   
1541
1542      /* set all indexes to default values */
1543      ue->drxCb->onDurIndx       = DRX_INVALID;
1544      ue->drxCb->onDurExpIndx    = DRX_INVALID;
1545      ue->drxCb->drxInactvIndx   = DRX_INVALID;
1546      ue->drxCb->shortCycleIndx  = DRX_INVALID;
1547
1548      /* set all distances to timer expiry */
1549      ue->drxCb->onDurExpDistance      = DRX_TMR_EXPRD;
1550      ue->drxCb->drxInactDistance      = DRX_TMR_EXPRD;
1551      ue->drxCb->drxShortCycleDistance = DRX_TMR_EXPRD;
1552      ue->drxCb->distance              = DRX_TMR_EXPRD;
1553      
1554   }
1555   if( ue->drxCb == NULLP ) 
1556   { 
1557      return RFAILED; 
1558   }
1559    ueDrxCb = ue->drxCb;
1560    
1561    /*drx was enabled but now disabled for this UE */
1562    if ( (ue->isDrxEnabled == TRUE )
1563             &&
1564         (ueReCfg->ueDrxRecfg.isDrxEnabled == FALSE)
1565       )
1566    {
1567       /* remove UE from all DRX Queues */
1568       (Void)rgSCHDrxUeDel(cell,ue);
1569
1570       /* free drxCb */
1571       /* ccpu00117052 - MOD - Passing double pointer
1572       for proper NULLP assignment*/
1573       rgSCHUtlFreeSBuf(instIdx,(Data **)(&((ue->drxCb))),
1574                               sizeof(RgSchDrxUeCb));
1575
1576       /* Resetting the DRX Bit set in Inactv Mask */
1577       ue->dl.dlInactvMask     &= ~RG_DRX_INACTIVE;
1578       ue->ul.ulInactvMask     &= ~RG_DRX_INACTIVE;
1579
1580       ue->isDrxEnabled = FALSE;
1581
1582    }/*isDrxEnabled == FALSE */
1583    else
1584    {
1585       /* If Application is updating DRX params */
1586       if (ueReCfg->ueRecfgTypes & RGR_UE_DRX_RECFG )
1587       {
1588          rgSCHDrxCpyUeCfg (ueDrxCb, &ueReCfg->ueDrxRecfg);
1589 #ifdef EMTC_ENABLE
1590          if(ue->isEmtcUe)
1591          {
1592             rgSCHEmtcDrxCpyUeCfg(ue, &ueReCfg->ueDrxRecfg);
1593          }
1594 #endif
1595
1596       }
1597
1598       /* Removing the UE from existing index of shortcycle, if any*/ 
1599       if(ueDrxCb->shortCycleIndx != DRX_INVALID)
1600       {
1601          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1602                &(ueDrxCb->shortCycleEnt)); 
1603
1604          ueDrxCb->shortCycleEnt.node = (PTR) NULLP;
1605          ueDrxCb->shortCycleIndx     = DRX_INVALID;
1606       }
1607       
1608       /* Mark for intiating long/short cycle as per received config */
1609       if(FALSE == ue->drxCb->isShortCycleCfgd)
1610       {
1611          ue->drxCb->isLongCycle = TRUE;
1612       }
1613       else
1614       {
1615          ue->drxCb->isLongCycle = FALSE;
1616       }  
1617
1618       /* Calculate the next occurance from this point */
1619       rgSCHDrxGetNxtOnDur (cell, ueDrxCb, &nxtOnDur,RG_SCH_NO_DELTA);
1620
1621       /* remove the UE from the current onDuration Queue */ 
1622       if ( ueDrxCb->onDurIndx != DRX_INVALID )
1623       {
1624          cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1625                              &(ueDrxCb->onDurationEnt)); 
1626       }
1627
1628
1629       nxtOnDurTime = (nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + nxtOnDur.slot;
1630       curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
1631                    cell->crntTime.slot);
1632
1633       /* If Onduration timer of old configuration is already running then waiting till it expires */
1634       if((ueDrxCb->onDurExpIndx != DRX_INVALID) && (ueDrxCb->onDurExpDistance != DRX_TMR_EXPRD))
1635       {
1636          curIndx = (curTime + RG_SCH_DRX_DL_DELTA) % RG_SCH_MAX_DRXQ_SIZE;
1637          RLOG_ARG3(L_DEBUG,DBG_CELLID,cell->cellId,
1638                "OLD ONDUR RUNNING-EXPIRES at %d curIdx-%d nxtOnDurTime-%d",
1639                ueDrxCb->onDurExpIndx, 
1640                curIndx,
1641                nxtOnDurTime);  
1642
1643          /* Manipulating the time when old onDuration timer can expire */ 
1644          if(curIndx >= ueDrxCb->onDurExpIndx)
1645          {
1646             onDurExpTime = curTime + ((ueDrxCb->onDurExpDistance+1) * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA); 
1647          }
1648          else
1649          {
1650             onDurExpTime = curTime + (ueDrxCb->onDurExpDistance * RG_SCH_MAX_DRXQ_SIZE)+ (ueDrxCb->onDurExpIndx - curIndx + RG_SCH_DRX_DL_DELTA); 
1651          }         
1652
1653          if(nxtOnDurTime <= onDurExpTime)
1654          {
1655             if(ueDrxCb->isLongCycle)
1656             {
1657                cycleLen = ueDrxCb->longDrxCycle;
1658             }
1659             else
1660             {
1661                cycleLen = ueDrxCb->shortDrxCycle;
1662             }
1663             /* Moving to the possible occassion of onduration after current onduration expiry:
1664              * If both are aligning then going for next cycle */
1665             nxtOnDurTime += ((onDurExpTime - nxtOnDurTime)/cycleLen + 1 ) *cycleLen ;
1666          }
1667       }   
1668       /* Add the UE to the index which corresponds to the next onduration start*/
1669       onDurIndx = nxtOnDurTime % RG_SCH_MAX_DRXQ_SIZE;
1670
1671       ueDrxCb->distance = (nxtOnDurTime - curTime) / RG_SCH_MAX_DRXQ_SIZE;
1672       if (ueDrxCb->distance < 0)
1673       {
1674          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
1675             "value for distance, %d CRNTI:%d", ueDrxCb->distance,ue->ueId);
1676       }
1677     
1678       cmLListAdd2Tail(&(cell->drxCb->drxQ[onDurIndx].onDurationQ), 
1679             &(ueDrxCb->onDurationEnt));
1680
1681       ueDrxCb->onDurationEnt.node = (PTR)ue;
1682       ueDrxCb->onDurIndx        = onDurIndx;
1683
1684       /* DRX_INFI_LOOP */
1685       cmLListInit(&dlInactvLst);
1686       /* Add to DL inactive list */
1687       cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
1688       ue->dlDrxInactvLnk.node = (PTR)ue;
1689       /* Send the list to the scheduler to mark UE as inactive */
1690       cellSch = RG_SCH_CMN_GET_CELL(cell);
1691       cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
1692       /* DRX_INFI_LOOP */
1693
1694       /* Starting short cycle timer as per the existence of old onDuration timer */
1695       if(TRUE == ueDrxCb->isShortCycleCfgd)
1696       {
1697          /* Expiring short DRX cycle Tmr once the number of short DRX cycles done */
1698          ueDrxCb->drxShortCycleDistance = (nxtOnDurTime + ueDrxCb->onDurTmrLen + (ueDrxCb->shortCycleTmrLen -1 )*
1699                ueDrxCb->shortDrxCycle) / RG_SCH_MAX_DRXQ_SIZE;
1700          shrtCycleExpIndx = (nxtOnDurTime + ueDrxCb->onDurTmrLen + ((ueDrxCb->shortCycleTmrLen -1)*
1701                ueDrxCb->shortDrxCycle)) % RG_SCH_MAX_DRXQ_SIZE; 
1702          cmLListAdd2Tail(&(cell->drxCb->drxQ[shrtCycleExpIndx].shortCycleQ),
1703                &(ueDrxCb->shortCycleEnt));
1704          ueDrxCb->shortCycleEnt.node = (PTR)ue;
1705          ueDrxCb->shortCycleIndx     = shrtCycleExpIndx;
1706       }   
1707    }
1708
1709    return ROK;
1710
1711 } /* end of rgSCHDrxUeReCfg */
1712 #endif
1713
1714 /** @brief This function Loop through the list of HARQ processes for this 
1715  *  UE and delete from  the harqRTTQ and harqRetxQ
1716  *
1717  *     Function: rgSCHDrxUeHqReset
1718  *         Invoked by rgSCHDrxUeDel
1719  *
1720  *         Processing steps:
1721            Loop through the list of HARQ processes for this UE and delete from
1722  *         the harqRTTQ and harqRetxQ. 
1723  *
1724  * @param  RgSchCellCb  *cell
1725  * @return ROK/RFAILED
1726  */
1727 #ifdef ANSI
1728 Void rgSCHDrxUeHqReset
1729 (
1730  RgSchCellCb   *cell,
1731  RgSchUeCb     *ue,
1732  RgSchDlHqEnt  *hqE,
1733  uint8_t            cellIdx
1734  )
1735 #else
1736 Void rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx)
1737  RgSchCellCb   *cell; 
1738  RgSchUeCb     *ue;
1739  RgSchDlHqEnt  *hqE;
1740  uint8_t            cellIdx;
1741 #endif
1742
1743    RgSchDlHqProcCb     *hqP;
1744    RgSchDrxDlHqProcCb  *drxHq   =NULLP;
1745    uint8_t                  i;
1746
1747    for(i=0; i < hqE->numHqPrcs; i++)
1748    {
1749       hqP     = &hqE->procs[i];
1750       drxHq   = RG_SCH_DRX_GET_DL_HQ(hqP);
1751
1752       if(drxHq->rttIndx != DRX_INVALID)
1753       {
1754          cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->rttIndx].harqRTTQ),
1755                &(drxHq->harqRTTEnt));
1756
1757          drxHq->rttIndx = DRX_INVALID;
1758       }
1759
1760       if(drxHq->reTxIndx != DRX_INVALID)
1761       {
1762          cmLListDelFrm (&(cell->drxCb->drxQ[drxHq->reTxIndx].harqRetxQ),
1763                &(drxHq->harqRetxEnt));
1764
1765          drxHq->reTxIndx = DRX_INVALID;
1766       }
1767    }
1768
1769    ue->drxCb->drxDlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1770    ue->drxCb->drxUlInactvMaskPerCell[cellIdx] = DRX_UE_INACTIVE;
1771 }
1772
1773 /** @brief This function Deletes DRX specific context for a UE.
1774  *
1775  * @details This funciton is invoked by the Configuration module on RGR UE Deletion.
1776  * This function removes the UE's context from all of the DRX Queues. 
1777  * In addition it deletes context of UE's HARQ Processes present in the harqRTTQ
1778  * and harqRetxQ
1779  *    
1780  * 
1781  *     Function: rgSCHDrxUeDel
1782  *         Invoked by rgSCHCfgRgrUeDel
1783  *
1784  *         Processing steps:
1785  *         - Remove the UE from the following queues
1786  *          - onDurationQ - using onDurIndx
1787  *          - onDurationExpQ - using onDurExpIndx
1788  *          - inActvTmrQ - using drxInactvIndx
1789  *          - shortCycleQ - using shortCycleIndx
1790  *         - Loop through the list of HARQ processes for this UE and delete from
1791  *         the harqRTTQ and harqRetxQ. 
1792  *
1793  * @param  RgSchCellCb  *cell
1794  * @param  RgSchUeCb    *ue
1795  * @return ROK/RFAILED
1796  */
1797 #ifdef ANSI
1798 S16 rgSCHDrxUeDel
1799 (
1800  RgSchCellCb   *cell,
1801  RgSchUeCb      *ue
1802  )
1803 #else
1804 S16 rgSCHDrxUeDel (cell, ue)
1805  RgSchCellCb   *cell; 
1806  RgSchUeCb     *ue;
1807 #endif
1808 {
1809    RgSchDrxUeCb       *ueDrxCb;
1810    RgSchDlHqEnt       *hqE = NULLP;
1811    uint8_t                  cellIdx;
1812    RgSchUeCellInfo    *cellInfo = NULLP;
1813 #ifdef EMTC_ENABLE
1814    RgSchCmnUlUe *ueUl = RG_SCH_CMN_GET_UL_UE(ue, cell);
1815 #endif
1816
1817
1818    /* ccpu00129899: Moved the drx-enabled check to the caller */   
1819    ueDrxCb = ue->drxCb;
1820
1821    /* Remove UE from all queues */
1822    if ( ueDrxCb->onDurIndx != DRX_INVALID )
1823    {
1824       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurIndx].onDurationQ),
1825             &(ueDrxCb->onDurationEnt));
1826
1827       ueDrxCb->onDurIndx = DRX_INVALID;
1828    }
1829
1830    if ( ueDrxCb->onDurExpIndx != DRX_INVALID )
1831    {
1832       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->onDurExpIndx].onDurationExpQ),
1833             &(ueDrxCb->onDurationExpEnt)); 
1834
1835       ueDrxCb->onDurExpIndx = DRX_INVALID;
1836    }
1837
1838    if ( ueDrxCb->drxInactvIndx != DRX_INVALID )
1839    {
1840       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->drxInactvIndx].inActvTmrQ),
1841             &(ueDrxCb->inActvTmrEnt)); 
1842
1843       ueDrxCb->drxInactvIndx = DRX_INVALID;
1844    }
1845
1846    if ( ueDrxCb->shortCycleIndx != DRX_INVALID )
1847    {
1848       cmLListDelFrm(&(cell->drxCb->drxQ[ueDrxCb->shortCycleIndx].shortCycleQ),
1849             &(ueDrxCb->shortCycleEnt)); 
1850
1851       ueDrxCb->shortCycleIndx = DRX_INVALID;
1852    }
1853
1854    for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
1855    {
1856       cellInfo = ue->cellInfo[cellIdx];
1857
1858       if(cellInfo)
1859       {   
1860          hqE = cellInfo->hqEnt;
1861          rgSCHDrxUeHqReset(cell, ue, hqE, cellIdx);
1862       }
1863    }
1864 #ifdef EMTC_ENABLE
1865    if(ue->isEmtcUe)
1866    {
1867        rgSCHDrxUeUlHqReset(cell, ue, &(ueUl->hqEnt));
1868    }
1869 #endif
1870    /* Resetting the DRX Bit set in Inactv Mask */
1871    ue->dl.dlInactvMask     &= ~RG_DRX_INACTIVE;
1872    ue->ul.ulInactvMask     &= ~RG_DRX_INACTIVE;
1873    ueDrxCb->drxDlInactvMask = DRX_UE_INACTIVE;
1874    ueDrxCb->drxUlInactvMask = DRX_UE_INACTIVE;
1875
1876    return ROK;
1877 }/*rgSCHDrxUeDel*/
1878
1879 /** @brief This function is called at the time of RGR cell configuration.
1880  *
1881  * @details
1882  *     Invoked by - rgSCHCfgRgrCellCfg
1883  *
1884  *     Function: rgSCHDrxCellCfg 
1885  *
1886  *         Processing steps:
1887  *         - Initializes the following drxQ (memset would do).
1888  *
1889  *
1890  * @param RgSchCellCb   *cell
1891  * @param RgrCellCfg    *cellCfg
1892  * @return ROK/RFAILED
1893  */
1894 #ifdef ANSI
1895 S16 rgSCHDrxCellCfg 
1896 (
1897  RgSchCellCb   *cell,
1898  RgrCellCfg    *cellCfg
1899  )
1900 #else
1901 S16 rgSCHDrxCellCfg (cell, cellCfg)
1902  RgSchCellCb   *cell; 
1903  RgrCellCfg    *cellCfg;
1904 #endif
1905 {
1906
1907    S16               ret       = ROK;
1908    Inst              instIdx   = cell->instIdx;
1909
1910 #if ( ERRCLASS & ERRCLS_INT_PAR )
1911   /*KWORK_FIX :Removed check for cell being NULL*/ 
1912    if( (cellCfg == (RgrCellCfg* )NULLP))
1913    {
1914       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
1915                 "rgSCHDrxCellCfg():Invalid Params. cell/cellCfg is NULL");
1916       return RFAILED;
1917    }
1918 #endif
1919
1920    /* allocate and initialize drxCb */
1921    ret = rgSCHUtlAllocSBuf(instIdx, (Data**)&cell->drxCb, 
1922          (sizeof(RgSchDRXCellCb)));
1923
1924    if(ret != ROK)
1925    {
1926       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,"rgSCHDrxCellCfg():"
1927                "Memory allocation FAILED for DRX cell Cb");
1928       return (ret);
1929    }
1930
1931    /* delInUlScan determines which index scans the queue last.
1932     * We look at onDurationQ both from ulIndex & dlIndex pov.
1933     * Consider, onDuration starts at index 5, and current index is 2,
1934     * while dlIndex is 2 & ulIndex is 3 i.e dl is looking 2 SF ahead
1935     * and ul is looking 3 SF ahead. In this case, dl will scan the queue
1936     * last and therefore DL will delete ueCb from onDuration q. 
1937     * The reverse is true for the other case.*/
1938    
1939    if ( RG_SCH_DRX_UL_DELTA > RG_SCH_DRX_DL_DELTA )
1940    {
1941       cell->drxCb->delInUlScan = FALSE;
1942    }
1943    else
1944    {
1945       cell->drxCb->delInUlScan = TRUE;
1946    }
1947
1948    return (ret);
1949 } /* end of rgSchDrxCellCfg */
1950
1951
1952
1953 /** @brief This function to delete DRX specific context in the cell control
1954  * block.
1955  *
1956  * @details
1957  *    Invoked by - rgSCHCfgRgrCellDel
1958  *
1959  *     Function: rgSCHDrxCellDel 
1960  *
1961  *         Processing steps:
1962  *         - De-Inits RgSchDRXCellCb (Nothing to be done)
1963  *         - Assumption: The API is invoked after deletion of UEs from the cell.
1964  *
1965  * @param  RgSchCellCb  *cell
1966  * @return Void
1967  */
1968 #ifdef ANSI
1969 Void rgSCHDrxCellDel 
1970 (
1971  RgSchCellCb *cell
1972  )
1973 #else
1974 Void rgSCHDrxCellDel (cell)
1975  RgSchCellCb *cell;
1976 #endif
1977 {
1978    Inst              instIdx      = cell->instIdx;
1979
1980    if (cell->drxCb)
1981    {
1982       /* ccpu00117052 - MOD - Passing double pointer
1983       for proper NULLP assignment*/
1984       rgSCHUtlFreeSBuf(instIdx, (Data **)(&(cell->drxCb)),
1985             sizeof(RgSchDRXCellCb));
1986    }
1987    return;
1988 } /* end of rgSchDrxCellDel */
1989
1990 /** @brief This function is called when an SR is received from the UE. In this
1991  * case the UE should be marked as ACTIVE till we send a UL allocation to the
1992  * UE.
1993  *
1994  * @details
1995  *    Invoked by - rgSCHCmnSrRcvd
1996  *    Must be called after calling the specific scheduler.
1997  *
1998  *     Function: rgSCHDrxSrInd 
1999  *
2000  *         Processing steps:
2001  *         - Mark the UE as ACTIVE 
2002  *           ueCb->drxUlInactvMask |= (DRX_SR_ACTIVE);
2003  *         - Optionally call schedulers to add this UE to their scheduling
2004  *         queues. 
2005  *         - Set drxUe->srRcvd = TRUE
2006  *
2007  *         Note : the specification state that the UE shall start be active
2008  *         listening for UL grant, this implies we could potentially exploit
2009  *         this to send DL transmissions as well. However we have currently
2010  *         chosen not to do so.
2011  *
2012  * @param   RgSchCellCb  *cell
2013  * @param   RgSchUeCb    *ue
2014  * @return  ROK/RFAILED
2015  */
2016 #ifdef ANSI
2017 S16 rgSCHDrxSrInd 
2018 (
2019  RgSchCellCb   *cell, 
2020  RgSchUeCb     *ue
2021  )
2022 #else
2023 S16 rgSCHDrxSrInd (cell, ue)
2024  RgSchCellCb   *cell; 
2025  RgSchUeCb     *ue;
2026 #endif
2027 {
2028    RgSchDrxUeCb      *drxCb;
2029
2030 #if ( ERRCLASS & ERRCLS_INT_PAR )
2031    if ( cell == (RgSchCellCb* )NULLP)
2032    {
2033       return ROK;
2034    }
2035
2036    if( (ue == (RgSchUeCb* )NULLP))
2037    {
2038       RLOG_ARG0(L_ERROR,DBG_CELLID,cell->cellId,
2039                  "rgSCHDrxSrInd():Invalid Params. cell/ue is NULL");
2040       return RFAILED;
2041    }
2042  #endif
2043    /* KWork fix - shifted this down */
2044    
2045
2046    drxCb = RG_SCH_DRX_GET_UE(ue);
2047
2048    /* Mark the UE as active for UL only */
2049    drxCb->drxUlInactvMask  &= ~RG_SCH_DRX_SR_BITMASK;
2050    drxCb->srRcvd = TRUE;
2051    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2052    RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
2053
2054    return ROK;
2055 } /* rgSCHDrxSrInd */
2056
2057
2058 /** @brief This function handles ACTIVITY due to RACH using a dedicated preamble
2059  * (PDCCH order) OR Handover. A UE shall remain marked as active from the time
2060  * we successfully send out a RAR upto the time it receives a PDCCH indicating a
2061  * new transmission. 
2062  *
2063  * @details
2064  *    Invoked by - rgSCHCmnHdlHoPo
2065  *
2066  *     Function: rgSCHDrxDedRa 
2067  *
2068  *         Processing steps:
2069  *         - MARK the UE as active
2070  *         - set the raRcvd = TRUE for this UE.
2071  *
2072  *         @code
2073  *         ueCb->drxDlInactvMask |= (DRX_RA_ACTIVE);
2074  *         ueCb->drxUlInactvMask |= (DRX_RA_ACTIVE);
2075  *         ueCb->raRcvd = TRUE;
2076  *         @endcode
2077  *
2078  * @param  RgSchCellCb  *cellCb
2079  * @param  RgSchUeCb    *ueCb
2080  * @return Void 
2081  */
2082 #ifdef ANSI
2083 Void rgSCHDrxDedRa 
2084 (
2085 RgSchCellCb   *cellCb, 
2086 RgSchUeCb     *ueCb
2087  )
2088 #else
2089 Void rgSCHDrxDedRa (cellCb, ueCb)
2090 RgSchCellCb   *cellCb; 
2091 RgSchUeCb     *ueCb;
2092 #endif
2093 {
2094    RgSchDrxUeCb      *drxCb;
2095
2096    drxCb = RG_SCH_DRX_GET_UE(ueCb);
2097
2098    /* Mark the UE as active for UL & DL */
2099    drxCb->drxUlInactvMask  &= ~RG_SCH_DRX_RA_BITMASK;
2100    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2101    RG_SCH_CMN_UL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2102    
2103    drxCb->drxDlInactvMask  &= ~RG_SCH_DRX_RA_BITMASK;
2104    /* Update UE's inactive mask and if required move UE to ACTIVE state */
2105    RG_SCH_CMN_DL_UPDT_INACTV_MASK(cellCb, ueCb, RG_DRX_INACTIVE);
2106
2107    drxCb->raRcvd = TRUE;
2108
2109    return;
2110 } /* end of rgSCHDrxDedRa */
2111
2112
2113 /** @brief This function calculates the next onDuration Occurence
2114  * and removes & queue it again in onDurationQ
2115  *
2116  * @details
2117  *    Invoked by - 
2118  *
2119  *     Function: rgSCHDrxMvToNxtOnDurOcc
2120  *
2121  *         Processing steps:
2122  *
2123  *
2124  * @param  RgSchCellCb     *cell
2125  * @param  RgSchUeCb       *ueCb
2126  * @param  uint16_t              idx  - if calcFrmOffst is TRUE,
2127  *                                 idx is delta to be added
2128  * @param  Bool             calcFrmOffst
2129  * @return Void 
2130  */
2131 #ifdef ANSI
2132 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc 
2133 (
2134 RgSchCellCb      *cell,
2135 RgSchUeCb        *ueCb,
2136 uint16_t               idx,
2137 Bool              calcFrmOffst
2138 )
2139 #else
2140 PRIVATE Void rgSCHDrxMvToNxtOnDurOcc (cell, ueCb, idx, calcFrmOffst)
2141 RgSchCellCb      *cell;
2142 RgSchUeCb        *ueCb; 
2143 uint16_t               idx;
2144 Bool              calcFrmOffst;
2145 #endif
2146 {
2147    uint16_t             nxtOnDurIndex;
2148    uint16_t             curTime;
2149    RgSchDrxUeCb    *drxUe;
2150    RgSchDRXCellCb  *drxCell;
2151    CmLteTimingInfo  nxtOnDur; /* to be used when calcFrmOffset is set */
2152    uint16_t              nxtOnDurInSf; /* next On Duration in no of subframes */
2153
2154    drxCell = cell->drxCb;
2155    drxUe   = ueCb->drxCb;
2156
2157
2158    if(calcFrmOffst == FALSE)
2159    {
2160       if (drxUe->isLongCycle)
2161       {
2162          nxtOnDurIndex = ((idx + drxUe->longDrxCycle)
2163                % RG_SCH_MAX_DRXQ_SIZE  );
2164          drxUe->distance = drxUe->longDrxCycle/RG_SCH_MAX_DRXQ_SIZE;
2165       }
2166       else
2167       {
2168          nxtOnDurIndex = ((idx + drxUe->shortDrxCycle)% RG_SCH_MAX_DRXQ_SIZE);
2169
2170          drxUe->distance = drxUe->shortDrxCycle / RG_SCH_MAX_DRXQ_SIZE;
2171       }
2172    }
2173    else
2174    {
2175       rgSCHDrxGetNxtOnDur(cell,drxUe,&nxtOnDur,(uint8_t)idx);
2176       
2177       nxtOnDurInSf = ((nxtOnDur.sfn * RGSCH_NUM_SUB_FRAMES_5G) + 
2178                          nxtOnDur.slot);
2179       
2180       curTime = ((cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G) +
2181             cell->crntTime.slot);
2182
2183       nxtOnDurIndex   = nxtOnDurInSf % RG_SCH_MAX_DRXQ_SIZE;
2184       drxUe->distance = (nxtOnDurInSf-curTime) / RG_SCH_MAX_DRXQ_SIZE;
2185       if (drxUe->distance < 0)
2186       {
2187          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId,"DRXUE. Invalid "
2188             "value for distance, %d CRNTI:%d", drxUe->distance,ueCb->ueId);
2189       }
2190    }
2191
2192    /* First remove from existing location */
2193    if ( drxUe->onDurIndx != DRX_INVALID )
2194    {
2195       cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurIndx].onDurationQ),
2196             &(drxUe->onDurationEnt));
2197    }
2198
2199    /* Add at new location */
2200    cmLListAdd2Tail(&(drxCell->drxQ[nxtOnDurIndex].onDurationQ),
2201          &(drxUe->onDurationEnt));
2202
2203    drxUe->onDurationEnt.node = (PTR)ueCb;
2204    drxUe->onDurIndx          = nxtOnDurIndex;
2205
2206    return;
2207 }/*rgSCHDrxMvToNxtOnDurOcc*/
2208
2209 #ifdef LTE_TDD
2210 /** @brief This function calculates the next SFN,subframe a given  
2211  *  timer is going to expire. Works for all TDD configurations. 
2212  *
2213  * @details
2214  *
2215  *     Function: rgSCHDrxGetNxtTmrExpry 
2216  *         We need to count only PDCCH frames in a given TDD
2217  *         configuration. This is true for onDuration, inActivity
2218  *         & drx-retransmission timers.
2219  *         
2220  *         Processing steps (assume timer starts at (12,2) and duration
2221  *                           is 23 DL subframes): 
2222  *              - based on TDD configuration, move to the next SFN and 
2223  *                count the number of DL subframes consumed. In our example,
2224  *                moving to (12,9) will consume 6 DL subframes assuming TDD 
2225  *                config of 2.
2226  *              - From this point on, determine how many exact Radio Frames
2227  *                will be consumed for the remaining DL subframes. In our 
2228  *                example, remaining DL subframes are (23-6) are 17. 
2229  *                For config 2, the following holds true
2230  *                  8 DLSF are in 1 RF
2231  *                  1 DLSF in 1/8 DLSF
2232  *                  17 DLSF in 17/8 i.e 2 RF + 1 subframe
2233  *                  In order to consume 17 DLSF, we need to move forward
2234  *                  2 RFs + 1 subframe. Adding 2 RF's gives us (14,9)
2235  *              - For the remaining subframe, we need to figure out the next 
2236  *                available DL subframe. For TDD_configuration, the first DL 
2237  *                subframe is at index 0. So, the timer will run till (15,0) 
2238  *                and will expire on (15,1)
2239  *
2240  * @param  RgSchUeCb       *ue          Ue control block.
2241  * @param  uint16_t             curTime      current Time 
2242  * @param  uint32_t             duration     Timer duration 
2243  * @param  CmLteTimingInfo *tmrExpryIdx Timer expry (SFN,sf)
2244  * @return ROK/RFAILED
2245  */
2246 #ifdef ANSI
2247 PRIVATE S16 rgSCHDrxGetNxtTmrExpry 
2248 (
2249  RgSchCellCb        *cell,
2250  uint16_t                curTime,
2251  uint32_t                duration, 
2252  CmLteTimingInfo    *tmrExpryIdx
2253 )
2254 #else
2255 PRIVATE S16 rgSCHDrxGetNxtTmrExpry (cell,curTime,duration,tmrExpryIdx)
2256  RgSchCellCb         *cell;
2257  uint16_t                 curTime;
2258  uint32_t                 duration;
2259  CmLteTimingInfo     *tmrExpryIdx;
2260 #endif
2261 {
2262    uint32_t             dlSfTillNxtSFN;  /*!< DL subframes till next SFN */
2263    uint8_t              tddCfgMode;      /*!< tdd config mode */
2264    Bool            isDwPtsCnted;    /*!< is DwPts counted as PDCCH sf */
2265    CmLteTimingInfo crntTime;        /*!< current SFN & sf */
2266
2267
2268 #if ( ERRCLASS & ERRCLS_INT_PAR )
2269    if ( (cell == (RgSchCellCb* )NULLP) 
2270          ||
2271          (tmrExpryIdx == (CmLteTimingInfo* )NULLP)
2272       )
2273    {
2274       return RFAILED;
2275    }
2276 #endif
2277
2278    
2279    isDwPtsCnted = cell->isDwPtsCnted ;
2280
2281    tddCfgMode        = cell->ulDlCfgIdx;
2282    crntTime.sfn      = curTime / RGSCH_NUM_SUB_FRAMES_5G;
2283    crntTime.slot = curTime % RGSCH_NUM_SUB_FRAMES_5G; 
2284
2285
2286
2287    /* First calculate the number of DL subframes till next SFN */
2288
2289    dlSfTillNxtSFN = rgSchDrxDLSfTillNxtSFN[isDwPtsCnted][tddCfgMode]
2290       [(crntTime.slot % RGSCH_NUM_SUB_FRAMES)];
2291
2292
2293    if ( dlSfTillNxtSFN >= duration )
2294    {
2295       /* the timer would expire on the same RF */
2296       uint32_t diff = dlSfTillNxtSFN - duration;
2297
2298       tmrExpryIdx->sfn = crntTime.sfn; 
2299
2300       if ( diff == 0 )
2301       {
2302          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2303             [0];
2304       }
2305       else
2306       {
2307          uint8_t arrayIdx;
2308          /* to know the DL sf index based on diff */
2309          arrayIdx = rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode]; 
2310
2311          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2312             [arrayIdx - diff];
2313       }
2314    }/* if ( dlSfTillNxtSFN >= duration...*/
2315    else
2316    {
2317       uint32_t             remSf;           /*!< remaining subframes */
2318       uint32_t             numRf;           /*!< num of complete radio frames */
2319       uint32_t             numRemSfs;       /*!< num of remaining subframes */
2320
2321       remSf = duration - dlSfTillNxtSFN;
2322
2323       /* move to (currSFN,9) having consued dlSfTillNxtSFN DL subframes */
2324       tmrExpryIdx->sfn      = crntTime.sfn;
2325       tmrExpryIdx->subframe = (uint8_t)9;
2326
2327       numRf      = (1 * remSf)/rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2328       numRemSfs  = (1 * remSf)%rgSchDrxDlSfTddCfg[isDwPtsCnted][tddCfgMode];
2329
2330       tmrExpryIdx->sfn = tmrExpryIdx->sfn + numRf;
2331
2332       /* we are now at (X,9) having consumed dlSfTillNxtSFN + numRf * num of DL
2333        * subframes in 1 RF */
2334
2335       if ( numRemSfs == 0 )
2336       {
2337          /* we are at subframe 9 i.e. the timer is going to expire using exact
2338           * radio frames. However, not all TDD_configurations have 9 as their
2339           * last DL subframe. We might have passed the last DL subfrme. 
2340           * Therefore, move back */
2341          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2342                                                                   [numRemSfs];
2343       }
2344       else
2345       {
2346          /* a reminder implies we have to move past this SFN as we are at the 
2347           * last subframe on that SFN */
2348          tmrExpryIdx->sfn++; 
2349          tmrExpryIdx->subframe = rgSchDrxDLSftoDLSfIdx[isDwPtsCnted][tddCfgMode]
2350                                                                   [numRemSfs];
2351       }
2352    }/*else if diff > duration */
2353
2354    /* timer will expire 1 + tmrExpryIdx */
2355
2356    if ( ( tmrExpryIdx->subframe + 1) == 10 )
2357    {
2358       tmrExpryIdx->sfn++;
2359       tmrExpryIdx->subframe = 0;
2360    }
2361    else
2362    {
2363       tmrExpryIdx->subframe++;
2364    }
2365
2366    /* check to see if it sfn has crossed its max */
2367    if ( tmrExpryIdx->sfn > RG_SCH_CMN_MAX_SFN_NUM )
2368    {
2369       tmrExpryIdx->sfn = tmrExpryIdx->sfn - (RG_SCH_CMN_MAX_SFN_NUM + 1);
2370    }
2371
2372    return ROK;
2373 }/*rgSCHDrxGetNxtTmrExpry*/
2374
2375 /** @brief This function calculates the next onDuration Occurence
2376  *         for TDD
2377  * @details
2378  *    Invoked by - 
2379  *
2380  *     Function: rgSCHDrxCalcNxtTmrExpry
2381  *
2382  *         Processing steps: a wrapper function to call
2383  *         rgSCHDrxGetNxtTmrExpry
2384  *
2385  * @param  RgSchCellCb      *cell
2386  * @param  RgSchUeCb        *ue
2387  * @param  uint16_t               delta
2388  * @param  uint32_t               tmrLen 
2389  * @param  uint16_t              *distance
2390  * @param  S16              *idx
2391  * @return ROK/RFAILED
2392  */
2393 #ifdef ANSI
2394 PRIVATE Void rgSCHDrxCalcNxtTmrExpry
2395 (
2396  RgSchCellCb     *cell,
2397  RgSchUeCb       *ue,
2398  uint16_t              delta,
2399  uint32_t              tmrLen,
2400  S16             *distance,
2401  uint16_t             *idx
2402 )
2403 #else
2404 PRIVATE Void rgSCHDrxCalcNxtTmrExpry (cell,ue,delta,tmrLen,distance,idx)
2405  RgSchCellCb     *cell;
2406  RgSchUeCb       *ue;
2407  uint16_t              delta;
2408  uint32_t              tmrLen;
2409  S16             *distance;
2410  uint16_t             *idx;
2411 #endif
2412 {
2413    uint16_t             curTimeInSf;  /*current time in no of subframes*/
2414    CmLteTimingInfo tmrExpry;
2415    uint16_t             tmrExpryInSf; /*timer expry in no of subframes*/
2416
2417    curTimeInSf = cell->crntTime.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2418                    cell->crntTime.slot;
2419
2420    /* add delta to curTime */
2421    curTimeInSf += delta;
2422
2423    rgSCHDrxGetNxtTmrExpry(ue->cell,curTimeInSf,tmrLen,&tmrExpry);
2424
2425    /* convert timre Expry in terms of subframes */
2426    tmrExpryInSf = tmrExpry.sfn * RGSCH_NUM_SUB_FRAMES_5G +
2427                    tmrExpry.subframe;
2428
2429   
2430    *idx = (tmrExpryInSf) % RG_SCH_MAX_DRXQ_SIZE;
2431
2432    if ( distance != NULLP ) /* hqReTx don't use the concept of distance.
2433                                They can send NULLP for distance.
2434                              */
2435    {
2436       if ( tmrExpryInSf > curTimeInSf )
2437       {
2438          *distance = (tmrExpryInSf - curTimeInSf) /
2439                    RG_SCH_MAX_DRXQ_SIZE;
2440       }
2441       else
2442       {
2443          /* in case the RF is at its max and wraps around */
2444
2445          *distance = ((tmrExpryInSf + (RG_SCH_CMN_MAX_NUM_OF_SFN - 1)) 
2446                                      -
2447                                     curTimeInSf) / RG_SCH_MAX_DRXQ_SIZE;
2448       }
2449       if (*distance < 0)
2450       {
2451          RLOG_ARG2(L_ERROR,DBG_CELLID,cell->cellId, "DRXUE. Invalid "
2452             "value for distance, %d CRNTI:%d", *distance,ue->ueId);
2453       }      
2454    }
2455   
2456    return;
2457 }/*rgSCHDrxCalcNxtTmrExpry*/
2458
2459 /* ccpu00134670- Validating onduration timer versus DRX cycle*/
2460 /***********************************************************
2461  *
2462  *     Func : rgSCHCfgVldtTddDrxCycCfg
2463  *
2464  *
2465  *     Desc : Validates DRX Cycle Length  configuration against received 
2466  *            onDuration timer from RRC.
2467  *
2468  *     Ret  : S16
2469  *            ROK - Success
2470  *
2471  *            RFAILED - Failed
2472  *
2473  *     Notes:
2474  *
2475  *     File :
2476  *
2477  **********************************************************/
2478 #ifdef ANSI
2479 S16 rgSCHCfgVldtTddDrxCycCfg
2480 (
2481 RgSchCellCb  *cell,
2482 uint16_t           drxCycle,
2483 uint8_t            onDurTmr, 
2484 uint16_t           offSet
2485 )
2486 #else
2487 S16 rgSCHCfgVldtTddDrxCycCfg(cell, drxCycle, onDurTmr, offSet)
2488 RgSchCellCb  *cell;
2489 uint16_t           drxCycle;
2490 uint8_t            onDurTmr;
2491 uint16_t           offSet; 
2492 #endif
2493 {
2494    uint16_t             startTime;
2495    uint16_t             endTimeInSf;
2496    CmLteTimingInfo endTime; 
2497
2498    startTime = offSet;
2499    do
2500    {
2501       rgSCHDrxGetNxtTmrExpry(cell, startTime, onDurTmr, &endTime);
2502     
2503       endTimeInSf = (endTime.sfn* RGSCH_NUM_SUB_FRAMES)+endTime.subframe;
2504      
2505       if(((RGSCH_MAX_SUBFRM_5G + endTimeInSf- startTime) % RGSCH_MAX_SUBFRM_5G) >= 
2506           drxCycle)
2507       {
2508           return RFAILED;
2509       }
2510       
2511       startTime = (startTime + drxCycle);
2512    /* Going for next iteration if the DRX cycle is not multiple of 10. If it is
2513       multiple of 10(Number of Subframes in a SFN) then subframe, at which 
2514       onduration timer can start, will be always same, Otherwise the possible 
2515       subframe numbers, where the onDuration timer can start, is 5. Hence 4 
2516       more iterations are required. */
2517    }while((drxCycle % RGSCH_NUM_SUB_FRAMES) && 
2518        (startTime < (drxCycle * RGSCH_NUM_SUB_FRAMES/2)));
2519    
2520    return ROK;
2521 }
2522
2523 #endif /*LTE_TDD */
2524
2525 /** @brief This function is called to handle onDurationTimer per TTI processing.
2526  *
2527  * @details
2528  *    Invoked by - rgSCHDrxTtiInd 
2529  *
2530  *     Function:  rgSCHDrxTtiHdlOnDurUl
2531  *
2532  *         Processing steps:
2533  *
2534  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2535  *
2536  *             - For Uplink we shall look at an index that is 
2537  *               n + RG_SCH_DRX_UL_DELTA as
2538  *             we are concerned with the PDCCH and not the actual PUSCH.
2539  *
2540  *
2541  * @param  RgSchCellCb  *cellCb
2542  * @param  uint16_t          ulIndex
2543  * @return Void 
2544  */
2545
2546 #ifdef ANSI
2547 PRIVATE Void rgSCHDrxTtiHdlOnDurUl
2548 (
2549 RgSchCellCb        *cell,
2550 uint16_t                ulIndex
2551 )
2552 #else
2553 PRIVATE Void rgSCHDrxTtiHdlOnDurUl(cell, ulIndex)
2554 RgSchCellCb   *cell;
2555 uint16_t           ulIndex;
2556 #endif
2557 {
2558    CmLList           *node;
2559    RgSchDRXCellCb    *drxCell  = NULLP;
2560    RgSchUeCb         *ue       = NULLP;
2561    RgSchDrxUeCb      *drxUe    = NULLP;
2562    CmLListCp         ulInactvLst; /* list of UE's becoming DL-inactive */
2563    RgSchCmnCell      *cellSch = NULLP;
2564    Bool              delInUlScan = FALSE;
2565    
2566    drxCell     = (cell->drxCb);
2567    delInUlScan = drxCell->delInUlScan;
2568    /***********************************************************
2569     *    Scanning OnDurationQ in UL
2570     ***********************************************************/
2571
2572    /* For Uplink we shall look at an index that is n + RG_SCH_DRX_UL_DELTA as
2573       we are concerned with the PDCCH and not the actual PUSCH.*/
2574
2575    node = drxCell->drxQ[ulIndex].onDurationQ.first;
2576
2577    while (node)
2578    {
2579       ue    = (RgSchUeCb*)node->node;
2580       node  = node->next;
2581       drxUe = RG_SCH_DRX_GET_UE(ue);
2582
2583
2584       if ( delInUlScan == FALSE)
2585       {
2586          drxUe->distance--;
2587       }
2588
2589       if ( drxUe->distance != DRX_TMR_EXPRD )
2590       {
2591          continue;
2592       }
2593
2594       /* reset the bit mask to indicate that onduration has started */
2595       drxUe->drxUlInactvMask  &= ~RG_SCH_DRX_ONDUR_BITMASK;
2596
2597       /* if no other condition is keeping UE as inactive,
2598        * activate UE
2599        */
2600       RG_SCH_CMN_UL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2601
2602       if ( delInUlScan == TRUE )
2603       {
2604          /*calculate next on duration occurence 
2605           * and it to the onDuration Queue*/
2606          rgSCHDrxMvToNxtOnDurOcc(cell,ue,ulIndex,FALSE);
2607       }/*delInUlScan == FALSE */
2608    }/*while(node)*/
2609    
2610    /***********************************************************
2611     *    Scanning OnDurationExpQ in UL
2612     ***********************************************************/
2613
2614    node = drxCell->drxQ[ulIndex].onDurationExpQ.first;
2615
2616    /* Initialize UL inactive list */
2617    cmLListInit(&ulInactvLst);
2618
2619    while (node)
2620    {
2621       ue = (RgSchUeCb*)node->node;
2622       node = node->next;
2623       drxUe = RG_SCH_DRX_GET_UE(ue);
2624
2625       if ( delInUlScan == FALSE )
2626       {
2627          drxUe->onDurExpDistance--;
2628       }
2629
2630       if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2631       {
2632          continue;
2633       }
2634
2635       /*UE is inactive as onduration has expired */
2636       drxUe->drxUlInactvMask  |= RG_SCH_DRX_ONDUR_BITMASK;
2637
2638       if( !RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
2639       {
2640          /* set the inactive bit to indicate UE has now become inactive */  
2641          ue->ul.ulInactvMask |= RG_DRX_INACTIVE;
2642
2643          /* Add to DL inactive list */
2644          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
2645          ue->ulDrxInactvLnk.node = (PTR)ue;
2646       }
2647
2648       if ( delInUlScan == TRUE)
2649       {
2650          /*Remove from DRX queue*/
2651          cmLListDelFrm(&(drxCell->drxQ[ulIndex].onDurationExpQ),
2652                &(drxUe->onDurationExpEnt));
2653
2654          drxUe->onDurExpIndx = DRX_INVALID;
2655       }
2656
2657    }/*while(node)*/
2658
2659    /* Send the list to the scheduler to mark UE as inactive in UL*/
2660    cellSch = RG_SCH_CMN_GET_CELL(cell);
2661    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
2662    
2663    return;
2664 }
2665
2666 /** @brief This function is called to handle onDurationTimer per TTI processing.
2667  *
2668  * @details
2669  *    Invoked by - rgSCHDrxTtiInd 
2670  *
2671  *     Function:  rgSCHDrxTtiHdlOnDurDl
2672  *
2673  *         Processing steps:
2674  *
2675  *           - OnDurationTimer is handled using the drxQ @sa RgSchDrxQ
2676  *
2677  *           - For Downlink we shall look at an index that is 
2678  *             n + RG_SCH_DRX_DL_DELTA. 
2679  *
2680  *
2681  * @param  RgSchCellCb  *cellCb
2682  * @param  uint16_t          dlIndex
2683  * @return Void
2684  */
2685
2686 #ifdef ANSI
2687 PRIVATE Void rgSCHDrxTtiHdlOnDurDl
2688 (
2689 RgSchCellCb    *cell,
2690 uint16_t                dlIndex
2691 )
2692 #else
2693 PRIVATE Void rgSCHDrxTtiHdlOnDurDl(cell, dlIndex)
2694 RgSchCellCb   *cell;
2695 uint16_t           dlIndex;
2696 #endif
2697 {
2698    CmLList           *node;
2699    RgSchDRXCellCb    *drxCell  = NULLP;
2700    RgSchUeCb         *ue       = NULLP;
2701    RgSchDrxUeCb      *drxUe    = NULLP;
2702    RgSchCmnCell      *cellSch = NULLP;
2703    uint16_t               expiryIndex;
2704    CmLListCp         dlInactvLst; /* list of UE's becoming DL-inactive */
2705    Bool              delInUlScan = FALSE;
2706
2707    /* The DL loop, if onDurationTimer has started, will add the UeCb
2708     * in the onDurationTmrExprQ. If !delInUlScan, then calculate the next
2709     * OnDuration occurence, q it there and remove it from the current location.
2710     */
2711    /***********************************************************
2712     *    Scanning OnDurationQ in DL
2713     ***********************************************************/
2714    drxCell     = (cell->drxCb);
2715    
2716    delInUlScan = drxCell->delInUlScan;
2717    //printf("CELL  Timer  [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2718    
2719    node = drxCell->drxQ[dlIndex].onDurationQ.first;
2720
2721
2722    while (node)
2723    {
2724       ue = (RgSchUeCb* )node->node;
2725
2726       node = node->next;
2727
2728       drxUe = RG_SCH_DRX_GET_UE(ue);
2729
2730       if ( delInUlScan == TRUE)
2731       {
2732          drxUe->distance--;
2733       }
2734
2735       if ( drxUe->distance != DRX_TMR_EXPRD )
2736       {
2737          continue;
2738       }
2739
2740
2741       /* UE is active as onduration is to start */
2742       drxUe->drxDlInactvMask &= ~RG_SCH_DRX_ONDUR_BITMASK;
2743
2744       /* set the UE as DRX active*/ 
2745
2746       /* Update UE's inactive mask and if required move UE to ACTIVE state */
2747       RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2748       /*ACC-TDD */      
2749       /* Temporary fix to delete stale entry */
2750       if (drxUe->onDurExpIndx != DRX_INVALID)
2751       {
2752          RLOG_ARG4(L_DEBUG,DBG_CELLID,cell->cellId, 
2753                "UEID:%d PreExisted[%d:%d]in onDurExpQ new[%d]",
2754                ue->ueId, 
2755                drxUe->onDurExpIndx, 
2756                drxUe->onDurExpDistance, 
2757                dlIndex);
2758          cmLListDelFrm(&(drxCell->drxQ[drxUe->onDurExpIndx].onDurationExpQ),
2759                &(drxUe->onDurationExpEnt));
2760
2761          drxUe->onDurExpIndx = DRX_INVALID;
2762       }
2763       /*start the onduration expiry timer*/
2764 #ifdef LTE_TDD
2765       rgSCHDrxCalcNxtTmrExpry(cell,
2766             ue,
2767             RG_DL_DELTA,
2768             drxUe->onDurTmrLen,
2769             &(drxUe->onDurExpDistance),
2770             &(expiryIndex)
2771             );
2772 #else /*LTE_TDD */
2773       expiryIndex = ((dlIndex + drxUe->onDurTmrLen) %
2774             RG_SCH_MAX_DRXQ_SIZE);
2775       drxUe->onDurExpDistance = (drxUe->onDurTmrLen)/
2776          RG_SCH_MAX_DRXQ_SIZE;
2777 #endif /*LTE_TDD */
2778
2779       cmLListAdd2Tail(&(drxCell->drxQ[expiryIndex].onDurationExpQ),
2780             &(drxUe->onDurationExpEnt));
2781       //printf("DRXOnDuration Timer Started at [SFN : %d],[SF : %d]\n",cell->crntTime.sfn,cell->crntTime.slot);
2782       drxUe->onDurationExpEnt.node = (PTR)ue;
2783       drxUe->onDurExpIndx          = expiryIndex;
2784
2785       //printf("DRxOnDuration will Expire = [%d]\n",(cell->crntTime.sfn*10+cell->crntTime.slot+drxUe->onDurTmrLen));
2786
2787       if ( delInUlScan == FALSE )
2788       {
2789          /*calculate next on duration occurence 
2790           * and it to the onDuration Queue*/
2791          rgSCHDrxMvToNxtOnDurOcc(cell,ue,dlIndex,FALSE);
2792       }/*delInUlScan == FALSE */
2793
2794    }/*while(node)*/
2795
2796    /***********************************************************
2797     *    Scanning OnDurationExpQ in DL
2798     ***********************************************************/
2799
2800    /* Mark UE as Inactive based on OnDuration Expiry */
2801    node = drxCell->drxQ[dlIndex].onDurationExpQ.first;
2802
2803    /* Initialize DL inactive list */
2804    cmLListInit(&dlInactvLst);
2805
2806    while (node)
2807    {
2808       ue    = (RgSchUeCb*)node->node;
2809       node  = node->next;
2810       drxUe = RG_SCH_DRX_GET_UE(ue);
2811
2812       if ( delInUlScan == TRUE )
2813       {
2814          drxUe->onDurExpDistance--;
2815       }
2816
2817       if ( drxUe->onDurExpDistance != DRX_TMR_EXPRD )
2818       {
2819          continue;
2820       }
2821
2822
2823       /* UE is inactive as onduration has expired */
2824       drxUe->drxDlInactvMask |= (RG_SCH_DRX_ONDUR_BITMASK);
2825
2826       if( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
2827       {
2828          /* set the inactive bit to indicate UE has now become inactive */  
2829          ue->dl.dlInactvMask |= RG_DRX_INACTIVE;
2830
2831          /* Add to DL inactive list */
2832          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
2833          ue->dlDrxInactvLnk.node = (PTR)ue;
2834       }
2835
2836       if ( delInUlScan == FALSE )
2837       {
2838          /*Remove from DRX queue*/
2839          cmLListDelFrm(&(drxCell->drxQ[dlIndex].onDurationExpQ),
2840                &(drxUe->onDurationExpEnt));
2841
2842          drxUe->onDurExpIndx = DRX_INVALID;
2843       }
2844
2845    }
2846
2847    /* Send the list to the scheduler to mark UE as inactive */
2848    cellSch = RG_SCH_CMN_GET_CELL(cell);
2849    cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
2850
2851    return;
2852 }/*rgSCHDrxTtiHdlOnDurDl*/
2853
2854  /** @brief This function handles the Dl HARQ timer's processing per TTI.
2855   *
2856   * @details
2857   * Invoked by - rgSCHDrxTtiHdlDlHarq 
2858   *
2859   *     Function: rgSCHDrxTtiHdlDlHarqRTT 
2860   *
2861   *         Processing steps:
2862   *         - In addition per TTI DRX module must look at Downlink HARQ queues
2863  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
2864  *             Every TTI at the scheduling index we shall check these queues and
2865  *             process accordingly. 
2866  *
2867  * @param  RgSchCellCb *cellCb
2868  * @param  uint16_t          dlIndex
2869  * @return Void 
2870  */
2871
2872 #ifdef ANSI
2873 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT
2874 (
2875 RgSchCellCb          *cell,
2876 uint16_t                   dlIndex
2877 )
2878 #else /* ANSI */
2879 PRIVATE Void rgSCHDrxTtiHdlDlHarqRTT(cell, dlIndex)
2880 RgSchCellCb          *cell;
2881 uint16_t                   dlIndex;
2882 #endif /* ANSI */
2883 {
2884    CmLList             *node;
2885    RgSchDrxDlHqProcCb  *drxHq;
2886    RgSchDlHqProcCb     *dlHq;
2887    RgSchDRXCellCb      *drxCell;
2888    RgSchDrxUeCb        *drxUe;
2889    uint16_t                 reTxExpIndx;
2890    Bool                delInUlScan;
2891    RgSchUeCb           *ue;
2892    CmLListCp           dlInactvLst; /* list of UE's becoming DL-inactive */
2893    RgSchCmnCell        *cellSch = RG_SCH_CMN_GET_CELL(cell);
2894    uint8_t                  cellIdx;
2895    uint32_t                 dlInactvMask;
2896
2897    drxCell     = cell->drxCb;
2898    delInUlScan = drxCell->delInUlScan;
2899
2900    /***********************************************************
2901     *    Scanning harqRTTQ in DL 
2902     ***********************************************************/
2903
2904    cmLListInit(&dlInactvLst);
2905    node = drxCell->drxQ[dlIndex].harqRTTQ.first;
2906
2907    while (node)
2908    {
2909       dlHq = (RgSchDlHqProcCb*)node->node;
2910       node = node->next;
2911       ue   = dlHq->hqE->ue;
2912 #ifdef EMTC_ENABLE
2913       if(TRUE == ue->isEmtcUe)
2914       {
2915          continue;
2916       }
2917 #endif
2918       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2919       drxUe = RG_SCH_DRX_GET_UE(ue);
2920       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2921       /* add the UE to the cell's retransmission queuee before starting 
2922        * reTx timer, because this will not depend on retx timer trigger*/
2923       rgSCHUtlDlProcAddToRetx(dlHq->hqE->cell, dlHq);
2924
2925       if ( delInUlScan == FALSE)
2926       {
2927          cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRTTQ),
2928                &(drxHq->harqRTTEnt));
2929
2930          drxHq->rttIndx = DRX_INVALID;
2931       }
2932       /* ccpu00134565: Starting retransmission timer only if timerLen is
2933        * having non-zero value after reduction, Adding to Retx queue is 
2934        * independent of starting retransmission timer. Hence if part will
2935        * take care of starting retx timer only*/
2936       if (drxUe->drxRetransTmrLen > drxHq->retxTmrReduction)
2937       {
2938          /* add the harq proc to the re-tx queue--*/
2939 #ifdef LTE_TDD
2940          /* ccpu00134196-[Add]-DRX retx timer changes */
2941          rgSCHDrxCalcNxtTmrExpry(cell,
2942               ue,
2943               RG_DL_DELTA,
2944               drxUe->drxRetransTmrLen-drxHq->retxTmrReduction,
2945               NULLP, /*retransQ does not maintain distance*/
2946               &reTxExpIndx
2947               );
2948
2949 #else /*LTE_TDD*/
2950          /* ccpu00134196-[Add]-DRX retx timer changes */
2951          reTxExpIndx =  ((dlIndex +
2952                   drxUe->drxRetransTmrLen-drxHq->retxTmrReduction) % 
2953                   RG_SCH_MAX_DRXQ_SIZE);
2954 #endif /*LTE_TDD*/
2955          /* TODO. Workaround to avoid duplicate entry */ 
2956          if(drxHq->reTxIndx == DRX_INVALID)
2957          {
2958             cmLListAdd2Tail (&(drxCell->drxQ[reTxExpIndx].harqRetxQ),
2959                   &(drxHq->harqRetxEnt));
2960
2961             drxHq->harqRetxEnt.node = (PTR)dlHq;
2962             drxHq->reTxIndx         = reTxExpIndx;
2963          }
2964          else
2965          {
2966             RLOG_ARG4(L_ERROR,DBG_CELLID,cell->cellId,"CRNTI:%d "
2967                "Adding Retx Node to expire at RetxIndx: %d at dlIndex %d "
2968                "drxHq->reTxIndx %d", ue->ueId, reTxExpIndx, dlIndex, 
2969                drxHq->reTxIndx); 
2970             continue;
2971          }
2972          /*mark the ue as active for downlink--*/
2973          drxUe->drxDlInactvMask  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2974          drxUe->drxDlInactvMaskPerCell[cellIdx]  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2975                                               
2976          /* Update UE's inactive mask and if required move UE to ACTIVE state */
2977          RG_SCH_CMN_DL_UPDT_INACTV_MASK(cell, ue, RG_DRX_INACTIVE);
2978       }
2979    }/*while(node)*/
2980    
2981    /***********************************************************
2982     *    Scanning harqRetxQ in DL 
2983     ***********************************************************/
2984
2985    node = drxCell->drxQ[dlIndex].harqRetxQ.first;
2986    while (node)
2987    {
2988       dlHq = (RgSchDlHqProcCb*)node->node;
2989       ue   = dlHq->hqE->ue;
2990       drxUe = RG_SCH_DRX_GET_UE(ue);
2991       node = node->next;
2992       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
2993       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
2994
2995       /*mark the ue as in-active for downlink*/
2996       drxUe->drxDlInactvMaskPerCell[cellIdx]  |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
2997
2998       dlInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
2999
3000       for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3001       {
3002          dlInactvMask &= drxUe->drxDlInactvMaskPerCell[cellIdx];
3003       }   
3004
3005       drxUe->drxDlInactvMask |= dlInactvMask;
3006
3007       /* if no other condition is keeping ue active,
3008        * inactivate the Ue 
3009        */
3010       if ( !RG_SCH_DRX_DL_IS_UE_ACTIVE(drxUe))
3011       {
3012           ue->dl.dlInactvMask |= (RG_DRX_INACTIVE);
3013
3014          /* Add to DL inactive list */
3015          cmLListAdd2Tail(&dlInactvLst,&(ue->dlDrxInactvLnk));
3016          ue->dlDrxInactvLnk.node = (PTR)ue;
3017       }
3018
3019       /*remove the harq proc from this queue*/
3020       if ( delInUlScan == FALSE)
3021       {
3022          cmLListDelFrm (&(drxCell->drxQ[dlIndex].harqRetxQ),
3023                &(drxHq->harqRetxEnt));
3024          drxHq->reTxIndx = DRX_INVALID;
3025       }
3026    }
3027    /*Call schedulers to inactivate ue*/
3028    cellSch->apisDl->rgSCHDlInactvtUes(cell, &dlInactvLst);
3029
3030    return;
3031 }
3032
3033  /** @brief This function handles the Ul HARQ timer's processing per TTI.
3034   *
3035   * @details
3036   * Invoked by - rgSCHDrxTtiHdlDlHarq 
3037   *
3038   *     Function: rgSCHDrxTtiHdlUlHarqRTT 
3039   *
3040   *         Processing steps:
3041   *         - In addition per TTI DRX module must look at Downlink HARQ queues
3042  *             maintained to track HARQ RTT timer and drx-RetransmissionTimer.
3043  *             Every TTI at the scheduling index we shall check these queues and
3044  *             process accordingly. 
3045  *
3046  *             - Though these timers are related to downlink HARQ processing, they
3047  *             have an impact on uplink scheduling. The reason is that the UE,
3048  *             if active for downlink scheduling implies that it is reading
3049  *             PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3050  *             every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
3051  *
3052  *
3053  *
3054  * @param  RgSchCellCb *cellCb
3055  * @param  uint16_t          ulIndex
3056   * @return Void 
3057   */
3058
3059 #ifdef ANSI
3060 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT
3061 (
3062 RgSchCellCb          *cell,
3063 uint16_t                   ulIndex
3064 )
3065 #else /* ANSI */
3066 PRIVATE Void rgSCHDrxTtiHdlUlHarqRTT(cell, ulIndex)
3067 RgSchCellCb          *cell;
3068 uint16_t                   ulIndex;
3069 #endif /* ANSI */
3070 {
3071    CmLList             *node;
3072    RgSchDrxDlHqProcCb  *drxHq;
3073    RgSchDlHqProcCb     *dlHq;
3074    RgSchDRXCellCb      *drxCell;
3075    RgSchDrxUeCb        *drxUe;
3076    Bool              delInUlScan;
3077    RgSchUeCb          *ue;
3078    CmLListCp         ulInactvLst; /* list of UE's becoming DL-inactive */
3079    RgSchCmnCell      *cellSch = RG_SCH_CMN_GET_CELL(cell);
3080    uint8_t                cellIdx;
3081    uint32_t               ulInactvMask;
3082
3083
3084    drxCell     = cell->drxCb;
3085    delInUlScan = drxCell->delInUlScan;
3086
3087    cmLListInit(&ulInactvLst);
3088
3089    /***********************************************************
3090     *    Scanning harqRTTQ in UL 
3091     ***********************************************************/
3092
3093    /*
3094       Though these timers are related to downlink HARQ processing, they
3095       have an impact on uplink scheduling. The reason is that the UE,
3096       if active for downlink scheduling implies that it is reading
3097       PDCCHs i.e. we can still send uplink allocations to the UE. Hence
3098       every TTI Uplink too would look at the harqRTTQ and harqRetxQ. 
3099       */
3100
3101    node = drxCell->drxQ[ulIndex].harqRTTQ.first;
3102    while (node)
3103    {
3104       dlHq = (RgSchDlHqProcCb*)node->node;
3105       ue   = dlHq->hqE->ue;
3106       drxUe = RG_SCH_DRX_GET_UE(ue);
3107       node = node->next;
3108       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3109       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3110
3111       if ( delInUlScan == TRUE )
3112       {
3113          /* remove the harq proc from this queue--*/
3114          cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRTTQ), 
3115                &(drxHq->harqRTTEnt));
3116
3117          drxHq->rttIndx = DRX_INVALID;
3118       }
3119
3120       /* mark the ue as active for uplink--*/
3121       drxUe->drxUlInactvMask  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3122       drxUe->drxUlInactvMaskPerCell[cellIdx]  &= ~(RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3123
3124       /* Update UE's inactive mask and if required move UE to ACTIVE state */
3125       RG_SCH_CMN_UL_UPDT_INACTV_MASK( cell, ue, RG_DRX_INACTIVE);
3126    }
3127
3128    /***********************************************************
3129     *    Scanning harqRetxQ in UL 
3130     ***********************************************************/
3131    node = drxCell->drxQ[ulIndex].harqRetxQ.first;
3132    while (node)
3133    {
3134       dlHq  = (RgSchDlHqProcCb*)node->node;
3135       ue    = dlHq->hqE->ue;
3136       drxUe = RG_SCH_DRX_GET_UE(ue);
3137       drxHq = RG_SCH_DRX_GET_DL_HQ(dlHq);
3138       cellIdx = ue->cellIdToCellIdxMap[RG_SCH_CELLINDEX(dlHq->hqE->cell)];
3139
3140       /*mark the ue as in-active for uplink*/
3141
3142       drxUe->drxUlInactvMaskPerCell[cellIdx]  |= (RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId);
3143
3144       ulInactvMask = RG_SCH_DRX_DLHQ_BITMASK << dlHq->procId;
3145
3146       for(cellIdx = 0; cellIdx < CM_LTE_MAX_CELLS; cellIdx++)
3147       {
3148          ulInactvMask &= drxUe->drxUlInactvMaskPerCell[cellIdx];
3149       }   
3150
3151       drxUe->drxUlInactvMask |= ulInactvMask; 
3152
3153       if(!RG_SCH_DRX_UL_IS_UE_ACTIVE(drxUe))
3154       {
3155          ue->ul.ulInactvMask |= (RG_DRX_INACTIVE);
3156
3157          cmLListAdd2Tail(&ulInactvLst,&(ue->ulDrxInactvLnk));
3158          ue->ulDrxInactvLnk.node  = (PTR)ue;
3159       }
3160
3161       /* remove the harq proc from this queue*/
3162       if ( delInUlScan == TRUE)
3163       {
3164          cmLListDelFrm (&(drxCell->drxQ[ulIndex].harqRetxQ),
3165                &(drxHq->harqRetxEnt));
3166          drxHq->reTxIndx = DRX_INVALID;
3167       }
3168
3169       node = node->next;
3170    }
3171    cellSch->apisUl->rgSCHUlInactvtUes(cell, &ulInactvLst);
3172
3173    return;
3174
3175 }
3176
3177 /**********************************************************************
3178  
3179          End of file
3180 **********************************************************************/