#define MAX_ZERO_CORR_CFG_IDX 16 /* max zero correlation config index */
#define MAC_TQ_SIZE 10 /* Timing Queue Size */
#define MAX_NUM_TIMER 1 /* MAX number of MAC timers */
+#define MAX_PENDING_STATS_RSP 5 /* Maximum number of statistics request for which response is pending */
#define DEFAULT_CELLS 1
#define SI_RNTI 0xFFFF
#define LC_ID_SIZE 6
#define TIMING_ADVANCE_SIZE 12
#define T_CRNTI_SIZE 16
+
/* UL Grant is of size = 27 bits. Refer to Spec 38.213, Table 8.2-1 for
* contents of UL grant in RAR */
#define FREQ_HOP_FLAG_SIZE 1
SlotTimingInfo currTime;
};
+typedef struct macStatistics
+{
+ uint8_t numPendingStatsRsp;
+ MacStatsRsp pendingStatsRsp[MAX_PENDING_STATS_RSP];
+
+ /* This structure can be developed in future to add details of
+ * the statistics to be calculated at MAC */
+}MacStatistics;
+
typedef struct macCb
{
Inst macInst;
CmTqType tmrTq[MAC_TQ_SIZE]; /*!< Timer Task Queue */
CmTimer tmrBlk[MAX_NUM_TIMER]; /*!< Timer Block */
MacCellCb *macCell[MAX_NUM_CELL];
+ MacStatistics statistics;
}MacCb;
/* global variable */
* @return int
* -# ROK
**/
-uint8_t MacSendStatsRspToDuApp(MacRsp rsp, CauseOfResult cause)
+uint8_t MacSendStatsRspToDuApp(MacStatsRsp *statsRsp)
{
uint8_t ret = ROK;
Pst pst;
MacStatsRsp *macStatsRsp = NULLP;
+ DU_LOG("\nINFO --> MAC : MacSendStatsRspToDuApp: Sending Statistics Response to DU APP");
+
/* Workaround : To skip corrupted memory, allocating a pointer that will
* remain unused */
uint8_t *dummyPtr = NULLP;
}
else
{
- macStatsRsp->rsp = rsp;
- macStatsRsp->cause = cause;
+ memcpy(macStatsRsp, statsRsp, sizeof(MacStatsRsp));
+ memset(statsRsp, 0, sizeof(MacStatsRsp));
memset(&pst, 0, sizeof(Pst));
FILL_PST_MAC_TO_DUAPP(pst, EVENT_MAC_STATISTICS_RSP);
return ret;
}
+/*******************************************************************
+ *
+ * @brief Rejects all statistics group requested by DU APP
+ *
+ * @details
+ *
+ * Function : MacRejectAllStats
+ *
+ * Functionality: Add all statistics group received in statistics
+ * request from DU APP, to Reject-Stats-Group-List in statistics
+ * response to DU APP
+ *
+ * @params[in] Statistics request from DU APP
+ * Cause of rejection
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t MacRejectAllStats(MacStatsReq *macStatsReq, CauseOfResult cause)
+{
+ uint8_t grpIdx = 0;
+ MacStatsRsp macStatsRsp;
+
+ memset(&macStatsRsp, 0, sizeof(MacStatsRsp));
+
+ /* Copying all stats group from stats request to stats response */
+ macStatsRsp.subscriptionId = macStatsReq->subscriptionId;
+ for(grpIdx = 0; grpIdx < macStatsReq->numStatsGroup; grpIdx++)
+ {
+ macStatsRsp.statsGrpRejectedList[grpIdx].groupId = macStatsReq->statsGrpList[grpIdx].groupId;
+ macStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
+ }
+ macStatsRsp.numGrpRejected = macStatsReq->numStatsGroup;
+
+ return MacSendStatsRspToDuApp(&macStatsRsp);
+}
+
/**
* @brief Mac process the statistics Req received from DUAPP
*
*
* Function : MacProcStatsReq
*
- * This function process the statistics request from duapp
+ * This function process the statistics request from duapp:
+ * [Step 1] Basic validation. If fails, all stats group in stats request are
+ * rejected.
+ * [Step 2] If basic validations passed, traverse all stats group and
+ * validate each measurement types in each group.
+ * [Step 3] If any measurement type validation fails in a group, that group
+ * is not configured and it is added to stats-group-rejected-list in
+ * mac-stats-response message.
+ * [Step 4] Even if one group passes all validation, it is sent to SCH in
+ * statistics request. The mac-stats-response message is added to
+ * pending-response list. This will be sent to DU APP after stats response
+ * is received from SCH.
+ * [Step 5] If none of the groups passes all validation, mac-stats-response
+ * is sent to du app with all group as part of stats-group-rejected-list.
*
* @param[in] Pst *pst
* @param[in] StatsReq *statsReq
**/
uint8_t MacProcStatsReq(Pst *pst, MacStatsReq *macStatsReq)
{
- uint8_t macStatsIdx = 0, schStatsIdx = 0;
- uint8_t ret = RFAILED;
- bool measTypeInvalid = false;
- Pst schPst;
- SchStatsReq *schStatsReq = NULLP;
- CauseOfResult cause;
+ uint8_t macStatsGrpIdx = 0, macStatsIdx = 0, schStatsGrpIdx = 0, schStatsIdx = 0;
+ uint8_t ret = RFAILED;
+ bool measTypeInvalid = false;
+ Pst schPst;
+ MacStatsGrpInfo *macStatsGrp = NULLP;
+ SchStatsReq *schStatsReq = NULLP;
+ MacStatsRsp *macStatsRsp = NULLP;
- if(macStatsReq)
+ DU_LOG("\nINFO --> MAC : Received Statistics Request from DU_APP");
+
+ if(macStatsReq == NULLP)
{
- DU_LOG("\nINFO --> MAC : Received Statistics Request from DU_APP");
+ DU_LOG("\nERROR --> MAC : MacProcStatsReq(): Received Null pointer");
+ return RFAILED;
+ }
+
+ /* [Step 1] Basic validation. If fails, statistics response is sent to DU APP
+ * that rejectes all stats */
- MAC_ALLOC(schStatsReq, sizeof(SchStatsReq));
- if(schStatsReq == NULLP)
- {
- DU_LOG("\nERROR --> MAC : MacProcStatsReq: Failed to allocate memory");
- cause = RESOURCE_UNAVAILABLE;
- }
- else
- {
- schStatsReq->numStats = 0;
- for(macStatsIdx=0; macStatsIdx < macStatsReq->numStats; macStatsIdx++)
- {
- /* Checking each measurement type to send only SCH related
- * measurement config to SCH
- * This will be useful in future when some measurement type will
- * be configured for SCH and rest for only MAC */
- switch(macStatsReq->statsList[macStatsIdx].type)
- {
- case MAC_DL_TOTAL_PRB_USAGE:
- {
- schStatsReq->statsList[schStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;
- break;
- }
- case MAC_UL_TOTAL_PRB_USAGE:
- {
- schStatsReq->statsList[schStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;
- break;
- }
- default:
- {
- DU_LOG("\nERROR --> MAC : MacProcStatsReq: Invalid measurement type [%d]", \
- macStatsReq->statsList[macStatsIdx].type);
- measTypeInvalid = true;
- }
- }
+ /* If number of statistics request for which response is still pending
+ * towards DU APP has reached its maximum limit */
+ if(macCb.statistics.numPendingStatsRsp >= MAX_PENDING_STATS_RSP)
+ {
+ DU_LOG("\nERROR --> MAC : MacProcStatsReq: Maximum number of statistics response is pending. \
+ Cannot process new request.");
+ MacRejectAllStats(macStatsReq, RESOURCE_UNAVAILABLE);
+ MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsReq, sizeof(MacStatsReq));
+ return RFAILED;
+ }
- if(!measTypeInvalid)
- {
- schStatsReq->statsList[schStatsIdx].periodicity = macStatsReq->statsList[macStatsIdx].periodicity;
- schStatsIdx++;
- measTypeInvalid = false;
- }
- }
- schStatsReq->numStats = schStatsIdx;
+ /* If memory resources are unavailable */
+ MAC_ALLOC(schStatsReq, sizeof(SchStatsReq));
+ if(schStatsReq == NULLP)
+ {
+ DU_LOG("\nERROR --> MAC : MacProcStatsReq: Failed to allocate memory");
+ MacRejectAllStats(macStatsReq, RESOURCE_UNAVAILABLE);
+ MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsReq, sizeof(MacStatsReq));
+ return RFAILED;
+ }
+
+ /* Add stats response to pending response list */
+ macStatsRsp = &macCb.statistics.pendingStatsRsp[macCb.statistics.numPendingStatsRsp];
+ memset(macStatsRsp, 0, sizeof(MacStatsRsp));
+
+ /* [Step 2] Traverse all stats group and validate each measurement types in each group */
+ schStatsReq->subscriptionId = macStatsReq->subscriptionId;
+ schStatsReq->numStatsGroup = 0;
+ for(macStatsGrpIdx = 0; macStatsGrpIdx < macStatsReq->numStatsGroup; macStatsGrpIdx++)
+ {
+ measTypeInvalid = false;
+ schStatsIdx = 0;
+ macStatsGrp = &macStatsReq->statsGrpList[macStatsGrpIdx];
- /* If no measurement types are valid, it is failure scenario.
- * Even if one measurement type is valid, send to SCH */
- if(schStatsReq->numStats)
+ for(macStatsIdx=0; macStatsIdx < macStatsGrp->numStats; macStatsIdx++)
+ {
+ /* Validate each measurement type */
+ switch(macStatsGrp->statsList[macStatsIdx])
{
- FILL_PST_MAC_TO_SCH(schPst, EVENT_STATISTICS_REQ_TO_SCH);
- ret = SchMessageRouter(&schPst, (void *)schStatsReq);
+ case MAC_DL_TOTAL_PRB_USAGE:
+ {
+ schStatsReq->statsGrpList[schStatsGrpIdx].statsList[schStatsIdx] = SCH_DL_TOTAL_PRB_USAGE;
+ break;
+ }
+ case MAC_UL_TOTAL_PRB_USAGE:
+ {
+ schStatsReq->statsGrpList[schStatsGrpIdx].statsList[schStatsIdx] = SCH_UL_TOTAL_PRB_USAGE;
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> MAC : MacProcStatsReq: Invalid measurement type [%d]", \
+ macStatsGrp->statsList[macStatsIdx]);
+ measTypeInvalid = true;
+ }
}
- else
+
+ /* Even if one measurement type is invalid, this group is rejected */
+ if(measTypeInvalid)
{
- cause = PARAM_INVALID;
+ memset(&schStatsReq->statsGrpList[schStatsGrpIdx], 0, sizeof(SchStatsGrpInfo));
+ break;
}
+
+ schStatsIdx++;
+ }
+
+ /* If all measurement type is valid, add group info to send to SCH */
+ if(!measTypeInvalid)
+ {
+ schStatsReq->statsGrpList[schStatsGrpIdx].groupId = macStatsGrp->groupId;
+ schStatsReq->statsGrpList[schStatsGrpIdx].periodicity = macStatsGrp->periodicity;
+ schStatsReq->statsGrpList[schStatsGrpIdx].numStats = schStatsIdx;
+ schStatsGrpIdx++;
+ }
+ else
+ {
+ /* [Step 3] If any measurement type validation fails in a group, that group
+ * is not configured and it is added to stats-group-rejected-list in
+ * mac-stats-response message */
+ macStatsRsp->statsGrpRejectedList[macStatsRsp->numGrpRejected].groupId = macStatsGrp->groupId;
+ macStatsRsp->statsGrpRejectedList[macStatsRsp->numGrpRejected].cause = PARAM_INVALID;
+ macStatsRsp->numGrpRejected++;
}
- MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsReq, sizeof(MacStatsReq));
}
- else
+ schStatsReq->numStatsGroup = schStatsGrpIdx;
+
+ macStatsRsp->subscriptionId = macStatsReq->subscriptionId;
+
+ if(schStatsReq->numStatsGroup)
{
- DU_LOG("\nERROR --> MAC : MacProcStatsReq(): Received Null pointer");
- cause = PARAM_INVALID;
- }
+ /* [Step 4] Even if one group passes all validation, it is sent to SCH in
+ * statistics request. The mac-stats-response message is added to
+ * pending-response list. */
+ macCb.statistics.numPendingStatsRsp++;
- if(ret == RFAILED)
+ FILL_PST_MAC_TO_SCH(schPst, EVENT_STATISTICS_REQ_TO_SCH);
+ ret = SchMessageRouter(&schPst, (void *)schStatsReq);
+ }
+ else
{
- MacSendStatsRspToDuApp(MAC_DU_APP_RSP_NOK, cause);
+ /* [Step 5] If none of the groups passes all validation, mac-stats-response
+ * is sent to du app with all group as part of stats-group-rejected-list. */
+ DU_LOG("\nERROR --> MAC : MacProcStatsReq: All statistics group found invalid");
+ MAC_FREE(schStatsReq, sizeof(SchStatsReq));
+ ret = MacSendStatsRspToDuApp(macStatsRsp);
}
+
+ MAC_FREE_SHRABL_BUF(pst->region, pst->pool, macStatsReq, sizeof(MacStatsReq));
return ret;
}
**/
uint8_t MacProcSchStatsRsp(Pst *pst, SchStatsRsp *schStatsRsp)
{
+ uint8_t idx = 0, accptdIdx = 0, rjctdIdx = 0;
uint8_t ret = RFAILED;
+ MacStatsRsp *macStatsRsp = NULLP;
if(schStatsRsp)
{
- if(schStatsRsp->rsp == RSP_OK)
- ret = MacSendStatsRspToDuApp(MAC_DU_APP_RSP_OK, schStatsRsp->cause);
- else
- ret = MacSendStatsRspToDuApp(MAC_DU_APP_RSP_NOK, schStatsRsp->cause);
+ /* Fetch pointer to statistics response from pending list saved at MAC
+ * during processing statistics request from DU APP */
+ for(idx = 0; idx < macCb.statistics.numPendingStatsRsp; idx++)
+ {
+ if(macCb.statistics.pendingStatsRsp[idx].subscriptionId == schStatsRsp->subscriptionId)
+ {
+ macStatsRsp = &macCb.statistics.pendingStatsRsp[idx];
+ break;
+ }
+ }
- MAC_FREE(schStatsRsp, sizeof(SchStatsRsp));
+ if(macStatsRsp == NULLP)
+ {
+ MAC_FREE(schStatsRsp, sizeof(SchStatsRsp));
+ return RFAILED;
+ }
+
+ /* Copy Stats-group-accpeted list received from SCH */
+ for(accptdIdx = 0; accptdIdx<schStatsRsp->numGrpAccepted && macStatsRsp->numGrpAccepted<MAX_NUM_STATS_GRP; accptdIdx++)
+ {
+ macStatsRsp->statsGrpAcceptedList[macStatsRsp->numGrpAccepted++] = schStatsRsp->statsGrpAcceptedList[accptdIdx];
+ }
+
+ /* List together all stats group rejected by MAC and by SCH */
+ for(rjctdIdx = 0; rjctdIdx < schStatsRsp->numGrpRejected && macStatsRsp->numGrpRejected<MAX_NUM_STATS_GRP; rjctdIdx++)
+ {
+ macStatsRsp->statsGrpRejectedList[macStatsRsp->numGrpRejected].groupId = \
+ schStatsRsp->statsGrpRejectedList[rjctdIdx].groupId;
+ macStatsRsp->statsGrpRejectedList[macStatsRsp->numGrpRejected].cause = \
+ schStatsRsp->statsGrpRejectedList[rjctdIdx].cause;
+ macStatsRsp->numGrpRejected++;
+ }
+
+ /* Send statistics response to DU APP */
+ ret = MacSendStatsRspToDuApp(macStatsRsp);
}
+ MAC_FREE(schStatsRsp, sizeof(SchStatsRsp));
return ret;
}
**/
uint8_t MacProcSchStatsInd(Pst *pst, SchStatsInd *schStatsInd)
{
+ uint8_t statsIdx = 0;
Pst indPst;
MacStatsInd *macStatsInd;
return RFAILED;
}
- switch(schStatsInd->type)
+ macStatsInd->subscriptionId = schStatsInd->subscriptionId;
+ macStatsInd->groupId = schStatsInd->groupId;
+
+ for(statsIdx = 0; statsIdx < schStatsInd->numStats; statsIdx++)
{
- case SCH_DL_TOTAL_PRB_USAGE:
- {
- macStatsInd->type = MAC_DL_TOTAL_PRB_USAGE;
- break;
- }
- case SCH_UL_TOTAL_PRB_USAGE:
- {
- macStatsInd->type = MAC_UL_TOTAL_PRB_USAGE;
- break;
- }
- default:
- {
- DU_LOG("\nERROR --> MAC : MacProcSchStatsInd: Invalid measurement type [%d]", schStatsInd->type);
- MAC_FREE_SHRABL_BUF(MAC_MEM_REGION, MAC_POOL, macStatsInd, sizeof(MacStatsInd));
- return RFAILED;
- }
+ switch(schStatsInd->measuredStatsList[statsIdx].type)
+ {
+ case SCH_DL_TOTAL_PRB_USAGE:
+ {
+ macStatsInd->measuredStatsList[statsIdx].type = MAC_DL_TOTAL_PRB_USAGE;
+ break;
+ }
+ case SCH_UL_TOTAL_PRB_USAGE:
+ {
+ macStatsInd->measuredStatsList[statsIdx].type = MAC_UL_TOTAL_PRB_USAGE;
+ break;
+ }
+ default:
+ {
+ DU_LOG("\nERROR --> MAC : MacProcSchStatsInd: Invalid measurement type [%d]", \
+ schStatsInd->measuredStatsList[statsIdx].type);
+ MAC_FREE_SHRABL_BUF(MAC_MEM_REGION, MAC_POOL, macStatsInd, sizeof(MacStatsInd));
+ return RFAILED;
+ }
+ }
+ macStatsInd->measuredStatsList[statsIdx].value = schStatsInd->measuredStatsList[statsIdx].value;
}
- macStatsInd->value = schStatsInd->value;
+ macStatsInd->numStats = schStatsInd->numStats;
memset(&indPst, 0, sizeof(Pst));
FILL_PST_MAC_TO_DUAPP(indPst, EVENT_MAC_STATISTICS_IND);
return (LCM_REASON_MEM_NOAVAIL);
}
+ /* Initialize statistics related configurations */
+ memset(&schCb[inst].statistics, 0, sizeof(SchStatistics));
+ cmLListInit(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList);
+ cmLListInit(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList);
+
/* Set Config done in TskInit */
schCb[inst].schInit.cfgDone = TRUE;
DU_LOG("\nINFO --> SCH : Scheduler gen config done");
}
/* Update statistics of PRB usage if stats calculation is enabled */
- if(schCb[cell->instIdx].statistics.dlTotalPrbUsage)
+ if(schCb[cell->instIdx].statistics.activeKpiList.dlTotPrbUseList.count)
prbAlloc->numPrbAlloc += numPrb;
/* Update the remaining number for free PRBs */
}
/* Update statistics of PRB usage if stats calculation is enabled */
- if(schCb[cell->instIdx].statistics.ulTotalPrbUsage)
+ if(schCb[cell->instIdx].statistics.activeKpiList.ulTotPrbUseList.count)
prbAlloc->numPrbAlloc += numPrb;
/* Update the remaining number for free PRBs */
* RFAILED - failure
*
* ****************************************************************/
-uint8_t SchSendStatsRspToMac(Inst inst, SchMacRsp result, CauseOfResult cause)
+uint8_t SchSendStatsRspToMac(SchStatsRsp *statsRsp)
{
Pst rspPst;
uint8_t ret = ROK;
- SchStatsRsp *statsRsp;
+ SchStatsRsp *schStatsRsp;
DU_LOG("\nINFO --> SCH : Filling statistics response");
- SCH_ALLOC(statsRsp, sizeof(SchStatsRsp));
- if(statsRsp == NULLP)
+ SCH_ALLOC(schStatsRsp, sizeof(SchStatsRsp));
+ if(schStatsRsp == NULLP)
{
DU_LOG("\nERROR --> SCH : Failed to allocate memory in SchSendStatsRspToMac()");
return RFAILED;
}
+
+ memcpy(schStatsRsp, statsRsp, sizeof(SchStatsRsp));
memset(statsRsp, 0, sizeof(SchStatsRsp));
- statsRsp->rsp = result;
- statsRsp->cause = cause;
/* Filling response post */
memset(&rspPst, 0, sizeof(Pst));
FILL_PST_SCH_TO_MAC(rspPst, inst);
rspPst.event = EVENT_STATISTICS_RSP_TO_MAC;
- ret = MacMessageRouter(&rspPst, (void *)statsRsp);
+ ret = MacMessageRouter(&rspPst, (void *)schStatsRsp);
if(ret == RFAILED)
{
DU_LOG("\nERROR --> SCH : SchSendStatsRspToMac(): Failed to send Statistics Response");
/*******************************************************************
*
- * @brief Processes Statistics Request from MAC
+ * @brief Rejects all statistics group requested by MAC
*
* @details
*
- * Function : SchProcStatsReq
+ * Function : SchRejectAllStats
*
- * Functionality:
- * Processes Statistics Request from MAC
+ * Functionality: Add all statistics group received in statistics
+ * request from MAC, to Reject-Stats-Group-List in statistics
+ * response to MAC
*
- * @params[in]
+ * @params[in] Statistics request from MAC
+ * Cause of rejection
* @return ROK - success
* RFAILED - failure
*
* ****************************************************************/
-uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
+uint8_t SchRejectAllStats(SchStatsReq *schStatsReq, CauseOfResult cause)
{
- uint8_t idx;
- Inst inst = pst->dstInst - SCH_INST_START;
- SchMacRsp rsp = RSP_OK;
- CauseOfResult cause = SUCCESSFUL;
- bool isDlTotlPrbUseCfgd = false, isUlTotlPrbUseCfgd = false;
+ uint8_t grpIdx = 0;
+ SchStatsRsp schStatsRsp;
- DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC");
+ memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
- for(idx=0; idx < statsReq->numStats; idx++)
+ /* Copying all stats group from stats request to stats response */
+ schStatsRsp.subscriptionId = schStatsReq->subscriptionId;
+ for(grpIdx = 0; grpIdx < schStatsReq->numStatsGroup; grpIdx++)
{
- switch(statsReq->statsList[idx].type)
- {
- case SCH_DL_TOTAL_PRB_USAGE:
- {
- /* Check if duplicate configuration */
- if(schCb[inst].statistics.dlTotalPrbUsage)
- {
- DU_LOG("\nERROR --> SCH : SCH_DL_TOTAL_PRB_USAGE stats already configured");
- rsp = RSP_NOK;
- cause = DUPLICATE_ENTRY;
- }
-
- /* Allocate memory */
- SCH_ALLOC(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
- if(!schCb[inst].statistics.dlTotalPrbUsage)
- {
- DU_LOG("\nERROR --> SCH : Memory allocation failed for dlTotalPrbUsage in \
- SchProcStatsReq()");
- rsp = RSP_NOK;
- cause = RESOURCE_UNAVAILABLE;
- break;
- }
-
- /* Initialize */
- memset(schCb[inst].statistics.dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
-
- /* Configure */
- schCb[inst].statistics.dlTotalPrbUsage->schInst = inst;
- schCb[inst].statistics.dlTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
- cmInitTimers(&(schCb[inst].statistics.dlTotalPrbUsage->periodTimer), 1);
+ schStatsRsp.statsGrpRejectedList[grpIdx].groupId = schStatsReq->statsGrpList[grpIdx].groupId;
+ schStatsRsp.statsGrpRejectedList[grpIdx].cause = cause;
+ }
+ schStatsRsp.numGrpRejected = schStatsReq->numStatsGroup;
- /* Start timer */
- schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), \
- EVENT_DL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.dlTotalPrbUsage->periodicity);
+ return SchSendStatsRspToMac(&schStatsRsp);
+}
- isDlTotlPrbUseCfgd = true;
- break;
- }
+/*******************************************************************
+ *
+ * @brief Add active KPI pointers to KPI-Active-List
+ *
+ * @details
+ *
+ * Function : schAddToKpiActiveList
+ *
+ * Functionality: For each active statistics group for which timer
+ * is running, add its KPI pointer to KPI-Active-List.
+ * Use case :
+ * When it is needed to update a KPI parameters, we need not
+ * traverse all statistics group and all KPIs within a group
+ * to get the specific KPI pointer to be updated.
+ * Instead, we can traverse through KPI-Active-List and update
+ * all entries in this list.
+ *
+ * @params[in] Statistics request from MAC
+ * Cause of rejection
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t schAddToKpiActiveList(Inst inst, SchStatsGrp *grpInfo)
+{
+ CmLList *node = NULLP;
- case SCH_UL_TOTAL_PRB_USAGE:
- {
- /* Check if duplicate configuration */
- if(schCb[inst].statistics.ulTotalPrbUsage)
- {
- DU_LOG("\nERROR --> SCH : SCH_UL_TOTAL_PRB_USAGE stats already configured");
- rsp = RSP_NOK;
- cause = DUPLICATE_ENTRY;
- }
+ /* If DL Total PRB Usage configured for this stats group, add to list */
+ if(grpInfo->kpiStats.dlTotalPrbUsage)
+ {
+ SCH_ALLOC(node, sizeof(CmLList));
+ if(node)
+ {
+ node->node = (PTR)grpInfo->kpiStats.dlTotalPrbUsage;
+ cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.dlTotPrbUseList, node);
+ }
+ }
- /* Allocate memory */
- SCH_ALLOC(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
- if(!schCb[inst].statistics.ulTotalPrbUsage)
- {
- DU_LOG("\nERROR --> SCH : Memory allocation failed for ulTotalPrbUsage in \
- SchProcStatsReq()");
- rsp = RSP_NOK;
- cause = RESOURCE_UNAVAILABLE;
- break;
- }
+ /* If UL Total PRB Usage configured for this stats group, add to list */
+ node = NULLP;
+ if(grpInfo->kpiStats.ulTotalPrbUsage)
+ {
+ SCH_ALLOC(node, sizeof(CmLList));
+ if(node)
+ {
+ node->node = (PTR)grpInfo->kpiStats.ulTotalPrbUsage;
+ cmLListAdd2Tail(&schCb[inst].statistics.activeKpiList.ulTotPrbUseList, node);
+ }
+ }
- /* Initialize */
- memset(schCb[inst].statistics.ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+ return ROK;
+}
- /* Configure */
- schCb[inst].statistics.ulTotalPrbUsage->schInst = inst;
- schCb[inst].statistics.ulTotalPrbUsage->periodicity = statsReq->statsList[idx].periodicity;
- cmInitTimers(&(schCb[inst].statistics.ulTotalPrbUsage->periodTimer), 1);
+/*******************************************************************
+ *
+ * @brief Processes Statistics Request from MAC
+ *
+ * @details
+ *
+ * Function : SchProcStatsReq
+ *
+ * Functionality:
+ *
+ * This function process the statistics request from MAC:
+ * [Step 1] Basic validation. If fails, all stats group in stats request are
+ * rejected.
+ * [Step 2] If basic validations passed, traverse all stats group and
+ * validate each measurement types in each group.
+ * [Step 3] If any measurement type validation fails in a group, that group
+ * is not configured and it is added to stats-group-rejected-list in
+ * sch-stats-response message.
+ * [Step 4] If a group passes all validation, it is added to SCH database.
+ * A timer is started for this group. And the group is added to
+ * stats-group-accepted-list in sch-stats-response message.
+ * [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+ * and stats-group-accepted-list.
+ *
+ * @params[in] Post structure
+ * Statistics Request from MAC
+ * @return ROK - success
+ * RFAILED - failure
+ *
+ * ****************************************************************/
+uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq)
+{
+ uint8_t grpIdx = 0, reqGrpIdx = 0, reqMeasIdx = 0;
+ Inst inst = pst->dstInst - SCH_INST_START;
+ bool measTypeInvalid;
+ CauseOfResult cause;
+ SchStatsInfo *statsInfo = NULLP;
+ SchStatsGrpInfo *grpInfo = NULLP;
+ SchStatsGrp *grpInfoDb = NULLP;
+ SchStatsRsp schStatsRsp;
- /* Start timer */
- schStartTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), \
- EVENT_UL_TOTAL_PRB_USAGE_TMR, schCb[inst].statistics.ulTotalPrbUsage->periodicity);
+ DU_LOG("\nINFO --> SCH : Received Statistics Request from MAC");
- isUlTotlPrbUseCfgd = true;
- break;
- }
- default:
- {
- DU_LOG("\nERROR --> SCH : Invalid statistics type [%d]", statsReq->statsList[idx].type);
- rsp = RSP_NOK;
- cause = PARAM_INVALID;
- }
- } /* End of switch */
+ if(statsReq == NULLP)
+ {
+ DU_LOG("\nERROR --> SCH : SchProcStatsReq(): Received Null pointer");
+ return RFAILED;
+ }
- if(rsp == RSP_NOK)
- {
- /* If failed to configure any KPI, then clear configuration of other
- * KPIs that were configured successfully as part of this statsReq */
- if(isDlTotlPrbUseCfgd)
- {
- if((schChkTmr((PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR)) == FALSE)
- {
- schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR);
- }
- SCH_FREE(schCb[inst].statistics.dlTotalPrbUsage, sizeof(TotalPrbUsage));
- }
+ /* [Step 1] Basic validation. If fails, all stats group in stats request are rejected */
+
+ /* If maximum number of statistics already configured */
+ if(schCb[inst].statistics.numOfStatsCfgd >= MAX_NUM_STATS_CFG)
+ {
+ DU_LOG("\nERROR --> SCH : SchProcStatsReq: Maximum number of statistics configured. \
+ Cannot process new request.");
+ SchRejectAllStats(statsReq, RESOURCE_UNAVAILABLE);
+ SCH_FREE(statsReq, sizeof(SchStatsReq));
+ return RFAILED;
+ }
- if(isUlTotlPrbUseCfgd)
- {
- if((schChkTmr((PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR)) == FALSE)
- {
- schStopTmr(&schCb[inst], (PTR)(schCb[inst].statistics.ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR);
- }
- SCH_FREE(schCb[inst].statistics.ulTotalPrbUsage, sizeof(TotalPrbUsage));
- }
- break;
- }
- } /* End of FOR */
+ memset(&schStatsRsp, 0, sizeof(SchStatsRsp));
+
+ /* [Step 2] Traverse all stats group and validate each measurement types in each group */
+ statsInfo = &schCb[inst].statistics.statsInfoList[schCb[inst].statistics.numOfStatsCfgd];
+ statsInfo->numStatsGroup = 0;
+ for(reqGrpIdx=0; reqGrpIdx<statsReq->numStatsGroup && grpIdx<MAX_NUM_STATS; reqGrpIdx++)
+ {
+ measTypeInvalid = false;
+ grpInfo = &statsReq->statsGrpList[reqGrpIdx];
+ grpInfoDb = &statsInfo->statsGrpList[grpIdx];
+ for(reqMeasIdx = 0; reqMeasIdx < grpInfo->numStats; reqMeasIdx++)
+ {
+ switch(grpInfo->statsList[reqMeasIdx])
+ {
+ case SCH_DL_TOTAL_PRB_USAGE:
+ {
+ /* Allocate memory */
+ SCH_ALLOC(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+ if(!grpInfoDb->kpiStats.dlTotalPrbUsage)
+ {
+ DU_LOG("\nERROR --> SCH : Memory allocation failed for dlTotalPrbUsage in \
+ SchProcStatsReq()");
+ measTypeInvalid = true;
+ cause = RESOURCE_UNAVAILABLE;
+ }
+ break;
+ }
+
+ case SCH_UL_TOTAL_PRB_USAGE:
+ {
+ /* Allocate memory */
+ SCH_ALLOC(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+ if(!grpInfoDb->kpiStats.ulTotalPrbUsage)
+ {
+ DU_LOG("\nERROR --> SCH : Memory allocation failed for dlTotalPrbUsage in \
+ SchProcStatsReq()");
+ measTypeInvalid = true;
+ cause = RESOURCE_UNAVAILABLE;
+ }
+ break;
+ }
+
+ default:
+ {
+ DU_LOG("\nERROR --> SCH : SchProcStatsReq: Invalid measurement type [%d]", \
+ grpInfo->statsList[reqMeasIdx]);
+ measTypeInvalid = true;
+ cause = PARAM_INVALID;
+ break;
+ }
+ }
+
+ /* [Step 3 a] If any measurement type validation fails in a group, that group
+ * is not configured */
+ if(measTypeInvalid)
+ {
+ SCH_FREE(grpInfoDb->kpiStats.dlTotalPrbUsage, sizeof(TotalPrbUsage));
+ SCH_FREE(grpInfoDb->kpiStats.ulTotalPrbUsage, sizeof(TotalPrbUsage));
+ memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+ break;
+ }
+ }
+
+ /* [Step 4] If a group passes all validation, it is added to SCH database.
+ * A timer is started for this group. And the group is added to
+ * stats-group-accepted-list in sch-stats-response message. */
+ if(!measTypeInvalid)
+ {
+ /* Add this group's configured KPIs to list of Active KPIs */
+ if(schAddToKpiActiveList(inst, grpInfoDb) == ROK)
+ {
+ grpInfoDb->schInst = inst;
+ grpInfoDb->subscriptionId = statsReq->subscriptionId;
+ grpInfoDb->groupId = grpInfo->groupId;
+ grpInfoDb->periodicity = grpInfo->periodicity;
+
+
+ /* Start timer */
+ cmInitTimers(&(grpInfoDb->periodTimer), 1);
+ schStartTmr(&schCb[inst], (PTR)(grpInfoDb), EVENT_STATISTICS_TMR, grpInfoDb->periodicity);
+
+ schStatsRsp.statsGrpAcceptedList[schStatsRsp.numGrpAccepted] = grpInfo->groupId;
+ schStatsRsp.numGrpAccepted++;
+ grpIdx++;
+ }
+ else
+ {
+ memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+ }
+ }
+ else
+ {
+ /* [Step 3 b] The rejected group is added to stats-group-rejected-list in
+ * sch-stats-response message */
+ memset(grpInfoDb, 0, sizeof(SchStatsGrp));
+ schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].groupId = grpInfo->groupId;
+ schStatsRsp.statsGrpRejectedList[schStatsRsp.numGrpRejected].cause = cause;
+ schStatsRsp.numGrpRejected++;
+ }
+ }
+ statsInfo->numStatsGroup = grpIdx;
+ if(statsInfo->numStatsGroup)
+ {
+ schCb[inst].statistics.numOfStatsCfgd++;
+ }
+ else
+ {
+ memset(statsInfo, 0, sizeof(SchStatsInfo));
+ }
+ schStatsRsp.subscriptionId = statsReq->subscriptionId;
SCH_FREE(statsReq, sizeof(SchStatsReq));
- SchSendStatsRspToMac(inst, rsp, cause);
+ /* [Step 5] sch-stats-response is sent to du app with stats-group-rejected-list
+ * and stats-group-accepted-list. */
+ SchSendStatsRspToMac(&schStatsRsp);
return ROK;
} /* End of SchProcStatsReq */
* RFAILED - failure
*
* ****************************************************************/
-uint8_t SchSendStatsIndToMac(Inst inst, SchMeasurementType measType, double value)
+uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd)
{
Pst pst;
uint8_t ret = ROK;
- SchStatsInd statsInd;
#ifdef DEBUG_PRINT
DU_LOG("\nDEBUG --> SCH : Filling statistics indication");
#endif
- memset(&statsInd, 0, sizeof(SchStatsInd));
- statsInd.type = measType;
- statsInd.value = value;
-
/* Filling post structure */
memset(&pst, 0, sizeof(Pst));
FILL_PST_SCH_TO_MAC(pst, inst);
pst.event = EVENT_STATISTICS_IND_TO_MAC;
- ret = MacMessageRouter(&pst, (void *)&statsInd);
+ ret = MacMessageRouter(&pst, (void *)statsInd);
if(ret == RFAILED)
{
DU_LOG("\nERROR --> SCH : SchSendStatsIndToMac(): Failed to send Statistics Indication");
return ret;
}
+/**
+ * @brief Handler to process Timer expiry of DL Total PRB Usage calculation
+ *
+ * @param[in] cb Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt Timer event to be started
+ *
+ * @return Bool indicating whether the timer is running or not
+ * -# ROK
+ * -# RFAILED
+*/
+double calcDlTotalPrbUsage(TotalPrbUsage *dlTotalPrbUsage)
+{
+ double percentageOfTotalPrbUsed = 0;
+
+ if(dlTotalPrbUsage->totalPrbAvailForTx)
+ percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
+
+ memset(dlTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+
+ return percentageOfTotalPrbUsed;
+}
+
+/**
+ * @brief Handler to check if the timer is running
+ *
+ * @param[in] cb Control block depending on the type of the timer event.
+ * @param[in] tmrEvnt Timer event to be started
+ *
+ * @return Bool indicating whether the timer is running or not
+ * -# ROK
+ * -# RFAILED
+*/
+uint8_t calcUlTotalPrbUsage(TotalPrbUsage *ulTotalPrbUsage)
+{
+ double percentageOfTotalPrbUsed = 0;
+
+ if(ulTotalPrbUsage->totalPrbAvailForTx)
+ percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
+
+ memset(ulTotalPrbUsage, 0, sizeof(TotalPrbUsage));
+
+ return percentageOfTotalPrbUsed;
+}
+
+/**
+ * @brief Calculates statistics in a group and sends
+ * statistics indication for this group
+ *
+ * @param[in] Statistics group info
+ *
+ * @return
+ * -# ROK
+ * -# RFAILED
+*/
+uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo)
+{
+ uint8_t measStatsIdx = 0;
+ SchStatsInd statsInd;
+
+ memset(&statsInd, 0, sizeof(SchStatsInd));
+ statsInd.subscriptionId = grpInfo->subscriptionId;
+ statsInd.groupId = grpInfo->groupId;
+
+ if(grpInfo->kpiStats.dlTotalPrbUsage)
+ {
+ statsInd.measuredStatsList[measStatsIdx].type = SCH_DL_TOTAL_PRB_USAGE;
+ statsInd.measuredStatsList[measStatsIdx].value = calcDlTotalPrbUsage(grpInfo->kpiStats.dlTotalPrbUsage);
+ measStatsIdx++;
+ }
+
+ if(grpInfo->kpiStats.ulTotalPrbUsage)
+ {
+ statsInd.measuredStatsList[measStatsIdx].type = SCH_UL_TOTAL_PRB_USAGE;
+ statsInd.measuredStatsList[measStatsIdx].value = calcUlTotalPrbUsage(grpInfo->kpiStats.ulTotalPrbUsage);
+ measStatsIdx++;
+ }
+
+ statsInd.numStats = measStatsIdx;
+
+ return SchSendStatsIndToMac(grpInfo->schInst, &statsInd);
+}
/**********************************************************************
End of file
typedef struct dlTotalPrbUsage
{
- Inst schInst;
uint16_t numPrbUsedForTx;
uint16_t totalPrbAvailForTx;
- uint16_t periodicity;
- CmTimer periodTimer;
}TotalPrbUsage;
-typedef struct schStatistics
+typedef struct
{
TotalPrbUsage *dlTotalPrbUsage;
TotalPrbUsage *ulTotalPrbUsage;
+}SchKpiSupported;
+
+typedef struct
+{
+ CmLListCp dlTotPrbUseList;
+ CmLListCp ulTotPrbUseList;
+}SchKpiActive;
+
+typedef struct schStatsGrp
+{
+ Inst schInst;
+ uint64_t subscriptionId;
+ uint8_t groupId;
+ uint16_t periodicity; /* In milliseconds */
+ CmTimer periodTimer;
+ SchKpiSupported kpiStats;
+}SchStatsGrp;
+
+typedef struct schStatsInfo
+{
+ uint8_t numStatsGroup;
+ SchStatsGrp statsGrpList[MAX_NUM_STATS_GRP];
+}SchStatsInfo;
+
+typedef struct schStatistics
+{
+ uint16_t numOfStatsCfgd;
+ SchStatsInfo statsInfoList[MAX_NUM_STATS_CFG];
+ SchKpiActive activeKpiList;
}SchStatistics;
/**
/* Statistics Function */
uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq);
-uint8_t SchSendStatsIndToMac(Inst inst, SchMeasurementType measType, double value);
+uint8_t SchSendStatsIndToMac(Inst inst, SchStatsInd *statsInd);
+uint8_t schCalcAndSendGrpStats(SchStatsGrp *grpInfo);
/**********************************************************************
End of file
UlSchedInfo ulSchedInfo;
SchUlSlotInfo *schUlSlotInfo = NULLP;
SlotTimingInfo ulTimingInfo;
+ CmLList *node = NULLP;
+ TotalPrbUsage *ulTotalPrbUsage = NULLP;
+
memset(&ulSchedInfo, 0, sizeof(UlSchedInfo));
/* add PHY delta */
DU_LOG("\nERROR --> SCH : Sending UL Sch info from SCH to MAC failed");
}
- /* Update UL statistics */
- if(schCb[schInst].statistics.ulTotalPrbUsage)
+ /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
+ node = cmLListFirst(&schCb[schInst].statistics.activeKpiList.ulTotPrbUseList);
+ while(node)
{
- schCb[schInst].statistics.ulTotalPrbUsage->numPrbUsedForTx += schUlSlotInfo->prbAlloc.numPrbAlloc;
- schCb[schInst].statistics.ulTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+ ulTotalPrbUsage = (TotalPrbUsage *)node->node;
+ ulTotalPrbUsage->numPrbUsedForTx += schUlSlotInfo->prbAlloc.numPrbAlloc;
+ ulTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+ node = node->next;
}
/* Re-initialize UL Slot */
DlBrdcstAlloc *dlBrdcstAlloc = NULLP;
SchCellCb *cell = NULLP;
Inst schInst = pst->dstInst-SCH_INST_START;
+ CmLList *node = NULLP;
+ TotalPrbUsage *dlTotalPrbUsage = NULLP;
cell = schCb[schInst].cells[schInst];
if(cell == NULLP)
return (ret);
}
- /* Update DL statistics */
- if(schCb[schInst].statistics.dlTotalPrbUsage)
+ /* Update DL PRB Usage for all stats group which requested for DL Total PRB Usage */
+ node = cmLListFirst(&schCb[schInst].statistics.activeKpiList.dlTotPrbUseList);
+ while(node)
{
- schCb[schInst].statistics.dlTotalPrbUsage->numPrbUsedForTx += cell->schDlSlotInfo[slot]->prbAlloc.numPrbAlloc;
- schCb[schInst].statistics.dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+ dlTotalPrbUsage = (TotalPrbUsage *)node->node;
+ dlTotalPrbUsage->numPrbUsedForTx += cell->schDlSlotInfo[slot]->prbAlloc.numPrbAlloc;
+ dlTotalPrbUsage->totalPrbAvailForTx += MAX_NUM_RB;
+ node = node->next;
}
/* Re-initialize DL slot */
{
switch (tmrEvnt)
{
- case EVENT_DL_TOTAL_PRB_USAGE_TMR:
- {
- if(((TotalPrbUsage *)cb)->periodTimer.tmrEvnt == EVENT_DL_TOTAL_PRB_USAGE_TMR)
+ case EVENT_STATISTICS_TMR:
{
- DU_LOG("\nDEBUG --> SCH : schChkTmr: Timer Evnt [%d] already running", tmrEvnt);
- return TRUE;
+ if(((SchStatsGrp *)cb)->periodTimer.tmrEvnt == EVENT_STATISTICS_TMR)
+ {
+ DU_LOG("\nDEBUG --> SCH : schChkTmr: Timer Evnt [%d] already running", tmrEvnt);
+ return TRUE;
+ }
+ break;
}
- break;
- }
-
- case EVENT_UL_TOTAL_PRB_USAGE_TMR:
- {
- if(((TotalPrbUsage *)cb)->periodTimer.tmrEvnt == EVENT_UL_TOTAL_PRB_USAGE_TMR)
+ default:
{
- DU_LOG("\nDEBUG --> SCH : schChkTmr: Timer Evnt [%d] already running", tmrEvnt);
- return TRUE;
+ DU_LOG("\nERROR --> SCH : schChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
}
- break;
- }
-
- default:
- {
- DU_LOG("\nERROR --> SCH : schChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
- }
}
-
return FALSE;
}
*
* @return Void
*/
-void schStartTmr(SchCb *gCb, PTR cb, int16_t tmrEvnt, uint8_t timerValue)
+void schStartTmr(SchCb *gCb, PTR cb, int16_t tmrEvnt, uint16_t timerValue)
{
- TotalPrbUsage *dlTotalPrbUsage;
- TotalPrbUsage *ulTotalPrbUsage;
+ SchStatsGrp *statsGrp = NULLP;
CmTmrArg arg;
arg.wait = 0;
switch (tmrEvnt)
{
- case EVENT_DL_TOTAL_PRB_USAGE_TMR:
+ case EVENT_STATISTICS_TMR:
{
- dlTotalPrbUsage = ((TotalPrbUsage *)cb);
+ statsGrp = ((SchStatsGrp *)cb);
TMR_CALCUATE_WAIT(arg.wait, timerValue, gCb->schTimersInfo.tmrRes);
- arg.timers = &dlTotalPrbUsage->periodTimer;
- arg.max = MAX_TOTAL_PRB_USAGE_TMR;
+ arg.timers = &statsGrp->periodTimer;
+ arg.max = MAX_NUM_TMR_PER_STATS_GRP;
break;
}
- case EVENT_UL_TOTAL_PRB_USAGE_TMR:
- {
- ulTotalPrbUsage = ((TotalPrbUsage *)cb);
- TMR_CALCUATE_WAIT(arg.wait, timerValue, gCb->schTimersInfo.tmrRes);
-
- arg.timers = &ulTotalPrbUsage->periodTimer;
- arg.max = MAX_TOTAL_PRB_USAGE_TMR;
- break;
- }
default:
{
DU_LOG("\nERROR --> SCH : schStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
switch (tmrType)
{
- case EVENT_DL_TOTAL_PRB_USAGE_TMR:
- {
- arg.timers = &((TotalPrbUsage *)cb)->periodTimer;
- arg.max = MAX_TOTAL_PRB_USAGE_TMR;
- break;
- }
- case EVENT_UL_TOTAL_PRB_USAGE_TMR:
+ case EVENT_STATISTICS_TMR:
{
- arg.timers = &((TotalPrbUsage *)cb)->periodTimer;
- arg.max = MAX_TOTAL_PRB_USAGE_TMR;
+ arg.timers = &((SchStatsGrp *)cb)->periodTimer;
+ arg.max = MAX_NUM_TMR_PER_STATS_GRP;
break;
}
}
/**
- * @brief Handler to process Timer expiry of DL Total PRB Usage calculation
+ * @brief Handler for Statistics group timer expiry
*
- * @param[in] cb Control block depending on the type of the timer event.
- * @param[in] tmrEvnt Timer event to be started
+ * @details
*
- * @return Bool indicating whether the timer is running or not
- * -# ROK
- * -# RFAILED
-*/
-uint8_t SchProcDlTotalPrbUsageTmrExp(TotalPrbUsage *dlTotalPrbUsage)
-{
- double percentageOfTotalPrbUsed = 0;
-
- if(dlTotalPrbUsage->totalPrbAvailForTx)
- percentageOfTotalPrbUsed = ((100.0 * dlTotalPrbUsage->numPrbUsedForTx) / dlTotalPrbUsage->totalPrbAvailForTx);
- SchSendStatsIndToMac(dlTotalPrbUsage->schInst, SCH_DL_TOTAL_PRB_USAGE, percentageOfTotalPrbUsed);
-
- /* Restart Timer */
- dlTotalPrbUsage->numPrbUsedForTx = 0;
- dlTotalPrbUsage->totalPrbAvailForTx = 0;
- schStartTmr(&schCb[dlTotalPrbUsage->schInst], (PTR)(dlTotalPrbUsage), EVENT_DL_TOTAL_PRB_USAGE_TMR, \
- dlTotalPrbUsage->periodicity);
-
- return ROK;
-}
-
-/**
- * @brief Handler to check if the timer is running
+ * Function : SchProcStatisticsGrpTmrExp
*
- * @param[in] cb Control block depending on the type of the timer event.
- * @param[in] tmrEvnt Timer event to be started
+ * This function calculates and sends statistics of
+ * the stats-group for which timer expired.
+ * Once Statistics Indication is sent, timer for this
+ * group is restarted.
*
- * @return Bool indicating whether the timer is running or not
+ * @param[in] Statistics group control block
+ * @return uint8_t
* -# ROK
- * -# RFAILED
-*/
-uint8_t SchProcUlTotalPrbUsageTmrExp(TotalPrbUsage *ulTotalPrbUsage)
+ **/
+uint8_t SchProcStatisticsGrpTmrExp(SchStatsGrp *cb)
{
- double percentageOfTotalPrbUsed = 0;
-
- if(ulTotalPrbUsage->totalPrbAvailForTx)
- percentageOfTotalPrbUsed = ((100.0 * ulTotalPrbUsage->numPrbUsedForTx) / ulTotalPrbUsage->totalPrbAvailForTx);
- SchSendStatsIndToMac(ulTotalPrbUsage->schInst, SCH_UL_TOTAL_PRB_USAGE, percentageOfTotalPrbUsed);
-
- /* Restart Timer */
- ulTotalPrbUsage->numPrbUsedForTx = 0;
- ulTotalPrbUsage->totalPrbAvailForTx = 0;
- schStartTmr(&schCb[ulTotalPrbUsage->schInst], (PTR)(ulTotalPrbUsage), EVENT_UL_TOTAL_PRB_USAGE_TMR, \
- ulTotalPrbUsage->periodicity);
-
+ if(schCalcAndSendGrpStats(cb) != ROK)
+ {
+ DU_LOG("\nERROR --> SCH : SchProcStatisticsGrpTmrExp: Fails to send group statistics");
+ }
+ schStartTmr(&schCb[cb->schInst], (PTR)(cb), EVENT_STATISTICS_TMR, cb->periodicity);
return ROK;
}
switch (tmrEvnt)
{
- case EVENT_DL_TOTAL_PRB_USAGE_TMR:
- {
- SchProcDlTotalPrbUsageTmrExp((TotalPrbUsage*)cb);
- break;
- }
- case EVENT_UL_TOTAL_PRB_USAGE_TMR:
+ case EVENT_STATISTICS_TMR:
{
- SchProcUlTotalPrbUsageTmrExp((TotalPrbUsage*)cb);
+#ifdef DEBUG_PRINT
+ DU_LOG("\nDEBUG --> SCH : Statistics Timer Expired for Subscription Id [%ld] GroupId [%d]", \
+ ((SchStatsGrp*)cb)->subscriptionId, ((SchStatsGrp*)cb)->groupId);
+#endif
+ SchProcStatisticsGrpTmrExp((SchStatsGrp*)cb);
break;
}
+
default:
{
DU_LOG("\nERROR --> DU : duStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
################################################################################
*******************************************************************************/
-#define MAX_TOTAL_PRB_USAGE_TMR 1
+#define MAX_NUM_TMR_PER_STATS_GRP 1
-#define EVENT_DL_TOTAL_PRB_USAGE_TMR 1
-#define EVENT_UL_TOTAL_PRB_USAGE_TMR 2
+#define EVENT_STATISTICS_TMR 1
bool schChkTmr(PTR cb, int16_t tmrEvnt);
-void schStartTmr(SchCb *gCb, PTR cb, int16_t tmrEvnt, uint8_t timerValue);
+void schStartTmr(SchCb *gCb, PTR cb, int16_t tmrEvnt, uint16_t timerValue);
void schStopTmr(SchCb *gCb, PTR cb, uint8_t tmrType);
/**********************************************************************
/*First SCS in kHz as per 3gpp spec 38.211 Table 4.2-1 */
#define BASE_SCS 15
-#define MAX_NUM_STATS 10
+#define MAX_NUM_STATS_CFG 2 /* Max number of statistics configuration/Subscription supported */
+#define MAX_NUM_STATS_GRP 5 /* Max number of statistics group per configuration request */
+#define MAX_NUM_STATS 10 /* Max number of statistics per group */
/* Defining macros for common utility functions */
#define ODU_GET_MSG_BUF SGetMsg
SiSchedulingInfo **siSchedulingInfo;
}MacDlBroadcastReq;
-typedef struct macStatsInfo
+typedef struct macStatsGrpInfo
{
- MacMeasurementType type;
- uint16_t periodicity; /* In milliseconds */
-}MacStatsInfo;
+ uint8_t groupId;
+ uint16_t periodicity; /* In milliseconds */
+ uint8_t numStats;
+ MacMeasurementType statsList[MAX_NUM_STATS];
+}MacStatsGrpInfo;
typedef struct macStatsReq
{
- uint8_t numStats;
- MacStatsInfo statsList[MAX_NUM_STATS];
+ uint64_t subscriptionId;
+ uint8_t numStatsGroup;
+ MacStatsGrpInfo statsGrpList[MAX_NUM_STATS_GRP];
}MacStatsReq;
-typedef struct macStatsRsp
+typedef struct macStatsGrpRejected
{
- MacRsp rsp;
+ uint8_t groupId;
CauseOfResult cause;
+}MacStatsGrpRejected;
+
+typedef struct macStatsRsp
+{
+ uint64_t subscriptionId;
+ uint8_t numGrpAccepted;
+ uint8_t statsGrpAcceptedList[MAX_NUM_STATS_GRP];
+ uint8_t numGrpRejected;
+ MacStatsGrpRejected statsGrpRejectedList[MAX_NUM_STATS_GRP];
}MacStatsRsp;
-typedef struct macStatsInd
+typedef struct macStats
{
MacMeasurementType type;
double value;
+}MacStats;
+
+typedef struct macStatsInd
+{
+ uint64_t subscriptionId;
+ uint8_t groupId;
+ uint8_t numStats;
+ MacStats measuredStatsList[MAX_NUM_STATS];
}MacStatsInd;
/****************** FUNCTION POINTERS ********************************/
SchUeHqInfo *ueHqInfo;
}SchRlsHqInfo;
-typedef struct schStatsInfo
+/* Statistics Request from MAC to SCH */
+typedef struct schStatsGrpInfo
{
- SchMeasurementType type;
- uint16_t periodicity; /* In milliseconds */
-}SchStatsInfo;
+ uint8_t groupId;
+ uint16_t periodicity; /* In milliseconds */
+ uint8_t numStats;
+ SchMeasurementType statsList[MAX_NUM_STATS];
+}SchStatsGrpInfo;
typedef struct schStatsReq
{
- uint8_t numStats;
- SchStatsInfo statsList[MAX_NUM_STATS];
+ uint64_t subscriptionId;
+ uint8_t numStatsGroup;
+ SchStatsGrpInfo statsGrpList[MAX_NUM_STATS_GRP];
}SchStatsReq;
-typedef struct schStatsRsp
+/* Statistics Response from SCH to MAC */
+typedef struct schStatsGrpRejected
{
- SchMacRsp rsp;
+ uint8_t groupId;
CauseOfResult cause;
+}SchStatsGrpRejected;
+
+typedef struct schStatsRsp
+{
+ uint64_t subscriptionId;
+ uint8_t numGrpAccepted;
+ uint8_t statsGrpAcceptedList[MAX_NUM_STATS_GRP];
+ uint8_t numGrpRejected;
+ SchStatsGrpRejected statsGrpRejectedList[MAX_NUM_STATS_GRP];
}SchStatsRsp;
-typedef struct schStatsInd
+/* Statistics Indication from SCH to MAC */
+typedef struct schStats
{
SchMeasurementType type;
double value;
+}SchStats;
+
+typedef struct schStatsInd
+{
+ uint64_t subscriptionId;
+ uint8_t groupId;
+ uint8_t numStats;
+ SchStats measuredStatsList[MAX_NUM_STATS];
}SchStatsInd;
+
/* function declarations */
uint8_t MacMessageRouter(Pst *pst, void *msg);
uint8_t SchMessageRouter(Pst *pst, void *msg);
/* Hardcoding values for now for testing purpose
* Will be removed in next gerrit */
- stats.macStatsReq.numStats = 2;
- stats.macStatsReq.statsList[0].type = MAC_DL_TOTAL_PRB_USAGE;
- stats.macStatsReq.statsList[0].periodicity = 100;
- stats.macStatsReq.statsList[1].type = MAC_UL_TOTAL_PRB_USAGE;
- stats.macStatsReq.statsList[1].periodicity = 100;
+ stats.macStatsReq.subscriptionId = 1;
+ stats.macStatsReq.numStatsGroup = 1;
+ stats.macStatsReq.statsGrpList[0].groupId = 1;
+ stats.macStatsReq.statsGrpList[0].periodicity = 100;
+ stats.macStatsReq.statsGrpList[0].numStats = 2;
+ stats.macStatsReq.statsGrpList[0].statsList[0] = MAC_DL_TOTAL_PRB_USAGE;
+ stats.macStatsReq.statsGrpList[0].statsList[1] = MAC_UL_TOTAL_PRB_USAGE;
return stats;
}
* ****************************************************************/
uint8_t DuProcMacStatsRsp(Pst *pst, MacStatsRsp *statsRsp)
{
+ uint8_t idx = 0;
+
+ DU_LOG("\nINFO --> DU_APP : DuProcMacStatsRsp: Received Statistics Response from MAC");
+
if(statsRsp)
{
- if(statsRsp->rsp == MAC_DU_APP_RSP_OK)
+#ifdef DEBUG_PRINT
+ DU_LOG("\n Subscription Id [%ld]", statsRsp->subscriptionId);
+
+ DU_LOG("\n Number of Accepted Groups [%d]", statsRsp->numGrpAccepted);
+ for(idx=0; idx<statsRsp->numGrpAccepted; idx++)
{
- DU_LOG("\nINFO --> DU_APP : Statistics configured successfully");
- /* TODO : Start Reporting period timer for this subscription request
- * To be handled in next gerrit */
+ DU_LOG("\n Group Id [%d]", statsRsp->statsGrpAcceptedList[idx]);
}
- else
+
+ DU_LOG("\n Number of Rejected Groups [%d]", statsRsp->numGrpRejected);
+ for(idx=0; idx<statsRsp->numGrpRejected; idx++)
{
- DU_LOG("\nERROR --> DU_APP : Statistics configuration failed with cause [%d]", statsRsp->cause);
+ DU_LOG("\n Group Id [%d]", statsRsp->statsGrpRejectedList[idx]);
}
+#endif
+
DU_FREE_SHRABL_BUF(pst->region, pst->pool, statsRsp, sizeof(MacStatsRsp));
return ROK;
}
- DU_LOG("\nINFO --> DU_APP : DuProcMacStatsRsp: Received NULL Pointer");
+ DU_LOG("\nERROR --> DU_APP : DuProcMacStatsRsp: Received NULL Pointer");
return RFAILED;
}
{
#ifdef DEBUG_PRINT
DU_LOG("\nDEBUG --> DU_APP : DuProcMacStatsInd: Received Statistics Indication");
- DU_LOG("\nMeasurement type [%d] Measurement Value [%lf]", statsInd->type, statsInd->value);
+ DU_LOG("\n Subscription Id [%ld]", statsInd->subscriptionId);
+ DU_LOG("\n Group Id [%d]", statsInd->groupId);
+ for(int idx = 0; idx < statsInd->numStats; idx++)
+ {
+ DU_LOG("\n Meas type [%d] Meas Value [%lf]", statsInd->measuredStatsList[idx].type,\
+ statsInd->measuredStatsList[idx].value);
+ }
#endif
/* TODO : When stats indication is received