From 0eb75ced70a514051fcc6a8f1d232e195b15b4a0 Mon Sep 17 00:00:00 2001 From: xqyjlj Date: Mon, 17 Jul 2023 20:11:58 +0800 Subject: [PATCH] =?UTF-8?q?[time]=E6=97=B6=E9=92=9F=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20(#7794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bsp/qemu-virt64-aarch64/.config | 2 +- bsp/qemu-virt64-aarch64/applications/mnt.c | 11 + bsp/qemu-virt64-aarch64/drivers/board.c | 3 + bsp/qemu-virt64-aarch64/drivers/drv_rtc.c | 4 +- bsp/qemu-virt64-aarch64/drivers/drv_timer.c | 46 -- bsp/qemu-virt64-aarch64/drivers/drv_timer.h | 16 - bsp/qemu-virt64-aarch64/rtconfig.h | 1 + bsp/qemu-virt64-riscv/.config | 12 +- bsp/qemu-virt64-riscv/applications/mnt.c | 15 +- bsp/qemu-virt64-riscv/rtconfig.h | 8 +- components/drivers/include/drivers/rtc.h | 8 + components/drivers/rtc/soft_rtc.c | 131 ++- components/ktime/SConscript | 19 + components/ktime/inc/ktime.h | 160 ++++ components/ktime/src/aarch64/cputimer.c | 32 + components/ktime/src/boottime.c | 51 ++ components/ktime/src/cputimer.c | 31 + components/ktime/src/hrtimer.c | 382 +++++++++ components/ktime/src/risc-v/virt64/cputimer.c | 33 + components/libc/compilers/common/ctime.c | 763 ++++++------------ .../libc/compilers/common/include/sys/time.h | 37 +- components/libc/posix/signal/posix_signal.c | 2 +- libcpu/risc-v/virt64/tick.c | 5 +- 23 files changed, 1170 insertions(+), 602 deletions(-) delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_timer.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_timer.h create mode 100644 components/ktime/SConscript create mode 100644 components/ktime/inc/ktime.h create mode 100644 components/ktime/src/aarch64/cputimer.c create mode 100644 components/ktime/src/boottime.c create mode 100644 components/ktime/src/cputimer.c create mode 100644 components/ktime/src/hrtimer.c create mode 100644 components/ktime/src/risc-v/virt64/cputimer.c diff --git a/bsp/qemu-virt64-aarch64/.config b/bsp/qemu-virt64-aarch64/.config index c6de1d3c7a..44f181b385 100644 --- a/bsp/qemu-virt64-aarch64/.config +++ b/bsp/qemu-virt64-aarch64/.config @@ -204,7 +204,7 @@ CONFIG_RT_USING_FDTLIB=y # CONFIG_FDT_USING_DEBUG is not set CONFIG_RT_USING_RTC=y # CONFIG_RT_USING_ALARM is not set -# CONFIG_RT_USING_SOFT_RTC is not set +CONFIG_RT_USING_SOFT_RTC=y # CONFIG_RT_USING_SDIO is not set # CONFIG_RT_USING_SPI is not set # CONFIG_RT_USING_WDT is not set diff --git a/bsp/qemu-virt64-aarch64/applications/mnt.c b/bsp/qemu-virt64-aarch64/applications/mnt.c index 6a226db6d8..262c19c4f7 100644 --- a/bsp/qemu-virt64-aarch64/applications/mnt.c +++ b/bsp/qemu-virt64-aarch64/applications/mnt.c @@ -22,6 +22,17 @@ int mnt_init(void) { rt_kprintf("file system initialization done!\n"); } + else + { + if (dfs_mount("virtio-blk0", "/", "ext", 0, RT_NULL) == 0) + { + rt_kprintf("file system initialization done!\n"); + } + else + { + rt_kprintf("file system initialization fail!\n"); + } + } } return 0; diff --git a/bsp/qemu-virt64-aarch64/drivers/board.c b/bsp/qemu-virt64-aarch64/drivers/board.c index ce8b88151d..7e8dc364da 100644 --- a/bsp/qemu-virt64-aarch64/drivers/board.c +++ b/bsp/qemu-virt64-aarch64/drivers/board.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef RT_USING_SMART #include @@ -98,6 +99,8 @@ void rt_hw_board_init(void) /* initialize hardware interrupt */ rt_hw_interrupt_init(); + rt_hw_gtimer_init(); + /* support debug feature before components init */ rt_hw_uart_init(); rt_console_set_device(RT_CONSOLE_DEVICE_NAME); diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c b/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c index 019c5d5b0e..a899c2a6c9 100644 --- a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c +++ b/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c @@ -115,8 +115,8 @@ int rt_hw_rtc_init(void) rtc_device.device.user_data = RT_NULL; /* register a rtc device */ - rt_device_register(&rtc_device.device, "rtc", RT_DEVICE_FLAG_RDWR); - + rt_device_register(&rtc_device.device, "rtc0", RT_DEVICE_FLAG_RDWR); + rt_soft_rtc_set_source("rtc0"); return 0; } INIT_DEVICE_EXPORT(rt_hw_rtc_init); diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_timer.c b/bsp/qemu-virt64-aarch64/drivers/drv_timer.c deleted file mode 100644 index 99eaa7b18c..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_timer.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018-11-22 Jesven first version - */ - -#include -#include -#include -#include "cp15.h" -#include "board.h" -#include "gtimer.h" - -#define TIMER_IRQ 30 - -static rt_uint64_t timerStep = 0; - -static void rt_hw_timer_isr(int vector, void *param) -{ - rt_hw_set_gtimer_val(timerStep); - rt_tick_increase(); -} - -void rt_hw_timer_enable(void) -{ - rt_hw_set_gtimer_val(timerStep); - rt_hw_interrupt_umask(TIMER_IRQ); - rt_hw_gtimer_enable(); -} - -int rt_hw_timer_init(void) -{ - rt_hw_interrupt_install(TIMER_IRQ, rt_hw_timer_isr, RT_NULL, "tick"); - __ISB(); - timerStep = rt_hw_get_gtimer_frq(); - __DSB(); - timerStep /= RT_TICK_PER_SECOND; - rt_hw_timer_enable(); - - return 0; -} -INIT_BOARD_EXPORT(rt_hw_timer_init); diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_timer.h b/bsp/qemu-virt64-aarch64/drivers/drv_timer.h deleted file mode 100644 index 784d07ec63..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_timer.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018-11-22 Jesven first version - */ - -#ifndef DRV_TIMER_H__ -#define DRV_TIMER_H__ - -void timer_init(int timer, unsigned int preload); - -#endif diff --git a/bsp/qemu-virt64-aarch64/rtconfig.h b/bsp/qemu-virt64-aarch64/rtconfig.h index 32757a23cc..5b71c996f6 100644 --- a/bsp/qemu-virt64-aarch64/rtconfig.h +++ b/bsp/qemu-virt64-aarch64/rtconfig.h @@ -133,6 +133,7 @@ #define RT_USING_FDT #define RT_USING_FDTLIB #define RT_USING_RTC +#define RT_USING_SOFT_RTC #define RT_USING_DEV_BUS #define RT_USING_VIRTIO #define RT_USING_VIRTIO10 diff --git a/bsp/qemu-virt64-riscv/.config b/bsp/qemu-virt64-riscv/.config index 571d1fdfe0..d3c3ff2f5a 100644 --- a/bsp/qemu-virt64-riscv/.config +++ b/bsp/qemu-virt64-riscv/.config @@ -84,7 +84,7 @@ CONFIG_RT_USING_DEVICE_OPS=y CONFIG_RT_USING_CONSOLE=y CONFIG_RT_CONSOLEBUF_SIZE=256 CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" -CONFIG_RT_VER_NUM=0x50000 +CONFIG_RT_VER_NUM=0x50001 # CONFIG_RT_USING_STDC_ATOMIC is not set CONFIG_ARCH_CPU_64BIT=y CONFIG_RT_USING_CACHE=y @@ -122,10 +122,12 @@ CONFIG_FINSH_ARG_MAX=10 CONFIG_RT_USING_DFS=y CONFIG_DFS_USING_POSIX=y CONFIG_DFS_USING_WORKDIR=y +# CONFIG_RT_USING_DFS_MNTTABLE is not set +CONFIG_DFS_FD_MAX=32 +CONFIG_RT_USING_DFS_V1=y +# CONFIG_RT_USING_DFS_V2 is not set CONFIG_DFS_FILESYSTEMS_MAX=4 CONFIG_DFS_FILESYSTEM_TYPES_MAX=4 -CONFIG_DFS_FD_MAX=32 -# CONFIG_RT_USING_DFS_MNTTABLE is not set CONFIG_RT_USING_DFS_ELMFAT=y # @@ -174,7 +176,7 @@ CONFIG_RT_SERIAL_RB_BUFSZ=64 # CONFIG_RT_USING_HWTIMER is not set CONFIG_RT_USING_CPUTIME=y CONFIG_RT_USING_CPUTIME_RISCV=y -CONFIG_CPUTIME_TIMER_FREQ=300000000 +CONFIG_CPUTIME_TIMER_FREQ=10000000 # CONFIG_RT_USING_I2C is not set # CONFIG_RT_USING_PHY is not set CONFIG_RT_USING_PIN=y @@ -190,7 +192,7 @@ CONFIG_RT_USING_RANDOM=y # CONFIG_RT_USING_FDT is not set CONFIG_RT_USING_RTC=y # CONFIG_RT_USING_ALARM is not set -# CONFIG_RT_USING_SOFT_RTC is not set +CONFIG_RT_USING_SOFT_RTC=y # CONFIG_RT_USING_SDIO is not set # CONFIG_RT_USING_SPI is not set # CONFIG_RT_USING_WDT is not set diff --git a/bsp/qemu-virt64-riscv/applications/mnt.c b/bsp/qemu-virt64-riscv/applications/mnt.c index d3849c569a..ccf2b39809 100644 --- a/bsp/qemu-virt64-riscv/applications/mnt.c +++ b/bsp/qemu-virt64-riscv/applications/mnt.c @@ -19,9 +19,20 @@ int mnt_init(void) if (rt_device_find("virtio-blk0")) { /* mount virtio-blk as root directory */ - if (dfs_mount("virtio-blk0", "/", "elm", 0, RT_NULL) != 0) + if (dfs_mount("virtio-blk0", "/", "elm", 0, RT_NULL) == 0) { - LOG_E("virtio-blk0 mount failed\n"); + rt_kprintf("file system initialization done!\n"); + } + else + { + if (dfs_mount("virtio-blk0", "/", "ext", 0, RT_NULL) == 0) + { + rt_kprintf("file system initialization done!\n"); + } + else + { + rt_kprintf("file system initialization fail!\n"); + } } } diff --git a/bsp/qemu-virt64-riscv/rtconfig.h b/bsp/qemu-virt64-riscv/rtconfig.h index 2d174cf9d7..7780e1d51d 100644 --- a/bsp/qemu-virt64-riscv/rtconfig.h +++ b/bsp/qemu-virt64-riscv/rtconfig.h @@ -53,7 +53,7 @@ #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 256 #define RT_CONSOLE_DEVICE_NAME "uart0" -#define RT_VER_NUM 0x50000 +#define RT_VER_NUM 0x50001 #define ARCH_CPU_64BIT #define RT_USING_CACHE #define RT_USING_HW_ATOMIC @@ -83,9 +83,10 @@ #define RT_USING_DFS #define DFS_USING_POSIX #define DFS_USING_WORKDIR +#define DFS_FD_MAX 32 +#define RT_USING_DFS_V1 #define DFS_FILESYSTEMS_MAX 4 #define DFS_FILESYSTEM_TYPES_MAX 4 -#define DFS_FD_MAX 32 #define RT_USING_DFS_ELMFAT /* elm-chan's FatFs, Generic FAT Filesystem Module */ @@ -117,12 +118,13 @@ #define RT_SERIAL_RB_BUFSZ 64 #define RT_USING_CPUTIME #define RT_USING_CPUTIME_RISCV -#define CPUTIME_TIMER_FREQ 300000000 +#define CPUTIME_TIMER_FREQ 10000000 #define RT_USING_PIN #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM #define RT_USING_RTC +#define RT_USING_SOFT_RTC #define RT_USING_VIRTIO #define RT_USING_VIRTIO10 #define RT_USING_VIRTIO_BLK diff --git a/components/drivers/include/drivers/rtc.h b/components/drivers/include/drivers/rtc.h index ce364d79a8..0aacc4665f 100644 --- a/components/drivers/include/drivers/rtc.h +++ b/components/drivers/include/drivers/rtc.h @@ -27,6 +27,9 @@ extern "C" { #define RT_DEVICE_CTRL_RTC_SET_TIMEVAL (RT_DEVICE_CTRL_BASE(RTC) + 0x04) /**< set timeval for gettimeofday */ #define RT_DEVICE_CTRL_RTC_GET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x05) /**< get alarm */ #define RT_DEVICE_CTRL_RTC_SET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x06) /**< set alarm */ +#define RT_DEVICE_CTRL_RTC_GET_TIMESPEC (RT_DEVICE_CTRL_BASE(RTC) + 0x07) /**< get timespec for clock_gettime */ +#define RT_DEVICE_CTRL_RTC_SET_TIMESPEC (RT_DEVICE_CTRL_BASE(RTC) + 0x08) /**< set timespec for clock_settime */ +#define RT_DEVICE_CTRL_RTC_GET_TIMERES (RT_DEVICE_CTRL_BASE(RTC) + 0x09) /**< get resolution for clock_getres */ /* used for alarm function */ struct rt_rtc_wkalarm @@ -64,6 +67,11 @@ rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second); rt_err_t set_timestamp(time_t timestamp); rt_err_t get_timestamp(time_t *timestamp); +#ifdef RT_USING_SYSTEM_WORKQUEUE +rt_err_t rt_soft_rtc_sync(); +rt_err_t rt_soft_rtc_set_source(const char *name); +#endif + #ifdef __cplusplus } #endif diff --git a/components/drivers/rtc/soft_rtc.c b/components/drivers/rtc/soft_rtc.c index d80e21372f..3d84e547ad 100644 --- a/components/drivers/rtc/soft_rtc.c +++ b/components/drivers/rtc/soft_rtc.c @@ -13,6 +13,8 @@ #include #include +#include + #ifdef RT_USING_SOFT_RTC /* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */ @@ -23,9 +25,21 @@ #define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0 ,0) #endif +#ifndef RTC_AUTO_SYNC_FIRST_DELAY +#define RTC_AUTO_SYNC_FIRST_DELAY 25 +#endif +#ifndef RTC_AUTO_SYNC_PERIOD +#define RTC_AUTO_SYNC_PERIOD 3600 +#endif + +static struct rt_work rtc_sync_work; +static rt_device_t source_device = RT_NULL; + static struct rt_device soft_rtc_dev; static rt_tick_t init_tick; static time_t init_time; +static struct timeval init_tv = {0}; +static struct timespec init_ts = {0}; #ifdef RT_USING_ALARM @@ -55,9 +69,33 @@ static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm) #endif +static void set_rtc_time(time_t t) +{ + init_time = t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND; +#ifdef RT_USING_ALARM + soft_rtc_alarm_update(&wkalarm); +#endif +} + +static void _source_device_control(int cmd, void *args) +{ + if (source_device == RT_NULL) + return; + + if (rt_device_open(source_device, 0) == RT_EOK) + { + rt_device_control(source_device, cmd, args); + rt_device_close(source_device); + } +} + static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args) { time_t *t; + struct timeval *tv; + struct timespec *ts; + struct timeval _tv; + struct timespec _ts; struct tm time_temp; RT_ASSERT(dev != RT_NULL); @@ -72,10 +110,8 @@ static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args) case RT_DEVICE_CTRL_RTC_SET_TIME: { t = (time_t *) args; - init_time = *t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND; -#ifdef RT_USING_ALARM - soft_rtc_alarm_update(&wkalarm); -#endif + set_rtc_time(*t); + _source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, t); break; } #ifdef RT_USING_ALARM @@ -87,6 +123,37 @@ static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args) soft_rtc_alarm_update(&wkalarm); break; #endif + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + tv = (struct timeval *)args; + rt_ktime_boottime_get_us(&_tv); + tv->tv_sec = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND; + tv->tv_usec = init_tv.tv_usec + _tv.tv_usec; + break; + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + tv = (struct timeval *)args; + rt_ktime_boottime_get_us(&_tv); + set_rtc_time(tv->tv_sec); + init_tv.tv_usec = tv->tv_usec - _tv.tv_usec; + _source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, &(tv->tv_sec)); + break; + case RT_DEVICE_CTRL_RTC_GET_TIMESPEC: + ts = (struct timespec *)args; + rt_ktime_boottime_get_ns(&_ts); + ts->tv_sec = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND; + ts->tv_nsec = init_ts.tv_nsec + _ts.tv_nsec; + break; + case RT_DEVICE_CTRL_RTC_SET_TIMESPEC: + ts = (struct timespec *)args; + rt_ktime_boottime_get_ns(&_ts); + set_rtc_time(ts->tv_sec); + init_ts.tv_nsec = ts->tv_nsec - _ts.tv_nsec; + _source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, &(ts->tv_sec)); + break; + case RT_DEVICE_CTRL_RTC_GET_TIMERES: + ts = (struct timespec *)args; + ts->tv_sec = 0; + ts->tv_nsec = (rt_ktime_cputimer_getres() / RT_KTIME_RESMUL); + break; } return RT_EOK; @@ -153,4 +220,60 @@ static int rt_soft_rtc_init(void) } INIT_DEVICE_EXPORT(rt_soft_rtc_init); +#ifdef RT_USING_SYSTEM_WORKQUEUE + +rt_err_t rt_soft_rtc_sync() +{ + time_t time = 0; + + if (source_device == RT_NULL) + { + rt_kprintf("error: rtc source not found, please set it!!!\n"); + return RT_ENOSYS; + } + + _source_device_control(RT_DEVICE_CTRL_RTC_GET_TIME, &time); + set_rtc_time(time); + return RT_EOK; +} + +static void rtc_sync_work_func(struct rt_work *work, void *work_data) +{ + rt_soft_rtc_sync(); + rt_work_submit(work, rt_tick_from_millisecond(RTC_AUTO_SYNC_PERIOD * 1000)); +} + +rt_err_t rt_soft_rtc_set_source(const char *name) +{ + RT_ASSERT(name != RT_NULL); + RT_ASSERT(rt_device_find(name)); // make sure source is exist + + source_device = rt_device_find(name); + rt_work_init(&rtc_sync_work, rtc_sync_work_func, RT_NULL); + rt_work_submit(&rtc_sync_work, rt_tick_from_millisecond(RTC_AUTO_SYNC_FIRST_DELAY * 1000)); + + return RT_EOK; +} + +#ifdef FINSH_USING_MSH +#include +static void cmd_rtc_sync(int argc, char **argv) +{ + struct timeval tv = {0}; + struct timezone tz = {0}; + time_t now = (time_t)0; + + rt_soft_rtc_sync(); + + gettimeofday(&tv, &tz); + now = tv.tv_sec; + /* output current time */ + rt_kprintf("local time: %.*s", 25, ctime(&now)); + rt_kprintf("timestamps: %ld\n", (long)tv.tv_sec); +} +MSH_CMD_EXPORT_ALIAS(cmd_rtc_sync, rtc_sync, Update time by real rtc); +#endif + +#endif /* RT_USING_SYSTEM_WORKQUEUE */ + #endif /* RT_USING_SOFT_RTC */ diff --git a/components/ktime/SConscript b/components/ktime/SConscript new file mode 100644 index 0000000000..0ec9655697 --- /dev/null +++ b/components/ktime/SConscript @@ -0,0 +1,19 @@ +import os +from building import * + +Import('rtconfig') + +cwd = GetCurrentDir() + +src = Glob('src/*.c') +list = os.listdir(cwd + "/src") +if rtconfig.ARCH in list: + if os.path.exists(cwd + "/src/" + rtconfig.ARCH + "/" + rtconfig.CPU): + src += Glob("src/" + rtconfig.ARCH + "/" + rtconfig.CPU + "/*.c") + else: + src += Glob("src/" + rtconfig.ARCH + "/*.c") +CPPPATH = [cwd, cwd + "/inc"] + +group = DefineGroup('ktime', src, depend=[''], CPPPATH=CPPPATH) + +Return('group') diff --git a/components/ktime/inc/ktime.h b/components/ktime/inc/ktime.h new file mode 100644 index 0000000000..86fbefd0bb --- /dev/null +++ b/components/ktime/inc/ktime.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#ifndef __KTIME_H__ +#define __KTIME_H__ + +#include +#include + +#include "rtthread.h" + +#define RT_KTIME_RESMUL (1000000UL) + +struct rt_ktime_hrtimer +{ + struct rt_object parent; /**< inherit from rt_object */ + rt_list_t row; + void *parameter; + unsigned long init_cnt; + unsigned long timeout_cnt; + struct rt_semaphore sem; + void (*timeout_func)(void *parameter); +}; +typedef struct rt_ktime_hrtimer *rt_ktime_hrtimer_t; + +/** + * @brief Get boottime with us precision + * + * @param tv: timeval + * @return rt_err_t + */ +rt_err_t rt_ktime_boottime_get_us(struct timeval *tv); + +/** + * @brief Get boottime with s precision + * + * @param t: time_t + * @return rt_err_t + */ +rt_err_t rt_ktime_boottime_get_s(time_t *t); + +/** + * @brief Get boottime with ns precision + * + * @param ts: timespec + * @return rt_err_t + */ +rt_err_t rt_ktime_boottime_get_ns(struct timespec *ts); + +/** + * @brief Get cputimer resolution + * + * @return (resolution * RT_KTIME_RESMUL) + */ +unsigned long rt_ktime_cputimer_getres(void); + +/** + * @brief Get cputimer frequency + * + * @return frequency + */ +unsigned long rt_ktime_cputimer_getfrq(void); + +/** + * @brief Get cputimer the value of the cnt counter + * + * @return cnt + */ +unsigned long rt_ktime_cputimer_getcnt(void); + +/** + * @brief Get cputimer the cnt value corresponding to 1 os tick + * + * @return step + */ +unsigned long rt_ktime_cputimer_getstep(void); + +/** + * @brief Get hrtimer resolution + * + * @return (resolution * RT_KTIME_RESMUL) + */ +unsigned long rt_ktime_hrtimer_getres(void); + +/** + * @brief Get hrtimer frequency + * + * @return frequency + */ +unsigned long rt_ktime_hrtimer_getfrq(void); + +/** + * @brief Get hrtimer the value of the cnt counter + * + * @return cnt + */ +unsigned long rt_ktime_hrtimer_getcnt(void); + +/** + * @brief set hrtimer timeout, when timeout, the timer callback will call timeout + * + * @param cnt: hrtimer requires a timing cnt value + * @param timeout: timeout callback + * @param param: parameter + * @return rt_err_t + */ +rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param); + +void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer, + const char *name, + unsigned long cnt, + rt_uint8_t flag, + void (*timeout)(void *parameter), + void *parameter); +rt_err_t rt_ktime_hrtimer_delete(rt_ktime_hrtimer_t timer); +rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer); +rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer); +rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg); +rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer); + +/** + * @brief sleep by the cputimer cnt value + * + * @param cnt: the cputimer cnt value + * @return rt_err_t + */ +rt_err_t rt_ktime_hrtimer_sleep(unsigned long cnt); + +/** + * @brief sleep by ns + * + * @param ns: ns + * @return rt_err_t + */ +rt_err_t rt_ktime_hrtimer_ndelay(unsigned long ns); + +/** + * @brief sleep by us + * + * @param us: us + * @return rt_err_t + */ +rt_err_t rt_ktime_hrtimer_udelay(unsigned long us); + +/** + * @brief sleep by ms + * + * @param ms: ms + * @return rt_err_t + */ +rt_err_t rt_ktime_hrtimer_mdelay(unsigned long ms); + +#endif diff --git a/components/ktime/src/aarch64/cputimer.c b/components/ktime/src/aarch64/cputimer.c new file mode 100644 index 0000000000..53c60736d4 --- /dev/null +++ b/components/ktime/src/aarch64/cputimer.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "gtimer.h" +#include "ktime.h" + +unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq(); +} + +unsigned long rt_ktime_cputimer_getfrq(void) +{ + return rt_hw_get_gtimer_frq(); +} + +unsigned long rt_ktime_cputimer_getcnt(void) +{ + return rt_hw_get_cntpct_val(); +} + +unsigned long rt_ktime_cputimer_getstep(void) +{ + return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND; +} diff --git a/components/ktime/src/boottime.c b/components/ktime/src/boottime.c new file mode 100644 index 0000000000..9d05266d71 --- /dev/null +++ b/components/ktime/src/boottime.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +#define __KTIME_MUL ((1000UL * 1000 * 1000) / RT_TICK_PER_SECOND) + +rt_err_t rt_ktime_boottime_get_us(struct timeval *tv) +{ + RT_ASSERT(tv != RT_NULL); + + rt_tick_t ms = rt_tick_get(); + unsigned long ns = + ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL; + ns = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns; + + tv->tv_sec = ms / RT_TICK_PER_SECOND; + tv->tv_usec = ns / 1000; + + return RT_EOK; +} + +rt_err_t rt_ktime_boottime_get_s(time_t *t) +{ + RT_ASSERT(t != RT_NULL); + + *t = rt_tick_get() / RT_TICK_PER_SECOND; + + return RT_EOK; +} + +rt_err_t rt_ktime_boottime_get_ns(struct timespec *ts) +{ + RT_ASSERT(ts != RT_NULL); + + rt_tick_t ms = rt_tick_get(); + unsigned long ns = + ((rt_ktime_cputimer_getcnt() % rt_ktime_cputimer_getstep()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL; + + ts->tv_sec = ms / RT_TICK_PER_SECOND; + ts->tv_nsec = ((ms % RT_TICK_PER_SECOND) * __KTIME_MUL) + ns; + + return RT_EOK; +} diff --git a/components/ktime/src/cputimer.c b/components/ktime/src/cputimer.c new file mode 100644 index 0000000000..c878581cdf --- /dev/null +++ b/components/ktime/src/cputimer.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +rt_weak unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_cputimer_getfrq(void) +{ + return RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_cputimer_getcnt(void) +{ + return rt_tick_get(); +} + +rt_weak unsigned long rt_ktime_cputimer_getstep(void) +{ + return 1; +} diff --git a/components/ktime/src/hrtimer.c b/components/ktime/src/hrtimer.c new file mode 100644 index 0000000000..81954c3e00 --- /dev/null +++ b/components/ktime/src/hrtimer.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include +#include +#include + +#include "ktime.h" + +#ifdef ARCH_CPU_64BIT +#define _HRTIMER_MAX_CNT UINT64_MAX +#else +#define _HRTIMER_MAX_CNT UINT32_MAX +#endif + +static rt_list_t _timer_list = RT_LIST_OBJECT_INIT(_timer_list); +static rt_ktime_hrtimer_t _nowtimer = RT_NULL; +static struct rt_spinlock _spinlock; + +rt_weak unsigned long rt_ktime_hrtimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_hrtimer_getfrq(void) +{ + return RT_TICK_PER_SECOND; +} + +rt_weak unsigned long rt_ktime_hrtimer_getcnt(void) +{ + return rt_tick_get(); +} + +static void (*_outcb)(void *param) = RT_NULL; + +static void _hrtimer_timeout(void *parameter) +{ + if (_outcb) + _outcb(parameter); +} + +rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param) +{ + static rt_timer_t timer = RT_NULL; + + if (timer == RT_NULL) + { + timer = rt_timer_create("shrtimer", _hrtimer_timeout, param, cnt, RT_TIMER_FLAG_ONE_SHOT); + } + else + { + rt_tick_t tick = cnt; + rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, param); + } + + _outcb = timeout; + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + rt_timer_stop(timer); + } + rt_timer_start(timer); + return RT_EOK; +} + +/** + * @brief convert cnt from cputimer cnt to hrtimer cnt + * + * @param cnt + * @return unsigned long + */ +static unsigned long _cnt_convert(unsigned long cnt) +{ + int64_t count = cnt - rt_ktime_cputimer_getcnt(); + if (count <= 0) + return 0; + + return (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres(); +} + +static void _sleep_timeout(void *parameter) +{ + struct rt_semaphore *sem; + sem = (struct rt_semaphore *)parameter; + rt_sem_release(sem); +} + +static void _set_next_timeout(void); +static void _timeout_callback(void *parameter) +{ + rt_ktime_hrtimer_t timer; + timer = (rt_ktime_hrtimer_t)parameter; + rt_base_t level; + + level = rt_spin_lock_irqsave(&_spinlock); + _nowtimer = RT_NULL; + rt_list_remove(&(timer->row)); + rt_spin_unlock_irqrestore(&_spinlock, level); + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + timer->timeout_func(timer->parameter); + } + + _set_next_timeout(); +} + +static void _set_next_timeout(void) +{ + rt_ktime_hrtimer_t t; + rt_base_t level; + + if (&_timer_list != _timer_list.prev) + { + level = rt_spin_lock_irqsave(&_spinlock); + t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row); + if (_nowtimer != RT_NULL) + { + if (t != _nowtimer && t->timeout_cnt < _nowtimer->timeout_cnt) + { + _nowtimer = t; + rt_spin_unlock_irqrestore(&_spinlock, level); + rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t); + } + else + { + rt_spin_unlock_irqrestore(&_spinlock, level); + } + } + else + { + _nowtimer = t; + rt_spin_unlock_irqrestore(&_spinlock, level); + rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t); + } + } + else + { + _nowtimer = RT_NULL; + rt_ktime_hrtimer_settimeout(RT_NULL, RT_NULL, RT_NULL); + } +} + +void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer, + const char *name, + unsigned long cnt, + rt_uint8_t flag, + void (*timeout)(void *parameter), + void *parameter) +{ + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(timeout != RT_NULL); + RT_ASSERT(cnt < (_HRTIMER_MAX_CNT / 2)); + + /* set flag */ + timer->parent.flag = flag; + + /* set deactivated */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + timer->timeout_func = timeout; + timer->parameter = parameter; + timer->timeout_cnt = cnt + rt_ktime_cputimer_getcnt(); + timer->init_cnt = cnt; + + rt_list_init(&(timer->row)); + rt_sem_init(&(timer->sem), "hrtimer", 0, RT_IPC_FLAG_PRIO); +} + +rt_err_t rt_ktime_hrtimer_delete(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* stop timer */ + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer) +{ + rt_list_t *timer_list; + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); /* remove timer from list */ + /* change status of timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + timer_list = &_timer_list; + for (; timer_list != _timer_list.prev; timer_list = timer_list->next) + { + rt_ktime_hrtimer_t t; + rt_list_t *p = timer_list->next; + + t = rt_list_entry(p, struct rt_ktime_hrtimer, row); + + if ((t->timeout_cnt - timer->timeout_cnt) == 0) + { + continue; + } + else if ((t->timeout_cnt - timer->timeout_cnt) < (_HRTIMER_MAX_CNT / 2)) + { + break; + } + } + rt_list_insert_after(timer_list, &(timer->row)); + timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + RT_ASSERT(timer != RT_NULL); /* timer check */ + + level = rt_spin_lock_irqsave(&_spinlock); + if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + rt_spin_unlock_irqrestore(&_spinlock, level); + return -RT_ERROR; + } + rt_list_remove(&timer->row); + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* change status */ + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + switch (cmd) + { + case RT_TIMER_CTRL_GET_TIME: + *(unsigned long *)arg = timer->init_cnt; + break; + + case RT_TIMER_CTRL_SET_TIME: + RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2)); + timer->init_cnt = *(unsigned long *)arg; + timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt(); + break; + + case RT_TIMER_CTRL_SET_ONESHOT: + timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; + break; + + case RT_TIMER_CTRL_SET_PERIODIC: + timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; + break; + + case RT_TIMER_CTRL_GET_STATE: + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + /*timer is start and run*/ + *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED; + } + else + { + /*timer is stop*/ + *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED; + } + break; + + case RT_TIMER_CTRL_GET_REMAIN_TIME: + *(unsigned long *)arg = timer->timeout_cnt; + break; + case RT_TIMER_CTRL_GET_FUNC: + arg = (void *)timer->timeout_func; + break; + + case RT_TIMER_CTRL_SET_FUNC: + timer->timeout_func = (void (*)(void *))arg; + break; + + case RT_TIMER_CTRL_GET_PARM: + *(void **)arg = timer->parameter; + break; + + case RT_TIMER_CTRL_SET_PARM: + timer->parameter = arg; + break; + + default: + break; + } + rt_spin_unlock_irqrestore(&_spinlock, level); + + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer) +{ + rt_base_t level; + + /* parameter check */ + RT_ASSERT(timer != RT_NULL); + + level = rt_spin_lock_irqsave(&_spinlock); + rt_list_remove(&timer->row); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_spin_unlock_irqrestore(&_spinlock, level); + + _set_next_timeout(); + + rt_sem_detach(&(timer->sem)); + + return RT_EOK; +} + +/************************** delay ***************************/ + +rt_err_t rt_ktime_hrtimer_sleep(unsigned long cnt) +{ + struct rt_ktime_hrtimer timer; + + if (cnt == 0) + return -RT_EINVAL; + + rt_ktime_hrtimer_init(&timer, "hrtimer_sleep", cnt, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER, + _sleep_timeout, &(timer.sem)); + + rt_ktime_hrtimer_start(&timer); /* reset the timeout of thread timer and start it */ + rt_sem_take_interruptible(&(timer.sem), RT_WAITING_FOREVER); + + rt_ktime_hrtimer_detach(&timer); + return RT_EOK; +} + +rt_err_t rt_ktime_hrtimer_ndelay(unsigned long ns) +{ + unsigned long res = rt_ktime_cputimer_getres(); + return rt_ktime_hrtimer_sleep((ns * RT_KTIME_RESMUL) / res); +} + +rt_err_t rt_ktime_hrtimer_udelay(unsigned long us) +{ + return rt_ktime_hrtimer_ndelay(us * 1000); +} + +rt_err_t rt_ktime_hrtimer_mdelay(unsigned long ms) +{ + return rt_ktime_hrtimer_ndelay(ms * 1000000); +} + +static int rt_ktime_hrtimer_lock_init(void) +{ + RT_UNUSED(_spinlock); + rt_spin_lock_init(&_spinlock); + return 0; +} +INIT_BOARD_EXPORT(rt_ktime_hrtimer_lock_init); diff --git a/components/ktime/src/risc-v/virt64/cputimer.c b/components/ktime/src/risc-v/virt64/cputimer.c new file mode 100644 index 0000000000..9b0f754751 --- /dev/null +++ b/components/ktime/src/risc-v/virt64/cputimer.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-10 xqyjlj The first version. + */ + +#include "ktime.h" + +unsigned long rt_ktime_cputimer_getres(void) +{ + return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / CPUTIME_TIMER_FREQ; +} + +unsigned long rt_ktime_cputimer_getfrq(void) +{ + return CPUTIME_TIMER_FREQ; +} + +unsigned long rt_ktime_cputimer_getcnt(void) +{ + unsigned long time_elapsed; + __asm__ __volatile__("rdtime %0" : "=r"(time_elapsed)); + return time_elapsed; +} + +unsigned long rt_ktime_cputimer_getstep(void) +{ + return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND; +} diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index 0e148ef56f..ea31cf753d 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -19,13 +19,16 @@ * 2021-03-15 Meco Man fixed a bug of leaking memory in asctime() * 2021-05-01 Meco Man support fixed timezone * 2021-07-21 Meco Man implement that change/set timezone APIs + * 2023-07-03 xqyjlj refactor posix time and timer */ #include "sys/time.h" -#include -#include +#include #include +#include +#include #include +#include "drivers/rtc.h" #ifdef RT_USING_SMART #include "lwp.h" #endif @@ -82,25 +85,12 @@ static void num2str(char *c, int i) c[1] = i % 10 + '0'; } -/** - * Get time from RTC device (without timezone, UTC+0) - * @param tv: struct timeval - * @return the operation status, RT_EOK on successful - */ -static rt_err_t get_timeval(struct timeval *tv) +static rt_err_t _control_rtc(int cmd, void *arg) { #ifdef RT_USING_RTC static rt_device_t device = RT_NULL; rt_err_t rst = -RT_ERROR; - if (tv == RT_NULL) - return -RT_EINVAL; - - /* default is 0 */ - tv->tv_sec = 0; - tv->tv_usec = 0; - - /* optimization: find rtc device only first */ if (device == RT_NULL) { device = rt_device_find("rtc"); @@ -111,8 +101,7 @@ static rt_err_t get_timeval(struct timeval *tv) { if (rt_device_open(device, 0) == RT_EOK) { - rst = rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &tv->tv_sec); - rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIMEVAL, tv); + rst = rt_device_control(device, cmd, arg); rt_device_close(device); } } @@ -121,53 +110,7 @@ static rt_err_t get_timeval(struct timeval *tv) LOG_W(_WARNING_NO_RTC); return -RT_ENOSYS; } - return rst; - -#else - LOG_W(_WARNING_NO_RTC); - return -RT_ENOSYS; -#endif /* RT_USING_RTC */ -} - -/** - * Set time to RTC device (without timezone) - * @param tv: struct timeval - * @return the operation status, RT_EOK on successful - */ -static int set_timeval(struct timeval *tv) -{ -#ifdef RT_USING_RTC - static rt_device_t device = RT_NULL; - rt_err_t rst = -RT_ERROR; - - if (tv == RT_NULL) - return -RT_EINVAL; - - /* optimization: find rtc device only first */ - if (device == RT_NULL) - { - device = rt_device_find("rtc"); - } - - /* read timestamp from RTC device */ - if (device != RT_NULL) - { - if (rt_device_open(device, 0) == RT_EOK) - { - rst = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &tv->tv_sec); - rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIMEVAL, tv); - rt_device_close(device); - } - } - else - { - LOG_W(_WARNING_NO_RTC); - return -RT_ENOSYS; - } - - return rst; - #else LOG_W(_WARNING_NO_RTC); return -RT_ENOSYS; @@ -351,51 +294,36 @@ RTM_EXPORT(strftime); /* inherent in the toolchain */ */ rt_weak time_t time(time_t *t) { - struct timeval now; + time_t _t; - if(get_timeval(&now) == RT_EOK) - { - if (t) - { - *t = now.tv_sec; - } - return now.tv_sec; - } - else + if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIME, &_t) != RT_EOK) { rt_set_errno(EFAULT); - return ((time_t)-1); + return -1; } + + if (t) + *t = _t; + + return _t; } RTM_EXPORT(time); rt_weak clock_t clock(void) { - return rt_tick_get(); + return rt_tick_get(); // TODO should return cpu usage time } RTM_EXPORT(clock); int stime(const time_t *t) { - struct timeval tv; - - if (t == RT_NULL) - { - rt_set_errno(EFAULT); - return -1; - } - - tv.tv_sec = *t; - tv.tv_usec = 0; - if (set_timeval(&tv) == RT_EOK) + if ((t != RT_NULL) && (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIME, (void *)t) == RT_EOK)) { return 0; } - else - { - rt_set_errno(EFAULT); - return -1; - } + + rt_set_errno(EFAULT); + return -1; } RTM_EXPORT(stime); @@ -497,15 +425,17 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) tz->tz_minuteswest = -(tz_get() * 60); } - if (tv != RT_NULL && get_timeval(tv) == RT_EOK) + if (tv != RT_NULL) { - return 0; - } - else - { - rt_set_errno(EINVAL); - return -1; + tv->tv_sec = 0; + tv->tv_usec = 0; + + if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMEVAL, tv) == RT_EOK) + return 0; } + + rt_set_errno(EINVAL); + return -1; } RTM_EXPORT(gettimeofday); @@ -516,111 +446,65 @@ int settimeofday(const struct timeval *tv, const struct timezone *tz) * The tz_dsttime field has never been used under Linux. * Thus, the following is purely of historic interest. */ - if (tv != RT_NULL - && tv->tv_usec >= 0 - && set_timeval((struct timeval *)tv) == RT_EOK) + if (tv != RT_NULL && tv->tv_usec >= 0 && tv->tv_sec >= 0) { - return 0; - } - else - { - rt_set_errno(EINVAL); - return -1; + if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMEVAL, (void *)tv) == RT_EOK) + return 0; } + + rt_set_errno(EINVAL); + return -1; } RTM_EXPORT(settimeofday); #ifdef RT_USING_POSIX_DELAY int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { + struct timespec old_ts = {0}; + struct timespec new_ts = {0}; + + if (rqtp == RT_NULL) + { + rt_set_errno(EFAULT); + return -1; + } + if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND) { rt_set_errno(EINVAL); return -1; } -#ifdef RT_USING_CPUTIME - rt_uint64_t unit = clock_cpu_getres(); - rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; - rt_uint64_t tick = (ns * (1000UL * 1000)) / unit; - rt_cputime_sleep(tick); - + unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; + rt_ktime_boottime_get_ns(&old_ts); + rt_ktime_hrtimer_ndelay(ns); if (rt_get_errno() == -RT_EINTR) { if (rmtp) { - uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); - rmtp->tv_sec = ((time_t)((rmtp_cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; - rmtp->tv_nsec = ((long)((rmtp_cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; - } - rt_set_errno(EINTR); - return -1; - } -#else - rt_tick_t tick, tick_old = rt_tick_get(); - tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)rqtp->tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; - rt_thread_delay(tick); + rt_ktime_boottime_get_ns(&new_ts); - if (rt_get_errno() == -RT_EINTR) - { - if (rmtp) - { - tick = tick_old + tick - rt_tick_get(); - /* get the passed time */ - rmtp->tv_sec = tick / RT_TICK_PER_SECOND; - rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); + rmtp->tv_sec = 0; + rmtp->tv_nsec = + (old_ts.tv_nsec + ns) - ((new_ts.tv_sec - old_ts.tv_sec) * NANOSECOND_PER_SECOND + new_ts.tv_nsec); + + if (rmtp->tv_nsec > NANOSECOND_PER_SECOND) + { + rmtp->tv_nsec %= NANOSECOND_PER_SECOND; + rmtp->tv_sec += rmtp->tv_nsec / NANOSECOND_PER_SECOND; + } } rt_set_errno(EINTR); return -1; } -#endif return 0; } RTM_EXPORT(nanosleep); #endif /* RT_USING_POSIX_DELAY */ #ifdef RT_USING_POSIX_CLOCK -#ifdef RT_USING_RTC -static volatile struct timeval _timevalue; -static int _rt_clock_time_system_init(void) -{ - rt_base_t level; - time_t time = 0; - rt_tick_t tick; - rt_device_t device; - - device = rt_device_find("rtc"); - if (device != RT_NULL) - { - /* get realtime seconds */ - if(rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time) == RT_EOK) - { - level = rt_hw_interrupt_disable(); - tick = rt_tick_get(); /* get tick */ - _timevalue.tv_usec = (tick%RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK; - _timevalue.tv_sec = time - tick/RT_TICK_PER_SECOND - 1; - rt_hw_interrupt_enable(level); - return 0; - } - } - - level = rt_hw_interrupt_disable(); - _timevalue.tv_usec = 0; - _timevalue.tv_sec = 0; - rt_hw_interrupt_enable(level); - - return -1; -} -INIT_COMPONENT_EXPORT(_rt_clock_time_system_init); -#endif /* RT_USING_RTC */ int clock_getres(clockid_t clockid, struct timespec *res) { -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; -#else - int ret = 0; - if (res == RT_NULL) { rt_set_errno(EFAULT); @@ -629,40 +513,29 @@ int clock_getres(clockid_t clockid, struct timespec *res) switch (clockid) { - case CLOCK_REALTIME: -#ifndef RT_USING_CPUTIME - res->tv_sec = 0; - res->tv_nsec = NANOSECOND_PER_SECOND/RT_TICK_PER_SECOND; - break; -#endif -#ifdef RT_USING_CPUTIME - case CLOCK_CPUTIME_ID: - res->tv_sec = 0; - res->tv_nsec = (clock_cpu_getres() / (1000UL * 1000)); - break; -#endif + case CLOCK_REALTIME: // use RTC + case CLOCK_REALTIME_COARSE: + return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMERES, res); - default: - res->tv_sec = 0; - res->tv_nsec = 0; - ret = -1; - rt_set_errno(EINVAL); - break; + case CLOCK_MONOTONIC: // use cputimer + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + res->tv_sec = 0; + res->tv_nsec = (rt_ktime_cputimer_getres() / RT_KTIME_RESMUL); + return 0; + + default: + rt_set_errno(EINVAL); + return -1; } - - return ret; -#endif /* RT_USING_RTC */ } RTM_EXPORT(clock_getres); int clock_gettime(clockid_t clockid, struct timespec *tp) { -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; -#else - int ret = 0; - if (tp == RT_NULL) { rt_set_errno(EFAULT); @@ -671,172 +544,117 @@ int clock_gettime(clockid_t clockid, struct timespec *tp) switch (clockid) { - case CLOCK_REALTIME: -#ifndef RT_USING_CPUTIME - { - rt_tick_t tick; - rt_base_t level; + case CLOCK_REALTIME: // use RTC + case CLOCK_REALTIME_COARSE: + return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, tp); - level = rt_hw_interrupt_disable(); - tick = rt_tick_get(); /* get tick */ - tp->tv_sec = _timevalue.tv_sec + tick / RT_TICK_PER_SECOND; - tp->tv_nsec = (_timevalue.tv_usec + (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK) * 1000U; - rt_hw_interrupt_enable(level); - if (tp->tv_nsec > 1000000000ULL) - { - tp->tv_nsec %= 1000000000ULL; - tp->tv_sec += 1; - } - } - break; -#endif -#ifdef RT_USING_CPUTIME - case CLOCK_MONOTONIC: - case CLOCK_CPUTIME_ID: - { - uint64_t unit = 0; - uint64_t cpu_tick; + case CLOCK_MONOTONIC: // use boottime + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + return rt_ktime_boottime_get_ns(tp); - unit = clock_cpu_getres(); - cpu_tick = clock_cpu_gettime(); + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + return rt_ktime_boottime_get_ns(tp); // TODO not yet implemented - tp->tv_sec = ((uint64_t)((cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; - tp->tv_nsec = ((uint64_t)((cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; - } - break; -#endif - default: - tp->tv_sec = 0; - tp->tv_nsec = 0; - rt_set_errno(EINVAL); - ret = -1; + default: + tp->tv_sec = 0; + tp->tv_nsec = 0; + rt_set_errno(EINVAL); + return -1; } - - return ret; -#endif /* RT_USING_RTC */ } RTM_EXPORT(clock_gettime); int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp) { -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; -#else - if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND) - { - rt_set_errno(EINVAL); - return -1; - } - switch (clockid) - { - case CLOCK_REALTIME: - { - rt_tick_t tick, tick_old = rt_tick_get(); - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - { - rt_int64_t ts = ((rqtp->tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); - rt_int64_t tns = (rqtp->tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); - tick = ts + tns; - rt_tick_t rt_tick = rt_tick_get(); - tick = tick < rt_tick ? 0 : tick - rt_tick; - } - else - { - tick = rqtp->tv_sec * RT_TICK_PER_SECOND + ((uint64_t)(rqtp->tv_nsec) * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; - } - rt_thread_delay(tick); + struct timespec ts = {0}; + rt_err_t err; - if (rt_get_errno() == -RT_EINTR) - { - if (rmtp) - { - tick = tick_old + tick - rt_tick_get(); - /* get the passed time */ - rmtp->tv_sec = tick / RT_TICK_PER_SECOND; - rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); - } - rt_set_errno(EINTR); - return -1; - } - } - break; - -#ifdef RT_USING_CPUTIME - case CLOCK_MONOTONIC: - case CLOCK_CPUTIME_ID: - { - rt_uint64_t cpu_tick_old = clock_cpu_gettime(); - uint64_t unit = clock_cpu_getres(); - rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; - rt_uint64_t tick = (ns * (1000UL * 1000)) / unit; - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - tick -= cpu_tick_old; - rt_cputime_sleep(tick); - - if (rt_get_errno() == -RT_EINTR) - { - if (rmtp) - { - uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); - rmtp->tv_sec = ((time_t)((rmtp_cpu_tick * unit) / (1000UL * 1000))) / NANOSECOND_PER_SECOND; - rmtp->tv_nsec = ((long)((rmtp_cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; - } - rt_set_errno(EINTR); - return -1; - } - } - break; -#endif - default: - rt_set_errno(EINVAL); - return -1; - } - return 0; -#endif -} -RTM_EXPORT(clock_nanosleep); - -int clock_settime(clockid_t clockid, const struct timespec *tp) -{ -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); - return -1; -#else - rt_base_t level; - int second; - rt_tick_t tick; - rt_device_t device; - - if ((clockid != CLOCK_REALTIME) || (tp == RT_NULL)) + if (rqtp == RT_NULL) { rt_set_errno(EFAULT); return -1; } - /* get second */ - second = tp->tv_sec; - - level = rt_hw_interrupt_disable(); - tick = rt_tick_get(); /* get tick */ - /* update timevalue */ - _timevalue.tv_usec = MICROSECOND_PER_SECOND - (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK; - _timevalue.tv_sec = second - tick / RT_TICK_PER_SECOND - 1; - rt_hw_interrupt_enable(level); - - /* update for RTC device */ - device = rt_device_find("rtc"); - if (device != RT_NULL) + if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND) { - /* set realtime seconds */ - if(rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second) == RT_EOK) - { - return 0; - } + rt_set_errno(EINVAL); + return -1; } - return -1; -#endif /* RT_USING_RTC */ + switch (clockid) + { + case CLOCK_REALTIME: // use RTC + if (flags & TIMER_ABSTIME) + err = _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, &ts); + break; + + case CLOCK_MONOTONIC: // use boottime + case CLOCK_PROCESS_CPUTIME_ID: + if (flags & TIMER_ABSTIME) + err = rt_ktime_boottime_get_ns(&ts); + break; + + default: + rt_set_errno(EINVAL); + return -1; + } + + if (err != RT_EOK) + return err; + + int64_t ns = rqtp->tv_nsec - ts.tv_nsec + (rqtp->tv_sec - ts.tv_sec) * NANOSECOND_PER_SECOND; + if (ns <= 0) + return 0; + + if (flags & TIMER_ABSTIME) + { + ts.tv_nsec = ns % NANOSECOND_PER_SECOND; + ts.tv_sec = ns / NANOSECOND_PER_SECOND; + return nanosleep(&ts, rmtp); + } + else + { + return nanosleep(rqtp, rmtp); + } +} +RTM_EXPORT(clock_nanosleep); + +int clock_settime(clockid_t clockid, const struct timespec *tp) +{ + if (tp == RT_NULL) + { + rt_set_errno(EFAULT); + return -1; + } + + if (tp->tv_sec < 0 || tp->tv_nsec < 0 || tp->tv_nsec >= NANOSECOND_PER_SECOND) + { + rt_set_errno(EINVAL); + return -1; + } + + switch (clockid) + { + case CLOCK_REALTIME: + return _control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMESPEC, (void *)tp); + + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + rt_set_errno(EPERM); + return -1; + + default: + rt_set_errno(EINVAL); + return -1; + } } RTM_EXPORT(clock_settime); @@ -884,18 +702,12 @@ RTM_EXPORT(rt_timespec_to_tick); struct timer_obj { - union - { - struct rt_timer timer; -#ifdef RT_USING_CPUTIME - struct rt_cputimer cputimer; -#endif - }; + struct rt_ktime_hrtimer hrtimer; void (*sigev_notify_function)(union sigval val); union sigval val; struct timespec interval; /* Reload value */ struct timespec value; /* Reload value */ - rt_uint64_t reload; /* Reload value in ms */ + unsigned long reload; /* Reload value in ms */ rt_uint32_t status; int sigev_signo; clockid_t clockid; @@ -915,21 +727,13 @@ static void rtthread_timer_wrapper(void *timerobj) timer->status = NOT_ACTIVE; } -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + timer->reload = ((timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) * RT_KTIME_RESMUL) / + rt_ktime_cputimer_getres(); + if (timer->reload) { - timer->reload = ((timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) * (1000UL * 1000)) / clock_cpu_getres(); - if (timer->reload) - rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_ktime_hrtimer_start(&timer->hrtimer); } - else -#endif /* RT_USING_CPUTIME */ - { - timer->reload = (timer->interval.tv_sec * RT_TICK_PER_SECOND) + (timer->interval.tv_nsec * RT_TICK_PER_SECOND) / NANOSECOND_PER_SECOND; - if (timer->reload) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); - } - #ifdef RT_USING_SMART sys_kill(timer->pid, timer->sigev_signo); #else @@ -960,14 +764,33 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) struct timer_obj *timer; char timername[RT_NAME_MAX] = {0}; - if (clockid > CLOCK_ID_MAX || - (evp->sigev_notify != SIGEV_NONE && - evp->sigev_notify != SIGEV_SIGNAL)) + if (evp == RT_NULL || timerid == RT_NULL) { rt_set_errno(EINVAL); return -1; } + if (evp->sigev_notify == SIGEV_THREAD) // TODO need to implement + { + rt_set_errno(EINVAL); + return -1; + } + + switch (clockid) + { + case CLOCK_REALTIME: + case CLOCK_REALTIME_ALARM: + case CLOCK_MONOTONIC: + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + break; // Only these ids are supported + default: + rt_set_errno(EINVAL); + return -1; + } + timer = rt_malloc(sizeof(struct timer_obj)); if(timer == RT_NULL) { @@ -989,19 +812,8 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) timer->status = NOT_ACTIVE; timer->clockid = clockid; -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) - { - rt_cputimer_init(&timer->cputimer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); - } - else -#endif /* RT_USING_CPUTIME */ - { - if (evp->sigev_notify == SIGEV_NONE) - rt_timer_init(&timer->timer, timername, RT_NULL, RT_NULL, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); - else - rt_timer_init(&timer->timer, timername, rtthread_timer_wrapper, timer, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER); - } + rt_ktime_hrtimer_init(&timer->hrtimer, timername, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER, + rtthread_timer_wrapper, timer); _timerid = resource_id_get(&id_timer); if (_timerid < 0) @@ -1048,28 +860,14 @@ int timer_delete(timer_t timerid) return -1; } -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + if (timer->status == ACTIVE) { - if (timer->status == ACTIVE) - { - timer->status = NOT_ACTIVE; - rt_cputimer_stop(&timer->cputimer); - } - rt_cputimer_detach(&timer->cputimer); + timer->status = NOT_ACTIVE; + rt_ktime_hrtimer_stop(&timer->hrtimer); } - else -#endif /* RT_USING_CPUTIME */ - { - if (timer->status == ACTIVE) - { - timer->status = NOT_ACTIVE; - rt_timer_stop(&timer->timer); - } - rt_timer_detach(&timer->timer); - } - rt_free(timer); + rt_ktime_hrtimer_detach(&timer->hrtimer); + rt_free(timer); return 0; } RTM_EXPORT(timer_delete); @@ -1111,45 +909,11 @@ int timer_gettime(timer_t timerid, struct itimerspec *its) if (timer->status == ACTIVE) { -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) - { - rt_uint64_t remain_tick; - rt_uint64_t remaining; - rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); - remaining = ((remain_tick - clock_cpu_gettime()) * (1000UL * 1000)) / clock_cpu_getres(); - seconds = remaining / NANOSECOND_PER_SECOND; - nanoseconds = remaining % NANOSECOND_PER_SECOND; - } - else -#endif /* RT_USING_CPUTIME */ - { - rt_tick_t remain_tick; - rt_tick_t remaining; - - rt_timer_control(&timer->timer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_tick); - - /* 'remain_tick' is minimum-unit in the RT-Thread' timer, - * so the seconds, nanoseconds will be calculated by 'remain_tick'. - */ - remaining = remain_tick - rt_tick_get(); - - /* calculate 'second' */ - seconds = remaining / RT_TICK_PER_SECOND; - - /* calculate 'nanosecond'; To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. - * - * remain_tick millisecond remain_tick * MILLISECOND_PER_SECOND - * ------------------------- = -------------------------- ---> millisecond = ------------------------------------------- - * RT_TICK_PER_SECOND MILLISECOND_PER_SECOND RT_TICK_PER_SECOND - * - * remain_tick * MILLISECOND_PER_SECOND remain_tick * MILLISECOND_PER_SECOND * MICROSECOND_PER_SECOND - * millisecond = ---------------------------------------- ---> nanosecond = ------------------------------------------------------------------- - * RT_TICK_PER_SECOND RT_TICK_PER_SECOND - * - */ - nanoseconds = (((remaining % RT_TICK_PER_SECOND) * MILLISECOND_PER_SECOND) * MICROSECOND_PER_SECOND) / RT_TICK_PER_SECOND; - } + unsigned long remain_cnt; + rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_GET_REMAIN_TIME, &remain_cnt); + nanoseconds = ((remain_cnt - rt_ktime_cputimer_getcnt()) * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL; + seconds = nanoseconds / NANOSECOND_PER_SECOND; + nanoseconds = nanoseconds % NANOSECOND_PER_SECOND; its->it_value.tv_sec = (rt_int32_t)seconds; its->it_value.tv_nsec = (rt_int32_t)nanoseconds; } @@ -1174,6 +938,9 @@ RTM_EXPORT(timer_gettime); int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue) { + struct timespec ts = {0}; + rt_err_t err = RT_EOK; + struct timer_obj *timer; timer = _g_timerid[(rt_ubase_t)timerid]; if (timer == NULL || @@ -1199,97 +966,61 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, { if (timer->status == ACTIVE) { -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) - rt_cputimer_stop(&timer->cputimer); - else -#endif /* RT_USING_CPUTIME */ - rt_timer_stop(&timer->timer); + rt_ktime_hrtimer_stop(&timer->hrtimer); } timer->status = NOT_ACTIVE; return 0; } - /* calculate timer period(tick); To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. - * - * tick nanosecond nanosecond * RT_TICK_PER_SECOND - * ------------------------- = -------------------------- ---> tick = ------------------------------------- - * RT_TICK_PER_SECOND NANOSECOND_PER_SECOND NANOSECOND_PER_SECOND - * - */ -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) + switch (timer->clockid) { - rt_uint64_t tick; - uint64_t unit = clock_cpu_getres(); - - tick = ((value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) * (1000UL * 1000)) / unit; - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - { - tick -= clock_cpu_gettime(); - } - timer->reload = tick; - } - else -#endif /* RT_USING_CPUTIME */ - { - if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) - { -#ifndef RT_USING_RTC - LOG_W(_WARNING_NO_RTC); + case CLOCK_REALTIME: + case CLOCK_REALTIME_ALARM: + if (flags & TIMER_ABSTIME) + err = _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, &ts); + break; + case CLOCK_MONOTONIC: + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + if (flags & TIMER_ABSTIME) + err = rt_ktime_boottime_get_ns(&ts); + break; + default: + rt_set_errno(EINVAL); return -1; -#else - rt_int64_t ts = ((value->it_value.tv_sec - _timevalue.tv_sec) * RT_TICK_PER_SECOND); - rt_int64_t tns = (value->it_value.tv_nsec - _timevalue.tv_usec * 1000) * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); - rt_int64_t reload = ts + tns; - rt_tick_t rt_tick = rt_tick_get(); - - timer->reload = reload < rt_tick ? 0 : reload - rt_tick; -#endif - } - else - timer->reload = (value->it_value.tv_sec * RT_TICK_PER_SECOND) + value->it_value.tv_nsec * (RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND); } - timer->interval.tv_sec = value->it_interval.tv_sec; + + if (err != RT_EOK) + return err; + + int64_t ns = value->it_value.tv_nsec - ts.tv_nsec + (value->it_value.tv_sec - ts.tv_sec) * NANOSECOND_PER_SECOND; + + if (ns <= 0) + return 0; + + unsigned long res = rt_ktime_cputimer_getres(); + timer->reload = (ns * RT_KTIME_RESMUL) / res; + timer->interval.tv_sec = value->it_interval.tv_sec; timer->interval.tv_nsec = value->it_interval.tv_nsec; - timer->value.tv_sec = value->it_value.tv_sec; - timer->value.tv_nsec = value->it_value.tv_nsec; + timer->value.tv_sec = value->it_value.tv_sec; + timer->value.tv_nsec = value->it_value.tv_nsec; if (timer->status == ACTIVE) { -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) - rt_cputimer_stop(&timer->cputimer); - else -#endif /* RT_USING_CPUTIME */ - rt_timer_stop(&timer->timer); + rt_ktime_hrtimer_stop(&timer->hrtimer); } - timer->status = ACTIVE; -#ifdef RT_USING_CPUTIME - if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) - { - if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) - rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); - else - rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); - - rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); - rt_cputimer_start(&timer->cputimer); - } + if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) + rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); else -#endif /* RT_USING_CPUTIME */ - { - if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0)) - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL); - else - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); + rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL); - rt_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); - rt_timer_start(&timer->timer); - } + rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); + rt_ktime_hrtimer_start(&timer->hrtimer); return 0; } diff --git a/components/libc/compilers/common/include/sys/time.h b/components/libc/compilers/common/include/sys/time.h index 8be8d60f29..f1d8585383 100644 --- a/components/libc/compilers/common/include/sys/time.h +++ b/components/libc/compilers/common/include/sys/time.h @@ -139,8 +139,12 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); #if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) /* POSIX clock and timer */ +#ifndef CLOCK_REALTIME_COARSE +#define CLOCK_REALTIME_COARSE 0 +#endif /* CLOCK_REALTIME_COARSE */ + #ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 1 +#define CLOCK_REALTIME 1 #endif /* CLOCK_REALTIME */ #define CLOCK_CPUTIME_ID 2 @@ -150,13 +154,37 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); #endif /* CLOCK_PROCESS_CPUTIME_ID */ #ifndef CLOCK_THREAD_CPUTIME_ID -#define CLOCK_THREAD_CPUTIME_ID CLOCK_CPUTIME_ID +#define CLOCK_THREAD_CPUTIME_ID 3 #endif /* CLOCK_THREAD_CPUTIME_ID */ #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 4 #endif /* CLOCK_MONOTONIC */ +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW 5 +#endif /* CLOCK_MONOTONIC_RAW */ + +#ifndef CLOCK_MONOTONIC_COARSE +#define CLOCK_MONOTONIC_COARSE 6 +#endif /* CLOCK_MONOTONIC_COARSE */ + +#ifndef CLOCK_BOOTTIME +#define CLOCK_BOOTTIME 7 +#endif /* CLOCK_BOOTTIME */ + +#ifndef CLOCK_REALTIME_ALARM +#define CLOCK_REALTIME_ALARM 8 +#endif /* CLOCK_REALTIME_ALARM */ + +#ifndef CLOCK_BOOTTIME_ALARM +#define CLOCK_BOOTTIME_ALARM 9 +#endif /* CLOCK_BOOTTIME_ALARM */ + +#ifndef CLOCK_SGI_CYCLE +#define CLOCK_SGI_CYCLE 10 // newlib says they don't have this definition, make the compiler happy +#endif /* CLOCK_SGI_CYCLE */ + #ifndef TIMER_ABSTIME #define TIMER_ABSTIME 4 #endif /* TIMER_ABSTIME */ @@ -166,6 +194,11 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); #else #define CLOCK_ID_MAX CLOCK_MONOTONIC #endif + +#ifndef CLOCK_TAI +#define CLOCK_TAI 11 // newlib says they don't have this definition, make the compiler happy +#endif /* CLOCK_TAI */ + #endif /* defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) */ #ifdef RT_USING_POSIX_CLOCK diff --git a/components/libc/posix/signal/posix_signal.c b/components/libc/posix/signal/posix_signal.c index 25475bdbad..00d925ea57 100644 --- a/components/libc/posix/signal/posix_signal.c +++ b/components/libc/posix/signal/posix_signal.c @@ -172,7 +172,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *ti if (timeout) { - tick = rt_timespec_to_tick(timeout); + tick = timeout->tv_sec * RT_TICK_PER_SECOND + timeout->tv_nsec * RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND; } ret = rt_signal_wait(set, info, tick); diff --git a/libcpu/risc-v/virt64/tick.c b/libcpu/risc-v/virt64/tick.c index 8fdbe0809f..cd628f0835 100644 --- a/libcpu/risc-v/virt64/tick.c +++ b/libcpu/risc-v/virt64/tick.c @@ -28,7 +28,6 @@ static uint64_t get_ticks() int tick_isr(void) { // uint64_t core_id = current_coreid(); - int tick_cycles = 40000; // clint->mtimecmp[core_id] += tick_cycles; rt_tick_increase(); sbi_set_timer(get_ticks() + tick_cycles); @@ -41,14 +40,12 @@ int rt_hw_tick_init(void) { /* Read core id */ // unsigned long core_id = current_coreid(); - unsigned long interval = 1000/RT_TICK_PER_SECOND; /* Clear the Supervisor-Timer bit in SIE */ clear_csr(sie, SIP_STIP); /* calculate the tick cycles */ - // tick_cycles = interval * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000ULL - 1; - tick_cycles = 40000; + tick_cycles = CPUTIME_TIMER_FREQ / RT_TICK_PER_SECOND; /* Set timer */ sbi_set_timer(get_ticks() + tick_cycles);