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