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