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