1 /******************************************************************************
3 * Copyright (c) 2020 Intel.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 *******************************************************************************/
20 * @brief XRAN Callback processing functionality and helper functions
21 * @file xran_cb_proc.c
22 * @ingroup group_source_xran
23 * @author Intel Corporation
28 #include <immintrin.h>
29 #include <rte_common.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>
37 #include <rte_timer.h>
40 #include "xran_fh_o_du.h"
41 #include "xran_main.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"
49 typedef void (*rx_dpdk_sym_cb_fn)(struct rte_timer *tim, void *arg);
51 void xran_timer_arm(struct rte_timer *tim, void* arg, void *p_dev_ctx)
53 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
54 uint64_t t3 = MLogXRANTick();
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);
60 MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
63 void xran_timer_arm_cp_dl(struct rte_timer *tim, void* arg, void *p_dev_ctx)
65 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
66 uint64_t t3 = MLogXRANTick();
68 unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_CP_DL, p_xran_dev_ctx);
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);
74 MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
77 void xran_timer_arm_cp_ul(struct rte_timer *tim, void* arg, void *p_dev_ctx)
79 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
80 uint64_t t3 = MLogXRANTick();
82 unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_CP_UL, p_xran_dev_ctx);
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);
88 MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
91 void xran_timer_arm_for_deadline(struct rte_timer *tim, void* arg, void *p_dev_ctx)
93 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)p_dev_ctx;
94 uint64_t t3 = MLogXRANTick();
96 unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_DEADLINE, p_xran_dev_ctx);
100 uint32_t nSubframeIdx;
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)
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);
115 MLogXRANTask(PID_TIME_ARM_TIMER_DEADLINE, t3, MLogXRANTick());
118 void xran_timer_arm_user_cb(struct rte_timer *tim, void* arg, void *p_ctx)
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();
124 unsigned tim_lcore = xran_schedule_to_worker(XRAN_JOB_TYPE_SYM_CB, NULL);
127 uint32_t nFrameIdx = 0;
128 uint32_t nSubframeIdx = 0;
129 uint32_t nSlotIdx = 0;
130 uint64_t nSecond = 0;
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)
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;
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;
149 MLogXRANTask(PID_TIME_ARM_USER_TIMER_DEADLINE, t3, MLogXRANTick());
152 void xran_timer_arm_ex(struct rte_timer *tim, void* CbFct, void *CbArg, unsigned tim_lcore)
154 uint64_t t3 = MLogXRANTick();
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);
160 MLogXRANTask(PID_TIME_ARM_TIMER, t3, MLogXRANTick());
164 xran_timing_create_cbs(void *args)
166 //int32_t res = XRAN_STATUS_SUCCESS;
168 uint32_t delay_cp_dl_max, delay_cp_dl_min;
169 uint32_t delay_cp_ul;
171 uint32_t time_diff_us;
172 uint32_t delay_cp2up;
173 uint32_t sym_cp_dl_max, sym_cp_dl_min;
175 uint32_t time_diff_nSymb;
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;
181 /* ToS = Top of Second start +- 1.5us */
185 if (p_dev_ctx->fh_init.io_cfg.id == O_DU) {
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;
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)
195 max_dl_delay_offset += interval_us_local;
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
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;
210 uint32_t min_dl_delay_offset=interval_us_local;
212 while(p_dev_ctx->fh_cfg.T1a_min_cp_dl > min_dl_delay_offset)
214 min_dl_delay_offset += interval_us_local;
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;
223 uint32_t ul_delay_offset=interval_us_local;
225 while(p_dev_ctx->fh_cfg.T1a_max_cp_ul > ul_delay_offset)
227 ul_delay_offset += interval_us_local;
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;
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);
243 delay_up = p_dev_ctx->fh_cfg.T1a_max_up;
244 time_diff_us = p_dev_ctx->fh_cfg.Ta4_max;
246 delay_cp2up = delay_up-delay_cp_dl_max;
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);
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);
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);
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);
263 if(1 == p_dev_ctx->fh_init.dlCpProcBurst){
264 p_dev_ctx->numSymsForDlCP = 1;
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;
270 p_dev_ctx->numSymsForDlCP = 1;
275 while (count < p_dev_ctx->numSymsForDlCP)
278 xran_create_cb (xran_timer_arm_cp_dl, tx_cp_dl_cb, (void *) p_dev_ctx);
281 LIST_INSERT_HEAD (&p_dev_ctx->sym_cb_list_head[sym_cp_dl_max],
286 print_err("cb_elm is NULL\n");
287 //res = XRAN_STATUS_FAIL;
290 printf ("created sym cp dl cb for symbol %u\n", sym_cp_dl_max);
292 sym_cp_dl_max = (sym_cp_dl_max+1)%N_SYM_PER_SLOT;
297 cb_elm = xran_create_cb(xran_timer_arm_cp_ul, tx_cp_ul_cb, (void*)p_dev_ctx);
299 LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[sym_cp_ul],
303 print_err("cb_elm is NULL\n");
304 //res = XRAN_STATUS_FAIL;
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);
311 LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[time_diff_nSymb % XRAN_NUM_OF_SYMBOL_PER_SLOT],
315 print_err("cb_elm is NULL\n");
316 //res = XRAN_STATUS_FAIL;
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);
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],
327 print_err("cb_elm is NULL\n");
328 //res = XRAN_STATUS_FAIL;
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);
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],
339 print_err("cb_elm is NULL\n");
340 //res = XRAN_STATUS_FAIL;
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);
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],
351 print_err("cb_elm is NULL\n");
352 //res = XRAN_STATUS_FAIL;
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);
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);
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);
369 LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[sym_up % XRAN_NUM_OF_SYMBOL_PER_SLOT],
373 print_err("cb_elm is NULL\n");
379 timespec_get(&ts, TIME_UTC);
380 }while (ts.tv_nsec >1500);
381 struct tm * ptm = gmtime(&ts.tv_sec);
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);
388 return XRAN_STATUS_SUCCESS;
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){
395 LIST_REMOVE(cb_elm, pointers);
396 xran_destroy_cb(cb_elm);
401 return XRAN_STATUS_FAIL;
404 xran_timing_destroy_cbs(void *args)
406 //int res = XRAN_STATUS_SUCCESS;
408 struct xran_device_ctx * p_dev_ctx = (struct xran_device_ctx *)args;
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){
414 LIST_REMOVE(cb_elm, pointers);
415 xran_destroy_cb(cb_elm);
420 return XRAN_STATUS_SUCCESS;
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)
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);
434 printf("requested symb %d OTA coresponds to symb %d OTA time\n", symb, symb);
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;
442 p_loc_sym_cb_ctx->symCb = symCb;
443 p_loc_sym_cb_ctx->symCbParam = symCbParam;
444 p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
446 p_loc_sym_cb_ctx->status = 1;
448 *p_sym_cb_ctx = p_loc_sym_cb_ctx;
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)
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;
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);
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) {
475 printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
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);
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;
487 p_loc_sym_cb_ctx->symCb = symCb;
488 p_loc_sym_cb_ctx->symCbParam = symCbParam;
489 p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
491 p_loc_sym_cb_ctx->status = 1;
493 *p_sym_cb_ctx =p_loc_sym_cb_ctx;
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)
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;
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);
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);
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;
528 p_loc_sym_cb_ctx->symCb = symCb;
529 p_loc_sym_cb_ctx->symCbParam = symCbParam;
530 p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
532 p_loc_sym_cb_ctx->status = 1;
534 *p_sym_cb_ctx =p_loc_sym_cb_ctx;
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)
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;
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);
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) {
561 printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
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);
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;
573 p_loc_sym_cb_ctx->symCb = symCb;
574 p_loc_sym_cb_ctx->symCbParam = symCbParam;
575 p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
577 p_loc_sym_cb_ctx->status = 1;
579 *p_sym_cb_ctx = p_loc_sym_cb_ctx;
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)
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;
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);
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) {
606 printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
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;
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;
618 p_loc_sym_cb_ctx->symCb = symCb;
619 p_loc_sym_cb_ctx->symCbParam = symCbParam;
620 p_loc_sym_cb_ctx->symCbTimeInfo = symCbTime;
622 p_loc_sym_cb_ctx->status = 1;
624 *p_sym_cb_ctx =p_loc_sym_cb_ctx;
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)
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;
638 if(xran_get_if_state() == XRAN_RUNNING) {
639 print_err("Cannot register callback while running!!");
644 p_dev_ctx = (struct xran_device_ctx *)pHandle;
646 print_err("pHandle==NULL");
647 ret = XRAN_STATUS_INVALID_PARAM;
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)
656 dpdk_cb_to_arm = rx_ul_user_sym_cb;
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)
662 dpdk_cb_to_arm = rx_ul_user_sym_cb;
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)
668 dpdk_cb_to_arm = rx_ul_user_sym_cb;
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)
674 dpdk_cb_to_arm = rx_ul_user_sym_cb;
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)
680 dpdk_cb_to_arm = rx_ul_user_sym_cb;
683 /* functionality is not yet implemented */
684 print_err("Functionality is not yet implemented !");
685 ret = XRAN_STATUS_INVALID_PARAM;
689 cb_elm = xran_create_cb(xran_timer_arm_user_cb, dpdk_cb_to_arm, (void*)p_sym_cb_ctx);
691 LIST_INSERT_HEAD(&p_dev_ctx->sym_cb_list_head[p_sym_cb_ctx->symb_num_ota],
695 print_err("cb_elm is NULL\n");
696 ret = XRAN_STATUS_FAIL;
704 xran_reg_physide_cb(void *pHandle, xran_fh_tti_callback_fn Cb, void *cbParam, int skipTtiNum, enum callback_to_phy_id id)
706 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
708 if(xran_get_if_state() == XRAN_RUNNING) {
709 print_err("Cannot register callback while running!!\n");
713 p_xran_dev_ctx->ttiCb[id] = Cb;
714 p_xran_dev_ctx->TtiCbParam[id] = cbParam;
715 p_xran_dev_ctx->SkipTti[id] = skipTtiNum;
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)
723 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx_by_id(xran_port_id);
726 print_err("Null xRAN context on port id %u!!\n", xran_port_id);
730 if(xran_get_if_state() == XRAN_RUNNING) {
731 print_err("Cannot register callback while running!!\n");
735 p_xran_dev_ctx->ttiCb[id] = Cb;
736 p_xran_dev_ctx->TtiCbParam[id] = cbParam;
737 p_xran_dev_ctx->SkipTti[id] = skipTtiNum;