+/*******************************************************************
+ *
+ * @brief Processes BSR indiation from MAC
+ *
+ * @details
+ *
+ * Function : MacSchBsr
+ *
+ * Functionality:
+ * Processes DL BSR from MAC
+ *
+ * @params[in] Pst pst
+ * UlBufferStatusRptInd bsrInd
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacSchBsr(Pst *pst, UlBufferStatusRptInd *bsrInd)
+{
+ Inst schInst = pst->dstInst-SCH_INST_START;
+ SchCellCb *cellCb = NULLP;
+ SchUeCb *ueCb = NULLP;
+ uint8_t lcgIdx = 0;
+
+#ifdef CALL_FLOW_DEBUG_LOG
+ DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_SHORT_BSR\n");
+#endif
+
+ DU_LOG("\nDEBUG --> SCH : Received BSR");
+ if(bsrInd == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : BSR Ind is empty");
+ return RFAILED;
+ }
+ cellCb = schCb[schInst].cells[schInst];
+ if(cellCb == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : CellCb is empty");
+ return RFAILED;
+ }
+ ueCb = schGetUeCb(cellCb, bsrInd->crnti);
+
+ if(ueCb == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : UeCB is empty");
+ return RFAILED;
+ }
+
+ if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
+ {
+ DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
+ return ROK;
+ }
+
+ ueCb->bsrRcvd = true;
+ /* store dataVolume per lcg in uecb */
+ for(lcgIdx = 0; lcgIdx < bsrInd->numLcg; lcgIdx++)
+ {
+ ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].priority = 1; //TODO: determining LCG priority?
+ ueCb->bsrInfo[bsrInd->dataVolInfo[lcgIdx].lcgId].dataVol = bsrInd->dataVolInfo[lcgIdx].dataVol;
+ }
+
+ /* Adding UE Id to list of pending UEs to be scheduled */
+ addUeToBeScheduled(cellCb, ueCb->ueId);
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Processes SR UCI indication from MAC
+ *
+ * @details
+ *
+ * Function : MacSchSrUciInd
+ *
+ * Functionality:
+ * Processes SR UCI indication from MAC
+ *
+ * @params[in] Post structure
+ * UCI Indication
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacSchSrUciInd(Pst *pst, SrUciIndInfo *uciInd)
+{
+ Inst inst = pst->dstInst-SCH_INST_START;
+
+ SchUeCb *ueCb;
+ SchCellCb *cellCb = schCb[inst].cells[inst];
+
+#ifdef CALL_FLOW_DEBUG_LOG
+ DU_LOG("\nCall Flow: ENTMAC -> ENTSCH : EVENT_UCI_IND_TO_SCH\n");
+#endif
+
+ DU_LOG("\nDEBUG --> SCH : Received SR");
+
+ ueCb = schGetUeCb(cellCb, uciInd->crnti);
+
+ if(ueCb->state == SCH_UE_STATE_INACTIVE)
+ {
+ DU_LOG("\nERROR --> SCH : Crnti %d is inactive", uciInd->crnti);
+ return ROK;
+ }
+ if(ueCb->ueCfg.dataTransmissionAction == STOP_DATA_TRANSMISSION)
+ {
+ DU_LOG("\nINFO --> SCH: UL Data transmission not allowed for UE %d", ueCb->ueCfg.ueId);
+ return ROK;
+ }
+ if(uciInd->numSrBits)
+ {
+ ueCb->srRcvd = true;
+
+ /* Adding UE Id to list of pending UEs to be scheduled */
+ addUeToBeScheduled(cellCb, ueCb->ueId);
+ }
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocates requested PRBs for DL
+ *
+ * @details
+ *
+ * Function : allocatePrbDl
+ *
+ * Functionality:
+ * Allocates requested PRBs in DL
+ * Keeps track of allocated PRB (using bitmap) and remaining PRBs
+ *
+ * @params[in] prbAlloc table
+ * Start symbol
+ * Number of symbols
+ * Start PRB
+ * Number of PRBs
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \
+ uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
+{
+ uint8_t symbol = 0;
+ uint16_t broadcastPrbStart=0, broadcastPrbEnd=0;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+ PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
+ SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
+ SchPrbAlloc *prbAlloc = &schDlSlotInfo->prbAlloc;
+
+ /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
+ * Search for an appropriate location in PRB grid and allocate requested resources */
+ if(*startPrb == MAX_NUM_RB)
+ {
+ /* Check if SSB/SIB1 is also scheduled in this slot */
+ ssbOccasion = schCheckSsbOcc(cell, slotTime);
+ sib1Occasion = schCheckSib1Occ(cell, slotTime);
+
+ if(ssbOccasion && sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+ else if(ssbOccasion)
+ {
+ broadcastPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ broadcastPrbEnd = broadcastPrbStart + SCH_SSB_NUM_PRB -1;
+ }
+ else if(sib1Occasion)
+ {
+ broadcastPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
+ broadcastPrbEnd = broadcastPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+
+ /* Iterate through all free PRB blocks */
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /* If broadcast message is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
+ if((ssbOccasion || sib1Occasion) &&
+ ((broadcastPrbStart >= freePrbBlock->startPrb) && (broadcastPrbStart <= freePrbBlock->endPrb)) && \
+ ((broadcastPrbEnd >= freePrbBlock->startPrb) && (broadcastPrbEnd <= freePrbBlock->endPrb)))
+ {
+ /* Implmentation is done such that highest-numbered free-RB is allocated first */
+ if((freePrbBlock->endPrb > broadcastPrbEnd) && ((freePrbBlock->endPrb - broadcastPrbEnd) >= numPrb))
+ {
+ /* If sufficient free PRBs are available above bradcast message then,
+ * endPrb = freePrbBlock->endPrb
+ * startPrb = endPrb - numPrb +1;
+ */
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ else if((broadcastPrbStart > freePrbBlock->startPrb) && ((broadcastPrbStart - freePrbBlock->startPrb) >= numPrb))
+ {
+ /* If free PRBs are available below broadcast message then,
+ * endPrb = broadcastPrbStart - 1
+ * startPrb = endPrb - numPrb +1
+ */
+ *startPrb = broadcastPrbStart - numPrb;
+ break;
+ }
+ else
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ }
+ else
+ {
+ /* Check if requested number of blocks can be allocated from the current block */
+ if (freePrbBlock->numFreePrb < numPrb)
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ }
+
+ /* If no free block can be used to allocated request number of RBs */
+ if(*startPrb == MAX_NUM_RB)
+ return RFAILED;
+ }
+
+ /* If startPrb is known already, check if requested PRBs are available for allocation */
+ else
+ {
+ freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
+ if(!freePrbNode)
+ {
+ DU_LOG("\nERROR --> SCH: Requested DL PRB unavailable");
+ return RFAILED;
+ }
+ }
+
+ /* Update bitmap to allocate PRBs */
+ for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
+ {
+ if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in DL", symbol);
+ return RFAILED;
+ }
+ }
+
+ /* Update the remaining number for free PRBs */
+ removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
+
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Allocates requested PRBs for UL
+ *
+ * @details
+ *
+ * Function : allocatePrbUl
+ *
+ * Functionality:
+ * Allocates requested PRBs in UL
+ * Keeps track of allocated PRB (using bitmap) and remaining PRBs
+ *
+ * @params[in] prbAlloc table
+ * Start symbol
+ * Number of symbols
+ * Start PRB
+ * Number of PRBs
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \
+ uint8_t startSymbol, uint8_t symbolLength, uint16_t *startPrb, uint16_t numPrb)
+{
+ uint8_t symbol = 0;
+ uint16_t prachStartPrb, prachNumPrb, prachEndPrb;
+ bool isPrachOccasion;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+ SchPrbAlloc *prbAlloc = NULLP;
+
+ if(cell == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : allocatePrbUl(): Received cellCb is null");
+ return RFAILED;
+ }
+
+ prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
+ /* If startPrb is set to MAX_NUM_RB, it means startPrb is not known currently.
+ * Search for an appropriate location in PRB grid and allocate requested resources */
+ if(*startPrb == MAX_NUM_RB)
+ {
+ /* Check if PRACH is also scheduled in this slot */
+ isPrachOccasion = schCheckPrachOcc(cell, slotTime);
+ if(isPrachOccasion)
+ {
+ prachStartPrb = cell->cellCfg.schRachCfg.msg1FreqStart;
+ prachNumPrb = schCalcPrachNumRb(cell);
+ prachEndPrb = prachStartPrb + prachNumPrb -1;
+ }
+
+ /* Iterate through all free PRB blocks */
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /* If PRACH is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * PRBs required for PRACH cannot be allocated to any other message */
+ if((isPrachOccasion) &&
+ ((prachStartPrb >= freePrbBlock->startPrb) && (prachStartPrb <= freePrbBlock->endPrb)) &&
+ ((prachEndPrb >= freePrbBlock->startPrb) && (prachEndPrb <= freePrbBlock->endPrb)))
+ {
+ /* Implmentation is done such that highest-numbered free-RB is allocated first */
+ if((freePrbBlock->endPrb > prachEndPrb) && ((freePrbBlock->endPrb - prachEndPrb) >= numPrb))
+ {
+ /* If sufficient free PRBs are available above PRACH message then,
+ * endPrb = freePrbBlock->endPrb
+ * startPrb = endPrb - numPrb +1;
+ */
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ else if((prachStartPrb > freePrbBlock->startPrb) && ((prachStartPrb - freePrbBlock->startPrb) >= numPrb))
+ {
+ /* If free PRBs are available below PRACH message then,
+ * endPrb = prachStartPrb - 1
+ * startPrb = endPrb - numPrb +1
+ */
+ *startPrb = prachStartPrb - numPrb;
+ break;
+ }
+ else
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ }
+ else
+ {
+ /* Check if requested number of PRBs can be allocated from currect block */
+ if(freePrbBlock->numFreePrb < numPrb)
+ {
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+ *startPrb = freePrbBlock->endPrb - numPrb +1;
+ break;
+ }
+ }
+
+ /* If no free block can be used to allocated requested number of RBs */
+ if(*startPrb == MAX_NUM_RB)
+ return RFAILED;
+ }
+ else
+ {
+ /* If startPrb is known already, check if requested PRBs are available for allocation */
+ freePrbNode = isPrbAvailable(&prbAlloc->freePrbBlockList, *startPrb, numPrb);
+ if(!freePrbNode)
+ {
+ DU_LOG("\nERROR --> SCH: Requested UL PRB unavailable");
+ return RFAILED;
+ }
+ }
+
+ /* Update bitmap to allocate PRBs */
+ for(symbol=startSymbol; symbol < (startSymbol+symbolLength); symbol++)
+ {
+ if(fillPrbBitmap(prbAlloc->prbBitMap[symbol], *startPrb, numPrb) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH: fillPrbBitmap() failed for symbol [%d] in UL", symbol);
+ return RFAILED;
+ }
+ }
+
+ /* Update the remaining number for free PRBs */
+ removeAllocatedPrbFromFreePrbList(&prbAlloc->freePrbBlockList, freePrbNode, *startPrb, numPrb);
+
+ return ROK;
+}
+
+/*******************************************************************
+ *
+ * @brief Add UE to ueToBeScheduled List
+ *
+ * @details
+ *
+ * Function : addUeToBeScheduled
+ *
+ * Functionality:
+ * Search if UE entry present in the list
+ * If yes, return.
+ * If no, add UE to the list
+ *
+ * @params[in] Cell control block
+ * Ue Idx to be added
+ *
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t addUeToBeScheduled(SchCellCb *cell, uint8_t ueIdToAdd)
+{
+ uint8_t *ueId;
+ CmLList *node;
+
+ /* Search if UE entry is already present in ueToBeScheduled list.
+ * If yes, another entry for same UE not needed. Hence, return */
+ node = cell->ueToBeScheduled.first;
+ while(node)
+ {
+ ueId = (uint8_t *)node->node;
+ if(*ueId == ueIdToAdd)
+ return ROK;
+ node = node->next;
+ }
+
+ /* If UE entry not present already, add UE to the end of ueToBeScheduled list */
+ SCH_ALLOC(ueId, sizeof(uint8_t));
+ if(!ueId)
+ {
+ DU_LOG("\nERROR --> SCH : Memory allocation failure in addUeToBeScheduled");
+ return RFAILED;
+ }
+ *ueId = ueIdToAdd;
+ if(addNodeToLList(&cell->ueToBeScheduled, ueId, NULLP) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to add ueId [%d] to cell->ueToBeScheduled list", *ueId);
+ return RFAILED;
+ }
+ return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief Try to find Best Free Block with Max Num PRB
+ *
+ * @details
+ *
+ * Function : searchLargestFreeBlock
+ *
+ * Functionality:
+ * Finds the FreeBlock with MaxNum of FREE PRB considering SSB/SIB1 ocassions.
+ *
+ * @params[in] I/P > prbAlloc table (FreeBlock list)
+ * I/P > Slot timing Info
+ * O/P > Start PRB
+ * I/P > Direction (UL/DL)
+ *
+ *
+ * @return Max Number of Free PRB
+ * If 0, then no Suitable Free Block
+ *
+ * ********************************************************************************/
+
+uint16_t searchLargestFreeBlock(SchCellCb *cell, SlotTimingInfo slotTime,uint16_t *startPrb, Direction dir)
+{
+ uint16_t reservedPrbStart=0, reservedPrbEnd=0, maxFreePRB = 0;
+ FreePrbBlock *freePrbBlock = NULLP;
+ CmLList *freePrbNode = NULLP;
+ SchPrbAlloc *prbAlloc = NULLP;
+ bool checkOccasion = FALSE;
+
+ *startPrb = 0; /*Initialize the StartPRB to zero*/
+
+ /*Based on Direction, Reserved Messsages will differi.e.
+ * DL >> SSB and SIB1 ocassions wheres for UL, PRACH ocassions to be checked
+ * and reserved before allocation for dedicated DL/UL msg*/
+ if(dir == DIR_DL)
+ {
+ SchDlSlotInfo *schDlSlotInfo = cell->schDlSlotInfo[slotTime.slot];
+ PduTxOccsaion ssbOccasion=0, sib1Occasion=0;
+
+ prbAlloc = &schDlSlotInfo->prbAlloc;
+
+ ssbOccasion = schCheckSsbOcc(cell, slotTime);
+ sib1Occasion = schCheckSib1Occ(cell, slotTime);
+
+ checkOccasion = TRUE;
+ if(ssbOccasion && sib1Occasion)
+ {
+ reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB + \
+ cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+ else if(ssbOccasion)
+ {
+ reservedPrbStart = cell->cellCfg.ssbSchCfg.ssbOffsetPointA;
+ reservedPrbEnd = reservedPrbStart + SCH_SSB_NUM_PRB -1;
+ }
+ else if(sib1Occasion)
+ {
+ reservedPrbStart = cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.startPrb;
+ reservedPrbEnd = reservedPrbStart + cell->cellCfg.sib1SchCfg.sib1PdschCfg.pdschFreqAlloc.freqAlloc.numPrb -1;
+ }
+ else
+ {
+ checkOccasion = FALSE;
+ }
+ }
+ else if(dir == DIR_UL)
+ {
+ prbAlloc = &cell->schUlSlotInfo[slotTime.slot]->prbAlloc;
+
+ /* Check if PRACH is also scheduled in this slot */
+ checkOccasion = schCheckPrachOcc(cell, slotTime);
+ if(checkOccasion)
+ {
+ reservedPrbStart = cell->cellCfg.schRachCfg.msg1FreqStart;
+ reservedPrbEnd = reservedPrbStart + (schCalcPrachNumRb(cell)) -1;
+ }
+ }
+ else
+ {
+ DU_LOG("\nERROR --> SCH: Invalid Direction!");
+ return (maxFreePRB);
+ }
+
+ freePrbNode = prbAlloc->freePrbBlockList.first;
+ while(freePrbNode)
+ {
+ freePrbBlock = (FreePrbBlock *)freePrbNode->node;
+
+ /*For block with same numFreeBlocks, choose the one with HighestPRB range
+ *Since FreeBLockList are arranged in Descending order of PRB range thus Skipping this block*/
+ if(maxFreePRB >= freePrbBlock->numFreePrb)
+ {
+ //skip this block
+ freePrbNode = freePrbNode->next;
+ continue;
+ }
+
+ /* If Broadcast/Prach message is scheduled in this slot, then check if its PRBs belong to the current free block.
+ * Since SSB/SIB1 PRB location is fixed, these PRBs cannot be allocated to other message in same slot */
+ if(checkOccasion &&
+ ((reservedPrbStart >= freePrbBlock->startPrb) && (reservedPrbStart <= freePrbBlock->endPrb)) && \
+ ((reservedPrbEnd >= freePrbBlock->startPrb) && (reservedPrbEnd <= freePrbBlock->endPrb)))
+ {
+
+ /* Implmentation is done such that highest-numbered free-RB is Checked first
+ and freePRB in this block is greater than Max till now */
+ if((freePrbBlock->endPrb > reservedPrbEnd) && ((freePrbBlock->endPrb - reservedPrbEnd) > maxFreePRB))
+ {
+ /* If sufficient free PRBs are available above reserved message*/
+ *startPrb = reservedPrbEnd + 1;
+ maxFreePRB = (freePrbBlock->endPrb - reservedPrbEnd);
+ }
+ /*Also check the other freeBlock (i.e. Above the reserved message) for MAX FREE PRB*/
+ if((reservedPrbStart > freePrbBlock->startPrb) && ((reservedPrbStart - freePrbBlock->startPrb) > maxFreePRB))
+ {
+ /* If free PRBs are available below reserved message*/
+ *startPrb = freePrbBlock->startPrb;
+ maxFreePRB = (reservedPrbStart - freePrbBlock->startPrb);
+ }
+ }
+ else //Best Block
+ {
+ if(maxFreePRB < freePrbBlock->numFreePrb)
+ {
+ *startPrb = freePrbBlock->startPrb;
+ maxFreePRB = freePrbBlock->numFreePrb;
+ }
+
+ }
+ freePrbNode = freePrbNode->next;
+ }
+ return(maxFreePRB);
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to send Slice Cfg rsp to MAC
+ *
+ * @details
+ *
+ * Function : SchSendSliceCfgRspToMac
+ *
+ * Functionality:
+ * function is used to send Slice Cfg rsp to MAC
+ *
+ * @params[in] Pst *pst, SchSliceCfgRsp sliceCfgRsp
+ *
+ * @return- void
+ *
+ * ********************************************************************************/
+void SchSendSliceCfgRspToMac(Inst inst, SchSliceCfgRsp sliceCfgRsp)
+{
+ Pst rspPst;
+
+ memset(&rspPst, 0, sizeof(Pst));
+ FILL_PST_SCH_TO_MAC(rspPst, inst);
+ rspPst.event = EVENT_SLICE_CFG_RSP_TO_MAC;
+
+ SchSliceCfgRspOpts[rspPst.selector](&rspPst, &sliceCfgRsp);
+
+}
+/*******************************************************************************
+ *
+ * @brief fill slice configuration response
+ *
+ * @details
+ *
+ * Function : fillSliceCfgRsp
+ *
+ * Functionality:
+ * fill slice configuration response
+ *
+ * @params[in] SchCellCb, SchSliceCfgReq, SchSliceCfgRsp,uint8_t count
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t fillSliceCfgRsp(bool sliceReCfg, SchSliceCfg *storedSliceCfg, SchCellCb *cellCb, SchSliceCfgReq *schSliceCfgReq, SchSliceCfgRsp *schSliceCfgRsp, uint8_t *count)
+{
+ bool sliceFound = false;
+ uint8_t cfgIdx = 0, sliceIdx = 0;
+
+ schSliceCfgRsp->numSliceCfgRsp = schSliceCfgReq->numOfConfiguredSlice;
+ SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp, schSliceCfgRsp->numSliceCfgRsp * sizeof(SliceRsp*));
+ if(schSliceCfgRsp->listOfSliceCfgRsp == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Memory allocation failed at fillSliceCfgRsp");
+ return RFAILED;
+ }
+
+ for(cfgIdx = 0; cfgIdx<schSliceCfgRsp->numSliceCfgRsp ; cfgIdx++)
+ {
+ sliceFound = false;
+ /* Here comparing the slice cfg request with the slice stored in cellCfg */
+ if(sliceReCfg != true)
+ {
+ for(sliceIdx = 0; sliceIdx<cellCb->cellCfg.plmnInfoList.numSliceSupport; sliceIdx++)
+ {
+ if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, cellCb->cellCfg.plmnInfoList.snssai[sliceIdx], sizeof(Snssai)))
+ {
+ (*count)++;
+ sliceFound = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Here comparing the slice cfg request with the slice stored in SchDb */
+ if(storedSliceCfg->listOfConfirguration)
+ {
+ for(sliceIdx = 0; sliceIdx<storedSliceCfg->numOfSliceConfigured; sliceIdx++)
+ {
+ if(!memcmp(&schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai, &storedSliceCfg->listOfConfirguration[sliceIdx]->snssai,\
+ sizeof(Snssai)))
+ {
+ (*count)++;
+ sliceFound = true;
+ break;
+ }
+ }
+ }
+ }
+
+ SCH_ALLOC(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx], sizeof(SliceRsp));
+ if(schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx] == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to allocate memory in fillSliceCfgRsp");
+ return RFAILED;
+ }
+
+
+ schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->snssai = schSliceCfgReq->listOfConfirguration[cfgIdx]->snssai;
+ if(sliceFound == true)
+ schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp = RSP_OK;
+ else
+ {
+ schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->rsp = RSP_NOK;
+ schSliceCfgRsp->listOfSliceCfgRsp[cfgIdx]->cause = SLICE_NOT_FOUND;
+ }
+ }
+ return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice configuration Sch DB
+ *
+ * @details
+ *
+ * Function : addSliceCfgInSchDb
+ *
+ * Functionality:
+ * function is used to store the slice configuration Sch DB
+ *
+ * @params[in] SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq,
+ * SchSliceCfgRsp cfgRsp, uint8_t count
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t addSliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
+{
+ uint8_t cfgIdx = 0, sliceIdx = 0;
+
+ if(count)
+ {
+ storeSliceCfg->numOfSliceConfigured = count;
+ SCH_ALLOC(storeSliceCfg->listOfConfirguration, storeSliceCfg->numOfSliceConfigured * sizeof(SchRrmPolicyOfSlice*));
+ if(storeSliceCfg->listOfConfirguration == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
+ return RFAILED;
+ }
+
+ for(cfgIdx = 0; cfgIdx<storeSliceCfg->numOfSliceConfigured; cfgIdx++)
+ {
+ if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
+ {
+ SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx], sizeof(SchRrmPolicyOfSlice));
+ if(storeSliceCfg->listOfConfirguration[sliceIdx] == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
+ return RFAILED;
+ }
+
+ SCH_ALLOC(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+ if(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to allocate memory in addSliceCfgInSchDb");
+ return RFAILED;
+ }
+
+ memcpy(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[sliceIdx]->snssai, sizeof(Snssai));
+ memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo,
+ sizeof(SchRrmPolicyRatio));
+ sliceIdx++;
+ }
+ }
+ }
+ return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to free the slice cfg and re cfg request pointer
+ *
+ * @details
+ *
+ * Function : freeSchSliceCfgReq
+ *
+ * Functionality:
+ * function is used to free the slice cfg and re cfg request pointer
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ * ********************************************************************************/
+void freeSchSliceCfgReq(SchSliceCfgReq *cfgReq)
+{
+ uint8_t cfgIdx = 0;
+
+ if(cfgReq)
+ {
+ if(cfgReq->numOfConfiguredSlice)
+ {
+ for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
+ {
+ if(cfgReq->listOfConfirguration[cfgIdx])
+ {
+ SCH_FREE(cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo, sizeof(SchRrmPolicyRatio));
+ SCH_FREE(cfgReq->listOfConfirguration[cfgIdx], sizeof(SchRrmPolicyOfSlice));
+ }
+ }
+ SCH_FREE(cfgReq->listOfConfirguration, cfgReq->numOfConfiguredSlice * sizeof(SchRrmPolicyOfSlice*));
+ }
+ SCH_FREE(cfgReq, sizeof(SchSliceCfgReq));
+ }
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice configuration Sch DB
+ *
+ * @details
+ *
+ * Function : MacSchSliceCfgReq
+ *
+ * Functionality:
+ * function is used to store the slice configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t MacSchSliceCfgReq(Pst *pst, SchSliceCfgReq *schSliceCfgReq)
+{
+ uint8_t count = 0;
+ Inst inst = pst->dstInst - SCH_INST_START;
+ SchSliceCfgRsp sliceCfgRsp;
+
+ DU_LOG("\nINFO --> SCH : Received Slice Cfg request from MAC");
+ if(schSliceCfgReq)
+ {
+ if(schSliceCfgReq->listOfConfirguration)
+ {
+ /* filling the slice configuration response of each slice */
+ if(fillSliceCfgRsp(false, NULLP, schCb[inst].cells[0], schSliceCfgReq, &sliceCfgRsp, &count) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to fill the slice cfg rsp");
+ return RFAILED;
+ }
+
+ if(addSliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceCfgReq, sliceCfgRsp, count) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to add slice cfg in sch database");
+ return RFAILED;
+ }
+ freeSchSliceCfgReq(schSliceCfgReq);
+ SchSendSliceCfgRspToMac(inst, sliceCfgRsp);
+ }
+ }
+ else
+ {
+ DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
+ }
+ return ROK;
+}
+
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice reconfiguration Sch DB
+ *
+ * @details
+ *
+ * Function : modifySliceCfgInSchDb
+ *
+ * Functionality:
+ * function is used to store the slice re configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceCfgReq
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t modifySliceCfgInSchDb(SchSliceCfg *storeSliceCfg, SchSliceCfgReq *cfgReq, SchSliceCfgRsp cfgRsp, uint8_t count)
+{
+ uint8_t cfgIdx = 0, sliceIdx = 0;
+
+ if(count)
+ {
+ if(storeSliceCfg->listOfConfirguration == NULLP)
+ {
+ DU_LOG("\nINFO --> SCH : Memory allocation failed in modifySliceCfgInSchDb");
+ return RFAILED;
+ }
+
+ for(cfgIdx = 0; cfgIdx<cfgReq->numOfConfiguredSlice; cfgIdx++)
+ {
+ if(cfgRsp.listOfSliceCfgRsp[cfgIdx]->rsp == RSP_OK)
+ {
+ for(sliceIdx = 0; sliceIdx<storeSliceCfg->numOfSliceConfigured; sliceIdx++)
+ {
+ if(!memcmp(&storeSliceCfg->listOfConfirguration[sliceIdx]->snssai, &cfgReq->listOfConfirguration[cfgIdx]->snssai, sizeof(Snssai)))
+ {
+ memcpy(storeSliceCfg->listOfConfirguration[sliceIdx]->rrmPolicyRatioInfo, cfgReq->listOfConfirguration[cfgIdx]->rrmPolicyRatioInfo,
+ sizeof(SchRrmPolicyRatio));
+ break;
+ }
+ }
+ }
+ }
+ }
+ freeSchSliceCfgReq(cfgReq);
+ return ROK;
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to send Slice re Cfg rsp to MAC
+ *
+ * @details
+ *
+ * Function : SchSendSliceCfgRspToMac
+ *
+ * Functionality:
+ * function is used to send Slice re Cfg rsp to MAC
+ *
+ * @params[in] Pst *pst, SchSliceCfgRsp schSliceReCfgRsp
+ *
+ * @return- void
+ *
+ * ********************************************************************************/
+void SchSendSliceReCfgRspToMac(Inst inst, SchSliceCfgRsp schSliceReCfgRsp)
+{
+ Pst rspPst;
+
+ memset(&rspPst, 0, sizeof(Pst));
+ FILL_PST_SCH_TO_MAC(rspPst, inst);
+ rspPst.event = EVENT_SLICE_RECFG_RSP_TO_MAC;
+
+ SchSliceReCfgRspOpts[rspPst.selector](&rspPst, &schSliceReCfgRsp);
+}
+/*******************************************************************************
+ *
+ * @brief This function is used to store the slice reconfiguration Sch DB
+ *
+ * @details
+ *
+ * Function : MacSchSliceReCfgReq
+ *
+ * Functionality:
+ * function is used to store the slice re configuration Sch DB
+ *
+ * @params[in] Pst *pst, SchSliceCfgReq *schSliceReCfgReq
+ *
+ * @return
+ * ROK - Success
+ * RFAILED - Failure
+ *
+ * ********************************************************************************/
+uint8_t MacSchSliceReCfgReq(Pst *pst, SchSliceCfgReq *schSliceReCfgReq)
+{
+ uint8_t count = 0;
+ Inst inst = pst->dstInst - SCH_INST_START;
+ SchSliceCfgRsp schSliceReCfgRsp;
+
+ DU_LOG("\nINFO --> SCH : Received Slice ReCfg request from MAC");
+ if(schSliceReCfgReq)
+ {
+ if(schSliceReCfgReq->listOfConfirguration)
+ {
+ /* filling the slice configuration response of each slice */
+ if(fillSliceCfgRsp(true, &schCb[inst].sliceCfg, NULLP, schSliceReCfgReq, &schSliceReCfgRsp, &count) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to fill sch slice cfg response");
+ return RFAILED;
+ }
+
+ /* Modify the slice configuration stored in schCb */
+ if(modifySliceCfgInSchDb(&schCb[inst].sliceCfg, schSliceReCfgReq, schSliceReCfgRsp, count) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : Failed to modify slice cfg of SchDb");
+ return RFAILED;
+ }
+ SchSendSliceReCfgRspToMac(inst, schSliceReCfgRsp);
+ }
+ }
+ else
+ {
+ DU_LOG("\nERROR --> SCH : Received SchSliceCfgReq is NULL");
+ }
+ return ROK;
+}
+
+/****************************************************************************
+ *
+ * @brief Stores the Paging Configuration from DU APP in CellCb
+ *
+ * @details
+ *
+ * Function : schProcPagingParam
+ *
+ * Functionality:
+ * Process the Paging Configuration when FirstPDCCHMonitoring for
+ * Paging Ocassion is not present.
+ *
+ * As per 38.304 Sec 7.1,
+ * "When firstPDCCH-MonitoringOccasionOfPO is present, the
+ * starting PDCCH monitoring occasion number of (i_s + 1)th PO is the
+ * (i_s + 1)th value of the firstPDCCHMonitoringOccasionOfPO
+ * parameter; otherwise, it is equal to i_s * S."
+ * "S = number of actual transmitted SSBs determined according
+ * to ssb-PositionsInBurst in SIB1"
+ *
+ * @params[in] SchCellCb *cell
+ *
+ * @return void
+ *
+ *************************************************************************/
+void schProcPagingCfg(SchCellCb *cell)
+{
+ PageCfg *pageCfgRcvd = NULL;
+ uint8_t i_sIdx = 0;
+
+ pageCfgRcvd = &(cell->cellCfg.sib1SchCfg.pageCfg);
+
+ if(pageCfgRcvd->poPresent == TRUE)
+ {
+ /*Fetching first Pdcch Monitoring Occasion for SFN (i_s + 1)th*/
+ for(i_sIdx = 0; i_sIdx < pageCfgRcvd->numPO; i_sIdx++)
+ {
+ cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pageCfgRcvd->pagingOcc[i_sIdx] / MAX_SYMB_PER_SLOT ;
+ if ((pageCfgRcvd->pagingOcc[i_sIdx] % MAX_SYMB_PER_SLOT) != 0 )
+ {
+ cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot++;
+ }
+
+ cell->pageCb.pagMonOcc[i_sIdx].frameOffset = 0;
+
+ }
+ }
+ else
+ {
+ schCfgPdcchMonOccOfPO(cell);
+ }
+}
+
+/****************************************************************************
+ *
+ * @brief Calculate PO if not present in Configuration
+ *
+ * @details
+ *
+ * Function : schCfgPdcchMonOccOfPO
+ *
+ * Functionality: In this function, PO are calculated i_s * S because
+ * FirstPDCCHMonitoring_ForPO is not present.
+ *
+ * @params[in] SchCellCb *cellCb
+ *
+ * @return void
+ *
+ *************************************************************************/
+void schCfgPdcchMonOccOfPO(SchCellCb *cell)
+{
+ uint8_t cnt = 0, incr = 1, i_sIdx = 0, frameOffSet = 0;
+ uint8_t nsValue = cell->cellCfg.sib1SchCfg.pageCfg.numPO;
+ uint8_t totalNumSsb = cell->cellCfg.ssbSchCfg.totNumSsb;
+ SlotTimingInfo tmpTimingInfo, pdcchTime;
+
+ /*Starting with First Sfn and slot*/
+ tmpTimingInfo.sfn = 0;
+ tmpTimingInfo.slot = 0;
+
+ pdcchTime = tmpTimingInfo;
+
+ while(i_sIdx < nsValue)
+ {
+ /*Increment frame Offset if PO falls on next SFN*/
+ if(pdcchTime.sfn != tmpTimingInfo.sfn)
+ {
+ frameOffSet++;
+ }
+ pdcchTime = tmpTimingInfo;
+ schIncrSlot(&(tmpTimingInfo), incr, cell->numSlots);
+
+ if (i_sIdx == 0)
+ {
+ cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
+ cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
+ i_sIdx++;
+ }
+ else
+ {
+ cnt++;
+ if((cnt == totalNumSsb) && (i_sIdx < MAX_PO_PER_PF))
+ {
+ cell->pageCb.pagMonOcc[i_sIdx].pagingOccSlot = pdcchTime.slot;
+ cell->pageCb.pagMonOcc[i_sIdx].frameOffset = frameOffSet;
+ cnt = 0;
+ i_sIdx++;
+ }
+ }
+ }
+}
+
+/**********************************************************************
+ End of file
+ **********************************************************************/