[IIO] Added more test cases with corresponding bug fixes
authorParichay Kapoor <pk.kapoor@samsung.com>
Tue, 9 Apr 2019 02:59:54 +0000 (11:59 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 12 Apr 2019 00:36:14 +0000 (09:36 +0900)
1. Added test cases for
  - caps verification
  - default restoration
  - setting trigger with number
  - using generic scan element type
  - auto enable channels
2. Corresponding bug fixes

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
gst/nnstreamer/tensor_source/tensor_src_iio.c
tests/nnstreamer_source/unittest_src_iio.cpp

index c7833f7..fc3206c 100644 (file)
@@ -1282,9 +1282,12 @@ gst_tensor_set_all_channels (GstTensorSrcIIO * self, const gint contents)
   for (ch_list = self->channels; ch_list != NULL; ch_list = ch_list->next) {
     channel_prop = (GstTensorSrcIIOChannelProperties *) ch_list->data;
     filename = g_strdup_printf ("%s%s", channel_prop->name, EN_SUFFIX);
-    ret &=
-        gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
-        contents);
+    if (gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
+            contents)) {
+      channel_prop->enabled = TRUE;
+    } else {
+      ret = FALSE;
+    }
     g_free (filename);
   }
 
@@ -1921,22 +1924,9 @@ gst_tensor_src_iio_query (GstBaseSrc * src, GstQuery * query)
 static gboolean
 gst_tensor_src_iio_set_caps (GstBaseSrc * src, GstCaps * caps)
 {
-  GstTensorSrcIIO *self;
   GstPad *pad;
 
-  self = GST_TENSOR_SRC_IIO (src);
   pad = src->srcpad;
-
-  if (DBG) {
-    GstCaps *cur_caps = gst_pad_get_current_caps (pad);
-    if (cur_caps != NULL && !gst_caps_is_subset (caps, cur_caps)) {
-      silent_debug ("Setting caps in source mismatch");
-      silent_debug ("caps = %" GST_PTR_FORMAT, caps);
-      silent_debug ("cur_caps = %" GST_PTR_FORMAT, cur_caps);
-      gst_caps_unref (cur_caps);
-    }
-  }
-
   if (!gst_pad_set_caps (pad, caps)) {
     return FALSE;
   }
index af08996..ccb63de 100644 (file)
@@ -6,12 +6,14 @@
  * @author     Parichay Kapoor <pk.kapoor@samsung.com>
  * @bug                No known bugs.
  */
+#include <glib/gstdio.h>
 #include <gtest/gtest.h>
 #include <gst/gst.h>
 #include <gst/check/gstharness.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <pthread.h>
+#include <tensor_common.h>
 
 /**
  * @brief element name to be tested
@@ -113,6 +115,7 @@ typedef struct _iio_dev_dir_struct
   gchar *scan_el_time_en;
   gchar *scan_el_time_index;
   gchar *scan_el_time_type;
+  gchar *scan_el_type_generic;
 
   gchar *dev_dir;
   gchar *dev_device_dir;
@@ -204,7 +207,10 @@ make_iio_dev_structure (int num)
       g_build_filename (iio_dev->scan_el, "timestamp_index", NULL);
   iio_dev->scan_el_time_type =
       g_build_filename (iio_dev->scan_el, "timestamp_type", NULL);
+  iio_dev->scan_el_type_generic =
+      g_build_filename (iio_dev->scan_el, "in_voltage_type", NULL);
 
+  iio_dev->log_file = NULL;
   iio_dev->dev_dir = g_build_filename (iio_dev->base_dir, "dev", NULL);
   iio_dev->dev_device_dir =
       g_build_filename (iio_dev->dev_dir, device_folder_name, NULL);
@@ -429,7 +435,7 @@ static gint
 build_dev_dir_samp_freq_avail (const iio_dev_dir_struct * iio_dev)
 {
   gint status = 0;
-  gchar *samp_freq_avail_string = g_strjoinv (",", (char **) samp_freq_avail);
+  gchar *samp_freq_avail_string = g_strjoinv (" ", (char **) samp_freq_avail);
 
   status +=
       write_file_string (iio_dev->samp_freq_avail, samp_freq_avail_string);
@@ -665,6 +671,7 @@ clean_iio_dev_structure (iio_dev_dir_struct * iio_dev)
   g_free (iio_dev->scan_el_time_en);
   g_free (iio_dev->scan_el_time_index);
   g_free (iio_dev->scan_el_time_type);
+  g_free (iio_dev->scan_el_type_generic);
 
   for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
     g_free (iio_dev->scan_el_en[idx]);
@@ -732,6 +739,7 @@ destroy_dev_dir (const iio_dev_dir_struct * iio_dev)
   status += safe_remove (iio_dev->scan_el_time_en);
   status += safe_remove (iio_dev->scan_el_time_index);
   status += safe_remove (iio_dev->scan_el_time_type);
+  status += safe_remove (iio_dev->scan_el_type_generic);
   status += safe_rmdir (iio_dev->scan_el);
 
   status += safe_remove (iio_dev->buf_en);
@@ -760,7 +768,9 @@ destroy_dev_dir (const iio_dev_dir_struct * iio_dev)
   close (iio_dev->dev_device_dir_fd_read);
   status += safe_remove (iio_dev->dev_device_dir);
   status += safe_rmdir (iio_dev->dev_dir);
-  status += safe_remove (iio_dev->log_file);
+  if (iio_dev->log_file != NULL) {
+    status += safe_remove (iio_dev->log_file);
+  }
   status += safe_rmdir (iio_dev->base_dir);
 
   return status;
@@ -1025,7 +1035,8 @@ TEST (test_tensor_src_iio, start_stop)
 /**
  * @brief tests tensor source IIO data without trigger
  */ \
-TEST (test_tensor_src_iio, data_verify_no_trigger_bits##DATA_BITS##_alternate##SKIP) \
+TEST (test_tensor_src_iio, \
+    data_verify_no_trigger_bits##DATA_BITS##_alternate##SKIP) \
 { \
   iio_dev_dir_struct *dev0; \
   GstElement *src_iio_pipeline; \
@@ -1050,14 +1061,15 @@ TEST (test_tensor_src_iio, data_verify_no_trigger_bits##DATA_BITS##_alternate##S
   /** setup */ \
   samp_freq = g_ascii_strtoll (samp_freq_avail[0], NULL, 10); \
   dev0->log_file = g_build_filename (dev0->base_dir, "temp.log", NULL); \
-  parse_launch = \
-      g_strdup_printf ("%s device=%s silent=FALSE ! multifilesink location=%s", \
+  parse_launch =  g_strdup_printf ( \
+      "%s device=%s silent=FALSE ! multifilesink location=%s", \
       ELEMENT_NAME, DEVICE_NAME, dev0->log_file); \
   src_iio_pipeline = gst_parse_launch (parse_launch, NULL); \
   /** state transition test upwards */ \
   status = gst_element_set_state (src_iio_pipeline, GST_STATE_PLAYING); \
   EXPECT_EQ (status, GST_STATE_CHANGE_ASYNC); \
-  status = gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
+  status = gst_element_get_state (\
+      src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS); \
   EXPECT_EQ (state, GST_STATE_PLAYING); \
   /** \
@@ -1073,14 +1085,16 @@ TEST (test_tensor_src_iio, data_verify_no_trigger_bits##DATA_BITS##_alternate##S
       if (stat_ret == 0 && stat_buf.st_size != 0) { \
         /** verify playing state has been maintained */ \
         status = \
-            gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
+            gst_element_get_state ( \
+                src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
         EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS); \
         EXPECT_EQ (state, GST_STATE_PLAYING); \
         /** state transition test downwards */ \
         status = gst_element_set_state (src_iio_pipeline, GST_STATE_NULL); \
         EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS); \
         status = \
-            gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
+            gst_element_get_state ( \
+                src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE); \
         EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS); \
         EXPECT_EQ (state, GST_STATE_NULL); \
         break; \
@@ -1132,11 +1146,13 @@ GENERATE_TESTS_TO_VERIFY_DATA_WO_TRIGGER (DATA, 64, 2);
 /**
  * @brief tests tensor source IIO data with trigger
  * @note verifies that no frames have been lost as well
+ * @note verifies caps for the src pad as well
  */
 TEST (test_tensor_src_iio, data_verify_trigger)
 {
   iio_dev_dir_struct *dev0;
   GstElement *src_iio_pipeline;
+  GstElement *src_iio;
   GstStateChangeReturn status;
   GstState state;
   gchar *parse_launch;
@@ -1152,23 +1168,54 @@ TEST (test_tensor_src_iio, data_verify_trigger)
   gint stat_ret;
   data_value = DATA;
   data_bits = 16;
+  GstCaps *caps;
+  GstPad *src_pad;
+  GstStructure *structure;
+  GstTensorConfig config;
+  gint num_scan_elements;
   /** Make device */
   dev0 = make_full_device (data_value, data_bits);
   ASSERT_NE (dev0, nullptr);
   /** setup */
+  num_scan_elements = dev0->num_scan_elements;
   samp_freq = g_ascii_strtoll (samp_freq_avail[0], NULL, 10);
   dev0->log_file = g_build_filename (dev0->base_dir, "temp.log", NULL);
   parse_launch =
       g_strdup_printf
-      ("%s device-number=%d trigger=%s silent=FALSE ! multifilesink location=%s",
+      ("%s device-number=%d trigger=%s silent=FALSE "
+      "name=my-src-iio ! multifilesink location=%s",
       ELEMENT_NAME, 0, TRIGGER_NAME, dev0->log_file);
   src_iio_pipeline = gst_parse_launch (parse_launch, NULL);
   /** state transition test upwards */
   status = gst_element_set_state (src_iio_pipeline, GST_STATE_PLAYING);
   EXPECT_EQ (status, GST_STATE_CHANGE_ASYNC);
-  status = gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE);
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
   EXPECT_EQ (state, GST_STATE_PLAYING);
+
+  /** get and verify the caps */
+  src_iio = gst_bin_get_by_name (GST_BIN (src_iio_pipeline), "my-src-iio");
+  ASSERT_NE (src_iio, nullptr);
+  src_pad = gst_element_get_static_pad (src_iio, "src");
+  ASSERT_NE (src_pad, nullptr);
+  caps = gst_pad_get_current_caps (src_pad);
+  ASSERT_NE (caps, nullptr);
+  structure = gst_caps_get_structure (caps, 0);
+  ASSERT_NE (structure, nullptr);
+
+  /** Default has merge channels enabled */
+  EXPECT_STREQ (gst_structure_get_name (structure), "other/tensor");
+  EXPECT_EQ (gst_tensor_config_from_structure (&config, structure), TRUE);
+  EXPECT_EQ (config.rate_n, samp_freq);
+  EXPECT_EQ (config.rate_d, 1);
+  EXPECT_EQ (config.info.type, _NNS_FLOAT32);
+  EXPECT_EQ (config.info.dimension[0], num_scan_elements);
+  EXPECT_EQ (config.info.dimension[1], 1);
+  EXPECT_EQ (config.info.dimension[2], 1);
+  EXPECT_EQ (config.info.dimension[3], 1);
+
   /** let a few frames transfer */
   for (int idx = 0; idx < NUM_FRAMES; idx++) {
     /** wait for filter to process the frame and multifilesink to write it */
@@ -1206,13 +1253,17 @@ TEST (test_tensor_src_iio, data_verify_trigger)
   }
 
   /** verify playing state has been maintained */
-  status = gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE);
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
   EXPECT_EQ (state, GST_STATE_PLAYING);
   /** state transition test downwards */
   status = gst_element_set_state (src_iio_pipeline, GST_STATE_NULL);
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
-  status = gst_element_get_state (src_iio_pipeline, &state, NULL, GST_CLOCK_TIME_NONE);
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
   EXPECT_EQ (state, GST_STATE_NULL);
 
@@ -1224,6 +1275,146 @@ TEST (test_tensor_src_iio, data_verify_trigger)
 }
 
 /**
+ * @brief tests tensor source IIO data with set frequency
+ * @note verifies restoration of default values
+ * @note verifies setting trigger using trigger number
+ * @note verifies setting frequency manually
+ * @note verifies enabling of channels automatically
+ * @note verifies using generic type information for channels
+ */
+TEST (test_tensor_src_iio, data_verify_freq_generic_type)
+{
+  iio_dev_dir_struct *dev0;
+  GstElement *src_iio_pipeline;
+  GstStateChangeReturn status;
+  GstState state;
+  gchar *parse_launch;
+  gint samp_freq;
+  gint data_value;
+  guint data_bits;
+  gint fd, bytes_to_read, bytes_read;
+  gchar *data_buffer;
+  gfloat expect_val, actual_val;
+  guint64 expect_val_mask;
+  gchar *expect_val_char, *actual_val_char;
+  struct stat stat_buf;
+  gint stat_ret;
+  data_value = DATA;
+  data_bits = 16;
+  gint samp_freq_idx = 1;
+  gint num_scan_elements;
+  gchar *ret_string = NULL;
+  const gchar *buffer_length_char = "3";
+  /** Make device */
+  dev0 = make_full_device (data_value, data_bits);
+  ASSERT_NE (dev0, nullptr);
+  /** setup */
+  num_scan_elements = dev0->num_scan_elements;
+  samp_freq = g_ascii_strtoll (samp_freq_avail[samp_freq_idx], NULL, 10);
+  dev0->log_file = g_build_filename (dev0->base_dir, "temp.log", NULL);
+  parse_launch =
+      g_strdup_printf
+      ("%s device-number=%d trigger-number=%d silent=FALSE frequency=%d "
+      "name=my-src-iio ! multifilesink location=%s",
+      ELEMENT_NAME, 0, 0, samp_freq, dev0->log_file);
+  src_iio_pipeline = gst_parse_launch (parse_launch, NULL);
+
+  /** move channel specific type for channel 1 to generic */
+  g_rename (dev0->scan_el_type[1], dev0->scan_el_type_generic);
+  /** disable all/some channels */
+  for (int idx = 0; idx < num_scan_elements; idx++) {
+    write_file_int (dev0->scan_el_en[idx], 0);
+  }
+  /** set default sampling frequency and verify reset after closure */
+  write_file_string (dev0->samp_freq, samp_freq_avail[samp_freq_idx + 1]);
+  /** set default sampling frequency and verify reset after closure */
+  write_file_string (dev0->buf_length, buffer_length_char);
+
+  /** state transition test upwards */
+  status = gst_element_set_state (src_iio_pipeline, GST_STATE_PLAYING);
+  EXPECT_EQ (status, GST_STATE_CHANGE_ASYNC);
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
+  EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+  EXPECT_EQ (state, GST_STATE_PLAYING);
+
+  /** let a few frames transfer */
+  for (int idx = 0; idx < NUM_FRAMES; idx++) {
+    /** wait for filter to process the frame and multifilesink to write it */
+    while (TRUE) {
+      if (g_file_test (dev0->log_file, G_FILE_TEST_IS_REGULAR)) {
+        stat_ret = stat (dev0->log_file, &stat_buf);
+        if (stat_ret == 0 && stat_buf.st_size != 0) {
+          break;
+        }
+      }
+      g_usleep (MAX (1, 1000000 / samp_freq));
+    }
+
+    /** verify correctness of data */
+    fd = open (dev0->log_file, O_RDONLY);
+    bytes_to_read = sizeof (float) * BUF_LENGTH * dev0->num_scan_elements;
+    data_buffer = (gchar *) malloc (bytes_to_read);
+    bytes_read = read (fd, data_buffer, bytes_to_read);
+    EXPECT_EQ (bytes_read, bytes_to_read);
+    expect_val_mask = G_MAXUINT64 >> (64 - data_bits);
+    expect_val = ((data_value & expect_val_mask) + OFFSET) * SCALE;
+    expect_val_char = g_strdup_printf ("%.2f", expect_val);
+    for (int idx = 0; idx < bytes_to_read; idx += sizeof (float)) {
+      actual_val = *((gfloat *) data_buffer);
+      actual_val_char = g_strdup_printf ("%.2f", actual_val);
+      EXPECT_STREQ (expect_val_char, actual_val_char);
+      g_free (actual_val_char);
+    }
+    close (fd);
+    ASSERT_EQ (safe_remove (dev0->log_file), 0);
+    /** update data value to check data updates */
+    data_value += 1;
+    ASSERT_EQ (build_dev_dir_scan_elements (dev0, data_bits, data_value,
+            data_value), 0);
+  }
+
+  /** verify playing state has been maintained */
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
+  EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+  EXPECT_EQ (state, GST_STATE_PLAYING);
+  /** state transition test downwards */
+  status = gst_element_set_state (src_iio_pipeline, GST_STATE_NULL);
+  EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+  status =
+      gst_element_get_state (src_iio_pipeline, &state, NULL,
+      GST_CLOCK_TIME_NONE);
+  EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+  EXPECT_EQ (state, GST_STATE_NULL);
+
+  /** Verify default values */
+  EXPECT_EQ (g_file_get_contents (dev0->samp_freq, &ret_string, NULL, NULL),
+      TRUE);
+  EXPECT_STREQ (ret_string, samp_freq_avail[samp_freq_idx + 1]);
+  g_free (ret_string);
+  EXPECT_EQ (g_file_get_contents (dev0->buf_length, &ret_string, NULL, NULL),
+      TRUE);
+  EXPECT_STREQ (ret_string, buffer_length_char);
+  g_free (ret_string);
+  for (int idx = 0; idx < num_scan_elements; idx++) {
+    EXPECT_EQ (g_file_get_contents (dev0->scan_el_en[idx], &ret_string, NULL,
+            NULL), TRUE);
+    EXPECT_STREQ (ret_string, "0");
+    g_free (ret_string);
+  }
+
+  /** delete device structure */
+  gst_object_unref (src_iio_pipeline);
+  ASSERT_EQ (destroy_dev_dir (dev0), 0);
+  g_free (dev0->log_file);
+  clean_iio_dev_structure (dev0);
+}
+
+
+/**
  * @brief Main function for unit test.
  */
 int