From b3d5c17f74361fcdcb9b9febff450292197e3a57 Mon Sep 17 00:00:00 2001 From: "lal.harshita" Date: Tue, 12 Sep 2023 15:26:24 +0530 Subject: [PATCH] [Epic-ID: ODUHIGH-516][Task-ID: ODUHIGH-523] KPI reporting per statistics group Change-Id: I0e43ebd13a1e1b5a082b0fa342fb547acc7bfc31 Signed-off-by: lal.harshita --- src/5gnrmac/mac.h | 12 ++ src/5gnrmac/mac_cfg_hdl.c | 279 ++++++++++++++++++++------- src/5gnrmac/mac_msg_hdl.c | 45 +++-- src/5gnrsch/sch.c | 463 ++++++++++++++++++++++++++++++++------------- src/5gnrsch/sch.h | 37 +++- src/5gnrsch/sch_common.c | 14 +- src/5gnrsch/sch_slot_ind.c | 13 +- src/5gnrsch/sch_tmr.c | 138 ++++---------- src/5gnrsch/sch_tmr.h | 7 +- src/cm/common_def.h | 4 +- src/cm/du_app_mac_inf.h | 38 +++- src/cm/mac_sch_interface.h | 42 +++- src/du_app/du_msg_hdl.c | 44 +++-- 13 files changed, 772 insertions(+), 364 deletions(-) diff --git a/src/5gnrmac/mac.h b/src/5gnrmac/mac.h index a24535823..a4dc3207e 100644 --- a/src/5gnrmac/mac.h +++ b/src/5gnrmac/mac.h @@ -26,6 +26,7 @@ #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 @@ -59,6 +60,7 @@ #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 @@ -245,6 +247,15 @@ struct macCellCb 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; @@ -254,6 +265,7 @@ typedef struct macCb 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 */ diff --git a/src/5gnrmac/mac_cfg_hdl.c b/src/5gnrmac/mac_cfg_hdl.c index 589f73029..0572fd781 100644 --- a/src/5gnrmac/mac_cfg_hdl.c +++ b/src/5gnrmac/mac_cfg_hdl.c @@ -1037,12 +1037,14 @@ uint8_t MacProcDlBroadcastReq(Pst *pst, MacDlBroadcastReq *dlBroadcastReq) * @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; @@ -1056,8 +1058,8 @@ uint8_t MacSendStatsRspToDuApp(MacRsp rsp, CauseOfResult cause) } 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); @@ -1074,6 +1076,43 @@ uint8_t MacSendStatsRspToDuApp(MacRsp rsp, CauseOfResult cause) 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 * @@ -1081,7 +1120,20 @@ uint8_t MacSendStatsRspToDuApp(MacRsp rsp, CauseOfResult cause) * * 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 @@ -1090,85 +1142,134 @@ uint8_t MacSendStatsRspToDuApp(MacRsp rsp, CauseOfResult cause) **/ 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; } @@ -1188,17 +1289,49 @@ uint8_t MacProcStatsReq(Pst *pst, MacStatsReq *macStatsReq) **/ 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; accptdIdxnumGrpAccepted && macStatsRsp->numGrpAcceptedstatsGrpAcceptedList[macStatsRsp->numGrpAccepted++] = schStatsRsp->statsGrpAcceptedList[accptdIdx]; + } + + /* List together all stats group rejected by MAC and by SCH */ + for(rjctdIdx = 0; rjctdIdx < schStatsRsp->numGrpRejected && macStatsRsp->numGrpRejectedstatsGrpRejectedList[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; } diff --git a/src/5gnrmac/mac_msg_hdl.c b/src/5gnrmac/mac_msg_hdl.c index f5e6649ff..d5544ba2d 100644 --- a/src/5gnrmac/mac_msg_hdl.c +++ b/src/5gnrmac/mac_msg_hdl.c @@ -1081,6 +1081,7 @@ uint8_t MacProcSliceRecfgReq(Pst *pst, MacSliceRecfgReq *macSliceRecfgReq) **/ uint8_t MacProcSchStatsInd(Pst *pst, SchStatsInd *schStatsInd) { + uint8_t statsIdx = 0; Pst indPst; MacStatsInd *macStatsInd; @@ -1101,26 +1102,34 @@ uint8_t MacProcSchStatsInd(Pst *pst, SchStatsInd *schStatsInd) 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); diff --git a/src/5gnrsch/sch.c b/src/5gnrsch/sch.c index 397e8621a..9017f924d 100644 --- a/src/5gnrsch/sch.c +++ b/src/5gnrsch/sch.c @@ -131,6 +131,11 @@ uint8_t SchInstCfg(RgCfg *cfg, Inst dInst) 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"); @@ -1383,7 +1388,7 @@ uint8_t allocatePrbDl(SchCellCb *cell, SlotTimingInfo slotTime, \ } /* 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 */ @@ -1520,7 +1525,7 @@ uint8_t allocatePrbUl(SchCellCb *cell, SlotTimingInfo slotTime, \ } /* 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 */ @@ -2516,29 +2521,29 @@ uint8_t SchProcPhrInd(Pst *pst, SchPwrHeadroomInd *schPhrInd) * 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"); @@ -2549,143 +2554,271 @@ uint8_t SchSendStatsRspToMac(Inst inst, SchMacRsp result, CauseOfResult cause) /******************************************************************* * - * @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; reqGrpIdxnumStatsGroup && grpIdxstatsGrpList[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 */ @@ -2708,26 +2841,21 @@ uint8_t SchProcStatsReq(Pst *pst, SchStatsReq *statsReq) * 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"); @@ -2735,6 +2863,87 @@ uint8_t SchSendStatsIndToMac(Inst inst, SchMeasurementType measType, double valu 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 diff --git a/src/5gnrsch/sch.h b/src/5gnrsch/sch.h index 38d006329..4a82d1786 100644 --- a/src/5gnrsch/sch.h +++ b/src/5gnrsch/sch.h @@ -602,17 +602,43 @@ typedef struct 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; /** @@ -796,7 +822,8 @@ void schMsg4Complete(SchUeCb *ueCb); /* 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 diff --git a/src/5gnrsch/sch_common.c b/src/5gnrsch/sch_common.c index d7b4016a7..c1dee263a 100644 --- a/src/5gnrsch/sch_common.c +++ b/src/5gnrsch/sch_common.c @@ -485,6 +485,9 @@ uint8_t schUlResAlloc(SchCellCb *cell, Inst schInst) UlSchedInfo ulSchedInfo; SchUlSlotInfo *schUlSlotInfo = NULLP; SlotTimingInfo ulTimingInfo; + CmLList *node = NULLP; + TotalPrbUsage *ulTotalPrbUsage = NULLP; + memset(&ulSchedInfo, 0, sizeof(UlSchedInfo)); /* add PHY delta */ @@ -543,11 +546,14 @@ uint8_t schUlResAlloc(SchCellCb *cell, Inst schInst) 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 */ diff --git a/src/5gnrsch/sch_slot_ind.c b/src/5gnrsch/sch_slot_ind.c index 643ee657c..2a21774e5 100644 --- a/src/5gnrsch/sch_slot_ind.c +++ b/src/5gnrsch/sch_slot_ind.c @@ -651,6 +651,8 @@ uint8_t SchProcSlotInd(Pst *pst, SlotTimingInfo *slotInd) 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) @@ -750,11 +752,14 @@ uint8_t SchProcSlotInd(Pst *pst, SlotTimingInfo *slotInd) 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 */ diff --git a/src/5gnrsch/sch_tmr.c b/src/5gnrsch/sch_tmr.c index fa716742e..1a7fb3f98 100644 --- a/src/5gnrsch/sch_tmr.c +++ b/src/5gnrsch/sch_tmr.c @@ -37,32 +37,20 @@ bool schChkTmr(PTR cb, int16_t tmrEvnt) { 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; } @@ -74,10 +62,9 @@ bool schChkTmr(PTR cb, int16_t tmrEvnt) * * @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; @@ -89,25 +76,16 @@ void schStartTmr(SchCb *gCb, PTR cb, int16_t tmrEvnt, uint8_t timerValue) 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); @@ -148,16 +126,10 @@ void schStopTmr(SchCb *gCb, PTR cb, uint8_t tmrType) 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; } @@ -183,56 +155,28 @@ void schStopTmr(SchCb *gCb, PTR cb, uint8_t tmrType) } /** - * @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; } @@ -260,16 +204,16 @@ uint8_t schTmrExpiry(PTR cb, uint8_t tmrEvnt) 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); diff --git a/src/5gnrsch/sch_tmr.h b/src/5gnrsch/sch_tmr.h index 105346d1e..b3914e7b3 100644 --- a/src/5gnrsch/sch_tmr.h +++ b/src/5gnrsch/sch_tmr.h @@ -16,13 +16,12 @@ ################################################################################ *******************************************************************************/ -#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); /********************************************************************** diff --git a/src/cm/common_def.h b/src/cm/common_def.h index 371a1d5a5..cbe952c27 100644 --- a/src/cm/common_def.h +++ b/src/cm/common_def.h @@ -132,7 +132,9 @@ /*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 diff --git a/src/cm/du_app_mac_inf.h b/src/cm/du_app_mac_inf.h index 4b2f98ece..9e5ee54cd 100644 --- a/src/cm/du_app_mac_inf.h +++ b/src/cm/du_app_mac_inf.h @@ -1855,28 +1855,48 @@ typedef struct macDlBroadcastReq 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 ********************************/ diff --git a/src/cm/mac_sch_interface.h b/src/cm/mac_sch_interface.h index 58f894a01..ae772ad74 100644 --- a/src/cm/mac_sch_interface.h +++ b/src/cm/mac_sch_interface.h @@ -2248,30 +2248,54 @@ typedef struct schRlsHqInfo 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); diff --git a/src/du_app/du_msg_hdl.c b/src/du_app/du_msg_hdl.c index ca5c9e5f3..644494300 100644 --- a/src/du_app/du_msg_hdl.c +++ b/src/du_app/du_msg_hdl.c @@ -2150,11 +2150,13 @@ Statistics FetchStatsFromActionDefFormat1(ActionDefFormat1 format1) /* 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; } @@ -2238,23 +2240,33 @@ uint8_t BuildAndSendStatsReq(ActionDefinition subscribedAction) * ****************************************************************/ 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; idxnumGrpAccepted; 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; idxnumGrpRejected; 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; } @@ -2280,7 +2292,13 @@ uint8_t DuProcMacStatsInd(Pst *pst, MacStatsInd *statsInd) { #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 -- 2.16.6