NuttX的学习笔记 14

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yt454287063/article/details/81463438

下面来分析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)&notify));
  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, &notify, &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();
}

这章就到这里吧。


就到这里吧。

猜你喜欢

转载自blog.csdn.net/yt454287063/article/details/81463438
今日推荐