Fix in DL PRB allocation [Issue-ID: ODUHIGH-380]
[o-du/l2.git] / src / 5gnrsch / sch_common.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:     5G NR SCH layer
22
23 Type:     C source file
24
25 Desc:     C source code for Entry point fucntions
26
27 File:     sch_common.c
28
29  **********************************************************************/
30
31 /** @file sch_common.c
32   @brief This module performs common scheduling
33  */
34 #include "common_def.h"
35 #include "tfu.h"
36 #include "lrg.h"
37
38 #include "tfu.x"
39 #include "lrg.x"
40 #include "du_log.h"
41 #include "du_app_mac_inf.h"
42 #include "mac_sch_interface.h"
43 #include "sch.h"
44 #include "sch_utils.h"
45
46 SchCb schCb[SCH_MAX_INST];
47 uint16_t prachCfgIdxTable[MAX_PRACH_CONFIG_IDX][8];
48 uint16_t numRbForPrachTable[MAX_RACH_NUM_RB_IDX][5];
49 uint8_t pucchResourceSet[MAX_PUCCH_RES_SET_IDX][4];
50 uint8_t puschDeltaTable[MAX_MU_PUSCH];
51
52 SchMacUlSchInfoFunc schMacUlSchInfoOpts[] =
53 {
54    packSchMacUlSchInfo,
55    MacProcUlSchInfo,
56    packSchMacUlSchInfo
57 };
58
59 /**
60  * @brief common resource allocation for SSB
61  *
62  * @details
63  *
64  *     Function : schBroadcastSsbAlloc
65  *     
66  *     This function handles common scheduling for SSB
67  *     
68  *  @param[in]  SchCellCb *cell, cell cb
69  *  @param[in]  DlBrdcstAlloc *dlBrdcstAlloc, DL brdcst allocation
70  *  @return  void
71  **/
72 uint8_t schBroadcastSsbAlloc(SchCellCb *cell, SlotTimingInfo slotTime, DlBrdcstAlloc *dlBrdcstAlloc)
73 {
74    /* schedule SSB */
75    uint8_t ssbStartSymb, idx;
76    uint16_t ssbStartPrb;
77    SchDlSlotInfo *schDlSlotInfo;
78    SsbInfo ssbInfo;
79
80    if(cell == NULL)
81    {
82       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : Cell is NULL");
83       return RFAILED;
84    }
85
86    if(dlBrdcstAlloc == NULL)
87    {
88       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : dlBrdcstAlloc is NULL");
89       return RFAILED;
90    }
91
92    schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
93    ssbStartPrb = cell->cellCfg.ssbSchCfg.ssbOffsetPointA; //+Kssb
94    ssbStartSymb = cell->ssbStartSymbArr[dlBrdcstAlloc->ssbIdxSupported-1]; /*since we are supporting only 1 ssb beam */
95
96    /* Assign interface structure */
97    for(idx=0; idx<dlBrdcstAlloc->ssbIdxSupported; idx++)
98    {
99       ssbInfo.ssbIdx              = idx;
100       ssbInfo.fdAlloc.startPrb    = ssbStartPrb;
101       ssbInfo.fdAlloc.numPrb      = SCH_SSB_NUM_PRB;
102       ssbInfo.tdAlloc.startSymb   = ssbStartSymb;
103       ssbInfo.tdAlloc.numSymb     = SCH_SSB_NUM_SYMB;
104       dlBrdcstAlloc->ssbInfo[idx] = ssbInfo;
105       schDlSlotInfo->ssbInfo[idx] = ssbInfo;
106    }
107
108    if((allocatePrbDl(cell, slotTime, ssbStartSymb, SCH_SSB_NUM_SYMB, &ssbInfo.fdAlloc.startPrb, ssbInfo.fdAlloc.numPrb)) != ROK)
109    {
110        DU_LOG("\nERROR  -->  SCH: PRB allocation failed for SSB in SFN:SLOT [%d : %d]", slotTime.sfn, slotTime.slot);
111        return RFAILED;
112    }
113
114
115    schDlSlotInfo->ssbPres = true;
116    schDlSlotInfo->ssbIdxSupported = dlBrdcstAlloc->ssbIdxSupported;
117    return ROK;
118 }
119
120 /**
121  * @brief common resource allocation for SIB1
122  *
123  * @details
124  *
125  *     Function : schBroadcastSib1Alloc
126  *     
127  *     This function handles common scheduling for SIB1
128  *     
129  *  @param[in]  SchCellCb *cell, cell cb
130  *  @param[in]  DlBrdcstAlloc *dlBrdcstAlloc, DL brdcst allocation
131  *  @return  void
132  **/
133 uint8_t schBroadcastSib1Alloc(SchCellCb *cell, SlotTimingInfo slotTime, DlBrdcstAlloc *dlBrdcstAlloc)
134 {
135    uint8_t dmrsStartSymbol, startSymbol, numSymbol ;
136    DmrsInfo dmrs;
137    FreqDomainAlloc freqAlloc;
138    TimeDomainAlloc timeAlloc;
139    SchDlSlotInfo *schDlSlotInfo = NULLP;
140
141    if(cell == NULL)
142    {
143       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : Cell is NULL");
144       return RFAILED;
145    }
146
147    if(dlBrdcstAlloc == NULL)
148    {
149       DU_LOG("\nERROR  -->  SCH: schBroadcastSsbAlloc() : dlBrdcstAlloc is NULL");
150       return RFAILED;
151    }
152
153    dmrs = cell->cellCfg.sib1SchCfg.sib1PdschCfg.dmrs;
154    freqAlloc = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc;
155    timeAlloc = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschTimeAlloc.timeAlloc;
156    schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
157
158    /* Find total symbols used including DMRS */
159    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
160     * in that case only PDSCH symbols are marked as occupied */
161    dmrsStartSymbol = findDmrsStartSymbol(dmrs.dlDmrsSymbPos);   
162    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
163    {
164       startSymbol = timeAlloc.startSymb;
165       numSymbol = timeAlloc.numSymb;
166    }
167    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
168    else
169    {
170       startSymbol = dmrsStartSymbol;
171       numSymbol = dmrs.nrOfDmrsSymbols + timeAlloc.numSymb;
172    }
173
174    /* Allocate PRB */
175    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol, &freqAlloc.startPrb, freqAlloc.numPrb)) != ROK)
176    {
177        DU_LOG("\nERROR  -->  SCH: PRB allocation failed for SIB1 in SFN:Slot [%d : %d]", slotTime.sfn, slotTime.slot);
178        return RFAILED;
179    }
180
181    memcpy(&dlBrdcstAlloc->sib1Alloc.bwp, &cell->cellCfg.sib1SchCfg.bwp, sizeof(BwpCfg)); 
182    memcpy(&dlBrdcstAlloc->sib1Alloc.sib1PdcchCfg, &cell->cellCfg.sib1SchCfg.sib1PdcchCfg, sizeof(PdcchCfg)); 
183    memcpy(&dlBrdcstAlloc->sib1Alloc.sib1PdschCfg, &cell->cellCfg.sib1SchCfg.sib1PdschCfg, sizeof(PdschCfg)); 
184    dlBrdcstAlloc->sib1Alloc.sib1PdcchCfg.dci.pdschCfg = &dlBrdcstAlloc->sib1Alloc.sib1PdschCfg;
185    schDlSlotInfo->sib1Pres = true;
186    return ROK;
187 }
188
189 /*******************************************************************
190  *
191  * @brief Handles sending UL scheduler info to MAC 
192  *
193  * @details
194  *
195  *    Function : sendUlSchInfoToMac
196  *
197  *    Functionality:
198  *     Sends UL Sch info to MAC from SCH
199  *
200  * @params[in] 
201  * @return ROK     - success
202  *         RFAILED - failure
203  *
204  * ****************************************************************/
205 int sendUlSchInfoToMac(UlSchedInfo *ulSchedInfo, Inst inst)
206 {
207    Pst pst;
208
209    memset(&pst, 0, sizeof(Pst));
210    FILL_PST_SCH_TO_MAC(pst, inst);
211    pst.event = EVENT_UL_SCH_INFO;
212
213    return(*schMacUlSchInfoOpts[pst.selector])(&pst, ulSchedInfo);
214 }
215 /**
216  * @brief resource allocation for PRACH
217  *
218  * @details
219  *
220  *     Function : schPrachResAlloc
221  *     
222  *     This function handles PRACH allocation
223  *     
224  *  @param[in]  SchCellCb *cell, cell cb
225  *  @param[in]  UlSchedInfo *ulSchedInfo, UL scheduling info
226  *  @return  void
227  **/
228 void schPrachResAlloc(SchCellCb *cell, UlSchedInfo *ulSchedInfo, SlotTimingInfo prachOccasionTimingInfo)
229 {
230    uint8_t  puschScs;
231    uint8_t  numPrachRb = 0;
232    uint8_t  numRa = 0;
233    uint8_t  freqStart = 0;
234    uint8_t  prachCfgIdx = 0;
235    uint8_t  prachFormat = 0;
236    uint8_t  x = 0;
237    uint8_t  y = 0;
238    uint16_t prachSubframe = 0;
239    uint8_t  prachStartSymbol = 0;
240    uint8_t  prachOcas = 0;
241    uint8_t  dataType = 0;
242    uint8_t  idx = 0;
243    uint8_t  subFrame = 0;
244    SchUlSlotInfo *schUlSlotInfo = NULLP;
245
246    puschScs      = cell->cellCfg.schInitialUlBwp.bwp.scs;
247    schUlSlotInfo = cell->schUlSlotInfo[prachOccasionTimingInfo.slot];
248    prachCfgIdx   = cell->cellCfg.schRachCfg.prachCfgIdx;
249
250    /* derive the prachCfgIdx table paramters */
251    x                = prachCfgIdxTable[prachCfgIdx][1];
252    y                = prachCfgIdxTable[prachCfgIdx][2];
253    prachSubframe    = prachCfgIdxTable[prachCfgIdx][3];
254
255    if((prachOccasionTimingInfo.sfn%x) == y)
256    {
257 #ifdef NR_TDD
258       subFrame = prachOccasionTimingInfo.slot/2;
259 #else
260       subFrame = prachOccasionTimingInfo.slot;
261 #endif
262       /* check for subFrame number */
263       if ((1 << subFrame) & prachSubframe)
264       {
265          /* prach ocassion present in this subframe */
266 #ifdef NR_TDD
267          if(UL_SLOT != schGetSlotSymbFrmt(prachOccasionTimingInfo.slot%cell->numSlotsInPeriodicity,\
268          cell->slotFrmtBitMap))
269          {
270             DU_LOG("\nERROR  --> SCH : PrachCfgIdx %d doesn't support UL slot", prachCfgIdx);
271          }
272          else
273 #endif
274          {
275             prachFormat      = prachCfgIdxTable[prachCfgIdx][0];
276             prachStartSymbol = prachCfgIdxTable[prachCfgIdx][4];
277             prachOcas        = prachCfgIdxTable[prachCfgIdx][6];
278
279             /* freq domain resource determination for RACH*/
280             freqStart = cell->cellCfg.schRachCfg.msg1FreqStart;
281             /* numRa determined as 𝑛 belonging {0,1,.., M − 1}, 
282              * where M is given by msg1Fdm */
283             numRa = (cell->cellCfg.schRachCfg.msg1Fdm - 1);
284             for(idx=0; idx<MAX_RACH_NUM_RB_IDX; idx++)
285             {
286                if(numRbForPrachTable[idx][0] == cell->cellCfg.schRachCfg.rootSeqLen)
287                {
288                   if(numRbForPrachTable[idx][1] == cell->cellCfg.schRachCfg.prachSubcSpacing)
289                   {
290                      if(numRbForPrachTable[idx][2] == puschScs)
291                      {
292                         break;
293                      }
294                   }
295                }
296             }
297             numPrachRb = numRbForPrachTable[idx][3];
298             dataType |= SCH_DATATYPE_PRACH;
299             /* Considering first slot in the frame for PRACH */
300             idx = 0;
301             //schUlSlotInfo->assignedPrb[idx] = freqStart+numPrachRb;
302          }
303          ulSchedInfo->dataType = dataType;
304          /* prach info */
305          ulSchedInfo->prachSchInfo.numPrachOcas   = prachOcas;
306          ulSchedInfo->prachSchInfo.prachFormat    = prachFormat;
307          ulSchedInfo->prachSchInfo.numRa          = numRa;
308          ulSchedInfo->prachSchInfo.prachStartSymb = prachStartSymbol;
309          DU_LOG("\nINFO  --> SCH : RACH occassion set for slot %d", prachOccasionTimingInfo.slot);
310       }
311    }
312 }
313
314
315 /**
316  * @brief Function to fill Pucch Format 0
317  *
318  * @details
319  *
320  *     Function : fillPucchFormat0
321  *     
322  *     Function to fill Pucch format 0
323  *     
324  *  @param[in]  SchPucchInfo pointer, SchPucchResrcInfo pointer
325  *  @return  void
326  **/
327
328 void fillPucchFormat0(SchPucchInfo *ulSchedPucch, SchPucchResrcInfo *resrcInfo)
329 {
330    if(resrcInfo->SchPucchFormat.format0)
331    {
332       ulSchedPucch->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
333       ulSchedPucch->pucchFormat  = PUCCH_FORMAT_0;
334       ulSchedPucch->initialCyclicShift =  resrcInfo->SchPucchFormat.format0->initialCyclicShift;
335       ulSchedPucch->tdAlloc.numSymb = resrcInfo->SchPucchFormat.format0->numSymbols;
336       ulSchedPucch->tdAlloc.startSymb = resrcInfo->SchPucchFormat.format0->startSymbolIdx;
337    }
338 }
339
340 /**
341  * @brief Function to fill Pucch Format 1
342  *
343  * @details
344  *
345  *     Function : fillPucchFormat1
346  *     
347  *     Function to fill Pucch format 1
348  *     
349  *  @param[in]  SchPucchInfo pointer, SchPucchResrcInfo pointer
350  *  @return  void
351  **/
352
353 void fillPucchFormat1(SchPucchInfo *ulSchedPucch, SchPucchResrcInfo *resrcInfo)
354 {
355    if(resrcInfo->SchPucchFormat.format1)
356    {
357       ulSchedPucch->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
358       ulSchedPucch->pucchFormat  = PUCCH_FORMAT_1;
359       ulSchedPucch->initialCyclicShift =  resrcInfo->SchPucchFormat.format1->initialCyclicShift;
360       ulSchedPucch->tdAlloc.numSymb = resrcInfo->SchPucchFormat.format1->numSymbols;
361       ulSchedPucch->tdAlloc.startSymb = resrcInfo->SchPucchFormat.format1->startSymbolIdx;
362       ulSchedPucch->timeDomOCC =  resrcInfo->SchPucchFormat.format1->timeDomOCC;
363   }
364 }
365
366 /**
367  * @brief Function to fill Pucch format for UL Sched Info
368  *
369  * @details
370  *
371  *     Function : fillUlSchedPucchFormat
372  *     
373  *     Function to fill Pucch format for UL Sched Info
374  *     
375  *  @param[in]  pucchFormat , SchPucchInfo pointer,
376  *  @param[in]  SchPucchFormatCfg pointer, SchPucchResrcInfo pointer
377  *  @return  void
378  **/
379
380 uint8_t fillUlSchedPucchFormat(uint8_t pucchFormat, SchPucchInfo *ulSchedPucch,\
381    SchPucchResrcInfo *resrcInfo, SchPucchFormatCfg *formatCfg)
382 {
383    uint8_t ret = ROK;
384
385    switch(pucchFormat)
386    {
387       case PUCCH_FORMAT_0:
388          {
389             if(resrcInfo)
390                fillPucchFormat0(ulSchedPucch, resrcInfo);
391             return ret;
392          }
393       case PUCCH_FORMAT_1:
394          {
395             if(resrcInfo)
396             {
397                fillPucchFormat1(ulSchedPucch, resrcInfo);
398             }
399             if(formatCfg)
400             {
401                memcpy(&ulSchedPucch->cmnFormatCfg, formatCfg, sizeof(SchPucchFormatCfg));
402             }
403             return ret;
404          }/* To Add support for more Pucch Format */
405       
406       default:
407          DU_LOG("\nERROR  --> SCH : Invalid PUCCH format[%d] in fillUlSchedPucchFormatCfg()", pucchFormat);
408          ret = RFAILED;
409          return ret;
410    }
411    return ret;
412 }
413
414 /**
415  * @brief Function to fill Pucch Dedicated Cfg for UL Sched Info
416  *
417  * @details
418  *
419  *     Function : fillUlSchedPucchDedicatedCfg
420  *     
421  *     Function to fill Pucch Dedicated Cfg for UL Sched Info
422  *     
423  *  @param[in]  pucchFormat to be filled
424  *  @param[in]  SchPucchFormatCfg pointer, SchPucchCfg pointer
425  *  @return  void
426  **/
427
428 uint8_t fillUlSchedPucchDedicatedCfg(uint16_t numSlots, SchPucchCfg *pucchDedCfg,\
429    SlotTimingInfo *slotInfo, SchPucchInfo *ulSchedPucch)
430 {
431    uint8_t ret, resrcSetIdx, resrcIdx, schedReqIdx, srPeriodicity = 0;
432    uint16_t srOffset = 0;
433
434    ret = ROK;
435    if(pucchDedCfg->resrcSet && pucchDedCfg->resrc)
436    {
437       //Assuming one entry in the list
438       for(resrcSetIdx = 0; resrcSetIdx < pucchDedCfg->resrcSet->resrcSetToAddModListCount; resrcSetIdx++)
439       {
440          for(resrcIdx = 0; resrcIdx < pucchDedCfg->resrc->resrcToAddModListCount; resrcIdx++)
441          {
442             if(pucchDedCfg->resrcSet->resrcSetToAddModList[resrcSetIdx].resrcList[resrcSetIdx] ==\
443                pucchDedCfg->resrc->resrcToAddModList[resrcIdx].resrcId)
444             {
445                ulSchedPucch->intraFreqHop = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].intraFreqHop;
446                ulSchedPucch->secondPrbHop = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].secondPrbHop;
447                ulSchedPucch->fdAlloc.startPrb = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].startPrb;
448                ulSchedPucch->pucchFormat = pucchDedCfg->resrc->resrcToAddModList[resrcIdx].pucchFormat;
449                ret = fillUlSchedPucchFormat(ulSchedPucch->pucchFormat, ulSchedPucch,\
450                         &pucchDedCfg->resrc->resrcToAddModList[resrcIdx], NULLP);
451                if(ret == RFAILED)
452                   return ret;
453             }
454          }
455       }
456    }
457    if(pucchDedCfg->format1)
458    {
459       memset(&ulSchedPucch->cmnFormatCfg, 0, sizeof(SchPucchFormatCfg));
460       ret = fillUlSchedPucchFormat(ulSchedPucch->pucchFormat, ulSchedPucch, NULLP, pucchDedCfg->format1);
461       if(ret == RFAILED)
462          return ret;
463    }
464    
465    /* setting SR and UCI flag */
466    if(pucchDedCfg->schedReq)
467    {
468       for(schedReqIdx = 0; schedReqIdx < pucchDedCfg->schedReq->schedAddModListCount; schedReqIdx++)
469       {
470          srPeriodicity = pucchDedCfg->schedReq->schedAddModList[schedReqIdx].periodicity;
471          srOffset      = pucchDedCfg->schedReq->schedAddModList[schedReqIdx].offset;
472          break;
473       }
474       if(((numSlots * slotInfo->sfn + slotInfo->slot - srOffset) % srPeriodicity) == 0)
475       {
476          ulSchedPucch->srFlag  = true;
477          ulSchedPucch->uciFlag = true;
478       }
479    }
480    return ret;
481 }
482
483 /**
484  * @brief Function to fill Pucch Resource Info
485  *
486  * @details
487  *
488  *     Function : fillPucchResourceInfo
489  *     
490  *     Function to fill Pucch Resource Info
491  *     
492  *  @param[in]  SchPucchInfo *schPucchInfo, Inst inst
493  *  @return  ROK/RFAILED
494  **/
495
496 uint16_t fillPucchResourceInfo(SchPucchInfo *schPucchInfo, Inst inst)
497 {
498    uint8_t ret = ROK, ueIdx = 0, pucchIdx = 0;
499    SchCellCb  *cell = schCb[inst].cells[inst];
500    SchPucchCfgCmn *pucchCfg = NULLP;
501    SchBwpParams *ulBwp = NULLP;
502
503    GET_UE_IDX(schPucchInfo->rnti, ueIdx);
504    if(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfgPres)
505    {
506       /* fill pucch dedicated cfg */
507       ret = fillUlSchedPucchDedicatedCfg(cell->numSlots,\
508        &cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg, &cell->slotInfo, schPucchInfo);
509       if(ret == RFAILED)
510       {
511          memset(schPucchInfo, 0, sizeof(SchPucchInfo));
512          DU_LOG("\nERROR  --> SCH : Filling PUCCH dedicated cfg failed at fillPucchResourceInfo()");
513          return ret;
514       }
515    }
516    else
517    {
518       /* fill pucch common cfg */
519       /* derive pucchResourceSet from schCellCfg */
520       pucchCfg = &cell->cellCfg.schInitialUlBwp.pucchCommon;
521       pucchIdx = pucchCfg->pucchResourceCommon;
522       ulBwp = &cell->cellCfg.schInitialUlBwp.bwp;
523       schPucchInfo->fdAlloc.startPrb = ulBwp->freqAlloc.startPrb + pucchResourceSet[pucchIdx][3];
524       schPucchInfo->fdAlloc.numPrb = PUCCH_NUM_PRB_FORMAT_0_1_4;
525       schPucchInfo->tdAlloc.startSymb = pucchResourceSet[pucchIdx][1];
526       schPucchInfo->tdAlloc.numSymb = pucchResourceSet[pucchIdx][2];
527       schPucchInfo->pucchFormat = pucchResourceSet[pucchIdx][0];
528
529       /* set SR and UCI flag to false */
530       schPucchInfo->srFlag  = true;
531       schPucchInfo->uciFlag = true;
532    }
533    /* set HARQ flag to true */
534    schPucchInfo->harqFlag = true;
535    schPucchInfo->numHarqBits = 1; /* 1 bit for HARQ */
536
537    return ROK;
538 }
539
540 /**
541  * @brief resource allocation for UL
542  *
543  * @details
544  *
545  *     Function : schUlResAlloc
546  *     
547  *     This function handles UL Resource allocation
548  *     
549  *  @param[in]  SchCellCb *cell, cellCb
550  *  @return  void
551  **/
552 uint8_t schUlResAlloc(SchCellCb *cell, Inst schInst)
553 {
554    int ret = ROK;
555    UlSchedInfo ulSchedInfo;
556    SchUlSlotInfo  *schUlSlotInfo = NULLP;
557    SlotTimingInfo ulTimingInfo;
558    memset(&ulSchedInfo, 0, sizeof(UlSchedInfo));
559
560    /* add PHY delta */
561    ADD_DELTA_TO_TIME(cell->slotInfo,ulTimingInfo,PHY_DELTA_UL+SCHED_DELTA);
562
563    ulSchedInfo.cellId = cell->cellId;
564    ulSchedInfo.slotIndInfo.cellId = ulSchedInfo.cellId;
565    ulSchedInfo.slotIndInfo.sfn = ulTimingInfo.sfn;
566    ulSchedInfo.slotIndInfo.slot = ulTimingInfo.slot;
567
568    /* Schedule resources for PRACH */
569    if(cell->firstSib1Transmitted)
570     schPrachResAlloc(cell, &ulSchedInfo, ulTimingInfo);
571
572    schUlSlotInfo = cell->schUlSlotInfo[ulTimingInfo.slot]; 
573    if(schUlSlotInfo->schPuschInfo)
574    {
575       ulSchedInfo.crnti = schUlSlotInfo->schPuschInfo->crnti;
576       ulSchedInfo.dataType |= SCH_DATATYPE_PUSCH;
577       memcpy(&ulSchedInfo.schPuschInfo, schUlSlotInfo->schPuschInfo,
578             sizeof(SchPuschInfo));
579       SCH_FREE(schUlSlotInfo->schPuschInfo, sizeof(SchPuschInfo));
580       schUlSlotInfo->schPuschInfo = NULL;
581    }
582
583    if(schUlSlotInfo->pucchPres)
584    {
585       ulSchedInfo.dataType |= SCH_DATATYPE_UCI;
586       fillPucchResourceInfo(&schUlSlotInfo->schPucchInfo, schInst);
587       memcpy(&ulSchedInfo.schPucchInfo, &schUlSlotInfo->schPucchInfo,
588             sizeof(SchPucchInfo));
589       memset(&schUlSlotInfo->schPucchInfo, 0, sizeof(SchPucchInfo));
590    }
591
592    //send msg to MAC
593    ret = sendUlSchInfoToMac(&ulSchedInfo, schInst);
594    if(ret != ROK)
595    {
596       DU_LOG("\nERROR  -->  SCH : Sending UL Sch info from SCH to MAC failed");
597    }
598
599    schInitUlSlot(schUlSlotInfo);
600    return ret;
601 }
602
603 /*******************************************************************
604  *
605  * @brief Fills pdcch and pdsch info for msg4
606  *
607  * @details
608  *
609  *    Function : schDlRsrcAllocMsg4
610  *
611  *    Functionality:
612  *       Fills pdcch and pdsch info for msg4
613  *
614  * @params[in] 
615  * @return ROK     - success
616  *         RFAILED - failure
617  *
618  * ****************************************************************/
619 uint8_t schDlRsrcAllocMsg4(SchCellCb *cell, SlotTimingInfo slotTime, DlMsgAlloc *msg4Alloc)
620 {
621    uint8_t coreset0Idx = 0;
622    uint8_t firstSymbol = 0;
623    uint8_t numSymbols = 0;
624    uint8_t mcs = 4;                         /* MCS fixed to 4 */
625    uint8_t dmrsStartSymbol = 0, startSymbol = 0, numSymbol = 0;
626    uint16_t tbSize = 0;
627    uint16_t numRbs;
628    SchBwpDlCfg *initialBwp = NULLP;
629    PdcchCfg *pdcch = NULLP;
630    PdschCfg *pdsch = NULLP;
631    BwpCfg *bwp = NULLP;
632
633    if(cell == NULL)
634    {
635       DU_LOG("\nERROR  -->  SCH: schDlRsrcAllocMsg4() : Cell is NULL");
636       return RFAILED;
637    }
638
639    if(msg4Alloc == NULL)
640    {
641       DU_LOG("\nERROR  -->  SCH: schDlRsrcAllocMsg4() :  msg4Alloc is NULL");
642       return RFAILED;
643    }
644
645    pdcch = &msg4Alloc->dlMsgPdcchCfg;
646    pdsch = &msg4Alloc->dlMsgPdschCfg;
647    bwp = &msg4Alloc->bwp;
648    initialBwp   = &cell->cellCfg.schInitialDlBwp;
649    coreset0Idx  = initialBwp->pdcchCommon.commonSearchSpace.coresetId;
650
651    /* derive the sib1 coreset0 params from table 13-1 spec 38.213 */
652    numRbs     = coresetIdxTable[coreset0Idx][1];
653    numSymbols = coresetIdxTable[coreset0Idx][2];
654
655    /* calculate time domain parameters */
656    uint16_t mask = 0x2000;
657    for(firstSymbol=0; firstSymbol<MAX_SYMB_PER_SLOT; firstSymbol++)
658    {
659       if(initialBwp->pdcchCommon.commonSearchSpace.monitoringSymbol & mask)
660          break;
661       else
662          mask = mask>>1;
663    }
664
665    /* fill BWP */
666    bwp->freqAlloc.numPrb   = initialBwp->bwp.freqAlloc.numPrb;
667    bwp->freqAlloc.startPrb = initialBwp->bwp.freqAlloc.startPrb;
668    bwp->subcarrierSpacing  = initialBwp->bwp.scs;
669    bwp->cyclicPrefix       = initialBwp->bwp.cyclicPrefix;
670
671    /* fill the PDCCH PDU */
672    pdcch->coresetCfg.startSymbolIndex = firstSymbol;
673    pdcch->coresetCfg.durationSymbols = numSymbols;
674    memcpy(pdcch->coresetCfg.freqDomainResource, \
675       cell->cellCfg.schInitialDlBwp.pdcchCommon.commonSearchSpace.freqDomainRsrc, FREQ_DOM_RSRC_SIZE);
676
677    pdcch->coresetCfg.cceRegMappingType = 1; /* coreset0 is always interleaved */
678    pdcch->coresetCfg.regBundleSize = 6;    /* spec-38.211 sec 7.3.2.2 */
679    pdcch->coresetCfg.interleaverSize = 2;  /* spec-38.211 sec 7.3.2.2 */
680    pdcch->coresetCfg.coreSetType = 0;
681    pdcch->coresetCfg.coreSetSize = numRbs;
682    pdcch->coresetCfg.shiftIndex = cell->cellCfg.phyCellId;
683    pdcch->coresetCfg.precoderGranularity = 0; /* sameAsRegBundle */
684    pdcch->numDlDci = 1;
685    pdcch->dci.rnti = cell->schDlSlotInfo[slotTime.slot]->dlMsgInfo->crnti;
686    pdcch->dci.scramblingId = cell->cellCfg.phyCellId;
687    pdcch->dci.scramblingRnti = 0;
688    pdcch->dci.cceIndex = 4; /* considering SIB1 is sent at cce 0-1-2-3 */
689    pdcch->dci.aggregLevel = 4;
690    pdcch->dci.beamPdcchInfo.numPrgs = 1;
691    pdcch->dci.beamPdcchInfo.prgSize = 1;
692    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
693    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
694    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
695    pdcch->dci.txPdcchPower.powerValue = 0;
696    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
697
698    /* fill the PDSCH PDU */
699    uint8_t cwCount = 0;
700    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
701    pdsch->rnti = cell->schDlSlotInfo[slotTime.slot]->dlMsgInfo->crnti;
702    pdsch->pduIndex = 0;
703    pdsch->numCodewords = 1;
704    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
705    {
706       pdsch->codeword[cwCount].targetCodeRate = 308;
707       pdsch->codeword[cwCount].qamModOrder = 2;
708       pdsch->codeword[cwCount].mcsIndex = mcs; /* mcs configured to 4 */
709       pdsch->codeword[cwCount].mcsTable = 0; /* notqam256 */
710       pdsch->codeword[cwCount].rvIndex = 0;
711       tbSize = schCalcTbSize(msg4Alloc->dlMsgInfo.dlMsgPduLen + TX_PAYLOAD_HDR_LEN); /* MSG4 size + FAPI header size*/
712       pdsch->codeword[cwCount].tbSize = tbSize;
713    }
714    pdsch->dataScramblingId = cell->cellCfg.phyCellId;
715    pdsch->numLayers = 1;
716    pdsch->transmissionScheme = 0;
717    pdsch->refPoint = 0;
718    pdsch->dmrs.dlDmrsSymbPos = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
719    pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
720    pdsch->dmrs.dlDmrsScramblingId = cell->cellCfg.phyCellId;
721    pdsch->dmrs.scid = 0;
722    pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
723    pdsch->dmrs.dmrsPorts = 0;
724    pdsch->dmrs.mappingType      = DMRS_MAP_TYPE_A; /* Setting to Type-A */
725    pdsch->dmrs.nrOfDmrsSymbols  = NUM_DMRS_SYMBOLS;
726    pdsch->dmrs.dmrsAddPos       = DMRS_ADDITIONAL_POS;
727
728    pdsch->pdschTimeAlloc.timeAlloc.startSymb = 3; /* spec-38.214, Table 5.1.2.1-1 */
729    pdsch->pdschTimeAlloc.timeAlloc.numSymb = NUM_PDSCH_SYMBOL;
730
731    pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
732    pdsch->pdschFreqAlloc.freqAlloc.startPrb = MAX_NUM_RB;
733    pdsch->pdschFreqAlloc.freqAlloc.numPrb = schCalcNumPrb(tbSize, mcs, NUM_PDSCH_SYMBOL);
734    pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
735
736    /* Find total symbols occupied including DMRS */
737    dmrsStartSymbol = findDmrsStartSymbol(pdsch->dmrs.dlDmrsSymbPos);
738    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
739     * in that case only PDSCH symbols are marked as occupied */
740    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
741    {
742       startSymbol = pdsch->pdschTimeAlloc.timeAlloc.startSymb;
743       numSymbol = pdsch->pdschTimeAlloc.timeAlloc.numSymb;
744    }
745    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
746    else
747    {
748       startSymbol = dmrsStartSymbol;
749       numSymbol = pdsch->dmrs.nrOfDmrsSymbols + pdsch->pdschTimeAlloc.timeAlloc.numSymb;
750    }
751
752    /* Allocate the number of PRBs required for RAR PDSCH */
753    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol,\
754       &pdsch->pdschFreqAlloc.freqAlloc.startPrb, pdsch->pdschFreqAlloc.freqAlloc.numPrb)) != ROK)
755    {
756       DU_LOG("\nERROR  --> SCH : Resource allocation failed for MSG4");
757       return RFAILED;
758    }
759
760    pdsch->beamPdschInfo.numPrgs = 1;
761    pdsch->beamPdschInfo.prgSize = 1;
762    pdsch->beamPdschInfo.digBfInterfaces = 0;
763    pdsch->beamPdschInfo.prg[0].pmIdx = 0;
764    pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
765    pdsch->txPdschPower.powerControlOffset = 0;
766    pdsch->txPdschPower.powerControlOffsetSS = 0;
767
768    pdcch->dci.pdschCfg = pdsch;
769
770    return ROK;
771 }
772  
773 uint16_t schAllocPucchResource(SchCellCb *cell, uint16_t crnti, uint16_t slot)
774 {
775    uint8_t k1 = SCH_DEFAULT_K1, ueIdx = 0, dlToUlAckIdx;
776    uint16_t pucchSlot = 0;
777    SchUlSlotInfo  *schUlSlotInfo = NULLP;
778    SchPucchCfg    *schPucchCfg = NULLP;
779
780    GET_UE_IDX(crnti, ueIdx);
781    if(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfgPres)
782    {
783       schPucchCfg = &(cell->ueCb[ueIdx].ueCfg.spCellCfg.servCellCfg.initUlBwp.pucchCfg);
784      if(schPucchCfg->dlDataToUlAck)
785      {
786         for(dlToUlAckIdx = 0; dlToUlAckIdx < schPucchCfg->dlDataToUlAck->dlDataToUlAckListCount; dlToUlAckIdx++)
787         {
788            //For now considering only the first value in the list
789            k1 = schPucchCfg->dlDataToUlAck->dlDataToUlAckList[dlToUlAckIdx];
790            break;
791         }
792      }
793    }
794    
795    pucchSlot = (slot + k1)  % cell->numSlots;
796    schUlSlotInfo = cell->schUlSlotInfo[pucchSlot];
797    memset(&schUlSlotInfo->schPucchInfo, 0, sizeof(SchPucchInfo));
798
799    schUlSlotInfo->pucchPres = true;
800    schUlSlotInfo->schPucchInfo.rnti = crnti;
801
802    return ROK;
803 }
804
805 /*******************************************************************
806  *
807  * @brief Fills pdcch and pdsch info for dedicated DL msg
808  *
809  * @details
810  *
811  *    Function : schDlRsrcAllocDlMsg
812  *
813  *    Functionality:
814  *       Fills pdcch and pdsch info for dl msg
815  *
816  * @params[in]
817  * @return ROK     - success
818  *         RFAILED - failure
819  *
820  * ****************************************************************/
821 uint8_t schDlRsrcAllocDlMsg(SchCellCb *cell, SlotTimingInfo slotTime, uint16_t crnti,
822       uint32_t *accumalatedSize, DlMsgAlloc *dlMsgAlloc)
823 {
824    uint8_t ueIdx;
825    uint16_t tbSize = 0;
826    PdcchCfg *pdcch = NULLP;
827    PdschCfg *pdsch = NULLP;
828    BwpCfg *bwp = NULLP;
829    SchUeCb ueCb;
830    SchControlRsrcSet coreset1;
831    SchPdschConfig pdschCfg;
832    uint8_t dmrsStartSymbol, startSymbol, numSymbol;
833
834    pdcch = &dlMsgAlloc->dlMsgPdcchCfg;
835    pdsch = &dlMsgAlloc->dlMsgPdschCfg;
836    bwp = &dlMsgAlloc->bwp;
837
838    GET_UE_IDX(crnti, ueIdx);
839    ueCb  = cell->ueCb[ueIdx-1];
840    coreset1 = ueCb.ueCfg.spCellCfg.servCellCfg.initDlBwp.pdcchCfg.cRSetToAddModList[0];
841    pdschCfg = ueCb.ueCfg.spCellCfg.servCellCfg.initDlBwp.pdschCfg;
842
843    /* fill BWP */
844    bwp->freqAlloc.numPrb = MAX_NUM_RB;
845    bwp->freqAlloc.startPrb = 0;
846    bwp->subcarrierSpacing = cell->cellCfg.sib1SchCfg.bwp.subcarrierSpacing;
847    bwp->cyclicPrefix = cell->cellCfg.sib1SchCfg.bwp.cyclicPrefix;
848
849    /* fill the PDCCH PDU */
850    //Considering coreset1 also starts from same symbol as coreset0
851    pdcch->coresetCfg.startSymbolIndex = coresetIdxTable[0][3];
852    pdcch->coresetCfg.durationSymbols = coreset1.duration;
853    memcpy(pdcch->coresetCfg.freqDomainResource, coreset1.freqDomainRsrc, FREQ_DOM_RSRC_SIZE);
854    pdcch->coresetCfg.cceRegMappingType = coreset1.cceRegMappingType; /* non-interleaved */
855    pdcch->coresetCfg.regBundleSize = 6;   /* must be 6 for non-interleaved */
856    pdcch->coresetCfg.interleaverSize = 0; /* NA for non-interleaved */
857    pdcch->coresetCfg.coreSetType = 1; /* non PBCH coreset */
858    //Considering number of RBs in coreset1 is same as coreset0
859    pdcch->coresetCfg.coreSetSize = coresetIdxTable[0][1];
860    pdcch->coresetCfg.shiftIndex = cell->cellCfg.phyCellId;
861    pdcch->coresetCfg.precoderGranularity =  coreset1.precoderGranularity;
862    pdcch->numDlDci = 1;
863    pdcch->dci.rnti = ueCb.crnti;
864    pdcch->dci.scramblingId = cell->cellCfg.phyCellId;
865    pdcch->dci.scramblingRnti = 0;
866    pdcch->dci.cceIndex = 0; /* 0-3 for UL and 4-7 for DL */
867    pdcch->dci.aggregLevel = 4;
868    pdcch->dci.beamPdcchInfo.numPrgs = 1;
869    pdcch->dci.beamPdcchInfo.prgSize = 1;
870    pdcch->dci.beamPdcchInfo.digBfInterfaces = 0;
871    pdcch->dci.beamPdcchInfo.prg[0].pmIdx = 0;
872    pdcch->dci.beamPdcchInfo.prg[0].beamIdx[0] = 0;
873    pdcch->dci.txPdcchPower.powerValue = 0;
874    pdcch->dci.txPdcchPower.powerControlOffsetSS = 0;
875
876    /* fill the PDSCH PDU */
877    uint8_t cwCount = 0;
878    pdsch->pduBitmap = 0; /* PTRS and CBG params are excluded */
879    pdsch->rnti = ueCb.crnti;
880    pdsch->pduIndex = 0;
881    pdsch->numCodewords = 1;
882    for(cwCount = 0; cwCount < pdsch->numCodewords; cwCount++)
883    {
884       pdsch->codeword[cwCount].targetCodeRate = 308;
885       pdsch->codeword[cwCount].qamModOrder = ueCb.ueCfg.dlModInfo.modOrder;
886       pdsch->codeword[cwCount].mcsIndex = ueCb.ueCfg.dlModInfo.mcsIndex;
887       pdsch->codeword[cwCount].mcsTable = ueCb.ueCfg.dlModInfo.mcsTable;
888       pdsch->codeword[cwCount].rvIndex = 0;
889       tbSize = schCalcTbSize(*accumalatedSize + TX_PAYLOAD_HDR_LEN);
890       if(tbSize < *accumalatedSize)
891          *accumalatedSize = tbSize - TX_PAYLOAD_HDR_LEN;
892       pdsch->codeword[cwCount].tbSize = tbSize;
893    }
894    pdsch->dataScramblingId = cell->cellCfg.phyCellId;
895    pdsch->numLayers = 1;
896    pdsch->transmissionScheme = 0;
897    pdsch->refPoint = 0;
898    pdsch->dmrs.dlDmrsSymbPos = 4; /* Bitmap value 00000000000100 i.e. using 3rd symbol for PDSCH DMRS */
899    pdsch->dmrs.dmrsConfigType = 0; /* type-1 */
900    pdsch->dmrs.dlDmrsScramblingId = cell->cellCfg.phyCellId;
901    pdsch->dmrs.scid = 0;
902    pdsch->dmrs.numDmrsCdmGrpsNoData = 1;
903    pdsch->dmrs.dmrsPorts = 0;
904    pdsch->dmrs.mappingType      = DMRS_MAP_TYPE_A; /* Setting to Type-A */
905    pdsch->dmrs.nrOfDmrsSymbols  = NUM_DMRS_SYMBOLS;
906    pdsch->dmrs.dmrsAddPos       = pdschCfg.dmrsDlCfgForPdschMapTypeA.addPos;
907
908    pdsch->pdschTimeAlloc.timeAlloc.startSymb = pdschCfg.timeDomRsrcAllociList[0].startSymbol;
909    pdsch->pdschTimeAlloc.timeAlloc.numSymb = pdschCfg.timeDomRsrcAllociList[0].symbolLength;
910
911    pdsch->pdschFreqAlloc.vrbPrbMapping = 0; /* non-interleaved */
912    pdsch->pdschFreqAlloc.resourceAllocType = 1; /* RAT type-1 RIV format */
913    pdsch->pdschFreqAlloc.freqAlloc.startPrb = MAX_NUM_RB;
914    pdsch->pdschFreqAlloc.freqAlloc.numPrb = schCalcNumPrb(tbSize, ueCb.ueCfg.dlModInfo.mcsIndex, \
915                    pdschCfg.timeDomRsrcAllociList[0].symbolLength);
916
917    /* Find total symbols occupied including DMRS */
918    dmrsStartSymbol = findDmrsStartSymbol(pdsch->dmrs.dlDmrsSymbPos);
919    /* If there are no DRMS symbols, findDmrsStartSymbol() returns MAX_SYMB_PER_SLOT,
920     * in that case only PDSCH symbols are marked as occupied */
921    if(dmrsStartSymbol == MAX_SYMB_PER_SLOT)
922    {
923       startSymbol = pdsch->pdschTimeAlloc.timeAlloc.startSymb;
924       numSymbol = pdsch->pdschTimeAlloc.timeAlloc.numSymb;
925    }
926    /* If DMRS symbol is found, mark DMRS and PDSCH symbols as occupied */
927    else
928    {
929       startSymbol = dmrsStartSymbol;
930       numSymbol = pdsch->dmrs.nrOfDmrsSymbols + pdsch->pdschTimeAlloc.timeAlloc.numSymb;
931    }
932
933    /* Allocate the number of PRBs required for DL PDSCH */
934    if((allocatePrbDl(cell, slotTime, startSymbol, numSymbol,\
935       &pdsch->pdschFreqAlloc.freqAlloc.startPrb, pdsch->pdschFreqAlloc.freqAlloc.numPrb)) != ROK)
936    {
937       DU_LOG("\nERROR  --> SCH : allocatePrbDl() failed for DL MSG");
938       return RFAILED;
939    }
940
941    pdsch->beamPdschInfo.numPrgs = 1;
942    pdsch->beamPdschInfo.prgSize = 1;
943    pdsch->beamPdschInfo.digBfInterfaces = 0;
944    pdsch->beamPdschInfo.prg[0].pmIdx = 0;
945    pdsch->beamPdschInfo.prg[0].beamIdx[0] = 0;
946    pdsch->txPdschPower.powerControlOffset = 0;
947    pdsch->txPdschPower.powerControlOffsetSS = 0;
948
949    pdcch->dci.pdschCfg = pdsch;
950    return ROK;
951 }
952
953 /*******************************************************************
954  *
955  * @brief Fills k0 and k1 information table for FDD 
956  *
957  * @details
958  *
959  *    Function : BuildK0K1TableForFdd 
960  *
961  *    Functionality:
962  *      Fills k0 and k1 information table for FDD
963  *
964  * @params[in] SchCellCb *cell,SchK0K1TimingInfoTbl *k0K1InfoTbl,bool
965  * pdschCfgCmnPres,uint8_t numTimeDomAlloc, SchPdschCfgCmnTimeDomRsrcAlloc
966  * cmnTimeDomRsrcAllocList[], SchPdschTimeDomRsrcAlloc
967  * dedTimeDomRsrcAllocList[], uint8_t ulAckListCount, uint8_t *UlAckTbl
968  * @return ROK     - success
969  *         RFAILED - failure
970  *
971  * ****************************************************************/
972 void BuildK0K1TableForFdd(SchCellCb *cell, SchK0K1TimingInfoTbl *k0K1InfoTbl, bool pdschCfgCmnPres,SchPdschCfgCmn pdschCmnCfg,\
973 SchPdschConfig pdschDedCfg, uint8_t ulAckListCount, uint8_t *UlAckTbl)
974 {
975    
976    uint8_t k1TmpVal =0, cfgIdx=0;
977    uint8_t slotIdx=0, k0Index=0, k1Index=0, numK0=0, numK1=0, numTimeDomAlloc=0;
978    
979    /* TODO Commented these below lines for resolving warnings. Presently these variable are not 
980     * required but this will require for harq processing */
981    // uint8_t k0TmpVal = 0; 
982    // SchPdschCfgCmnTimeDomRsrcAlloc cmnTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
983    // SchPdschTimeDomRsrcAlloc dedTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
984
985    /* Initialization the structure and storing the total slot values. */
986    memset(k0K1InfoTbl, 0, sizeof(SchK0K1TimingInfoTbl));
987    k0K1InfoTbl->tblSize = cell->numSlots;
988    
989    /* Storing time domain resource allocation list based on common or dedicated configuration. */
990    if(pdschCfgCmnPres == true)
991    {
992       numTimeDomAlloc = pdschCmnCfg.numTimeDomAlloc;
993       for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
994       {
995          /*TODO uncomment this line during harq processing */
996          //cmnTimeDomRsrcAllocList[cfgIdx] = pdschCmnCfg.timeDomRsrcAllocList[cfgIdx];
997       }
998    }
999    else
1000    {
1001       numTimeDomAlloc = pdschDedCfg.numTimeDomRsrcAlloc;
1002       for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1003       {
1004          /*TODO uncomment this line during harq processing */
1005          //dedTimeDomRsrcAllocList[cfgIdx] = pdschDedCfg.timeDomRsrcAllociList[cfgIdx];
1006       }
1007    }
1008    
1009    /* Checking all the slots for K0 and K1 values. */
1010    for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1011    {
1012       numK0 = 0;
1013       /* Storing the values of k0 based on time domain resource
1014        * allocation list. If the value is unavailable then fill default values,
1015        * As per 38.331 PDSCH-TimeDomainResourceAllocation field descriptions. */
1016       for(k0Index = 0; ((k0Index < numTimeDomAlloc) && (k0Index < MAX_NUM_K0_IDX));  k0Index++)
1017       {
1018          /* TODO These if 0 we will remove during harq processing */
1019 #if 0
1020          if(pdschCfgCmnPres == true)
1021          {
1022             k0TmpVal = cmnTimeDomRsrcAllocList[k0Index].k0;
1023          }
1024          else
1025          {
1026             if(dedTimeDomRsrcAllocList[k0Index].k0 != NULLP)
1027             {
1028                k0TmpVal = *(dedTimeDomRsrcAllocList[k0Index].k0);
1029             }
1030             else
1031             { 
1032                k0TmpVal = DEFAULT_K0_VALUE;
1033             }
1034          }
1035 #endif         
1036          /* Checking all the Ul Alloc values. If value is less than MIN_NUM_K1_IDX
1037           * then skip else continue storing the values. */
1038          numK1 = 0;
1039          for(k1Index = 0; k1Index < ulAckListCount; k1Index++)
1040          {
1041             k1TmpVal = UlAckTbl[k1Index];
1042             if(k1TmpVal <= MIN_NUM_K1_IDX)
1043             {
1044                continue;
1045             }
1046
1047             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.k1Indexes[numK1++] = k1Index;
1048             /* TODO Store K1 index where harq feedback will be received in harq table. */ 
1049          }
1050          if(numK1)
1051          {
1052             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.numK1 = numK1;
1053             k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k0Index = k0Index;
1054             numK0++;
1055          }
1056       }
1057       if(numK0)
1058       {
1059          k0K1InfoTbl->k0k1TimingInfo[slotIdx].numK0 = numK0;
1060       }
1061    }
1062 }
1063
1064 /*******************************************************************
1065  *
1066  * @brief Fills k0 and k1 information table  
1067  *
1068  * @details
1069  *
1070  *    Function : BuildK0K1Table
1071  *
1072  *    Functionality:
1073  *       Fills K0 and k1 information table 
1074  *
1075  * @params[in] SchCellCb *cell,SchK0K1TimingInfoTbl *k0K1InfoTbl,bool
1076  * pdschCfgCmnPres,uint8_t numTimeDomAlloc, SchPdschCfgCmnTimeDomRsrcAlloc
1077  * cmnTimeDomRsrcAllocList[], SchPdschTimeDomRsrcAlloc
1078  * dedTimeDomRsrcAllocList[], uint8_t ulAckListCount, uint8_t *UlAckTbl
1079  * @return ROK     - success
1080  *         RFAILED - failure
1081  *
1082  * ****************************************************************/
1083 void BuildK0K1Table(SchCellCb *cell, SchK0K1TimingInfoTbl *k0K1InfoTbl, bool pdschCfgCmnPres, SchPdschCfgCmn pdschCmnCfg,\
1084 SchPdschConfig pdschDedCfg, uint8_t ulAckListCount, uint8_t *UlAckTbl)
1085 {
1086
1087 #ifdef NR_TDD
1088    SlotConfig  slotCfg;
1089    bool ulSlotPresent = false;
1090    uint8_t k0TmpVal = 0, k1TmpVal =0, tmpSlot=0, startSymbol=0, endSymbol=0, checkSymbol=0;
1091    uint8_t slotIdx=0, k0Index=0, k1Index=0, numK0=0, numK1=0, cfgIdx=0, numTimeDomAlloc =0, totalCfgSlot =0;
1092    SchPdschCfgCmnTimeDomRsrcAlloc cmnTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1093    SchPdschTimeDomRsrcAlloc dedTimeDomRsrcAllocList[MAX_NUM_DL_ALLOC];
1094 #endif
1095
1096    if(cell->cellCfg.dupMode == DUPLEX_MODE_FDD)
1097    {
1098       BuildK0K1TableForFdd(cell, k0K1InfoTbl, pdschCfgCmnPres, pdschCmnCfg, pdschDedCfg, ulAckListCount, UlAckTbl);
1099    }
1100    else
1101    {
1102 #ifdef NR_TDD
1103       
1104       /* Initialization the K0K1 structure, total num of slot and calculating the slot pattern length. */
1105       memset(k0K1InfoTbl, 0, sizeof(SchK0K1TimingInfoTbl));
1106       k0K1InfoTbl->tblSize = cell->numSlots;
1107       totalCfgSlot = calculateSlotPatternLength(cell->cellCfg.ssbSchCfg.scsCommon, cell->cellCfg.tddCfg.tddPeriod);
1108       
1109       /* Storing time domain resource allocation list based on common or 
1110        * dedicated configuration availability. */
1111       if(pdschCfgCmnPres == true)
1112       {
1113          numTimeDomAlloc = pdschCmnCfg.numTimeDomAlloc;
1114          for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1115          {
1116             cmnTimeDomRsrcAllocList[cfgIdx] = pdschCmnCfg.timeDomRsrcAllocList[cfgIdx];
1117          }
1118       }
1119       else
1120       {
1121          numTimeDomAlloc = pdschDedCfg.numTimeDomRsrcAlloc;
1122          for(cfgIdx = 0; cfgIdx<numTimeDomAlloc; cfgIdx++)
1123          {
1124             dedTimeDomRsrcAllocList[cfgIdx] = pdschDedCfg.timeDomRsrcAllociList[cfgIdx];
1125          }
1126       }
1127
1128       /* Checking all possible indexes for K0 and K1 values. */
1129       for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1130       {
1131          /* If current slot is UL or FLEXI then Skip because PDCCH is sent only in DL slots. */
1132          slotCfg = schGetSlotSymbFrmt(slotIdx%totalCfgSlot, cell->slotFrmtBitMap);
1133          if(slotCfg == UL_SLOT || slotCfg == FLEXI_SLOT)
1134          {
1135             continue;
1136          }
1137          
1138          /* Storing K0 , start symbol and length symbol for further processing.
1139           * If K0 value is not available then we can fill the default values
1140           * given in spec 38.331. */
1141          numK0 = 0;
1142          for(k0Index = 0; ((k0Index < numTimeDomAlloc) && (k0Index < MAX_NUM_K0_IDX)); k0Index++)
1143          {
1144             if(pdschCfgCmnPres == true)
1145             {
1146                k0TmpVal = cmnTimeDomRsrcAllocList[k0Index].k0;
1147                startSymbol = cmnTimeDomRsrcAllocList[k0Index].startSymbol;
1148                endSymbol = startSymbol + cmnTimeDomRsrcAllocList[k0Index].lengthSymbol;
1149             }
1150             else
1151             {
1152                if(dedTimeDomRsrcAllocList[k0Index].k0 != NULLP)
1153                {
1154                   k0TmpVal =  *(dedTimeDomRsrcAllocList[k0Index].k0);
1155                }
1156                else
1157                {
1158                   k0TmpVal = DEFAULT_K0_VALUE;
1159                }
1160                startSymbol = dedTimeDomRsrcAllocList[k0Index].startSymbol;
1161                endSymbol = startSymbol + dedTimeDomRsrcAllocList[k0Index].symbolLength;
1162             }
1163             
1164             /* If current slot + k0 is UL then skip the slot
1165              * else if it is DL slot then continue the next steps
1166              * else if it is a FLEXI slot then check symbols of slot, It should not
1167              * contain any UL slot. */
1168             tmpSlot = (slotIdx+k0TmpVal) % totalCfgSlot;
1169             slotCfg = schGetSlotSymbFrmt(tmpSlot, cell->slotFrmtBitMap);
1170             if(slotCfg == UL_SLOT)
1171             {
1172                continue;
1173             }
1174             if(slotCfg == FLEXI_SLOT)
1175             {
1176                for(checkSymbol = startSymbol; checkSymbol<endSymbol; checkSymbol ++)
1177                {
1178                   slotCfg = cell->cellCfg.tddCfg.slotCfg[tmpSlot][checkSymbol];
1179                   if(slotCfg == UL_SLOT)
1180                   {
1181                      continue;
1182                   }
1183                }
1184             }
1185
1186             /* If current slot + k0 + k1 is a DL slot then skip the slot
1187              * else if it is UL slot then store the information 
1188              * else if it is FLEXI slot then check the symbols, it must have
1189              * at least one UL symbol. */
1190             numK1 = 0;
1191             for(k1Index = 0; k1Index < ulAckListCount; k1Index++)
1192             {
1193                k1TmpVal = UlAckTbl[k1Index];
1194                if(k1TmpVal > MIN_NUM_K1_IDX)
1195                {
1196                   tmpSlot = (slotIdx+k0TmpVal+k1TmpVal) % totalCfgSlot;
1197                   slotCfg =  schGetSlotSymbFrmt(tmpSlot, cell->slotFrmtBitMap);
1198                   if(slotCfg == DL_SLOT) 
1199                   {
1200                      continue;
1201                   }   
1202                   if(slotCfg == FLEXI_SLOT)
1203                   {
1204                      for(checkSymbol = 0; checkSymbol< MAX_SYMB_PER_SLOT;checkSymbol++)
1205                      {
1206                         if(cell->cellCfg.tddCfg.slotCfg[tmpSlot][checkSymbol] == UL_SLOT)
1207                         {
1208                            ulSlotPresent = true;
1209                            break;
1210                         }
1211                      }
1212                   }
1213                   if(ulSlotPresent == true || slotCfg ==  UL_SLOT)
1214                   {
1215                      k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.k1Indexes[numK1++] = k1Index;
1216                      /* TODO Store K1 index where harq feedback will be received
1217                       * in harq table. */
1218                   }
1219                }
1220             }
1221             
1222             /* Store all the values if all condition satisfies. */
1223             if(numK1)
1224             {
1225                k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k1TimingInfo.numK1 = numK1;
1226                k0K1InfoTbl->k0k1TimingInfo[slotIdx].k0Indexes[numK0].k0Index = k0Index;
1227                numK0++;
1228             }
1229          }
1230          if(numK0)
1231          {
1232             k0K1InfoTbl->k0k1TimingInfo[slotIdx].numK0 = numK0;
1233          }
1234       }
1235 #endif
1236    }
1237 }
1238
1239 /*******************************************************************
1240 *
1241 * @brief Fills K2 information table for FDD
1242 *
1243 * @details
1244 *
1245 *    Function : BuildK2InfoTableForFdd 
1246 *
1247 *    Functionality:
1248 *       Fills K2 information table for FDD
1249 *
1250 * @params[in] SchCellCb *cell,SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[],
1251 * uint16_t puschSymTblSize,SchK2TimingInfoTbl *k2InfoTbl
1252 * @return ROK     - success
1253 *         RFAILED - failure
1254 *
1255 * ****************************************************************/
1256 void BuildK2InfoTableForFdd(SchCellCb *cell, SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[], uint16_t puschSymTblSize,\
1257 SchK2TimingInfoTbl *msg3K2InfoTbl, SchK2TimingInfoTbl *k2InfoTbl)
1258 {
1259    uint16_t slotIdx=0, k2Index=0, k2TmpIdx=0, msg3K2TmpIdx=0;
1260
1261    /* Initialization the structure and storing the total slot values. */
1262    memset(k2InfoTbl, 0, sizeof(SchK2TimingInfoTbl));
1263    k2InfoTbl->tblSize = cell->numSlots;
1264    if(msg3K2InfoTbl)
1265       msg3K2InfoTbl->tblSize = cell->numSlots;
1266    
1267    /* Checking all possible indexes for K2. */
1268    for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1269    {
1270       /* Storing K2 values. */
1271       for(k2Index = 0; ((k2Index < puschSymTblSize) && (k2Index < MAX_NUM_K2_IDX)); k2Index++)
1272       {
1273          k2TmpIdx= k2InfoTbl->k2TimingInfo[slotIdx].numK2;
1274          k2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[k2TmpIdx] = k2Index;
1275          k2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1276
1277          /* Updating K2 values for MSG3 */
1278          if(msg3K2InfoTbl)
1279          {
1280             msg3K2TmpIdx = msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2;
1281             msg3K2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[msg3K2TmpIdx] = k2Index;
1282             msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1283          }
1284       }
1285    }
1286 }
1287
1288 /*******************************************************************
1289  *
1290  * @brief Fills K2 information table
1291  *
1292  * @details
1293  *
1294  *    Function : BuildK2InfoTable 
1295  *
1296  *    Functionality:
1297  *       Fills K2 information table
1298  *
1299  * @params[in] SchCellCb *cell,SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[],
1300  * uint16_t puschSymTblSize, SchK2TimingInfoTbl *k2InfoTbl
1301  * @return ROK     - success
1302  *         RFAILED - failure
1303  *
1304  * ****************************************************************/
1305 void BuildK2InfoTable(SchCellCb *cell, SchPuschTimeDomRsrcAlloc timeDomRsrcAllocList[], uint16_t puschSymTblSize,\
1306 SchK2TimingInfoTbl *msg3K2InfoTbl, SchK2TimingInfoTbl *k2InfoTbl)
1307 {
1308
1309 #ifdef NR_TDD
1310    bool dlSymbolPresent = false;
1311    uint8_t slotIdx=0, k2Index=0, k2Val=0, k2TmpVal=0, msg3K2TmpVal=0, msg3Delta=0, numK2 =0, currentSymbol =0;
1312    uint8_t startSymbol =0, endSymbol =0, checkSymbol=0, totalCfgSlot=0, slotCfg=0;
1313    SlotConfig currentSlot;
1314 #endif
1315
1316    if(cell->cellCfg.dupMode == DUPLEX_MODE_FDD)
1317    {
1318       BuildK2InfoTableForFdd(cell, timeDomRsrcAllocList, puschSymTblSize, msg3K2InfoTbl, k2InfoTbl);
1319    }
1320    else
1321    {
1322 #ifdef NR_TDD
1323
1324       /* Initialization the structure and storing the total slot values. */
1325       memset(k2InfoTbl, 0, sizeof(SchK2TimingInfoTbl));
1326       k2InfoTbl->tblSize = cell->numSlots;
1327       if(msg3K2InfoTbl)
1328          msg3K2InfoTbl->tblSize = cell->numSlots;
1329       totalCfgSlot = calculateSlotPatternLength(cell->cellCfg.ssbSchCfg.scsCommon, cell->cellCfg.tddCfg.tddPeriod);
1330
1331       /* Checking all possible indexes for K2. */
1332       for(slotIdx = 0; slotIdx < cell->numSlots; slotIdx++)
1333       {
1334          currentSlot = schGetSlotSymbFrmt(slotIdx % totalCfgSlot, cell->slotFrmtBitMap);
1335          
1336          /* If current slot is UL then skip because PDCCH is sent only in DL slots */
1337          if(currentSlot != UL_SLOT)
1338          {
1339             for(k2Index = 0; ((k2Index < puschSymTblSize) && (k2Index < MAX_NUM_K2_IDX)); k2Index++)
1340             {
1341                /* Storing k2, startSymbol, endSymbol information for further processing.
1342                 * If k2 is absent then fill the default values given in spec 38.331
1343                 * PUSCH-TimeDomainResourceAllocationList field descriptions */
1344                k2Val = timeDomRsrcAllocList[k2Index].k2;
1345                if(!k2Val)
1346                {
1347                   switch(cell->cellCfg.ssbSchCfg.scsCommon)
1348                   {
1349                      case SCS_15KHZ:
1350                         k2Val = DEFAULT_K2_VALUE_FOR_SCS15;
1351                         break;
1352                      case SCS_30KHZ:
1353                         k2Val = DEFAULT_K2_VALUE_FOR_SCS30;
1354                         break;
1355                      case SCS_60KHZ:
1356                         k2Val = DEFAULT_K2_VALUE_FOR_SCS60;
1357                         break;
1358                      case SCS_120KHZ:
1359                         k2Val = DEFAULT_K2_VALUE_FOR_SCS120;
1360                         break;
1361                   }
1362                }
1363                
1364                /* Current slot + k2 should be either UL or FLEXI slot.
1365                 * If slot is FLEXI then check all the symbols of that slot,
1366                 * it should not contain any DL or FLEXI slot */
1367                k2TmpVal = (slotIdx + k2Val) % totalCfgSlot;
1368                slotCfg = schGetSlotSymbFrmt(k2TmpVal, cell->slotFrmtBitMap);
1369                if(slotCfg != DL_SLOT)
1370                {
1371                   if(slotCfg == FLEXI_SLOT)
1372                   {
1373                      startSymbol =  timeDomRsrcAllocList[k2Index].startSymbol;
1374                      endSymbol   =  startSymbol+ timeDomRsrcAllocList[k2Index].symbolLength;
1375                      dlSymbolPresent = false;
1376                      for(checkSymbol= startSymbol; checkSymbol<endSymbol; checkSymbol++)
1377                      {
1378                         currentSymbol = cell->cellCfg.tddCfg.slotCfg[k2TmpVal][checkSymbol];
1379                         if(currentSymbol == DL_SLOT || currentSymbol == FLEXI_SLOT)
1380                         {
1381                            dlSymbolPresent = true;
1382                            break;
1383                         }
1384                      }
1385                   }
1386                   /* Store all the values if all condition satisfies. */
1387                   if(dlSymbolPresent != true || slotCfg == UL_SLOT)
1388                   {
1389                      numK2 = k2InfoTbl->k2TimingInfo[slotIdx].numK2;
1390                      k2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[numK2] = k2Index;
1391                      k2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1392                   }
1393                }
1394
1395                if(msg3K2InfoTbl)
1396                {
1397                    msg3Delta = puschDeltaTable[cell->cellCfg.numerology];
1398
1399                   /* Check for K2 for MSG3 */
1400                   /* Current slot + k2 should be either UL or FLEXI slot.
1401                    * If slot is FLEXI then check all the symbols of that slot,
1402                    * it should not contain any DL or FLEXI slot */
1403                   msg3K2TmpVal = (slotIdx + k2Val + msg3Delta) % totalCfgSlot;
1404                   slotCfg = schGetSlotSymbFrmt(msg3K2TmpVal, cell->slotFrmtBitMap);
1405                   if(slotCfg != DL_SLOT)
1406                   {
1407                      if(slotCfg == FLEXI_SLOT)
1408                      {
1409                         startSymbol =  timeDomRsrcAllocList[k2Index].startSymbol;
1410                         endSymbol   =  startSymbol+ timeDomRsrcAllocList[k2Index].symbolLength;
1411                         dlSymbolPresent = false;
1412                         for(checkSymbol= startSymbol; checkSymbol<endSymbol; checkSymbol++)
1413                         {
1414                            currentSymbol = cell->cellCfg.tddCfg.slotCfg[msg3K2TmpVal][checkSymbol];
1415                            if(currentSymbol == DL_SLOT || currentSymbol == FLEXI_SLOT)
1416                            {
1417                               dlSymbolPresent = true;
1418                               break;
1419                            }
1420                         }
1421                      }
1422                      /* Store all the values if all condition satisfies. */
1423                      if(dlSymbolPresent != true || slotCfg == UL_SLOT)
1424                      {
1425                         numK2 = msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2;
1426                         msg3K2InfoTbl->k2TimingInfo[slotIdx].k2Indexes[numK2] = k2Index;
1427                         msg3K2InfoTbl->k2TimingInfo[slotIdx].numK2++;
1428                      }
1429                   }
1430                }
1431             }
1432          }
1433       }
1434 #endif
1435    }
1436 }
1437
1438 /**********************************************************************
1439   End of file
1440  **********************************************************************/
1441