Merge branch 'feature/clock_gettime' into 'master'
newlib: Add function clock_gettime() See merge request idf/esp-idf!2610
This commit is contained in:
commit
6d46220456
3 changed files with 226 additions and 0 deletions
35
components/newlib/platform_include/time.h
Normal file
35
components/newlib/platform_include/time.h
Normal 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 */
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue