Merge branch 'feature/clock_gettime' into 'master'

newlib: Add function clock_gettime()

See merge request idf/esp-idf!2610
This commit is contained in:
Ivan Grokhotkov 2018-07-04 18:09:04 +08:00
commit 6d46220456
3 changed files with 226 additions and 0 deletions

View file

@ -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 <time.h>
#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 */

View file

@ -9,6 +9,8 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "soc/rtc.h"
#include "esp_clk.h"
#if portNUM_PROCESSORS == 2 #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); 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();
}

View file

@ -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)); set_boot_time(get_adjusted_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur));
#endif #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
}