Oopenvela-robotfix compile error
8fa28318创建于 4月20日历史提交
/****************************************************************************
 * apps/testing/sched/timerjitter/timerjitter.c
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/clock.h>

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define DEFAULT_CLOCKID   CLOCK_REALTIME
#define DEFAULT_INTERVAL  (1000 * USEC_PER_TICK)
#define DEFAULT_ITERATION (USEC_PER_SEC / DEFAULT_INTERVAL)

/* Fix compilation error for Non-NuttX OS */
#ifndef FAR
  #define FAR
#endif

#ifndef USEC_PER_SEC
  #define USEC_PER_SEC 1000000
#endif

#ifndef NSEC_PER_SEC
  #define NSEC_PER_SEC 1000000000
#endif

/****************************************************************************
 * Private Type
 ****************************************************************************/

struct timerjitter_param_s
{
  clockid_t     clockid;
  unsigned int  interval;
  unsigned long max_cnt;
  unsigned long cur_cnt;
  double        avg;
  unsigned long max;
  unsigned long min;
  int           print;
  unsigned int  missed;
};

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/* Helper functions for timespec calculating */

static inline int64_t calc_diff(FAR const struct timespec *t1,
                                FAR const struct timespec *t2)
{
  int64_t diff;

  diff  = USEC_PER_SEC * (t1->tv_sec - t2->tv_sec);
  diff += (t1->tv_nsec - t2->tv_nsec) / 1000;

  return diff;
}

static inline void ts_norm(FAR struct timespec *ts)
{
  while (ts->tv_nsec >= NSEC_PER_SEC)
    {
      ts->tv_nsec -= NSEC_PER_SEC;
      ts->tv_sec++;
    }
}

static inline int ts_greater(FAR const struct timespec *a,
                             FAR const struct timespec *b)
{
  return (a->tv_sec > b->tv_sec) ||
         (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec);
}

static inline void calc_next(FAR struct timespec *t,
                             FAR struct timespec *intv)
{
  t->tv_sec  += intv->tv_sec;
  t->tv_nsec += intv->tv_nsec;
  ts_norm(t);
}

/* Helper function for number parsing */

static unsigned long get_num(FAR const char *str)
{
  FAR char     *end;
  unsigned long val;

  if (!str)
    {
      return 0;
    }

  val = strtoul(str, &end, 0);
  if (!val || val == (unsigned long)-1)
    {
      return 0;
    }

  return val;
}

static FAR void *timerjitter(FAR void *arg)
{
  FAR struct timerjitter_param_s *param = arg;
  struct timespec   now;
  struct timespec   next;
  struct timespec   intv;
  struct itimerspec tspec;
  sigset_t          sigset;
  timer_t           timer;
  int64_t           diff;
  int               sigs;
  int               ret;
  struct sigevent   sigev =
  {
    0
  };

  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  sigprocmask(SIG_BLOCK, &sigset, NULL);

  intv.tv_sec  = param->interval / USEC_PER_SEC;
  intv.tv_nsec = (param->interval % USEC_PER_SEC) * 1000;

  sigev.sigev_notify = SIGEV_SIGNAL;
  sigev.sigev_signo  = SIGALRM;

  ret = timer_create(param->clockid, &sigev, &timer);

  if (ret != 0)
    {
      printf("timer_create failed %d\n", ret);
      return NULL;
    }

  ret = clock_gettime(param->clockid, &now);

  if (ret)
    {
      printf("clock_gettime failed %d\n", ret);
    }

  next = now;
  calc_next(&next, &intv);

  /* Set cyclic timer */

  tspec.it_interval = intv;

  /* Using TIMER_ABSTIME */

  tspec.it_value = next;
  ret = timer_settime(timer, TIMER_ABSTIME, &tspec, NULL);

  if (ret)
    {
      printf("timer_settime failed %d\n", ret);
      return NULL;
    }

  param->avg = 0;
  param->max = 0;
  param->min = (unsigned long)-1;

  while (param->cur_cnt++ < param->max_cnt)
    {
      /* Wait for SIGALRM */

      if (sigwait(&sigset, &sigs) < 0)
        {
          printf("sig wait failed\n");
          break;
        }

      ret = clock_gettime(param->clockid, &now);
      if (ret)
        {
          printf("clock_gettime failed %d\n", ret);
        }

      diff = calc_diff(&now, &next);
      if (param->print)
        {
          printf("diff %ju, now %ju.%09lu\n", (uintmax_t)diff,
                 (uintmax_t)now.tv_sec, now.tv_nsec);
        }

      if (diff > param->max)
        {
          param->max = diff;
        }

      if (diff < param->min)
        {
          param->min = diff;
        }

      param->avg += diff;

      /* Calculate next = next + intv */

      calc_next(&next, &intv);

      /* Calibrate if we miss current time frame */

      while (ts_greater(&now, &next))
        {
          calc_next(&next, &intv);
          printf("time frame missed %u\n", ++param->missed);
        }
    }

  timer_delete(timer);
  param->avg = param->avg / param->cur_cnt;
  return NULL;
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * timerjitter main
 ****************************************************************************/

int main(int argc, FAR char *argv[])
{
  struct timerjitter_param_s param =
  {
    .clockid  = DEFAULT_CLOCKID,
    .interval = DEFAULT_INTERVAL,
    .max_cnt  = DEFAULT_ITERATION,
    .cur_cnt  = 0,
    .print    = 0,
    .missed   = 0
  };

  pthread_attr_t  attr;
  pthread_t       thread;
  sigset_t        sigset;
  FAR const char *arg;
  int             ret;

  /* Mask SIGALRM at first */

  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  sigprocmask(SIG_BLOCK, &sigset, NULL);

  if (argc > 1)
    {
      while ((arg = argv[1]) != NULL)
        {
          if (*arg != '-')
            {
              break;
            }

          for (; ; )
            {
              switch (*++arg)
                {
                  case 0:
                    break;
                  case 'p':
                    param.print = 1;
                    continue;
                  case 'm':
                    param.clockid = CLOCK_MONOTONIC;
                    continue;
                  case 'r':
                    param.clockid = CLOCK_REALTIME;
                    continue;
                  case 'h':
                    printf(
                    "usage: timerjitter [-pmr] [interval(us)] [iteration]\n"
                    "-p: print time diff between two iteration\n"
                    "-m: use CLOCK_MONOTONIC\n"
                    "-r: use CLOCK_REALTIME\n"
                    "");
                    return 0;
                  default:
                    printf("Unknown flag '%s'", arg);
                    return -1;
                }
              break;
            }

          /* Find next parameters */

          argv++;
          argc--;
        }

      if (argc > 1)
        {
          param.interval = get_num(argv[1]);
        }

      if (argc > 2)
        {
          param.max_cnt = get_num(argv[2]);
        }
    }

  ret = pthread_attr_init(&attr);
  if (ret)
    {
      printf("pthread_attr_init failed %d\n", ret);
    }

  ret = pthread_create(&thread, &attr, timerjitter, &param);
  if (ret)
    {
      printf("thread created failed %d\n", ret);
    }

  pthread_join(thread, NULL);

  ret = pthread_attr_destroy(&attr);
  if (ret)
    {
      printf("pthread_attr_destroy failed %d\n", ret);
    }

  printf("timer jitter in %lu run:\n", param.max_cnt);
  printf("(latency/us) min: %lu, avg: %.0lf, max %lu\n",
         param.min, param.avg, param.max);

  return 0;
}