[time]时钟框架重构 (#7794)

This commit is contained in:
xqyjlj 2023-07-17 20:11:58 +08:00 committed by GitHub
parent b424169e17
commit 0eb75ced70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1170 additions and 602 deletions

View File

@ -204,7 +204,7 @@ CONFIG_RT_USING_FDTLIB=y
# CONFIG_FDT_USING_DEBUG is not set # CONFIG_FDT_USING_DEBUG is not set
CONFIG_RT_USING_RTC=y CONFIG_RT_USING_RTC=y
# CONFIG_RT_USING_ALARM is not set # 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_SDIO is not set
# CONFIG_RT_USING_SPI is not set # CONFIG_RT_USING_SPI is not set
# CONFIG_RT_USING_WDT is not set # CONFIG_RT_USING_WDT is not set

View File

@ -22,6 +22,17 @@ int mnt_init(void)
{ {
rt_kprintf("file system initialization done!\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");
}
}
} }
return 0; return 0;

View File

@ -14,6 +14,7 @@
#include <rthw.h> #include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include <mmu.h> #include <mmu.h>
#include <gtimer.h>
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
#include <lwp_arch.h> #include <lwp_arch.h>
@ -98,6 +99,8 @@ void rt_hw_board_init(void)
/* initialize hardware interrupt */ /* initialize hardware interrupt */
rt_hw_interrupt_init(); rt_hw_interrupt_init();
rt_hw_gtimer_init();
/* support debug feature before components init */ /* support debug feature before components init */
rt_hw_uart_init(); rt_hw_uart_init();
rt_console_set_device(RT_CONSOLE_DEVICE_NAME); rt_console_set_device(RT_CONSOLE_DEVICE_NAME);

View File

