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 9246502ac drivertest/drivertest_uart: uart driver testcase
9246502ac is described below

commit 9246502acacb876085655862fa9b16444c712d19
Author: xinbingnan <[email protected]>
AuthorDate: Thu Oct 27 15:02:39 2022 +0800

    drivertest/drivertest_uart: uart driver testcase
    
    VELAPLATFO-4612
    
    There are three test.
    
    1. Write a long default string into the serial port.
    2. Read the default string given by the last test from the serial port.
    3. Manually execute the `test_content_ gen.py` script and write the text 
into the serial device to test the burst capability or run this script and 
specify device path to automatically test.
    
    Signed-off-by: xinbingnan <[email protected]>
---
 testing/drivertest/Makefile            |   5 +
 testing/drivertest/drivertest_uart.c   | 359 +++++++++++++++++++++++++++++++++
 testing/drivertest/test_content_gen.py | 129 ++++++++++++
 3 files changed, 493 insertions(+)

diff --git a/testing/drivertest/Makefile b/testing/drivertest/Makefile
index 82277b949..439453b1b 100644
--- a/testing/drivertest/Makefile
+++ b/testing/drivertest/Makefile
@@ -71,4 +71,9 @@ MAINSRC  += drivertest_relay.c
 PROGNAME += cmocka_driver_relay
 endif
 
+ifneq ($(CONFIG_SERIAL),)
+MAINSRC  += drivertest_uart.c
+PROGNAME += cmocka_driver_uart
+endif
+
 include $(APPDIR)/Application.mk
