diff --git a/components/newlib/platform_include/time.h b/components/newlib/platform_include/time.h new file mode 100644 index 0000000000..954d824d13 --- /dev/null +++ b/components/newlib/platform_include/time.h @@ -0,0 +1,35 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef _ESP_TIME_H +#define _ESP_TIME_H + +#ifdef __cplusplus +extern "C" { +#endif +#include_next + +#define _POSIX_TIMERS 1 +#define CLOCK_MONOTONIC (clockid_t)4 +#define CLOCK_BOOTTIME (clockid_t)4 + +int _EXFUN(clock_settime, (clockid_t clock_id, const struct timespec *tp)); +int _EXFUN(clock_gettime, (clockid_t clock_id, struct timespec *tp)); +int _EXFUN(clock_getres, (clockid_t clock_id, struct timespec *res)); + +#ifdef __cplusplus +} +#endif +#endif /* _ESP_TIME_H */ diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c index 47df5b9de2..0b9b4daa9f 100644 --- a/components/newlib/test/test_time.c +++ b/components/newlib/test/test_time.c @@ -9,6 +9,8 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "sdkconfig.h" +#include "soc/rtc.h" +#include "esp_clk.h" #if portNUM_PROCESSORS == 2 @@ -289,3 +291,108 @@ TEST_CASE("test for thread safety adjtime and gettimeofday functions", "[newlib] TEST_ASSERT(adjtime_test_result == false && gettimeofday_test_result == false); } + +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_RTC 1 +#endif + +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_FRC 1 +#endif +void test_posix_timers_clock (void) +{ +#ifndef _POSIX_TIMERS + TEST_ASSERT_MESSAGE(false, "_POSIX_TIMERS - is not defined"); +#endif + +#if defined( WITH_FRC ) + printf("WITH_FRC "); +#endif + +#if defined( WITH_RTC ) + printf("WITH_RTC "); +#endif + +#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL + printf("External (crystal) Frequency = %d Hz\n", rtc_clk_slow_freq_get_hz()); +#else + printf("Internal Frequency = %d Hz\n", rtc_clk_slow_freq_get_hz()); +#endif + + TEST_ASSERT(clock_settime(CLOCK_REALTIME, NULL) == -1); + TEST_ASSERT(clock_gettime(CLOCK_REALTIME, NULL) == -1); + TEST_ASSERT(clock_getres(CLOCK_REALTIME, NULL) == -1); + + TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, NULL) == -1); + TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, NULL) == -1); + TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, NULL) == -1); + +#if defined( WITH_FRC ) || defined( WITH_RTC ) + struct timeval now = {0}; + now.tv_sec = 10L; + now.tv_usec = 100000L; + TEST_ASSERT(settimeofday(&now, NULL) == 0); + TEST_ASSERT(gettimeofday(&now, NULL) == 0); + + struct timespec ts = {0}; + + TEST_ASSERT(clock_settime(0xFFFFFFFF, &ts) == -1); + TEST_ASSERT(clock_gettime(0xFFFFFFFF, &ts) == -1); + TEST_ASSERT(clock_getres(0xFFFFFFFF, &ts) == 0); + + TEST_ASSERT(clock_gettime(CLOCK_REALTIME, &ts) == 0); + TEST_ASSERT(now.tv_sec == ts.tv_sec); + TEST_ASSERT_INT_WITHIN(5000000L, ts.tv_nsec, now.tv_usec * 1000L); + + ts.tv_sec = 20; + ts.tv_nsec = 100000000L; + TEST_ASSERT(clock_settime(CLOCK_REALTIME, &ts) == 0); + TEST_ASSERT(gettimeofday(&now, NULL) == 0); + TEST_ASSERT(now.tv_sec == ts.tv_sec); + TEST_ASSERT_INT_WITHIN(5000L, now.tv_usec, ts.tv_nsec / 1000L); + + TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, &ts) == -1); + + uint64_t delta_monotonic_us = 0; +#if defined( WITH_FRC ) + + TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == 0); + TEST_ASSERT_EQUAL_INT(1000, ts.tv_nsec); + TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == 0); + TEST_ASSERT_EQUAL_INT(1000, ts.tv_nsec); + + TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + delta_monotonic_us = esp_timer_get_time() - (ts.tv_sec * 1000000L + ts.tv_nsec / 1000L); + TEST_ASSERT(delta_monotonic_us > 0 || delta_monotonic_us == 0); + TEST_ASSERT_INT_WITHIN(5000L, 0, delta_monotonic_us); + + #elif defined( WITH_RTC ) + + TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == 0); + TEST_ASSERT_EQUAL_INT(1000000000L / rtc_clk_slow_freq_get_hz(), ts.tv_nsec); + TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == 0); + TEST_ASSERT_EQUAL_INT(1000000000L / rtc_clk_slow_freq_get_hz(), ts.tv_nsec); + + TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + delta_monotonic_us = esp_clk_rtc_time() - (ts.tv_sec * 1000000L + ts.tv_nsec / 1000L); + TEST_ASSERT(delta_monotonic_us > 0 || delta_monotonic_us == 0); + TEST_ASSERT_INT_WITHIN(5000L, 0, delta_monotonic_us); + +#endif // WITH_FRC + +#else + struct timespec ts = {0}; + TEST_ASSERT(clock_settime(CLOCK_REALTIME, &ts) == -1); + TEST_ASSERT(clock_gettime(CLOCK_REALTIME, &ts) == -1); + TEST_ASSERT(clock_getres(CLOCK_REALTIME, &ts) == -1); + + TEST_ASSERT(clock_settime(CLOCK_MONOTONIC, &ts) == -1); + TEST_ASSERT(clock_gettime(CLOCK_MONOTONIC, &ts) == -1); + TEST_ASSERT(clock_getres(CLOCK_MONOTONIC, &ts) == -1); +#endif // defined( WITH_FRC ) || defined( WITH_RTC ) +} + +TEST_CASE("test posix_timers clock_... functions", "[newlib]") +{ + test_posix_timers_clock(); +} diff --git a/components/newlib/time.c b/components/newlib/time.c index 6137f21435..892ab2ff83 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -380,3 +380,87 @@ void esp_sync_counters_rtc_and_frc() set_boot_time(get_adjusted_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur)); #endif } + + +int clock_settime (clockid_t clock_id, const struct timespec *tp) +{ +#if defined( WITH_FRC ) || defined( WITH_RTC ) + if (tp == NULL) { + errno = EINVAL; + return -1; + } + struct timeval tv; + switch (clock_id) { + case CLOCK_REALTIME: + tv.tv_sec = tp->tv_sec; + tv.tv_usec = tp->tv_nsec / 1000L; + settimeofday(&tv, NULL); + break; + default: + errno = EINVAL; + return -1; + } + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +int clock_gettime (clockid_t clock_id, struct timespec *tp) +{ +#if defined( WITH_FRC ) || defined( WITH_RTC ) + if (tp == NULL) { + errno = EINVAL; + return -1; + } + struct timeval tv; + _gettimeofday_r(NULL, &tv, NULL); + uint64_t monotonic_time_us = 0; + switch (clock_id) { + case CLOCK_REALTIME: + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000L; + break; + case CLOCK_MONOTONIC: +#if defined( WITH_FRC ) + monotonic_time_us = (uint64_t) esp_timer_get_time(); +#elif defined( WITH_RTC ) + monotonic_time_us = get_rtc_time_us(); +#endif // WITH_FRC + tp->tv_sec = monotonic_time_us / 1000000LL; + tp->tv_nsec = (monotonic_time_us % 1000000LL) * 1000L; + break; + default: + errno = EINVAL; + return -1; + } + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +int clock_getres (clockid_t clock_id, struct timespec *res) +{ +#if defined( WITH_FRC ) || defined( WITH_RTC ) + if (res == NULL) { + errno = EINVAL; + return -1; + } +#if defined( WITH_FRC ) + res->tv_sec = 0; + res->tv_nsec = 1000L; +#elif defined( WITH_RTC ) + res->tv_sec = 0; + uint32_t rtc_freq = rtc_clk_slow_freq_get_hz(); + assert(rtc_freq != 0); + res->tv_nsec = 1000000000L / rtc_freq; +#endif // WITH_FRC + return 0; +#else + errno = ENOSYS; + return -1; +#endif +}