DL throughput calculation for UM [Issue-ID: ODUHIGH-319]
[o-du/l2.git] / src / 5gnrrlc / kw_tmr.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17 *******************************************************************************/
18
19 /********************************************************************20**
20   
21         Name:    RLC - TMR module file
22     
23         Type:    C source file
24   
25         Desc:    Source code for timer functions such as, 
26
27                  - rlcStartTmr
28                  - rlcStopTmr
29                  - rlcTmrExpiry
30                  - rlcBndTmrExpiry  
31                   
32         File:    kw_tmr.c
33   
34 *********************************************************************21*/
35
36 /* header (.h) include files */
37 #include "common_def.h"
38 #include "lkw.h"           /* LKW defines */
39 #include "ckw.h"           /* CKW defines */
40 #include "kwu.h"           /* KWU defines */
41 #include "rgu.h"           /* RGU defines */
42 #include "kw_env.h"        /* RLC environment options */
43
44 #include "kw.h"            /* RLC defines */
45 #include "kw_err.h"        /* Error defines */
46 #include "kw_ul.h"
47 #include "kw_udx.h"
48 #include "kw_dl.h"
49
50 /* extern (.x) include files */
51 #include "lkw.x"           /* LKW */
52 #include "ckw.x"           /* CKW */
53 #include "kwu.x"           /* KWU */
54 #include "rgu.x"           /* RGU */
55
56 #include "kw.x"
57 #include "kw_udx.x"
58 #include "kw_dl.x"
59 #include "kw_ul.x"
60
61 /** 
62  * @file gp_tmr.c
63  * @brief RLC Timer Module
64 */
65
66 /**
67  * @def RLC_TMR_CALCUATE_WAIT
68  *
69  *    This macro calculates and assigns wait time based on the value of the 
70  *    timer and the timer resolution. Timer value of 0 signifies that the
71  *    timer is not configured
72  *
73  * @param[out] _wait   Time for which to arm the timer changed to proper 
74  *                     value according to the resolution
75  * @param[in] _tmrVal   Value of the timer
76  * @param[in] _timerRes   Resolution of the timer
77  *
78 */
79 #define RLC_TMR_CALCUATE_WAIT(_wait, _tmrVal, _timerRes)       \
80 {                                                             \
81    (_wait) = ((_tmrVal) * SS_TICKS_SEC)/((_timerRes) * 1000); \
82    if((0 != (_tmrVal)) && (0 == (_wait)))                     \
83    {                                                          \
84       (_wait) = 1;                                            \
85    }                                                          \
86 }
87
88 /* private function declarations */
89 static Void rlcBndTmrExpiry(PTR cb);
90 void rlcThptTmrExpiry(PTR cb);
91
92 /**
93  * @brief Handler to start timer
94  *       
95  * @param[in] gCb       Pointer to the RLC instance control block
96  * @param[in] cb        Control block depending on the type of the timer event. 
97  *                      It can be uplink/downlink rbCb or rgu sap control block
98  * @param[in] tmrEvnt   Timer event to be started
99  *
100  * @return  Void
101 */
102 void rlcStartTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
103 {
104 /* kw005.201 added support for L2 Measurement */
105 #ifdef LTE_L2_MEAS
106    RlcL2MeasEvtCb *measEvtCb = NULLP;
107 #endif
108
109    CmTmrArg arg;
110    arg.wait = 0;
111
112    /* kw002.201 Adjusting the wait time as per timeRes configured by layer manager */
113    switch (tmrEvnt)
114    {
115       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
116       {
117          RlcUmUl* umUl = &(((RlcUlRbCb *)cb)->m.umUl);
118          /* kw005.201 Changed wait calculation ccpu00117634*/ 
119          RLC_TMR_CALCUATE_WAIT(arg.wait, umUl->reAsmblTmrInt, gCb->genCfg.timeRes);
120
121          arg.timers = &umUl->reAsmblTmr;
122          arg.max = RLC_MAX_UM_TMR;
123          break;
124       }
125       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
126       {
127          RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
128          /* kw005.201 Changed wait calculation ccpu00117634*/ 
129          RLC_TMR_CALCUATE_WAIT(arg.wait, amUl->reAsmblTmrInt, gCb->genCfg.timeRes);         
130
131          arg.timers = &amUl->reAsmblTmr;
132          arg.max = RLC_MAX_AM_TMR;
133          break;
134       }
135       case EVENT_RLC_AMUL_STA_PROH_TMR:
136       {
137          RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
138          /* kw005.201 Changed wait calculation ccpu00117634*/ 
139          RLC_TMR_CALCUATE_WAIT(arg.wait,
140                               amUl->staProhTmrInt,
141                               gCb->genCfg.timeRes);                  
142
143          arg.timers = &amUl->staProhTmr;
144          arg.max = RLC_MAX_AM_TMR;
145          break;
146       } 
147       case EVENT_RLC_AMDL_POLL_RETX_TMR:
148       {
149          RlcAmDl* amDl = &(((RlcDlRbCb *)cb)->m.amDl);
150          /* kw005.201 Changed wait calculation ccpu00117634*/ 
151          RLC_TMR_CALCUATE_WAIT(arg.wait, 
152                               amDl->pollRetxTmrInt, 
153                               gCb->genCfg.timeRes);                  
154
155          arg.timers = &amDl->pollRetxTmr;
156          arg.max = RLC_MAX_AM_TMR;
157          break;
158       } 
159       case EVENT_RLC_WAIT_BNDCFM:
160       {
161          RlcRguSapCb* rguSap = (RlcRguSapCb *)cb;
162          /* kw005.201 Changed wait calculation ccpu00117634*/ 
163          RLC_TMR_CALCUATE_WAIT(arg.wait, rguSap->bndTmrInt, gCb->genCfg.timeRes);                  
164
165          arg.timers = &rguSap->bndTmr;
166          arg.max = RLC_MAX_RGUSAP_TMR;
167          break;
168       }
169 /* kw005.201 added support for L2 Measurement */
170 #ifdef LTE_L2_MEAS
171       case EVENT_RLC_L2_TMR:
172       {
173          measEvtCb = (RlcL2MeasEvtCb *)cb;
174          /* kw005.201 Changed wait calculation ccpu00117634*/ 
175          RLC_TMR_CALCUATE_WAIT(arg.wait, 
176                               measEvtCb->l2TmrCfg.val, 
177                               gCb->genCfg.timeRes);                  
178
179          arg.timers = &measEvtCb->l2Tmr;
180          arg.max = RLC_L2_MAX_TIMERS;
181          break;
182       }
183 #endif
184       case EVENT_RLC_THROUGHPUT_TMR:
185       {
186          RlcThpt *thptCb = (RlcThpt *)cb;
187          RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
188          arg.timers = &thptCb->thptTmr;
189          arg.max = RLC_MAX_THPT_TMR; 
190          break;
191       }
192       default:
193       {
194          DU_LOG("\nERROR  -->  RLC : rlcStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
195       }
196    } 
197
198    if(arg.wait != 0)
199    {
200       arg.tqCp   = &gCb->rlcTqCp;
201       arg.tq     = gCb->rlcTq;
202       arg.cb     = cb;
203       arg.evnt   = tmrEvnt;
204       arg.tNum   = 0;
205
206       cmPlcCbTq(&arg);
207    }
208
209    return;
210 }
211
212 /**
213  * @brief Handler to stop a timer
214  *       
215  * @param[in] gCb       Pointer to the RLC instance control block
216  * @param[in] cb        Control block depending on the type of the timer event. 
217  *                      It can be uplink/downlink rbCb or rgu sap control block
218  * @param[in] tmrType   Timer event to be started
219  *
220  * @return  Void
221 */
222 void rlcStopTmr(RlcCb *gCb, PTR cb, uint8_t tmrType)
223 {
224    CmTmrArg   arg;
225 /* kw005.201 added support for L2 Measurement */
226 #ifdef LTE_L2_MEAS
227    RlcL2MeasEvtCb *measEvtCb = NULLP;
228 #endif
229
230    arg.timers = NULLP;
231
232    switch (tmrType)
233    {
234       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
235       {
236          arg.timers  = &((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr;
237          arg.max = RLC_MAX_UM_TMR;
238          break;
239       }
240       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
241       {
242          arg.timers = &((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr;
243          arg.max = RLC_MAX_AM_TMR;
244          break;
245       }
246       case EVENT_RLC_AMUL_STA_PROH_TMR:
247       {
248          arg.timers = &((RlcUlRbCb *)cb)->m.amUl.staProhTmr;
249          arg.max = RLC_MAX_AM_TMR;
250          break;
251       } 
252       case EVENT_RLC_AMDL_POLL_RETX_TMR:
253       {
254          arg.timers = &((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr;
255          arg.max = RLC_MAX_AM_TMR;
256          break;
257       } 
258       case EVENT_RLC_WAIT_BNDCFM:
259       {
260          arg.timers = &((RlcRguSapCb *)cb)->bndTmr;
261          arg.max = RLC_MAX_RGUSAP_TMR;
262          break;
263       }
264 /* kw005.201 added support for L2 Measurement */
265 #ifdef LTE_L2_MEAS
266       case EVENT_RLC_L2_TMR:
267       {
268          measEvtCb = (RlcL2MeasEvtCb *)cb;
269          arg.timers   = &measEvtCb->l2Tmr;
270          arg.max  = RLC_L2_MAX_TIMERS;
271          break;
272       }
273 #endif
274       case EVENT_RLC_THROUGHPUT_TMR:
275       {
276          arg.timers   = &((RlcThpt *)cb)->thptTmr;
277          arg.max  = RLC_MAX_THPT_TMR;
278       }
279       default:
280       {
281          DU_LOG("\nERROR  -->  RLC : rlcStopTmr: Invalid tmr Evnt[%d]", tmrType);
282       }
283    } 
284    if (tmrType != TMR0)
285    {
286       arg.tqCp   = &gCb->rlcTqCp;
287       arg.tq     = gCb->rlcTq;
288       arg.cb     = cb;
289       arg.evnt   = tmrType;
290       arg.wait   = 0;
291       arg.tNum   = 0;
292       cmRmvCbTq(&arg);
293    }
294    
295    return;
296 }
297
298 /**
299  * @brief Handler to invoke events on expiry of timer.
300  *
301  * @details
302  *    This function is used to handle expiry of timer,it invokes relevant 
303  *    functions.
304  *       
305  * @param[in] cb        Control block depending on the type of the timer event. 
306  *                      It can be uplink/downlink rbCb or rgu sap control block
307  * @param[in] tmrEvnt   Timer event to be started
308  *
309  * @return  Void
310 */
311 Void rlcTmrExpiry(PTR cb,S16 tmrEvnt)
312 {
313 /* kw005.201 added support for L2 Measurement */
314
315    switch (tmrEvnt)
316    {
317       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
318       {
319          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
320          rlcUmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
321
322          break;
323       }
324       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
325       {
326          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
327          rlcAmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
328          break;
329       }
330       case EVENT_RLC_AMUL_STA_PROH_TMR:
331       {
332          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
333          rlcAmmStaProTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
334
335          break;
336       }
337       case EVENT_RLC_AMDL_POLL_RETX_TMR:
338       {
339          RlcDlRbCb *dlRbCb = (RlcDlRbCb *)cb;
340          RlcCb *gCb = RLC_GET_RLCCB(dlRbCb->inst);
341          
342          rlcAmmPollRetxTmrExp(gCb, dlRbCb);
343
344          gCb->genSts.protTimeOut++;
345          break;
346       }
347       case EVENT_RLC_WAIT_BNDCFM:
348       {
349          rlcBndTmrExpiry(cb);
350          break;
351       }
352       case EVENT_RLC_THROUGHPUT_TMR:
353       {
354          rlcThptTmrExpiry(cb);
355          break;
356       }
357       default:
358       {
359          break;
360       }
361    }
362
363    return;
364 }
365
366 /**
367  * @brief Handler to check if the timer is running
368  *       
369  * @param[in] gCb       Pointer to the RLC instance control block
370  * @param[in] cb        Control block depending on the type of the timer event. 
371  *                      It can be uplink/downlink rbCb or rgu sap control block
372  * @param[in] tmrEvnt   Timer event to be started
373  *
374  * @return  Bool indicating whether the timer is running or not
375  *      -# ROK 
376  *      -# RFAILED 
377 */
378 bool rlcChkTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
379 {
380    switch (tmrEvnt)
381    {
382       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
383       {
384          return (((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr.tmrEvnt == 
385                   EVENT_RLC_UMUL_REASSEMBLE_TMR);
386       }
387       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
388       {
389          return (((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr.tmrEvnt == 
390                   EVENT_RLC_AMUL_REASSEMBLE_TMR);
391       }
392       case EVENT_RLC_AMUL_STA_PROH_TMR:
393       {
394          return (((RlcUlRbCb *)cb)->m.amUl.staProhTmr.tmrEvnt == 
395                   EVENT_RLC_AMUL_STA_PROH_TMR);
396       } 
397       case EVENT_RLC_AMDL_POLL_RETX_TMR:
398       {
399          return (((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr.tmrEvnt == 
400                   EVENT_RLC_AMDL_POLL_RETX_TMR);
401       } 
402       case EVENT_RLC_WAIT_BNDCFM:
403       {
404          return (((RlcRguSapCb *)cb)->bndTmr.tmrEvnt == EVENT_RLC_WAIT_BNDCFM);
405       }
406       case EVENT_RLC_THROUGHPUT_TMR:
407       {
408          return (((RlcThpt *)cb)->thptTmr.tmrEvnt == EVENT_RLC_THROUGHPUT_TMR);
409       }
410       default:
411       {
412          DU_LOG("\nERROR  -->  RLC : rlcChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
413       }
414    } 
415
416    return FALSE;
417 }
418
419 /**
420  * @brief Handler to do processing on expiry of the bind timer
421  *
422  * @details
423  *    This function processes the RLC bind timer expiry. If the number of 
424  *    retries is less than the maximum retry counter, bind request is sent 
425  *    again, else an alarm is raised to the layer manager.
426  *       
427  * @param[in] cb  Pointer to the Rgu sap
428  *
429  * @return  Void
430 */
431 static Void rlcBndTmrExpiry(PTR cb)
432 {
433    RlcRguSapCb *rguSapCb; 
434
435    rguSapCb = (RlcRguSapCb *) cb;
436
437    if (rguSapCb->state == RLC_SAP_BINDING)
438    {
439       if (rguSapCb->retryCnt < RLC_MAX_SAP_BND_RETRY)
440       {
441          /* start timer to wait for bind confirm */
442          rlcStartTmr(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
443                     (PTR)rguSapCb, 
444                     EVENT_RLC_WAIT_BNDCFM);
445          
446          /* Send bind request */
447          rguSapCb->retryCnt++;
448          RlcLiRguBndReq (&rguSapCb->pst, rguSapCb->suId, rguSapCb->spId);
449       }
450       else
451       {
452          rguSapCb->retryCnt = 0;
453          rguSapCb->state = RLC_SAP_CFG;
454
455          /* Send alarm to the layer manager */
456 #ifdef LTE_L2_MEAS
457          rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
458                         LCM_CATEGORY_INTERFACE, 
459                         LCM_EVENT_BND_FAIL,
460                         LCM_CAUSE_TMR_EXPIRED, 
461                         0, 
462                         0, 
463                         0);
464 #else
465          rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
466                         LCM_CATEGORY_INTERFACE, 
467                         LCM_EVENT_BND_FAIL,
468                         LCM_CAUSE_TMR_EXPIRED, 
469                         0, /* suId */
470                         0 /* ueId */);
471 #endif
472       }
473    }
474
475    return;
476 }
477
478 /**
479  * @brief Handler to do processing on expiry of the throughput timer
480  *
481  * @details
482  *    This function processes the RLC throughput timer expiry.
483  *
484  * @param[in] cb  Pointer to the RLC throughput struct
485  *
486  * @return  Void
487  */
488 void rlcThptTmrExpiry(PTR cb)
489 {
490    uint16_t  ueIdx;
491    long double tpt;
492    RlcThpt *rlcThptCb = (RlcThpt*)cb; 
493
494    /* Print throughput */
495    DU_LOG("\n===================== DL Throughput ==============================");
496    DU_LOG("\nNumber of UEs : %d", rlcThptCb->numActvUe);
497    for(ueIdx = 0; ueIdx < rlcThptCb->numActvUe; ueIdx++)
498    {
499       /* Spec 28.552, section 5.1.1.3 : 
500        * Throughput in kilobits/sec = (dataVol in kiloBits * 1000)/time in milligseconds
501        * 
502        * Since our dataVol is in bytes, multiplying 0.008 to covert into kilobits i.e. 
503        * Throughput[kbits/sec] = (dataVol * 0.008 * 1000)/time in ms
504        */
505       tpt = (double)(rlcThptCb->thptPerUe[ueIdx].dataVol * 8)/(double)ODU_THROUGHPUT_PRINT_TIME_INTERVAL;
506       
507       DU_LOG("\nUE Id : %d   DL Tpt : %.2Lf", rlcThptCb->thptPerUe[ueIdx].ueIdx, tpt);
508       rlcThptCb->thptPerUe[ueIdx].dataVol = 0;
509    }
510    DU_LOG("\n==================================================================");
511
512    /* Restart timer */
513    rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_THROUGHPUT_TMR);
514
515    return;
516 }
517
518 \f  
519 /********************************************************************30**
520   
521          End of file
522 **********************************************************************/