@ -115,8 +115,8 @@ int rt_hw_rtc_init(void)
rtc_device.device.user_data = RT_NULL; rtc_device.device.user_data = RT_NULL;
/* register a rtc device */ /* 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; return 0;
} }
INIT_DEVICE_EXPORT(rt_hw_rtc_init); INIT_DEVICE_EXPORT(rt_hw_rtc_init);

View File

@ -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 <rthw.h>
#include <rtthread.h>
#include <stdint.h>
#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);

View File

@ -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

View File

@ -133,6 +133,7 @@
#define RT_USING_FDT #define RT_USING_FDT
#define RT_USING_FDTLIB #define RT_USING_FDTLIB
#define RT_USING_RTC #define RT_USING_RTC
#define RT_USING_SOFT_RTC
#define RT_USING_DEV_BUS #define RT_USING_DEV_BUS
#define RT_USING_VIRTIO #define RT_USING_VIRTIO
#define RT_USING_VIRTIO10 #define RT_USING_VIRTIO10

View File

@ -84,7 +84,7 @@ CONFIG_RT_USING_DEVICE_OPS=y
CONFIG_RT_USING_CONSOLE=y CONFIG_RT_USING_CONSOLE=y
CONFIG_RT_CONSOLEBUF_SIZE=256 CONFIG_RT_CONSOLEBUF_SIZE=256
CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" 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_RT_USING_STDC_ATOMIC is not set
CONFIG_ARCH_CPU_64BIT=y CONFIG_ARCH_CPU_64BIT=y
CONFIG_RT_USING_CACHE=y CONFIG_RT_USING_CACHE=y
@ -122,10 +122,12 @@ CONFIG_FINSH_ARG_MAX=10
CONFIG_RT_USING_DFS=y CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_POSIX=y CONFIG_DFS_USING_POSIX=y
CONFIG_DFS_USING_WORKDIR=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_FILESYSTEMS_MAX=4
CONFIG_DFS_FILESYSTEM_TYPES_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 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_HWTIMER is not set
CONFIG_RT_USING_CPUTIME=y CONFIG_RT_USING_CPUTIME=y
CONFIG_RT_USING_CPUTIME_RISCV=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_I2C is not set
# CONFIG_RT_USING_PHY is not set # CONFIG_RT_USING_PHY is not set
CONFIG_RT_USING_PIN=y CONFIG_RT_USING_PIN=y
@ -190,7 +192,7 @@ CONFIG_RT_USING_RANDOM=y
# CONFIG_RT_USING_FDT is not set # CONFIG_RT_USING_FDT is not set
CONFIG_RT_USING_RTC=y CONFIG_RT_USING_RTC=y
# CONFIG_RT_USING_ALARM is not set # 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_SDIO is not set
# CONFIG_RT_USING_SPI is not set # CONFIG_RT_USING_SPI is not set
# CONFIG_RT_USING_WDT is not set # CONFIG_RT_USING_WDT is not set

View File

@ -19,9 +19,20 @@ int mnt_init(void)
if (rt_device_find("virtio-blk0")) if (rt_device_find("virtio-blk0"))
{ {
/* mount virtio-blk as root directory */ /* 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");
}
} }
} }

View File

@ -53,7 +53,7 @@
#define RT_USING_CONSOLE #define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 256 #define RT_CONSOLEBUF_SIZE 256
#define RT_CONSOLE_DEVICE_NAME "uart0" #define RT_CONSOLE_DEVICE_NAME "uart0"
#define RT_VER_NUM 0x50000 #define RT_VER_NUM 0x50001
#define ARCH_CPU_64BIT #define ARCH_CPU_64BIT
#define RT_USING_CACHE #define RT_USING_CACHE
#define RT_USING_HW_ATOMIC #define RT_USING_HW_ATOMIC
@ -83,9 +83,10 @@
#define RT_USING_DFS #define RT_USING_DFS
#define DFS_USING_POSIX #define DFS_USING_POSIX
#define DFS_USING_WORKDIR #define DFS_USING_WORKDIR
#define DFS_FD_MAX 32
#define RT_USING_DFS_V1
#define DFS_FILESYSTEMS_MAX 4 #define DFS_FILESYSTEMS_MAX 4
#define DFS_FILESYSTEM_TYPES_MAX 4 #define DFS_FILESYSTEM_TYPES_MAX 4
#define DFS_FD_MAX 32
#define RT_USING_DFS_ELMFAT #define RT_USING_DFS_ELMFAT
/* elm-chan's FatFs, Generic FAT Filesystem Module */ /* elm-chan's FatFs, Generic FAT Filesystem Module */
@ -117,12 +118,13 @@
#define RT_SERIAL_RB_BUFSZ 64 #define RT_SERIAL_RB_BUFSZ 64
#define RT_USING_CPUTIME #define RT_USING_CPUTIME
#define RT_USING_CPUTIME_RISCV #define RT_USING_CPUTIME_RISCV
#define CPUTIME_TIMER_FREQ 300000000 #define CPUTIME_TIMER_FREQ 10000000
#define RT_USING_PIN #define RT_USING_PIN
#define RT_USING_NULL #define RT_USING_NULL
#define RT_USING_ZERO #define RT_USING_ZERO
#define RT_USING_RANDOM #define RT_USING_RANDOM
#define RT_USING_RTC #define RT_USING_RTC
#define RT_USING_SOFT_RTC
#define RT_USING_VIRTIO #define RT_USING_VIRTIO
#define RT_USING_VIRTIO10 #define RT_USING_VIRTIO10
#define RT_USING_VIRTIO_BLK #define RT_USING_VIRTIO_BLK

View File

@ -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_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_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_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 */ /* used for alarm function */
struct rt_rtc_wkalarm 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 set_timestamp(time_t timestamp);
rt_err_t get_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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -13,6 +13,8 @@
#include <rtthread.h> #include <rtthread.h>
#include <rtdevice.h> #include <rtdevice.h>
#include <ktime.h>
#ifdef RT_USING_SOFT_RTC #ifdef RT_USING_SOFT_RTC
/* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */ /* 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) #define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0 ,0)
#endif #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 struct rt_device soft_rtc_dev;
static rt_tick_t init_tick; static rt_tick_t init_tick;
static time_t init_time; static time_t init_time;
static struct timeval init_tv = {0};
static struct timespec init_ts = {0};
#ifdef RT_USING_ALARM #ifdef RT_USING_ALARM
@ -55,9 +69,33 @@ static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
#endif #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) static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
{ {
time_t *t; time_t *t;
struct timeval *tv;
struct timespec *ts;
struct timeval _tv;
struct timespec _ts;
struct tm time_temp; struct tm time_temp;
RT_ASSERT(dev != RT_NULL); 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: case RT_DEVICE_CTRL_RTC_SET_TIME:
{ {
t = (time_t *) args; t = (time_t *) args;
init_time = *t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND; set_rtc_time(*t);
#ifdef RT_USING_ALARM _source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, t);
soft_rtc_alarm_update(&wkalarm);
#endif
break; break;
} }
#ifdef RT_USING_ALARM #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); soft_rtc_alarm_update(&wkalarm);
break; break;
#endif #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; return RT_EOK;
@ -153,4 +220,60 @@ static int rt_soft_rtc_init(void)
} }
INIT_DEVICE_EXPORT(rt_soft_rtc_init); 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 <finsh.h>
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 */ #endif /* RT_USING_SOFT_RTC */

