Front Haul Interface Library first seed code contribution
[o-du/phy.git] / fhi_lib / lib / src / xran_timer.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 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 /**
21  * @brief This file provides implementation to Timing for XRAN.
22  *
23  * @file xran_timer.c
24  * @ingroup group_lte_source_xran
25  * @author Intel Corporation
26  *
27  **/
28
29 #include <time.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdint.h>
33
34 #include "xran_timer.h"
35 #include "xran_printf.h"
36 #ifndef MLOG_ENABLED
37 #include "mlog_lnx_xRAN.h"
38 #else
39 #include "mlog_lnx.h"
40 #endif
41 #include "xran_lib_mlog_tasks_id.h"
42 #include "ethdi.h"
43
44 #define NSEC_PER_SEC  1000000000L
45 #define NSEC_PER_USEC 1000L
46 #define THRESHOLD        35  /**< the avg cost of clock_gettime() in ns */
47 #define TIMECOMPENSATION 2   /**< time compensation in us, avg latency of clock_nanosleep */
48
49 #define SEC_MOD_STOP (30)
50
51 static struct timespec started_time;
52 static struct timespec last_time;
53 static struct timespec cur_time;
54
55 static struct timespec* p_cur_time = &cur_time;
56 static struct timespec* p_last_time = &last_time;
57
58 static struct timespec* p_temp_time;
59
60 static unsigned long current_second = 0;
61 static unsigned long started_second = 0;
62 extern uint32_t xran_lib_ota_sym;
63 extern uint32_t xran_lib_ota_tti;
64 extern uint32_t xran_lib_ota_sym_idx;
65
66 static int debugStop = 0;
67
68 uint64_t timing_get_current_second(void)
69 {
70     return current_second;
71 }
72
73 int timing_set_debug_stop(int value)
74 {
75     debugStop = value;
76
77     if(debugStop){
78         clock_gettime(CLOCK_REALTIME, &started_time);
79         started_second =started_time.tv_sec;
80     }
81     return debugStop;
82 }
83
84 int timing_get_debug_stop(void)
85 {
86     return debugStop;
87 }
88
89 long poll_next_tick(long interval_ns)
90 {
91     long target_time;
92     long delta;
93     static int counter = 0;
94     static long sym_acc = 0;
95     static long sym_cnt = 0;
96
97     if(counter){
98        clock_gettime(CLOCK_REALTIME, p_last_time);
99        current_second = p_last_time->tv_sec;
100        counter = 1;
101     }
102
103     target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);
104
105     while(1)
106     {
107         clock_gettime(CLOCK_REALTIME, p_cur_time);
108         delta = (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec) - target_time;
109         if(delta > 0 || (delta < 0 && abs(delta) < THRESHOLD)) {
110             if(current_second != p_cur_time->tv_sec){
111                 current_second = p_cur_time->tv_sec;
112                 xran_lib_ota_sym_idx = 0;
113                 xran_lib_ota_tti = 0;
114                 xran_lib_ota_sym = 0;
115                 sym_cnt = 0;
116                 sym_acc = 0;
117                 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
118                 if(debugStop){
119                     if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){
120                         uint64_t t1;
121                         printf("STOP:[%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
122                         t1 = MLogTick();
123                         rte_pause();
124                         MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
125                         xran_if_current_state = XRAN_STOPPED;
126                     }
127                 }
128                 p_cur_time->tv_nsec = 0; // adjust to 1pps
129             } else {
130                 xran_lib_ota_sym_idx = XranIncrementSymIdx(xran_lib_ota_sym_idx, 14*8);
131                 /* adjust to sym boundary */
132                 if(sym_cnt & 1)
133                     sym_acc += 8928L;
134                 else
135                     sym_acc += 8929L;
136                 /* fine tune to second boundary */
137                 if(sym_cnt % 13 == 0)
138                     sym_acc += 1;
139
140                 p_cur_time->tv_nsec = sym_acc;
141                 sym_cnt++;
142             }
143             if(debugStop && delta < interval_ns*10)
144                 MLogTask(PID_TIME_SYSTIME_POLL, (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec), (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec));
145             p_temp_time = p_last_time;
146             p_last_time = p_cur_time;
147             p_cur_time  = p_temp_time;
148             break;
149         }
150   }
151
152   return delta;
153 }
154
155 long sleep_next_tick(long interval)
156 {
157    struct timespec start_time;
158    struct timespec cur_time;
159    //struct timespec target_time_convert;
160    struct timespec sleep_target_time_convert;
161    long target_time;
162    long sleep_target_time;
163    long delta;
164
165    clock_gettime(CLOCK_REALTIME, &start_time);
166    target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;
167    //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);
168    sleep_target_time = target_time - TIMECOMPENSATION;
169    sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;
170    sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
171
172    //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;
173    //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
174
175    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);
176
177    clock_gettime(CLOCK_REALTIME, &cur_time);
178
179    delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;
180
181    return delta;
182 }
183
184
185