下面来分析timer这个例子吧。
int timer_main(int argc, char *argv[])
{
struct timer_notify_s notify;
struct sigaction act;
int ret;
int fd;
int i;
/* Open the timer device */
printf("Open %s\n", CONFIG_EXAMPLES_TIMER_DEVNAME);
fd = open(CONFIG_EXAMPLES_TIMER_DEVNAME, O_RDONLY);
打开定时器接口。
if (fd < 0)
{
fprintf(stderr, "ERROR: Failed to open %s: %d\n",
CONFIG_EXAMPLES_TIMER_DEVNAME, errno);
return EXIT_FAILURE;
}
打开定时器接口。
/* Show the timer status before setting the timer interval */
timer_status(fd);
显示定时器状态。
/* Set the timer interval */
printf("Set timer interval to %lu\n",
(unsigned long)CONFIG_EXAMPLES_TIMER_INTERVAL);
ret = ioctl(fd, TCIOC_SETTIMEOUT, CONFIG_EXAMPLES_TIMER_INTERVAL);
if (ret < 0)
{
fprintf(stderr, "ERROR: Failed to set the timer interval: %d\n", errno);
close(fd);
return EXIT_FAILURE;
}
设定定时时间。
/* Show the timer status before attaching the timer handler */
timer_status(fd);
显示定时器状态。
/* Attach a signal handler to catch the notifications. NOTE that using
* signal handler is very slow. A much more efficient thing to do is to
* create a separate pthread that waits on sigwaitinfo() for timer events.
* Much less overhead in that case.
*/
/* 附加信号处理程序以捕获通知。注意使用信号处理程序会非常的慢,更有效的方法是,创建一个
* 单独的线程使用sigwaitinfo()等待定时器事件。在这种情况下,开销要少得多。
*/
g_nsignals = 0;
act.sa_sigaction = timer_sighandler;
act.sa_flags = SA_SIGINFO;
这里涉及到了结构体,其内容:
/* The following structure defines the action to take for given signal */
struct sigaction
{
union
{
_sa_handler_t _sa_handler; // 联合体,这两个东西地址相同。
_sa_sigaction_t _sa_sigaction; //
} sa_u;
sigset_t sa_mask;
int sa_flags;
};
(void)sigfillset(&act.sa_mask);
(void)sigdelset(&act.sa_mask, CONFIG_EXAMPLES_TIMER_SIGNO);
初始化信号,此时信号为0xFFFFFFFF,删除第17个信号后,结果为0xFFFDFFFF
ret = sigaction(CONFIG_EXAMPLES_TIMER_SIGNO, &act, NULL);
if (ret != OK)
{
fprintf(stderr, "ERROR: Fsigaction failed: %d\n", errno);
close(fd);
return EXIT_FAILURE;
}
关联信号和句柄。
/* Register a callback for notifications using the configured signal.
* 使用配置的信号注册通知回调。
* NOTE: If no callback is attached, the timer stop at the first interrupt.
* 注意:如果没有设置回叫,定时器将在第一次中断时停止。
*/
printf("Attach timer handler\n");
notify.arg = NULL;
notify.pid = getpid();
notify.signo = CONFIG_EXAMPLES_TIMER_SIGNO;
ret = ioctl(fd, TCIOC_NOTIFICATION, (unsigned long)((uintptr_t)¬ify));
if (ret < 0)
{
fprintf(stderr, "ERROR: Failed to set the timer handler: %d\n", errno);
close(fd);
return EXIT_FAILURE;
}
关联定时器和通知。
/* Show the timer status before starting */
timer_status(fd);
/* Start the timer */
printf("Start the timer\n");
ret = ioctl(fd, TCIOC_START, 0);
if (ret < 0)
{
fprintf(stderr, "ERROR: Failed to start the timer: %d\n", errno);
close(fd);
return EXIT_FAILURE;
}
启动定时器
/* Wait a bit showing timer status */
for (i = 0; i < CONFIG_EXAMPLES_TIMER_NSAMPLES; i++)
{
usleep(CONFIG_EXAMPLES_TIMER_DELAY);
timer_status(fd);
}
做10次循环,每次延时100ms。
/* Stop the timer */
printf("Stop the timer\n");
ret = ioctl(fd, TCIOC_STOP, 0);
if (ret < 0)
{
fprintf(stderr, "ERROR: Failed to stop the timer: %d\n", errno);
close(fd);
return EXIT_FAILURE;
}
关闭定时器
/* Detach the signal handler */
act.sa_handler = SIG_DFL;
(void)sigaction(CONFIG_EXAMPLES_TIMER_SIGNO, &act, NULL);
/* Show the timer status before starting */
timer_status(fd);
取消信号和句柄的关联
/* Close the timer driver */
printf("Finished\n");
close(fd);
return EXIT_SUCCESS;
}
最后关闭接口。
然后这个东西好像和我正在看的这个标题没什么关系啊。
就当白看了。
2.6.1 clock_settime
int clock_settime(clockid_t clockid, const struct timespec *tp);
位置在:
nuttx\sched\clock\clock_gettime.c:68
根据源代码来看,clock_id
只有一个可能,那就是CLOCK_REALTIME
,第二个参数是一个结构体指针,结构体如下:
struct timespec
{
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
有两个值,一个秒级,一个是纳秒级。来试一下么。写个例子。就写到example
里。名称我都想好了,就叫Clocks and Timers
。然后把本章的所有函数都写进去。
void clock_settime_test(void) {
struct timespec tp;
int ret = 0;
tp.tv_sec = 23;
tp.tv_nsec = 1000000 * tp.tv_sec;
printf(" clock_settime_test: tp.tv_nsec = %d\n", tp.tv_nsec);
printf(" clock_settime_test: tp.tv_sec = %d\n", tp.tv_sec);
printf(" clock_settime_test: clock_settime(CLOCK_REALTIME, &tp)\n");
ret = clock_settime(CLOCK_REALTIME, &tp);
if (ret < 0) {
int err = -errno;
if (err == EINVAL) {
printf(" clock_settime_test: clock_settime() fail, errno = %s\n",
EINVAL_STR);
}
}
printf(" clock_settime_test: ret = %s\n", "OK");
}
运行
2.6.1 clock_settime
clock_settime_test: tp.tv_nsec = 23000000
clock_settime_test: tp.tv_sec = 23
clock_settime_test: clock_settime(CLOCK_REALTIME, &tp)
clock_settime_test: ret = OK
效果并看不到。
2.6.2 clock_gettime
#include <time.h>
int clock_gettime(clockid_t clockid, struct timespec *tp);
用这个就可以读出刚刚设定的东西。再写一个试试。
void clock_gettime_test(void) {
struct timespec tp;
int ret = 0;
printf(" clock_gettime_test: clock_settime(CLOCK_REALTIME, &tp)\n");
ret = clock_gettime(CLOCK_REALTIME, &tp);
if (ret < 0) {
int err = -errno;
if (err == EINVAL) {
printf(" clock_gettime_test: clock_settime() fail, errno = %s\n",
EINVAL_STR);
}
}
printf(" clock_gettime_test: ret = %s\n", "OK");
printf(" clock_gettime_test: tp.tv_nsec = %d\n", tp.tv_nsec);
printf(" clock_gettime_test: tp.tv_sec = %d\n", tp.tv_sec);
}
调用两个函数中间加上延迟。运行
2.6.1 clock_settime
clock_settime_test: tp.tv_nsec = 23000000
clock_settime_test: tp.tv_sec = 23
clock_settime_test: clock_settime(CLOCK_REALTIME, &tp)
clock_settime_test: ret = OK
sleep 1 second
sleep 1 second
2.6.2 clock_gettime
clock_gettime_test: clock_gettime(CLOCK_REALTIME, &tp)
clock_gettime_test: ret = OK
clock_gettime_test: tp.tv_nsec = 43000000
clock_gettime_test: tp.tv_sec = 25
嗯,效果还不错。
下一个。
2.6.3 clock_getres
#include <time.h>
int clock_getres(clockid_t clockid, struct timespec *res);
写一个这样的代码
void clock_getres_test(void) {
struct timespec res;
int ret = 0;
printf(" clock_getres_test: clock_getres(CLOCK_REALTIME, &tp)\n");
ret = clock_getres(CLOCK_REALTIME, &res);
if (ret < 0) {
int err = -errno;
if (err == EINVAL) {
printf(" clock_gettime_test: clock_getres() fail, errno = %s\n",
EINVAL_STR);
}
}
printf(" clock_getres_test: ret = %s\n", "OK");
printf(" clock_getres_test: tp.tv_nsec = %d\n", res.tv_nsec);
printf(" clock_getres_test: tp.tv_sec = %d\n", res.tv_sec);
}
运行结果:
2.6.3 clock_getres
clock_getres_test: clock_getres(CLOCK_REALTIME, &tp)
clock_getres_test: ret = OK
clock_getres_test: tp.tv_nsec = 10000000
clock_getres_test: tp.tv_sec = 0
我在Ubuntu上跑了这个函数,输出为:
2.6.3 clock_getres
clock_getres_test: clock_getres(CLOCK_REALTIME, &tp)
clock_getres_test: ret = OK
clock_getres_test: tp.tv_nsec = 1
clock_getres_test: tp.tv_sec = 0
这个函数是为了得到时钟精度,PC端有1n秒的精度,而NuttX只有10ms的精度。这差别。。。。
2.6.4 mktime
#include <time.h>
time_t mktime(struct tm *tp);
看内容。
time_t mktime(FAR struct tm *tp)
{
time_t ret;
time_t jdn;
/* Get the EPOCH-relative julian date from the calendar year,
* month, and date
*/
jdn = clock_calendar2utc(tp->tm_year + 1900, tp->tm_mon, tp->tm_mday);
linfo("jdn=%d tm_year=%d tm_mon=%d tm_mday=%d\n",
(int)jdn, tp->tm_year, tp->tm_mon, tp->tm_mday);
/* Return the seconds into the julian day. */
ret = ((jdn * 24 + tp->tm_hour) * 60 + tp->tm_min) * 60 + tp->tm_sec;
linfo("ret=%d tm_hour=%d tm_min=%d tm_sec=%d\n",
(int)ret, tp->tm_hour, tp->tm_min, tp->tm_sec);
return ret;
}
看起来它可以吧类似 1996-1-6 22:30:10
转换成从1970年到现在为止的秒数。
写一个试试看。
因为mktime
内部增加了1900年,所以,我想要在外面减去1900年。
void mktime_test(void) {
FAR struct tm t;
t.tm_sec = 0;
t.tm_min = 0;
t.tm_hour = 0;
t.tm_mday = 1;
t.tm_mon = 1;
t.tm_year = 1970 - 1900;
time_t tt;
printf(" mktime_test: t = %4d-%2d-%2d %2d:%2d:%2d\n", t.tm_year + 1900, t.tm_mon,
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
printf(" mktime_test: tt = Run mktime(&t)\n");
tt = mktime(&t);
printf(" mktime_test: tt = %ld\n", tt);
}
输出:
2.6.4 mktime
mktime_test: t = 1970- 1- 1 0: 0: 0
mktime_test: tt = Run mktime(&t)
mktime_test: tt = 2678400
居然不是0,这个2672400应该可以反推一下。
转换下来近似一个月。所以再剪掉一个月。
结果就是标准的0s了:
2.6.4 mktime
mktime_test: t = 1970- 1- 1 0: 0: 0
mktime_test: tt = Run mktime(&t)
mktime_test: tt = 0
和Ubuntu上跑出来结果是一样的。
这个时间差其实在结构体定义中有写:
struct tm
{
int tm_sec; /* Seconds (0-61, allows for leap seconds) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Years since 1900 */
};
所以1月就是0 而年也是按照1900的差来记录的。
OK,过。
2.6.5 gmtime
#include <time.h>
FAR struct tm *gmtime(FAR const time_t *timep);
这个参数和函数返回类型和上一个应该是正好相反的。
void gmtime_test(void) {
FAR struct tm *t;
time_t tt;
tt = 123456789;
printf(" gmtime_test: tt = %ld\n", tt);
printf(" gmtime_test: t = Run gmtime(&tt)\n");
t = gmtime(&tt);
printf(" gmtime_test: t = %4d-%2d-%2d %2d:%2d:%2d\n", t->tm_year + 1900,
t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
}
运行。
2.6.5 gmtime
gmtime_test: tt = 123456789
gmtime_test: t = Run gmtime(&tt)
gmtime_test: t = 1973-11-29 21:33: 9
Google unixtimestamp。找个在线网站转换一下,结果是一样的。
2.6.6 localtime
#include <time.h>
#ifdef CONFIG_LIBC_LOCALTIME
# define localtime(c) gmtime(c)
#else
FAR struct tm *localtime(FAR const time_t *timep);
#endif
配置一下CONFIG_LIBC_LOCALTIME
。
再编译,出现了多重编译的错误。很麻烦,先跳过这个。
2.6.7 asctime
#include <time.h>
#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
FAR char *asctime(FAR const struct tm *tp);
#endif
写一个这样的:
void asctime_test(void) {
time_t tt;
FAR struct tm *t;
tt = time(NULL);
printf(" asctime_test: tt = %ld\n", tt);
printf(" asctime_test: printf asctime(gmtime(&tt))\n");
printf(" asctime_test: %s\n", asctime(gmtime(&tt)));
}
输出
2.6.7 asctime
asctime_test: tt = 33
asctime_test: printf asctime(gmtime(&tt))
asctime_test: Sun Jan 1 0:0:33 1970
时间不对,不应该是星期天。
所有查到的资料都显示是周2。可能我忘记开启什么了。检查一下。结果发现开头说的两个定义一个定义都没有。第一个报错,那就定义第二个吧。
具体位置
> Library Routines > Time/Time Zone Support
打开后再编译。
2.6.7 asctime
asctime_test: tt = 35
asctime_test: printf asctime(gmtime(&tt))
asctime_test: Thu Jan 1 0:0:35 1970
这就对了。
跳过几个。
2.6.13 timer_create
2.6.14 timer_delete
2.6.15 timer_settime
2.6.16 timer_gettime
2.6.17 timer_getoverrun
ostest里的例子posix_timer可以拿来参考。
void timer_test(void)
{
sigset_t set;
struct sigaction act;
struct sigaction oact;
struct sigevent notify;
struct itimerspec timer;
timer_t timerid;
int status;
int i;
printf("timer_test: Initializing semaphore to 0\n" );
sem_init(&sem, 0, 0); // 初始化信号量
/* Start waiter thread */
printf("timer_test: Unmasking signal %d\n" , MY_TIMER_SIGNAL);
(void)sigemptyset(&set); // 清空信号 set: 32'b00000000000000000000000000000000
(void)sigaddset(&set, MY_TIMER_SIGNAL); // 增加信号 set: 32'b00000000000000100000000000000000
status = sigprocmask(SIG_UNBLOCK, &set, NULL); // 此任务的 sigprocmask &= 32'b11111111111111011111111111111111
if (status != OK)
{
printf("timer_test: ERROR sigprocmask failed, status=%d\n",
status);
}
printf("timer_test: Registering signal handler\n" ); // 注册信号句柄
act.sa_sigaction = timer_expiration; // 添加句柄
act.sa_flags = SA_SIGINFO;
(void)sigfillset(&act.sa_mask); // 置位信号 act.sa_mask: 32'b11111111111111111111111111111111
(void)sigdelset(&act.sa_mask, MY_TIMER_SIGNAL); // 清除信号 act.sa_mask: 32'b11111111111111011111111111111111
status = sigaction(MY_TIMER_SIGNAL, &act, &oact); // 注册信号句柄
if (status != OK)
{
printf("timer_test: ERROR sigaction failed, status=%d\n" , status);
}
#ifndef SDCC
printf("timer_test: oact.sigaction=%p oact.sa_flags=%x oact.sa_mask=%x\n",
oact.sa_sigaction, oact.sa_flags, oact.sa_mask);
#endif
/* Create the POSIX timer */
printf("timer_test: Creating timer\n" );
notify.sigev_notify = SIGEV_SIGNAL; // 设定定时器到时后会产生信号
notify.sigev_signo = MY_TIMER_SIGNAL; // 信号值
notify.sigev_value.sival_int = SIGVALUE_INT; // 信号携带的信息
#ifdef CONFIG_SIG_EVTHREAD
notify.sigev_notify_function = NULL;
notify.sigev_notify_attributes = NULL;
#endif
status = timer_create(CLOCK_REALTIME, ¬ify, &timerid); // 创建定时器
if (status != OK)
{
printf("timer_test: timer_create failed, errno=%d\n", errno);
goto errorout;
}
/* Start the POSIX timer */
printf("timer_test: Starting timer\n" );
timer.it_value.tv_sec = 2; // 设定时间2s
timer.it_value.tv_nsec = 0;
timer.it_interval.tv_sec = 2; // 设定之后的定时时间
timer.it_interval.tv_nsec = 0;
status = timer_settime(timerid, 0, &timer, NULL); // 设定定时器
if (status != OK)
{
printf("timer_test: timer_settime failed, errno=%d\n", errno);
goto errorout;
}
/* Take the semaphore */
for (i = 0; i < 5; i++)
{
printf("timer_test: Waiting on semaphore\n" );
FFLUSH();
status = sem_wait(&sem);
if (status != 0)
{
int error = errno;
if (error == EINTR)
{
printf("timer_test: sem_wait() successfully interrupted by signal\n" );
}
else
{
printf("timer_test: ERROR sem_wait failed, errno=%d\n" , error);
}
}
else
{
printf("timer_test: ERROR awakened with no error!\n" );
}
printf("timer_test: g_nsigreceived=%d\n", g_nsigreceived);
}
errorout:
sem_destroy(&sem);
/* Then delete the timer */
printf("timer_test: Deleting timer\n" );
status = timer_delete(timerid);
if (status != OK)
{
printf("timer_test: timer_create failed, errno=%d\n", errno);
}
/* Detach the signal handler */
act.sa_handler = SIG_DFL;
status = sigaction(MY_TIMER_SIGNAL, &act, &oact);
printf("timer_test: done\n" );
FFLUSH();
}
这章就到这里吧。
就到这里吧。