* INTC Contribution to the O-RAN F Release for O-DU Low
[o-du/phy.git] / fhi_lib / lib / src / xran_cb_proc.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2020 Intel.
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  * @brief XRAN Callback processing functionality and helper functions
21  * @file xran_cb_proc.c
22  * @ingroup group_source_xran
23  * @author Intel Corporation
24  **/
25
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <immintrin.h>
29 #include <rte_common.h>
30 #include <rte_eal.h>
31 #include <rte_errno.h>
32 #include <rte_lcore.h>
33 #include <rte_cycles.h>
34 #include <rte_memory.h>
35 #include <rte_memzone.h>
36 #include <rte_mbuf.h>
37 #include <rte_timer.h>
38
39 #include "ethdi.h"
40 #include "xran_fh_o_du.h"
41 #include "xran_main.h"
42 #include "xran_dev.h"
43 #include "xran_common.h"
44 #include "xran_cb_proc.h"
45 #include "xran_mlog_lnx.h"
46 #include "xran_lib_mlog_tasks_id.h"
47 #include "xran_printf.h"
48
49 typedef void (*rx_dpdk_sym_cb_fn)(struct rte_timer *tim, void *arg);
50
51 void xran_timer_arm(struct rte_timer *tim, void* arg, void *p_dev_ctx)
52 {
53     struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
54     uint64_t t3 = MLogXRANTick();
55
56     if (xran_if_current_state == XRAN_RUNNING){
57         rte_timer_cb_t fct = (rte_timer_cb_t)arg;
58         rte_timer_reset_sync(tim, 0, SINGLE, p_xran_dev_ctx->fh_init.io_cfg.timing_core, fct, p_dev_ctx);
59     }
60     MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
61 }
62
63 void xran_timer_arm_cp_dl(struct rte_timer *tim, void* arg, void *p_dev_ctx)
64 {
65     struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
66     uint64_t t3 = MLogXRANTick();
67
68     unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_CP_DL, p_xran_dev_ctx);
69
70     if (xran_if_current_state == XRAN_RUNNING){
71         rte_timer_cb_t fct = (rte_timer_cb_t)arg;
72         rte_timer_reset_sync(tim, 0, SINGLE, tim_lcore, fct, p_dev_ctx);
73     }
74     MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
75 }
76
77 void xran_timer_arm_cp_ul(struct rte_timer *tim, void* arg, void *p_dev_ctx)
78 {
79     struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
80     uint64_t t3 = MLogXRANTick();
81
82     unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_CP_UL, p_xran_dev_ctx);
83
84     if (xran_if_current_state == XRAN_RUNNING){
85         rte_timer_cb_t fct = (rte_timer_cb_t)arg;
86         rte_timer_reset_sync(tim, 0, SINGLE, tim_lcore, fct, p_dev_ctx);
87     }
88     MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
89 }
90
91 void xran_timer_arm_for_deadline(struct rte_timer *tim, void* arg,  void *p_dev_ctx)
92 {
93     struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
94     uint64_t t3 = MLogXRANTick();
95
96     unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_DEADLINE, p_xran_dev_ctx);
97
98     int32_t rx_tti;
99     uint32_t nFrameIdx;
100     uint32_t nSubframeIdx;
101     uint32_t nSlotIdx;
102     uint64_t nSecond;
103
104     xran_get_slot_idx(p_xran_dev_ctx->xran_port_id, &nFrameIdx, &nSubframeIdx, &nSlotIdx, &nSecond);
105     rx_tti = nFrameIdx*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)
106            + nSubframeIdx*SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)
107            + nSlotIdx;
108
109     p_xran_dev_ctx->cb_timer_ctx[p_xran_dev_ctx->timer_put %  MAX_CB_TIMER_CTX].tti_to_process = rx_tti;
110     if (xran_if_current_state == XRAN_RUNNING){
111         rte_timer_cb_t fct = (rte_timer_cb_t)arg;
112         rte_timer_reset_sync(tim, 0, SINGLE, tim_lcore, fct, p_xran_dev_ctx);
113     }
114
115     MLogXRANTask(PID_TIME_ARM_TIMER_DEADLINE, t3, MLogXRANTick());
116 }
117
118 void xran_timer_arm_user_cb(struct rte_timer *tim, void* arg,  void *p_ctx)
119 {
120     struct cb_user_per_sym_ctx* p_sym_cb_ctx = (struct cb_user_per_sym_ctx *)p_ctx;
121     struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_sym_cb_ctx->p_dev;
122     uint64_t t3 = MLogXRANTick();
123
124     unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_SYM_CB, NULL);
125
126     int32_t rx_tti;
127     uint32_t nFrameIdx = 0;
128     uint32_t nSubframeIdx = 0;
129     uint32_t nSlotIdx = 0;
130     uint64_t nSecond = 0;
131
132     xran_get_slot_idx(p_xran_dev_ctx->xran_port_id, &nFrameIdx, &nSubframeIdx, &nSlotIdx, &nSecond);
133     rx_tti = nFrameIdx*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)
134            + nSubframeIdx*SLOTNUM_PER_SUBFRAME(p_xran_dev_ctx->interval_us_local)
135            + nSlotIdx;
136
137     p_sym_cb_ctx->user_cb_timer_ctx[p_sym_cb_ctx->user_timer_put % MAX_CB_TIMER_CTX].tti_to_process = rx_tti;
138     p_sym_cb_ctx->user_cb_timer_ctx[p_sym_cb_ctx->user_timer_put % MAX_CB_TIMER_CTX].ota_sym_idx = xran_lib_ota_sym_idx[p_xran_dev_ctx->xran_port_id];
139     p_sym_cb_ctx->user_cb_timer_ctx[p_sym_cb_ctx->user_timer_put % MAX_CB_TIMER_CTX].xran_sfn_at_sec_start = xran_getSfnSecStart();
140     p_sym_cb_ctx->user_cb_timer_ctx[p_sym_cb_ctx->user_timer_put % MAX_CB_TIMER_CTX].current_second = nSecond;
141
142     if (xran_if_current_state == XRAN_RUNNING){
143         rte_timer_cb_t fct = (rte_timer_cb_t)arg;
144         rte_timer_reset_sync(tim, 0, SINGLE, tim_lcore, fct, p_sym_cb_ctx);
145         if (++p_sym_cb_ctx->user_timer_put >= MAX_CB_TIMER_CTX)
146             p_sym_cb_ctx->user_timer_put = 0;
147     }
148
149     MLogXRANTask(PID_TIME_ARM_USER_TIMER_DEADLINE, t3, MLogXRANTick());
150 }
151
152 void xran_timer_arm_ex(struct rte_timer *tim, void* CbFct, void *CbArg, unsigned tim_lcore)
153 {
154     uint64_t t3 = MLogXRANTick();
155
156     if (xran_if_current_state == XRAN_RUNNING){
157         rte_timer_cb_t fct = (rte_timer_cb_t)CbFct;
158         rte_timer_reset_sync(tim, 0, SINGLE, tim_lcore, fct, CbArg);
159     }
160     MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
161 }
162
163 int32_t
164 xran_timing_create_cbs(void *args)
165 {
166     //int32_t  res = XRAN_STATUS_SUCCESS;
167     int32_t  j;
168     uint32_t delay_cp_dl_max, delay_cp_dl_min;
169     uint32_t delay_cp_ul;
170     uint32_t delay_up;
171     uint32_t time_diff_us;
172     uint32_t delay_cp2up;
173     uint32_t sym_cp_dl_max, sym_cp_dl_min;
174     uint32_t sym_cp_ul;
175     uint32_t time_diff_nSymb;
176     int32_t  sym_up;
177     struct xran_device_ctx * p_dev_ctx =  (struct xran_device_ctx *)args;
178     struct cb_elem_entry * cb_elm = NULL;
179     uint32_t interval_us_local = p_dev_ctx->interval_us_local;
180
181     /* ToS = Top of Second start +- 1.5us */
182     struct timespec ts;
183     char buff[100];
184
185     if (p_dev_ctx->fh_init.io_cfg.id == O_DU) {
186
187         delay_cp_dl_max = interval_us_local - p_dev_ctx->fh_cfg.T1a_max_cp_dl;
188         delay_cp_dl_min = interval_us_local - p_dev_ctx->fh_cfg.T1a_min_cp_dl;
189         delay_cp_ul = interval_us_local - p_dev_ctx->fh_cfg.T1a_max_cp_ul;
190
191         uint8_t numSlots=0; /* How many slots you need to go backwards from OTA */
192         uint32_t max_dl_delay_offset=interval_us_local; /* Start of the slot in which you will start CP DL */
193         while(p_dev_ctx->fh_cfg.T1a_max_cp_dl > max_dl_delay_offset)
194         {
195             max_dl_delay_offset += interval_us_local;
196             numSlots++;
197         }
198
199         /* Delay from start of 'a' slot */
200         delay_cp_dl_max = max_dl_delay_offset - p_dev_ctx->fh_cfg.T1a_max_cp_dl;
201         /* Symbol on which we will start CP transmission */
202         sym_cp_dl_max = delay_cp_dl_max*1000/(interval_us_local*1000/N_SYM_PER_SLOT)+1;
203         /* Backward offset from OTA in terms of symbols when Cp transmission will start
204          * i.e. cp transmission will start 'max_dl_offset_sym' symbols before OTA
205          */
206         uint8_t max_dl_offset_sym = (numSlots+1)*N_SYM_PER_SLOT - sym_cp_dl_max;
207         /* Handle corner case of symbol-0*/
208         sym_cp_dl_max%=N_SYM_PER_SLOT;
209
210         uint32_t min_dl_delay_offset=interval_us_local;
211         numSlots=0;
212         while(p_dev_ctx->fh_cfg.T1a_min_cp_dl > min_dl_delay_offset)
213         {
214             min_dl_delay_offset += interval_us_local;
215             numSlots++;
216         }
217         delay_cp_dl_min = min_dl_delay_offset - p_dev_ctx->fh_cfg.T1a_min_cp_dl;
218         sym_cp_dl_min = delay_cp_dl_min*1000/(interval_us_local*1000/N_SYM_PER_SLOT) - 1;
219         uint8_t min_dl_offset_sym = (numSlots+1)*N_SYM_PER_SLOT - sym_cp_dl_min;
220         sym_cp_dl_min%=N_SYM_PER_SLOT;
221
222
223         uint32_t ul_delay_offset=interval_us_local;
224         numSlots=0;
225         while(p_dev_ctx->fh_cfg.T1a_max_cp_ul > ul_delay_offset)
226         {
227             ul_delay_offset += interval_us_local;
228             numSlots++;
229         }
230         delay_cp_ul = ul_delay_offset - p_dev_ctx->fh_cfg.T1a_max_cp_ul;
231         sym_cp_ul = (delay_cp_ul*1000/(interval_us_local*1000/N_SYM_PER_SLOT)+1);
232         uint8_t ul_offset_sym = (numSlots+1)*N_SYM_PER_SLOT - sym_cp_ul;
233         sym_cp_ul%=N_SYM_PER_SLOT;
234
235         printf("delay_cp_dl_max=%u, sym_cp_dl_max=%u, max_dl_offset_sym=%u\n"
236                "delay_cp_dl_min=%u, sym_cp_dl_min=%u, min_dl_offset_sym=%u\n"
237                "delay_cp_ul=%u,     sym_cp_ul=%u,     ul_offset_sym=%u\n",
238                 delay_cp_dl_max, sym_cp_dl_max, max_dl_offset_sym,
239                 delay_cp_dl_min, sym_cp_dl_min, min_dl_offset_sym,
240                 delay_cp_ul, sym_cp_ul, ul_offset_sym);
241
242
243         delay_up    = p_dev_ctx->fh_cfg.T1a_max_up;
244         time_diff_us = p_dev_ctx->fh_cfg.Ta4_max;
245
246         delay_cp2up = delay_up-delay_cp_dl_max;
247
248
249         time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
250         p_dev_ctx->sym_up = sym_up = -(delay_up*1000/(interval_us_local*1000/N_SYM_PER_SLOT));
251         p_dev_ctx->sym_up_ul = time_diff_nSymb = (time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT)+1);
252
253         printf("C-plane DL from %d us after TTI  [trigger on sym %d] to %d us after TTI [trigger on sym %d]\n",
254                 delay_cp_dl_max, sym_cp_dl_max, delay_cp_dl_min, sym_cp_dl_min);
255
256         printf("Start C-plane UL %d us after TTI  [trigger on sym %d]\n", delay_cp_ul, sym_cp_ul);
257         printf("Start U-plane DL %d us before OTA [offset  in sym %d]\n", delay_up, sym_up);
258         printf("Start U-plane UL %d us OTA        [offset  in sym %d]\n", time_diff_us, time_diff_nSymb);
259
260         printf("C-plane to U-plane delay %d us after TTI\n", delay_cp2up);
261         printf("Start Sym timer %ld ns\n", TX_TIMER_INTERVAL/N_SYM_PER_SLOT);
262
263         if(1 == p_dev_ctx->fh_init.dlCpProcBurst){
264             p_dev_ctx->numSymsForDlCP = 1;
265         }
266         else{
267             if(max_dl_offset_sym >= min_dl_offset_sym) /* corner case where only 1 symbol is available for transmission */
268                 p_dev_ctx->numSymsForDlCP = max_dl_offset_sym - min_dl_offset_sym + 1;
269             else
270                 p_dev_ctx->numSymsForDlCP = 1;
271
272         }
273
274         int count=0;
275         while (count < p_dev_ctx->numSymsForDlCP)
276         {
277             cb_elm =
278                     xran_create_cb (xran_timer_arm_cp_dl, tx_cp_dl_cb, (void *) p_dev_ctx);
279             if (cb_elm)
280             {
281                 LIST_INSERT_HEAD (&p_dev_ctx->sym_cb_list_head[sym_cp_dl_max],
282                         cb_elm, pointers);
283             }
284             else
285             {
286             print_err("cb_elm is NULL\n");
287                 //res = XRAN_STATUS_FAIL;
288             goto err0;
289         }
290             printf ("created sym cp dl cb for symbol %u\n", sym_cp_dl_max);
291
292             sym_cp_dl_max = (sym_cp_dl_max+1)%N_SYM_PER_SLOT;
293             max_dl_offset_sym--;
294             count++;
295         }
296
297         cb_elm = xran_create_cb(xran_timer_arm_cp_ul, tx_cp_ul_cb, (void*)p_dev_ctx);
298         if(cb_elm){
299             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[sym_cp_ul],
300                              cb_elm,
301                              pointers);
302         } else {
303             print_err("cb_elm is NULL\n");
304             //res =  XRAN_STATUS_FAIL;
305             goto err0;
306         }
307
308         /* Full slot UL OTA + time_diff_us */
309         cb_elm = xran_create_cb(xran_timer_arm_for_deadline, rx_ul_deadline_full_cb, (void*)p_dev_ctx);
310         if(cb_elm){
311             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[time_diff_nSymb % XRAN_NUM_OF_SYMBOL_PER_SLOT],
312                              cb_elm,
313                              pointers);
314         } else {
315             print_err("cb_elm is NULL\n");
316             //res =  XRAN_STATUS_FAIL;
317             goto err0;
318         }
319
320         /* 1/4 UL OTA + time_diff_us*/
321         cb_elm = xran_create_cb(xran_timer_arm_for_deadline, rx_ul_deadline_one_fourths_cb, (void*)p_dev_ctx);
322         if(cb_elm){
323             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[(time_diff_nSymb + 1*(N_SYM_PER_SLOT/4)) % XRAN_NUM_OF_SYMBOL_PER_SLOT],
324                          cb_elm,
325                          pointers);
326         } else {
327             print_err("cb_elm is NULL\n");
328             //res =  XRAN_STATUS_FAIL;
329             goto err0;
330         }
331
332         /* Half slot UL OTA + time_diff_us*/
333         cb_elm = xran_create_cb(xran_timer_arm_for_deadline, rx_ul_deadline_half_cb, (void*)p_dev_ctx);
334         if(cb_elm){
335             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[(time_diff_nSymb + N_SYM_PER_SLOT/2) % XRAN_NUM_OF_SYMBOL_PER_SLOT],
336                          cb_elm,
337                          pointers);
338         } else {
339             print_err("cb_elm is NULL\n");
340             //res =  XRAN_STATUS_FAIL;
341             goto err0;
342         }
343
344         /* 3/4 UL OTA + time_diff_us*/
345         cb_elm = xran_create_cb(xran_timer_arm_for_deadline, rx_ul_deadline_three_fourths_cb, (void*)p_dev_ctx);
346         if(cb_elm){
347             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[(time_diff_nSymb + 4*(N_SYM_PER_SLOT/4)) % XRAN_NUM_OF_SYMBOL_PER_SLOT],
348                          cb_elm,
349                          pointers);
350         } else {
351             print_err("cb_elm is NULL\n");
352             //res =  XRAN_STATUS_FAIL;
353             goto err0;
354         }
355     } else {    // APP_O_RU
356         /* calculate when to send UL U-plane */
357         delay_up = p_dev_ctx->fh_cfg.Ta3_min;
358         p_dev_ctx->sym_up = sym_up = delay_up*1000/(interval_us_local*1000/N_SYM_PER_SLOT)+1;
359         printf("Start UL U-plane %d us after OTA [offset in sym %d]\n", delay_up, sym_up);
360
361         /* calculate when to Receive DL U-plane */
362         delay_up = p_dev_ctx->fh_cfg.T2a_max_up;
363         sym_up = delay_up*1000/(interval_us_local*1000/N_SYM_PER_SLOT)+1;
364         printf("Receive DL U-plane %d us after OTA [offset in sym %d]\n", delay_up, sym_up);
365
366         /* Full slot UL OTA + time_diff_us */
367         cb_elm = xran_create_cb(xran_timer_arm_for_deadline, rx_ul_deadline_full_cb, (void*)p_dev_ctx);
368         if(cb_elm){
369             LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[sym_up % XRAN_NUM_OF_SYMBOL_PER_SLOT],
370                              cb_elm,
371                              pointers);
372         } else {
373             print_err("cb_elm is NULL\n");
374             //res =  -1;
375             goto err0;
376         }
377
378         do {
379            timespec_get(&ts, TIME_UTC);
380         }while (ts.tv_nsec >1500);
381         struct tm * ptm = gmtime(&ts.tv_sec);
382         if(ptm){
383             strftime(buff, sizeof buff, "%D %T", ptm);
384             printf("RU: thread_run start time: %s.%09ld UTC [%d]\n", buff, ts.tv_nsec, interval_us_local);
385         }
386     }
387
388     return XRAN_STATUS_SUCCESS;
389
390     err0:
391     for (j = 0; j< XRAN_NUM_OF_SYMBOL_PER_SLOT; j++){
392         struct cb_elem_entry *cb_elm;
393         LIST_FOREACH(cb_elm, &p_dev_ctx->sym_cb_list_head[j], pointers){
394             if(cb_elm){
395                 LIST_REMOVE(cb_elm, pointers);
396                 xran_destroy_cb(cb_elm);
397             }
398         }
399     }
400
401     return XRAN_STATUS_FAIL;
402 }
403 int32_t
404 xran_timing_destroy_cbs(void *args)
405 {
406     //int res = XRAN_STATUS_SUCCESS;
407     int32_t j;
408     struct xran_device_ctx * p_dev_ctx = (struct xran_device_ctx *)args;
409
410     for (j = 0; j< XRAN_NUM_OF_SYMBOL_PER_SLOT; j++){
411         struct cb_elem_entry *cb_elm;
412         LIST_FOREACH(cb_elm, &p_dev_ctx->sym_cb_list_head[j], pointers){
413             if(cb_elm){
414                 LIST_REMOVE(cb_elm, pointers);
415                 xran_destroy_cb(cb_elm);
416             }
417         }
418     }
419
420     return XRAN_STATUS_SUCCESS;
421 }
422
423 static int32_t
424 xran_reg_sym_cb_ota(struct xran_device_ctx * p_dev_ctx, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime,  uint8_t symb,
425     struct cb_user_per_sym_ctx **p_sym_cb_ctx)
426 {
427     int32_t ret = XRAN_STATUS_SUCCESS;
428     struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_OTA_TIME];
429     if(p_loc_sym_cb_ctx->status){
430         ret =  XRAN_STATUS_RESOURCE;
431         print_err("timer sym %d type id %d was already created",symb, XRAN_CB_SYM_OTA_TIME);
432         return ret;
433     }
434     printf("requested symb %d OTA coresponds to symb %d OTA time\n", symb, symb);
435
436     p_loc_sym_cb_ctx->symb_num_req  = symb;
437     p_loc_sym_cb_ctx->sym_diff      = 0; /* OTA and Request Symb are the same */
438     p_loc_sym_cb_ctx->symb_num_ota  = symb;
439     p_loc_sym_cb_ctx->cb_type_id    = XRAN_CB_SYM_OTA_TIME;
440     p_loc_sym_cb_ctx->p_dev         = p_dev_ctx;
441
442     p_loc_sym_cb_ctx->symCb         = symCb;
443     p_loc_sym_cb_ctx->symCbParam    = symCbParam;
444     p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
445
446     p_loc_sym_cb_ctx->status        = 1;
447
448     *p_sym_cb_ctx = p_loc_sym_cb_ctx;
449
450     return ret;
451 }
452
453 static int32_t
454 xran_reg_sym_cb_rx_win_end(struct xran_device_ctx * p_dev_ctx, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime,
455     uint8_t symb, struct cb_user_per_sym_ctx **p_sym_cb_ctx)
456 {
457     int32_t ret = XRAN_STATUS_SUCCESS;
458     struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_RX_WIN_END];
459     uint32_t time_diff_us      = 0;
460     uint32_t time_diff_nSymb   = 0;
461     uint32_t absolute_ota_sym  = 0;
462     uint32_t interval_us_local = p_dev_ctx->interval_us_local;
463
464     if(p_loc_sym_cb_ctx->status) {
465         ret =  XRAN_STATUS_RESOURCE;
466         print_err("timer sym %d type id %d was already created",symb, XRAN_CB_SYM_RX_WIN_END);
467         return ret;
468     }
469
470     time_diff_us = p_dev_ctx->fh_cfg.Ta4_max;
471     printf("RX WIN end Ta4_max is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
472     time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
473     if ((time_diff_nSymb/1000/(interval_us_local*1000/N_SYM_PER_SLOT)) < time_diff_us) {
474         time_diff_nSymb+=1;
475         printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
476     }
477     printf("U-plane UL delay %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, time_diff_nSymb);
478     absolute_ota_sym =  (symb + time_diff_nSymb) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
479     printf("requested symb %d pkt arrival time [deadline] coresponds to symb %d OTA time\n", symb, absolute_ota_sym);
480
481     p_loc_sym_cb_ctx->symb_num_req  = symb;
482     p_loc_sym_cb_ctx->sym_diff      = -time_diff_nSymb;
483     p_loc_sym_cb_ctx->symb_num_ota  = absolute_ota_sym;
484     p_loc_sym_cb_ctx->cb_type_id    = XRAN_CB_SYM_RX_WIN_END;
485     p_loc_sym_cb_ctx->p_dev         = p_dev_ctx;
486
487     p_loc_sym_cb_ctx->symCb         = symCb;
488     p_loc_sym_cb_ctx->symCbParam    = symCbParam;
489     p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
490
491     p_loc_sym_cb_ctx->status        = 1;
492
493     *p_sym_cb_ctx  =p_loc_sym_cb_ctx;
494
495     return ret;
496 }
497
498 static int32_t
499 xran_reg_sym_cb_rx_win_begin(struct xran_device_ctx * p_dev_ctx, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime,
500     uint8_t symb, struct cb_user_per_sym_ctx **p_sym_cb_ctx)
501 {
502     int32_t ret = XRAN_STATUS_SUCCESS;
503     struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_RX_WIN_BEGIN];
504     uint32_t time_diff_us      = 0;
505     uint32_t time_diff_nSymb   = 0;
506     uint32_t absolute_ota_sym  = 0;
507     uint32_t interval_us_local = p_dev_ctx->interval_us_local;
508
509     if(p_loc_sym_cb_ctx->status) {
510         ret =  XRAN_STATUS_RESOURCE;
511         print_err("timer sym %d type id %d was already created",symb, XRAN_CB_SYM_RX_WIN_BEGIN);
512         return ret;
513     }
514
515     time_diff_us = p_dev_ctx->fh_cfg.Ta4_min;
516     printf("RX WIN begin Ta4_min is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
517     time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
518     printf("U-plane UL delay %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, time_diff_nSymb);
519     absolute_ota_sym =  (symb + time_diff_nSymb) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
520     printf("requested symb %d pkt arrival time [deadline] coresponds to symb %d OTA time\n", symb, absolute_ota_sym);
521
522     p_loc_sym_cb_ctx->symb_num_req  = symb;
523     p_loc_sym_cb_ctx->sym_diff      = -time_diff_nSymb;
524     p_loc_sym_cb_ctx->symb_num_ota  = absolute_ota_sym;
525     p_loc_sym_cb_ctx->cb_type_id    = XRAN_CB_SYM_RX_WIN_BEGIN;
526     p_loc_sym_cb_ctx->p_dev         = p_dev_ctx;
527
528     p_loc_sym_cb_ctx->symCb         = symCb;
529     p_loc_sym_cb_ctx->symCbParam    = symCbParam;
530     p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
531
532     p_loc_sym_cb_ctx->status        = 1;
533
534     *p_sym_cb_ctx  =p_loc_sym_cb_ctx;
535
536     return ret;
537 }
538
539 static int32_t
540 xran_reg_sym_cb_tx_win_end(struct xran_device_ctx * p_dev_ctx, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime,
541     uint8_t symb, struct cb_user_per_sym_ctx **p_sym_cb_ctx)
542 {
543     int32_t ret = XRAN_STATUS_SUCCESS;
544     struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_TX_WIN_END];
545     uint32_t time_diff_us      = 0;
546     uint32_t time_diff_nSymb   = 0;
547     uint32_t absolute_ota_sym  = 0;
548     uint32_t interval_us_local = p_dev_ctx->interval_us_local;
549
550     if(p_loc_sym_cb_ctx->status) {
551         ret =  XRAN_STATUS_RESOURCE;
552         print_err("timer sym %d type id %d was already created",symb, XRAN_CB_SYM_TX_WIN_END);
553         return ret;
554     }
555
556     time_diff_us = p_dev_ctx->fh_cfg.T1a_min_up;
557     printf("TX WIN end -T1a_min_up is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
558     time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
559     if ((time_diff_nSymb/1000/(interval_us_local*1000/N_SYM_PER_SLOT)) < time_diff_us) {
560         time_diff_nSymb +=1;
561         printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
562     }
563     printf("U-plane DL advance is %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, -time_diff_nSymb);
564     absolute_ota_sym =  ((symb + XRAN_NUM_OF_SYMBOL_PER_SLOT) - time_diff_nSymb) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
565     printf("requested symb %d pkt tx time [deadline] corresponds to symb %d OTA time\n", symb, absolute_ota_sym);
566
567     p_loc_sym_cb_ctx->symb_num_req  = symb;
568     p_loc_sym_cb_ctx->sym_diff      = time_diff_nSymb;
569     p_loc_sym_cb_ctx->symb_num_ota  = absolute_ota_sym;
570     p_loc_sym_cb_ctx->cb_type_id    = XRAN_CB_SYM_TX_WIN_END;
571     p_loc_sym_cb_ctx->p_dev         = p_dev_ctx;
572
573     p_loc_sym_cb_ctx->symCb         = symCb;
574     p_loc_sym_cb_ctx->symCbParam    = symCbParam;
575     p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
576
577     p_loc_sym_cb_ctx->status        = 1;
578
579     *p_sym_cb_ctx  = p_loc_sym_cb_ctx;
580
581     return ret;
582 }
583
584 static int32_t
585 xran_reg_sym_cb_tx_win_begin(struct xran_device_ctx * p_dev_ctx, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime,
586      uint8_t symb, struct cb_user_per_sym_ctx **p_sym_cb_ctx)
587 {
588     int32_t ret = XRAN_STATUS_SUCCESS;
589     struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_TX_WIN_BEGIN];
590     uint32_t time_diff_us      = 0;
591     uint32_t time_diff_nSymb   = 0;
592     uint32_t absolute_ota_sym  = 0;
593     uint32_t interval_us_local = p_dev_ctx->interval_us_local;
594
595     if(p_loc_sym_cb_ctx->status) {
596         ret =  XRAN_STATUS_RESOURCE;
597         print_err("timer sym %d type id %d was already created",symb, XRAN_CB_SYM_TX_WIN_BEGIN);
598         return ret;
599     }
600
601     time_diff_us = p_dev_ctx->fh_cfg.T1a_max_up;
602     printf("TX WIN begin -T1a_max_up is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
603     time_diff_nSymb = (time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT));
604     if ((time_diff_nSymb/1000/(interval_us_local*1000/N_SYM_PER_SLOT)) < time_diff_us) {
605         time_diff_nSymb +=1;
606         printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
607     }
608     printf("U-plane DL advance is %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, -time_diff_nSymb);
609     printf("requested symb %d pkt tx time [deadline] corresponds to symb %d OTA time\n", symb, absolute_ota_sym);
610     absolute_ota_sym =  ((symb + XRAN_NUM_OF_SYMBOL_PER_SLOT) - time_diff_nSymb) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
611
612     p_loc_sym_cb_ctx->symb_num_req  = symb;
613     p_loc_sym_cb_ctx->sym_diff      = time_diff_nSymb;
614     p_loc_sym_cb_ctx->symb_num_ota  = absolute_ota_sym;
615     p_loc_sym_cb_ctx->cb_type_id    = XRAN_CB_SYM_TX_WIN_BEGIN;
616     p_loc_sym_cb_ctx->p_dev         = p_dev_ctx;
617
618     p_loc_sym_cb_ctx->symCb         = symCb;
619     p_loc_sym_cb_ctx->symCbParam    = symCbParam;
620     p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
621
622     p_loc_sym_cb_ctx->status        = 1;
623
624     *p_sym_cb_ctx  =p_loc_sym_cb_ctx;
625
626     return ret;
627 }
628
629 int32_t
630 xran_reg_sym_cb(void *pHandle, xran_callback_sym_fn symCb, void * symCbParam, struct xran_sense_of_time* symCbTime, uint8_t symb, enum cb_per_sym_type_id cb_sym_t_id)
631 {
632     int32_t ret = XRAN_STATUS_SUCCESS;
633     struct xran_device_ctx * p_dev_ctx       = NULL;
634     struct cb_elem_entry * cb_elm            = NULL;
635     struct cb_user_per_sym_ctx *p_sym_cb_ctx = NULL;
636     rx_dpdk_sym_cb_fn dpdk_cb_to_arm         = NULL;
637
638     if(xran_get_if_state() == XRAN_RUNNING) {
639         print_err("Cannot register callback while running!!");
640         return (-1);
641     }
642
643     if(pHandle) {
644         p_dev_ctx = (struct xran_device_ctx *)pHandle;
645     } else {
646         print_err("pHandle==NULL");
647         ret = XRAN_STATUS_INVALID_PARAM;
648         return ret;
649     }
650
651     switch (cb_sym_t_id) {
652         case XRAN_CB_SYM_OTA_TIME:
653             ret = xran_reg_sym_cb_ota(p_dev_ctx, symCb, symCbParam, symCbTime, symb, &p_sym_cb_ctx);
654             if(ret != XRAN_STATUS_SUCCESS)
655                 return ret;
656             dpdk_cb_to_arm = rx_ul_user_sym_cb;
657         break;
658         case XRAN_CB_SYM_RX_WIN_BEGIN:
659             ret = xran_reg_sym_cb_rx_win_begin(p_dev_ctx, symCb, symCbParam, symCbTime, symb, &p_sym_cb_ctx);
660             if(ret != XRAN_STATUS_SUCCESS)
661                 return ret;
662             dpdk_cb_to_arm = rx_ul_user_sym_cb;
663             break;
664         case XRAN_CB_SYM_RX_WIN_END:
665             ret = xran_reg_sym_cb_rx_win_end(p_dev_ctx, symCb, symCbParam, symCbTime, symb, &p_sym_cb_ctx);
666             if(ret != XRAN_STATUS_SUCCESS)
667                 return ret;
668             dpdk_cb_to_arm = rx_ul_user_sym_cb;
669         break;
670         case XRAN_CB_SYM_TX_WIN_BEGIN:
671             ret = xran_reg_sym_cb_tx_win_begin(p_dev_ctx, symCb, symCbParam, symCbTime, symb, &p_sym_cb_ctx);
672             if(ret != XRAN_STATUS_SUCCESS)
673                 return ret;
674             dpdk_cb_to_arm = rx_ul_user_sym_cb;
675             break;
676         case XRAN_CB_SYM_TX_WIN_END:
677             ret = xran_reg_sym_cb_tx_win_end(p_dev_ctx, symCb, symCbParam, symCbTime, symb, &p_sym_cb_ctx);
678             if(ret != XRAN_STATUS_SUCCESS)
679                 return ret;
680             dpdk_cb_to_arm = rx_ul_user_sym_cb;
681         break;
682         default:
683             /* functionality is not yet implemented */
684             print_err("Functionality is not yet implemented !");
685             ret = XRAN_STATUS_INVALID_PARAM;
686             return ret;
687     }
688
689     cb_elm = xran_create_cb(xran_timer_arm_user_cb, dpdk_cb_to_arm, (void*)p_sym_cb_ctx);
690     if(cb_elm){
691         LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[p_sym_cb_ctx->symb_num_ota],
692                             cb_elm,
693                             pointers);
694     } else {
695         print_err("cb_elm is NULL\n");
696         ret =  XRAN_STATUS_FAIL;
697         return ret;
698     }
699
700     return ret;
701 }
702
703 int32_t
704 xran_reg_physide_cb(void *pHandle, xran_fh_tti_callback_fn Cb, void *cbParam, int skipTtiNum, enum callback_to_phy_id id)
705 {
706     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
707
708     if(xran_get_if_state() == XRAN_RUNNING) {
709         print_err("Cannot register callback while running!!\n");
710         return (-1);
711     }
712
713     p_xran_dev_ctx->ttiCb[id]      = Cb;
714     p_xran_dev_ctx->TtiCbParam[id] = cbParam;
715     p_xran_dev_ctx->SkipTti[id]    = skipTtiNum;
716
717     return 0;
718 }
719
720 int32_t
721 xran_reg_physide_cb_by_dev_id(void *pHandle, xran_fh_tti_callback_fn Cb, void *cbParam, int skipTtiNum, enum callback_to_phy_id id, uint8_t xran_port_id)
722 {
723     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx_by_id(xran_port_id);
724     if (!p_xran_dev_ctx)
725     {
726         print_err("Null xRAN context on port id %u!!\n", xran_port_id);
727         return -1;
728     }
729
730     if(xran_get_if_state() == XRAN_RUNNING) {
731         print_err("Cannot register callback while running!!\n");
732         return (-1);
733     }
734
735     p_xran_dev_ctx->ttiCb[id]      = Cb;
736     p_xran_dev_ctx->TtiCbParam[id] = cbParam;
737     p_xran_dev_ctx->SkipTti[id]    = skipTtiNum;
738
739     return 0;
740 }
741
742