diff --git a/testing/drivertest/drivertest_uart.c 
b/testing/drivertest/drivertest_uart.c
new file mode 100644
index 000000000..8d06d0a4f
--- /dev/null
+++ b/testing/drivertest/drivertest_uart.c
@@ -0,0 +1,359 @@
+/****************************************************************************
+ * apps/testing/drivertest/drivertest_uart.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 <assert.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <cmocka.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_TESTING_DRIVER_TEST_UART_DEVICE
+  #define CONFIG_TESTING_DRIVER_TEST_UART_DEVICE "/dev/console"
+#endif
+
+#ifndef CONFIG_TESTING_DRIVER_TEST_UART_DEFAULT_CONTENT
+  #define CONFIG_TESTING_DRIVER_TEST_UART_DEFAULT_CONTENT "0123456789abcdefg"\
+      "hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;':\"[]{}\\|!@#$%^"\
+      "&*()-+_="
+  #define DEFAULT_CONTENT CONFIG_TESTING_DRIVER_TEST_UART_DEFAULT_CONTENT
+#endif
+
+#ifndef CONFIG_TESTING_DRIVER_TEST_UART_BUFFER_SIZE
+  #define CONFIG_TESTING_DRIVER_TEST_UART_BUFFER_SIZE 1024
+  #define BUFFER_SIZE CONFIG_TESTING_DRIVER_TEST_UART_BUFFER_SIZE
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+struct test_confs_s
+{
+  FAR const char *dev_path;
+};
+
+struct test_state_s
+{
+  FAR const char *dev_path;
+  FAR char *buffer;
+  int fd;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: read_until
+ ****************************************************************************/
+
+static uint32_t read_until(int fd, FAR char *buffer,
+                           uint32_t buffer_len, char terminator)
+{
+  uint32_t cnt = 0;
+  ssize_t len = 0;
+  char tmp_char = 0;
+
+  while (cnt <= buffer_len)
+    {
+      assert_true(cnt < buffer_len);
+
+      len = read(fd, &tmp_char, 1);
+      assert_true(len >= 0);
+
+      if (len == 0 || tmp_char == terminator)
+        {
+          buffer[cnt] = '\0';
+          return cnt;
+        }
+
+      buffer[cnt] = tmp_char;
+      cnt++;
+    }
+
+  buffer[buffer_len - 1] = '\0';
+  return UINT32_MAX;
+}
+
+/****************************************************************************
+ * Name: read_length
+ ****************************************************************************/
+
+static uint32_t read_length(int fd, FAR char *buffer,
+                            uint32_t max_size)
+{
+  uint32_t cnt = 0;
+  ssize_t len = 0;
+
+  while (cnt < max_size)
+    {
+      len = read(fd, buffer + cnt, max_size - cnt);
+      assert_true(len >= 0);
+
+      if (len == 0)
+        {
+          return cnt;
+        }
+
+      cnt += len;
+    }
+
+  return cnt;
+}
+
+/****************************************************************************
+ * Name: write_length
+ ****************************************************************************/
+
+static uint32_t write_length(int fd, FAR const char *buffer,
+                             uint32_t max_size)
+{
+  uint32_t cnt = 0;
+  ssize_t len = 0;
+
+  while (cnt < max_size)
+    {
+      len = write(fd, buffer + cnt, max_size - cnt);
+      assert_true(len >= 0);
+
+      if (len == 0)
+        {
+          return cnt;
+        }
+
+      cnt += len;
+    }
+
+  return cnt;
+}
+
+/****************************************************************************
+ * Name: setup
+ ****************************************************************************/
+
+static int setup(FAR void **state)
+{
+  FAR struct test_confs_s *confs = (FAR struct test_confs_s *)*state;
+  FAR struct test_state_s *test_state = malloc(sizeof(struct test_state_s));
+  assert_true(test_state != NULL);
+
+  test_state->dev_path = confs->dev_path;
+  assert_true(sizeof(DEFAULT_CONTENT) <= BUFFER_SIZE);
+  test_state->buffer = malloc(BUFFER_SIZE);
+  assert_true(test_state->buffer != NULL);
+
+  test_state->fd = open(test_state->dev_path, O_RDWR);
+  assert_true(test_state->fd > 0);
+
+  *state = test_state;
+  return 0;
+}
+
+/****************************************************************************
+ * Name: teardown
+ ****************************************************************************/
+
+static int teardown(FAR void **state)
+{
+  FAR struct test_state_s *test_state = (FAR struct test_state_s *)*state;
+
+  free(test_state->buffer);
+  assert_int_equal(close(test_state->fd), 0);
+  free(test_state);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: write_default
+ ****************************************************************************/
+
+static void write_default(FAR void **state)
+{
+  FAR struct test_state_s *test_state = (FAR struct test_state_s *)*state;
+  int res = write(test_state->fd,
+                  DEFAULT_CONTENT,
+                  sizeof(DEFAULT_CONTENT) - 1);
+
+  assert_int_equal(res, sizeof(DEFAULT_CONTENT) - 1);
+}
+
+/****************************************************************************
+ * Name: read_default
+ ****************************************************************************/
+
+static void read_default(FAR void **state)
+{
+  FAR struct test_state_s *test_state = (FAR struct test_state_s *)*state;
+  sigset_t buffer_size = sizeof(DEFAULT_CONTENT);
+  int cnt = 0;
+  FAR char *buffer = test_state->buffer;
+  assert_true(buffer != NULL);
+
+  buffer[buffer_size - 1] = '\0';
+
+  while (cnt < sizeof(DEFAULT_CONTENT) - 1)
+    {
+      ssize_t n = read(test_state->fd, buffer + cnt, buffer_size - cnt);
+
+      assert_true(n >= 0);
+      if (n == 0)
+        {
+          break;
+        }
+      else
+        {
+          cnt += n;
+        }
+    }
+
+  assert_string_equal(buffer, DEFAULT_CONTENT);
+}
+
+/****************************************************************************
+ * Name: burst_test
+ ****************************************************************************/
+
+static void burst_test(FAR void **state)
+{
+  FAR struct test_state_s *test_state = (FAR struct test_state_s *)*state;
+  int res = 0;
+  char num_buffer[16];
+  char ret_msg_buffer[8];
+
+  num_buffer[0] = '\0';
+  ret_msg_buffer[0] = '\0';
+
+  while (true)
+    {
+      int num = 0;
+      FAR char *read_buffer = test_state->buffer;
+
+      res = read_until(test_state->fd, num_buffer, sizeof(num_buffer), '#');
+      assert_true(res > 0);
+
+      num = strtol(num_buffer, NULL, 10);
+      assert_true(num >= 0);
+      assert_true(num < BUFFER_SIZE);
+
+      if (num == 0)
+        {
+          break;
+        }
+
+      res = read_length(test_state->fd, read_buffer, num);
+      assert_int_equal(res, num);
+      read_buffer[num] = '\0';
+
+      res = write_length(test_state->fd, read_buffer, num);
+      assert_int_equal(res, num);
+
+      res = read_until(test_state->fd, ret_msg_buffer,
+                       sizeof(ret_msg_buffer), '#');
+
+      /* length of 'pass' or 'fail' */
+
+      assert_int_equal(res, 4);
+
+      assert_string_equal(ret_msg_buffer, "pass");
+    }
+}
+
+/****************************************************************************
+ * Name: show_usage
+ ****************************************************************************/
+
+static void show_usage(FAR const char *progname, int exitcode)
+{
+  printf("Usage: %s -d <dev path>\n", progname);
+  printf("Where:\n");
+  printf("  -d <dev path> uart device path "
+         "[default device: /dev/console].\n");
+  exit(exitcode);
+}
+
+/****************************************************************************
+ * Name: parse_args
+ ****************************************************************************/
+
+static void parse_args(int argc, FAR char **argv,
+                       FAR struct test_confs_s *conf)
+{
+  int option;
+
+  while ((option = getopt(argc, argv, "d:")) != ERROR)
+    {
+      switch (option)
+        {
+          case 'd':
+            conf->dev_path = optarg;
+            break;
+          case '?':
+            printf("Unknown option: %c\n", optopt);
+            show_usage(argv[0], EXIT_FAILURE);
+            break;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * cmocka_driver_uart_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  struct test_confs_s confs =
+  {
+    .dev_path = CONFIG_TESTING_DRIVER_TEST_UART_DEVICE
+  };
+
+  parse_args(argc, argv, &confs);
+
+  const struct CMUnitTest tests[] =
+    {
+      cmocka_unit_test_prestate_setup_teardown(write_default, setup,
+                                               teardown, &confs),
+      cmocka_unit_test_prestate_setup_teardown(read_default, setup,
+                                               teardown, &confs),
+      cmocka_unit_test_prestate_setup_teardown(burst_test, setup,
+                                               teardown, &confs),
+    };
+
+  return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
diff --git a/testing/drivertest/test_content_gen.py 
b/testing/drivertest/test_content_gen.py
new file mode 100644
index 000000000..8c3b2fcc2
--- /dev/null
+++ b/testing/drivertest/test_content_gen.py
@@ -0,0 +1,129 @@
+#!/bin/python3
+
+# ****************************************************************************
+# apps/testing/drivertest/cmocka_driver_uart/test_content_gen.py
+#
+# 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.
+#
+import argparse
+import sys
+import time
+from random import choices, randint
+
+try:
+    import serial
+except ImportError:
+    print("Please Install pyserial first [pip install pyserial]")
+    sys.exit(1)
+
+DEFAULT_CONTENT = 
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;':\"[]{}\\|!@#$%^&*()-+_="
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description="Use this script to test whether the serial port is 
working properly. If the device path is not "
+        "provided, the text of the test will be output manually, which 
requires the user to copy and "
+        "paste manually to complete the test. If provided, it will be tested 
automatically."
+    )
+    parser.add_argument("dev", type=str, nargs="?", help="tty device", 
default="")
+    parser.add_argument(
+        "-t", "--turn", type=int, nargs="?", help="test turns [10]", default=10
+    )
+    parser.add_argument(
+        "-l",
+        "--length",
+        type=int,
+        nargs="?",
+        help="each turn max length [100]",
+        default=100,
+    )
+
+    return parser.parse_args()
+
+
+def fake_symbol(k):
+    return "".join(choices(DEFAULT_CONTENT, k=k))
+
+
+def s_write(fd, content, end="#"):
+    if fd:
+        try:
+            fd.write((content + end).encode())
+        except Exception:
+            fd.flush()
+            fd.close()
+    else:
+        print(content, end=end)
+
+
+def s_read(fd, size: int):
+    if fd:
+        try:
+            return fd.read(size).decode()
+        except Exception:
+            fd.flush()
+            fd.close()
+    else:
+        return input()
+
+
+def make_test(device: str, default_content: str, turn: int, max_length: int):
+    fd = None
+    if len(device) > 0:
+        fd = serial.Serial(device, 115200)
+        if not fd.is_open:
+            fd.open()
+        print("FROM SERIAL:", s_read(fd, size=len(default_content)))
+        fd.flushInput()
+        fd.flushOutput()
+
+    print("START WRITE:")
+    time.sleep(1)
+    s_write(fd, DEFAULT_CONTENT, end="")
+    time.sleep(1)
+
+    print("START BURST TEST:")
+    fail_count = 0
+    for i in range(turn):
+        content_length = randint(1, max_length)
+        content = fake_symbol(content_length)
+        s_write(fd, f"{content_length}")
+        s_write(fd, content, end="")
+
+        back = s_read(fd, content_length)
+        if back == content:
+            s_write(fd, "pass")
+            print(f"TURN[{i + 1}]: PASS")
+        else:
+            s_write(fd, "fail")
+            fail_count += 1
+            print(f"TURN[{i + 1}]: FAIL")
+    s_write(fd, "0")
+    if fail_count != 0:
+        print(f"### FAIL {fail_count} TURNS ###")
+    else:
+        print("### ALL PASSED ###")
+
+
+if __name__ == "__main__":
+    args = parse_args()
+
+    make_test(
+        args.dev,
+        default_content=DEFAULT_CONTENT,
+        turn=args.turn,
+        max_length=args.length,
+    )

Reply via email to