ebd0eafe880510866761a01e716d56e478af5503
[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    CmLListCp *list=NULL;
890    CmLList *node=NULL, *next=NULL;
891    SchPageInfo *tempNode = NULLP;
892
893    if(cellCb->schDlSlotInfo)
894    {
895       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
896       {
897          list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
898          node = list->first;
899          while(node)
900          {
901             next = node->next;
902             SCH_FREE(node->node, sizeof(FreePrbBlock));
903             deleteNodeFromLList(list, node);
904             node = next;
905          }
906          SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
907       }
908       SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
909    }
910
911    if(cellCb->schUlSlotInfo)
912    {
913       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
914       {
915          list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
916          node = list->first;
917          while(node)
918          {
919             next = node->next;
920             SCH_FREE(node->node, sizeof(FreePrbBlock));
921             deleteNodeFromLList(list, node);
922             node = next;
923          }
924          SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));  
925       }
926       SCH_FREE(cellCb->schUlSlotInfo,  cellCb->numSlots * sizeof(SchUlSlotInfo*));
927    }
928
929    for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
930    {
931       if(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai)
932       {
933          for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
934          {
935             SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai));
936          }
937          SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*));
938       }
939    }
940
941    for(uint16_t idx =0; idx<MAX_SFN; idx++)
942    {
943       list = &cellCb->pageCb.pageIndInfoRecord[idx];
944       node = list->first;
945       while(node)
946       {
947          next = node->next;
948          if(node->node)
949          {
950             tempNode = (SchPageInfo*)(node->node);
951             SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
952             SCH_FREE(node->node,  sizeof(SchPageInfo));
953          }
954          deleteNodeFromLList(list, node);
955          node = next;
956       }
957    }
958
959    cellCb->api->SchCellDeleteReq(cellCb);
960
961    memset(cellCb, 0, sizeof(SchCellCb));
962 }
963
964 /*******************************************************************
965  *
966  * @brief Function for cell Delete request from MAC to SCH
967  *
968  * @details
969  *
970  *    Function : SchProcCellDeleteReq
971  *
972  *    Functionality: Function for cell Delete request from MAC to SCH
973  *
974  * @params[in] Pst *pst, SchCellDelete  *cellDelete
975  * @return ROK     - success
976  *         RFAILED - failure
977  *
978  * ****************************************************************/
979 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq  *cellDelete)
980 {
981    uint8_t   cellIdx=0, ret = RFAILED;
982    Inst      inst = pst->dstInst - SCH_INST_START;
983    SchMacRsp result= RSP_OK;
984    
985    if(!cellDelete)
986    {
987       DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): Ue Delete request failed");
988    }
989    else
990    {
991       GET_CELL_IDX(cellDelete->cellId, cellIdx);
992       if(schCb[inst].cells[cellIdx] == NULLP)
993       { 
994          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
995          result = RSP_NOK;
996       }
997       else
998       {
999          if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
1000          {
1001             deleteSchCellCb(schCb[inst].cells[cellIdx]);
1002             result = RSP_OK;
1003             ret = ROK;
1004             SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1005             DU_LOG("\nINFO   -->  SCH : Sending Cell Delete response to MAC");
1006          }
1007          else
1008          {
1009             DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1010             result = RSP_NOK;
1011          }
1012       }
1013
1014       if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1015       {
1016          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1017          ret =  RFAILED;
1018       }
1019    }
1020    return ret;   
1021 }
1022
1023 /*******************************************************************
1024  *
1025  * @brief Processes DL RLC BO info from MAC
1026  *
1027  * @details
1028  *
1029  *    Function : SchProcDlRlcBoInfo
1030  *
1031  *    Functionality:
1032  *       Processes DL RLC BO info from MAC
1033  *
1034  * @params[in] 
1035  * @return ROK     - success
1036  *         RFAILED - failure
1037  *
1038  * ****************************************************************/
1039 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1040 {
1041    uint8_t  lcId = 0;
1042    uint16_t ueId = 0;
1043    bool isLcIdValid = false;
1044    SchUeCb *ueCb = NULLP;
1045    SchCellCb *cell = NULLP;
1046    Inst  inst = pst->dstInst-SCH_INST_START;   
1047
1048    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1049    cell = schCb[inst].cells[inst];
1050
1051    if(cell == NULLP)
1052    {
1053       DU_LOG("\nERROR  -->  SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1054       return RFAILED;
1055    }
1056
1057    GET_UE_ID(dlBoInfo->crnti, ueId);
1058    ueCb = &cell->ueCb[ueId-1];
1059    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1060    {
1061       DU_LOG("INFO  --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1062       return ROK;
1063    }
1064    
1065    lcId  = dlBoInfo->lcId;
1066    CHECK_LCID(lcId, isLcIdValid);
1067    if(isLcIdValid == FALSE)
1068    {
1069       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1070       return RFAILED;
1071    }
1072
1073    /*Expected when theres a case of Retransmission Failure or Resetablishment
1074     *By Zero BO, the RLC is informing that previous data can be cleared out
1075     *Thus clearing out the LC from the Lc priority list*/
1076    if(dlBoInfo->dataVolume == 0)
1077    {
1078       /* TODO : Check the LC is Dedicated or default and accordingly LCList
1079        * will be used*/
1080       return ROK;
1081    }
1082
1083    if(lcId == SRB0_LCID)
1084    {
1085       cell->raCb[ueId -1].msg4recvd = true;
1086       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;      
1087    }
1088    else
1089    {
1090       /* TODO : These part of changes will be corrected during DL scheduling as
1091        * per K0 - K1 -K2 */
1092       SET_ONE_BIT(ueId, cell->boIndBitMap);
1093       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1094       {
1095          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1096       }
1097       else
1098       {
1099          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1100          return RFAILED;
1101       }
1102    }
1103    /* Adding UE Id to list of pending UEs to be scheduled */
1104    cell->api->SchDlRlcBoInfo(cell, ueId);
1105    return ROK;
1106 }
1107
1108 /*******************************************************************
1109  *
1110  * @brief Processes BSR indiation from MAC
1111  *
1112  * @details
1113  *
1114  *    Function : SchProcBsr
1115  *
1116  *    Functionality:
1117  *       Processes DL BSR from MAC
1118  *
1119  * @params[in]    Pst pst
1120  *                UlBufferStatusRptInd bsrInd
1121  * @return ROK     - success
1122  *         RFAILED - failure
1123  *
1124  * ****************************************************************/
1125 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1126 {
1127    Inst           schInst       = pst->dstInst-SCH_INST_START;
1128    SchCellCb      *cellCb       = NULLP;
1129    SchUeCb        *ueCb         = NULLP;
1130    uint8_t        lcgIdx = 0;
1131
1132    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1133    if(bsrInd == NULLP)
1134    {
1135       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1136       return RFAILED;
1137    }
1138    cellCb = schCb[schInst].cells[schInst];
1139    if(cellCb == NULLP)
1140    {
1141       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1142       return RFAILED;
1143    }
1144    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1145
1146    if(ueCb == NULLP)
1147    {
1148       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1149       return RFAILED;
1150    }
1151
1152    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1153    {
1154       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1155       return ROK;
1156    }
1157    
1158    ueCb->bsrRcvd = true;
1159    /* store dataVolume per lcg in uecb */
1160    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1161    {
1162       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1163       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1164    }
1165    
1166    /* Adding UE Id to list of pending UEs to be scheduled */
1167    cellCb->api->SchBsr(cellCb, ueCb->ueId);
1168    return ROK;
1169 }
1170
1171 /*******************************************************************
1172  *
1173  * @brief Processes SR UCI indication from MAC 
1174  *
1175  * @details
1176  *
1177  *    Function : SchProcSrUciInd
1178  *
1179  *    Functionality:
1180  *      Processes SR UCI indication from MAC
1181  *
1182  * @params[in] Post structure
1183  *             UCI Indication
1184  * @return ROK     - success
1185  *         RFAILED - failure
1186  *
1187  * ****************************************************************/
1188 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1189 {
1190    Inst  inst = pst->dstInst-SCH_INST_START;
1191
1192    SchUeCb   *ueCb; 
1193    SchCellCb *cellCb = schCb[inst].cells[inst];
1194
1195    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1196
1197    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1198    
1199    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1200    {
1201       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1202       return ROK;  
1203    }
1204    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1205    {
1206       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1207       return ROK;
1208    }
1209    if(uciInd->numSrBits)
1210    {
1211       ueCb->srRcvd = true;      
1212       /* Adding UE Id to list of pending UEs to be scheduled */
1213       cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1214    }
1215    return ROK;
1216 }
1217
1218 /*******************************************************************
1219  *
1220  * @brief Processes DL HARQ indication from MAC 
1221  *
1222  * @details
1223  *
1224  *    Function : SchProcDlHarqInd
1225  *
1226  *    Functionality:
1227  *      Processes DL HARQ indication from MAC
1228  *
1229  * @params[in] Post structure
1230  *             DL HARQ Indication
1231  * @return ROK     - success
1232  *         RFAILED - failure
1233  *
1234  * ****************************************************************/
1235 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1236 {
1237    Inst  inst = pst->dstInst-SCH_INST_START;
1238    SchUeCb   *ueCb;
1239    SchCellCb *cellCb = schCb[inst].cells[inst];
1240
1241    DU_LOG("\nDEBUG  -->  SCH : Received HARQ");
1242
1243    ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1244
1245    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1246    {
1247       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", dlHarqInd->crnti);
1248       return ROK;
1249    }
1250
1251    schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1252
1253    return ROK;
1254 }
1255
1256 /*******************************************************************
1257  *
1258  * @brief Allocates requested PRBs for DL
1259  *
1260  * @details
1261  *
1262  *    Function : allocatePrbDl
1263  *
1264  *    Functionality:
1265  *      Allocates requested PRBs in DL
1266  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1267  *
1268  * @params[in] prbAlloc table
1269  *             Start symbol
1270  *             Number of symbols
1271  *             Start PRB
1272  *             Number of PRBs
1273  *
1274  * @return ROK     - success
1275  *         RFAILED - failure
1276  *
1277  * ****************************************************************/
1278 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1279    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1280 {
1281    uint8_t        symbol = 0;
1282    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1283    FreePrbBlock   *freePrbBlock = NULLP;
1284    CmLList        *freePrbNode = NULLP;
1285    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1286    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1287    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1288
1289    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1290     * Search for an appropriate location in PRB grid and allocate requested resources */
1291    if(*startPrb == MAX_NUM_RB)
1292    {
1293       /* Check if SSB/SIB1 is also scheduled in this slot  */
1294       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1295       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1296
1297       if(ssbOccasion && sib1Occasion)
1298       {
1299          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1300          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1301       }
1302       else if(ssbOccasion)
1303       {
1304          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1305          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1306       }
1307       else if(sib1Occasion)
1308       {
1309          broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1310          broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1311       }
1312
1313       /* Iterate through all free PRB blocks */
1314       freePrbNode = prbAlloc->freePrbBlockList.first; 
1315       while(freePrbNode)
1316       {
1317          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1318
1319          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1320           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1321          if((ssbOccasion || sib1Occasion) && 
1322             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1323             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1324          {
1325             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1326             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1327             {
1328                /* If sufficient free PRBs are available above bradcast message then,
1329                 * endPrb = freePrbBlock->endPrb
1330                 * startPrb = endPrb - numPrb +1;
1331                 */
1332                *startPrb = freePrbBlock->endPrb - numPrb +1;
1333                break;
1334             }
1335             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1336             {
1337                /* If free PRBs are available below broadcast message then,
1338                 * endPrb = broadcastPrbStart - 1
1339                 * startPrb = endPrb - numPrb +1
1340                 */
1341                *startPrb = broadcastPrbStart - numPrb; 
1342                break;
1343             }
1344             else
1345             {
1346                freePrbNode = freePrbNode->next;
1347                continue;
1348             }
1349          }
1350          else
1351          {
1352             /* Check if requested number of blocks can be allocated from the current block */ 
1353             if (freePrbBlock->numFreePrb < numPrb)
1354             {
1355                freePrbNode = freePrbNode->next;
1356                continue;
1357             }
1358             *startPrb = freePrbBlock->endPrb - numPrb +1;
1359             break;  
1360          }
1361       }
1362
1363       /* If no free block can be used to allocated request number of RBs */
1364       if(*startPrb == MAX_NUM_RB)
1365          return RFAILED;
1366    }
1367
1368    /* If startPrb is known already, check if requested PRBs are available for allocation */
1369    else
1370    {
1371       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1372       if(!freePrbNode)
1373       {
1374          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1375          return RFAILED;
1376       }
1377    }
1378
1379    /* Update bitmap to allocate PRBs */
1380    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1381    {
1382       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1383       {
1384          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1385          return RFAILED;
1386       }
1387    }
1388    
1389    /* Update statistics of PRB usage if stats calculation is enabled */
1390    if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
1391       prbAlloc->numPrbAlloc += numPrb;
1392
1393    /* Update the remaining number for free PRBs */
1394    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1395
1396    return ROK;
1397 }
1398
1399 /*******************************************************************
1400  *
1401  * @brief Allocates requested PRBs for UL
1402  *
1403  * @details
1404  *
1405  *    Function : allocatePrbUl
1406  *
1407  *    Functionality:
1408  *      Allocates requested PRBs in UL
1409  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1410  *
1411  * @params[in] prbAlloc table
1412  *             Start symbol
1413  *             Number of symbols
1414  *             Start PRB
1415  *             Number of PRBs
1416  *
1417  * @return ROK     - success
1418  *         RFAILED - failure
1419  *
1420  * ****************************************************************/
1421 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1422    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1423 {
1424    uint8_t        symbol = 0;
1425    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1426    bool           isPrachOccasion;
1427    FreePrbBlock   *freePrbBlock = NULLP;
1428    CmLList        *freePrbNode = NULLP;
1429    SchPrbAlloc    *prbAlloc = NULLP;
1430
1431    if(cell == NULLP)
1432    {
1433       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1434       return RFAILED;
1435    }
1436    
1437    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1438    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1439     * Search for an appropriate location in PRB grid and allocate requested resources */
1440    if(*startPrb == MAX_NUM_RB)
1441    {
1442       /* Check if PRACH is also scheduled in this slot */
1443       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1444       if(isPrachOccasion)
1445       {
1446          prachStartPrb =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1447          prachNumPrb = schCalcPrachNumRb(cell);
1448          prachEndPrb = prachStartPrb + prachNumPrb -1;
1449       }
1450
1451       /* Iterate through all free PRB blocks */
1452       freePrbNode = prbAlloc->freePrbBlockList.first; 
1453       while(freePrbNode)
1454       {
1455          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1456
1457          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1458           * PRBs required for PRACH cannot be allocated to any other message */
1459          if((isPrachOccasion) &&
1460             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1461             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1462          {
1463             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1464             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1465             {
1466                /* If sufficient free PRBs are available above PRACH message then,
1467                 * endPrb = freePrbBlock->endPrb
1468                 * startPrb = endPrb - numPrb +1;
1469                 */
1470                *startPrb = freePrbBlock->endPrb - numPrb +1;
1471                break;
1472             }
1473             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1474             {
1475                /* If free PRBs are available below PRACH message then,
1476                 * endPrb = prachStartPrb - 1
1477                 * startPrb = endPrb - numPrb +1
1478                 */
1479                *startPrb = prachStartPrb - numPrb; 
1480                break;
1481             }
1482             else
1483             {
1484                freePrbNode = freePrbNode->next;
1485                continue;
1486             } 
1487          }
1488          else
1489          {
1490             /* Check if requested number of PRBs can be allocated from currect block */
1491             if(freePrbBlock->numFreePrb < numPrb)
1492             {
1493                freePrbNode = freePrbNode->next;
1494                continue;
1495             }
1496             *startPrb = freePrbBlock->endPrb - numPrb +1;
1497             break;
1498          }
1499       }
1500
1501       /* If no free block can be used to allocated requested number of RBs */
1502       if(*startPrb == MAX_NUM_RB)
1503          return RFAILED;
1504    }
1505    else
1506    {
1507       /* If startPrb is known already, check if requested PRBs are available for allocation */
1508       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1509       if(!freePrbNode)
1510       {
1511          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1512          return RFAILED;
1513       }
1514    }
1515
1516    /* Update bitmap to allocate PRBs */
1517    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1518    {
1519       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1520       {
1521          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1522          return RFAILED;
1523       }
1524    }
1525
1526    /* Update statistics of PRB usage if stats calculation is enabled */
1527    if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
1528       prbAlloc->numPrbAlloc += numPrb;
1529
1530    /* Update the remaining number for free PRBs */
1531    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1532
1533    return ROK;
1534 }
1535
1536 /*******************************************************************************
1537  *
1538  * @brief Try to find Best Free Block with Max Num PRB 
1539  *
1540  * @details
1541  *
1542  *    Function : searchLargestFreeBlock
1543  *
1544  *    Functionality:
1545  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1546  *
1547  * @params[in] I/P > prbAlloc table (FreeBlock list)
1548  *             I/P > Slot timing Info
1549  *             O/P > Start PRB
1550  *             I/P > Direction (UL/DL)
1551  *       
1552  *
1553  * @return Max Number of Free PRB 
1554  *         If 0, then no Suitable Free Block
1555  *
1556  * ********************************************************************************/
1557
1558 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1559 {
1560    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1561    FreePrbBlock   *freePrbBlock = NULLP;
1562    CmLList        *freePrbNode = NULLP;
1563    SchPrbAlloc    *prbAlloc = NULLP;
1564    bool           checkOccasion = FALSE;
1565
1566    *startPrb = 0; /*Initialize the StartPRB to zero*/
1567
1568    /*Based on Direction, Reserved Messsages will differi.e.
1569     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1570     * and reserved before allocation for dedicated DL/UL msg*/
1571    if(dir == DIR_DL)
1572    {
1573       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1574       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1575
1576       prbAlloc = &schDlSlotInfo->prbAlloc;
1577
1578       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1579       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1580
1581       checkOccasion = TRUE;
1582       if(ssbOccasion && sib1Occasion)
1583       {
1584          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1585          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1586                           cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1587       }
1588       else if(ssbOccasion)
1589       {
1590          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1591          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1592       }
1593       else if(sib1Occasion)
1594       {
1595          reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.startPrb;
1596          reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci[0].pdschCfg.pdschFreqAlloc.numPrb -1;
1597       }
1598       else
1599       {
1600          checkOccasion = FALSE;  
1601       }
1602    }
1603    else if(dir == DIR_UL)
1604    {
1605       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1606
1607       /* Check if PRACH is also scheduled in this slot */
1608       checkOccasion = schCheckPrachOcc(cell, slotTime);
1609       if(checkOccasion)
1610       {
1611          reservedPrbStart =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1612          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1613       }
1614    }
1615    else
1616    {
1617       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1618       return (maxFreePRB);
1619    }
1620
1621    freePrbNode = prbAlloc->freePrbBlockList.first; 
1622    while(freePrbNode)
1623    {
1624       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1625
1626       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1627        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1628       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1629       {
1630          //skip this block
1631          freePrbNode = freePrbNode->next;
1632          continue;
1633       }
1634
1635       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1636        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1637       if(checkOccasion && 
1638             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1639             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1640       {
1641
1642          /* Implmentation is done such that highest-numbered free-RB is Checked first
1643             and freePRB in this block is greater than Max till now */
1644          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1645          {
1646             /* If sufficient free PRBs are available above reserved message*/
1647             *startPrb = reservedPrbEnd + 1;
1648             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1649          }
1650          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1651          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1652          {
1653             /* If free PRBs are available below reserved message*/
1654             *startPrb = freePrbBlock->startPrb;
1655             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1656          }
1657       }
1658       else  //Best Block
1659       {
1660          if(maxFreePRB < freePrbBlock->numFreePrb)
1661          {
1662             *startPrb = freePrbBlock->startPrb;
1663             maxFreePRB = freePrbBlock->numFreePrb;
1664          }
1665
1666       }
1667       freePrbNode = freePrbNode->next;
1668    }  
1669    return(maxFreePRB);
1670 }
1671
1672 /*******************************************************************************
1673  *
1674  * @brief This function is used to send Slice Cfg rsp to MAC
1675  *
1676  * @details
1677  *
1678  *    Function : SchSendSliceCfgRspToMac
1679  *
1680  *    Functionality:
1681  *     function is used to send Slice Cfg rsp to MAC
1682  *
1683  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1684  *
1685  * @return- void
1686  *
1687  * ********************************************************************************/
1688 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1689 {
1690    Pst rspPst;
1691    
1692    memset(&rspPst, 0, sizeof(Pst));
1693    FILL_PST_SCH_TO_MAC(rspPst, inst);
1694    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1695    
1696    MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1697
1698 }
1699
1700 /*******************************************************************************
1701  *
1702  * @brief This function is used to store or modify the slice configuration Sch DB
1703  *
1704  * @details
1705  *
1706  *    Function : addOrModifySliceCfgInSchDb 
1707  *
1708  *    Functionality:
1709  *     function is used to store or modify the slice configuration Sch DB
1710  *
1711  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1712  * SchSliceCfgRsp cfgRsp, uint8_t count
1713  *
1714  * @return
1715  *        ROK - Success
1716  *        RFAILED - Failure
1717  *
1718  * ********************************************************************************/
1719 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1720 {
1721    SchRrmPolicyOfSlice *sliceToStore;
1722
1723    SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1724    if(sliceToStore)
1725    {
1726       memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));  
1727       memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));  
1728       addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1729    }
1730    else
1731    {
1732       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1733       return RFAILED;
1734    }
1735    return ROK;
1736 }
1737
1738 /*******************************************************************************
1739  *
1740  * @brief fill slice configuration response
1741  *
1742  * @details
1743  *
1744  *    Function : fillSliceCfgRsp
1745  *
1746  *    Functionality:
1747  *     fill slice configuration response
1748  *
1749  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1750  *
1751  * @return
1752  *        ROK - Success
1753  *        RFAILED - Failure
1754  *
1755  * ********************************************************************************/
1756 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1757 {
1758    SchMacRsp sliceFound;
1759    uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1760    SchSliceCfgRsp schSliceCfgRsp;
1761
1762    for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1763    {
1764       sliceFound = RSP_NOK;
1765       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1766       for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1767       {
1768          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
1769          {
1770             /* 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. */ 
1771             if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)))
1772             {
1773                if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1774                {
1775                   sliceFound = RSP_OK;
1776                   schSliceCfgRsp.cause = SUCCESSFUL;
1777                }
1778                else
1779                {
1780                   DU_LOG("\nERROR  --> SCH : Failed to store slice configuration in SchDb");
1781                   schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1782                   ret = RFAILED;
1783                }
1784                plmnIdx = MAX_PLMN;
1785                break;
1786             }
1787          }
1788       }
1789       
1790       if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1791          schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1792       
1793       schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1794       schSliceCfgRsp.rsp    = sliceFound;
1795       SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1796    }
1797    return ret;
1798 }
1799
1800 /*******************************************************************************
1801  *
1802  * @brief This function is used to free the slice cfg and re cfg request pointer
1803  *
1804  * @details
1805  *
1806  *    Function : freeSchSliceCfgReq 
1807  *
1808  *    Functionality:
1809  *     function is used to free the slice cfg and re cfg request pointer
1810  *
1811  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1812  *
1813  * @return
1814  *        ROK - Success
1815  *        RFAILED - Failure
1816  * ********************************************************************************/
1817 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1818 {
1819    uint8_t cfgIdx = 0;
1820    
1821    if(sliceCfgReq)
1822    {
1823       if(sliceCfgReq->numOfConfiguredSlice)
1824       {
1825          for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1826          {
1827             if(sliceCfgReq->listOfSlices[cfgIdx])
1828             {
1829                SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1830             }
1831          }
1832          SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1833       }
1834       SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1835    }
1836 }
1837 /*******************************************************************************
1838  *
1839  * @brief This function is used to store the slice configuration Sch DB
1840  *
1841  * @details
1842  *
1843  *    Function : SchProcSliceCfgReq 
1844  *
1845  *    Functionality:
1846  *     function is used to store the slice configuration Sch DB
1847  *
1848  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1849  *
1850  * @return
1851  *        ROK - Success
1852  *        RFAILED - Failure
1853  *
1854  * ********************************************************************************/
1855 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1856 {
1857    uint8_t ret = ROK;
1858    Inst   inst = pst->dstInst - SCH_INST_START;
1859
1860    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1861    if(schSliceCfgReq)
1862    {
1863       if(schSliceCfgReq->listOfSlices)
1864       {
1865          /* filling the slice configuration response of each slice */
1866          if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1867          {
1868             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1869             ret = RFAILED;
1870          }
1871          freeSchSliceCfgReq(schSliceCfgReq);
1872       }
1873    }
1874    else
1875    {
1876       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1877       ret = RFAILED;
1878    }
1879    return ret;
1880 }
1881
1882 /*******************************************************************************
1883  *
1884  * @brief This function is used to send Slice re Cfg rsp to MAC
1885  *
1886  * @details
1887  *
1888  *    Function : SchSendSliceRecfgRspToMac
1889  *
1890  *    Functionality:
1891  *     function is used to send Slice re Cfg rsp to MAC
1892  *
1893  * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1894  *
1895  * @return- void
1896  *
1897  * ********************************************************************************/
1898 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1899 {
1900    Pst rspPst;
1901    
1902    memset(&rspPst, 0, sizeof(Pst));
1903    FILL_PST_SCH_TO_MAC(rspPst, inst);
1904    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1905    
1906    MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1907 }
1908
1909 /*******************************************************************************
1910  *
1911  * @brief fill slice configuration response
1912  *
1913  * @details
1914  *
1915  *    Function : fillSliceRecfgRsp
1916  *
1917  *    Functionality: fill slice reconfiguration response
1918  *
1919  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1920  *
1921  * @return
1922  *        ROK - Success
1923  *        RFAILED - Failure
1924  *
1925  * ********************************************************************************/
1926
1927 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1928 {
1929    SchMacRsp sliceFound;
1930    uint8_t cfgIdx = 0;
1931    SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1932    SchSliceRecfgRsp schSliceRecfgRsp;
1933
1934    for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1935    {
1936       sliceFound = RSP_NOK;
1937       /* Here comparing the slice recfg request with the StoredSliceCfg */
1938       CmLList *sliceCfg = storedSliceCfg->first;
1939
1940       while(sliceCfg)
1941       {
1942          rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1943          
1944          if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1945          {
1946             memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1947             sliceFound = RSP_OK;
1948             break;
1949          }
1950          sliceCfg = sliceCfg->next;
1951       }
1952
1953       schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1954       schSliceRecfgRsp.rsp    = sliceFound;
1955       if(schSliceRecfgRsp.rsp == RSP_OK)
1956          schSliceRecfgRsp.cause = SUCCESSFUL;
1957       else
1958          schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1959       SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1960    }
1961    return ROK;
1962 }
1963 /*******************************************************************************
1964  *
1965  * @brief This function is used to store the slice reconfiguration Sch DB
1966  *
1967  * @details
1968  *
1969  *    Function : SchProcSliceRecfgReq 
1970  *
1971  *    Functionality:
1972  *     function is used to store the slice re configuration Sch DB
1973  *
1974  * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1975  *
1976  * @return
1977  *        ROK - Success
1978  *        RFAILED - Failure
1979  *
1980  * ********************************************************************************/
1981 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1982 {
1983    uint8_t ret = ROK;
1984    Inst   inst = pst->dstInst - SCH_INST_START;
1985
1986    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1987    if(schSliceRecfgReq)
1988    {
1989       if(schSliceRecfgReq->listOfSlices)
1990       {
1991          /* filling the slice configuration response of each slice */
1992          if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
1993          {
1994             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
1995             ret = RFAILED;
1996          }
1997          freeSchSliceCfgReq(schSliceRecfgReq);
1998       }
1999    }
2000    else
2001    {
2002       DU_LOG("\nERROR  -->  SCH : Received SchSliceRecfgReq is NULL");
2003
2004    }
2005    return ret;
2006 }
2007
2008 /****************************************************************************
2009  *
2010  * @brief Stores the Paging Configuration from DU APP in CellCb 
2011  *
2012  * @details
2013  *
2014  *    Function : schProcPagingParam
2015  *
2016  *    Functionality:
2017  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2018  *          Paging Ocassion is not present.
2019  *
2020  *          As per 38.304 Sec 7.1,
2021  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2022  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2023  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2024  *          parameter; otherwise, it is equal to i_s * S."
2025  *          "S = number of actual transmitted SSBs determined according 
2026  *              to ssb-PositionsInBurst in SIB1"
2027  *
2028  * @params[in] SchCellCb *cell 
2029  *       
2030  * @return void 
2031  *        
2032  *************************************************************************/
2033 void schProcPagingCfg(SchCellCb *cell)
2034 {
2035    SchPcchCfg *pageCfgRcvd = NULL;
2036    uint8_t i_sIdx = 0;
2037
2038    pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2039
2040    if(pageCfgRcvd->poPresent == TRUE)
2041    {
2042       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2043       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2044       {
2045          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2046          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2047          {
2048             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2049          }
2050
2051          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2052
2053       }
2054    }
2055    else
2056    {
2057       schCfgPdcchMonOccOfPO(cell);                  
2058    }
2059 }
2060
2061 /****************************************************************************
2062  *
2063  * @brief Calculate PO if not present in Configuration 
2064  *
2065  * @details
2066  *
2067  *    Function : schCfgPdcchMonOccOfPO
2068  *
2069  *    Functionality: In this function, PO are calculated i_s * S because
2070  *    FirstPDCCHMonitoring_ForPO is not present.
2071  *
2072  * @params[in] SchCellCb *cellCb
2073  *       
2074  * @return void 
2075  *        
2076  *************************************************************************/
2077 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2078 {
2079    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2080    uint8_t         nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2081    uint8_t         totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2082    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2083
2084    /*Starting with First Sfn and slot*/
2085    tmpTimingInfo.sfn = 0;
2086    tmpTimingInfo.slot = 0;
2087
2088    pdcchTime = tmpTimingInfo;
2089
2090    while(i_sIdx < nsValue)
2091    {
2092       /*Increment frame Offset if PO falls on next SFN*/
2093       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2094       {
2095          frameOffSet++;
2096       }
2097       pdcchTime = tmpTimingInfo;
2098       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2099
2100       if (i_sIdx == 0)
2101       {
2102          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2103          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2104          i_sIdx++;
2105       }
2106       else
2107       {
2108          cnt++;
2109          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2110          {
2111             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2112             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2113             cnt = 0;
2114             i_sIdx++;
2115          }
2116       }
2117    }
2118 }
2119
2120 /****************************************************************************
2121  *
2122  * @brief Storing the paging information in SCH database 
2123  *
2124  * @details
2125  *
2126  *    Function : schAddPagingIndtoList
2127  *
2128  *    Functionality: Storing the paging information in SCH database
2129  *
2130  * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2131  *       
2132  * @return ROK - sucess
2133  *         RFAILED - failure
2134  *        
2135  *************************************************************************/
2136 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2137 {
2138    CmLList  *firstNodeOfList = NULLP;
2139    CmLList  *currentNodeInfo = NULLP;
2140    SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2141    
2142    recvdNode = (SchPageInfo*) pageIndInfo;
2143    CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2144    
2145    SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2146    if(!currentNodeInfo)
2147    {  
2148       DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2149       return RFAILED;
2150    }
2151    
2152    currentNodeInfo->node = (PTR)pageIndInfo;
2153    while(firstNodeOfList)
2154    {
2155       tempNode = (SchPageInfo*)(firstNodeOfList->node);
2156       if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2157       {
2158          cmLListInsCrnt(storedPageList, currentNodeInfo);
2159          break;
2160       }
2161       else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2162       {
2163          DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2164          return RFAILED;
2165       }
2166       else
2167       {
2168          CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2169       }
2170    } 
2171    
2172    if(!firstNodeOfList)
2173    {
2174       cmLListAdd2Tail(storedPageList, currentNodeInfo);
2175    }
2176    DU_LOG("\nDEBUG   -->  SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2177               recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2178    return ROK;
2179 }
2180
2181 /****************************************************************************
2182  *
2183  * @brief Process paging indication at  SCH recevied form MAC 
2184  *
2185  * @details
2186  *
2187  *    Function : SchProcPagingInd
2188  *
2189  *    Functionality: Process paging indication at SCH recevied form MAC 
2190  *
2191  * @params[in] Pst *pst,  SchPageInd *pageInd 
2192  *       
2193  * @return void 
2194  *        
2195  *************************************************************************/
2196 uint8_t SchProcPagingInd(Pst *pst,  SchPageInd *pageInd)
2197 {
2198    uint8_t ret = RFAILED;
2199    uint16_t cellIdx = 0;
2200    Inst  inst = pst->dstInst - SCH_INST_START;
2201    SchCellCb *cellCb = NULLP;
2202    SchPageInfo *pageInfo = NULLP;
2203
2204    if(pageInd)
2205    {
2206       DU_LOG("\nDEBUG   -->  SCH : Received paging indication from MAC for cellId[%d]",\
2207                   pageInd->cellId);
2208
2209       /* Fetch Cell CB */
2210       for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2211       {
2212          if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2213          {
2214             cellCb = schCb[inst].cells[cellIdx];
2215             break;
2216          }
2217       }
2218       if(cellCb)
2219       {
2220          if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2221          {
2222             DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2223          }
2224          else
2225          {
2226             SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2227             if(pageInfo)
2228             {
2229                pageInfo->pf = pageInd->pf; 
2230                pageInfo->i_s = pageInd->i_s;
2231                pageInfo->pageTxTime.cellId = pageInd->cellId;
2232                pageInfo->pageTxTime.sfn = (pageInd->pf +  cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2233                pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2234                pageInfo->mcs = DEFAULT_MCS;
2235                pageInfo->msgLen =  pageInd->pduLen;
2236                SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2237                if(!pageInfo->pagePdu)
2238                {
2239                   DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2240                }
2241                else
2242                {
2243                   memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2244                   ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2245                   if(ret != ROK)
2246                   {
2247                      DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to store paging record");
2248                   }
2249                }
2250             }
2251             else
2252             {
2253                DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2254             }
2255          }
2256       }
2257       else
2258       {
2259          DU_LOG("\nERROR  -->  SCH : Cell ID [%d] not found", pageInd->cellId);
2260       }
2261       SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2262       SCH_FREE(pageInd, sizeof(SchPageInd));
2263    }
2264    else
2265    {
2266       DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Received null pointer");
2267    }
2268    return ret;
2269 }
2270
2271 \f
2272 /***********************************************************
2273  *
2274  *     Func : SchFillCfmPst 
2275  *        
2276  *
2277  *     Desc : Fills the Confirmation Post Structure cfmPst using the reqPst 
2278  *            and the cfm->hdr.response.
2279  *            
2280  *
2281  *     Ret  : Void
2282  *
2283  *     Notes: 
2284  *
2285  *     File : rg_sch_lmm.c 
2286  *
2287  **********************************************************/
2288 Void SchFillCfmPst
2289 (
2290 Pst           *reqPst,
2291 Pst           *cfmPst,
2292 RgMngmt       *cfm
2293 )
2294 {
2295    Inst inst;
2296
2297    inst = (reqPst->dstInst - SCH_INST_START);
2298
2299    cfmPst->srcEnt    = ENTMAC;
2300    cfmPst->srcInst   = (Inst) 1;
2301    cfmPst->srcProcId = schCb[inst].schInit.procId;
2302    cfmPst->dstEnt    = ENTMAC;
2303    cfmPst->dstInst   = (Inst) 0;
2304    cfmPst->dstProcId = reqPst->srcProcId;
2305
2306    cfmPst->selector  = cfm->hdr.response.selector;
2307    cfmPst->region    = cfm->hdr.response.mem.region;
2308    cfmPst->pool      = cfm->hdr.response.mem.pool;
2309
2310    return;
2311 }
2312
2313 /*******************************************************************
2314  *
2315  * @brief Processes DL CQI ind from MAC
2316  *
2317  * @details
2318  *
2319  *    Function : SchProcDlCqiInd
2320  *
2321  *    Functionality:
2322  *       Processes DL CQI ind from MAC
2323  *
2324  * @params[in] 
2325  * @return ROK     - success
2326  *         RFAILED - failure
2327  *
2328  * ****************************************************************/
2329 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2330 {
2331    uint8_t  ret = ROK;
2332    uint16_t ueId = 0, cellIdx = 0;
2333    SchUeCb *ueCb = NULLP;
2334    SchCellCb *cell = NULLP;
2335    Inst  inst = pst->dstInst-SCH_INST_START;   
2336
2337    if(!dlCqiInd)
2338    {
2339       DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): CQI Ind is empty");
2340       ret = RFAILED;
2341    }
2342    else
2343    {
2344       GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2345       cell = schCb[inst].cells[cellIdx];
2346       if(cell == NULLP)
2347       { 
2348          DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2349          ret = RFAILED;
2350       }
2351       else
2352       {
2353          if(cell->cellId == dlCqiInd->cellId)
2354          {
2355             GET_UE_ID(dlCqiInd->crnti, ueId);
2356             ueCb = &cell->ueCb[ueId-1];
2357             if(ueCb->crnti != dlCqiInd->crnti)
2358             {
2359                DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2360                ret = RFAILED;
2361             }
2362             else
2363             {
2364                /*TODO: complete the processing of DL CQI Ind*/ 
2365             }
2366          }
2367          else
2368          {
2369             DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2370                     dlCqiInd->cellId, cell->cellId);
2371             ret = RFAILED;
2372          }
2373       }
2374    }
2375    return ret;
2376 }
2377
2378 /*******************************************************************
2379  *
2380  * @brief Processes UL CQI ind from MAC
2381  *
2382  * @details
2383  *
2384  *    Function : SchProcUlCqiInd
2385  *
2386  *    Functionality:
2387  *       Processes UL CQI ind from MAC
2388  *
2389  * @params[in] 
2390  * @return ROK     - success
2391  *         RFAILED - failure
2392  *
2393  * ****************************************************************/
2394 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2395 {
2396    uint8_t  ret = ROK;
2397    uint16_t ueId = 0, cellIdx = 0;
2398    SchUeCb *ueCb = NULLP;
2399    SchCellCb *cell = NULLP;
2400    Inst  inst = pst->dstInst-SCH_INST_START;   
2401
2402    if(!ulCqiInd)
2403    {
2404       DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): CQI Ind is empty");
2405       ret = RFAILED;
2406    }
2407    else
2408    {
2409       GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2410       cell = schCb[inst].cells[cellIdx];
2411       if(cell == NULLP)
2412       { 
2413          DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2414          ret = RFAILED;
2415       }
2416       else
2417       {
2418          if(cell->cellId == ulCqiInd->cellId)
2419          {
2420             GET_UE_ID(ulCqiInd->crnti, ueId);
2421             ueCb = &cell->ueCb[ueId-1];
2422             if(ueCb->crnti != ulCqiInd->crnti)
2423             {
2424                DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2425                ret = RFAILED;
2426             }
2427             else
2428             {
2429                /*TODO: complete the processing of UL CQI Ind*/ 
2430             }
2431          }
2432          else
2433          {
2434             DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2435                     ulCqiInd->cellId, cell->cellId);
2436             ret = RFAILED;
2437          }
2438       }
2439    }
2440    return ret;
2441 }
2442
2443 /*******************************************************************
2444  *
2445  * @brief Processes PHR ind from MAC
2446  *
2447  * @details
2448  *
2449  *    Function : SchProcPhrInd
2450  *
2451  *    Functionality:
2452  *       Processes PHR ind from MAC
2453  *
2454  * @params[in] 
2455  * @return ROK     - success
2456  *         RFAILED - failure
2457  *
2458  * ****************************************************************/
2459 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2460 {
2461    uint8_t  ret = ROK;
2462    uint16_t ueId = 0, cellIdx = 0;
2463    SchUeCb *ueCb = NULLP;
2464    SchCellCb *cell = NULLP;
2465    Inst  inst = pst->dstInst-SCH_INST_START;   
2466
2467    if(!schPhrInd)
2468    {
2469       DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): PHR is empty");
2470       ret = RFAILED;
2471    }
2472    else
2473    {
2474       GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2475       cell = schCb[inst].cells[cellIdx];
2476       if(cell == NULLP)
2477       { 
2478          DU_LOG("\nERROR  -->  SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2479          ret = RFAILED;
2480       }
2481       else
2482       {
2483          if(cell->cellId == schPhrInd->cellId)
2484          {
2485             GET_UE_ID(schPhrInd->crnti, ueId);
2486             ueCb = &cell->ueCb[ueId-1];
2487             if(ueCb->crnti != schPhrInd->crnti)
2488             {
2489                DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2490                ret = RFAILED;
2491             }
2492             else
2493             {
2494                /*TODO: complete the processing of PHR Ind*/ 
2495             }
2496          }
2497          else
2498          {
2499             DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2500                     schPhrInd->cellId, cell->cellId);
2501             ret = RFAILED;
2502          }
2503       }
2504    }
2505    return ret;
2506 }
2507
2508 /*******************************************************************
2509  *
2510  * @brief Fill and send statistics response to MAC
2511  *
2512  * @details
2513  *
2514  *    Function :  SchSendStatsRspToMac
2515  *
2516  *    Functionality: Fill and send statistics response to MAC
2517  *
2518  * @params[in]  Inst inst, SchMacRsp result
2519  * @return ROK     - success
2520  *         RFAILED - failure
2521  *
2522  * ****************************************************************/
2523 uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
2524 {
2525    Pst rspPst;
2526    uint8_t ret = ROK;
2527    SchStatsRsp  *schStatsRsp;
2528
2529    DU_LOG("\nINFO   --> SCH : Filling statistics response");
2530    SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
2531    if(schStatsRsp == NULLP)
2532    {
2533       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2534       return RFAILED;
2535    }
2536  
2537    memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
2538    memset(statsRsp, 0, sizeof(SchStatsRsp));
2539
2540    /* Filling response post */
2541    memset(&rspPst, 0, sizeof(Pst));
2542    FILL_PST_SCH_TO_MAC(rspPst, inst);
2543    rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2544
2545    ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
2546    if(ret == RFAILED)
2547    {
2548       DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2549       return ret;
2550    }
2551    return ret;
2552 }
2553
2554 /*******************************************************************
2555  *
2556  * @brief Rejects all statistics group requested by MAC
2557  *
2558  * @details
2559  *
2560  *    Function : SchRejectAllStats
2561  *
2562  *    Functionality: Add all statistics group received in statistics
2563  *       request from MAC, to Reject-Stats-Group-List in statistics
2564  *       response to MAC
2565  *
2566  * @params[in]  Statistics request from MAC
2567  *              Cause of rejection
2568  * @return ROK     - success
2569  *         RFAILED - failure
2570  *
2571  * ****************************************************************/
2572 uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
2573 {
2574    uint8_t grpIdx = 0;
2575    SchStatsRsp schStatsRsp;
2576
2577    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2578
2579    /* Copying all stats group from stats request to stats response */
2580    schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
2581    for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
2582    {
2583       schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
2584       schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
2585    }
2586    schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
2587
2588    return SchSendStatsRspToMac(&schStatsRsp);
2589 }
2590
2591 /*******************************************************************
2592  *
2593  * @brief Add active KPI pointers to KPI-Active-List
2594  *
2595  * @details
2596  *
2597  *    Function : schAddToKpiActiveList
2598  *
2599  *    Functionality: For each active statistics group for which timer
2600  *       is running, add its KPI pointer to KPI-Active-List.
2601  *       Use case :
2602  *       When it is needed to update a KPI parameters, we need not
2603  *       traverse all statistics group and all KPIs within a group
2604  *       to get the specific KPI pointer to be updated.
2605  *       Instead, we can traverse through KPI-Active-List and update
2606  *       all entries in this list.
2607  *
2608  * @params[in]  Pointer to the prb usage info link list
2609  *              Pointer to the stats ccnfig which we need to add
2610  * @return ROK     - success
2611  *         RFAILED - failure
2612  *
2613  * ****************************************************************/
2614 uint8_t schAddToKpiActiveList(CmLListCp *kpiList, PTR kpiStatsInfo)
2615 {
2616    CmLList  *node = NULLP;
2617
2618    SCH_ALLOC(node, sizeof(CmLList));
2619    if(node)
2620    {
2621       node->node = kpiStatsInfo; 
2622       cmLListAdd2Tail(kpiList, node);
2623       return ROK;
2624    }
2625    DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2626    return RFAILED;
2627 }
2628
2629  /*******************************************************************
2630  *
2631  * @brief add the stats group information in statistics's statsGrpList
2632  *
2633  * @details
2634  *
2635  *    Function : schAddToStatsGrpList
2636  *
2637  *    Functionality: add the stats group information in statsGrpList
2638  *    [Step 1] - Allocating the memory for the stats group in which 
2639  *          we need to fill into the list as a node.
2640  *    [Step 2] - If allocation is successful then start traversing 
2641  *          each measurment cfg index of received group info.
2642  *       [Step 2.1] Validate all measurements. If validation succeeds, go
2643  *       to [step 2.2]. Otherwise, reject the stats group and go to step 3.
2644  *       [Step 2.2] Add each KPI/measurementCfg into activeKpiList one by one.
2645  *       If it fails for any KPI, reject the whole statsGrp and go to step 3..
2646  *       [Step 2.3] Fill other group related information
2647  *       [Step 2.4] Initialise and start timer
2648  *       [Step 2.5] Once all validation and configuration is successful, add
2649  *       statsGrp node into statistic's StatsGrpList.
2650  *          [Step 2.5.1] If node successfully added to the list, then 
2651  *             fill the group related info in stats rsp's accepted list.
2652  *          [Step 2.5.2] Else goto step 3
2653  *    [Step 3] - If failed fill the group related info in stats rsp's 
2654  *          rejected list.
2655  *
2656  * @params[in]  
2657  *          Inst
2658  *          Pointer to the stats rsp
2659  *          Subscription Id
2660  *          Stats Grp Info which needs to be store in the list
2661  * @return ROK     - success
2662  *         RFAILED - failure
2663  *
2664  * ****************************************************************/
2665
2666 uint8_t schAddToStatsGrpList(Inst inst, struct schStatsRsp *statsRsp, uint64_t subscriptionId, SchStatsGrpInfo *grpInfo)
2667 {
2668    uint8_t ret =ROK;
2669    uint8_t grpIdx=0;
2670    uint8_t reqMeasIdx=0;
2671    CauseOfResult cause;
2672    bool measTypeInvalid=false;
2673    CmLList *statsGrpNode=NULLP; 
2674    SchStatsGrp *grpInfoDb = NULLP;
2675    
2676    /* Step 1 */
2677    SCH_ALLOC(grpInfoDb, sizeof(SchStatsGrp));
2678    if(grpInfoDb == NULLP)
2679    {
2680       DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2681       cause = RESOURCE_UNAVAILABLE;
2682       ret = RFAILED;
2683    }
2684    else
2685    {
2686       /* Step 2 */
2687       for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
2688       {
2689          /* Step 2.1 */
2690          switch(grpInfo->statsList[reqMeasIdx])
2691          {
2692             case SCH_DL_TOTAL_PRB_USAGE:
2693                {
2694                   SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2695                   if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
2696                   {
2697                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2698                      measTypeInvalid = true;
2699                      cause = RESOURCE_UNAVAILABLE;
2700                      break;
2701                   }
2702                   break;
2703                }
2704
2705             case SCH_UL_TOTAL_PRB_USAGE:
2706                {
2707                   SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2708                   if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
2709                   {
2710                      DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at line %d",__func__, __LINE__);
2711                      measTypeInvalid = true;
2712                      cause = RESOURCE_UNAVAILABLE;
2713                      break;
2714                   }
2715                   break;
2716                }
2717
2718             default:
2719                {
2720                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Invalid measurement type [%d]", \
2721                         grpInfo->statsList[reqMeasIdx]);
2722                   measTypeInvalid = true;
2723                   cause = PARAM_INVALID;
2724                   break;
2725                }
2726          }
2727
2728          if(measTypeInvalid)
2729          {
2730             ret =RFAILED;
2731             break;
2732          }
2733       }
2734
2735       while(measTypeInvalid==false)
2736       {
2737          if(grpInfoDb->kpiStats.dlTotalPrbUsage)
2738          {
2739             /* Step 2.2 */
2740             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR)grpInfoDb->kpiStats.dlTotalPrbUsage)!=ROK)
2741             {
2742                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2743                cause = RESOURCE_UNAVAILABLE;
2744                ret =RFAILED;
2745                break;
2746             }
2747          }
2748
2749          if(grpInfoDb->kpiStats.ulTotalPrbUsage)
2750          {
2751             /* Step 2.2 */
2752             if(schAddToKpiActiveList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR)grpInfoDb->kpiStats.ulTotalPrbUsage) != ROK)
2753             {
2754                DU_LOG("\nERROR  -->  E2AP : KPI addition failed in %s at %d",__func__,__LINE__);
2755                cause = RESOURCE_UNAVAILABLE;
2756                ret =RFAILED;
2757                break;
2758             }
2759          }
2760
2761          /* Step 2.3 */
2762          grpInfoDb->schInst = inst;
2763          grpInfoDb->groupId = grpInfo->groupId;
2764          grpInfoDb->periodicity = grpInfo->periodicity;
2765          grpInfoDb->subscriptionId = subscriptionId;
2766
2767          /* Step 2.4 */
2768          cmInitTimers(&(grpInfoDb->periodTimer), 1);
2769          schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
2770
2771          /* Step 2.5 */
2772          SCH_ALLOC(statsGrpNode, sizeof(CmLList));
2773          if(statsGrpNode)
2774          {
2775             /* Step 2.5.1 */
2776             statsGrpNode->node = (PTR) grpInfoDb;
2777             cmLListAdd2Tail(&schCb[inst].statistics.statsGrpList, statsGrpNode);
2778             statsRsp->statsGrpAcceptedList[statsRsp->numGrpAccepted] = grpInfo->groupId;
2779             statsRsp->numGrpAccepted++;
2780             grpIdx++;
2781             ret =  ROK;
2782             break;
2783          }
2784          else
2785          {
2786             /* Step 2.5.2 */
2787             DU_LOG("\nERROR  -->  E2AP : Memory allocation failed in %s at %d",__func__,__LINE__);
2788             cause = RESOURCE_UNAVAILABLE;
2789             ret  = RFAILED;
2790             break;
2791          }
2792       }
2793    }
2794
2795    if(ret != ROK)
2796    {
2797       /* Step 3 */
2798       if(grpInfoDb)
2799       {
2800          deleteStatsGrpInfo(inst, grpInfoDb);      
2801          SCH_FREE(grpInfoDb, sizeof(SchStatsGrp));
2802       }
2803       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].groupId = grpInfo->groupId;
2804       statsRsp->statsGrpRejectedList[statsRsp->numGrpRejected].cause = cause;
2805       statsRsp->numGrpRejected++;
2806       return RFAILED;
2807    }
2808    return ROK;
2809 }
2810
2811 /*******************************************************************
2812  *
2813  * @brief Processes Statistics Request from MAC
2814  *
2815  * @details
2816  *
2817  *    Function : SchProcStatsReq
2818  *
2819  *    Functionality:
2820  *
2821  *     This function process the statistics request from MAC:
2822  *     [Step 1] Basic validation. If fails, all stats group in stats request are
2823  *     rejected.
2824  *     [Step 2] If basic validations passed, traverse all stats group and
2825  *     validate each measurement types in each group.
2826  *     [Step 3] If any measurement type validation fails in a group, that group
2827  *     is not configured and it is added to stats-group-rejected-list in
2828  *     sch-stats-response message.
2829  *     [Step 4] If a group passes all validation, it is added to SCH database.
2830  *     And the group is added to stats-group-accepted-list in sch-stats-response message.
2831  *     [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
2832  *     and stats-group-accepted-list.
2833  *
2834  * @params[in] Post structure
2835  *             Statistics Request from MAC 
2836  * @return ROK     - success
2837  *         RFAILED - failure
2838  *
2839  * ****************************************************************/
2840 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2841 {
2842    bool allocFailed = false;
2843    uint8_t grpIdx = 0, reqGrpIdx = 0;
2844    SchStatsGrpInfo *grpInfo = NULLP;
2845    SchStatsRsp schStatsRsp;
2846    Inst inst = pst->dstInst - SCH_INST_START;
2847
2848    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
2849
2850    if(statsReq == NULLP)
2851    {
2852       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Received Null pointer");
2853       return RFAILED;
2854    }
2855
2856    /*Step -1*/
2857    if(schCb[inst].statistics.statsGrpList.count >= MAX_NUM_STATS_GRP)
2858    {
2859       DU_LOG("\nERROR  -->  SCH : SchProcStatsReq: Maximum number of statistics configured. \
2860             Cannot process new request.");
2861       SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
2862       SCH_FREE(statsReq, sizeof(SchStatsReq));
2863       return RFAILED;
2864    }
2865
2866    memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
2867
2868    /*Step -2*/
2869    for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
2870    {
2871       grpInfo = &statsReq->statsGrpList[reqGrpIdx];
2872       /*Step -3 */
2873       if(allocFailed  == true)
2874       {
2875          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
2876          schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
2877          schStatsRsp.numGrpRejected++;
2878       }
2879       else
2880       {
2881          /*Step -4 */
2882          if(schAddToStatsGrpList(inst, &schStatsRsp, statsReq->subscriptionId, grpInfo) != ROK)
2883          {
2884             DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
2885             if((schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].groupId == grpInfo->groupId &&\
2886                      (schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)))
2887             { 
2888                allocFailed = true;
2889             }
2890          }
2891       }
2892    }
2893
2894    schStatsRsp.subscriptionId = statsReq->subscriptionId;
2895    SCH_FREE(statsReq, sizeof(SchStatsReq));
2896    
2897    /*Step -5 */
2898    SchSendStatsRspToMac(&schStatsRsp);
2899
2900    return ROK;
2901 }
2902
2903 /*******************************************************************
2904  *
2905  * @brief Fill and send statistics indication to MAC
2906  *
2907  * @details
2908  *
2909  *    Function :  SchSendStatsIndToMac
2910  *
2911  *    Functionality: Fill and send statistics indication to MAC
2912  *
2913  * @params[in]  SCH Instance
2914  *              Measurement Type
2915  *              Measurement Value
2916  *              Size of value parameter
2917  * @return ROK     - success
2918  *         RFAILED - failure
2919  *
2920  * ****************************************************************/
2921 uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd  *statsInd)
2922 {
2923    Pst pst;
2924    uint8_t ret = ROK;
2925
2926 #ifdef DEBUG_PRINT
2927    DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
2928 #endif
2929
2930    /* Filling post structure */
2931    memset(&pst, 0, sizeof(Pst));
2932    FILL_PST_SCH_TO_MAC(pst, inst);
2933    pst.event = EVENT_STATISTICS_IND_TO_MAC;
2934
2935    ret = MacMessageRouter(&pst, (void *)statsInd);
2936    if(ret == RFAILED)
2937    {
2938       DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2939    }
2940    return ret;
2941 }
2942
2943 /**
2944  * @brief Handler to process Timer expiry of DL Total PRB Usage calculation 
2945  *
2946  * @param[in] cb        Control block depending on the type of the timer event.
2947  * @param[in] tmrEvnt   Timer event to be started
2948  *
2949  * @return  Bool indicating whether the timer is running or not
2950  *      -# ROK
2951  *      -# RFAILED
2952 */
2953 double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
2954 {
2955    double percentageOfTotalPrbUsed = 0;
2956
2957    if(dlTotalPrbUsage->totalPrbAvailForTx)
2958       percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
2959    
2960    memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2961
2962    return percentageOfTotalPrbUsed;
2963 }
2964
2965 /**
2966  * @brief Handler to check if the timer is running
2967  *
2968  * @param[in] cb        Control block depending on the type of the timer event.
2969  * @param[in] tmrEvnt   Timer event to be started
2970  *
2971  * @return  Bool indicating whether the timer is running or not
2972  *      -# ROK
2973  *      -# RFAILED
2974 */
2975 uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
2976 {
2977    double percentageOfTotalPrbUsed = 0;
2978
2979    if(ulTotalPrbUsage->totalPrbAvailForTx)
2980       percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
2981
2982    memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2983
2984    return percentageOfTotalPrbUsed;
2985 }
2986
2987 /**
2988  * @brief Calculates statistics in a group and sends
2989  *          statistics indication for this group
2990  *
2991  * @param[in] Statistics group info
2992  *
2993  * @return
2994  *      -# ROK
2995  *      -# RFAILED
2996 */
2997 uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
2998 {
2999    uint8_t measStatsIdx = 0;
3000    SchStatsInd  statsInd;
3001
3002    memset(&statsInd, 0, sizeof(SchStatsInd));
3003    statsInd.subscriptionId = grpInfo->subscriptionId;
3004    statsInd.groupId = grpInfo->groupId;
3005
3006    if(grpInfo->kpiStats.dlTotalPrbUsage)
3007    {
3008       statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;  
3009       statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);   
3010       measStatsIdx++;
3011    }
3012    
3013    if(grpInfo->kpiStats.ulTotalPrbUsage)
3014    {
3015       statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;  
3016       statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);   
3017       measStatsIdx++;
3018    }
3019    
3020    statsInd.numStats = measStatsIdx;
3021
3022    return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
3023 }
3024
3025 /*******************************************************************
3026  *
3027  * @brief Delete node from active kpi list
3028  *
3029  * @details
3030  *
3031  *    Function :deleteNodeFrmKpiList 
3032  *
3033  *    Functionality:
3034  *    Delete statistics group
3035  *
3036  * @params[in]
3037  *           Kpi list from which a node needs to be deleted
3038  *           Nodes info which a node needs to be deleted
3039  * @return void
3040  * ****************************************************************/
3041
3042 void deleteNodeFrmKpiList(CmLListCp *kpiList, PTR kpiNodeInfoToDel)
3043 {
3044    CmLList *kpiNode=NULLP;
3045
3046    CM_LLIST_FIRST_NODE(kpiList, kpiNode);
3047    while(kpiNode)
3048    {
3049       if(kpiNode->node == kpiNodeInfoToDel)
3050       {
3051          cmLListDelFrm(kpiList, kpiNode);
3052          SCH_FREE(kpiNode, sizeof(CmLList));
3053          break;
3054       }
3055       kpiNode = kpiNode->next;
3056    }
3057
3058 }
3059
3060 /*******************************************************************
3061  *
3062  * @brief Delete statistics group info
3063  *
3064  * @details
3065  *
3066  *    Function : deleteStatsGrpInfo
3067  *
3068  *    Functionality:
3069  *    Delete statistics group info
3070  *
3071  * @params[in]
3072  *           Inst
3073  *           Stats Grp info
3074  * @return void
3075  *
3076  * ****************************************************************/
3077 void deleteStatsGrpInfo(Inst inst, SchStatsGrp *statsGrpInfo)
3078 {
3079    if(statsGrpInfo)
3080    {
3081       if(statsGrpInfo->kpiStats.dlTotalPrbUsage)
3082       {
3083          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, (PTR) statsGrpInfo->kpiStats.dlTotalPrbUsage);
3084          SCH_FREE(statsGrpInfo->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
3085       }
3086
3087       if(statsGrpInfo->kpiStats.ulTotalPrbUsage)
3088       {
3089          deleteNodeFrmKpiList(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, (PTR) statsGrpInfo->kpiStats.ulTotalPrbUsage);
3090          SCH_FREE(statsGrpInfo->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
3091       }
3092
3093       if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3094       {
3095          schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3096       }
3097
3098       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3099    }
3100 }
3101
3102 /*******************************************************************
3103  *
3104  * @brief Delete statistics group Node
3105  *
3106  * @details
3107  *
3108  *    Function : deleteStatsGrpNode
3109  *
3110  *    Functionality:
3111  *    Delete statistics group node
3112  *
3113  * @params[in]
3114  *           Inst
3115  *           Stats Grp Node
3116  * @return void
3117  *
3118  * ****************************************************************/
3119 void deleteStatsGrpNode(Inst inst, CmLList *grpNode)
3120 {
3121    SchStatsGrp *statsGrpInfo=NULLP;
3122
3123    if(grpNode)
3124    {
3125       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3126       deleteStatsGrpInfo(inst, statsGrpInfo);      
3127       memset(statsGrpInfo, 0, sizeof(SchStatsGrp));
3128       SCH_FREE(grpNode->node, sizeof(SchStatsGrp));
3129       SCH_FREE(grpNode, sizeof(CmLList));
3130    }
3131 }
3132
3133 /******************************************************************
3134  *
3135  * @brief Deletion of node from statistics group list
3136  *
3137  * @details
3138  *
3139  *    Function : deleteFromStatsGrpList
3140  *
3141  *    Functionality: Deletion of node from statistics group list
3142  *    [Step 1]: Traverse each and every node of stats group list
3143  *    stored in the database
3144  *    [Step 2]: Check if the node's subscription id is same 
3145  *    as the subscription id received. If same then go to step 3
3146  *    else move to the next node of the list.
3147  *    [Step 3]: If deleteAllGrp == true, then delete the node and 
3148  *    move to the next node of the list.
3149  *    [Step 4]: If deleteAllGrp != true, then check if the node's group
3150  *    id is same as group id received then delete the node and mark the 
3151  *    status found true else move to the next node of the list.
3152  *    [Step 5]: Once the traversing complete,  
3153  *    if deleteAllGrp is true, then return successful rsp;
3154  *    else if status found is true, then return  successful rsp;
3155  *    else return failure.
3156  * @params[in] 
3157  *           Inst
3158  *           Stats Grp List 
3159  *           Subscription Id
3160  *           Group Id
3161  *           boolen of deleteAllGrp
3162  * @return void
3163  *
3164  * ****************************************************************/
3165 uint8_t deleteFromStatsGrpList(Inst inst, CmLListCp *statsGrpList, uint64_t  subscriptionId, uint8_t  groupId, bool deleteAllGrp)
3166 {
3167    bool statsFound=false;
3168    SchStatsGrp *statsGrpInfo=NULLP;
3169    CmLList *grpNode=NULLP;
3170
3171    /* [Step 1] */
3172    CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3173    while(grpNode)
3174    {
3175       statsGrpInfo = (SchStatsGrp*)grpNode->node;
3176
3177       /* [Step 2] */
3178       if(statsGrpInfo->subscriptionId== subscriptionId) 
3179       {
3180          if(deleteAllGrp == true)
3181          {
3182             /* [Step 3] */
3183             cmLListDelFrm(statsGrpList, grpNode);
3184             deleteStatsGrpNode(inst, grpNode);
3185          }
3186          else
3187          {
3188             /* [Step 4] */
3189             if(statsGrpInfo->groupId== groupId) 
3190             {
3191                cmLListDelFrm(statsGrpList, grpNode);
3192                deleteStatsGrpNode(inst, grpNode);
3193                statsFound = true;
3194             }
3195          }
3196       }
3197       CM_LLIST_FIRST_NODE(statsGrpList, grpNode);
3198    }
3199
3200    /* [Step 5] */
3201    if(deleteAllGrp == true)
3202    {
3203       return ROK;
3204    }
3205    else
3206    {
3207       if(statsFound == true)
3208          return ROK;
3209    }
3210    return RFAILED;
3211 }
3212
3213 /*******************************************************************
3214  *
3215  * @brief Delete statistics information 
3216  *
3217  * @details
3218  *
3219  *    Function : deleteStatsInfo 
3220  *
3221  *    Functionality:
3222  *   Delete statistics information base on numStatsGroup 
3223  *   Info- If numStatsGroup = 0' indicates the Deletion procedure triggered by
3224  *   'SUBS_DELETION_REQ' wherein all the groups of this particular
3225  *   Subscription has to be removed 
3226  *   else when numStatsGroup != 0 then this is
3227  *   for SUBS_MOD_REQ's actionToBeDeleted wherein particular action(s) has
3228  *   to be removed thus need to pass groupId belonging to that subscription
3229  *   which has to be deleted.'
3230  *
3231  *   [Step-1] If numStatsGroup = 0, Deletion of all stats group belonging to
3232  *   received subscription Id.
3233  *   [Step-2] Else if numStatsGroup > 0, Deletion of individual stats group 
3234  *   from list whose information are present in stats delete request.
3235  *   [Step-3] Fill the result of the stats deletion in the SCH stats delete
3236  *   response
3237  * @params[in] 
3238  *             Instance
3239  *             Subscription delete req
3240  *             Subscription delete rsp
3241  * @return ROK     - success
3242  *         RFAILED - failure
3243  *
3244  * ****************************************************************/
3245 uint8_t deleteStatsInfo(Inst inst, SchStatsDeleteReq *statsDeleteReq, SchStatsDeleteRsp  *schStatsDeleteRsp)
3246 {
3247    uint8_t statsGrpIdx=0;
3248    CmLListCp  *statsGrpList =NULLP;
3249
3250    statsGrpList = &schCb[inst].statistics.statsGrpList;
3251    
3252    if(!statsDeleteReq->numStatsGroupToBeDeleted)
3253    {
3254       /* [Step-1] */
3255       if(deleteFromStatsGrpList(inst,statsGrpList, statsDeleteReq->subscriptionId, 0, true) == ROK)
3256       {
3257          /* [Step 3]*/
3258          schStatsDeleteRsp->subsDelRsp = RSP_OK;  
3259          schStatsDeleteRsp->subsDelCause = SUCCESSFUL;
3260       }
3261       else
3262       {
3263          /* [Step-3]*/
3264          schStatsDeleteRsp->subsDelRsp = RSP_NOK;  
3265          schStatsDeleteRsp->subsDelCause = STATS_ID_NOT_FOUND; 
3266       }
3267    }
3268    else
3269    {
3270       for(statsGrpIdx=0; statsGrpIdx<statsDeleteReq->numStatsGroupToBeDeleted; statsGrpIdx++)
3271       {
3272          /* [Step-2] */
3273          if(deleteFromStatsGrpList(inst, statsGrpList, statsDeleteReq->subscriptionId,\
3274                   statsDeleteReq->statsGrpIdToBeDelList[statsGrpIdx], false) == ROK)
3275          {
3276             /* [Step-3]*/
3277             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_OK;  
3278             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = SUCCESSFUL; 
3279          }
3280          else
3281          {
3282             /* [Step-3]*/
3283             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelRsp = RSP_NOK;  
3284             schStatsDeleteRsp->statsGrpDelInfo[statsGrpIdx].statsGrpDelCause = STATS_ID_NOT_FOUND; 
3285          }
3286       }
3287       schStatsDeleteRsp->numStatsGroupDeleted = statsDeleteReq->numStatsGroupToBeDeleted;
3288    }
3289    return ROK;
3290 }
3291
3292 /*******************************************************************
3293  *
3294  * @brief Processes Statistics Delete Request from MAC
3295  *
3296  * @details
3297  *
3298  *    Function : SchProcStatsDeleteReq
3299  *
3300  *    Functionality:
3301  *     This function process the statistics delete request from MAC:
3302  *
3303  * @params[in] Post structure
3304  *             Statistics Delete Request from MAC
3305  * @return ROK     - success
3306  *         RFAILED - failure
3307  *
3308  * ****************************************************************/
3309 uint8_t SchProcStatsDeleteReq(Pst *pst, SchStatsDeleteReq *statsDeleteReq)
3310 {
3311    Pst rspPst;
3312    uint8_t ret =ROK;
3313    SchStatsDeleteRsp  *schStatsDeleteRsp;
3314    Inst    inst = pst->dstInst - SCH_INST_START;
3315
3316    DU_LOG("\nINFO   -->  SCH : Received Statistics Delete Request from MAC");
3317
3318    if(statsDeleteReq == NULLP)
3319    {
3320       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Received Null pointer");
3321       return RFAILED;
3322    }
3323    
3324    /* Process Stats delete request and fill stats delete response simultaneously */
3325    SCH_ALLOC(schStatsDeleteRsp, sizeof(SchStatsDeleteRsp));
3326    if(schStatsDeleteRsp == NULLP)
3327    {
3328       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchProcStatsDeleteReq()");
3329       return RFAILED;
3330    }
3331    schStatsDeleteRsp->subscriptionId=statsDeleteReq->subscriptionId;
3332    deleteStatsInfo(inst, statsDeleteReq, schStatsDeleteRsp);
3333    
3334    memset(&rspPst, 0, sizeof(Pst));
3335    FILL_PST_SCH_TO_MAC(rspPst, inst);
3336    rspPst.event = EVENT_STATISTICS_DELETE_RSP_TO_MAC;
3337
3338    ret = MacMessageRouter(&rspPst, (void *)schStatsDeleteRsp);
3339    if(ret == RFAILED)
3340    {
3341       DU_LOG("\nERROR  -->  SCH : SchProcStatsDeleteReq(): Failed to send Statistics Response");
3342    }
3343    SCH_FREE(statsDeleteReq, sizeof(SchStatsDeleteReq));
3344
3345    return ret;
3346 } /* End of SchProcStatsDeleteReq */
3347
3348 /*******************************************************************
3349  *
3350  * @brief Fill and send statistics modification response to MAC
3351  *
3352  * @details
3353  *
3354  *    Function :  SchSendStatsRspToMac
3355  *
3356  *    Functionality: Fill and send statistics
3357  * modification response to MAC
3358  *
3359  * @params[in]  Inst inst, SchMacRsp result
3360  * @return ROK     - success
3361  *         RFAILED - failure
3362  *
3363  * ****************************************************************/
3364 uint8_t SchSendStatsModificationRspToMac(SchStatsModificationRsp *tmpSchStatsModRsp)
3365 {
3366    Pst rspPst;
3367    uint8_t ret = ROK;
3368    SchStatsModificationRsp  *schStatsModificationRsp=NULLP;
3369
3370    DU_LOG("\nINFO   --> SCH : Filling statistics modification response");
3371    SCH_ALLOC(schStatsModificationRsp, sizeof(SchStatsModificationRsp));
3372    if(schStatsModificationRsp == NULLP)
3373    {
3374       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsModificationRspToMac()");
3375       return RFAILED;
3376    }
3377
3378    memcpy(schStatsModificationRsp, tmpSchStatsModRsp, sizeof(SchStatsModificationRsp));
3379    memset(tmpSchStatsModRsp, 0, sizeof(SchStatsModificationRsp));
3380
3381    /* Filling response post */
3382    memset(&rspPst, 0, sizeof(Pst));
3383    FILL_PST_SCH_TO_MAC(rspPst, inst);
3384    rspPst.event = EVENT_STATISTICS_MODIFY_RSP_TO_MAC;
3385
3386    ret = MacMessageRouter(&rspPst, (void *)schStatsModificationRsp);
3387    if(ret == RFAILED)
3388    {
3389       DU_LOG("\nERROR  -->  SCH : SchSendStatsModificationRspToMac(): Failed to send Statistics Modification Response");
3390       return ret;
3391    }
3392    return ret;
3393 }
3394
3395 /*******************************************************************
3396  *
3397  * @brief Rejects all statistics modification group requested by MAC
3398  *
3399  * @details
3400  *
3401  *    Function : SchRejectAllStatsModification
3402  *
3403  *    Functionality: Add all statistics modification group received in statistics
3404  *       request from MAC, to Reject-StatsModification-Group-List in statistics
3405  *       response to MAC
3406  *
3407  * @params[in]  Statistics request from MAC
3408  *              Cause of rejection
3409  * @return ROK     - success
3410  *         RFAILED - failure
3411  *
3412  * ****************************************************************/
3413 uint8_t SchRejectAllStatsModification(SchStatsModificationReq *statsModificationReq, CauseOfResult cause)
3414 {
3415    uint8_t grpIdx = 0;
3416    SchStatsModificationRsp statsModificationRsp;
3417
3418    memset(&statsModificationRsp, 0, sizeof(SchStatsModificationRsp));
3419
3420    /* fill the subscriptionId and the rejected list in stats modification rsp */
3421    statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3422    for(grpIdx = 0; grpIdx < statsModificationReq->numStatsGroup; grpIdx++)
3423    {
3424       statsModificationRsp.statsGrpRejectedList[grpIdx].groupId = statsModificationReq->statsGrpList[grpIdx].groupId;
3425       statsModificationRsp.statsGrpRejectedList[grpIdx].cause = cause;
3426    }
3427    statsModificationRsp.numGrpRejected = statsModificationReq->numStatsGroup;
3428
3429    return SchSendStatsModificationRspToMac(&statsModificationRsp);
3430 }
3431
3432 /****************************************************************************************
3433 *
3434 * @brief Processes Statistics modification Request from MAC
3435 *
3436 * @details
3437 *
3438 *    Function :SchProcStatsModificationReq 
3439 *
3440 *    Functionality:
3441 *     This function process the statistics modification request from MAC:
3442 *     [Step -1] Check the stored stats group list empty.
3443 *        [Step - 1.1] If empty Send the rejected group list to MAC as a stats 
3444 *        modification response.
3445 *        [Step - 1.2] Else go to step 2.
3446 *     [Step -2] Traverse all stats group and validate each measurement types in
3447 *     each group.
3448 *     [Step -3] Check for any failure and if failed fill the remaining group's
3449 *     info in rejected list.
3450 *     [Step -4] Else Check if the received subscriptionId and groupId match the 
3451 *     values with the database node. 
3452 *        [Step -4.1] If  matches then follow the below mentioned steps.
3453 *           [Step -4.1.1] Stop the timer.
3454 *           [Step -4.1.2] Reconfigure stats group by adding a new entry for this
3455 *           statsGroup with updated configuration in database.
3456 *           [Step -4.1.3] if configured successfully, store stats info into
3457 *           stats mod rsp's accepted list, restart timer and go to step 4.1.4 
3458 *           [Step -4.1.4] Delete the old entry of this stats group..
3459 *        [Step -4.2] Else fill the group related info in stats modification rsp's 
3460 *           rejected list.
3461 *     [Step -5] Send the stats modification rsp to MAC
3462 * @params[in] Post structure
3463 *             Statistics modification Request from MAC
3464 * @return ROK     - success
3465 *         RFAILED - failure
3466 *
3467 * *******************************************************************************************/
3468 uint8_t SchProcStatsModificationReq(Pst *pst, SchStatsModificationReq *statsModificationReq)
3469 {
3470    Inst inst;
3471    uint8_t reqGrpIdx=0;
3472    uint64_t subscriptionId =0;
3473    bool allocFailed = false;
3474    bool statsGrpFound= false;
3475    CmLList *grpNode = NULLP;
3476    SchStatsGrp *statsGrpInfo=NULLP;
3477    SchStatsGrpInfo statsGrpToModify;
3478    SchStatsModificationRsp statsModificationRsp;
3479
3480    inst=pst->dstInst - SCH_INST_START;
3481
3482    DU_LOG("\nINFO   -->  SCH : Received Statistics modification request from MAC");
3483
3484    if(statsModificationReq == NULLP)
3485    {
3486       DU_LOG("\nERROR  -->  SCH : SchProcStatsModificationReq(): Received Null pointer");
3487       return RFAILED;
3488    }
3489    memset(&statsModificationRsp, 0, sizeof(SchStatsRsp));
3490
3491    /* [Step -1] */
3492    if(schCb[inst].statistics.statsGrpList.count)
3493    {
3494       /* [Step -1.2] */
3495       subscriptionId = statsModificationReq->subscriptionId;
3496
3497       /* [Step - 2] */
3498       for(reqGrpIdx=0; reqGrpIdx<statsModificationReq->numStatsGroup; reqGrpIdx++)
3499       {
3500          /* [Step - 3] */
3501          statsGrpToModify = statsModificationReq->statsGrpList[reqGrpIdx];
3502          if(allocFailed  != true)
3503          {
3504             CM_LLIST_FIRST_NODE(&schCb[inst].statistics.statsGrpList, grpNode);
3505             while(grpNode)
3506             {
3507                /* [Step - 4] */
3508                statsGrpInfo = (SchStatsGrp*)grpNode->node;
3509                if((statsGrpInfo->subscriptionId== subscriptionId) && (statsGrpInfo->groupId== statsGrpToModify.groupId))
3510                {
3511                   statsGrpFound= true;
3512                   break; 
3513                }
3514                grpNode = grpNode->next;
3515             }
3516
3517             /* [Step - 4.1] */
3518             if(statsGrpFound== true)
3519             {
3520                /* [Step - 4.1.1] */
3521                if(schChkTmr((PTR)statsGrpInfo, EVENT_STATISTICS_TMR) == true)
3522                {
3523                   schStopTmr(&schCb[inst], (PTR)statsGrpInfo, EVENT_STATISTICS_TMR);
3524                }
3525
3526                /* [Step - 4.1.2] */
3527                if(schAddToStatsGrpList(inst, &statsModificationRsp, subscriptionId, &statsGrpToModify) != ROK)
3528                {
3529                   DU_LOG("\nERROR  -->  SCH : SchProcStatsReq(): Failed to fill the stats group list");
3530                   if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].groupId == statsGrpToModify.groupId)
3531                   {
3532                      /* [Step - 4.1.3] */
3533                      schStartTmr(&schCb[inst], (PTR)(statsGrpInfo), EVENT_STATISTICS_TMR, statsGrpInfo->periodicity);
3534                      if(statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected-1].cause == RESOURCE_UNAVAILABLE)
3535                      {
3536                         allocFailed = true;
3537                         break;
3538                      }
3539                   }
3540                }
3541                else
3542                {
3543                   /* [Step - 4.1.4] */
3544                   deleteStatsGrpNode(inst, grpNode);
3545                }
3546             }
3547             else
3548             {
3549                /* [Step - 4.2] */
3550                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3551                statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = STATS_ID_NOT_FOUND;
3552                statsModificationRsp.numGrpRejected++;
3553             }
3554          }
3555          else
3556          {
3557             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].groupId = statsGrpToModify.groupId;
3558             statsModificationRsp.statsGrpRejectedList[statsModificationRsp.numGrpRejected].cause = RESOURCE_UNAVAILABLE;
3559             statsModificationRsp.numGrpRejected++;
3560          }
3561       }
3562
3563       statsModificationRsp.subscriptionId = statsModificationReq->subscriptionId;
3564       SchSendStatsModificationRspToMac(&statsModificationRsp);
3565    }
3566    else
3567    {
3568       /* [Step -1.1] */
3569       SchRejectAllStatsModification(statsModificationReq, STATS_ID_NOT_FOUND);
3570    }
3571    SCH_FREE(statsModificationReq, sizeof(SchStatsModificationReq));
3572    return ROK;
3573 }
3574 /**********************************************************************
3575   End of file
3576  **********************************************************************/