[Epic-ID: ODUHIGH-556][Task-ID: ODUHIGH-570] UL Candidate Sel and Res Alloc for Multi UE
[o-du/l2.git] / src / 5gnrsch / sch.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:     sch.c
22   
23      Type:     C source file
24   
25      Desc:     C source code for scheduler fucntions
26   
27      File:     sch.c
28   
29 **********************************************************************/
30
31 /** @file sch.c
32 @brief This file implements the schedulers main access to MAC layer code.
33 */
34 #include "common_def.h" 
35 #include "du_app_mac_inf.h"
36 #include "lrg.h"
37 #include "tfu.h"
38 #include "du_log.h"
39 #include "rgr.h"
40 #include "rg_sch_inf.h"
41 #include "rg_sch.h"
42
43 #include "tfu.x"           /* TFU types */
44 #include "lrg.x"           /* layer management typedefs for MAC */
45 #include "rgr.x"           /* layer management typedefs for MAC */
46 #include "rg_sch_inf.x"         /* typedefs for Scheduler */
47 #include "mac_sch_interface.h"
48 #include "sch.h"
49 #include "sch_tmr.h"
50 #include "sch_utils.h"
51 #include "sch_fcfs.h"
52 #include "sch_slice_based.h"
53
54 /**
55  * @brief Scheduler All Apis initialized. 
56  *
57  * @details
58  *
59  *     Function : schAllApisInit
60  *     
61  *     This function initializes all Scheduler APIs/functionality for each kind
62  *     of scheduler type. 
63  *     
64  *  @param[in]  Inst inst, the Scheduler instance 
65  *  @return  void
66  **/
67 void schAllApisInit(Inst inst)
68 {
69     schFcfsAllApisInit(&schCb[inst].allApis[SCH_FCFS]);  
70     schSliceBasedAllApisInit(&schCb[inst].allApis[SCH_SLICE_BASED]);
71 }
72
73 /**
74  * @brief Scheduler instance Configuration Handler. 
75  *
76  * @details
77  *
78  *     Function : SchInstCfg
79  *     
80  *     This function in called by SchProcGenCfgReq(). It handles the
81  *     general configurations of the scheduler instance. Returns
82  *     reason for success/failure of this function.
83  *     
84  *  @param[in]  RgCfg *cfg, the Configuaration information 
85  *  @return  uint16_t
86  *      -# LCM_REASON_NOT_APPL 
87  *      -# LCM_REASON_INVALID_MSGTYPE
88  *      -# LCM_REASON_MEM_NOAVAIL
89  **/
90 uint8_t SchInstCfg(RgCfg *cfg, Inst  dInst)
91 {
92    uint16_t ret = LCM_REASON_NOT_APPL;
93    Inst     inst = (dInst - SCH_INST_START);
94
95    DU_LOG("\nDEBUG  -->  SCH : Entered SchInstCfg()");
96    /* Check if Instance Configuration is done already */
97    if (schCb[inst].schInit.cfgDone == TRUE)
98    {
99       return LCM_REASON_INVALID_MSGTYPE;
100    }
101    /* Update the Pst structure for LM interface */
102    memcpy(&schCb[inst].schInit.lmPst, &cfg->s.schInstCfg.genCfg.lmPst, sizeof(Pst));
103
104    schCb[inst].schInit.inst = inst;
105    schCb[inst].schInit.lmPst.srcProcId = schCb[inst].schInit.procId;
106    schCb[inst].schInit.lmPst.srcEnt = schCb[inst].schInit.ent;
107    schCb[inst].schInit.lmPst.srcInst = schCb[inst].schInit.inst +
108       SCH_INST_START;
109    schCb[inst].schInit.lmPst.event = EVTNONE;
110
111    schCb[inst].schInit.region = cfg->s.schInstCfg.genCfg.mem.region;
112    schCb[inst].schInit.pool = cfg->s.schInstCfg.genCfg.mem.pool;
113 #ifdef LTE_ADV
114    schCb[inst].genCfg.forceCntrlSrbBoOnPCel =  cfg->s.schInstCfg.genCfg.forceCntrlSrbBoOnPCel;
115    schCb[inst].genCfg.isSCellActDeactAlgoEnable =  cfg->s.schInstCfg.genCfg.isSCellActDeactAlgoEnable;
116 #endif
117    schCb[inst].genCfg.startCellId    = cfg->s.schInstCfg.genCfg.startCellId;
118
119    schCb[inst].schTimersInfo.tmrRes = cfg->s.schInstCfg.genCfg.tmrRes;
120    /* Initialzie the timer queue */   
121    memset(&schCb[inst].schTimersInfo.tmrTq, 0, sizeof(CmTqType) * SCH_TQ_SIZE);
122    /* Initialize the timer control point */
123    memset(&schCb[inst].schTimersInfo.tmrTqCp, 0, sizeof(CmTqCp));
124    schCb[inst].schTimersInfo.tmrTqCp.tmrLen = SCH_TQ_SIZE;
125
126    /* SS_MT_TMR needs to be enabled as schActvTmr needs instance information */
127    /* Timer Registration request to system services */
128    if (ODU_REG_TMR_MT(schCb[inst].schInit.ent, dInst, (int)schCb[inst].schTimersInfo.tmrRes, schActvTmr) != ROK)
129    {
130       DU_LOG("\nERROR  -->  SCH : SchInstCfg(): Failed to register timer.");
131       return (LCM_REASON_MEM_NOAVAIL);
132    }   
133
134    /* Initialize statistics related configurations */
135    memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
136    cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
137    cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
138
139    /* Set Config done in TskInit */
140    schCb[inst].schInit.cfgDone = TRUE;
141    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
142    
143    schAllApisInit(inst);
144    return ret;
145 }
146
147 /**
148  * @brief Layer Manager Configuration request handler. 
149  *
150  * @details
151  *
152  *     Function : SchProcGenCfgReq
153  *     
154  *     This function handles the configuration
155  *     request received at scheduler instance from the Layer Manager.
156  *     -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
157  *        functions rgHdlGenCfg() or rgHdlSapCfg().
158  *     -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
159  *     
160  *  @param[in]  Pst *pst, the post structure     
161  *  @param[in]  RgMngmt *cfg, the configuration parameter's structure
162  *  @return  S16
163  *      -# ROK
164  **/
165 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
166 {
167    uint8_t   ret = LCM_PRIM_OK;
168    uint16_t  reason = LCM_REASON_NOT_APPL;
169    RgMngmt   cfm;
170    Pst       cfmPst;
171
172    if(pst->dstInst < SCH_INST_START)
173    {
174       DU_LOG("\nERROR  -->  SCH : Invalid inst ID");
175       DU_LOG("\nERROR  -->  SCH : SchProcGenCfgReq(): "
176             "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
177       return ROK;
178    }
179    DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
180    /* Fill the post structure for sending the confirmation */
181    memset(&cfmPst, 0 , sizeof(Pst));
182    SchFillCfmPst(pst, &cfmPst, cfg);
183
184    memset(&cfm, 0, sizeof(RgMngmt));
185
186 #ifdef LMINT3
187    cfm.hdr.transId =
188       cfg->hdr.transId;
189 #endif
190
191    cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
192    switch(cfg->hdr.elmId.elmnt)
193    {
194       case STSCHINST:
195          reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
196          break;
197       default:
198          ret = LCM_PRIM_NOK;
199          reason = LCM_REASON_INVALID_ELMNT;
200          DU_LOG("\nERROR  -->  SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
201          break;
202    }
203
204    if (reason != LCM_REASON_NOT_APPL)
205    {
206       ret = LCM_PRIM_NOK;
207    }
208
209    cfm.cfm.status = ret;
210    cfm.cfm.reason = reason;
211
212    SchSendCfgCfm(&cfmPst, &cfm);
213    /*   SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
214
215    return ROK;
216 }/*-- SchProcGenCfgReq --*/
217
218 #ifdef NR_TDD
219 /**
220  *@brief Returns TDD periodicity in micro seconds
221  *
222  * @details
223  * 
224  * Function : schGetPeriodicityInMsec 
225  * 
226  * This API retunrs TDD periodicity in micro seconds
227  * 
228  * @param[in] DlUlTxPeriodicity 
229  * @return  periodicityInMsec
230  * **/
231
232 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
233 {
234    uint16_t  periodicityInMsec = 0;
235    switch(tddPeriod)
236    {
237       case TX_PRDCTY_MS_0P5:
238       {
239          periodicityInMsec = 500;
240          break;
241       }
242       case TX_PRDCTY_MS_0P625:
243       {
244          periodicityInMsec = 625;
245          break;
246       }
247       case TX_PRDCTY_MS_1:
248       {
249          periodicityInMsec = 1000;
250          break;
251       }
252       case TX_PRDCTY_MS_1P25:
253       {
254          periodicityInMsec = 1250;
255          break;
256       }
257       case TX_PRDCTY_MS_2:
258       {
259          periodicityInMsec = 2000;
260          break;
261       }
262       case TX_PRDCTY_MS_2P5:
263       {
264          periodicityInMsec = 2500;
265          break;
266       }
267       case TX_PRDCTY_MS_5:
268       {
269          periodicityInMsec = 5000;
270          break;
271       }
272       case TX_PRDCTY_MS_10:
273       {
274          periodicityInMsec = 10000;
275          break;
276       }
277       default:
278       {
279          DU_LOG("\nERROR  -->  SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
280       }
281    }
282
283    return periodicityInMsec;
284 }
285
286 /**
287  *@brief Fills the slotCfg from CellCfg
288  *
289  * @details
290  * 
291  * Function : schFillSlotConfig 
292  * 
293  * This API Fills the slotCfg from CellCfg
294  * 
295  * @param[in] SchCellCb *cell, TDDCfg tddCfg
296  * @return  void
297  * **/
298 void schFillSlotConfig(SchCellCb *cell, TDDCfg tddCfg)
299 {
300    uint8_t slotIdx = 0, symbolIdx = 0;
301
302    for(slotIdx =0 ;slotIdx < MAX_TDD_PERIODICITY_SLOTS; slotIdx++) 
303    {
304       for(symbolIdx = 0; symbolIdx < MAX_SYMB_PER_SLOT; symbolIdx++)
305       {
306          /*Fill Full-DL Slots as well as DL symbols ini 1st Flexi Slo*/
307          if(slotIdx < tddCfg.nrOfDlSlots || \
308                (slotIdx == tddCfg.nrOfDlSlots && symbolIdx < tddCfg.nrOfDlSymbols)) 
309          {
310               cell->slotCfg[slotIdx][symbolIdx] = DL_SYMBOL; 
311          }
312
313          /*Fill Full-FLEXI SLOT and as well as Flexi Symbols in 1 slot preceding FULL-UL slot*/ 
314          else if(slotIdx < (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) ||  \
315                (slotIdx == (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) && \
316                 symbolIdx < (MAX_SYMB_PER_SLOT - tddCfg.nrOfUlSymbols)))
317          {
318               cell->slotCfg[slotIdx][symbolIdx] = FLEXI_SYMBOL; 
319          }
320          /*Fill Partial UL symbols and Full-UL slot*/
321          else
322          {
323               cell->slotCfg[slotIdx][symbolIdx] = UL_SYMBOL; 
324          }
325       }
326    }
327 }
328
329 /**
330  * @brief init TDD slot config 
331  *
332  * @details
333  *
334  *     Function : schInitTddSlotCfg 
335  *      
336  *      This API is invoked after receiving schCellCfg
337  *           
338  *  @param[in]  schCellCb *cell
339  *  @param[in]  SchCellCfg *schCellCfg
340  *  @return  void
341  **/
342 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
343 {
344    uint16_t periodicityInMicroSec = 0;
345    int8_t slotIdx, symbIdx;
346
347    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
348    cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
349    cell->slotFrmtBitMap = 0;
350    schFillSlotConfig(cell, schCellCfg->tddCfg);
351    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
352    {
353       symbIdx = 0;
354       /* If the first and last symbol are the same, the entire slot is the same type */
355       if((cell->slotCfg[slotIdx][symbIdx] == cell->slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
356               cell->slotCfg[slotIdx][symbIdx] != FLEXI_SYMBOL)
357       {
358          switch(cell->slotCfg[slotIdx][symbIdx])
359          {
360             case DL_SLOT:
361             {
362                /*BitMap to be set to 00 */
363                cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
364                break;
365             }
366             case UL_SLOT:
367             {
368                /*BitMap to be set to 01 */
369                cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
370                break;
371             }
372             default:
373                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
374            }
375          continue;
376       }
377       /* slot config is flexible. First set slotBitMap to 10 */
378       cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
379    }
380 }
381 #endif
382
383 /**
384  * @brief Fill SSB start symbol
385  *
386  * @details
387  *
388  *     Function : fillSsbStartSymb 
389  *      
390  *      This API stores SSB start index per beam
391  *           
392  *  @param[in]  SchCellCb     *cellCb
393  *  @return  int
394  *      -# ROK 
395  *      -# RFAILED 
396  **/
397 void fillSsbStartSymb(SchCellCb *cellCb)
398 {
399    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
400
401    scs = cellCb->cellCfg.ssbScs;
402
403    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
404    symbIdx = 0;
405    /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
406    switch(scs)
407    {
408       case SCS_15KHZ:
409          {
410             if(cellCb->cellCfg.ssbFrequency <= 300000)
411                cnt = 2;/* n = 0, 1 */
412             else
413                cnt = 4; /* n = 0, 1, 2, 3 */
414             for(uint8_t idx=0; idx<cnt; idx++)
415             {
416                /* start symbol determined using {2, 8} + 14n */
417                ssbStartSymbArr[symbIdx++] = 2 +  MAX_SYMB_PER_SLOT*idx;
418                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
419             }
420          }
421          break;
422       case SCS_30KHZ:
423          {
424             if(cellCb->cellCfg.ssbFrequency <= 300000)
425                cnt = 1;/* n = 0 */
426             else
427                cnt = 2; /* n = 0, 1 */
428             for(uint8_t idx=0; idx<cnt; idx++)
429             {
430                /* start symbol determined using {4, 8, 16, 20} + 28n */
431                ssbStartSymbArr[symbIdx++] = 4 +  MAX_SYMB_PER_SLOT*idx;
432                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
433                ssbStartSymbArr[symbIdx++] = 16 +  MAX_SYMB_PER_SLOT*idx;
434                ssbStartSymbArr[symbIdx++] = 20 +  MAX_SYMB_PER_SLOT*idx;
435             }
436          }
437          break;
438       default:
439          DU_LOG("\nERROR  -->  SCH : SCS %d is currently not supported", scs);
440    }
441    memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
442    memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
443 }
444
445
446 /**
447  * @brief init cellCb based on cellCfg
448  *
449  * @details
450  *
451  *     Function : schInitCellCb 
452  *      
453  *      This API is invoked after receiving schCellCfg
454  *           
455  *  @param[in]  schCellCb *cell
456  *  @param[in]  SchCellCfg *schCellCfg
457  *  @return  int
458  *      -# ROK 
459  *      -# RFAILED 
460  **/
461 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
462 {
463    uint16_t scsInKhz = 0;
464    SchCellCb *cell= NULLP;
465    SCH_ALLOC(cell, sizeof(SchCellCb));
466    if(!cell)
467    {
468       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
469       return RFAILED;
470    }
471
472    cell->cellId = schCellCfg->cellId; 
473    cell->instIdx = inst;
474    scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
475    
476    /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
477    cell->numerology = log2(scsInKhz/BASE_SCS);
478    switch(cell->numerology)
479    {
480       case SCH_NUMEROLOGY_0:
481          {
482             cell->numSlots = SCH_MU0_NUM_SLOTS;
483          }
484          break;
485       case SCH_NUMEROLOGY_1:
486          {
487             cell->numSlots = SCH_MU1_NUM_SLOTS;
488          }
489          break;
490       case SCH_NUMEROLOGY_2:
491          {
492             cell->numSlots = SCH_MU2_NUM_SLOTS;
493          }
494          break;
495       case SCH_NUMEROLOGY_3:
496          {
497             cell->numSlots = SCH_MU3_NUM_SLOTS;
498          }
499          break;
500       case SCH_NUMEROLOGY_4:
501          {
502             cell->numSlots = SCH_MU4_NUM_SLOTS;
503          }
504          break;
505       default:
506          DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", cell->numerology);
507    }
508 #ifdef NR_TDD
509    schInitTddSlotCfg(cell, schCellCfg);   
510 #endif
511
512    SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
513    if(!cell->schDlSlotInfo)
514    {
515       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
516       return RFAILED;
517    }
518
519    SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
520    if(!cell->schUlSlotInfo)
521    {
522       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
523       return RFAILED;
524    }
525
526    for(uint8_t idx=0; idx<cell->numSlots; idx++)
527    {
528       SchDlSlotInfo *schDlSlotInfo;
529       SchUlSlotInfo *schUlSlotInfo;
530
531       /* DL Alloc */
532       SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
533       if(!schDlSlotInfo)
534       {
535          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
536          return RFAILED;
537       }
538
539       /* UL Alloc */
540       SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
541       if(!schUlSlotInfo)
542       {
543          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
544          return RFAILED;
545       }
546
547       schInitDlSlot(schDlSlotInfo);
548       schInitUlSlot(schUlSlotInfo);
549
550       cell->schDlSlotInfo[idx] = schDlSlotInfo;
551       cell->schUlSlotInfo[idx] = schUlSlotInfo;
552
553    }
554    cell->firstSsbTransmitted = false;
555    cell->firstSib1Transmitted = false;
556    fillSsbStartSymb(cell);
557
558 #ifdef NR_DRX
559    memset(cell->drxCb, 0, MAX_DRX_SIZE*sizeof(SchDrxCb));
560 #endif   
561    schCb[inst].cells[inst] = cell;
562
563    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
564
565    return ROK;   
566 }
567
568 /**
569  * @brief Fill SIB1 configuration
570  *
571  * @details
572  *
573  *     Function : fillSchSib1Cfg
574  *
575  *     Fill SIB1 configuration
576  *
577  *  @param[in]  uint8_t bandwidth : total available bandwidth
578  *              uint8_t numSlots : total slots per SFN
579  *              SchSib1Cfg *sib1SchCfg : cfg to be filled
580  *              uint16_t pci : physical cell Id
581  *              uint8_t offsetPointA : offset
582  *  @return  void
583  **/
584 uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchConfigSib1 *pdcchCfgSib1,\
585                SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA, uint16_t sib1PduLen)
586 {
587    uint8_t coreset0Idx = 0;
588    uint8_t searchSpace0Idx = 0;
589    //uint8_t ssbMuxPattern = 0;
590    uint8_t numRbs = 0;
591    uint8_t numSymbols = 0;
592    uint8_t offset = 0;
593    uint8_t oValue = 0;
594    //uint8_t numSearchSpacePerSlot = 0;
595    uint8_t mValue = 0;
596    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
597    uint8_t slotIndex = 0;
598    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
599    uint16_t tbSize = 0;
600    uint8_t ssbIdx = 0;
601    PdcchCfg *pdcch;
602    PdschCfg *pdsch;
603    BwpCfg *bwp;
604
605    pdcch = &(sib1SchCfg->sib1PdcchCfg);
606    bwp = &(sib1SchCfg->bwp);
607
608    coreset0Idx     = pdcchCfgSib1->coresetZeroIndex;
609    searchSpace0Idx = pdcchCfgSib1->searchSpaceZeroIndex;
610
611    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
612    //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
613    numRbs        = coresetIdxTable[coreset0Idx][1];
614    numSymbols    = coresetIdxTable[coreset0Idx][2];
615    offset        = coresetIdxTable[coreset0Idx][3];
616
617    /* derive the search space params from table 13-11 spec 38.213 */
618    oValue                = searchSpaceIdxTable[searchSpace0Idx][0];
619    //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
620    mValue                = searchSpaceIdxTable[searchSpace0Idx][2];
621    firstSymbol           = searchSpaceIdxTable[searchSpace0Idx][3];
622
623    /* calculate the n0, need to add the formulae, as of now the value is 0 
624     * Need to add the even and odd values of i during configuration 
625     * [(O . 2^u + i . M )  ] mod numSlotsPerSubframe 
626     * assuming u = 0, i = 0, numSlotsPerSubframe = 10
627     * Also, from this configuration, coreset0 is only on even subframe */
628    slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
629    sib1SchCfg->n0 = slotIndex;
630
631    /* fill BWP */
632    switch(bandwidth)
633    {
634       case BANDWIDTH_20MHZ:
635          {
636             bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
637          }
638          break;
639       case BANDWIDTH_100MHZ:
640          {
641             bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
642          }
643          break;
644       default:
645          DU_LOG("\nERROR  -->  SCH : Bandwidth %d not supported", bandwidth);
646
647    }
648    bwp->freqAlloc.startPrb = 0;
649    bwp->subcarrierSpacing  = 0;         /* 15Khz */
650    bwp->cyclicPrefix       = 0;              /* normal */
651
652    /* fill the PDCCH PDU */
653    pdcch->coresetCfg.coreSetSize = numRbs;
654    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
655    pdcch->coresetCfg.durationSymbols = numSymbols;
656    
657    /* Fill Bitmap for PRBs in coreset */
658    fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), freqDomainResource);
659    memcpy(pdcch->coresetCfg.freqDomainResource, freqDomainResource, FREQ_DOM_RSRC_SIZE);
660
661    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
662    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
663    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
664    pdcch->coresetCfg.coreSetType = 0;
665    pdcch->coresetCfg.shiftIndex = pci;
666    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
667    pdcch->numDlDci = 1;
668    pdcch->dci[0].rnti = SI_RNTI;
669    pdcch->dci[0].scramblingId = pci;
670    pdcch->dci[0].scramblingRnti = 0;
671    pdcch->dci[0].cceIndex = 0;
672    pdcch->dci[0].aggregLevel = 4;
673    pdcch->dci[0].beamPdcchInfo.numPrgs = 1;
674    pdcch->dci[0].beamPdcchInfo.prgSize = 1;
675    pdcch->dci[0].beamPdcchInfo.digBfInterfaces = 0;
676    pdcch->dci[0].beamPdcchInfo.prg[0].pmIdx = 0;
677    pdcch->dci[0].beamPdcchInfo.prg[0].beamIdx[0] = 0;
678    pdcch->dci[0].txPdcchPower.beta_pdcch_1_0= 0;
679    pdcch->dci[0].txPdcchPower.powerControlOffsetSS = 0;
680    /* Storing pdschCfg pointer here. Required to access pdsch config while
681       fillig up pdcch pdu */
682    pdsch = &pdcch->dci[0].pdschCfg; 
683
684    /* fill the PDSCH PDU */
685    uint8_t cwCount = 0;
686    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
687    pdsch->rnti = 0xFFFF; /* SI-RNTI */
688    pdsch->pduIndex = 0;
689    pdsch->numCodewords = 1;
690    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
691    {
692       pdsch->codeword[cwCount].targetCodeRate = 308;
693       pdsch->codeword[cwCount].qamModOrder = 2;
694       pdsch->codeword[cwCount].mcsIndex = DEFAULT_MCS;
695       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
696       pdsch->codeword[cwCount].rvIndex = 0;
697       tbSize = schCalcTbSize(sib1PduLen + TX_PAYLOAD_HDR_LEN);
698       pdsch->codeword[cwCount].tbSize = tbSize;
699    }
700    pdsch->dataScramblingId                   = pci;
701    pdsch->numLayers                          = 1;
702    pdsch->transmissionScheme                 = 0;
703    pdsch->refPoint                           = 0;
704    pdsch->dmrs.dlDmrsSymbPos                 = DL_DMRS_SYMBOL_POS; 
705    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
706    pdsch->dmrs.dlDmrsScramblingId            = pci;
707    pdsch->dmrs.scid                          = 0;
708    pdsch->dmrs.numDmrsCdmGrpsNoData          = 1;
709    pdsch->dmrs.dmrsPorts                     = 0x0001;
710    pdsch->dmrs.mappingType                   = DMRS_MAP_TYPE_A; /* Type-A */
711    pdsch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
712    pdsch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
713
714    pdsch->pdschFreqAlloc.resourceAllocType   = 1; /* RAT type-1 RIV format */
715    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
716    pdsch->pdschFreqAlloc.startPrb  = offsetPointA + SCH_SSB_NUM_PRB;
717    pdsch->pdschFreqAlloc.numPrb    = schCalcNumPrb(tbSize, DEFAULT_MCS, NUM_PDSCH_SYMBOL);
718    pdsch->pdschFreqAlloc.vrbPrbMapping       = 0; /* non-interleaved */
719    pdsch->pdschTimeAlloc.rowIndex            = 1;
720    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
721    pdsch->pdschTimeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
722    pdsch->pdschTimeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
723    pdsch->beamPdschInfo.numPrgs              = 1;
724    pdsch->beamPdschInfo.prgSize              = 1;
725    pdsch->beamPdschInfo.digBfInterfaces      = 0;
726    pdsch->beamPdschInfo.prg[0].pmIdx         = 0;
727    pdsch->beamPdschInfo.prg[0].beamIdx[0]    = 0;
728    pdsch->txPdschPower.powerControlOffset    = 0;
729    pdsch->txPdschPower.powerControlOffsetSS  = 0;
730
731    return ROK;
732 }
733
734 /**
735  * @brief cell config from MAC to SCH.
736  *
737  * @details
738  *
739  *     Function : macSchCellCfgReq
740  *      
741  *      This API is invoked by MAC to send cell config to SCH
742  *           
743  *  @param[in]  Pst            *pst
744  *  @param[in]  SchCellCfg     *schCellCfg
745  *  @return  int
746  *      -# ROK 
747  *      -# RFAILED 
748  **/
749 uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
750 {
751    uint8_t ret = ROK;
752    SchCellCb *cellCb;
753    SchCellCfgCfm schCellCfgCfm;
754    Pst rspPst;
755    Inst inst = pst->dstInst - SCH_INST_START; 
756    uint8_t coreset0Idx = 0;
757    uint8_t numRbs = 0;
758    uint8_t offset = 0;
759    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
760    SchPdschConfig pdschCfg;
761
762    schInitCellCb(inst, schCellCfg);
763    cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
764    cellCb->macInst = pst->srcInst;
765
766    /* derive the SIB1 config parameters */
767    ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
768          &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
769          schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
770    
771    if(ret != ROK)
772    {
773       DU_LOG("\nERROR --> SCH : Failed to fill sib1 configuration");
774       return RFAILED;
775    }
776    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
777    schProcPagingCfg(cellCb);
778
779    /* Fill coreset frequencyDomainResource bitmap */
780    coreset0Idx = cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
781    numRbs = coresetIdxTable[coreset0Idx][1];
782    offset = coresetIdxTable[coreset0Idx][3];
783    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
784                                   (numRbs/6), freqDomainResource);
785    memcpy(cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc,\
786                freqDomainResource,FREQ_DOM_RSRC_SIZE);
787    /* Fill K0 - K1 table for common cfg*/ 
788    BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
789                    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
790    
791    BuildK2InfoTable(cellCb, cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
792    cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->msg3K2InfoTbl, \
793    &cellCb->k2InfoTbl);
794    
795    /*As per Spec 38.211, Sec 6.3.3.2; RootSeq Len(Lra) where Lra=839 or Lra=139,
796     *depending on the PRACH preamble format as given by Tables 6.3.3.1-1 and 6.3.3.1-2.*/
797    if(prachCfgIdxTable[cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.prachCfgIdx][0] <= 3)
798    {
799       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_1;
800    }
801    else
802    {
803       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_2;
804    }
805    /* Initializing global variables */
806    cellCb->actvUeBitMap = 0;
807    cellCb->boIndBitMap = 0;
808
809    cellCb->schHqCfg.maxDlDataHqTx = SCH_MAX_NUM_DL_HQ_TX;
810    cellCb->schHqCfg.maxMsg4HqTx = SCH_MAX_NUM_MSG4_TX;
811    cellCb->schHqCfg.maxUlDataHqTx = SCH_MAX_NUM_UL_HQ_TX;
812    cellCb->maxMsg3Tx = SCH_MAX_NUM_MSG3_TX;
813
814    cellCb->schAlgoType = SCH_FCFS;
815    cellCb->api = &schCb[inst].allApis[cellCb->schAlgoType]; /* For FCFS */
816    cellCb->api->SchCellCfgReq(cellCb);
817    
818    /* Fill and send Cell config confirm */
819    memset(&rspPst, 0, sizeof(Pst));
820    FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
821    rspPst.event = EVENT_SCH_CELL_CFG_CFM;
822
823    schCellCfgCfm.cellId = schCellCfg->cellId; 
824    schCellCfgCfm.rsp = RSP_OK;
825
826    ret = MacMessageRouter(&rspPst, (void *)&schCellCfgCfm);
827    return ret;
828
829 }
830
831 /*******************************************************************
832  *
833  * @brief Fill and send Cell delete response to MAC
834  *
835  * @details
836  *
837  *    Function :  SchSendCellDeleteRspToMac
838  *
839  *    Functionality: Fill and send Cell delete response to MAC
840  *
841  * @params[in] SchCellDelete  *ueDelete, Inst inst, SchMacRsp result
842  * @return ROK     - success
843  *         RFAILED - failure
844  *
845  * ****************************************************************/
846 uint8_t SchSendCellDeleteRspToMac(SchCellDeleteReq  *ueDelete, Inst inst, SchMacRsp result)
847 {
848    Pst rspPst;
849    uint8_t ret=0;
850    
851    SchCellDeleteRsp  delRsp;
852
853    DU_LOG("\nINFO   --> SCH : Filling Cell Delete response");
854    memset(&delRsp, 0, sizeof(SchCellDeleteRsp));
855    delRsp.cellId = ueDelete->cellId;
856    delRsp.rsp = result;
857
858    /* Filling response post */
859    memset(&rspPst, 0, sizeof(Pst));
860    FILL_PST_SCH_TO_MAC(rspPst, inst);
861    rspPst.event = EVENT_CELL_DELETE_RSP_TO_MAC;
862    ret = MacMessageRouter(&rspPst, (void *)&delRsp);
863    if(ret == RFAILED)
864    {
865       DU_LOG("\nERROR  -->  SCH : SchSendCellDeleteRspToMac(): failed to send the Cell Delete response");
866       return ret;
867    }
868    return ret;
869 }
870
871 /*******************************************************************
872  *
873  * @brief Function for cellCb Deletion 
874  *
875  * @details
876  *
877  *    Function : deleteSchCellCb 
878  *
879  *    Functionality: Function for cellCb Deletion 
880  *
881  * @params[in] SchCellDelete  *cellDelete
882  * @return ROK     - success
883  *         RFAILED - failure
884  *
885  * ****************************************************************/
886 void deleteSchCellCb(SchCellCb *cellCb)
887 {
888    uint8_t sliceIdx=0, slotIdx=0, plmnIdx = 0;
889    uint8_t ueIdx = 0;
890    CmLListCp *list=NULL;
891    CmLList *node=NULL, *next=NULL;
892    SchPageInfo *tempNode = NULLP;
893
894    if(cellCb->schDlSlotInfo)
895    {
896       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
897       {
898          list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
899          node = list->first;
900          while(node)
901          {
902             next = node->next;
903             SCH_FREE(node->node, sizeof(FreePrbBlock));
904             deleteNodeFromLList(list, node);
905             node = next;
906          }
907          for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
908          {
909             SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->rarAlloc[ueIdx], sizeof(RarAlloc));
910             SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->dlMsgAlloc[ueIdx], sizeof(DlMsgSchInfo));
911          }
912          SCH_FREE(cellCb->schDlSlotInfo[slotIdx]->ulGrant, sizeof(DciInfo));
913          SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
914       }
915       SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
916    }
917
918    if(cellCb->schUlSlotInfo)
919    {
920       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
921       {
922          list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
923          node = list->first;
924          while(node)
925          {
926             next = node->next;
927             SCH_FREE(node->node, sizeof(FreePrbBlock));
928             deleteNodeFromLList(list, node);
929             node = next;
930          }
931          for(ueIdx = 0; ueIdx< MAX_NUM_UE; ueIdx++)
932          {
933             SCH_FREE(cellCb->schUlSlotInfo[slotIdx]->schPuschInfo[ueIdx], sizeof(SchPuschInfo));
934          }
935          SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));  
936       }
937       SCH_FREE(cellCb->schUlSlotInfo,  cellCb->numSlots * sizeof(SchUlSlotInfo*));
938    }
939
940    for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
941    {
942       if(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai)
943       {
944          for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
945          {
946             SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai));
947          }
948          SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices*sizeof(Snssai*));
949       }
950    }
951
952    for(uint16_t idx =0; idx<MAX_SFN; idx++)
953    {
954       list = &cellCb->pageCb.pageIndInfoRecord[idx];
955       node = list->first;
956       while(node)
957       {
958          next = node->next;
959          if(node->node)
960          {
961             tempNode = (SchPageInfo*)(node->node);
962             SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
963             SCH_FREE(node->node,  sizeof(SchPageInfo));
964          }
965          deleteNodeFromLList(list, node);
966          node = next;
967       }
968    }
969
970    cellCb->api->SchCellDeleteReq(cellCb);
971
972    memset(cellCb, 0, sizeof(SchCellCb));
973 }
974
975 /*******************************************************************
976  *
977  * @brief Function for cell Delete request from MAC to SCH
978  *
979  * @details
980  *
981  *    Function : SchProcCellDeleteReq
982  *
983  *    Functionality: Function for cell Delete request from MAC to SCH
984  *
985  * @params[in] Pst *pst, SchCellDelete  *cellDelete
986  * @return ROK     - success
987  *         RFAILED - failure
988  *
989  * ****************************************************************/
990 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq  *cellDelete)
991 {
992    uint8_t   cellIdx=0, ret = RFAILED;
993    Inst      inst = pst->dstInst - SCH_INST_START;
994    SchMacRsp result= RSP_OK;
995    
996    if(!cellDelete)
997    {
998       DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): Ue Delete request failed");
999    }
1000    else
1001    {
1002       GET_CELL_IDX(cellDelete->cellId, cellIdx);
1003       if(schCb[inst].cells[cellIdx] == NULLP)
1004       { 
1005          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
1006          result = RSP_NOK;
1007       }
1008       else
1009       {
1010          if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1011          {
1012             deleteSchCellCb(schCb[inst].cells[cellIdx]);
1013             result = RSP_OK;
1014             ret = ROK;
1015             SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1016             DU_LOG("\nINFO   -->  SCH : Sending Cell Delete response to MAC");
1017          }
1018          else
1019          {
1020             DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1021             result = RSP_NOK;
1022          }
1023       }
1024
1025       if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1026       {
1027          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1028          ret =  RFAILED;
1029       }
1030    }
1031    return ret;   
1032 }
1033
1034 /*******************************************************************
1035  *
1036  * @brief Processes DL RLC BO info from MAC
1037  *
1038  * @details
1039  *
1040  *    Function : SchProcDlRlcBoInfo
1041  *
1042  *    Functionality:
1043  *       Processes DL RLC BO info from MAC
1044  *
1045  * @params[in] 
1046  * @return ROK     - success
1047  *         RFAILED - failure
1048  *
1049  * ****************************************************************/
1050 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1051 {
1052    uint8_t  lcId = 0;
1053    uint16_t ueId = 0;
1054    bool isLcIdValid = false;
1055    SchUeCb *ueCb = NULLP;
1056    SchCellCb *cell = NULLP;
1057    Inst  inst = pst->dstInst-SCH_INST_START;   
1058
1059    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1060    cell = schCb[inst].cells[inst];
1061
1062    if(cell == NULLP)
1063    {
1064       DU_LOG("\nERROR  -->  SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1065       return RFAILED;
1066    }
1067
1068    GET_UE_ID(dlBoInfo->crnti, ueId);
1069    ueCb = &cell->ueCb[ueId-1];
1070    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1071    {
1072       DU_LOG("INFO  --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1073       return ROK;
1074    }
1075    
1076    lcId  = dlBoInfo->lcId;
1077    CHECK_LCID(lcId, isLcIdValid);
1078    if(isLcIdValid == FALSE)
1079    {
1080       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1081       return RFAILED;
1082    }
1083
1084    /*Expected when theres a case of Retransmission Failure or Resetablishment
1085     *By Zero BO, the RLC is informing that previous data can be cleared out
1086     *Thus clearing out the LC from the Lc priority list*/
1087    if(dlBoInfo->dataVolume == 0)
1088    {
1089       /* TODO : Check the LC is Dedicated or default and accordingly LCList
1090        * will be used*/
1091       return ROK;
1092    }
1093
1094    if(lcId == SRB0_LCID)
1095    {
1096       cell->raCb[ueId -1].msg4recvd = true;
1097       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;      
1098    }
1099    else
1100    {
1101       /* TODO : These part of changes will be corrected during DL scheduling as
1102        * per K0 - K1 -K2 */
1103       SET_ONE_BIT(ueId, cell->boIndBitMap);
1104       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1105       {
1106          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1107       }
1108       else
1109       {
1110          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1111          return RFAILED;
1112       }
1113    }
1114    /* Adding UE Id to list of pending UEs to be scheduled */
1115    cell->api->SchDlRlcBoInfo(cell, ueId);
1116    return ROK;
1117 }
1118
1119 /*******************************************************************
1120  *
1121  * @brief Processes BSR indiation from MAC
1122  *
1123  * @details
1124  *
1125  *    Function : SchProcBsr
1126  *
1127  *    Functionality:
1128  *       Processes DL BSR from MAC
1129  *
1130  * @params[in]    Pst pst
1131  *                UlBufferStatusRptInd bsrInd
1132  * @return ROK     - success
1133  *         RFAILED - failure
1134  *
1135  * ****************************************************************/
1136 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1137 {
1138    Inst           schInst       = pst->dstInst-SCH_INST_START;
1139    SchCellCb      *cellCb       = NULLP;
1140    SchUeCb        *ueCb         = NULLP;
1141    uint8_t        lcgIdx = 0;
1142
1143    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1144    if(bsrInd == NULLP)
1145    {
1146       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1147       return RFAILED;
1148    }
1149    cellCb = schCb[schInst].cells[schInst];
1150    if(cellCb == NULLP)
1151    {
1152       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1153       return RFAILED;
1154    }
1155    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1156
1157    if(ueCb == NULLP)
1158    {
1159       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1160       return RFAILED;
1161    }
1162
1163    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1164    {
1165       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1166       return ROK;
1167    }
1168    
1169    ueCb->bsrRcvd = true;
1170    /* store dataVolume per lcg in uecb */
1171    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1172    {
1173       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1174       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1175    }
1176    
1177    /* Adding UE Id to list of pending UEs to be scheduled */
1178    cellCb->api->SchBsr(cellCb, ueCb->ueId);
1179    return ROK;
1180 }
1181
1182 /*******************************************************************
1183  *
1184  * @brief Processes SR UCI indication from MAC 
1185  *
1186  * @details
1187  *
1188  *    Function : SchProcSrUciInd
1189  *
1190  *    Functionality:
1191  *      Processes SR UCI indication from MAC
1192  *
1193  * @params[in] Post structure
1194  *             UCI Indication
1195  * @return ROK     - success
1196  *         RFAILED - failure
1197  *
1198  * ****************************************************************/
1199 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1200 {
1201    Inst  inst = pst->dstInst-SCH_INST_START;
1202
1203    SchUeCb   *ueCb; 
1204    SchCellCb *cellCb = schCb[inst].cells[inst];
1205
1206    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1207
1208    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1209    
1210    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1211    {
1212       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1213       return ROK;  
1214    }
1215    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1216    {
1217       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1218       return ROK;
1219    }
1220    if(uciInd->numSrBits)
1221    {
1222       ueCb->srRcvd = true;      
1223       /* Adding UE Id to list of pending UEs to be scheduled */
1224       cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1225    }
1226    return ROK;
1227 }
1228
1229 /*******************************************************************
1230  *
1231  * @brief Processes DL HARQ indication from MAC 
1232  *
1233  * @details
1234  *
1235  *    Function : SchProcDlHarqInd
1236  *
1237  *    Functionality:
1238  *      Processes DL HARQ indication from MAC
1239  *
1240  * @params[in] Post structure
1241  *             DL HARQ Indication
1242  * @return ROK     - success
1243  *         RFAILED - failure
1244  *
1245  * ****************************************************************/
1246 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1247 {
1248    Inst  inst = pst->dstInst-SCH_INST_START;
1249    SchUeCb   *ueCb;
1250    SchCellCb *cellCb = schCb[inst].cells[inst];
1251
1252    DU_LOG("\nDEBUG  -->  SCH : Received HARQ");
1253
1254    ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1255
1256    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1257    {
1258       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", dlHarqInd->crnti);
1259       return ROK;
1260    }
1261
1262    schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1263
1264    return ROK;
1265 }
1266
1267 /*******************************************************************
1268  *
1269  * @brief Allocates requested PRBs for DL
1270  *
1271  * @details
1272  *
1273  *    Function : allocatePrbDl
1274  *
1275  *    Functionality:
1276  *      Allocates requested PRBs in DL
1277  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1278  *
1279  * @params[in] prbAlloc table
1280  *             Start symbol
1281  *             Number of symbols
1282  *             Start PRB
1283  *             Number of PRBs
1284  *
1285  * @return ROK     - success
1286  *         RFAILED - failure
1287  *
1288  * ****************************************************************/
1289 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1290    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1291 {
1292    uint8_t        symbol = 0;
1293    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1294    FreePrbBlock   *freePrbBlock = NULLP;
1295    CmLList        *freePrbNode = NULLP;
1296    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1297    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1298    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1299
1300    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1301     * Search for an appropriate location in PRB grid and allocate requested resources */
1302    if(*startPrb == MAX_NUM_RB)
1303    {
1304       /* Check if SSB/SIB1 is also scheduled in this slot  */
1305       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1306       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1307
1308       if(ssbOccasion && sib1Occasion)
1309       {
1310          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1311          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1312       }
1313       else if(ssbOccasion)
1314       {
1315          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1316          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1317       }
1318       else if(sib1Occasion)
1319       {
1320          broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1321          broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1322       }
1323
1324       /* Iterate through all free PRB blocks */
1325       freePrbNode = prbAlloc->freePrbBlockList.first; 
1326       while(freePrbNode)
1327       {
1328          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1329
1330          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1331           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1332          if((ssbOccasion || sib1Occasion) && 
1333             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1334             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1335          {
1336             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1337             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1338             {
1339                /* If sufficient free PRBs are available above bradcast message then,
1340                 * endPrb = freePrbBlock->endPrb
1341                 * startPrb = endPrb - numPrb +1;
1342                 */
1343                *startPrb = freePrbBlock->endPrb - numPrb +1;
1344                break;
1345             }
1346             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1347             {
1348                /* If free PRBs are available below broadcast message then,
1349                 * endPrb = broadcastPrbStart - 1
1350                 * startPrb = endPrb - numPrb +1
1351                 */
1352                *startPrb = broadcastPrbStart - numPrb; 
1353                break;
1354             }
1355             else
1356             {
1357                freePrbNode = freePrbNode->next;
1358                continue;
1359             }
1360          }
1361          else
1362          {
1363             /* Check if requested number of blocks can be allocated from the current block */ 
1364             if (freePrbBlock->numFreePrb < numPrb)
1365             {
1366                freePrbNode = freePrbNode->next;
1367                continue;
1368             }
1369             *startPrb = freePrbBlock->endPrb - numPrb +1;
1370             break;  
1371          }
1372       }
1373
1374       /* If no free block can be used to allocated request number of RBs */
1375       if(*startPrb == MAX_NUM_RB)
1376          return RFAILED;
1377    }
1378
1379    /* If startPrb is known already, check if requested PRBs are available for allocation */
1380    else
1381    {
1382       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1383       if(!freePrbNode)
1384       {
1385          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1386          return RFAILED;
1387       }
1388    }
1389
1390    /* Update bitmap to allocate PRBs */
1391    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1392    {
1393       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1394       {
1395          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1396          return RFAILED;
1397       }
1398    }
1399    
1400    /* Update statistics of PRB usage if stats calculation is enabled */
1401    if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1402       prbAlloc->numPrbAlloc += numPrb;
1403
1404    /* Update the remaining number for free PRBs */
1405    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1406
1407    return ROK;
1408 }
1409
1410 /*******************************************************************
1411  *
1412  * @brief Allocates requested PRBs for UL
1413  *
1414  * @details
1415  *
1416  *    Function : allocatePrbUl
1417  *
1418  *    Functionality:
1419  *      Allocates requested PRBs in UL
1420  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1421  *
1422  * @params[in] prbAlloc table
1423  *             Start symbol
1424  *             Number of symbols
1425  *             Start PRB
1426  *             Number of PRBs
1427  *
1428  * @return ROK     - success
1429  *         RFAILED - failure
1430  *
1431  * ****************************************************************/
1432 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1433    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1434 {
1435    uint8_t        symbol = 0;
1436    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1437    bool           isPrachOccasion;
1438    FreePrbBlock   *freePrbBlock = NULLP;
1439    CmLList        *freePrbNode = NULLP;
1440    SchPrbAlloc    *prbAlloc = NULLP;
1441
1442    if(cell == NULLP)
1443    {
1444       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1445       return RFAILED;
1446    }
1447    
1448    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1449    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1450     * Search for an appropriate location in PRB grid and allocate requested resources */
1451    if(*startPrb == MAX_NUM_RB)
1452    {
1453       /* Check if PRACH is also scheduled in this slot */
1454       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1455       if(isPrachOccasion)
1456       {
1457          prachStartPrb =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1458          prachNumPrb = schCalcPrachNumRb(cell);
1459          prachEndPrb = prachStartPrb + prachNumPrb -1;
1460       }
1461
1462       /* Iterate through all free PRB blocks */
1463       freePrbNode = prbAlloc->freePrbBlockList.first; 
1464       while(freePrbNode)
1465       {
1466          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1467
1468          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1469           * PRBs required for PRACH cannot be allocated to any other message */
1470          if((isPrachOccasion) &&
1471             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1472             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1473          {
1474             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1475             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1476             {
1477                /* If sufficient free PRBs are available above PRACH message then,
1478                 * endPrb = freePrbBlock->endPrb
1479                 * startPrb = endPrb - numPrb +1;
1480                 */
1481                *startPrb = freePrbBlock->endPrb - numPrb +1;
1482                break;
1483             }
1484             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1485             {
1486                /* If free PRBs are available below PRACH message then,
1487                 * endPrb = prachStartPrb - 1
1488                 * startPrb = endPrb - numPrb +1
1489                 */
1490                *startPrb = prachStartPrb - numPrb; 
1491                break;
1492             }
1493             else
1494             {
1495                freePrbNode = freePrbNode->next;
1496                continue;
1497             } 
1498          }
1499          else
1500          {
1501             /* Check if requested number of PRBs can be allocated from currect block */
1502             if(freePrbBlock->numFreePrb < numPrb)
1503             {
1504                freePrbNode = freePrbNode->next;
1505                continue;
1506             }
1507             *startPrb = freePrbBlock->endPrb - numPrb +1;
1508             break;
1509          }
1510       }
1511
1512       /* If no free block can be used to allocated requested number of RBs */
1513       if(*startPrb == MAX_NUM_RB)
1514          return RFAILED;
1515    }
1516    else
1517    {
1518       /* If startPrb is known already, check if requested PRBs are available for allocation */
1519       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1520       if(!freePrbNode)
1521       {
1522          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1523          return RFAILED;
1524       }
1525    }
1526
1527    /* Update bitmap to allocate PRBs */
1528    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1529    {
1530       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1531       {
1532          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1533          return RFAILED;
1534       }
1535    }
1536
1537    /* Update statistics of PRB usage if stats calculation is enabled */
1538    if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1539       prbAlloc->numPrbAlloc += numPrb;
1540
1541    /* Update the remaining number for free PRBs */
1542    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1543
1544    return ROK;
1545 }
1546
1547 /*******************************************************************************
1548  *
1549  * @brief Try to find Best Free Block with Max Num PRB 
1550  *
1551  * @details
1552  *
1553  *    Function : searchLargestFreeBlock
1554  *
1555  *    Functionality:
1556  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1557  *
1558  * @params[in] I/P > prbAlloc table (FreeBlock list)
1559  *             I/P > Slot timing Info
1560  *             O/P > Start PRB
1561  *             I/P > Direction (UL/DL)
1562  *       
1563  *
1564  * @return Max Number of Free PRB 
1565  *         If 0, then no Suitable Free Block
1566  *
1567  * ********************************************************************************/
1568
1569 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1570 {
1571    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1572    FreePrbBlock   *freePrbBlock = NULLP;
1573    CmLList        *freePrbNode = NULLP;
1574    SchPrbAlloc    *prbAlloc = NULLP;
1575    bool           checkOccasion = FALSE;
1576
1577    *startPrb = 0; /*Initialize the StartPRB to zero*/
1578
1579    /*Based on Direction, Reserved Messsages will differi.e.
1580     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1581     * and reserved before allocation for dedicated DL/UL msg*/
1582    if(dir == DIR_DL)
1583    {
1584       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1585       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1586
1587       prbAlloc = &schDlSlotInfo->prbAlloc;
1588
1589       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1590       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1591
1592       checkOccasion = TRUE;
1593       if(ssbOccasion && sib1Occasion)
1594       {
1595          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1596          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1597                           cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1598       }
1599       else if(ssbOccasion)
1600       {
1601          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1602          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1603       }
1604       else if(sib1Occasion)
1605       {
1606          reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1607          reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1608       }
1609       else
1610       {
1611          checkOccasion = FALSE;  
1612       }
1613    }
1614    else if(dir == DIR_UL)
1615    {
1616       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1617
1618       /* Check if PRACH is also scheduled in this slot */
1619       checkOccasion = schCheckPrachOcc(cell, slotTime);
1620       if(checkOccasion)
1621       {
1622          reservedPrbStart =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1623          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1624       }
1625    }
1626    else
1627    {
1628       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1629       return (maxFreePRB);
1630    }
1631
1632    freePrbNode = prbAlloc->freePrbBlockList.first; 
1633    while(freePrbNode)
1634    {
1635       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1636
1637       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1638        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1639       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1640       {
1641          //skip this block
1642          freePrbNode = freePrbNode->next;
1643          continue;
1644       }
1645
1646       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1647        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1648       if(checkOccasion && 
1649             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1650             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1651       {
1652
1653          /* Implmentation is done such that highest-numbered free-RB is Checked first
1654             and freePRB in this block is greater than Max till now */
1655          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1656          {
1657             /* If sufficient free PRBs are available above reserved message*/
1658             *startPrb = reservedPrbEnd + 1;
1659             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1660          }
1661          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1662          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1663          {
1664             /* If free PRBs are available below reserved message*/
1665             *startPrb = freePrbBlock->startPrb;
1666             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1667          }
1668       }
1669       else  //Best Block
1670       {
1671          if(maxFreePRB < freePrbBlock->numFreePrb)
1672          {
1673             *startPrb = freePrbBlock->startPrb;
1674             maxFreePRB = freePrbBlock->numFreePrb;
1675          }
1676
1677       }
1678       freePrbNode = freePrbNode->next;
1679    }  
1680    return(maxFreePRB);
1681 }
1682
1683 /*******************************************************************************
1684  *
1685  * @brief This function is used to send Slice Cfg rsp to MAC
1686  *
1687  * @details
1688  *
1689  *    Function : SchSendSliceCfgRspToMac
1690  *
1691  *    Functionality:
1692  *     function is used to send Slice Cfg rsp to MAC
1693  *
1694  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1695  *
1696  * @return- void
1697  *
1698  * ********************************************************************************/
1699 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1700 {
1701    Pst rspPst;
1702    
1703    memset(&rspPst, 0, sizeof(Pst));
1704    FILL_PST_SCH_TO_MAC(rspPst, inst);
1705    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1706    
1707    MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1708
1709 }
1710
1711 /*******************************************************************************
1712  *
1713  * @brief This function is used to store or modify the slice configuration Sch DB
1714  *
1715  * @details
1716  *
1717  *    Function : addOrModifySliceCfgInSchDb 
1718  *
1719  *    Functionality:
1720  *     function is used to store or modify the slice configuration Sch DB
1721  *
1722  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1723  * SchSliceCfgRsp cfgRsp, uint8_t count
1724  *
1725  * @return
1726  *        ROK - Success
1727  *        RFAILED - Failure
1728  *
1729  * ********************************************************************************/
1730 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1731 {
1732    SchRrmPolicyOfSlice *sliceToStore;
1733
1734    SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1735    if(sliceToStore)
1736    {
1737       memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));  
1738       memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));  
1739       addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1740    }
1741    else
1742    {
1743       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1744       return RFAILED;
1745    }
1746    return ROK;
1747 }
1748
1749 /*******************************************************************************
1750  *
1751  * @brief fill slice configuration response
1752  *
1753  * @details
1754  *
1755  *    Function : fillSliceCfgRsp
1756  *
1757  *    Functionality:
1758  *     fill slice configuration response
1759  *
1760  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1761  *
1762  * @return
1763  *        ROK - Success
1764  *        RFAILED - Failure
1765  *
1766  * ********************************************************************************/
1767 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1768 {
1769    SchMacRsp sliceFound;
1770    uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1771    SchSliceCfgRsp schSliceCfgRsp;
1772
1773    for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1774    {
1775       sliceFound = RSP_NOK;
1776       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1777       for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1778       {
1779          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.numSupportedSlices; sliceIdx++)
1780          {
1781             /* If we find the SliceCfgReq's SNSSAI in CellCb's SNSSAI DB, we mark this slice as configured and add it to Sch's DB. */ 
1782             if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].suppSliceList.snssai[sliceIdx], sizeof(Snssai)))
1783             {
1784                if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1785                {
1786                   sliceFound = RSP_OK;
1787                   schSliceCfgRsp.cause = SUCCESSFUL;
1788                }
1789                else
1790                {
1791                   DU_LOG("\nERROR  --> SCH : Failed to store slice configuration in SchDb");
1792                   schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1793                   ret = RFAILED;
1794                }
1795                plmnIdx = MAX_PLMN;
1796                break;
1797             }
1798          }
1799       }
1800       
1801       if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1802          schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1803       
1804       schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1805       schSliceCfgRsp.rsp    = sliceFound;
1806       SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1807    }
1808    return ret;
1809 }
1810
1811 /*******************************************************************************
1812  *
1813  * @brief This function is used to free the slice cfg and re cfg request pointer
1814  *
1815  * @details
1816  *
1817  *    Function : freeSchSliceCfgReq 
1818  *
1819  *    Functionality:
1820  *     function is used to free the slice cfg and re cfg request pointer
1821  *
1822  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1823  *
1824  * @return
1825  *        ROK - Success
1826  *        RFAILED - Failure
1827  * ********************************************************************************/
1828 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1829 {
1830    uint8_t cfgIdx = 0;
1831    
1832    if(sliceCfgReq)
1833    {
1834       if(sliceCfgReq->numOfConfiguredSlice)
1835       {
1836          for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1837          {
1838             if(sliceCfgReq->listOfSlices[cfgIdx])
1839             {
1840                SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1841             }
1842          }
1843          SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1844       }
1845       SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1846    }
1847 }
1848 /*******************************************************************************
1849  *
1850  * @brief This function is used to store the slice configuration Sch DB
1851  *
1852  * @details
1853  *
1854  *    Function : SchProcSliceCfgReq 
1855  *
1856  *    Functionality:
1857  *     function is used to store the slice configuration Sch DB
1858  *
1859  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1860  *
1861  * @return
1862  *        ROK - Success
1863  *        RFAILED - Failure
1864  *
1865  * ********************************************************************************/
1866 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1867 {
1868    uint8_t ret = ROK;
1869    Inst   inst = pst->dstInst - SCH_INST_START;
1870
1871    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1872    if(schSliceCfgReq)
1873    {
1874       if(schSliceCfgReq->listOfSlices)
1875       {
1876          /* filling the slice configuration response of each slice */
1877          if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1878          {
1879             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1880             ret = RFAILED;
1881          }
1882          freeSchSliceCfgReq(schSliceCfgReq);
1883       }
1884    }
1885    else
1886    {
1887       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1888       ret = RFAILED;
1889    }
1890    return ret;
1891 }
1892
1893 /*******************************************************************************
1894  *
1895  * @brief This function is used to send Slice re Cfg rsp to MAC
1896  *
1897  * @details
1898  *
1899  *    Function : SchSendSliceRecfgRspToMac
1900  *
1901  *    Functionality:
1902  *     function is used to send Slice re Cfg rsp to MAC
1903  *
1904  * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1905  *
1906  * @return- void
1907  *
1908  * ********************************************************************************/
1909 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1910 {
1911    Pst rspPst;
1912    
1913    memset(&rspPst, 0, sizeof(Pst));
1914    FILL_PST_SCH_TO_MAC(rspPst, inst);
1915    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1916    
1917    MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1918 }
1919
1920 /*******************************************************************************
1921  *
1922  * @brief fill slice configuration response
1923  *
1924  * @details
1925  *
1926  *    Function : fillSliceRecfgRsp
1927  *
1928  *    Functionality: fill slice reconfiguration response
1929  *
1930  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1931  *
1932  * @return
1933  *        ROK - Success
1934  *        RFAILED - Failure
1935  *
1936  * ********************************************************************************/
1937
1938 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1939 {
1940    SchMacRsp sliceFound;
1941    uint8_t cfgIdx = 0;
1942    SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1943    SchSliceRecfgRsp schSliceRecfgRsp;
1944
1945    for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1946    {
1947       sliceFound = RSP_NOK;
1948       /* Here comparing the slice recfg request with the StoredSliceCfg */
1949       CmLList *sliceCfg = storedSliceCfg->first;
1950
1951       while(sliceCfg)
1952       {
1953          rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1954          
1955          if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1956          {
1957             memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1958             sliceFound = RSP_OK;
1959             break;
1960          }
1961          sliceCfg = sliceCfg->next;
1962       }
1963
1964       schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1965       schSliceRecfgRsp.rsp    = sliceFound;
1966       if(schSliceRecfgRsp.rsp == RSP_OK)
1967          schSliceRecfgRsp.cause = SUCCESSFUL;
1968       else
1969          schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1970       SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1971    }
1972    return ROK;
1973 }
1974 /*******************************************************************************
1975  *
1976  * @brief This function is used to store the slice reconfiguration Sch DB
1977  *
1978  * @details
1979  *
1980  *    Function : SchProcSliceRecfgReq 
1981  *
1982  *    Functionality:
1983  *     function is used to store the slice re configuration Sch DB
1984  *
1985  * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1986  *
1987  * @return
1988  *        ROK - Success
1989  *        RFAILED - Failure
1990  *
1991  * ********************************************************************************/
1992 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1993 {
1994    uint8_t ret = ROK;
1995    Inst   inst = pst->dstInst - SCH_INST_START;
1996
1997    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1998    if(schSliceRecfgReq)
1999    {
2000       if(schSliceRecfgReq->listOfSlices)
2001       {
2002          /* filling the slice configuration response of each slice */
2003          if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
2004          {
2005             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
2006             ret = RFAILED;
2007          }
2008          freeSchSliceCfgReq(schSliceRecfgReq);
2009       }
2010    }
2011    else
2012    {
2013       DU_LOG("\nERROR  -->  SCH : Received SchSliceRecfgReq is NULL");
2014
2015    }
2016    return ret;
2017 }
2018
2019 /****************************************************************************
2020  *
2021  * @brief Stores the Paging Configuration from DU APP in CellCb 
2022  *
2023  * @details
2024  *
2025  *    Function : schProcPagingParam
2026  *
2027  *    Functionality:
2028  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2029  *          Paging Ocassion is not present.
2030  *
2031  *          As per 38.304 Sec 7.1,
2032  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2033  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2034  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2035  *          parameter; otherwise, it is equal to i_s * S."
2036  *          "S = number of actual transmitted SSBs determined according 
2037  *              to ssb-PositionsInBurst in SIB1"
2038  *
2039  * @params[in] SchCellCb *cell 
2040  *       
2041  * @return void 
2042  *        
2043  *************************************************************************/
2044 void schProcPagingCfg(SchCellCb *cell)
2045 {
2046    SchPcchCfg *pageCfgRcvd = NULL;
2047    uint8_t i_sIdx = 0;
2048
2049    pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2050
2051    if(pageCfgRcvd->poPresent == TRUE)
2052    {
2053       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2054       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2055       {
2056          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2057          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2058          {
2059             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2060          }
2061
2062          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2063
2064       }
2065    }
2066    else
2067    {
2068       schCfgPdcchMonOccOfPO(cell);                  
2069    }
2070 }
2071
2072 /****************************************************************************
2073  *
2074  * @brief Calculate PO if not present in Configuration 
2075  *
2076  * @details
2077  *
2078  *    Function : schCfgPdcchMonOccOfPO
2079  *
2080  *    Functionality: In this function, PO are calculated i_s * S because
2081  *    FirstPDCCHMonitoring_ForPO is not present.
2082  *
2083  * @params[in] SchCellCb *cellCb
2084  *       
2085  * @return void 
2086  *        
2087  *************************************************************************/
2088 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2089 {
2090    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2091    uint8_t         nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2092    uint8_t         totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2093    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2094
2095    /*Starting with First Sfn and slot*/
2096    tmpTimingInfo.sfn = 0;
2097    tmpTimingInfo.slot = 0;
2098
2099    pdcchTime = tmpTimingInfo;
2100
2101    while(i_sIdx < nsValue)
2102    {
2103       /*Increment frame Offset if PO falls on next SFN*/
2104       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2105       {
2106          frameOffSet++;
2107       }
2108       pdcchTime = tmpTimingInfo;
2109       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2110
2111       if (i_sIdx == 0)
2112       {
2113          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2114          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2115          i_sIdx++;
2116       }
2117       else
2118       {
2119          cnt++;
2120          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2121          {
2122             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2123             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2124             cnt = 0;
2125             i_sIdx++;
2126          }
2127       }
2128    }
2129 }
2130
2131 /****************************************************************************
2132  *
2133  * @brief Storing the paging information in SCH database 
2134  *
2135  * @details
2136  *
2137  *    Function : schAddPagingIndtoList
2138  *
2139  *    Functionality: Storing the paging information in SCH database
2140  *
2141  * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2142  *       
2143  * @return ROK - sucess
2144  *         RFAILED - failure
2145  *        
2146  *************************************************************************/
2147 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2148 {
2149    CmLList  *firstNodeOfList = NULLP;
2150    CmLList  *currentNodeInfo = NULLP;
2151    SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2152    
2153    recvdNode = (SchPageInfo*) pageIndInfo;
2154    CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2155    
2156    SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2157    if(!currentNodeInfo)
2158    {  
2159       DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2160       return RFAILED;
2161    }
2162    
2163    currentNodeInfo->node = (PTR)pageIndInfo;
2164    while(firstNodeOfList)
2165    {
2166       tempNode = (SchPageInfo*)(firstNodeOfList->node);
2167       if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2168       {
2169          cmLListInsCrnt(storedPageList, currentNodeInfo);
2170          break;
2171       }
2172       else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2173       {
2174          DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2175          return RFAILED;
2176       }
2177       else
2178       {
2179          CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2180       }
2181    } 
2182    
2183    if(!firstNodeOfList)
2184    {
2185       cmLListAdd2Tail(storedPageList, currentNodeInfo);
2186    }
2187    DU_LOG("\nDEBUG   -->  SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2188               recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2189    return ROK;
2190 }
2191
2192 /****************************************************************************
2193  *
2194  * @brief Process paging indication at  SCH recevied form MAC 
2195  *
2196  * @details
2197  *
2198  *    Function : SchProcPagingInd
2199  *
2200  *    Functionality: Process paging indication at SCH recevied form MAC 
2201  *
2202  * @params[in] Pst *pst,  SchPageInd *pageInd 
2203  *       
2204  * @return void 
2205  *        
2206  *************************************************************************/
2207 uint8_t SchProcPagingInd(Pst *pst,  SchPageInd *pageInd)
2208 {
2209    uint8_t ret = RFAILED;
2210    uint16_t cellIdx = 0;
2211    Inst  inst = pst->dstInst - SCH_INST_START;
2212    SchCellCb *cellCb = NULLP;
2213    SchPageInfo *pageInfo = NULLP;
2214
2215    if(pageInd)
2216    {
2217       DU_LOG("\nDEBUG   -->  SCH : Received paging indication from MAC for cellId[%d]",\
2218                   pageInd->cellId);
2219
2220       /* Fetch Cell CB */
2221       for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2222       {
2223          if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2224          {
2225             cellCb = schCb[inst].cells[cellIdx];
2226             break;
2227          }
2228       }
2229       if(cellCb)
2230       {
2231          if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2232          {
2233             DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2234          }
2235          else
2236          {
2237             SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2238             if(pageInfo)
2239             {
2240                pageInfo->pf = pageInd->pf; 
2241                pageInfo->i_s = pageInd->i_s;
2242                pageInfo->pageTxTime.cellId = pageInd->cellId;
2243                pageInfo->pageTxTime.sfn = (pageInd->pf +  cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2244                pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2245                pageInfo->mcs = DEFAULT_MCS;
2246                pageInfo->msgLen =  pageInd->pduLen;
2247                SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2248                if(!pageInfo->pagePdu)
2249                {
2250                   DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2251                }
2252                else
2253                {
2254                   memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2255                   ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2256                   if(ret != ROK)
2257                   {
2258                      DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to store paging record");
2259                   }
2260                }
2261             }
2262             else
2263             {
2264                DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2265             }
2266          }
2267       }
2268       else
2269       {
2270          DU_LOG("\nERROR  -->  SCH : Cell ID [%d] not found", pageInd->cellId);
2271       }
2272       SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2273       SCH_FREE(pageInd, sizeof(SchPageInd));
2274    }
2275    else
2276    {
2277       DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Received null pointer");
2278    }
2279    return ret;
2280 }
2281
2282 \f
2283 /***********************************************************
2284  *
2285  *     Func : SchFillCfmPst 
2286  *        
2287  *
2288  *     Desc : Fills the Confirmation Post Structure cfmPst using the reqPst 
2289  *            and the cfm->hdr.response.
2290  *            
2291  *
2292  *     Ret  : Void
2293  *
2294  *     Notes: 
2295  *
2296  *     File : rg_sch_lmm.c 
2297  *
2298  **********************************************************/
2299 Void SchFillCfmPst
2300 (
2301 Pst           *reqPst,
2302 Pst           *cfmPst,
2303 RgMngmt       *cfm
2304 )
2305 {
2306    Inst inst;
2307
2308    inst = (reqPst->dstInst - SCH_INST_START);
2309
2310    cfmPst->srcEnt    = ENTMAC;
2311    cfmPst->srcInst   = (Inst) 1;
2312    cfmPst->srcProcId = schCb[inst].schInit.procId;
2313    cfmPst->dstEnt    = ENTMAC;
2314    cfmPst->dstInst   = (Inst) 0;
2315    cfmPst->dstProcId = reqPst->srcProcId;
2316
2317    cfmPst->selector  = cfm->hdr.response.selector;
2318    cfmPst->region    = cfm->hdr.response.mem.region;
2319    cfmPst->pool      = cfm->hdr.response.mem.pool;
2320
2321    return;
2322 }
2323
2324 /*******************************************************************
2325  *
2326  * @brief Processes DL CQI ind from MAC
2327  *
2328  * @details
2329  *
2330  *    Function : SchProcDlCqiInd
2331  *
2332  *    Functionality:
2333  *       Processes DL CQI ind from MAC
2334  *
2335  * @params[in] 
2336  * @return ROK     - success
2337  *         RFAILED - failure
2338  *
2339  * ****************************************************************/
2340 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2341 {
2342    uint8_t  ret = ROK;
2343    uint16_t ueId = 0, cellIdx = 0;
2344    SchUeCb *ueCb = NULLP;
2345    SchCellCb *cell = NULLP;
2346    Inst  inst = pst->dstInst-SCH_INST_START;   
2347
2348    if(!dlCqiInd)
2349    {
2350       DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): CQI Ind is empty");
2351       ret = RFAILED;
2352    }
2353    else
2354    {
2355       GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2356       cell = schCb[inst].cells[cellIdx];
2357       if(cell == NULLP)
2358       { 
2359          DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2360          ret = RFAILED;
2361       }
2362       else
2363       {
2364          if(cell->cellId == dlCqiInd->cellId)
2365          {
2366             GET_UE_ID(dlCqiInd->crnti, ueId);
2367             ueCb = &cell->ueCb[ueId-1];
2368             if(ueCb->crnti != dlCqiInd->crnti)
2369             {
2370                DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2371                ret = RFAILED;
2372             }
2373             else
2374             {
2375                /*TODO: complete the processing of DL CQI Ind*/ 
2376             }
2377          }
2378          else
2379          {
2380             DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2381                     dlCqiInd->cellId, cell->cellId);
2382             ret = RFAILED;
2383          }
2384       }
2385    }
2386    return ret;
2387 }
2388
2389 /*******************************************************************
2390  *
2391  * @brief Processes UL CQI ind from MAC
2392  *
2393  * @details
2394  *
2395  *    Function : SchProcUlCqiInd
2396  *
2397  *    Functionality:
2398  *       Processes UL CQI ind from MAC
2399  *
2400  * @params[in] 
2401  * @return ROK     - success
2402  *         RFAILED - failure
2403  *
2404  * ****************************************************************/
2405 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2406 {
2407    uint8_t  ret = ROK;
2408    uint16_t ueId = 0, cellIdx = 0;
2409    SchUeCb *ueCb = NULLP;
2410    SchCellCb *cell = NULLP;
2411    Inst  inst = pst->dstInst-SCH_INST_START;   
2412
2413    if(!ulCqiInd)
2414    {
2415       DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): CQI Ind is empty");
2416       ret = RFAILED;
2417    }
2418    else
2419    {
2420       GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2421       cell = schCb[inst].cells[cellIdx];
2422       if(cell == NULLP)
2423       { 
2424          DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2425          ret = RFAILED;
2426       }
2427       else
2428       {
2429          if(cell->cellId == ulCqiInd->cellId)
2430          {
2431             GET_UE_ID(ulCqiInd->crnti, ueId);
2432             ueCb = &cell->ueCb[ueId-1];
2433             if(ueCb->crnti != ulCqiInd->crnti)
2434             {
2435                DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2436                ret = RFAILED;
2437             }
2438             else
2439             {
2440                /*TODO: complete the processing of UL CQI Ind*/ 
2441             }
2442          }
2443          else
2444          {
2445             DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2446                     ulCqiInd->cellId, cell->cellId);
2447             ret = RFAILED;
2448          }
2449       }
2450    }
2451    return ret;
2452 }
2453
2454 /*******************************************************************
2455  *
2456  * @brief Processes PHR ind from MAC
2457  *
2458  * @details
2459  *
2460  *    Function : SchProcPhrInd
2461  *
2462  *    Functionality:
2463  *       Processes PHR ind from MAC
2464  *
2465  * @params[in] 
2466  * @return ROK     - success
2467  *         RFAILED - failure
2468  *
2469  * ****************************************************************/
2470 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2471 {
2472    uint8_t  ret = ROK;
2473    uint16_t ueId = 0, cellIdx = 0;
2474    SchUeCb *ueCb = NULLP;
2475    SchCellCb *cell = NULLP;
2476    Inst  inst = pst->dstInst-SCH_INST_START;   
2477
2478    if(!schPhrInd)
2479    {
2480       DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): PHR is empty");
2481       ret = RFAILED;
2482    }
2483    else
2484    {
2485       GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2486       cell = schCb[inst].cells[cellIdx];
2487       if(cell == NULLP)
2488       { 
2489          DU_LOG("\nERROR  -->  SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2490          ret = RFAILED;
2491       }
2492       else
2493       {
2494          if(cell->cellId == schPhrInd->cellId)
2495          {
2496             GET_UE_ID(schPhrInd->crnti, ueId);
2497             ueCb = &cell->ueCb[ueId-1];
2498             if(ueCb->crnti != schPhrInd->crnti)
2499             {
2500                DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2501                ret = RFAILED;
2502             }
2503             else
2504             {
2505                /*TODO: complete the processing of PHR Ind*/ 
2506             }
2507          }
2508          else
2509          {
2510             DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2511                     schPhrInd->cellId, cell->cellId);
2512             ret = RFAILED;
2513          }
2514       }
2515    }
2516    return ret;
2517 }
2518
2519 /*******************************************************************
2520  *
2521  * @brief Fill and send statistics response to MAC
2522  *
2523  * @details
2524  *
2525  *    Function :  SchSendStatsRspToMac
2526  *
2527  *    Functionality: Fill and send statistics response to MAC
2528  *
2529  * @params[in]  Inst inst, SchMacRsp result
2530  * @return ROK     - success
2531  *         RFAILED - failure
2532  *
2533  * ****************************************************************/
2534 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2535 {
2536    Pst rspPst;
2537    uint8_t ret = ROK;
2538    SchStatsRsp  *schStatsRsp;
2539
2540    DU_LOG("\nINFO   --> SCH : Filling statistics response");
2541    SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2542    if(schStatsRsp == NULLP)
2543    {
2544       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2545       return RFAILED;
2546    }
2547  
2548    memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2549    memset(statsRsp, 0, sizeof(SchStatsRsp));
2550
2551    /* Filling response post */
2552    memset(&rspPst, 0, sizeof(Pst));
2553    FILL_PST_SCH_TO_MAC(rspPst, inst);
2554    rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2555
2556    ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2557    if(ret == RFAILED)
2558    {
2559       DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2560       return ret;
2561    }
2562    return ret;
2563 }
2564
2565 /*******************************************************************
2566  *
2567  * @brief Rejects all statistics group requested by MAC
2568  *
2569  * @details
2570  *
2571  *    Function : SchRejectAllStats
2572  *
2573  *    Functionality: Add all statistics group received in statistics
2574  *       request from MAC, to Reject-Stats-Group-List in statistics
2575  *       response to MAC
2576  *
2577  * @params[in]  Statistics request from MAC
2578  *              Cause of rejection
2579  * @return ROK     - success
2580  *         RFAILED - failure
2581  *
2582  * ****************************************************************/
2583 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2584 {
2585    uint8_t grpIdx = 0;
2586    SchStatsRsp schStatsRsp;
2587
2588    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2589
2590    /* Copying all stats group from stats request to stats response */
2591    schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2592    for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2593    {
2594       schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2595       schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2596    }
2597    schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2598
2599    return SchSendStatsRspToMac(&schStatsRsp);
2600 }
2601
2602 /*******************************************************************
2603  *
2604  * @brief Add active KPI pointers to KPI-Active-List
2605  *
2606  * @details
2607  *
2608  *    Function : schAddToKpiActiveList
2609  *
2610  *    Functionality: For each active statistics group for which timer
2611  *       is running, add its KPI pointer to KPI-Active-List.
2612  *       Use case :
2613  *       When it is needed to update a KPI parameters, we need not
2614  *       traverse all statistics group and all KPIs within a group
2615  *       to get the specific KPI pointer to be updated.
2616  *       Instead, we can traverse through KPI-Active-List and update
2617  *       all entries in this list.
2618  *
2619  * @params[in]  Pointer to the prb usage info link list
2620  *              Pointer to the stats ccnfig which we need to add
2621  * @return ROK     - success
2622  *         RFAILED - failure
2623  *
2624  * ****************************************************************/
2625 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2626 {
2627    CmLList  *node = NULLP;
2628
2629    SCH_ALLOC(node, sizeof(CmLList));
2630    if(node)
2631    {
2632       node->node = kpiStatsInfo; 
2633       cmLListAdd2Tail(kpiList, node);
2634       return ROK;
2635    }
2636    DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2637    return RFAILED;
2638 }
2639
2640  /*******************************************************************
2641  *
2642  * @brief add the stats group information in statistics's statsGrpList
2643  *
2644  * @details
2645  *
2646  *    Function : schAddToStatsGrpList
2647  *
2648  *    Functionality: add the stats group information in statsGrpList
2649  *    [Step 1] - Allocating the memory for the stats group in which 
2650  *          we need to fill into the list as a node.
2651  *    [Step 2] - If allocation is successful then start traversing 
2652  *          each measurment cfg index of received group info.
2653  *       [Step 2.1] Validate all measurements. If validation succeeds, go
2654  *       to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2655  *       [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2656  *       If it fails for any KPI, reject the whole statsGrp and go to step 3..
2657  *       [Step 2.3] Fill other group related information
2658  *       [Step 2.4] Initialise and start timer
2659  *       [Step 2.5] Once all validation and configuration is successful, add
2660  *       statsGrp node into statistic's StatsGrpList.
2661  *          [Step 2.5.1] If node successfully added to the list, then 
2662  *             fill the group related info in stats rsp's accepted list.
2663  *          [Step 2.5.2] Else goto step 3
2664  *    [Step 3] - If failed fill the group related info in stats rsp's 
2665  *          rejected list.
2666  *
2667  * @params[in]  
2668  *          Inst
2669  *          Pointer to the stats rsp
2670  *          Subscription Id
2671  *          Stats Grp Info which needs to be store in the list
2672  * @return ROK     - success
2673  *         RFAILED - failure
2674  *
2675  * ****************************************************************/
2676
2677 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2678 {
2679    uint8_t ret =ROK;
2680    uint8_t grpIdx=0;
2681    uint8_t reqMeasIdx=0;
2682    CauseOfResult cause;
2683    bool measTypeInvalid=false;
2684    CmLList *statsGrpNode=NULLP; 
2685    SchStatsGrp *grpInfoDb = NULLP;
2686    
2687    /* Step 1 */
2688    SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2689    if(grpInfoDb == NULLP)
2690    {
2691       DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2692       cause = RESOURCE_UNAVAILABLE;
2693       ret = RFAILED;
2694    }
2695    else
2696    {
2697       /* Step 2 */
2698       for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2699       {
2700          /* Step 2.1 */
2701          switch(grpInfo->statsList[reqMeasIdx])
2702          {
2703             case SCH_DL_TOTAL_PRB_USAGE:
2704                {
2705                   SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2706                   if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2707                   {
2708                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2709                      measTypeInvalid = true;
2710                      cause = RESOURCE_UNAVAILABLE;
2711                      break;
2712                   }
2713                   break;
2714                }
2715
2716             case SCH_UL_TOTAL_PRB_USAGE:
2717                {
2718                   SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2719                   if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2720                   {
2721                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2722                      measTypeInvalid = true;
2723                      cause = RESOURCE_UNAVAILABLE;
2724                      break;
2725                   }
2726                   break;
2727                }
2728
2729             default:
2730                {
2731                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2732                         grpInfo->statsList[reqMeasIdx]);
2733                   measTypeInvalid = true;
2734                   cause = PARAM_INVALID;
2735                   break;
2736                }
2737          }
2738
2739          if(measTypeInvalid)
2740          {
2741             ret =RFAILED;
2742             break;
2743          }
2744       }
2745
2746       while(measTypeInvalid==false)
2747       {
2748          if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2749          {
2750             /* Step 2.2 */
2751             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2752             {
2753                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2754                cause = RESOURCE_UNAVAILABLE;
2755                ret =RFAILED;
2756                break;
2757             }
2758          }
2759
2760          if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2761          {
2762             /* Step 2.2 */
2763             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2764             {
2765                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2766                cause = RESOURCE_UNAVAILABLE;
2767                ret =RFAILED;
2768                break;
2769             }
2770          }
2771
2772          /* Step 2.3 */
2773          grpInfoDb->schInst = inst;
2774          grpInfoDb->groupId = grpInfo->groupId;
2775          grpInfoDb->periodicity = grpInfo->periodicity;
2776          grpInfoDb->subscriptionId = subscriptionId;
2777
2778          /* Step 2.4 */
2779          cmInitTimers(&(grpInfoDb->periodTimer), 1);
2780          schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2781
2782          /* Step 2.5 */
2783          SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2784          if(statsGrpNode)
2785          {
2786             /* Step 2.5.1 */
2787             statsGrpNode->node = (PTR) grpInfoDb;
2788             cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2789             statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2790             statsRsp->numGrpAccepted++;
2791             grpIdx++;
2792             ret =  ROK;
2793             break;
2794          }
2795          else
2796          {
2797             /* Step 2.5.2 */
2798             DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2799             cause = RESOURCE_UNAVAILABLE;
2800             ret  = RFAILED;
2801             break;
2802          }
2803       }
2804    }
2805
2806    if(ret != ROK)
2807    {
2808       /* Step 3 */
2809       if(grpInfoDb)
2810       {
2811          deleteStatsGrpInfo(inst, grpInfoDb);      
2812          SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2813       }
2814       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2815       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2816       statsRsp->numGrpRejected++;
2817       return RFAILED;
2818    }
2819    return ROK;
2820 }
2821
2822 /*******************************************************************
2823  *
2824  * @brief Processes Statistics Request from MAC
2825  *
2826  * @details
2827  *
2828  *    Function : SchProcStatsReq
2829  *
2830  *    Functionality:
2831  *
2832  *     This function process the statistics request from MAC:
2833  *     [Step 1] Basic validation. If fails, all stats group in stats request are
2834  *     rejected.
2835  *     [Step 2] If basic validations passed, traverse all stats group and
2836  *     validate each measurement types in each group.
2837  *     [Step 3] If any measurement type validation fails in a group, that group
2838  *     is not configured and it is added to stats-group-rejected-list in
2839  *     sch-stats-response message.
2840  *     [Step 4] If a group passes all validation, it is added to SCH database.
2841  *     And the group is added to stats-group-accepted-list in sch-stats-response message.
2842  *     [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2843  *     and stats-group-accepted-list.
2844  *
2845  * @params[in] Post structure
2846  *             Statistics Request from MAC 
2847  * @return ROK     - success
2848  *         RFAILED - failure
2849  *
2850  * ****************************************************************/
2851 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2852 {
2853    bool allocFailed = false;
2854    uint8_t grpIdx = 0, reqGrpIdx = 0;
2855    SchStatsGrpInfo *grpInfo = NULLP;
2856    SchStatsRsp schStatsRsp;
2857    Inst inst = pst->dstInst - SCH_INST_START;
2858
2859    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
2860
2861    if(statsReq == NULLP)
2862    {
2863       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
2864       return RFAILED;
2865    }
2866
2867    /*Step -1*/
2868    if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2869    {
2870       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
2871             Cannot process new request.");
2872       SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2873       SCH_FREE(statsReq, sizeof(SchStatsReq));
2874       return RFAILED;
2875    }
2876
2877    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2878
2879    /*Step -2*/
2880    for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2881    {
2882       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2883       /*Step -3 */
2884       if(allocFailed  == true)
2885       {
2886          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2887          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2888          schStatsRsp.numGrpRejected++;
2889       }
2890       else
2891       {
2892          /*Step -4 */
2893          if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2894          {
2895             DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
2896             if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2897                      (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2898             { 
2899                allocFailed = true;
2900             }
2901          }
2902       }
2903    }
2904
2905    schStatsRsp.subscriptionId = statsReq->subscriptionId;
2906    SCH_FREE(statsReq, sizeof(SchStatsReq));
2907    
2908    /*Step -5 */
2909    SchSendStatsRspToMac(&schStatsRsp);
2910
2911    return ROK;
2912 }
2913
2914 /*******************************************************************
2915  *
2916  * @brief Fill and send statistics indication to MAC
2917  *
2918  * @details
2919  *
2920  *    Function :  SchSendStatsIndToMac
2921  *
2922  *    Functionality: Fill and send statistics indication to MAC
2923  *
2924  * @params[in]  SCH Instance
2925  *              Measurement Type
2926  *              Measurement Value
2927  *              Size of value parameter
2928  * @return ROK     - success
2929  *         RFAILED - failure
2930  *
2931  * ****************************************************************/
2932 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd)
2933 {
2934    Pst pst;
2935    uint8_t ret = ROK;
2936
2937 #ifdef DEBUG_PRINT
2938    DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
2939 #endif
2940
2941    /* Filling post structure */
2942    memset(&pst, 0, sizeof(Pst));
2943    FILL_PST_SCH_TO_MAC(pst, inst);
2944    pst.event = EVENT_STATISTICS_IND_TO_MAC;
2945
2946    ret = MacMessageRouter(&pst, (void *)statsInd);
2947    if(ret == RFAILED)
2948    {
2949       DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2950    }
2951    return ret;
2952 }
2953
2954 /**
2955  * @brief Handler to process Timer expiry of DL Total PRB Usage calculation 
2956  *
2957  * @param[in] cb        Control block depending on the type of the timer event.
2958  * @param[in] tmrEvnt   Timer event to be started
2959  *
2960  * @return  Bool indicating whether the timer is running or not
2961  *      -# ROK
2962  *      -# RFAILED
2963 */
2964 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2965 {
2966    double percentageOfTotalPrbUsed = 0;
2967
2968    if(dlTotalPrbUsage->totalPrbAvailForTx)
2969       percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2970    
2971    memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2972
2973    return percentageOfTotalPrbUsed;
2974 }
2975
2976 /**
2977  * @brief Handler to check if the timer is running
2978  *
2979  * @param[in] cb        Control block depending on the type of the timer event.
2980  * @param[in] tmrEvnt   Timer event to be started
2981  *
2982  * @return  Bool indicating whether the timer is running or not
2983  *      -# ROK
2984  *      -# RFAILED
2985 */
2986 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2987 {
2988    double percentageOfTotalPrbUsed = 0;
2989
2990    if(ulTotalPrbUsage->totalPrbAvailForTx)
2991       percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2992
2993    memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2994
2995    return percentageOfTotalPrbUsed;
2996 }
2997
2998 /**
2999  * @brief Calculates statistics in a group and sends
3000  *          statistics indication for this group
3001  *
3002  * @param[in] Statistics group info
3003  *
3004  * @return
3005  *      -# ROK
3006  *      -# RFAILED
3007 */
3008 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
3009 {
3010    uint8_t measStatsIdx = 0;
3011    SchStatsInd  statsInd;
3012
3013    memset(&statsInd, 0, sizeof(SchStatsInd));
3014    statsInd.subscriptionId = grpInfo->subscriptionId;
3015    statsInd.groupId = grpInfo->groupId;
3016
3017    if(grpInfo->kpiStats.dlTotalPrbUsage)
3018    {
3019       statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;  
3020       statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);   
3021       measStatsIdx++;
3022    }
3023    
3024    if(grpInfo->kpiStats.ulTotalPrbUsage)
3025    {
3026       statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;  
3027       statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);   
3028       measStatsIdx++;
3029    }
3030    
3031    statsInd.numStats = measStatsIdx;
3032
3033    return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3034 }
3035
3036 /*******************************************************************
3037  *
3038  * @brief Delete node from active kpi list
3039  *
3040  * @details
3041  *
3042  *    Function :deleteNodeFrmKpiList 
3043  *
3044  *    Functionality:
3045  *    Delete statistics group
3046  *
3047  * @params[in]
3048  *           Kpi list from which a node needs to be deleted
3049  *           Nodes info which a node needs to be deleted
3050  * @return void
3051  * ****************************************************************/
3052
3053 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3054 {
3055    CmLList *kpiNode=NULLP;
3056
3057    CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3058    while(kpiNode)
3059    {
3060       if(kpiNode->node == kpiNodeInfoToDel)
3061       {
3062          cmLListDelFrm(kpiList, kpiNode);
3063          SCH_FREE(kpiNode, sizeof(CmLList));
3064          break;
3065       }
3066       kpiNode = kpiNode->next;
3067    }
3068
3069 }
3070
3071 /*******************************************************************
3072  *
3073  * @brief Delete statistics group info
3074  *
3075  * @details
3076  *
3077  *    Function : deleteStatsGrpInfo
3078  *
3079  *    Functionality:
3080  *    Delete statistics group info
3081  *
3082  * @params[in]
3083  *           Inst
3084  *           Stats Grp info
3085  * @return void
3086  *
3087  * ****************************************************************/
3088 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3089 {
3090    if(statsGrpInfo)
3091    {
3092       if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3093       {
3094          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3095          SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3096       }
3097
3098       if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3099       {
3100          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3101          SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3102       }
3103
3104       if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3105       {
3106          schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3107       }
3108
3109       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3110    }
3111 }
3112
3113 /*******************************************************************
3114  *
3115  * @brief Delete statistics group Node
3116  *
3117  * @details
3118  *
3119  *    Function : deleteStatsGrpNode
3120  *
3121  *    Functionality:
3122  *    Delete statistics group node
3123  *
3124  * @params[in]
3125  *           Inst
3126  *           Stats Grp Node
3127  * @return void
3128  *
3129  * ****************************************************************/
3130 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3131 {
3132    SchStatsGrp *statsGrpInfo=NULLP;
3133
3134    if(grpNode)
3135    {
3136       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3137       deleteStatsGrpInfo(inst, statsGrpInfo);      
3138       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3139       SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3140       SCH_FREE(grpNode, sizeof(CmLList));
3141    }
3142 }
3143
3144 /******************************************************************
3145  *
3146  * @brief Deletion of node from statistics group list
3147  *
3148  * @details
3149  *
3150  *    Function : deleteFromStatsGrpList
3151  *
3152  *    Functionality: Deletion of node from statistics group list
3153  *    [Step 1]: Traverse each and every node of stats group list
3154  *    stored in the database
3155  *    [Step 2]: Check if the node's subscription id is same 
3156  *    as the subscription id received. If same then go to step 3
3157  *    else move to the next node of the list.
3158  *    [Step 3]: If deleteAllGrp == true, then delete the node and 
3159  *    move to the next node of the list.
3160  *    [Step 4]: If deleteAllGrp != true, then check if the node's group
3161  *    id is same as group id received then delete the node and mark the 
3162  *    status found true else move to the next node of the list.
3163  *    [Step 5]: Once the traversing complete,  
3164  *    if deleteAllGrp is true, then return successful rsp;
3165  *    else if status found is true, then return  successful rsp;
3166  *    else return failure.
3167  * @params[in] 
3168  *           Inst
3169  *           Stats Grp List 
3170  *           Subscription Id
3171  *           Group Id
3172  *           boolen of deleteAllGrp
3173  * @return void
3174  *
3175  * ****************************************************************/
3176 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  subscriptionId, uint8_t  groupId, bool deleteAllGrp)
3177 {
3178    bool statsFound=false;
3179    SchStatsGrp *statsGrpInfo=NULLP;
3180    CmLList *grpNode=NULLP;
3181
3182    /* [Step 1] */
3183    CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3184    while(grpNode)
3185    {
3186       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3187
3188       /* [Step 2] */
3189       if(statsGrpInfo->subscriptionId== subscriptionId) 
3190       {
3191          if(deleteAllGrp == true)
3192          {
3193             /* [Step 3] */
3194             cmLListDelFrm(statsGrpList, grpNode);
3195             deleteStatsGrpNode(inst, grpNode);
3196          }
3197          else
3198          {
3199             /* [Step 4] */
3200             if(statsGrpInfo->groupId== groupId) 
3201             {
3202                cmLListDelFrm(statsGrpList, grpNode);
3203                deleteStatsGrpNode(inst, grpNode);
3204                statsFound = true;
3205             }
3206          }
3207       }
3208       CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3209    }
3210
3211    /* [Step 5] */
3212    if(deleteAllGrp == true)
3213    {
3214       return ROK;
3215    }
3216    else
3217    {
3218       if(statsFound == true)
3219          return ROK;
3220    }
3221    return RFAILED;
3222 }
3223
3224 /*******************************************************************
3225  *
3226  * @brief Delete statistics information 
3227  *
3228  * @details
3229  *
3230  *    Function : deleteStatsInfo 
3231  *
3232  *    Functionality:
3233  *   Delete statistics information base on numStatsGroup 
3234  *   Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3235  *   'SUBS_DELETION_REQ' wherein all the groups of this particular
3236  *   Subscription has to be removed 
3237  *   else when numStatsGroup != 0 then this is
3238  *   for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3239  *   to be removed thus need to pass groupId belonging to that subscription
3240  *   which has to be deleted.'
3241  *
3242  *   [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3243  *   received subscription Id.
3244  *   [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group 
3245  *   from list whose information are present in stats delete request.
3246  *   [Step-3] Fill the result of the stats deletion in the SCH stats delete
3247  *   response
3248  * @params[in] 
3249  *             Instance
3250  *             Subscription delete req
3251  *             Subscription delete rsp
3252  * @return ROK     - success
3253  *         RFAILED - failure
3254  *
3255  * ****************************************************************/
3256 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp  *schStatsDeleteRsp)
3257 {
3258    uint8_t statsGrpIdx=0;
3259    CmLListCp  *statsGrpList =NULLP;
3260
3261    statsGrpList = &schCb[inst].statistics.statsGrpList;
3262    
3263    if(!statsDeleteReq->numStatsGroupToBeDeleted)
3264    {
3265       /* [Step-1] */
3266       if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3267       {
3268          /* [Step 3]*/
3269          schStatsDeleteRsp->subsDelRsp = RSP_OK;  
3270          schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3271       }
3272       else
3273       {
3274          /* [Step-3]*/
3275          schStatsDeleteRsp->subsDelRsp = RSP_NOK;  
3276          schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND; 
3277       }
3278    }
3279    else
3280    {
3281       for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3282       {
3283          /* [Step-2] */
3284          if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3285                   statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3286          {
3287             /* [Step-3]*/
3288             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;  
3289             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL; 
3290          }
3291          else
3292          {
3293             /* [Step-3]*/
3294             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;  
3295             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND; 
3296          }
3297       }
3298       schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3299    }
3300    return ROK;
3301 }
3302
3303 /*******************************************************************
3304  *
3305  * @brief Processes Statistics Delete Request from MAC
3306  *
3307  * @details
3308  *
3309  *    Function : SchProcStatsDeleteReq
3310  *
3311  *    Functionality:
3312  *     This function process the statistics delete request from MAC:
3313  *
3314  * @params[in] Post structure
3315  *             Statistics Delete Request from MAC
3316  * @return ROK     - success
3317  *         RFAILED - failure
3318  *
3319  * ****************************************************************/
3320 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3321 {
3322    Pst rspPst;
3323    uint8_t ret =ROK;
3324    SchStatsDeleteRsp  *schStatsDeleteRsp;
3325    Inst    inst = pst->dstInst - SCH_INST_START;
3326
3327    DU_LOG("\nINFO   -->  SCH : Received Statistics Delete Request from MAC");
3328
3329    if(statsDeleteReq == NULLP)
3330    {
3331       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Received Null pointer");
3332       return RFAILED;
3333    }
3334    
3335    /* Process Stats delete request and fill stats delete response simultaneously */
3336    SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3337    if(schStatsDeleteRsp == NULLP)
3338    {
3339       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3340       return RFAILED;
3341    }
3342    schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3343    deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3344    
3345    memset(&rspPst, 0, sizeof(Pst));
3346    FILL_PST_SCH_TO_MAC(rspPst, inst);
3347    rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3348
3349    ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3350    if(ret == RFAILED)
3351    {
3352       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3353    }
3354    SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3355
3356    return ret;
3357 } /* End of SchProcStatsDeleteReq */
3358
3359 /*******************************************************************
3360  *
3361  * @brief Fill and send statistics modification response to MAC
3362  *
3363  * @details
3364  *
3365  *    Function :  SchSendStatsRspToMac
3366  *
3367  *    Functionality: Fill and send statistics
3368  * modification response to MAC
3369  *
3370  * @params[in]  Inst inst, SchMacRsp result
3371  * @return ROK     - success
3372  *         RFAILED - failure
3373  *
3374  * ****************************************************************/
3375 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3376 {
3377    Pst rspPst;
3378    uint8_t ret = ROK;
3379    SchStatsModificationRsp  *schStatsModificationRsp=NULLP;
3380
3381    DU_LOG("\nINFO   --> SCH : Filling statistics modification response");
3382    SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3383    if(schStatsModificationRsp == NULLP)
3384    {
3385       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3386       return RFAILED;
3387    }
3388
3389    memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3390    memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3391
3392    /* Filling response post */
3393    memset(&rspPst, 0, sizeof(Pst));
3394    FILL_PST_SCH_TO_MAC(rspPst, inst);
3395    rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3396
3397    ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3398    if(ret == RFAILED)
3399    {
3400       DU_LOG("\nERROR  -->  SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3401       return ret;
3402    }
3403    return ret;
3404 }
3405
3406 /*******************************************************************
3407  *
3408  * @brief Rejects all statistics modification group requested by MAC
3409  *
3410  * @details
3411  *
3412  *    Function : SchRejectAllStatsModification
3413  *
3414  *    Functionality: Add all statistics modification group received in statistics
3415  *       request from MAC, to Reject-StatsModification-Group-List in statistics
3416  *       response to MAC
3417  *
3418  * @params[in]  Statistics request from MAC
3419  *              Cause of rejection
3420  * @return ROK     - success
3421  *         RFAILED - failure
3422  *
3423  * ****************************************************************/
3424 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3425 {
3426    uint8_t grpIdx = 0;
3427    SchStatsModificationRsp statsModificationRsp;
3428
3429    memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3430
3431    /* fill the subscriptionId and the rejected list in stats modification rsp */
3432    statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3433    for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3434    {
3435       statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3436       statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3437    }
3438    statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3439
3440    return SchSendStatsModificationRspToMac(&statsModificationRsp);
3441 }
3442
3443 /****************************************************************************************
3444 *
3445 * @brief Processes Statistics modification Request from MAC
3446 *
3447 * @details
3448 *
3449 *    Function :SchProcStatsModificationReq 
3450 *
3451 *    Functionality:
3452 *     This function process the statistics modification request from MAC:
3453 *     [Step -1] Check the stored stats group list empty.
3454 *        [Step - 1.1] If empty Send the rejected group list to MAC as a stats 
3455 *        modification response.
3456 *        [Step - 1.2] Else go to step 2.
3457 *     [Step -2] Traverse all stats group and validate each measurement types in
3458 *     each group.
3459 *     [Step -3] Check for any failure and if failed fill the remaining group's
3460 *     info in rejected list.
3461 *     [Step -4] Else Check if the received subscriptionId and groupId match the 
3462 *     values with the database node. 
3463 *        [Step -4.1] If  matches then follow the below mentioned steps.
3464 *           [Step -4.1.1] Stop the timer.
3465 *           [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3466 *           statsGroup with updated configuration in database.
3467 *           [Step -4.1.3] if configured successfully, store stats info into
3468 *           stats mod rsp's accepted list, restart timer and go to step 4.1.4 
3469 *           [Step -4.1.4] Delete the old entry of this stats group..
3470 *        [Step -4.2] Else fill the group related info in stats modification rsp's 
3471 *           rejected list.
3472 *     [Step -5] Send the stats modification rsp to MAC
3473 * @params[in] Post structure
3474 *             Statistics modification Request from MAC
3475 * @return ROK     - success
3476 *         RFAILED - failure
3477 *
3478 * *******************************************************************************************/
3479 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3480 {
3481    Inst inst;
3482    uint8_t reqGrpIdx=0;
3483    uint64_t subscriptionId =0;
3484    bool allocFailed = false;
3485    bool statsGrpFound= false;
3486    CmLList *grpNode = NULLP;
3487    SchStatsGrp *statsGrpInfo=NULLP;
3488    SchStatsGrpInfo statsGrpToModify;
3489    SchStatsModificationRsp statsModificationRsp;
3490
3491    inst=pst->dstInst - SCH_INST_START;
3492
3493    DU_LOG("\nINFO   -->  SCH : Received Statistics modification request from MAC");
3494
3495    if(statsModificationReq == NULLP)
3496    {
3497       DU_LOG("\nERROR  -->  SCH : SchProcStatsModificationReq(): Received Null pointer");
3498       return RFAILED;
3499    }
3500    memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3501
3502    /* [Step -1] */
3503    if(schCb[inst].statistics.statsGrpList.count)
3504    {
3505       /* [Step -1.2] */
3506       subscriptionId = statsModificationReq->subscriptionId;
3507
3508       /* [Step - 2] */
3509       for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3510       {
3511          /* [Step - 3] */
3512          statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3513          if(allocFailed  != true)
3514          {
3515             CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3516             while(grpNode)
3517             {
3518                /* [Step - 4] */
3519                statsGrpInfo = (SchStatsGrp*)grpNode->node;
3520                if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3521                {
3522                   statsGrpFound= true;
3523                   break; 
3524                }
3525                grpNode = grpNode->next;
3526             }
3527
3528             /* [Step - 4.1] */
3529             if(statsGrpFound== true)
3530             {
3531                /* [Step - 4.1.1] */
3532                if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3533                {
3534                   schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3535                }
3536
3537                /* [Step - 4.1.2] */
3538                if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3539                {
3540                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
3541                   if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3542                   {
3543                      /* [Step - 4.1.3] */
3544                      schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3545                      if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3546                      {
3547                         allocFailed = true;
3548                         break;
3549                      }
3550                   }
3551                }
3552                else
3553                {
3554                   /* [Step - 4.1.4] */
3555                   deleteStatsGrpNode(inst, grpNode);
3556                }
3557             }
3558             else
3559             {
3560                /* [Step - 4.2] */
3561                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3562                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3563                statsModificationRsp.numGrpRejected++;
3564             }
3565          }
3566          else
3567          {
3568             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3569             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3570             statsModificationRsp.numGrpRejected++;
3571          }
3572       }
3573
3574       statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3575       SchSendStatsModificationRspToMac(&statsModificationRsp);
3576    }
3577    else
3578    {
3579       /* [Step -1.1] */
3580       SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3581    }
3582    SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3583    return ROK;
3584 }
3585 /**********************************************************************
3586   End of file
3587  **********************************************************************/