1 /******************************************************************************
\r
3 * Copyright (c) 2019 Intel.
\r
5 * Licensed under the Apache License, Version 2.0 (the "License");
\r
6 * you may not use this file except in compliance with the License.
\r
7 * You may obtain a copy of the License at
\r
9 * http://www.apache.org/licenses/LICENSE-2.0
\r
11 * Unless required by applicable law or agreed to in writing, software
\r
12 * distributed under the License is distributed on an "AS IS" BASIS,
\r
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
14 * See the License for the specific language governing permissions and
\r
15 * limitations under the License.
\r
17 *******************************************************************************/
\r
20 * @brief This file provides implementation to Timing for XRAN.
\r
22 * @file xran_timer.c
\r
23 * @ingroup group_lte_source_xran
\r
24 * @author Intel Corporation
\r
33 #include "xran_timer.h"
\r
34 #include "xran_printf.h"
\r
35 #include "xran_mlog_lnx.h"
\r
36 #include "xran_lib_mlog_tasks_id.h"
\r
38 #include "xran_fh_o_du.h"
\r
39 #include "xran_common.h"
\r
41 #define NSEC_PER_SEC 1000000000L
\r
42 #define NSEC_PER_USEC 1000L
\r
43 #define THRESHOLD 35 /**< the avg cost of clock_gettime() in ns */
\r
44 #define TIMECOMPENSATION 2 /**< time compensation in us, avg latency of clock_nanosleep */
\r
46 #define SEC_MOD_STOP (60)
\r
48 static struct timespec started_time;
\r
49 static struct timespec last_time;
\r
50 static struct timespec cur_time;
\r
52 static uint64_t curr_tick;
\r
53 static uint64_t last_tick;
\r
55 static struct timespec* p_cur_time = &cur_time;
\r
56 static struct timespec* p_last_time = &last_time;
\r
59 static struct timespec* p_temp_time;
\r
61 static unsigned long current_second = 0;
\r
62 static unsigned long started_second = 0;
\r
63 static uint8_t numerlogy = 0;
\r
64 extern uint32_t xran_lib_ota_sym;
\r
65 extern uint32_t xran_lib_ota_tti;
\r
66 extern uint32_t xran_lib_ota_sym_idx;
\r
68 static int debugStop = 0;
\r
69 static int debugStopCount = 0;
\r
71 static long fine_tuning[5][2] =
\r
73 {71428L, 71429L}, /* mu = 0 */
\r
74 {35714L, 35715L}, /* mu = 1 */
\r
75 {0, 0}, /* mu = 2 not supported */
\r
76 {8928L, 8929L}, /* mu = 3 */
\r
77 {0,0 } /* mu = 4 not supported */
\r
80 static uint8_t slots_per_subframe[4] =
\r
88 uint64_t timing_get_current_second(void)
\r
90 return current_second;
\r
93 int timing_set_numerology(uint8_t value)
\r
99 int timing_set_debug_stop(int value, int count)
\r
102 debugStopCount = count;
\r
105 clock_gettime(CLOCK_REALTIME, &started_time);
\r
106 started_second =started_time.tv_sec;
\r
111 int timing_get_debug_stop(void)
\r
116 void timing_adjust_gps_second(struct timespec* p_time)
\r
118 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
\r
120 long nsec = p_time->tv_nsec + p_xran_dev_ctx->offset_nsec;
\r
121 p_time->tv_sec += p_xran_dev_ctx->offset_sec;
\r
125 p_time->tv_sec += 1;
\r
127 p_time->tv_nsec = nsec;
\r
131 uint64_t xran_tick(void)
\r
134 __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
\r
135 return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
\r
138 unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_tick)
\r
140 if (curr_tick >= last_tick)
\r
141 return (unsigned long)(curr_tick - last_tick);
\r
143 return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);
\r
146 long poll_next_tick(long interval_ns, unsigned long *used_tick)
\r
148 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
\r
151 static int counter = 0;
\r
152 static long sym_acc = 0;
\r
153 static long sym_cnt = 0;
\r
156 clock_gettime(CLOCK_REALTIME, p_last_time);
\r
157 last_tick = MLogTick();
\r
158 if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
\r
159 timing_adjust_gps_second(p_last_time);
\r
160 current_second = p_last_time->tv_sec;
\r
164 target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);
\r
167 clock_gettime(CLOCK_REALTIME, p_cur_time);
\r
168 curr_tick = MLogTick();
\r
169 if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
\r
170 timing_adjust_gps_second(p_cur_time);
\r
171 delta = (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec) - target_time;
\r
172 if(delta > 0 || (delta < 0 && abs(delta) < THRESHOLD)) {
\r
173 if (debugStop &&(debugStopCount > 0) && (tx_counter >= debugStopCount)){
\r
175 printf("STOP:[%ld.%09ld], debugStopCount %d, tx_counter %ld\n", p_cur_time->tv_sec, p_cur_time->tv_nsec, debugStopCount, tx_counter);
\r
178 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
\r
179 xran_if_current_state = XRAN_STOPPED;
\r
181 if(current_second != p_cur_time->tv_sec){
\r
182 current_second = p_cur_time->tv_sec;
\r
183 xran_updateSfnSecStart();
\r
184 xran_lib_ota_sym_idx = 0;
\r
185 xran_lib_ota_tti = 0;
\r
186 xran_lib_ota_sym = 0;
\r
189 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
\r
191 if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){
\r
193 printf("STOP:[%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
\r
196 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
\r
197 xran_if_current_state = XRAN_STOPPED;
\r
200 p_cur_time->tv_nsec = 0; // adjust to 1pps
\r
202 xran_lib_ota_sym_idx = XranIncrementSymIdx(xran_lib_ota_sym_idx, XRAN_NUM_OF_SYMBOL_PER_SLOT*slots_per_subframe[numerlogy]);
\r
203 /* adjust to sym boundary */
\r
205 sym_acc += fine_tuning[numerlogy][0];
\r
207 sym_acc += fine_tuning[numerlogy][1];
\r
208 /* fine tune to second boundary */
\r
209 if(sym_cnt % 13 == 0)
\r
212 p_cur_time->tv_nsec = sym_acc;
\r
216 #ifdef USE_PTP_TIME
\r
217 if(debugStop && delta < interval_ns*10)
\r
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));
\r
220 MLogTask(PID_TIME_SYSTIME_POLL, last_tick, curr_tick);
\r
221 last_tick = curr_tick;
\r
225 p_temp_time = p_last_time;
\r
226 p_last_time = p_cur_time;
\r
227 p_cur_time = p_temp_time;
\r
230 if( likely(xran_if_current_state == XRAN_RUNNING)){
\r
234 ring_processing_func();
\r
238 *used_tick += get_ticks_diff(t2, t1);
\r
246 long sleep_next_tick(long interval)
\r
248 struct timespec start_time;
\r
249 struct timespec cur_time;
\r
250 //struct timespec target_time_convert;
\r
251 struct timespec sleep_target_time_convert;
\r
253 long sleep_target_time;
\r
256 clock_gettime(CLOCK_REALTIME, &start_time);
\r
257 target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;
\r
258 //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);
\r
259 sleep_target_time = target_time - TIMECOMPENSATION;
\r
260 sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;
\r
261 sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
\r
263 //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;
\r
264 //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
\r
266 clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);
\r
268 clock_gettime(CLOCK_REALTIME, &cur_time);
\r
270 delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;
\r