Front Haul Interface Library update to third 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  * @brief This file provides implementation to Timing for XRAN.
21  *
22  * @file xran_timer.c
23  * @ingroup group_lte_source_xran
24  * @author Intel Corporation
25  *
26  **/
27
28 #include <time.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32
33 #include "xran_timer.h"
34 #include "xran_printf.h"
35 #include "xran_mlog_lnx.h"
36 #include "xran_lib_mlog_tasks_id.h"
37 #include "ethdi.h"
38 #include "xran_fh_o_du.h"
39 #include "xran_common.h"
40
41 #define NSEC_PER_SEC  1000000000L
42 #define NSEC_PER_USEC 1000L
43 #define THRESHOLD        35  /**< the avg cost of clock_gettime() in ns */
44 #define TIMECOMPENSATION 2   /**< time compensation in us, avg latency of clock_nanosleep */
45
46 #define SEC_MOD_STOP (60)
47
48 static struct timespec started_time;
49 static struct timespec last_time;
50 static struct timespec cur_time;
51
52 static uint64_t  curr_tick;
53 static uint64_t  last_tick;
54
55 static struct timespec* p_cur_time = &cur_time;
56 static struct timespec* p_last_time = &last_time;
57
58
59 static struct timespec* p_temp_time;
60
61 static unsigned long current_second = 0;
62 static unsigned long started_second = 0;
63 static uint8_t numerlogy = 0;
64 extern uint32_t xran_lib_ota_sym;
65 extern uint32_t xran_lib_ota_tti;
66 extern uint32_t xran_lib_ota_sym_idx;
67
68 static int debugStop = 0;
69 static int debugStopCount = 0;
70
71 static long fine_tuning[5][2] =
72 {
73     {71428L, 71429L},  /* mu = 0 */
74     {35714L, 35715L},  /* mu = 1 */
75     {0, 0},            /* mu = 2 not supported */
76     {8928L, 8929L},    /* mu = 3 */
77     {0,0  }            /* mu = 4 not supported */
78 };
79
80 static uint8_t slots_per_subframe[4] =
81 {
82     1,  /* mu = 0 */
83     2,  /* mu = 1 */
84     4,  /* mu = 2 */
85     8,  /* mu = 3 */
86 };
87
88 uint64_t timing_get_current_second(void)
89 {
90     return current_second;
91 }
92
93 int timing_set_numerology(uint8_t value)
94 {
95     numerlogy = value;
96     return numerlogy;
97 }
98
99 int timing_set_debug_stop(int value, int count)
100 {
101     debugStop = value;
102     debugStopCount = count;
103
104     if(debugStop){
105         clock_gettime(CLOCK_REALTIME, &started_time);
106         started_second =started_time.tv_sec;
107     }
108     return debugStop;
109 }
110
111 int timing_get_debug_stop(void)
112 {
113     return debugStop;
114 }
115
116 void timing_adjust_gps_second(struct timespec* p_time)
117 {
118     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
119
120     long nsec = p_time->tv_nsec + p_xran_dev_ctx->offset_nsec;
121     p_time->tv_sec += p_xran_dev_ctx->offset_sec;
122     if (nsec >= 1e9)
123     {
124         nsec -=1e9;
125         p_time->tv_sec += 1;
126     }
127     p_time->tv_nsec = nsec;
128
129     return;
130 }
131 uint64_t xran_tick(void)
132 {
133     uint32_t hi, lo;
134     __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
135     return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
136 }
137
138 unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_tick)
139 {
140     if (curr_tick >= last_tick)
141         return (unsigned long)(curr_tick - last_tick);
142     else
143         return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);
144 }
145
146 long poll_next_tick(long interval_ns, unsigned long *used_tick)
147 {
148     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
149     long target_time;
150     long delta;
151     static int counter = 0;
152     static long sym_acc = 0;
153     static long sym_cnt = 0;
154
155     if(counter == 0) {
156        clock_gettime(CLOCK_REALTIME, p_last_time);
157        last_tick = MLogTick();
158        if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
159            timing_adjust_gps_second(p_last_time);
160        current_second = p_last_time->tv_sec;
161        counter = 1;
162     }
163
164     target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);
165
166     while(1) {
167         clock_gettime(CLOCK_REALTIME, p_cur_time);
168         curr_tick = MLogTick();
169         if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
170             timing_adjust_gps_second(p_cur_time);
171         delta = (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec) - target_time;
172         if(delta > 0 || (delta < 0 && abs(delta) < THRESHOLD)) {
173             if (debugStop &&(debugStopCount > 0) && (tx_counter >= debugStopCount)){
174                 uint64_t t1;
175                 printf("STOP:[%ld.%09ld], debugStopCount %d, tx_counter %ld\n", p_cur_time->tv_sec, p_cur_time->tv_nsec, debugStopCount, tx_counter);
176                 t1 = MLogTick();
177                 rte_pause();
178                 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
179                 xran_if_current_state = XRAN_STOPPED;
180             }
181             if(current_second != p_cur_time->tv_sec){
182                 current_second = p_cur_time->tv_sec;
183                 xran_updateSfnSecStart();
184                 xran_lib_ota_sym_idx = 0;
185                 xran_lib_ota_tti = 0;
186                 xran_lib_ota_sym = 0;
187                 sym_cnt = 0;
188                 sym_acc = 0;
189                 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
190                 if(debugStop){
191                     if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){
192                         uint64_t t1;
193                         printf("STOP:[%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
194                         t1 = MLogTick();
195                         rte_pause();
196                         MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
197                         xran_if_current_state = XRAN_STOPPED;
198                     }
199                 }
200                 p_cur_time->tv_nsec = 0; // adjust to 1pps
201             } else {
202                 xran_lib_ota_sym_idx = XranIncrementSymIdx(xran_lib_ota_sym_idx, XRAN_NUM_OF_SYMBOL_PER_SLOT*slots_per_subframe[numerlogy]);
203                 /* adjust to sym boundary */
204                 if(sym_cnt & 1)
205                     sym_acc +=  fine_tuning[numerlogy][0];
206                 else
207                     sym_acc +=  fine_tuning[numerlogy][1];
208                 /* fine tune to second boundary */
209                 if(sym_cnt % 13 == 0)
210                     sym_acc += 1;
211
212                 p_cur_time->tv_nsec = sym_acc;
213                 sym_cnt++;
214             }
215
216 #ifdef USE_PTP_TIME
217             if(debugStop && delta < interval_ns*10)
218                 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));
219 #else
220             MLogTask(PID_TIME_SYSTIME_POLL, last_tick, curr_tick);
221             last_tick = curr_tick;
222 #endif
223
224
225             p_temp_time = p_last_time;
226             p_last_time = p_cur_time;
227             p_cur_time  = p_temp_time;
228             break;
229         } else {
230             if( likely(xran_if_current_state == XRAN_RUNNING)){
231                 uint64_t t1, t2;
232                 t1 = xran_tick();
233
234                 ring_processing_func();
235                 process_dpdk_io();
236
237                 t2 = xran_tick();
238                 *used_tick += get_ticks_diff(t2, t1);
239             }
240         }
241   }
242
243   return delta;
244 }
245
246 long sleep_next_tick(long interval)
247 {
248    struct timespec start_time;
249    struct timespec cur_time;
250    //struct timespec target_time_convert;
251    struct timespec sleep_target_time_convert;
252    long target_time;
253    long sleep_target_time;
254    long delta;
255
256    clock_gettime(CLOCK_REALTIME, &start_time);
257    target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;
258    //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);
259    sleep_target_time = target_time - TIMECOMPENSATION;
260    sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;
261    sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
262
263    //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;
264    //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
265
266    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);
267
268    clock_gettime(CLOCK_REALTIME, &cur_time);
269
270    delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;
271
272    return delta;
273 }
274
275
276