This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 8a131cb7e testing/drivertest: add timer driver test
8a131cb7e is described below

commit 8a131cb7e73df9bb15e0cbac25d310821553f4ec
Author: cuiziwei <[email protected]>
AuthorDate: Fri Feb 3 14:51:56 2023 +0800

    testing/drivertest: add timer driver test
    
    Signed-off-by: cuiziwei <[email protected]>
---
 testing/drivertest/Makefile           |   6 +
 testing/drivertest/drivertest_timer.c | 308 ++++++++++++++++++++++++++++++++++
 2 files changed, 314 insertions(+)

diff --git a/testing/drivertest/Makefile b/testing/drivertest/Makefile
index 004cab21c..a1e735a6c 100644
--- a/testing/drivertest/Makefile
+++ b/testing/drivertest/Makefile
@@ -34,4 +34,10 @@ MAINSRC  += drivertest_rtc.c
 PROGNAME += cmocka_driver_rtc
 endif
 
+ifneq ($(CONFIG_TIMER),)
+MAINSRC  += drivertest_timer.c
+PROGNAME += cmocka_driver_timer
+endif
+
+
 include $(APPDIR)/Application.mk
diff --git a/testing/drivertest/drivertest_timer.c 
b/testing/drivertest/drivertest_timer.c
new file mode 100644
index 000000000..676964b1e
--- /dev/null
+++ b/testing/drivertest/drivertest_timer.c
@@ -0,0 +1,308 @@
+/****************************************************************************
+ * apps/testing/drivertest/drivertest_timer.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/config.h>
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+
+#include <nuttx/timers/timer.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TIMER_DEFAULT_DEVPATH "/dev/timer0"
+#define TIMER_DEFAULT_INTERVAL 1000000
+#define TIMER_DEFAULT_NSAMPLES 20
+#define TIMER_DEFAULT_SIGNO 17
+#define TIMER_DEFAULT_RANGE 1
+
+#define OPTARG_TO_VALUE(value, type, base)                            \
+  do                                                                  \
+    {                                                                 \
+      FAR char *ptr;                                                  \
+      value = (type)strtoul(optarg, &ptr, base);                      \
+      if (*ptr != '\0')                                               \
+        {                                                             \
+          printf("Parameter error: -%c %s\n", ch, optarg);            \
+          show_usage(argv[0], timer_state, EXIT_FAILURE);             \
+        }                                                             \
+    } while (0)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct timer_state_s
+{
+  char devpath[PATH_MAX];
+  uint32_t interval;
+  uint32_t nsamples;
+  uint32_t signo;
+  uint32_t range;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: get_timestamp
+ ****************************************************************************/
+
+static uint32_t get_timestamp(void)
+{
+  struct timespec ts;
+  uint32_t ms;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+  return ms;
+}
+
+/****************************************************************************
+ * Name: show_usage
+ ****************************************************************************/
+
+static void show_usage(FAR const char *progname,
+                       FAR struct timer_state_s *timer_state, int exitcode)
+{
+  printf("Usage: %s"
+         " -d <devpath> -i <interval> -n <nsamples> -r <range> -s <signo>\n",
+         progname);
+  printf("  [-d devpath] selects the TIMER device.\n"
+         "  Default: %s Current: %s\n",
+         TIMER_DEFAULT_DEVPATH, timer_state->devpath);
+  printf("  [-i interval] timer interval in microseconds.\n"
+         "  Default: %d Current: %" PRIu32 "\n",
+         TIMER_DEFAULT_INTERVAL, timer_state->interval);
+  printf("  [-n nsamples] timer samples will be collected numbers.\n"
+         "  Default: %d Current: %" PRIu32 "\n",
+         TIMER_DEFAULT_NSAMPLES, timer_state->nsamples);
+  printf("  [-r range] the max range of timer delay.\n"
+         "  Default: %d Current: %" PRIu32 "\n",
+         TIMER_DEFAULT_RANGE, timer_state->range);
+  printf("  [-s signo] used to notify the test of timer expiration events.\n"
+         "  Default: %d Current: %" PRIu32 "\n",
+         TIMER_DEFAULT_SIGNO, timer_state->signo);
+  printf("  [-h] = Shows this message and exits\n");
+
+  exit(exitcode);
+}
+
+/****************************************************************************
+ * Name: parse_commandline
+ ****************************************************************************/
+
+static void parse_commandline(FAR struct timer_state_s *timer_state,
+                              int argc, FAR char **argv)
+{
+  int ch;
+  int converted;
+
+  while ((ch = getopt(argc, argv, "d:i:n:r:s:h")) != ERROR)
+    {
+      switch (ch)
+        {
+          case 'd':
+            strncpy(timer_state->devpath, optarg,
+                    sizeof(timer_state->devpath));
+            timer_state->devpath[sizeof(timer_state->devpath) - 1] = '\0';
+            break;
+
+          case 'i':
+            OPTARG_TO_VALUE(converted, uint32_t, 10);
+            if (converted < 1 || converted > INT_MAX)
+              {
+                printf("signal out of range: %d\n", converted);
+                show_usage(argv[0], timer_state, EXIT_FAILURE);
+              }
+
+            timer_state->interval = (uint32_t)converted;
+            break;
+
+          case 'n':
+            OPTARG_TO_VALUE(converted, uint32_t, 10);
+            if (converted < 1 || converted > INT_MAX)
+              {
+                printf("signal out of range: %d\n", converted);
+                show_usage(argv[0], timer_state, EXIT_FAILURE);
+              }
+
+            timer_state->nsamples = (uint32_t)converted;
+            break;
+
+          case 'r':
+            OPTARG_TO_VALUE(converted, uint32_t, 10);
+            if (converted < 1 || converted > INT_MAX)
+              {
+                printf("signal out of range: %d\n", converted);
+                show_usage(argv[0], timer_state, EXIT_FAILURE);
+              }
+
+            timer_state->range = (uint32_t)converted;
+            break;
+
+          case 's':
+            OPTARG_TO_VALUE(converted, uint32_t, 10);
+            if (converted < 1 || converted > INT_MAX)
+              {
+                printf("signal out of range: %d\n", converted);
+                show_usage(argv[0], timer_state, EXIT_FAILURE);
+              }
+
+            timer_state->signo = (uint32_t)converted;
+            break;
+
+          case '?':
+            printf("Unsupported option: %s\n", optarg);
+            show_usage(argv[0], timer_state, EXIT_FAILURE);
+            break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: test_case_timer
+ ****************************************************************************/
+
+static void test_case_timer(FAR void **state)
+{
+  int i;
+  int fd;
+  int ret;
+  uint32_t range;
+  uint32_t tim;
+  struct sigaction act;
+  struct timer_notify_s notify;
+  FAR struct timer_state_s *timer_state;
+
+  timer_state = (FAR struct timer_state_s *)*state;
+
+  /* Open the timer device */
+
+  fd = open(timer_state->devpath, O_RDONLY);
+  assert_true(fd > 0);
+
+  /* Show the timer status before setting the timer interval */
+
+  ret = ioctl(fd, TCIOC_SETTIMEOUT, timer_state->interval);
+  assert_return_code(ret, OK);
+
+  act.sa_sigaction = NULL;
+  act.sa_flags     = SA_SIGINFO;
+  sigfillset(&act.sa_mask);
+  sigdelset(&act.sa_mask, timer_state->signo);
+
+  ret = sigaction(timer_state->signo, &act, NULL);
+  assert_in_range(ret, 0, timer_state->signo);
+
+  /* Register a callback for notifications using the configured signal.
+   * NOTE: If no callback is attached, the timer stop at the first interrupt.
+   */
+
+  notify.pid      = getpid();
+  notify.periodic = true;
+  notify.event.sigev_notify = SIGEV_SIGNAL;
+  notify.event.sigev_signo  = timer_state->signo;
+  notify.event.sigev_value.sival_ptr = NULL;
+
+  ret = ioctl(fd, TCIOC_NOTIFICATION, (unsigned long)((uintptr_t)&notify));
+  assert_return_code(ret, OK);
+
+  /* Start the timer */
+
+  ret = ioctl(fd, TCIOC_START, 0);
+  assert_return_code(ret, OK);
+
+  /* Set the timer interval */
+
+  for (i = 0; i < timer_state->nsamples; i++)
+    {
+      tim = get_timestamp();
+      usleep(2 * timer_state->interval);
+      tim = get_timestamp() - tim;
+      range = timer_state->interval / 1000 - tim;
+      assert_in_range(range, 0, timer_state->range);
+    }
+
+  /* Stop the timer */
+
+  ret = ioctl(fd, TCIOC_STOP, 0);
+  assert_return_code(ret, OK);
+
+  /* Detach the signal handler */
+
+  act.sa_handler = SIG_DFL;
+  sigaction(timer_state->signo, &act, NULL);
+
+  /* Close the timer driver */
+
+  close(fd);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: drivertest_timer_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  struct timer_state_s timer_state =
+  {
+    .devpath = TIMER_DEFAULT_DEVPATH,
+    .interval = TIMER_DEFAULT_INTERVAL,
+    .nsamples = TIMER_DEFAULT_NSAMPLES,
+    .range = TIMER_DEFAULT_RANGE,
+    .signo = TIMER_DEFAULT_SIGNO
+  };
+
+  parse_commandline(&timer_state, argc, argv);
+
+  const struct CMUnitTest tests[] =
+  {
+    cmocka_unit_test_prestate(test_case_timer, &timer_state)
+  };
+
+  return cmocka_run_group_tests(tests, NULL, NULL);
+}

Reply via email to