/* * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */#include<errno.h>#include<stdlib.h>#include<time.h>#include<limits.h>#include<reent.h>#include<unistd.h>#include<sys/types.h>#include<sys/reent.h>#include<sys/time.h>#include<sys/times.h>#include<sys/lock.h>#include"esp_system.h"#include"esp_attr.h"#include"esp_rom_sys.h"#include"freertos/FreeRTOS.h"#include"freertos/task.h"#include"esp_private/system_internal.h"#include"soc/rtc.h"#include"esp_time_impl.h"#include"sdkconfig.h"20 includes#if!CONFIG_ESP_TIME_FUNCS_USE_NONE#defineIMPL_NEWLIB_TIME_FUNCS1#endif#ifIMPL_NEWLIB_TIME_FUNCS// time functions are implemented -- they should not be weak#defineWEAK_UNLESS_TIMEFUNC_IMPL// stores the start time of the slewstaticuint64_ts_adjtime_start_us;// is how many microseconds total to slewstaticint64_ts_adjtime_total_correction_us;static_lock_ts_time_lock;// This function gradually changes boot_time to the correction value and immediately updates it.staticuint64_tadjust_boot_time(void){#defineADJTIME_CORRECTION_FACTOR6uint64_tboot_time=esp_time_impl_get_boot_time();if((boot_time==0)||(esp_time_impl_get_time_since_boot()<s_adjtime_start_us)){s_adjtime_start_us=0;}{...}if(s_adjtime_start_us>0){uint64_tsince_boot=esp_time_impl_get_time_since_boot();// If to call this function once per second, then (since_boot - s_adjtime_start_us) will be 1_000_000 (1 second),// and the correction will be equal to (1_000_000us >> 6) = 15_625 us.// The minimum possible correction step can be (64us >> 6) = 1us.// Example: if the time error is 1 second, then it will be compensate for 1 sec / 0,015625 = 64 seconds.int64_tcorrection=(since_boot>>ADJTIME_CORRECTION_FACTOR)-(s_adjtime_start_us>>ADJTIME_CORRECTION_FACTOR);if(correction>0){s_adjtime_start_us=since_boot;if(s_adjtime_total_correction_us<0){if((s_adjtime_total_correction_us+correction)>=0){boot_time=boot_time+s_adjtime_total_correction_us;s_adjtime_start_us=0;}{...}else{s_adjtime_total_correction_us+=correction;boot_time-=correction;}{...}}{...}else{if((s_adjtime_total_correction_us-correction)<=0){boot_time=boot_time+s_adjtime_total_correction_us;s_adjtime_start_us=0;}{...}else{s_adjtime_total_correction_us-=correction;boot_time+=correction;}{...}}{...}esp_time_impl_set_boot_time(boot_time);}{...}}{...}returnboot_time;}{ ... }// Get the adjusted boot time.staticuint64_tget_adjusted_boot_time(void){_lock_acquire(&s_time_lock);uint64_tadjust_time=adjust_boot_time();_lock_release(&s_time_lock);returnadjust_time;}{ ... }// Applying the accumulated correction to base_time and stopping the smooth time adjustment.staticvoidadjtime_corr_stop(void){_lock_acquire(&s_time_lock);if(s_adjtime_start_us!=0){adjust_boot_time();s_adjtime_start_us=0;}{...}_lock_release(&s_time_lock);}{ ... }#else/* ... */// no time functions are actually implemented -- allow users to override them#defineWEAK_UNLESS_TIMEFUNC_IMPL__attribute__((weak))/* ... */#endifWEAK_UNLESS_TIMEFUNC_IMPLintadjtime(conststructtimeval*delta,structtimeval*outdelta){#ifIMPL_NEWLIB_TIME_FUNCSif(outdelta!=NULL){_lock_acquire(&s_time_lock);adjust_boot_time();if(s_adjtime_start_us!=0){outdelta->tv_sec=s_adjtime_total_correction_us/1000000L;outdelta->tv_usec=s_adjtime_total_correction_us%1000000L;}{...}else{outdelta->tv_sec=0;outdelta->tv_usec=0;}{...}_lock_release(&s_time_lock);}{...}if(delta!=NULL){int64_tsec=delta->tv_sec;int64_tusec=delta->tv_usec;if(llabs(sec)>((INT_MAX/1000000L)-1L)){errno=EINVAL;return-1;}{...}/* * If adjusting the system clock by adjtime () is already done during the second call adjtime (), * and the delta of the second call is not NULL, the earlier tuning is stopped, * but the already completed part of the adjustment is not canceled. *//* ... */_lock_acquire(&s_time_lock);// If correction is already in progress (s_adjtime_start_time_us != 0), then apply accumulated corrections.adjust_boot_time();s_adjtime_start_us=esp_time_impl_get_time_since_boot();s_adjtime_total_correction_us=sec*1000000L+usec;_lock_release(&s_time_lock);}{...}return0;/* ... */#elseerrno=ENOSYS;return-1;/* ... */#endif}{ ... }clock_tIRAM_ATTR_times_r(struct_reent*r,structtms*ptms){clock_tt=xTaskGetTickCount()*(portTICK_PERIOD_MS*CLK_TCK/1000);ptms->tms_cstime=0;ptms->tms_cutime=0;ptms->tms_stime=t;ptms->tms_utime=0;structtimevaltv={0,0};_gettimeofday_r(r,&tv,NULL);return(clock_t)tv.tv_sec;}{ ... }WEAK_UNLESS_TIMEFUNC_IMPLintIRAM_ATTR_gettimeofday_r(struct_reent*r,structtimeval*tv,void*tz){(void)tz;#ifIMPL_NEWLIB_TIME_FUNCSif(tv){uint64_tmicroseconds=get_adjusted_boot_time()+esp_time_impl_get_time_since_boot();tv->tv_sec=microseconds/1000000;tv->tv_usec=microseconds%1000000;}{...}return0;/* ... */#else__errno_r(r)=ENOSYS;return-1;/* ... */#endif}{ ... }WEAK_UNLESS_TIMEFUNC_IMPLintsettimeofday(conststructtimeval*tv,conststructtimezone*tz){(void)tz;#ifIMPL_NEWLIB_TIME_FUNCSif(tv){adjtime_corr_stop();uint64_tnow=((uint64_t)tv->tv_sec)*1000000LL+tv->tv_usec;uint64_tsince_boot=esp_time_impl_get_time_since_boot();esp_time_impl_set_boot_time(now-since_boot);}{...}return0;/* ... */#elseerrno=ENOSYS;return-1;/* ... */#endif}{ ... }intusleep(useconds_tus){/* Even at max tick rate, vTaskDelay can still delay for the max of the us argument, we just need to make sure the tick calculation does not overflow *//* ... */constint64_tus_per_tick=portTICK_PERIOD_MS*1000;if(us<us_per_tick){esp_rom_delay_us((uint32_t)us);}{...}else{/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS, * round up to compensate. *//* ... */vTaskDelay((us+us_per_tick-1)/us_per_tick);}{...}return0;}{ ... }unsignedintsleep(unsignedintseconds){usleep(seconds*1000000UL);return0;}{ ... }WEAK_UNLESS_TIMEFUNC_IMPLintclock_settime(clockid_tclock_id,conststructtimespec*tp){#ifIMPL_NEWLIB_TIME_FUNCSif(tp==NULL){errno=EINVAL;return-1;}{...}structtimevaltv;switch(clock_id){caseCLOCK_REALTIME:tv.tv_sec=tp->tv_sec;tv.tv_usec=tp->tv_nsec/1000L;settimeofday(&tv,NULL);break;...default:errno=EINVAL;return-1;...}{...}return0;/* ... */#elseerrno=ENOSYS;return-1;/* ... */#endif}{ ... }WEAK_UNLESS_TIMEFUNC_IMPLintclock_gettime(clockid_tclock_id,structtimespec*tp){#ifIMPL_NEWLIB_TIME_FUNCSif(tp==NULL){errno=EINVAL;return-1;}{...}structtimevaltv;uint64_tmonotonic_time_us=0;switch(clock_id){caseCLOCK_REALTIME:_gettimeofday_r(NULL,&tv,NULL);tp->tv_sec=tv.tv_sec;tp->tv_nsec=tv.tv_usec*1000L;break;...caseCLOCK_MONOTONIC:monotonic_time_us=esp_time_impl_get_time();tp->tv_sec=monotonic_time_us/1000000LL;tp->tv_nsec=(monotonic_time_us%1000000LL)*1000L;break;...default:errno=EINVAL;return-1;...}{...}return0;/* ... */#elseerrno=ENOSYS;return-1;/* ... */#endif}{ ... }WEAK_UNLESS_TIMEFUNC_IMPLintclock_getres(clockid_tclock_id,structtimespec*res){#ifIMPL_NEWLIB_TIME_FUNCSif(res==NULL){errno=EINVAL;return-1;}{...}res->tv_sec=0;res->tv_nsec=esp_system_get_time_resolution();return0;/* ... */#elseerrno=ENOSYS;return-1;/* ... */#endif}{ ... }voidesp_newlib_time_init(void){esp_time_impl_init();}{ ... }
Details
Show: from
Types: Columns:
All items filtered out
All items filtered out
This file uses the notable symbols shown below. Click anywhere in the file to view more details.