#define RLC_TMR_LEN 10
#define RLC_MAX_UM_TMR 1
#define RLC_MAX_AM_TMR 3
+#define RLC_MAX_THPT_TMR 1
/* Timer events */
#define EVENT_RLC_UMUL_REASSEMBLE_TMR 1
#ifdef LTE_L2_MEAS
#define EVENT_RLC_L2_TMR 6
#endif /* LTE_L2_MEAS */
+#define EVENT_RLC_THROUGHPUT_TMR 7
/*******************************************************************************
* DBM Defines
#endif /* LTE_L2_MEAS */
}RlcUlCb;
+typedef struct rlcThptPerUe
+{
+ uint16_t ueIdx;
+ uint64_t dataVol;
+}RlcThptPerUe;
+
+/**
+ * @brief Structure to hold information about throughput at RLC
+ *
+ */
+typedef struct rlcThpt
+{
+ Inst inst; /* RLC instance */
+ CmTimer thptTmr; /* Throughput Timer */
+ uint8_t numActvUe; /* Number of Active UEs */
+ RlcThptPerUe thptPerUe[MAX_NUM_UE]; /* Throughput calculated per UE */
+}RlcThpt;
/**
* @brief Structure to hold an information about a RLC instance
RlcDlCb *dlCb; /*!< Dl Control Block */
} u;
uint8_t dlSduId; /*!< Downlink SDU ID */
+ RlcThpt rlcThpt; /*!< Throughput at RLC*/
}RlcCb;
RlcCb *rlcCb[MAX_RLC_INSTANCES]; /*!< RLC global control block */
entCfg->rbId);
return RFAILED;
}
+ /* Start throughput calculation for this UE */
+ gCb->rlcThpt.thptPerUe[gCb->rlcThpt.numActvUe].ueIdx = ueId;
+ gCb->rlcThpt.thptPerUe[gCb->rlcThpt.numActvUe].dataVol = 0;
+ gCb->rlcThpt.numActvUe++;
+
+ if((rlcChkTmr(gCb, (PTR)(&gCb->rlcThpt), EVENT_RLC_THROUGHPUT_TMR)) == FALSE)
+ {
+ printf("\nHLAL Starting Throughput timer");
+ rlcStartTmr(gCb, (PTR)(&gCb->rlcThpt), EVENT_RLC_THROUGHPUT_TMR);
+ }
}
/* Validate LChId for UM and AM modes */
rlcTqCp->tmrLen = RLC_TMR_LEN;
rlcTqCp->nxtEnt = 0;
+ gCb->rlcThpt.inst = gCb->init.inst;
+ gCb->rlcThpt.thptTmr.tmrEvnt = TMR_NONE;
+ gCb->rlcThpt.numActvUe = 0;
+ memset(gCb->rlcThpt.thptPerUe, 0, MAX_NUM_UE * sizeof(RlcThptPerUe));
+
if(gCb->genCfg.rlcMode == LKW_RLC_MODE_DL)
{
RLC_ALLOC(gCb,gCb->u.dlCb, sizeof (RlcDlCb));
/* private function declarations */
static Void rlcBndTmrExpiry(PTR cb);
+void rlcThptTmrExpiry(PTR cb);
/**
* @brief Handler to start timer
break;
}
#endif
+ case EVENT_RLC_THROUGHPUT_TMR:
+ {
+ RlcThpt *thptCb = (RlcThpt *)cb;
+ RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
+ arg.timers = &thptCb->thptTmr;
+ arg.max = RLC_MAX_THPT_TMR;
+ break;
+ }
default:
{
DU_LOG("\nERROR --> RLC : rlcStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
break;
}
#endif
+ case EVENT_RLC_THROUGHPUT_TMR:
+ {
+ arg.timers = &((RlcThpt *)cb)->thptTmr;
+ arg.max = RLC_MAX_THPT_TMR;
+ }
default:
{
DU_LOG("\nERROR --> RLC : rlcStopTmr: Invalid tmr Evnt[%d]", tmrType);
rlcBndTmrExpiry(cb);
break;
}
- /* kw005.201 L2 Measurement support */
+ case EVENT_RLC_THROUGHPUT_TMR:
+ {
+ rlcThptTmrExpiry(cb);
+ break;
+ }
default:
{
break;
{
return (((RlcRguSapCb *)cb)->bndTmr.tmrEvnt == EVENT_RLC_WAIT_BNDCFM);
}
+ case EVENT_RLC_THROUGHPUT_TMR:
+ {
+ return (((RlcThpt *)cb)->thptTmr.tmrEvnt == EVENT_RLC_THROUGHPUT_TMR);
+ }
default:
{
DU_LOG("\nERROR --> RLC : rlcChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
return;
}
+/**
+ * @brief Handler to do processing on expiry of the throughput timer
+ *
+ * @details
+ * This function processes the RLC throughput timer expiry.
+ *
+ * @param[in] cb Pointer to the RLC throughput struct
+ *
+ * @return Void
+ */
+void rlcThptTmrExpiry(PTR cb)
+{
+ uint16_t ueIdx;
+ long double tpt;
+ RlcThpt *rlcThptCb = (RlcThpt*)cb;
+
+ /* Print throughput */
+ DU_LOG("\n===================== DL Throughput ==============================");
+ DU_LOG("\nNumber of UEs : %d", rlcThptCb->numActvUe);
+ for(ueIdx = 0; ueIdx < rlcThptCb->numActvUe; ueIdx++)
+ {
+ /* Spec 28.552, section 5.1.1.3 :
+ * Throughput in kilobits/sec = (dataVol in kiloBits * 1000)/time in milligseconds
+ *
+ * Since our dataVol is in bytes, multiplying 0.008 to covert into kilobits i.e.
+ * Throughput[kbits/sec] = (dataVol * 0.008 * 1000)/time in ms
+ */
+ tpt = (double)(rlcThptCb->thptPerUe[ueIdx].dataVol * 8)/(double)ODU_THROUGHPUT_PRINT_TIME_INTERVAL;
+
+ DU_LOG("\nUE Id : %d DL Tpt : %.2Lf", rlcThptCb->thptPerUe[ueIdx].ueIdx, tpt);
+ rlcThptCb->thptPerUe[ueIdx].dataVol = 0;
+ }
+ DU_LOG("\n==================================================================");
+
+ /* Restart timer */
+ rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_THROUGHPUT_TMR);
+
+ return;
+}
\f
/********************************************************************30**
{
uint8_t numPdu = 0;
uint16_t ueIdx;
+ uint16_t actvUeIdx;
RlcDlUeCb *ueCb; /* UE control block */
uint32_t count; /* Loop Counter */
uint32_t numTb; /* Number of Tbs */
/* If ueCb is not found for current rnti then continue to look for next rnti*/
continue;
}
+
+ /* Find ueIdx for throughput calculation */
+ for(actvUeIdx = 0; actvUeIdx < gCb->rlcThpt.numActvUe; actvUeIdx++)
+ {
+ if(gCb->rlcThpt.thptPerUe[actvUeIdx].ueIdx == ueIdx)
+ break;
+ }
+
/* kw002.201 Removed the allocation of RlcDatReq */
/* kw004.201 Used SSI function to initialize the variable */
memset(&datReq, 0, sizeof(RlcDatReq) );
if (rbCb && (!rlcDlUtlIsReestInProgress(rbCb)))
{
-//Debug
+ /* Cosider buffer size for throughput calculation */
+ gCb->rlcThpt.thptPerUe[actvUeIdx].dataVol += staIndTb->lchStaInd[count].totBufSize;
+
staIndSz += staIndTb->lchStaInd[count].totBufSize;
datReq.pduSz = staIndTb->lchStaInd[count].totBufSize;
#ifdef LTE_L2_MEAS
if(!datReqInfo)
{
DU_LOG("\nERROR --> RLC_DL : Memory allocation failed for DatReq in RlcProcDlUserDataTransfer()");
- RLC_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, dlDataMsgInfo->dlMsg, dlDataMsgInfo->msgLen);
+ ODU_PUT_MSG_BUF(dlDataMsgInfo->dlMsg);
RLC_SHRABL_STATIC_BUF_FREE(pst->region, pst->pool, dlDataMsgInfo, sizeof(RlcDlUserDataInfo));
return RFAILED;
}
#define TOTAL_PRB_20MHZ_MU0 106
#define TOTAL_PRB_100MHZ_MU1 273
+#define ODU_THROUGHPUT_PRINT_TIME_INTERVAL 5 /* in milliseconds */
+
/* Defining macros for common utility functions */
#define ODU_GET_MSG_BUF SGetMsg
#define ODU_PUT_MSG_BUF SPutMsg
/* Supported by SPLIT Architecture */
uint16_t maxUdxSaps; /*!< Maximum Udx SAPs. */
/* Supported by SPLIT Architecture ends */
- Ticks timeRes; /*!< Time resolution. */
+ Ticks timeRes; /*!< Time resolution. */
/* Supported by SPLIT Architecture */
uint8_t rlcMode; /*!< RLC_DL or RLC_UL */
/* Supported by SPLIT Architecture ends */
if(ret != ROK)
{
DU_LOG("\nERROR --> DU_APP : Failed to send User Data to RLC in duHdlEgtpDlData()");
- DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlDataMsgInfo->dlMsg, msgLen);
+ ODU_PUT_MSG_BUF(dlDataMsgInfo->dlMsg);
DU_FREE_SHRABL_BUF(DU_APP_MEM_REGION, DU_POOL, dlDataMsgInfo, sizeof(RlcDlUserDataInfo));
}
return ret;
* ****************************************************************/
uint8_t duUpdateMacCfg(MacUeCfg *macUeCfg, F1UeContextSetupDb *f1UeDb)
{
- uint8_t ret, lcIdx, dbIdx, numLcs, lcDelIdx;
+ uint8_t ret, lcIdx, dbIdx, numLcs, lcDelIdx, cellIdx;
+ MacUeCfg *oldMacUeCfg;
ret = ROK;
/*Filling Cell Group Cfg*/
NULL, &macUeCfg->spCellCfg.servCellCfg.initUlBwp.puschCfg);
}
ret = fillAmbr(&macUeCfg->ambrCfg, f1UeDb->duUeCfg.ambrCfg);
+
+ GET_CELL_IDX(macUeCfg->cellId, cellIdx);
+ oldMacUeCfg = &duCb.actvCellLst[cellIdx]->ueCb[macUeCfg->ueIdx-1].macUeCfg;
+ duFillModulationDetails(macUeCfg, oldMacUeCfg, f1UeDb->duUeCfg.ueNrCapability);
}
+
/* Filling LC Context */
for(dbIdx = 0; (dbIdx < f1UeDb->duUeCfg.numMacLcs && ret == ROK); dbIdx++)
{