View File

@ -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')

View File

@ -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 <stdint.h>
#include <sys/time.h>
#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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <rtdevice.h>
#include <rthw.h>
#include <rtthread.h>
#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);

View File

@ -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;
}

View File

@ -19,13 +19,16 @@
* 2021-03-15 Meco Man fixed a bug of leaking memory in asctime() * 2021-03-15 Meco Man fixed a bug of leaking memory in asctime()
* 2021-05-01 Meco Man support fixed timezone * 2021-05-01 Meco Man support fixed timezone
* 2021-07-21 Meco Man implement that change/set timezone APIs * 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 "sys/time.h"
#include <sys/errno.h> #include <ktime.h>
#include <rtthread.h>
#include <rthw.h> #include <rthw.h>
#include <rtthread.h>
#include <sys/errno.h>
#include <unistd.h> #include <unistd.h>
#include "drivers/rtc.h"
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
#include "lwp.h" #include "lwp.h"
#endif #endif
@ -82,25 +85,12 @@ static void num2str(char *c, int i)
c[1] = i % 10 + '0'; c[1] = i % 10 + '0';
} }
/** static rt_err_t _control_rtc(int cmd, void *arg)
* 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)
{ {
#ifdef RT_USING_RTC #ifdef RT_USING_RTC
static rt_device_t device = RT_NULL; static rt_device_t device = RT_NULL;
rt_err_t rst = -RT_ERROR; 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) if (device == RT_NULL)
{ {
device = rt_device_find("rtc"); 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) if (rt_device_open(device, 0) == RT_EOK)
{ {
rst = rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &tv->tv_sec); rst = rt_device_control(device, cmd, arg);
rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIMEVAL, tv);
rt_device_close(device); rt_device_close(device);
} }
} }
@ -121,53 +110,7 @@ static rt_err_t get_timeval(struct timeval *tv)
LOG_W(_WARNING_NO_RTC); LOG_W(_WARNING_NO_RTC);
return -RT_ENOSYS; return -RT_ENOSYS;
} }
return rst; 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 #else
LOG_W(_WARNING_NO_RTC); LOG_W(_WARNING_NO_RTC);
return -RT_ENOSYS; return -RT_ENOSYS;
@ -351,51 +294,36 @@ RTM_EXPORT(strftime); /* inherent in the toolchain */
*/ */
rt_weak time_t time(time_t *t) rt_weak time_t time(time_t *t)
{ {
struct timeval now; time_t _t;
if(get_timeval(&now) == RT_EOK) if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIME, &_t) != RT_EOK)
{
if (t)
{
*t = now.tv_sec;
}
return now.tv_sec;
}
else
{ {
rt_set_errno(EFAULT); rt_set_errno(EFAULT);
return ((time_t)-1); return -1;
} }
if (t)
*t = _t;
return _t;
} }
RTM_EXPORT(time); RTM_EXPORT(time);
rt_weak clock_t clock(void) rt_weak clock_t clock(void)
{ {
return rt_tick_get(); return rt_tick_get(); // TODO should return cpu usage time
} }
RTM_EXPORT(clock); RTM_EXPORT(clock);
int stime(const time_t *t) int stime(const time_t *t)
{ {
struct timeval tv; if ((t != RT_NULL) && (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIME, (void *)t) == RT_EOK))
if (t == RT_NULL)
{
rt_set_errno(EFAULT);
return -1;
}
tv.tv_sec = *t;
tv.tv_usec = 0;
if (set_timeval(&tv) == RT_EOK)
{ {
return 0; return 0;
} }
else
{ rt_set_errno(EFAULT);
rt_set_errno(EFAULT); return -1;
return -1;
}
} }
RTM_EXPORT(stime); RTM_EXPORT(stime);
@ -497,15 +425,17 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
tz->tz_minuteswest = -(tz_get() * 60); tz->tz_minuteswest = -(tz_get() * 60);
} }
if (tv != RT_NULL && get_timeval(tv) == RT_EOK) if (tv != RT_NULL)
{ {
return 0; tv->tv_sec = 0;
} tv->tv_usec = 0;
else
{ if (_control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMEVAL, tv) == RT_EOK)
rt_set_errno(EINVAL); return 0;
return -1;
} }
rt_set_errno(EINVAL);
return -1;
} }
RTM_EXPORT(gettimeofday); 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. * The tz_dsttime field has never been used under Linux.
* Thus, the following is purely of historic interest. * Thus, the following is purely of historic interest.
*/ */
if (tv != RT_NULL if (tv != RT_NULL && tv->tv_usec >= 0 && tv->tv_sec >= 0)
&& tv->tv_usec >= 0
&& set_timeval((struct timeval *)tv) == RT_EOK)
{ {
return 0; if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMEVAL, (void *)tv) == RT_EOK)
} return 0;
else
{
rt_set_errno(EINVAL);
return -1;
} }
rt_set_errno(EINVAL);
return -1;
} }
RTM_EXPORT(settimeofday); RTM_EXPORT(settimeofday);
#ifdef RT_USING_POSIX_DELAY #ifdef RT_USING_POSIX_DELAY
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) 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) if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
{ {
rt_set_errno(EINVAL); rt_set_errno(EINVAL);
return -1; return -1;
} }
#ifdef RT_USING_CPUTIME unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec;
rt_uint64_t unit = clock_cpu_getres(); rt_ktime_boottime_get_ns(&old_ts);
rt_uint64_t ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec; rt_ktime_hrtimer_ndelay(ns);
rt_uint64_t tick = (ns * (1000UL * 1000)) / unit;
rt_cputime_sleep(tick);
if (rt_get_errno() == -RT_EINTR) if (rt_get_errno() == -RT_EINTR)
{ {
if (rmtp) if (rmtp)
{ {
uint64_t rmtp_cpu_tick = tick - clock_cpu_gettime(); rt_ktime_boottime_get_ns(&new_ts);
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);
if (rt_get_errno() == -RT_EINTR) rmtp->tv_sec = 0;
{ rmtp->tv_nsec =
if (rmtp) (old_ts.tv_nsec + ns) - ((new_ts.tv_sec - old_ts.tv_sec) * NANOSECOND_PER_SECOND + new_ts.tv_nsec);
{
tick = tick_old + tick - rt_tick_get(); if (rmtp->tv_nsec > NANOSECOND_PER_SECOND)
/* get the passed time */ {
rmtp->tv_sec = tick / RT_TICK_PER_SECOND; rmtp->tv_nsec %= NANOSECOND_PER_SECOND;
rmtp->tv_nsec = (tick % RT_TICK_PER_SECOND) * (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND); rmtp->tv_sec += rmtp->tv_nsec / NANOSECOND_PER_SECOND;
}
} }
rt_set_errno(EINTR); rt_set_errno(EINTR);
return -1; return -1;
} }
#endif
return 0; return 0;
} }
RTM_EXPORT(nanosleep); RTM_EXPORT(nanosleep);
#endif /* RT_USING_POSIX_DELAY */ #endif /* RT_USING_POSIX_DELAY */
#ifdef RT_USING_POSIX_CLOCK #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) 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) if (res == RT_NULL)
{ {
rt_set_errno(EFAULT); rt_set_errno(EFAULT);
@ -629,40 +513,29 @@ int clock_getres(clockid_t clockid, struct timespec *res)
switch (clockid) switch (clockid)
{ {
case CLOCK_REALTIME: case CLOCK_REALTIME: // use RTC
#ifndef RT_USING_CPUTIME case CLOCK_REALTIME_COARSE:
res->tv_sec = 0; return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMERES, res);
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
default: case CLOCK_MONOTONIC: // use cputimer
res->tv_sec = 0; case CLOCK_MONOTONIC_COARSE:
res->tv_nsec = 0; case CLOCK_MONOTONIC_RAW:
ret = -1; case CLOCK_BOOTTIME:
rt_set_errno(EINVAL); case CLOCK_PROCESS_CPUTIME_ID:
break; 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); RTM_EXPORT(clock_getres);
int clock_gettime(clockid_t clockid, struct timespec *tp) 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) if (tp == RT_NULL)
{ {
rt_set_errno(EFAULT); rt_set_errno(EFAULT);
@ -671,172 +544,117 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
switch (clockid) switch (clockid)
{ {
case CLOCK_REALTIME: case CLOCK_REALTIME: // use RTC
#ifndef RT_USING_CPUTIME case CLOCK_REALTIME_COARSE:
{ return _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, tp);
rt_tick_t tick;
rt_base_t level;
level = rt_hw_interrupt_disable(); case CLOCK_MONOTONIC: // use boottime
tick = rt_tick_get(); /* get tick */ case CLOCK_MONOTONIC_COARSE:
tp->tv_sec = _timevalue.tv_sec + tick / RT_TICK_PER_SECOND; case CLOCK_MONOTONIC_RAW:
tp->tv_nsec = (_timevalue.tv_usec + (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK) * 1000U; case CLOCK_BOOTTIME:
rt_hw_interrupt_enable(level); return rt_ktime_boottime_get_ns(tp);
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;
unit = clock_cpu_getres(); case CLOCK_PROCESS_CPUTIME_ID:
cpu_tick = clock_cpu_gettime(); 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; default:
tp->tv_nsec = ((uint64_t)((cpu_tick * unit) / (1000UL * 1000))) % NANOSECOND_PER_SECOND; tp->tv_sec = 0;
} tp->tv_nsec = 0;
break; rt_set_errno(EINVAL);
#endif return -1;
default:
tp->tv_sec = 0;
tp->tv_nsec = 0;
rt_set_errno(EINVAL);
ret = -1;
} }
return ret;
#endif /* RT_USING_RTC */
} }
RTM_EXPORT(clock_gettime); RTM_EXPORT(clock_gettime);
int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp) int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp, struct timespec *rmtp)
{ {
#ifndef RT_USING_RTC struct timespec ts = {0};
LOG_W(_WARNING_NO_RTC); rt_err_t err;
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);
if (rt_get_errno() == -RT_EINTR) if (rqtp == RT_NULL)
{
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))
{ {
rt_set_errno(EFAULT); rt_set_errno(EFAULT);
return -1; return -1;
} }
/* get second */ if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_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)
{ {
/* set realtime seconds */ rt_set_errno(EINVAL);
if(rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second) == RT_EOK) return -1;
{
return 0;
}
} }
return -1; switch (clockid)
#endif /* RT_USING_RTC */ {
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); RTM_EXPORT(clock_settime);
@ -884,18 +702,12 @@ RTM_EXPORT(rt_timespec_to_tick);
struct timer_obj struct timer_obj
{ {
union struct rt_ktime_hrtimer hrtimer;
{
struct rt_timer timer;
#ifdef RT_USING_CPUTIME
struct rt_cputimer cputimer;
#endif
};
void (*sigev_notify_function)(union sigval val); void (*sigev_notify_function)(union sigval val);
union sigval val; union sigval val;
struct timespec interval; /* Reload value */ struct timespec interval; /* Reload value */
struct timespec value; /* 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; rt_uint32_t status;
int sigev_signo; int sigev_signo;
clockid_t clockid; clockid_t clockid;
@ -915,21 +727,13 @@ static void rtthread_timer_wrapper(void *timerobj)
timer->status = NOT_ACTIVE; timer->status = NOT_ACTIVE;
} }
#ifdef RT_USING_CPUTIME timer->reload = ((timer->interval.tv_sec * NANOSECOND_PER_SECOND + timer->interval.tv_nsec) * RT_KTIME_RESMUL) /
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) 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(); rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
if (timer->reload) rt_ktime_hrtimer_start(&timer->hrtimer);
rt_cputimer_control(&timer->cputimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
} }
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 #ifdef RT_USING_SMART
sys_kill(timer->pid, timer->sigev_signo); sys_kill(timer->pid, timer->sigev_signo);
#else #else
@ -960,14 +764,33 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
struct timer_obj *timer; struct timer_obj *timer;
char timername[RT_NAME_MAX] = {0}; char timername[RT_NAME_MAX] = {0};
if (clockid > CLOCK_ID_MAX || if (evp == RT_NULL || timerid == RT_NULL)
(evp->sigev_notify != SIGEV_NONE &&
evp->sigev_notify != SIGEV_SIGNAL))
{ {
rt_set_errno(EINVAL); rt_set_errno(EINVAL);
return -1; 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)); timer = rt_malloc(sizeof(struct timer_obj));
if(timer == RT_NULL) 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->status = NOT_ACTIVE;
timer->clockid = clockid; timer->clockid = clockid;
#ifdef RT_USING_CPUTIME rt_ktime_hrtimer_init(&timer->hrtimer, timername, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) rtthread_timer_wrapper, timer);
{
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);
}
_timerid = resource_id_get(&id_timer); _timerid = resource_id_get(&id_timer);
if (_timerid < 0) if (_timerid < 0)
@ -1048,28 +860,14 @@ int timer_delete(timer_t timerid)
return -1; return -1;
} }
#ifdef RT_USING_CPUTIME if (timer->status == ACTIVE)
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout())
{ {
if (timer->status == ACTIVE) timer->status = NOT_ACTIVE;
{ rt_ktime_hrtimer_stop(&timer->hrtimer);
timer->status = NOT_ACTIVE;
rt_cputimer_stop(&timer->cputimer);
}
rt_cputimer_detach(&timer->cputimer);
} }
else rt_ktime_hrtimer_detach(&timer->hrtimer);
#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_free(timer);
return 0; return 0;
} }
RTM_EXPORT(timer_delete); RTM_EXPORT(timer_delete);
@ -1111,45 +909,11 @@ int timer_gettime(timer_t timerid, struct itimerspec *its)
if (timer->status == ACTIVE) if (timer->status == ACTIVE)
{ {
#ifdef RT_USING_CPUTIME unsigned long remain_cnt;
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) 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;
rt_uint64_t remain_tick; seconds = nanoseconds / NANOSECOND_PER_SECOND;
rt_uint64_t remaining; nanoseconds = nanoseconds % NANOSECOND_PER_SECOND;
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;
}
its->it_value.tv_sec = (rt_int32_t)seconds; its->it_value.tv_sec = (rt_int32_t)seconds;
its->it_value.tv_nsec = (rt_int32_t)nanoseconds; 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, int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
struct itimerspec *ovalue) struct itimerspec *ovalue)
{ {
struct timespec ts = {0};
rt_err_t err = RT_EOK;
struct timer_obj *timer; struct timer_obj *timer;
timer = _g_timerid[(rt_ubase_t)timerid]; timer = _g_timerid[(rt_ubase_t)timerid];
if (timer == NULL || if (timer == NULL ||
@ -1199,97 +966,61 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
{ {
if (timer->status == ACTIVE) if (timer->status == ACTIVE)
{ {
#ifdef RT_USING_CPUTIME rt_ktime_hrtimer_stop(&timer->hrtimer);
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout())
rt_cputimer_stop(&timer->cputimer);
else
#endif /* RT_USING_CPUTIME */
rt_timer_stop(&timer->timer);
} }
timer->status = NOT_ACTIVE; timer->status = NOT_ACTIVE;
return 0; return 0;
} }
/* calculate timer period(tick); To avoid lost of accuracy, because "RT_TICK_PER_SECOND" maybe 100, 1000, 1024 and so on. switch (timer->clockid)
*
* 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())
{ {
rt_uint64_t tick; case CLOCK_REALTIME:
uint64_t unit = clock_cpu_getres(); case CLOCK_REALTIME_ALARM:
if (flags & TIMER_ABSTIME)
tick = ((value->it_value.tv_sec * NANOSECOND_PER_SECOND + value->it_value.tv_nsec) * (1000UL * 1000)) / unit; err = _control_rtc(RT_DEVICE_CTRL_RTC_GET_TIMESPEC, &ts);
if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) break;
{ case CLOCK_MONOTONIC:
tick -= clock_cpu_gettime(); case CLOCK_BOOTTIME:
} case CLOCK_BOOTTIME_ALARM:
timer->reload = tick; case CLOCK_PROCESS_CPUTIME_ID:
} case CLOCK_THREAD_CPUTIME_ID:
else if (flags & TIMER_ABSTIME)
#endif /* RT_USING_CPUTIME */ err = rt_ktime_boottime_get_ns(&ts);
{ break;
if ((flags & TIMER_ABSTIME) == TIMER_ABSTIME) default:
{ rt_set_errno(EINVAL);
#ifndef RT_USING_RTC
LOG_W(_WARNING_NO_RTC);
return -1; 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->interval.tv_nsec = value->it_interval.tv_nsec;
timer->value.tv_sec = value->it_value.tv_sec; timer->value.tv_sec = value->it_value.tv_sec;
timer->value.tv_nsec = value->it_value.tv_nsec; timer->value.tv_nsec = value->it_value.tv_nsec;
if (timer->status == ACTIVE) if (timer->status == ACTIVE)
{ {
#ifdef RT_USING_CPUTIME rt_ktime_hrtimer_stop(&timer->hrtimer);
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout())
rt_cputimer_stop(&timer->cputimer);
else
#endif /* RT_USING_CPUTIME */
rt_timer_stop(&timer->timer);
} }
timer->status = ACTIVE; timer->status = ACTIVE;
#ifdef RT_USING_CPUTIME if ((value->it_interval.tv_sec == 0) && (value->it_interval.tv_nsec == 0))
if (timer->clockid == CLOCK_CPUTIME_ID && clock_cpu_issettimeout()) rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_ONESHOT, RT_NULL);
{
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);
}
else else
#endif /* RT_USING_CPUTIME */ rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_PERIODIC, RT_NULL);
{
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_timer_control(&timer->timer, RT_TIMER_CTRL_SET_TIME, &(timer->reload)); rt_ktime_hrtimer_control(&timer->hrtimer, RT_TIMER_CTRL_SET_TIME, &(timer->reload));
rt_timer_start(&timer->timer); rt_ktime_hrtimer_start(&timer->hrtimer);
}
return 0; return 0;
} }

