[Epic-ID: ODUHIGH-516][Task-ID: ODUHIGH-523] Statistics Indication between DU APP...
[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    /* Set Config done in TskInit */
135    schCb[inst].schInit.cfgDone = TRUE;
136    DU_LOG("\nINFO   -->  SCH : Scheduler gen config done");
137    
138    schAllApisInit(inst);
139    return ret;
140 }
141
142 /**
143  * @brief Layer Manager Configuration request handler. 
144  *
145  * @details
146  *
147  *     Function : SchProcGenCfgReq
148  *     
149  *     This function handles the configuration
150  *     request received at scheduler instance from the Layer Manager.
151  *     -# Based on the cfg->hdr.elmId.elmnt value it invokes one of the
152  *        functions rgHdlGenCfg() or rgHdlSapCfg().
153  *     -# Invokes RgMiLrgSchCfgCfm() to send back the confirmation to the LM.
154  *     
155  *  @param[in]  Pst *pst, the post structure     
156  *  @param[in]  RgMngmt *cfg, the configuration parameter's structure
157  *  @return  S16
158  *      -# ROK
159  **/
160 uint8_t SchProcGenCfgReq(Pst *pst, RgMngmt *cfg)
161 {
162    uint8_t   ret = LCM_PRIM_OK;
163    uint16_t  reason = LCM_REASON_NOT_APPL;
164    RgMngmt   cfm;
165    Pst       cfmPst;
166
167    if(pst->dstInst < SCH_INST_START)
168    {
169       DU_LOG("\nERROR  -->  SCH : Invalid inst ID");
170       DU_LOG("\nERROR  -->  SCH : SchProcGenCfgReq(): "
171             "pst->dstInst=%d SCH_INST_START=%d", pst->dstInst,SCH_INST_START); 
172       return ROK;
173    }
174    DU_LOG("\nINFO   -->  SCH : Received scheduler gen config");
175    /* Fill the post structure for sending the confirmation */
176    memset(&cfmPst, 0 , sizeof(Pst));
177    SchFillCfmPst(pst, &cfmPst, cfg);
178
179    memset(&cfm, 0, sizeof(RgMngmt));
180
181 #ifdef LMINT3
182    cfm.hdr.transId =
183       cfg->hdr.transId;
184 #endif
185
186    cfm.hdr.elmId.elmnt = cfg->hdr.elmId.elmnt;
187    switch(cfg->hdr.elmId.elmnt)
188    {
189       case STSCHINST:
190          reason = SchInstCfg(&cfg->t.cfg,pst->dstInst );
191          break;
192       default:
193          ret = LCM_PRIM_NOK;
194          reason = LCM_REASON_INVALID_ELMNT;
195          DU_LOG("\nERROR  -->  SCH : Invalid Elmnt=%d", cfg->hdr.elmId.elmnt);
196          break;
197    }
198
199    if (reason != LCM_REASON_NOT_APPL)
200    {
201       ret = LCM_PRIM_NOK;
202    }
203
204    cfm.cfm.status = ret;
205    cfm.cfm.reason = reason;
206
207    SchSendCfgCfm(&cfmPst, &cfm);
208    /*   SCH_FREE(pst->region, pst->pool, (Data *)cfg, sizeof(RgMngmt)); */
209
210    return ROK;
211 }/*-- SchProcGenCfgReq --*/
212
213 #ifdef NR_TDD
214 /**
215  *@brief Returns TDD periodicity in micro seconds
216  *
217  * @details
218  * 
219  * Function : schGetPeriodicityInMsec 
220  * 
221  * This API retunrs TDD periodicity in micro seconds
222  * 
223  * @param[in] DlUlTxPeriodicity 
224  * @return  periodicityInMsec
225  * **/
226
227 uint16_t schGetPeriodicityInMsec(DlUlTxPeriodicity tddPeriod)
228 {
229    uint16_t  periodicityInMsec = 0;
230    switch(tddPeriod)
231    {
232       case TX_PRDCTY_MS_0P5:
233       {
234          periodicityInMsec = 500;
235          break;
236       }
237       case TX_PRDCTY_MS_0P625:
238       {
239          periodicityInMsec = 625;
240          break;
241       }
242       case TX_PRDCTY_MS_1:
243       {
244          periodicityInMsec = 1000;
245          break;
246       }
247       case TX_PRDCTY_MS_1P25:
248       {
249          periodicityInMsec = 1250;
250          break;
251       }
252       case TX_PRDCTY_MS_2:
253       {
254          periodicityInMsec = 2000;
255          break;
256       }
257       case TX_PRDCTY_MS_2P5:
258       {
259          periodicityInMsec = 2500;
260          break;
261       }
262       case TX_PRDCTY_MS_5:
263       {
264          periodicityInMsec = 5000;
265          break;
266       }
267       case TX_PRDCTY_MS_10:
268       {
269          periodicityInMsec = 10000;
270          break;
271       }
272       default:
273       {
274          DU_LOG("\nERROR  -->  SCH : Invalid DlUlTxPeriodicity:%d", tddPeriod);
275       }
276    }
277
278    return periodicityInMsec;
279 }
280
281 /**
282  *@brief Fills the slotCfg from CellCfg
283  *
284  * @details
285  * 
286  * Function : schFillSlotConfig 
287  * 
288  * This API Fills the slotCfg from CellCfg
289  * 
290  * @param[in] SchCellCb *cell, TDDCfg tddCfg
291  * @return  void
292  * **/
293 void schFillSlotConfig(SchCellCb *cell, TDDCfg tddCfg)
294 {
295    uint8_t slotIdx = 0, symbolIdx = 0;
296
297    for(slotIdx =0 ;slotIdx < MAX_TDD_PERIODICITY_SLOTS; slotIdx++) 
298    {
299       for(symbolIdx = 0; symbolIdx < MAX_SYMB_PER_SLOT; symbolIdx++)
300       {
301          /*Fill Full-DL Slots as well as DL symbols ini 1st Flexi Slo*/
302          if(slotIdx < tddCfg.nrOfDlSlots || \
303                (slotIdx == tddCfg.nrOfDlSlots && symbolIdx < tddCfg.nrOfDlSymbols)) 
304          {
305               cell->slotCfg[slotIdx][symbolIdx] = DL_SYMBOL; 
306          }
307
308          /*Fill Full-FLEXI SLOT and as well as Flexi Symbols in 1 slot preceding FULL-UL slot*/ 
309          else if(slotIdx < (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) ||  \
310                (slotIdx == (MAX_TDD_PERIODICITY_SLOTS - tddCfg.nrOfUlSlots -1) && \
311                 symbolIdx < (MAX_SYMB_PER_SLOT - tddCfg.nrOfUlSymbols)))
312          {
313               cell->slotCfg[slotIdx][symbolIdx] = FLEXI_SYMBOL; 
314          }
315          /*Fill Partial UL symbols and Full-UL slot*/
316          else
317          {
318               cell->slotCfg[slotIdx][symbolIdx] = UL_SYMBOL; 
319          }
320       }
321    }
322 }
323
324 /**
325  * @brief init TDD slot config 
326  *
327  * @details
328  *
329  *     Function : schInitTddSlotCfg 
330  *      
331  *      This API is invoked after receiving schCellCfg
332  *           
333  *  @param[in]  schCellCb *cell
334  *  @param[in]  SchCellCfg *schCellCfg
335  *  @return  void
336  **/
337 void schInitTddSlotCfg(SchCellCb *cell, SchCellCfg *schCellCfg)
338 {
339    uint16_t periodicityInMicroSec = 0;
340    int8_t slotIdx, symbIdx;
341
342    periodicityInMicroSec = schGetPeriodicityInMsec(schCellCfg->tddCfg.tddPeriod);
343    cell->numSlotsInPeriodicity = (periodicityInMicroSec * pow(2, cell->numerology))/1000;
344    cell->slotFrmtBitMap = 0;
345    schFillSlotConfig(cell, schCellCfg->tddCfg);
346    for(slotIdx = cell->numSlotsInPeriodicity-1; slotIdx >= 0; slotIdx--)
347    {
348       symbIdx = 0;
349       /* If the first and last symbol are the same, the entire slot is the same type */
350       if((cell->slotCfg[slotIdx][symbIdx] == cell->slotCfg[slotIdx][MAX_SYMB_PER_SLOT-1]) &&
351               cell->slotCfg[slotIdx][symbIdx] != FLEXI_SYMBOL)
352       {
353          switch(cell->slotCfg[slotIdx][symbIdx])
354          {
355             case DL_SLOT:
356             {
357                /*BitMap to be set to 00 */
358                cell->slotFrmtBitMap = (cell->slotFrmtBitMap<<2);
359                break;
360             }
361             case UL_SLOT:
362             {
363                /*BitMap to be set to 01 */
364                cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (UL_SLOT));
365                break;
366             }
367             default:
368                DU_LOG("\nERROR  -->  SCH : Invalid slot Config in schInitTddSlotCfg");
369            }
370          continue;
371       }
372       /* slot config is flexible. First set slotBitMap to 10 */
373       cell->slotFrmtBitMap = ((cell->slotFrmtBitMap<<2) | (FLEXI_SLOT));
374    }
375 }
376 #endif
377
378 /**
379  * @brief Fill SSB start symbol
380  *
381  * @details
382  *
383  *     Function : fillSsbStartSymb 
384  *      
385  *      This API stores SSB start index per beam
386  *           
387  *  @param[in]  SchCellCb     *cellCb
388  *  @return  int
389  *      -# ROK 
390  *      -# RFAILED 
391  **/
392 void fillSsbStartSymb(SchCellCb *cellCb)
393 {
394    uint8_t cnt, scs, symbIdx, ssbStartSymbArr[SCH_MAX_SSB_BEAM];
395
396    scs = cellCb->cellCfg.ssbScs;
397
398    memset(ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
399    symbIdx = 0;
400    /* Determine value of "n" based on Section 4.1 of 3GPP TS 38.213 */
401    switch(scs)
402    {
403       case SCS_15KHZ:
404          {
405             if(cellCb->cellCfg.ssbFrequency <= 300000)
406                cnt = 2;/* n = 0, 1 */
407             else
408                cnt = 4; /* n = 0, 1, 2, 3 */
409             for(uint8_t idx=0; idx<cnt; idx++)
410             {
411                /* start symbol determined using {2, 8} + 14n */
412                ssbStartSymbArr[symbIdx++] = 2 +  MAX_SYMB_PER_SLOT*idx;
413                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
414             }
415          }
416          break;
417       case SCS_30KHZ:
418          {
419             if(cellCb->cellCfg.ssbFrequency <= 300000)
420                cnt = 1;/* n = 0 */
421             else
422                cnt = 2; /* n = 0, 1 */
423             for(uint8_t idx=0; idx<cnt; idx++)
424             {
425                /* start symbol determined using {4, 8, 16, 20} + 28n */
426                ssbStartSymbArr[symbIdx++] = 4 +  MAX_SYMB_PER_SLOT*idx;
427                ssbStartSymbArr[symbIdx++] = 8 +  MAX_SYMB_PER_SLOT*idx;
428                ssbStartSymbArr[symbIdx++] = 16 +  MAX_SYMB_PER_SLOT*idx;
429                ssbStartSymbArr[symbIdx++] = 20 +  MAX_SYMB_PER_SLOT*idx;
430             }
431          }
432          break;
433       default:
434          DU_LOG("\nERROR  -->  SCH : SCS %d is currently not supported", scs);
435    }
436    memset(cellCb->ssbStartSymbArr, 0, sizeof(SCH_MAX_SSB_BEAM));
437    memcpy(cellCb->ssbStartSymbArr, ssbStartSymbArr, SCH_MAX_SSB_BEAM);
438 }
439
440
441 /**
442  * @brief init cellCb based on cellCfg
443  *
444  * @details
445  *
446  *     Function : schInitCellCb 
447  *      
448  *      This API is invoked after receiving schCellCfg
449  *           
450  *  @param[in]  schCellCb *cell
451  *  @param[in]  SchCellCfg *schCellCfg
452  *  @return  int
453  *      -# ROK 
454  *      -# RFAILED 
455  **/
456 uint8_t schInitCellCb(Inst inst, SchCellCfg *schCellCfg)
457 {
458    uint16_t scsInKhz = 0;
459    SchCellCb *cell= NULLP;
460    SCH_ALLOC(cell, sizeof(SchCellCb));
461    if(!cell)
462    {
463       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
464       return RFAILED;
465    }
466
467    cell->cellId = schCellCfg->cellId; 
468    cell->instIdx = inst;
469    scsInKhz = convertScsEnumValToScsVal(schCellCfg->ssbScs);
470    
471    /*Ref : 3GPP 38.211 Table 4.2-1: SCS = (2 ^ numerology * 15kHz)*/
472    cell->numerology = log2(scsInKhz/BASE_SCS);
473    switch(cell->numerology)
474    {
475       case SCH_NUMEROLOGY_0:
476          {
477             cell->numSlots = SCH_MU0_NUM_SLOTS;
478          }
479          break;
480       case SCH_NUMEROLOGY_1:
481          {
482             cell->numSlots = SCH_MU1_NUM_SLOTS;
483          }
484          break;
485       case SCH_NUMEROLOGY_2:
486          {
487             cell->numSlots = SCH_MU2_NUM_SLOTS;
488          }
489          break;
490       case SCH_NUMEROLOGY_3:
491          {
492             cell->numSlots = SCH_MU3_NUM_SLOTS;
493          }
494          break;
495       case SCH_NUMEROLOGY_4:
496          {
497             cell->numSlots = SCH_MU4_NUM_SLOTS;
498          }
499          break;
500       default:
501          DU_LOG("\nERROR  -->  SCH : Numerology %d not supported", cell->numerology);
502    }
503 #ifdef NR_TDD
504    schInitTddSlotCfg(cell, schCellCfg);   
505 #endif
506
507    SCH_ALLOC(cell->schDlSlotInfo, cell->numSlots * sizeof(SchDlSlotInfo*));
508    if(!cell->schDlSlotInfo)
509    {
510       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schDlSlotInfo");
511       return RFAILED;
512    }
513
514    SCH_ALLOC(cell->schUlSlotInfo, cell->numSlots * sizeof(SchUlSlotInfo*));
515    if(!cell->schUlSlotInfo)
516    {
517       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb for schUlSlotInfo");
518       return RFAILED;
519    }
520
521    for(uint8_t idx=0; idx<cell->numSlots; idx++)
522    {
523       SchDlSlotInfo *schDlSlotInfo;
524       SchUlSlotInfo *schUlSlotInfo;
525
526       /* DL Alloc */
527       SCH_ALLOC(schDlSlotInfo, sizeof(SchDlSlotInfo));
528       if(!schDlSlotInfo)
529       {
530          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
531          return RFAILED;
532       }
533
534       /* UL Alloc */
535       SCH_ALLOC(schUlSlotInfo, sizeof(SchUlSlotInfo));
536       if(!schUlSlotInfo)
537       {
538          DU_LOG("\nERROR  -->  SCH : Memory allocation failed in schInitCellCb");
539          return RFAILED;
540       }
541
542       schInitDlSlot(schDlSlotInfo);
543       schInitUlSlot(schUlSlotInfo);
544
545       cell->schDlSlotInfo[idx] = schDlSlotInfo;
546       cell->schUlSlotInfo[idx] = schUlSlotInfo;
547
548    }
549    cell->firstSsbTransmitted = false;
550    cell->firstSib1Transmitted = false;
551    fillSsbStartSymb(cell);
552
553 #ifdef NR_DRX
554    memset(cell->drxCb, 0, MAX_DRX_SIZE*sizeof(SchDrxCb));
555 #endif   
556    schCb[inst].cells[inst] = cell;
557
558    DU_LOG("\nINFO  -->  SCH : Cell init completed for cellId:%d", cell->cellId);
559
560    return ROK;   
561 }
562
563 /**
564  * @brief Fill SIB1 configuration
565  *
566  * @details
567  *
568  *     Function : fillSchSib1Cfg
569  *
570  *     Fill SIB1 configuration
571  *
572  *  @param[in]  uint8_t bandwidth : total available bandwidth
573  *              uint8_t numSlots : total slots per SFN
574  *              SchSib1Cfg *sib1SchCfg : cfg to be filled
575  *              uint16_t pci : physical cell Id
576  *              uint8_t offsetPointA : offset
577  *  @return  void
578  **/
579 uint8_t fillSchSib1Cfg(uint8_t mu, uint8_t bandwidth, uint8_t numSlots,SchPdcchConfigSib1 *pdcchCfgSib1,\
580                SchSib1Cfg *sib1SchCfg, uint16_t pci, uint8_t offsetPointA, uint16_t sib1PduLen)
581 {
582    uint8_t coreset0Idx = 0;
583    uint8_t searchSpace0Idx = 0;
584    //uint8_t ssbMuxPattern = 0;
585    uint8_t numRbs = 0;
586    uint8_t numSymbols = 0;
587    uint8_t offset = 0;
588    uint8_t oValue = 0;
589    //uint8_t numSearchSpacePerSlot = 0;
590    uint8_t mValue = 0;
591    uint8_t firstSymbol = 0; /* need to calculate using formula mentioned in 38.213 */
592    uint8_t slotIndex = 0;
593    uint8_t FreqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
594    uint16_t tbSize = 0;
595    uint8_t ssbIdx = 0;
596    PdcchCfg *pdcch;
597    PdschCfg *pdsch;
598    BwpCfg *bwp;
599
600    pdcch = &(sib1SchCfg->sib1PdcchCfg);
601    bwp = &(sib1SchCfg->bwp);
602
603    coreset0Idx     = pdcchCfgSib1->coresetZeroIndex;
604    searchSpace0Idx = pdcchCfgSib1->searchSpaceZeroIndex;
605
606    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
607    //ssbMuxPattern = coresetIdxTable[coreset0Idx][0];
608    numRbs        = coresetIdxTable[coreset0Idx][1];
609    numSymbols    = coresetIdxTable[coreset0Idx][2];
610    offset        = coresetIdxTable[coreset0Idx][3];
611
612    /* derive the search space params from table 13-11 spec 38.213 */
613    oValue                = searchSpaceIdxTable[searchSpace0Idx][0];
614    //numSearchSpacePerSlot = searchSpaceIdxTable[searchSpace0Idx][1];
615    mValue                = searchSpaceIdxTable[searchSpace0Idx][2];
616    firstSymbol           = searchSpaceIdxTable[searchSpace0Idx][3];
617
618    /* calculate the n0, need to add the formulae, as of now the value is 0 
619     * Need to add the even and odd values of i during configuration 
620     * [(O . 2^u + i . M )  ] mod numSlotsPerSubframe 
621     * assuming u = 0, i = 0, numSlotsPerSubframe = 10
622     * Also, from this configuration, coreset0 is only on even subframe */
623    slotIndex = (int)((oValue*pow(2, mu)) + floor(ssbIdx*mValue))%numSlots;
624    sib1SchCfg->n0 = slotIndex;
625
626    /* fill BWP */
627    switch(bandwidth)
628    {
629       case BANDWIDTH_20MHZ:
630          {
631             bwp->freqAlloc.numPrb = TOTAL_PRB_20MHZ_MU0;
632          }
633          break;
634       case BANDWIDTH_100MHZ:
635          {
636             bwp->freqAlloc.numPrb = TOTAL_PRB_100MHZ_MU1;
637          }
638          break;
639       default:
640          DU_LOG("\nERROR  -->  SCH : Bandwidth %d not supported", bandwidth);
641
642    }
643    bwp->freqAlloc.startPrb = 0;
644    bwp->subcarrierSpacing  = 0;         /* 15Khz */
645    bwp->cyclicPrefix       = 0;              /* normal */
646
647    /* fill the PDCCH PDU */
648    pdcch->coresetCfg.coreSetSize = numRbs;
649    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
650    pdcch->coresetCfg.durationSymbols = numSymbols;
651    
652    /* Fill Bitmap for PRBs in coreset */
653    fillCoresetFeqDomAllocMap(((offsetPointA-offset)/6), (numRbs/6), FreqDomainResource);
654    covertFreqDomRsrcMapToIAPIFormat(FreqDomainResource, pdcch->coresetCfg.freqDomainResource);
655
656    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
657    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
658    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
659    pdcch->coresetCfg.coreSetType = 0;
660    pdcch->coresetCfg.shiftIndex = pci;
661    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
662    pdcch->numDlDci = 1;
663    pdcch->dci.rnti = SI_RNTI;
664    pdcch->dci.scramblingId = pci;
665    pdcch->dci.scramblingRnti = 0;
666    pdcch->dci.cceIndex = 0;
667    pdcch->dci.aggregLevel = 4;
668    pdcch->dci.beamPdcchInfo.numPrgs = 1;
669    pdcch->dci.beamPdcchInfo.prgSize = 1;
670    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
671    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
672    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
673    pdcch->dci.txPdcchPower.beta_pdcch_1_0= 0;
674    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
675    /* Storing pdschCfg pointer here. Required to access pdsch config while
676       fillig up pdcch pdu */
677    pdsch = &pdcch->dci.pdschCfg; 
678
679    /* fill the PDSCH PDU */
680    uint8_t cwCount = 0;
681    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
682    pdsch->rnti = 0xFFFF; /* SI-RNTI */
683    pdsch->pduIndex = 0;
684    pdsch->numCodewords = 1;
685    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
686    {
687       pdsch->codeword[cwCount].targetCodeRate = 308;
688       pdsch->codeword[cwCount].qamModOrder = 2;
689       pdsch->codeword[cwCount].mcsIndex = DEFAULT_MCS;
690       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
691       pdsch->codeword[cwCount].rvIndex = 0;
692       tbSize = schCalcTbSize(sib1PduLen + TX_PAYLOAD_HDR_LEN);
693       pdsch->codeword[cwCount].tbSize = tbSize;
694    }
695    pdsch->dataScramblingId                   = pci;
696    pdsch->numLayers                          = 1;
697    pdsch->transmissionScheme                 = 0;
698    pdsch->refPoint                           = 0;
699    pdsch->dmrs.dlDmrsSymbPos                 = DL_DMRS_SYMBOL_POS; 
700    pdsch->dmrs.dmrsConfigType                = 0; /* type-1 */
701    pdsch->dmrs.dlDmrsScramblingId            = pci;
702    pdsch->dmrs.scid                          = 0;
703    pdsch->dmrs.numDmrsCdmGrpsNoData          = 1;
704    pdsch->dmrs.dmrsPorts                     = 0x0001;
705    pdsch->dmrs.mappingType                   = DMRS_MAP_TYPE_A; /* Type-A */
706    pdsch->dmrs.nrOfDmrsSymbols               = NUM_DMRS_SYMBOLS;
707    pdsch->dmrs.dmrsAddPos                    = DMRS_ADDITIONAL_POS;
708
709    pdsch->pdschFreqAlloc.resourceAllocType   = 1; /* RAT type-1 RIV format */
710    /* the RB numbering starts from coreset0, and PDSCH is always above SSB */
711    pdsch->pdschFreqAlloc.startPrb  = offsetPointA + SCH_SSB_NUM_PRB;
712    pdsch->pdschFreqAlloc.numPrb    = schCalcNumPrb(tbSize, DEFAULT_MCS, NUM_PDSCH_SYMBOL);
713    pdsch->pdschFreqAlloc.vrbPrbMapping       = 0; /* non-interleaved */
714    pdsch->pdschTimeAlloc.rowIndex            = 1;
715    /* This is Intel's requirement. PDSCH should start after PDSCH DRMS symbol */
716    pdsch->pdschTimeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
717    pdsch->pdschTimeAlloc.numSymb   = NUM_PDSCH_SYMBOL;
718    pdsch->beamPdschInfo.numPrgs              = 1;
719    pdsch->beamPdschInfo.prgSize              = 1;
720    pdsch->beamPdschInfo.digBfInterfaces      = 0;
721    pdsch->beamPdschInfo.prg[0].pmIdx         = 0;
722    pdsch->beamPdschInfo.prg[0].beamIdx[0]    = 0;
723    pdsch->txPdschPower.powerControlOffset    = 0;
724    pdsch->txPdschPower.powerControlOffsetSS  = 0;
725
726    return ROK;
727 }
728
729 /**
730  * @brief cell config from MAC to SCH.
731  *
732  * @details
733  *
734  *     Function : macSchCellCfgReq
735  *      
736  *      This API is invoked by MAC to send cell config to SCH
737  *           
738  *  @param[in]  Pst            *pst
739  *  @param[in]  SchCellCfg     *schCellCfg
740  *  @return  int
741  *      -# ROK 
742  *      -# RFAILED 
743  **/
744 uint8_t SchProcCellCfgReq(Pst *pst, SchCellCfg *schCellCfg)
745 {
746    uint8_t ret = ROK;
747    SchCellCb *cellCb;
748    SchCellCfgCfm schCellCfgCfm;
749    Pst rspPst;
750    Inst inst = pst->dstInst - SCH_INST_START; 
751    uint8_t coreset0Idx = 0;
752    uint8_t numRbs = 0;
753    uint8_t offset = 0;
754    uint8_t freqDomainResource[FREQ_DOM_RSRC_SIZE] = {0};
755    SchPdschConfig pdschCfg;
756
757    schInitCellCb(inst, schCellCfg);
758    cellCb = schCb[inst].cells[inst]; //cells is of MAX_CELLS, why inst
759    cellCb->macInst = pst->srcInst;
760
761    /* derive the SIB1 config parameters */
762    ret = fillSchSib1Cfg(cellCb->numerology, schCellCfg->dlBandwidth, cellCb->numSlots,
763          &(schCellCfg->pdcchCfgSib1), &(cellCb->sib1SchCfg), schCellCfg->phyCellId,
764          schCellCfg->dlCfgCommon.schFreqInfoDlSib.offsetToPointA, schCellCfg->sib1PduLen);
765    
766    if(ret != ROK)
767    {
768       DU_LOG("\nERROR --> SCH : Failed to fill sib1 configuration");
769       return RFAILED;
770    }
771    memcpy(&cellCb->cellCfg, schCellCfg, sizeof(SchCellCfg));
772    schProcPagingCfg(cellCb);
773
774    /* Fill coreset frequencyDomainResource bitmap */
775    coreset0Idx = cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.coresetId;
776    numRbs = coresetIdxTable[coreset0Idx][1];
777    offset = coresetIdxTable[coreset0Idx][3];
778    fillCoresetFeqDomAllocMap(((cellCb->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA - offset)/6), \
779                                   (numRbs/6), freqDomainResource);
780    covertFreqDomRsrcMapToIAPIFormat(freqDomainResource, \
781       cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc);
782
783    /* Fill K0 - K1 table for common cfg*/ 
784    BuildK0K1Table(cellCb, &cellCb->k0K1InfoTbl, true, cellCb->cellCfg.dlCfgCommon.schInitialDlBwp.pdschCommon,
785                    pdschCfg, DEFAULT_UL_ACK_LIST_COUNT, defaultUlAckTbl);
786    
787    BuildK2InfoTable(cellCb, cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.timeDomRsrcAllocList,\
788    cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.puschCommon.numTimeDomRsrcAlloc, &cellCb->msg3K2InfoTbl, \
789    &cellCb->k2InfoTbl);
790    
791    /*As per Spec 38.211, Sec 6.3.3.2; RootSeq Len(Lra) where Lra=839 or Lra=139,
792     *depending on the PRACH preamble format as given by Tables 6.3.3.1-1 and 6.3.3.1-2.*/
793    if(prachCfgIdxTable[cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.prachCfgIdx][0] <= 3)
794    {
795       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_1;
796    }
797    else
798    {
799       cellCb->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.rootSeqLen = ROOT_SEQ_LEN_2;
800    }
801    /* Initializing global variables */
802    cellCb->actvUeBitMap = 0;
803    cellCb->boIndBitMap = 0;
804
805    cellCb->schHqCfg.maxDlDataHqTx = SCH_MAX_NUM_DL_HQ_TX;
806    cellCb->schHqCfg.maxMsg4HqTx = SCH_MAX_NUM_MSG4_TX;
807    cellCb->schHqCfg.maxUlDataHqTx = SCH_MAX_NUM_UL_HQ_TX;
808    cellCb->maxMsg3Tx = SCH_MAX_NUM_MSG3_TX;
809
810    cellCb->schAlgoType = SCH_FCFS;
811    cellCb->api = &schCb[inst].allApis[cellCb->schAlgoType]; /* For FCFS */
812    cellCb->api->SchCellCfgReq(cellCb);
813    
814    /* Fill and send Cell config confirm */
815    memset(&rspPst, 0, sizeof(Pst));
816    FILL_PST_SCH_TO_MAC(rspPst, pst->dstInst);
817    rspPst.event = EVENT_SCH_CELL_CFG_CFM;
818
819    schCellCfgCfm.cellId = schCellCfg->cellId; 
820    schCellCfgCfm.rsp = RSP_OK;
821
822    ret = MacMessageRouter(&rspPst, (void *)&schCellCfgCfm);
823    return ret;
824
825 }
826
827 /*******************************************************************
828  *
829  * @brief Fill and send Cell delete response to MAC
830  *
831  * @details
832  *
833  *    Function :  SchSendCellDeleteRspToMac
834  *
835  *    Functionality: Fill and send Cell delete response to MAC
836  *
837  * @params[in] SchCellDelete  *ueDelete, Inst inst, SchMacRsp result
838  * @return ROK     - success
839  *         RFAILED - failure
840  *
841  * ****************************************************************/
842 uint8_t SchSendCellDeleteRspToMac(SchCellDeleteReq  *ueDelete, Inst inst, SchMacRsp result)
843 {
844    Pst rspPst;
845    uint8_t ret=0;
846    
847    SchCellDeleteRsp  delRsp;
848
849    DU_LOG("\nINFO   --> SCH : Filling Cell Delete response");
850    memset(&delRsp, 0, sizeof(SchCellDeleteRsp));
851    delRsp.cellId = ueDelete->cellId;
852    delRsp.rsp = result;
853
854    /* Filling response post */
855    memset(&rspPst, 0, sizeof(Pst));
856    FILL_PST_SCH_TO_MAC(rspPst, inst);
857    rspPst.event = EVENT_CELL_DELETE_RSP_TO_MAC;
858    ret = MacMessageRouter(&rspPst, (void *)&delRsp);
859    if(ret == RFAILED)
860    {
861       DU_LOG("\nERROR  -->  SCH : SchSendCellDeleteRspToMac(): failed to send the Cell Delete response");
862       return ret;
863    }
864    return ret;
865 }
866
867 /*******************************************************************
868  *
869  * @brief Function for cellCb Deletion 
870  *
871  * @details
872  *
873  *    Function : deleteSchCellCb 
874  *
875  *    Functionality: Function for cellCb Deletion 
876  *
877  * @params[in] SchCellDelete  *cellDelete
878  * @return ROK     - success
879  *         RFAILED - failure
880  *
881  * ****************************************************************/
882 void deleteSchCellCb(SchCellCb *cellCb)
883 {
884    uint8_t sliceIdx=0, slotIdx=0, plmnIdx = 0;
885    CmLListCp *list=NULL;
886    CmLList *node=NULL, *next=NULL;
887    SchPageInfo *tempNode = NULLP;
888
889    if(cellCb->schDlSlotInfo)
890    {
891       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
892       {
893          list = &cellCb->schDlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
894          node = list->first;
895          while(node)
896          {
897             next = node->next;
898             SCH_FREE(node->node, sizeof(FreePrbBlock));
899             deleteNodeFromLList(list, node);
900             node = next;
901          }
902          SCH_FREE(cellCb->schDlSlotInfo[slotIdx], sizeof(SchDlSlotInfo));
903       }
904       SCH_FREE(cellCb->schDlSlotInfo, cellCb->numSlots *sizeof(SchDlSlotInfo*));
905    }
906
907    if(cellCb->schUlSlotInfo)
908    {
909       for(slotIdx=0; slotIdx<cellCb->numSlots; slotIdx++)
910       {
911          list = &cellCb->schUlSlotInfo[slotIdx]->prbAlloc.freePrbBlockList;
912          node = list->first;
913          while(node)
914          {
915             next = node->next;
916             SCH_FREE(node->node, sizeof(FreePrbBlock));
917             deleteNodeFromLList(list, node);
918             node = next;
919          }
920          SCH_FREE(cellCb->schUlSlotInfo[slotIdx], sizeof(SchUlSlotInfo));  
921       }
922       SCH_FREE(cellCb->schUlSlotInfo,  cellCb->numSlots * sizeof(SchUlSlotInfo*));
923    }
924
925    for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
926    {
927       if(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai)
928       {
929          for(sliceIdx=0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
930          {
931             SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai));
932          }
933          SCH_FREE(cellCb->cellCfg.plmnInfoList[plmnIdx].snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport*sizeof(Snssai*));
934       }
935    }
936
937    for(uint16_t idx =0; idx<MAX_SFN; idx++)
938    {
939       list = &cellCb->pageCb.pageIndInfoRecord[idx];
940       node = list->first;
941       while(node)
942       {
943          next = node->next;
944          if(node->node)
945          {
946             tempNode = (SchPageInfo*)(node->node);
947             SCH_FREE(tempNode->pagePdu, tempNode->msgLen);
948             SCH_FREE(node->node,  sizeof(SchPageInfo));
949          }
950          deleteNodeFromLList(list, node);
951          node = next;
952       }
953    }
954
955    cellCb->api->SchCellDeleteReq(cellCb);
956
957    memset(cellCb, 0, sizeof(SchCellCb));
958 }
959
960 /*******************************************************************
961  *
962  * @brief Function for cell Delete request from MAC to SCH
963  *
964  * @details
965  *
966  *    Function : SchProcCellDeleteReq
967  *
968  *    Functionality: Function for cell Delete request from MAC to SCH
969  *
970  * @params[in] Pst *pst, SchCellDelete  *cellDelete
971  * @return ROK     - success
972  *         RFAILED - failure
973  *
974  * ****************************************************************/
975 uint8_t SchProcCellDeleteReq(Pst *pst, SchCellDeleteReq  *cellDelete)
976 {
977    uint8_t   cellIdx=0, ret = RFAILED;
978    Inst      inst = pst->dstInst - SCH_INST_START;
979    SchMacRsp result= RSP_OK;
980    
981    if(!cellDelete)
982    {
983       DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): Ue Delete request failed");
984    }
985    else
986    {
987       GET_CELL_IDX(cellDelete->cellId, cellIdx);
988       if(schCb[inst].cells[cellIdx] == NULLP)
989       { 
990          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available", cellDelete->cellId);
991          result = RSP_NOK;
992       }
993       else
994       {
995          if(schCb[inst].cells[cellIdx]->cellId == cellDelete->cellId)
996          {
997             deleteSchCellCb(schCb[inst].cells[cellIdx]);
998             result = RSP_OK;
999             ret = ROK;
1000             SCH_FREE(schCb[inst].cells[cellIdx], sizeof(SchCellCb));
1001             DU_LOG("\nINFO   -->  SCH : Sending Cell Delete response to MAC");
1002          }
1003          else
1004          {
1005             DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): cell Id[%d] is not available",cellDelete->cellId);
1006             result = RSP_NOK;
1007          }
1008       }
1009
1010       if(SchSendCellDeleteRspToMac(cellDelete, inst, result)!=ROK)
1011       {
1012          DU_LOG("\nERROR  -->  SCH : SchProcCellDeleteReq(): failed to send Cell Delete response");
1013          ret =  RFAILED;
1014       }
1015    }
1016    return ret;   
1017 }
1018
1019 /*******************************************************************
1020  *
1021  * @brief Processes DL RLC BO info from MAC
1022  *
1023  * @details
1024  *
1025  *    Function : SchProcDlRlcBoInfo
1026  *
1027  *    Functionality:
1028  *       Processes DL RLC BO info from MAC
1029  *
1030  * @params[in] 
1031  * @return ROK     - success
1032  *         RFAILED - failure
1033  *
1034  * ****************************************************************/
1035 uint8_t SchProcDlRlcBoInfo(Pst *pst, DlRlcBoInfo *dlBoInfo)
1036 {
1037    uint8_t  lcId = 0;
1038    uint16_t ueId = 0;
1039    bool isLcIdValid = false;
1040    SchUeCb *ueCb = NULLP;
1041    SchCellCb *cell = NULLP;
1042    Inst  inst = pst->dstInst-SCH_INST_START;   
1043
1044    DU_LOG("\nDEBUG  -->  SCH : Received RLC BO Status indication LCId [%d] BO [%d]", dlBoInfo->lcId, dlBoInfo->dataVolume);
1045    cell = schCb[inst].cells[inst];
1046
1047    if(cell == NULLP)
1048    {
1049       DU_LOG("\nERROR  -->  SCH : SchProcDlRlcBoInfo(): Cell does not exists");
1050       return RFAILED;
1051    }
1052
1053    GET_UE_ID(dlBoInfo->crnti, ueId);
1054    ueCb = &cell->ueCb[ueId-1];
1055    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1056    {
1057       DU_LOG("INFO  --> SCH : DL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1058       return ROK;
1059    }
1060    
1061    lcId  = dlBoInfo->lcId;
1062    CHECK_LCID(lcId, isLcIdValid);
1063    if(isLcIdValid == FALSE)
1064    {
1065       DU_LOG("ERROR --> SCH: LCID:%d is not valid", lcId);
1066       return RFAILED;
1067    }
1068
1069    /*Expected when theres a case of Retransmission Failure or Resetablishment
1070     *By Zero BO, the RLC is informing that previous data can be cleared out
1071     *Thus clearing out the LC from the Lc priority list*/
1072    if(dlBoInfo->dataVolume == 0)
1073    {
1074       /* TODO : Check the LC is Dedicated or default and accordingly LCList
1075        * will be used*/
1076       return ROK;
1077    }
1078
1079    if(lcId == SRB0_LCID)
1080    {
1081       cell->raCb[ueId -1].msg4recvd = true;
1082       cell->raCb[ueId -1].dlMsgPduLen = dlBoInfo->dataVolume;      
1083    }
1084    else
1085    {
1086       /* TODO : These part of changes will be corrected during DL scheduling as
1087        * per K0 - K1 -K2 */
1088       SET_ONE_BIT(ueId, cell->boIndBitMap);
1089       if(ueCb->dlInfo.dlLcCtxt[lcId].lcId == lcId)
1090       {
1091          ueCb->dlInfo.dlLcCtxt[lcId].bo = dlBoInfo->dataVolume;
1092       }
1093       else
1094       {
1095          DU_LOG("ERROR --> SCH: LCID:%d is not configured in SCH Cb",lcId);
1096          return RFAILED;
1097       }
1098    }
1099    /* Adding UE Id to list of pending UEs to be scheduled */
1100    cell->api->SchDlRlcBoInfo(cell, ueId);
1101    return ROK;
1102 }
1103
1104 /*******************************************************************
1105  *
1106  * @brief Processes BSR indiation from MAC
1107  *
1108  * @details
1109  *
1110  *    Function : SchProcBsr
1111  *
1112  *    Functionality:
1113  *       Processes DL BSR from MAC
1114  *
1115  * @params[in]    Pst pst
1116  *                UlBufferStatusRptInd bsrInd
1117  * @return ROK     - success
1118  *         RFAILED - failure
1119  *
1120  * ****************************************************************/
1121 uint8_t SchProcBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
1122 {
1123    Inst           schInst       = pst->dstInst-SCH_INST_START;
1124    SchCellCb      *cellCb       = NULLP;
1125    SchUeCb        *ueCb         = NULLP;
1126    uint8_t        lcgIdx = 0;
1127
1128    DU_LOG("\nDEBUG  -->  SCH : Received BSR");
1129    if(bsrInd == NULLP)
1130    {
1131       DU_LOG("\nERROR  -->  SCH : BSR Ind is empty");
1132       return RFAILED;
1133    }
1134    cellCb = schCb[schInst].cells[schInst];
1135    if(cellCb == NULLP)
1136    {
1137       DU_LOG("\nERROR  -->  SCH : CellCb is empty");
1138       return RFAILED;
1139    }
1140    ueCb = schGetUeCb(cellCb, bsrInd->crnti);
1141
1142    if(ueCb == NULLP)
1143    {
1144       DU_LOG("\nERROR  -->  SCH : UeCB is empty");
1145       return RFAILED;
1146    }
1147
1148    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1149    {
1150       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1151       return ROK;
1152    }
1153    
1154    ueCb->bsrRcvd = true;
1155    /* store dataVolume per lcg in uecb */
1156    for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
1157    {
1158       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
1159       ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
1160    }
1161    
1162    /* Adding UE Id to list of pending UEs to be scheduled */
1163    cellCb->api->SchBsr(cellCb, ueCb->ueId);
1164    return ROK;
1165 }
1166
1167 /*******************************************************************
1168  *
1169  * @brief Processes SR UCI indication from MAC 
1170  *
1171  * @details
1172  *
1173  *    Function : SchProcSrUciInd
1174  *
1175  *    Functionality:
1176  *      Processes SR UCI indication from MAC
1177  *
1178  * @params[in] Post structure
1179  *             UCI Indication
1180  * @return ROK     - success
1181  *         RFAILED - failure
1182  *
1183  * ****************************************************************/
1184 uint8_t SchProcSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
1185 {
1186    Inst  inst = pst->dstInst-SCH_INST_START;
1187
1188    SchUeCb   *ueCb; 
1189    SchCellCb *cellCb = schCb[inst].cells[inst];
1190
1191    DU_LOG("\nDEBUG  -->  SCH : Received SR");
1192
1193    ueCb = schGetUeCb(cellCb, uciInd->crnti);
1194    
1195    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1196    {
1197       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", uciInd->crnti);
1198       return ROK;  
1199    }
1200    if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
1201    {
1202       DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
1203       return ROK;
1204    }
1205    if(uciInd->numSrBits)
1206    {
1207       ueCb->srRcvd = true;      
1208       /* Adding UE Id to list of pending UEs to be scheduled */
1209       cellCb->api->SchSrUciInd(cellCb, ueCb->ueId);
1210    }
1211    return ROK;
1212 }
1213
1214 /*******************************************************************
1215  *
1216  * @brief Processes DL HARQ indication from MAC 
1217  *
1218  * @details
1219  *
1220  *    Function : SchProcDlHarqInd
1221  *
1222  *    Functionality:
1223  *      Processes DL HARQ indication from MAC
1224  *
1225  * @params[in] Post structure
1226  *             DL HARQ Indication
1227  * @return ROK     - success
1228  *         RFAILED - failure
1229  *
1230  * ****************************************************************/
1231 uint8_t SchProcDlHarqInd(Pst *pst, DlHarqInd *dlHarqInd)
1232 {
1233    Inst  inst = pst->dstInst-SCH_INST_START;
1234    SchUeCb   *ueCb;
1235    SchCellCb *cellCb = schCb[inst].cells[inst];
1236
1237    DU_LOG("\nDEBUG  -->  SCH : Received HARQ");
1238
1239    ueCb = schGetUeCb(cellCb, dlHarqInd->crnti);
1240
1241    if(ueCb->state == SCH_UE_STATE_INACTIVE)
1242    {
1243       DU_LOG("\nERROR  -->  SCH : Crnti %d is inactive", dlHarqInd->crnti);
1244       return ROK;
1245    }
1246
1247    schUpdateHarqFdbk(ueCb, dlHarqInd->numHarq, dlHarqInd->harqPayload, &dlHarqInd->slotInd);
1248
1249    return ROK;
1250 }
1251
1252 /*******************************************************************
1253  *
1254  * @brief Allocates requested PRBs for DL
1255  *
1256  * @details
1257  *
1258  *    Function : allocatePrbDl
1259  *
1260  *    Functionality:
1261  *      Allocates requested PRBs in DL
1262  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1263  *
1264  * @params[in] prbAlloc table
1265  *             Start symbol
1266  *             Number of symbols
1267  *             Start PRB
1268  *             Number of PRBs
1269  *
1270  * @return ROK     - success
1271  *         RFAILED - failure
1272  *
1273  * ****************************************************************/
1274 uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
1275    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1276 {
1277    uint8_t        symbol = 0;
1278    uint16_t       broadcastPrbStart=0, broadcastPrbEnd=0;
1279    FreePrbBlock   *freePrbBlock = NULLP;
1280    CmLList        *freePrbNode = NULLP;
1281    PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1282    SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1283    SchPrbAlloc    *prbAlloc = &schDlSlotInfo->prbAlloc;
1284
1285    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1286     * Search for an appropriate location in PRB grid and allocate requested resources */
1287    if(*startPrb == MAX_NUM_RB)
1288    {
1289       /* Check if SSB/SIB1 is also scheduled in this slot  */
1290       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1291       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1292
1293       if(ssbOccasion && sib1Occasion)
1294       {
1295          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1296          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1297       }
1298       else if(ssbOccasion)
1299       {
1300          broadcastPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1301          broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
1302       }
1303       else if(sib1Occasion)
1304       {
1305          broadcastPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
1306          broadcastPrbEnd = broadcastPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1307       }
1308
1309       /* Iterate through all free PRB blocks */
1310       freePrbNode = prbAlloc->freePrbBlockList.first; 
1311       while(freePrbNode)
1312       {
1313          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1314
1315          /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
1316           * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1317          if((ssbOccasion || sib1Occasion) && 
1318             ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
1319             ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
1320          {
1321             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1322             if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
1323             {
1324                /* If sufficient free PRBs are available above bradcast message then,
1325                 * endPrb = freePrbBlock->endPrb
1326                 * startPrb = endPrb - numPrb +1;
1327                 */
1328                *startPrb = freePrbBlock->endPrb - numPrb +1;
1329                break;
1330             }
1331             else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
1332             {
1333                /* If free PRBs are available below broadcast message then,
1334                 * endPrb = broadcastPrbStart - 1
1335                 * startPrb = endPrb - numPrb +1
1336                 */
1337                *startPrb = broadcastPrbStart - numPrb; 
1338                break;
1339             }
1340             else
1341             {
1342                freePrbNode = freePrbNode->next;
1343                continue;
1344             }
1345          }
1346          else
1347          {
1348             /* Check if requested number of blocks can be allocated from the current block */ 
1349             if (freePrbBlock->numFreePrb < numPrb)
1350             {
1351                freePrbNode = freePrbNode->next;
1352                continue;
1353             }
1354             *startPrb = freePrbBlock->endPrb - numPrb +1;
1355             break;  
1356          }
1357       }
1358
1359       /* If no free block can be used to allocated request number of RBs */
1360       if(*startPrb == MAX_NUM_RB)
1361          return RFAILED;
1362    }
1363
1364    /* If startPrb is known already, check if requested PRBs are available for allocation */
1365    else
1366    {
1367       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1368       if(!freePrbNode)
1369       {
1370          DU_LOG("\nERROR  -->  SCH: Requested DL PRB unavailable");
1371          return RFAILED;
1372       }
1373    }
1374
1375    /* Update bitmap to allocate PRBs */
1376    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1377    {
1378       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1379       {
1380          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
1381          return RFAILED;
1382       }
1383    }
1384    
1385    /* Update statistics of PRB usage if stats calculation is enabled */
1386    if(schCb[cell->instIdx].statistics.dlTotalPrbUsage)
1387       prbAlloc->numPrbAlloc += numPrb;
1388
1389    /* Update the remaining number for free PRBs */
1390    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1391
1392    return ROK;
1393 }
1394
1395 /*******************************************************************
1396  *
1397  * @brief Allocates requested PRBs for UL
1398  *
1399  * @details
1400  *
1401  *    Function : allocatePrbUl
1402  *
1403  *    Functionality:
1404  *      Allocates requested PRBs in UL
1405  *      Keeps track of allocated PRB (using bitmap) and remaining PRBs
1406  *
1407  * @params[in] prbAlloc table
1408  *             Start symbol
1409  *             Number of symbols
1410  *             Start PRB
1411  *             Number of PRBs
1412  *
1413  * @return ROK     - success
1414  *         RFAILED - failure
1415  *
1416  * ****************************************************************/
1417 uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
1418    uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
1419 {
1420    uint8_t        symbol = 0;
1421    uint16_t       prachStartPrb, prachNumPrb, prachEndPrb;
1422    bool           isPrachOccasion;
1423    FreePrbBlock   *freePrbBlock = NULLP;
1424    CmLList        *freePrbNode = NULLP;
1425    SchPrbAlloc    *prbAlloc = NULLP;
1426
1427    if(cell == NULLP)
1428    {
1429       DU_LOG("\nERROR  --> SCH : allocatePrbUl(): Received cellCb is null");
1430       return RFAILED;
1431    }
1432    
1433    prbAlloc =   &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1434    /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
1435     * Search for an appropriate location in PRB grid and allocate requested resources */
1436    if(*startPrb == MAX_NUM_RB)
1437    {
1438       /* Check if PRACH is also scheduled in this slot */
1439       isPrachOccasion = schCheckPrachOcc(cell, slotTime);
1440       if(isPrachOccasion)
1441       {
1442          prachStartPrb =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1443          prachNumPrb = schCalcPrachNumRb(cell);
1444          prachEndPrb = prachStartPrb + prachNumPrb -1;
1445       }
1446
1447       /* Iterate through all free PRB blocks */
1448       freePrbNode = prbAlloc->freePrbBlockList.first; 
1449       while(freePrbNode)
1450       {
1451          freePrbBlock = (FreePrbBlock *)freePrbNode->node; 
1452
1453          /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
1454           * PRBs required for PRACH cannot be allocated to any other message */
1455          if((isPrachOccasion) &&
1456             ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
1457             ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
1458          {
1459             /* Implmentation is done such that highest-numbered free-RB is allocated first */ 
1460             if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
1461             {
1462                /* If sufficient free PRBs are available above PRACH message then,
1463                 * endPrb = freePrbBlock->endPrb
1464                 * startPrb = endPrb - numPrb +1;
1465                 */
1466                *startPrb = freePrbBlock->endPrb - numPrb +1;
1467                break;
1468             }
1469             else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
1470             {
1471                /* If free PRBs are available below PRACH message then,
1472                 * endPrb = prachStartPrb - 1
1473                 * startPrb = endPrb - numPrb +1
1474                 */
1475                *startPrb = prachStartPrb - numPrb; 
1476                break;
1477             }
1478             else
1479             {
1480                freePrbNode = freePrbNode->next;
1481                continue;
1482             } 
1483          }
1484          else
1485          {
1486             /* Check if requested number of PRBs can be allocated from currect block */
1487             if(freePrbBlock->numFreePrb < numPrb)
1488             {
1489                freePrbNode = freePrbNode->next;
1490                continue;
1491             }
1492             *startPrb = freePrbBlock->endPrb - numPrb +1;
1493             break;
1494          }
1495       }
1496
1497       /* If no free block can be used to allocated requested number of RBs */
1498       if(*startPrb == MAX_NUM_RB)
1499          return RFAILED;
1500    }
1501    else
1502    {
1503       /* If startPrb is known already, check if requested PRBs are available for allocation */
1504       freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
1505       if(!freePrbNode)
1506       {
1507          DU_LOG("\nERROR  -->  SCH: Requested UL PRB unavailable");
1508          return RFAILED;
1509       }
1510    }
1511
1512    /* Update bitmap to allocate PRBs */
1513    for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
1514    {
1515       if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
1516       {
1517          DU_LOG("\nERROR  -->  SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
1518          return RFAILED;
1519       }
1520    }
1521
1522    /* Update statistics of PRB usage if stats calculation is enabled */
1523    if(schCb[cell->instIdx].statistics.ulTotalPrbUsage)
1524       prbAlloc->numPrbAlloc += numPrb;
1525
1526    /* Update the remaining number for free PRBs */
1527    removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
1528
1529    return ROK;
1530 }
1531
1532 /*******************************************************************************
1533  *
1534  * @brief Try to find Best Free Block with Max Num PRB 
1535  *
1536  * @details
1537  *
1538  *    Function : searchLargestFreeBlock
1539  *
1540  *    Functionality:
1541  *     Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
1542  *
1543  * @params[in] I/P > prbAlloc table (FreeBlock list)
1544  *             I/P > Slot timing Info
1545  *             O/P > Start PRB
1546  *             I/P > Direction (UL/DL)
1547  *       
1548  *
1549  * @return Max Number of Free PRB 
1550  *         If 0, then no Suitable Free Block
1551  *
1552  * ********************************************************************************/
1553
1554 uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
1555 {
1556    uint16_t       reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
1557    FreePrbBlock   *freePrbBlock = NULLP;
1558    CmLList        *freePrbNode = NULLP;
1559    SchPrbAlloc    *prbAlloc = NULLP;
1560    bool           checkOccasion = FALSE;
1561
1562    *startPrb = 0; /*Initialize the StartPRB to zero*/
1563
1564    /*Based on Direction, Reserved Messsages will differi.e.
1565     * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
1566     * and reserved before allocation for dedicated DL/UL msg*/
1567    if(dir == DIR_DL)
1568    {
1569       SchDlSlotInfo  *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
1570       PduTxOccsaion  ssbOccasion=0, sib1Occasion=0;
1571
1572       prbAlloc = &schDlSlotInfo->prbAlloc;
1573
1574       ssbOccasion = schCheckSsbOcc(cell, slotTime);
1575       sib1Occasion = schCheckSib1Occ(cell, slotTime);
1576
1577       checkOccasion = TRUE;
1578       if(ssbOccasion && sib1Occasion)
1579       {
1580          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA; 
1581          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
1582                           cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1583       }
1584       else if(ssbOccasion)
1585       {
1586          reservedPrbStart = cell->cellCfg.dlCfgCommon.schFreqInfoDlSib.offsetToPointA;
1587          reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
1588       }
1589       else if(sib1Occasion)
1590       {
1591          reservedPrbStart = cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.startPrb;
1592          reservedPrbEnd = reservedPrbStart + cell->sib1SchCfg.sib1PdcchCfg.dci.pdschCfg.pdschFreqAlloc.numPrb -1;
1593       }
1594       else
1595       {
1596          checkOccasion = FALSE;  
1597       }
1598    }
1599    else if(dir == DIR_UL)
1600    {
1601       prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
1602
1603       /* Check if PRACH is also scheduled in this slot */
1604       checkOccasion = schCheckPrachOcc(cell, slotTime);
1605       if(checkOccasion)
1606       {
1607          reservedPrbStart =  cell->cellCfg.ulCfgCommon.schInitialUlBwp.schRachCfg.prachCfgGeneric.msg1FreqStart;
1608          reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
1609       }
1610    }
1611    else
1612    {
1613       DU_LOG("\nERROR --> SCH: Invalid Direction!");
1614       return (maxFreePRB);
1615    }
1616
1617    freePrbNode = prbAlloc->freePrbBlockList.first; 
1618    while(freePrbNode)
1619    {
1620       freePrbBlock = (FreePrbBlock *)freePrbNode->node;
1621
1622       /*For block with same numFreeBlocks, choose the one with HighestPRB range
1623        *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
1624       if(maxFreePRB >= freePrbBlock->numFreePrb) 
1625       {
1626          //skip this block
1627          freePrbNode = freePrbNode->next;
1628          continue;
1629       }
1630
1631       /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
1632        * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
1633       if(checkOccasion && 
1634             ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
1635             ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
1636       {
1637
1638          /* Implmentation is done such that highest-numbered free-RB is Checked first
1639             and freePRB in this block is greater than Max till now */
1640          if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
1641          {
1642             /* If sufficient free PRBs are available above reserved message*/
1643             *startPrb = reservedPrbEnd + 1;
1644             maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);                
1645          }
1646          /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
1647          if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
1648          {
1649             /* If free PRBs are available below reserved message*/
1650             *startPrb = freePrbBlock->startPrb;
1651             maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
1652          }
1653       }
1654       else  //Best Block
1655       {
1656          if(maxFreePRB < freePrbBlock->numFreePrb)
1657          {
1658             *startPrb = freePrbBlock->startPrb;
1659             maxFreePRB = freePrbBlock->numFreePrb;
1660          }
1661
1662       }
1663       freePrbNode = freePrbNode->next;
1664    }  
1665    return(maxFreePRB);
1666 }
1667
1668 /*******************************************************************************
1669  *
1670  * @brief This function is used to send Slice Cfg rsp to MAC
1671  *
1672  * @details
1673  *
1674  *    Function : SchSendSliceCfgRspToMac
1675  *
1676  *    Functionality:
1677  *     function is used to send Slice Cfg rsp to MAC
1678  *
1679  * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
1680  *
1681  * @return- void
1682  *
1683  * ********************************************************************************/
1684 void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
1685 {
1686    Pst rspPst;
1687    
1688    memset(&rspPst, 0, sizeof(Pst));
1689    FILL_PST_SCH_TO_MAC(rspPst, inst);
1690    rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
1691    
1692    MacMessageRouter(&rspPst, (void *)&sliceCfgRsp);
1693
1694 }
1695
1696 /*******************************************************************************
1697  *
1698  * @brief This function is used to store or modify the slice configuration Sch DB
1699  *
1700  * @details
1701  *
1702  *    Function : addOrModifySliceCfgInSchDb 
1703  *
1704  *    Functionality:
1705  *     function is used to store or modify the slice configuration Sch DB
1706  *
1707  * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
1708  * SchSliceCfgRsp cfgRsp, uint8_t count
1709  *
1710  * @return
1711  *        ROK - Success
1712  *        RFAILED - Failure
1713  *
1714  * ********************************************************************************/
1715 uint8_t addSliceCfgInSchDb(CmLListCp *sliceCfgInDb, SchRrmPolicyOfSlice *cfgReq)
1716 {
1717    SchRrmPolicyOfSlice *sliceToStore;
1718
1719    SCH_ALLOC(sliceToStore, sizeof(SchRrmPolicyOfSlice));
1720    if(sliceToStore)
1721    {
1722       memcpy(&sliceToStore->snssai, &cfgReq->snssai, sizeof(Snssai));  
1723       memcpy(&sliceToStore->rrmPolicyRatioInfo, &cfgReq->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));  
1724       addNodeToLList(sliceCfgInDb, sliceToStore, NULL);
1725    }
1726    else
1727    {
1728       DU_LOG("\nERROR  -->  SCH : Memory allocation failed in addOrModifySliceCfgInSchDb");
1729       return RFAILED;
1730    }
1731    return ROK;
1732 }
1733
1734 /*******************************************************************************
1735  *
1736  * @brief fill slice configuration response
1737  *
1738  * @details
1739  *
1740  *    Function : fillSliceCfgRsp
1741  *
1742  *    Functionality:
1743  *     fill slice configuration response
1744  *
1745  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1746  *
1747  * @return
1748  *        ROK - Success
1749  *        RFAILED - Failure
1750  *
1751  * ********************************************************************************/
1752 uint8_t fillSliceCfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq)
1753 {
1754    SchMacRsp sliceFound;
1755    uint8_t cfgIdx = 0, sliceIdx = 0, plmnIdx = 0, ret =ROK;
1756    SchSliceCfgRsp schSliceCfgRsp;
1757
1758    for(cfgIdx = 0; cfgIdx<schSliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1759    {
1760       sliceFound = RSP_NOK;
1761       /* Here comparing the slice cfg request with the slice stored in cellCfg */
1762       for(plmnIdx = 0; plmnIdx < MAX_PLMN; plmnIdx++)
1763       {
1764          for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList[plmnIdx].numSliceSupport; sliceIdx++)
1765          {
1766             /* 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. */ 
1767             if(!memcmp(&schSliceCfgReq->listOfSlices[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList[plmnIdx].snssai[sliceIdx], sizeof(Snssai)))
1768             {
1769                if(addSliceCfgInSchDb(storedSliceCfg, schSliceCfgReq->listOfSlices[cfgIdx]) == ROK)
1770                {
1771                   sliceFound = RSP_OK;
1772                   schSliceCfgRsp.cause = SUCCESSFUL;
1773                }
1774                else
1775                {
1776                   DU_LOG("\nERROR  --> SCH : Failed to store slice configuration in SchDb");
1777                   schSliceCfgRsp.cause = RESOURCE_UNAVAILABLE;
1778                   ret = RFAILED;
1779                }
1780                plmnIdx = MAX_PLMN;
1781                break;
1782             }
1783          }
1784       }
1785       
1786       if((sliceFound == RSP_NOK) && (schSliceCfgRsp.cause != RESOURCE_UNAVAILABLE))
1787          schSliceCfgRsp.cause = SLICE_NOT_FOUND;
1788       
1789       schSliceCfgRsp.snssai = schSliceCfgReq->listOfSlices[cfgIdx]->snssai;
1790       schSliceCfgRsp.rsp    = sliceFound;
1791       SchSendSliceCfgRspToMac(inst, schSliceCfgRsp);
1792    }
1793    return ret;
1794 }
1795
1796 /*******************************************************************************
1797  *
1798  * @brief This function is used to free the slice cfg and re cfg request pointer
1799  *
1800  * @details
1801  *
1802  *    Function : freeSchSliceCfgReq 
1803  *
1804  *    Functionality:
1805  *     function is used to free the slice cfg and re cfg request pointer
1806  *
1807  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1808  *
1809  * @return
1810  *        ROK - Success
1811  *        RFAILED - Failure
1812  * ********************************************************************************/
1813 void freeSchSliceCfgReq(SchSliceCfgReq *sliceCfgReq)
1814 {
1815    uint8_t cfgIdx = 0;
1816    
1817    if(sliceCfgReq)
1818    {
1819       if(sliceCfgReq->numOfConfiguredSlice)
1820       {
1821          for(cfgIdx = 0; cfgIdx<sliceCfgReq->numOfConfiguredSlice; cfgIdx++)
1822          {
1823             if(sliceCfgReq->listOfSlices[cfgIdx])
1824             {
1825                SCH_FREE(sliceCfgReq->listOfSlices[cfgIdx], sizeof(SchRrmPolicyOfSlice));
1826             }
1827          }
1828          SCH_FREE(sliceCfgReq->listOfSlices, sliceCfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
1829       }
1830       SCH_FREE(sliceCfgReq, sizeof(SchSliceCfgReq));
1831    }
1832 }
1833 /*******************************************************************************
1834  *
1835  * @brief This function is used to store the slice configuration Sch DB
1836  *
1837  * @details
1838  *
1839  *    Function : SchProcSliceCfgReq 
1840  *
1841  *    Functionality:
1842  *     function is used to store the slice configuration Sch DB
1843  *
1844  * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
1845  *
1846  * @return
1847  *        ROK - Success
1848  *        RFAILED - Failure
1849  *
1850  * ********************************************************************************/
1851 uint8_t SchProcSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
1852 {
1853    uint8_t ret = ROK;
1854    Inst   inst = pst->dstInst - SCH_INST_START;
1855
1856    DU_LOG("\nINFO  -->  SCH : Received Slice Cfg request from MAC");
1857    if(schSliceCfgReq)
1858    {
1859       if(schSliceCfgReq->listOfSlices)
1860       {
1861          /* filling the slice configuration response of each slice */
1862          if(fillSliceCfgRsp(inst, &schCb[inst].sliceCfg, schCb[inst].cells[0], schSliceCfgReq) != ROK)
1863          {
1864             DU_LOG("\nERROR  -->  SCH : Failed to fill the slice cfg rsp");
1865             ret = RFAILED;
1866          }
1867          freeSchSliceCfgReq(schSliceCfgReq);
1868       }
1869    }
1870    else
1871    {
1872       DU_LOG("\nERROR  -->  SCH : Received SchSliceCfgReq is NULL");
1873       ret = RFAILED;
1874    }
1875    return ret;
1876 }
1877
1878 /*******************************************************************************
1879  *
1880  * @brief This function is used to send Slice re Cfg rsp to MAC
1881  *
1882  * @details
1883  *
1884  *    Function : SchSendSliceRecfgRspToMac
1885  *
1886  *    Functionality:
1887  *     function is used to send Slice re Cfg rsp to MAC
1888  *
1889  * @params[in] Pst *pst, SchSliceRecfgRsp schSliceRecfgRsp
1890  *
1891  * @return- void
1892  *
1893  * ********************************************************************************/
1894 void SchSendSliceRecfgRspToMac(Inst inst, SchSliceRecfgRsp schSliceRecfgRsp)
1895 {
1896    Pst rspPst;
1897    
1898    memset(&rspPst, 0, sizeof(Pst));
1899    FILL_PST_SCH_TO_MAC(rspPst, inst);
1900    rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
1901    
1902    MacMessageRouter(&rspPst, (void *)&schSliceRecfgRsp);
1903 }
1904
1905 /*******************************************************************************
1906  *
1907  * @brief fill slice configuration response
1908  *
1909  * @details
1910  *
1911  *    Function : fillSliceRecfgRsp
1912  *
1913  *    Functionality: fill slice reconfiguration response
1914  *
1915  * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t  count
1916  *
1917  * @return
1918  *        ROK - Success
1919  *        RFAILED - Failure
1920  *
1921  * ********************************************************************************/
1922
1923 uint8_t fillSliceRecfgRsp(Inst inst, CmLListCp *storedSliceCfg, SchSliceRecfgReq *schSliceRecfgReq)
1924 {
1925    SchMacRsp sliceFound;
1926    uint8_t cfgIdx = 0;
1927    SchRrmPolicyOfSlice *rrmPolicyOfSlices;
1928    SchSliceRecfgRsp schSliceRecfgRsp;
1929
1930    for(cfgIdx = 0; cfgIdx<schSliceRecfgReq->numOfConfiguredSlice; cfgIdx++)
1931    {
1932       sliceFound = RSP_NOK;
1933       /* Here comparing the slice recfg request with the StoredSliceCfg */
1934       CmLList *sliceCfg = storedSliceCfg->first;
1935
1936       while(sliceCfg)
1937       {
1938          rrmPolicyOfSlices = (SchRrmPolicyOfSlice*)sliceCfg->node;
1939          
1940          if(rrmPolicyOfSlices && (memcmp(&schSliceRecfgReq->listOfSlices[cfgIdx]->snssai, &(rrmPolicyOfSlices->snssai), sizeof(Snssai)) == 0))
1941          {
1942             memcpy(&rrmPolicyOfSlices->rrmPolicyRatioInfo, &schSliceRecfgReq->listOfSlices[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
1943             sliceFound = RSP_OK;
1944             break;
1945          }
1946          sliceCfg = sliceCfg->next;
1947       }
1948
1949       schSliceRecfgRsp.snssai = schSliceRecfgReq->listOfSlices[cfgIdx]->snssai;
1950       schSliceRecfgRsp.rsp    = sliceFound;
1951       if(schSliceRecfgRsp.rsp == RSP_OK)
1952          schSliceRecfgRsp.cause = SUCCESSFUL;
1953       else
1954          schSliceRecfgRsp.cause = SLICE_NOT_FOUND;
1955       SchSendSliceRecfgRspToMac(inst, schSliceRecfgRsp);
1956    }
1957    return ROK;
1958 }
1959 /*******************************************************************************
1960  *
1961  * @brief This function is used to store the slice reconfiguration Sch DB
1962  *
1963  * @details
1964  *
1965  *    Function : SchProcSliceRecfgReq 
1966  *
1967  *    Functionality:
1968  *     function is used to store the slice re configuration Sch DB
1969  *
1970  * @params[in] Pst *pst, SchSliceRecfgReq *schSliceRecfgReq
1971  *
1972  * @return
1973  *        ROK - Success
1974  *        RFAILED - Failure
1975  *
1976  * ********************************************************************************/
1977 uint8_t SchProcSliceRecfgReq(Pst *pst, SchSliceRecfgReq *schSliceRecfgReq)
1978 {
1979    uint8_t ret = ROK;
1980    Inst   inst = pst->dstInst - SCH_INST_START;
1981
1982    DU_LOG("\nINFO  -->  SCH : Received Slice ReCfg request from MAC");
1983    if(schSliceRecfgReq)
1984    {
1985       if(schSliceRecfgReq->listOfSlices)
1986       {
1987          /* filling the slice configuration response of each slice */
1988          if(fillSliceRecfgRsp(inst, &schCb[inst].sliceCfg, schSliceRecfgReq) != ROK)
1989          {
1990             DU_LOG("\nERROR  -->  SCH : Failed to fill sch slice cfg response");
1991             ret = RFAILED;
1992          }
1993          freeSchSliceCfgReq(schSliceRecfgReq);
1994       }
1995    }
1996    else
1997    {
1998       DU_LOG("\nERROR  -->  SCH : Received SchSliceRecfgReq is NULL");
1999
2000    }
2001    return ret;
2002 }
2003
2004 /****************************************************************************
2005  *
2006  * @brief Stores the Paging Configuration from DU APP in CellCb 
2007  *
2008  * @details
2009  *
2010  *    Function : schProcPagingParam
2011  *
2012  *    Functionality:
2013  *          Process the Paging Configuration when FirstPDCCHMonitoring for
2014  *          Paging Ocassion is not present.
2015  *
2016  *          As per 38.304 Sec 7.1,
2017  *          "When firstPDCCH-MonitoringOccasionOfPO is present, the
2018  *          starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
2019  *          (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
2020  *          parameter; otherwise, it is equal to i_s * S."
2021  *          "S = number of actual transmitted SSBs determined according 
2022  *              to ssb-PositionsInBurst in SIB1"
2023  *
2024  * @params[in] SchCellCb *cell 
2025  *       
2026  * @return void 
2027  *        
2028  *************************************************************************/
2029 void schProcPagingCfg(SchCellCb *cell)
2030 {
2031    SchPcchCfg *pageCfgRcvd = NULL;
2032    uint8_t i_sIdx = 0;
2033
2034    pageCfgRcvd = &(cell->cellCfg.dlCfgCommon.schPcchCfg);
2035
2036    if(pageCfgRcvd->poPresent == TRUE)
2037    {
2038       /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
2039       for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
2040       {
2041          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
2042          if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
2043          {
2044             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
2045          }
2046
2047          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
2048
2049       }
2050    }
2051    else
2052    {
2053       schCfgPdcchMonOccOfPO(cell);                  
2054    }
2055 }
2056
2057 /****************************************************************************
2058  *
2059  * @brief Calculate PO if not present in Configuration 
2060  *
2061  * @details
2062  *
2063  *    Function : schCfgPdcchMonOccOfPO
2064  *
2065  *    Functionality: In this function, PO are calculated i_s * S because
2066  *    FirstPDCCHMonitoring_ForPO is not present.
2067  *
2068  * @params[in] SchCellCb *cellCb
2069  *       
2070  * @return void 
2071  *        
2072  *************************************************************************/
2073 void schCfgPdcchMonOccOfPO(SchCellCb *cell)
2074 {
2075    uint8_t         cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
2076    uint8_t         nsValue = cell->cellCfg.dlCfgCommon.schPcchCfg.numPO;
2077    uint8_t         totalNumSsb = countSetBits(cell->cellCfg.ssbPosInBurst[0]);
2078    SlotTimingInfo  tmpTimingInfo, pdcchTime; 
2079
2080    /*Starting with First Sfn and slot*/
2081    tmpTimingInfo.sfn = 0;
2082    tmpTimingInfo.slot = 0;
2083
2084    pdcchTime = tmpTimingInfo;
2085
2086    while(i_sIdx < nsValue)
2087    {
2088       /*Increment frame Offset if PO falls on next SFN*/
2089       if(pdcchTime.sfn != tmpTimingInfo.sfn)
2090       {
2091          frameOffSet++;
2092       }
2093       pdcchTime = tmpTimingInfo;
2094       schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
2095
2096       if (i_sIdx == 0)
2097       {
2098          cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2099          cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2100          i_sIdx++;
2101       }
2102       else
2103       {
2104          cnt++;
2105          if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF)) 
2106          {
2107             cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
2108             cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
2109             cnt = 0;
2110             i_sIdx++;
2111          }
2112       }
2113    }
2114 }
2115
2116 /****************************************************************************
2117  *
2118  * @brief Storing the paging information in SCH database 
2119  *
2120  * @details
2121  *
2122  *    Function : schAddPagingIndtoList
2123  *
2124  *    Functionality: Storing the paging information in SCH database
2125  *
2126  * @params[in] CmLListCp *storedPageList, CmLList *pageIndInfo
2127  *       
2128  * @return ROK - sucess
2129  *         RFAILED - failure
2130  *        
2131  *************************************************************************/
2132 uint8_t schAddPagingIndtoList(CmLListCp *storedPageList,void * pageIndInfo)
2133 {
2134    CmLList  *firstNodeOfList = NULLP;
2135    CmLList  *currentNodeInfo = NULLP;
2136    SchPageInfo *tempNode = NULLP, *recvdNode = NULLP;
2137    
2138    recvdNode = (SchPageInfo*) pageIndInfo;
2139    CM_LLIST_FIRST_NODE(storedPageList,firstNodeOfList);
2140    
2141    SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
2142    if(!currentNodeInfo)
2143    {  
2144       DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Memory allocation failed");
2145       return RFAILED;
2146    }
2147    
2148    currentNodeInfo->node = (PTR)pageIndInfo;
2149    while(firstNodeOfList)
2150    {
2151       tempNode = (SchPageInfo*)(firstNodeOfList->node);
2152       if ((recvdNode->pageTxTime.slot < tempNode->pageTxTime.slot))
2153       {
2154          cmLListInsCrnt(storedPageList, currentNodeInfo);
2155          break;
2156       }
2157       else if ((recvdNode->pageTxTime.slot == tempNode->pageTxTime.slot))
2158       {
2159          DU_LOG("\nERROR  --> SCH : schAddPagingIndtoList() : Slot[%d] is already present in the list", recvdNode->pageTxTime.slot);
2160          return RFAILED;
2161       }
2162       else
2163       {
2164          CM_LLIST_NEXT_NODE(storedPageList, firstNodeOfList);
2165       }
2166    } 
2167    
2168    if(!firstNodeOfList)
2169    {
2170       cmLListAdd2Tail(storedPageList, currentNodeInfo);
2171    }
2172    DU_LOG("\nDEBUG   -->  SCH : Paging information is stored successfully for PF:%d, Slot:%d",\
2173               recvdNode->pageTxTime.sfn, recvdNode->pageTxTime.slot);
2174    return ROK;
2175 }
2176
2177 /****************************************************************************
2178  *
2179  * @brief Process paging indication at  SCH recevied form MAC 
2180  *
2181  * @details
2182  *
2183  *    Function : SchProcPagingInd
2184  *
2185  *    Functionality: Process paging indication at SCH recevied form MAC 
2186  *
2187  * @params[in] Pst *pst,  SchPageInd *pageInd 
2188  *       
2189  * @return void 
2190  *        
2191  *************************************************************************/
2192 uint8_t SchProcPagingInd(Pst *pst,  SchPageInd *pageInd)
2193 {
2194    uint8_t ret = RFAILED;
2195    uint16_t cellIdx = 0;
2196    Inst  inst = pst->dstInst - SCH_INST_START;
2197    SchCellCb *cellCb = NULLP;
2198    SchPageInfo *pageInfo = NULLP;
2199
2200    if(pageInd)
2201    {
2202       DU_LOG("\nDEBUG   -->  SCH : Received paging indication from MAC for cellId[%d]",\
2203                   pageInd->cellId);
2204
2205       /* Fetch Cell CB */
2206       for(cellIdx = 0; cellIdx < MAX_NUM_CELL; cellIdx++)
2207       {
2208          if((schCb[inst].cells[cellIdx]) && (schCb[inst].cells[cellIdx]->cellId == pageInd->cellId))
2209          {
2210             cellCb = schCb[inst].cells[cellIdx];
2211             break;
2212          }
2213       }
2214       if(cellCb)
2215       {
2216          if(pageInd->i_s > cellCb->cellCfg.dlCfgCommon.schPcchCfg.numPO)
2217          {
2218             DU_LOG("\nERROR --> SCH : SchProcPagingInd(): i_s should not be greater than number of paging occasion");
2219          }
2220          else
2221          {
2222             SCH_ALLOC(pageInfo, sizeof(SchPageInfo));
2223             if(pageInfo)
2224             {
2225                pageInfo->pf = pageInd->pf; 
2226                pageInfo->i_s = pageInd->i_s;
2227                pageInfo->pageTxTime.cellId = pageInd->cellId;
2228                pageInfo->pageTxTime.sfn = (pageInd->pf +  cellCb->pageCb.pagMonOcc[pageInd->i_s].frameOffset) % MAX_SFN;
2229                pageInfo->pageTxTime.slot = cellCb->pageCb.pagMonOcc[pageInd->i_s].pagingOccSlot;
2230                pageInfo->mcs = DEFAULT_MCS;
2231                pageInfo->msgLen =  pageInd->pduLen;
2232                SCH_ALLOC(pageInfo->pagePdu, pageInfo->msgLen);
2233                if(!pageInfo->pagePdu)
2234                {
2235                   DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2236                }
2237                else
2238                {
2239                   memcpy(pageInfo->pagePdu, pageInd->pagePdu, pageInfo->msgLen);
2240                   ret = schAddPagingIndtoList(&cellCb->pageCb.pageIndInfoRecord[pageInfo->pageTxTime.sfn], pageInfo);
2241                   if(ret != ROK)
2242                   {
2243                      DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to store paging record");
2244                   }
2245                }
2246             }
2247             else
2248             {
2249                DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Failed to allocate memory");
2250             }
2251          }
2252       }
2253       else
2254       {
2255          DU_LOG("\nERROR  -->  SCH : Cell ID [%d] not found", pageInd->cellId);
2256       }
2257       SCH_FREE(pageInd->pagePdu, pageInd->pduLen);
2258       SCH_FREE(pageInd, sizeof(SchPageInd));
2259    }
2260    else
2261    {
2262       DU_LOG("\nERROR  --> SCH : SchProcPagingInd(): Received null pointer");
2263    }
2264    return ret;
2265 }
2266
2267 \f
2268 /***********************************************************
2269  *
2270  *     Func : SchFillCfmPst 
2271  *        
2272  *
2273  *     Desc : Fills the Confirmation Post Structure cfmPst using the reqPst 
2274  *            and the cfm->hdr.response.
2275  *            
2276  *
2277  *     Ret  : Void
2278  *
2279  *     Notes: 
2280  *
2281  *     File : rg_sch_lmm.c 
2282  *
2283  **********************************************************/
2284 Void SchFillCfmPst
2285 (
2286 Pst           *reqPst,
2287 Pst           *cfmPst,
2288 RgMngmt       *cfm
2289 )
2290 {
2291    Inst inst;
2292
2293    inst = (reqPst->dstInst - SCH_INST_START);
2294
2295    cfmPst->srcEnt    = ENTMAC;
2296    cfmPst->srcInst   = (Inst) 1;
2297    cfmPst->srcProcId = schCb[inst].schInit.procId;
2298    cfmPst->dstEnt    = ENTMAC;
2299    cfmPst->dstInst   = (Inst) 0;
2300    cfmPst->dstProcId = reqPst->srcProcId;
2301
2302    cfmPst->selector  = cfm->hdr.response.selector;
2303    cfmPst->region    = cfm->hdr.response.mem.region;
2304    cfmPst->pool      = cfm->hdr.response.mem.pool;
2305
2306    return;
2307 }
2308
2309 /*******************************************************************
2310  *
2311  * @brief Processes DL CQI ind from MAC
2312  *
2313  * @details
2314  *
2315  *    Function : SchProcDlCqiInd
2316  *
2317  *    Functionality:
2318  *       Processes DL CQI ind from MAC
2319  *
2320  * @params[in] 
2321  * @return ROK     - success
2322  *         RFAILED - failure
2323  *
2324  * ****************************************************************/
2325 uint8_t SchProcDlCqiInd(Pst *pst, SchDlCqiInd *dlCqiInd)
2326 {
2327    uint8_t  ret = ROK;
2328    uint16_t ueId = 0, cellIdx = 0;
2329    SchUeCb *ueCb = NULLP;
2330    SchCellCb *cell = NULLP;
2331    Inst  inst = pst->dstInst-SCH_INST_START;   
2332
2333    if(!dlCqiInd)
2334    {
2335       DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): CQI Ind is empty");
2336       ret = RFAILED;
2337    }
2338    else
2339    {
2340       GET_CELL_IDX(dlCqiInd->cellId, cellIdx);
2341       cell = schCb[inst].cells[cellIdx];
2342       if(cell == NULLP)
2343       { 
2344          DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): cell Id[%d] not found", dlCqiInd->cellId);
2345          ret = RFAILED;
2346       }
2347       else
2348       {
2349          if(cell->cellId == dlCqiInd->cellId)
2350          {
2351             GET_UE_ID(dlCqiInd->crnti, ueId);
2352             ueCb = &cell->ueCb[ueId-1];
2353             if(ueCb->crnti != dlCqiInd->crnti)
2354             {
2355                DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): UeCb for received crnti[%d] not found", dlCqiInd->crnti);
2356                ret = RFAILED;
2357             }
2358             else
2359             {
2360                /*TODO: complete the processing of DL CQI Ind*/ 
2361             }
2362          }
2363          else
2364          {
2365             DU_LOG("\nERROR  -->  SCH : SchProcDlCqiInd(): Received cell Id[%d] from MAC is not matching with CellID[%d] in SCH Cb",\
2366                     dlCqiInd->cellId, cell->cellId);
2367             ret = RFAILED;
2368          }
2369       }
2370    }
2371    return ret;
2372 }
2373
2374 /*******************************************************************
2375  *
2376  * @brief Processes UL CQI ind from MAC
2377  *
2378  * @details
2379  *
2380  *    Function : SchProcUlCqiInd
2381  *
2382  *    Functionality:
2383  *       Processes UL CQI ind from MAC
2384  *
2385  * @params[in] 
2386  * @return ROK     - success
2387  *         RFAILED - failure
2388  *
2389  * ****************************************************************/
2390 uint8_t SchProcUlCqiInd(Pst *pst, SchUlCqiInd *ulCqiInd)
2391 {
2392    uint8_t  ret = ROK;
2393    uint16_t ueId = 0, cellIdx = 0;
2394    SchUeCb *ueCb = NULLP;
2395    SchCellCb *cell = NULLP;
2396    Inst  inst = pst->dstInst-SCH_INST_START;   
2397
2398    if(!ulCqiInd)
2399    {
2400       DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): CQI Ind is empty");
2401       ret = RFAILED;
2402    }
2403    else
2404    {
2405       GET_CELL_IDX(ulCqiInd->cellId, cellIdx);
2406       cell = schCb[inst].cells[cellIdx];
2407       if(cell == NULLP)
2408       { 
2409          DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): cell Id[%d] not found", ulCqiInd->cellId);
2410          ret = RFAILED;
2411       }
2412       else
2413       {
2414          if(cell->cellId == ulCqiInd->cellId)
2415          {
2416             GET_UE_ID(ulCqiInd->crnti, ueId);
2417             ueCb = &cell->ueCb[ueId-1];
2418             if(ueCb->crnti != ulCqiInd->crnti)
2419             {
2420                DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): UeCb for received crnti[%d] not found",ulCqiInd->crnti);
2421                ret = RFAILED;
2422             }
2423             else
2424             {
2425                /*TODO: complete the processing of UL CQI Ind*/ 
2426             }
2427          }
2428          else
2429          {
2430             DU_LOG("\nERROR  -->  SCH : SchProcUlCqiInd(): Received cell Id[%d] from MAC is not matching with CellId[%d] in SCH Cb",\
2431                     ulCqiInd->cellId, cell->cellId);
2432             ret = RFAILED;
2433          }
2434       }
2435    }
2436    return ret;
2437 }
2438
2439 /*******************************************************************
2440  *
2441  * @brief Processes PHR ind from MAC
2442  *
2443  * @details
2444  *
2445  *    Function : SchProcPhrInd
2446  *
2447  *    Functionality:
2448  *       Processes PHR ind from MAC
2449  *
2450  * @params[in] 
2451  * @return ROK     - success
2452  *         RFAILED - failure
2453  *
2454  * ****************************************************************/
2455 uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd)
2456 {
2457    uint8_t  ret = ROK;
2458    uint16_t ueId = 0, cellIdx = 0;
2459    SchUeCb *ueCb = NULLP;
2460    SchCellCb *cell = NULLP;
2461    Inst  inst = pst->dstInst-SCH_INST_START;   
2462
2463    if(!schPhrInd)
2464    {
2465       DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): PHR is empty");
2466       ret = RFAILED;
2467    }
2468    else
2469    {
2470       GET_CELL_IDX(schPhrInd->cellId, cellIdx);
2471       cell = schCb[inst].cells[cellIdx];
2472       if(cell == NULLP)
2473       { 
2474          DU_LOG("\nERROR  -->  SCH : schProcPhrInd(): cell Id[%d] is not found", schPhrInd->cellId);
2475          ret = RFAILED;
2476       }
2477       else
2478       {
2479          if(cell->cellId == schPhrInd->cellId)
2480          {
2481             GET_UE_ID(schPhrInd->crnti, ueId);
2482             ueCb = &cell->ueCb[ueId-1];
2483             if(ueCb->crnti != schPhrInd->crnti)
2484             {
2485                DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): UeCb for received crnti[%d] not found",schPhrInd->crnti);
2486                ret = RFAILED;
2487             }
2488             else
2489             {
2490                /*TODO: complete the processing of PHR Ind*/ 
2491             }
2492          }
2493          else
2494          {
2495             DU_LOG("\nERROR  -->  SCH : SchProcPhrInd(): Mismatch between Received cell Id[%d] from MAC and CellID[%d] in SCH CB ",\
2496                     schPhrInd->cellId, cell->cellId);
2497             ret = RFAILED;
2498          }
2499       }
2500    }
2501    return ret;
2502 }
2503
2504 /*******************************************************************
2505  *
2506  * @brief Fill and send statistics response to MAC
2507  *
2508  * @details
2509  *
2510  *    Function :  SchSendStatsRspToMac
2511  *
2512  *    Functionality: Fill and send statistics response to MAC
2513  *
2514  * @params[in]  Inst inst, SchMacRsp result
2515  * @return ROK     - success
2516  *         RFAILED - failure
2517  *
2518  * ****************************************************************/
2519 uint8_t SchSendStatsRspToMac(Inst inst, SchMacRsp result, CauseOfResult cause)
2520 {
2521    Pst rspPst;
2522    uint8_t ret = ROK;
2523    SchStatsRsp  *statsRsp;
2524
2525    DU_LOG("\nINFO   --> SCH : Filling statistics response");
2526    SCH_ALLOC(statsRsp, sizeof(SchStatsRsp));
2527    if(statsRsp == NULLP)
2528    {
2529       DU_LOG("\nERROR  --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
2530       return RFAILED;
2531    }
2532    memset(statsRsp, 0, sizeof(SchStatsRsp));
2533    statsRsp->rsp = result;
2534    statsRsp->cause = cause;
2535
2536    /* Filling response post */
2537    memset(&rspPst, 0, sizeof(Pst));
2538    FILL_PST_SCH_TO_MAC(rspPst, inst);
2539    rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
2540
2541    ret = MacMessageRouter(&rspPst, (void *)statsRsp);
2542    if(ret == RFAILED)
2543    {
2544       DU_LOG("\nERROR  -->  SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
2545       return ret;
2546    }
2547    return ret;
2548 }
2549
2550 /*******************************************************************
2551  *
2552  * @brief Processes Statistics Request from MAC
2553  *
2554  * @details
2555  *
2556  *    Function : SchProcStatsReq
2557  *
2558  *    Functionality:
2559  *       Processes Statistics Request from MAC
2560  *
2561  * @params[in] 
2562  * @return ROK     - success
2563  *         RFAILED - failure
2564  *
2565  * ****************************************************************/
2566 uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
2567 {
2568    uint8_t idx;
2569    Inst    inst = pst->dstInst - SCH_INST_START;
2570    SchMacRsp     rsp = RSP_OK;
2571    CauseOfResult cause = SUCCESSFUL;
2572    bool isDlTotlPrbUseCfgd = false, isUlTotlPrbUseCfgd = false;
2573
2574    DU_LOG("\nINFO   -->  SCH : Received Statistics Request from MAC");
2575
2576    for(idx=0; idx < statsReq->numStats; idx++)
2577    {
2578       switch(statsReq->statsList[idx].type)
2579       {
2580          case SCH_DL_TOTAL_PRB_USAGE:
2581             {
2582                /* Check if duplicate configuration */
2583                if(schCb[inst].statistics.dlTotalPrbUsage)
2584                {
2585                   DU_LOG("\nERROR   -->  SCH : SCH_DL_TOTAL_PRB_USAGE stats already configured");
2586                   rsp = RSP_NOK;
2587                   cause = DUPLICATE_ENTRY;
2588                }
2589
2590                /* Allocate memory */
2591                SCH_ALLOC(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2592                if(!schCb[inst].statistics.dlTotalPrbUsage)
2593                {
2594                   DU_LOG("\nERROR   -->  SCH : Memory allocation failed for dlTotalPrbUsage in \
2595                         SchProcStatsReq()");
2596                   rsp = RSP_NOK;
2597                   cause = RESOURCE_UNAVAILABLE;
2598                   break;
2599                }
2600
2601                /* Initialize */
2602                memset(schCb[inst].statistics.dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2603
2604                /* Configure */
2605                schCb[inst].statistics.dlTotalPrbUsage->schInst = inst;
2606                schCb[inst].statistics.dlTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
2607                cmInitTimers(&(schCb[inst].statistics.dlTotalPrbUsage->periodTimer), 1);
2608
2609                /* Start timer */
2610                schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), \
2611                      EVENT_DL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.dlTotalPrbUsage->periodicity);
2612
2613                isDlTotlPrbUseCfgd = true;
2614                break;
2615             }
2616
2617          case SCH_UL_TOTAL_PRB_USAGE:
2618             {
2619                /* Check if duplicate configuration */
2620                if(schCb[inst].statistics.ulTotalPrbUsage)
2621                {
2622                   DU_LOG("\nERROR   -->  SCH : SCH_UL_TOTAL_PRB_USAGE stats already configured");
2623                   rsp = RSP_NOK;
2624                   cause = DUPLICATE_ENTRY;
2625                }
2626
2627                /* Allocate memory */
2628                SCH_ALLOC(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2629                if(!schCb[inst].statistics.ulTotalPrbUsage)
2630                {
2631                   DU_LOG("\nERROR   -->  SCH : Memory allocation failed for ulTotalPrbUsage in \
2632                         SchProcStatsReq()");
2633                   rsp = RSP_NOK;
2634                   cause = RESOURCE_UNAVAILABLE;
2635                   break;
2636                }
2637
2638                /* Initialize */
2639                memset(schCb[inst].statistics.ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
2640
2641                /* Configure */
2642                schCb[inst].statistics.ulTotalPrbUsage->schInst = inst;
2643                schCb[inst].statistics.ulTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
2644                cmInitTimers(&(schCb[inst].statistics.ulTotalPrbUsage->periodTimer), 1);
2645
2646                /* Start timer */
2647                schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), \
2648                      EVENT_UL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.ulTotalPrbUsage->periodicity);
2649
2650                isUlTotlPrbUseCfgd = true;
2651                break;
2652             }
2653          default:
2654             {
2655                DU_LOG("\nERROR   -->  SCH : Invalid statistics type [%d]", statsReq->statsList[idx].type);
2656                rsp = RSP_NOK;
2657                cause = PARAM_INVALID;
2658             }
2659       } /* End of switch */
2660
2661       if(rsp == RSP_NOK)
2662       {
2663          /* If failed to configure any KPI, then clear configuration of other
2664           * KPIs that were configured successfully as part of this statsReq */
2665          if(isDlTotlPrbUseCfgd)
2666          {
2667             if((schChkTmr((PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR)) == FALSE)
2668             {
2669                schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR);
2670             }
2671             SCH_FREE(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
2672          }
2673
2674          if(isUlTotlPrbUseCfgd)
2675          {
2676             if((schChkTmr((PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR)) == FALSE)
2677             {
2678                schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR);
2679             }
2680             SCH_FREE(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
2681          }
2682          break;
2683       }
2684    } /* End of FOR */
2685
2686    SCH_FREE(statsReq, sizeof(SchStatsReq));
2687
2688    SchSendStatsRspToMac(inst, rsp, cause);
2689
2690    return ROK;
2691 } /* End of SchProcStatsReq */
2692
2693 /*******************************************************************
2694  *
2695  * @brief Fill and send statistics indication to MAC
2696  *
2697  * @details
2698  *
2699  *    Function :  SchSendStatsIndToMac
2700  *
2701  *    Functionality: Fill and send statistics indication to MAC
2702  *
2703  * @params[in]  SCH Instance
2704  *              Measurement Type
2705  *              Measurement Value
2706  *              Size of value parameter
2707  * @return ROK     - success
2708  *         RFAILED - failure
2709  *
2710  * ****************************************************************/
2711 uint8_t SchSendStatsIndToMac(Inst inst, SchMeasurementType measType, double value)
2712 {
2713    Pst pst;
2714    uint8_t ret = ROK;
2715    SchStatsInd  statsInd;
2716
2717 #ifdef DEBUG_PRINT
2718    DU_LOG("\nDEBUG  --> SCH : Filling statistics indication");
2719 #endif
2720
2721    memset(&statsInd, 0, sizeof(SchStatsInd));
2722    statsInd.type = measType;
2723    statsInd.value = value;
2724
2725    /* Filling post structure */
2726    memset(&pst, 0, sizeof(Pst));
2727    FILL_PST_SCH_TO_MAC(pst, inst);
2728    pst.event = EVENT_STATISTICS_IND_TO_MAC;
2729
2730    ret = MacMessageRouter(&pst, (void *)&statsInd);
2731    if(ret == RFAILED)
2732    {
2733       DU_LOG("\nERROR  -->  SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
2734    }
2735    return ret;
2736 }
2737
2738
2739 /**********************************************************************
2740   End of file
2741  **********************************************************************/