View File

@ -139,8 +139,12 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) #if defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER)
/* POSIX clock and timer */ /* POSIX clock and timer */
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 0
#endif /* CLOCK_REALTIME_COARSE */
#ifndef CLOCK_REALTIME #ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1 #define CLOCK_REALTIME 1
#endif /* CLOCK_REALTIME */ #endif /* CLOCK_REALTIME */
#define CLOCK_CPUTIME_ID 2 #define CLOCK_CPUTIME_ID 2
@ -150,13 +154,37 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#endif /* CLOCK_PROCESS_CPUTIME_ID */ #endif /* CLOCK_PROCESS_CPUTIME_ID */
#ifndef CLOCK_THREAD_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 */ #endif /* CLOCK_THREAD_CPUTIME_ID */
#ifndef CLOCK_MONOTONIC #ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 4 #define CLOCK_MONOTONIC 4
#endif /* CLOCK_MONOTONIC */ #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 #ifndef TIMER_ABSTIME
#define TIMER_ABSTIME 4 #define TIMER_ABSTIME 4
#endif /* TIMER_ABSTIME */ #endif /* TIMER_ABSTIME */
@ -166,6 +194,11 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#else #else
#define CLOCK_ID_MAX CLOCK_MONOTONIC #define CLOCK_ID_MAX CLOCK_MONOTONIC
#endif #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) */ #endif /* defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) */
#ifdef RT_USING_POSIX_CLOCK #ifdef RT_USING_POSIX_CLOCK

View File

@ -172,7 +172,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *ti
if (timeout) 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); ret = rt_signal_wait(set, info, tick);

View File

@ -28,7 +28,6 @@ static uint64_t get_ticks()
int tick_isr(void) int tick_isr(void)
{ {
// uint64_t core_id = current_coreid(); // uint64_t core_id = current_coreid();
int tick_cycles = 40000;
// clint->mtimecmp[core_id] += tick_cycles; // clint->mtimecmp[core_id] += tick_cycles;
rt_tick_increase(); rt_tick_increase();
sbi_set_timer(get_ticks() + tick_cycles); sbi_set_timer(get_ticks() + tick_cycles);
@ -41,14 +40,12 @@ int rt_hw_tick_init(void)
{ {
/* Read core id */ /* Read core id */
// unsigned long core_id = current_coreid(); // unsigned long core_id = current_coreid();
unsigned long interval = 1000/RT_TICK_PER_SECOND;
/* Clear the Supervisor-Timer bit in SIE */ /* Clear the Supervisor-Timer bit in SIE */
clear_csr(sie, SIP_STIP); clear_csr(sie, SIP_STIP);
/* calculate the tick cycles */ /* calculate the tick cycles */
// tick_cycles = interval * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000ULL - 1; tick_cycles = CPUTIME_TIMER_FREQ / RT_TICK_PER_SECOND;
tick_cycles = 40000;
/* Set timer */ /* Set timer */
sbi_set_timer(get_ticks() + tick_cycles); sbi_set_timer(get_ticks() + tick_cycles);