[IIO] register iio source and add test cases
authorParichay Kapoor <pk.kapoor@samsung.com>
Mon, 25 Mar 2019 06:50:49 +0000 (15:50 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Wed, 27 Mar 2019 04:11:22 +0000 (13:11 +0900)
1. Register plugin as a nnstreamer plugin and initialize it
2. Add test case for setting/getting properties of tensor src iio
3. Bug fixes for the bugs found with the tests
Removed srcpad from properties as it is not needed

V2:
- include tensor source in nnstreamer for android build

V3:
- removed srcpad from properties as it is not needed

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
gst/nnstreamer/nnstreamer.c
gst/nnstreamer/tensor_source/tensor_src_iio.c
gst/nnstreamer/tensor_source/tensor_src_iio.h
jni/Android-nnstreamer.mk
tests/meson.build
tests/nnstreamer_source/unittest_src_iio.cpp [new file with mode: 0644]

index 86a178d..4a6e73e 100644 (file)
@@ -64,6 +64,7 @@ NNSTREAMER_PLUGIN (tensor_mux);
 NNSTREAMER_PLUGIN (tensor_load);
 /* NNSTREAMER_PLUGIN (tensor_save); */
 NNSTREAMER_PLUGIN (tensor_sink);
+NNSTREAMER_PLUGIN (tensor_src_iio);
 NNSTREAMER_PLUGIN (tensor_split);
 NNSTREAMER_PLUGIN (tensor_transform);
 NNSTREAMER_PLUGIN (tensor_filter);
@@ -96,6 +97,7 @@ gst_nnstreamer_init (GstPlugin * plugin)
   NNSTREAMER_INIT (tensor_load, plugin);
   /*  NNSTREAMER_INIT (tensor_save, plugin); */
   NNSTREAMER_INIT (tensor_sink, plugin);
+  NNSTREAMER_INIT (tensor_src_iio, plugin);
   NNSTREAMER_INIT (tensor_split, plugin);
   NNSTREAMER_INIT (tensor_transform, plugin);
   NNSTREAMER_INIT (tensor_filter, plugin);
index 82acd59..d58644d 100644 (file)
@@ -163,9 +163,9 @@ enum
 
 /**
  * @brief Minimum and maximum operating frequency for the device
- * Default frequency chooses the first available frequency supported by device
+ * Frequency 0 chooses the first available frequency supported by device
  */
-#define MIN_FREQUENCY 1
+#define MIN_FREQUENCY 0
 #define MAX_FREQUENCY 999999999
 #define DEFAULT_FREQUENCY 0
 
@@ -303,18 +303,18 @@ gst_tensor_src_iio_class_init (GstTensorSrcIIOClass * klass)
           DEFAULT_OPERATING_CHANNELS_ENABLED, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class, PROP_BUFFER_CAPACITY,
-      g_param_spec_uint ("buffer_capacity", "Buffer Capacity",
+      g_param_spec_uint ("buffer-capacity", "Buffer Capacity",
           "Capacity of the data buffer", MIN_BUFFER_CAPACITY,
           MAX_BUFFER_CAPACITY, DEFAULT_BUFFER_CAPACITY,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_FREQUENCY,
-      g_param_spec_uint64 ("frequency", "Frequency",
+      g_param_spec_ulong ("frequency", "Frequency",
           "Operating frequency of the device", MIN_FREQUENCY, MAX_FREQUENCY,
           DEFAULT_FREQUENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_MERGE_CHANNELS,
-      g_param_spec_boolean ("merge_channels_data", "Merge Channels Data",
+      g_param_spec_boolean ("merge-channels-data", "Merge Channels Data",
           "Merge the data of channels into single tensor",
           DEFAULT_MERGE_CHANNELS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
@@ -378,6 +378,7 @@ gst_tensor_src_iio_init (GstTensorSrcIIO * self)
   /** init properties */
   self->configured = FALSE;
   self->channels = DEFAULT_PROP_STRING;
+  self->mode = DEFAULT_OPERATING_MODE;
   self->channels_enabled = CHANNELS_ENABLED_AUTO;
   gst_tensor_src_iio_device_properties_init (&self->trigger);
   gst_tensor_src_iio_device_properties_init (&self->device);
@@ -921,9 +922,9 @@ gst_tensor_src_iio_set_property (GObject * object, guint prop_id,
     case PROP_CHANNELS:
     {
       const gchar *param = g_value_get_string (value);
-      if (g_strcmp0 (param, CHANNELS_ENABLED_ALL_CHAR)) {
+      if (!g_strcmp0 (param, CHANNELS_ENABLED_ALL_CHAR)) {
         self->channels_enabled = CHANNELS_ENABLED_ALL;
-      } else if (g_strcmp0 (param, CHANNELS_ENABLED_AUTO_CHAR)) {
+      } else if (!g_strcmp0 (param, CHANNELS_ENABLED_AUTO_CHAR)) {
         self->channels_enabled = CHANNELS_ENABLED_AUTO;
       }
       break;
@@ -934,7 +935,7 @@ gst_tensor_src_iio_set_property (GObject * object, guint prop_id,
       break;
 
     case PROP_FREQUENCY:
-      self->sampling_frequency = g_value_get_uint64 (value);
+      self->sampling_frequency = (guint64) g_value_get_ulong (value);
       break;
 
     case PROP_MERGE_CHANNELS:
@@ -990,7 +991,7 @@ gst_tensor_src_iio_get_property (GObject * object, guint prop_id,
 
     case PROP_FREQUENCY:
       /** interface of frequency is kept long for outside but uint64 inside */
-      g_value_set_ulong (value, self->sampling_frequency);
+      g_value_set_ulong (value, (gulong) self->sampling_frequency);
       break;
 
     case PROP_MERGE_CHANNELS:
@@ -1313,14 +1314,13 @@ gst_tensor_src_iio_start (GstBaseSrc * src)
       self->sampling_frequency);
   if (0 == sampling_frequency) {
     GST_ERROR_OBJECT (self, "IIO device does not support %lu frequency.\n",
-        self->sampling_frequency);
+        (gulong) self->sampling_frequency);
     goto error_trigger_free;
   } else {
     self->sampling_frequency = sampling_frequency;
     /** interface of frequency is kept long for outside but uint64 inside */
-    gulong sampling_frequency_long = (long) self->sampling_frequency;
     gchar *sampling_frequency_char =
-        g_strdup_printf ("%lu", sampling_frequency_long);
+        g_strdup_printf ("%lu", (gulong) self->sampling_frequency);
     if (G_UNLIKELY (!gst_tensor_write_sysfs_string (self, "sampling_frequency",
                 self->device.base_dir, sampling_frequency_char))) {
       GST_ERROR_OBJECT (self,
@@ -1375,8 +1375,7 @@ gst_tensor_src_iio_start (GstBaseSrc * src)
   GstCaps *prev_caps, *caps, *updated_caps;
   GstPad *pad;
 
-  self->srcpad = src->srcpad;
-  pad = self->srcpad;
+  pad = src->srcpad;
   gst_pad_use_fixed_caps (pad);
 
   /**
@@ -1582,7 +1581,7 @@ gst_tensor_src_iio_set_caps (GstBaseSrc * src, GstCaps * caps)
   GstPad *pad;
 
   self = GST_TENSOR_SRC_IIO (src);
-  pad = self->srcpad;
+  pad = src->srcpad;
 
   if (DBG) {
     GstCaps *cur_caps = gst_pad_get_current_caps (pad);
@@ -1609,13 +1608,14 @@ gst_tensor_src_iio_set_caps (GstBaseSrc * src, GstCaps * caps)
 static GstCaps *
 gst_tensor_src_iio_get_caps (GstBaseSrc * src, GstCaps * filter)
 {
-  GstTensorSrcIIO *self;
   GstCaps *caps;
   GstPad *pad;
 
-  self = GST_TENSOR_SRC_IIO (src);
-  pad = self->srcpad;
+  pad = src->srcpad;
   caps = gst_pad_get_current_caps (pad);
+  if (caps == NULL) {
+    caps = gst_pad_get_pad_template_caps (pad);
+  }
 
   if (filter) {
     GstCaps *intersection;
@@ -1857,7 +1857,7 @@ gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
     }
   } else {
     /** sleep for a device tick */
-    g_usleep (MAX (1, (gulong) 1000000 / self->sampling_frequency));
+    g_usleep (MAX (1, (guint64) 1000000 / self->sampling_frequency));
   }
 
   /** read the data from file */
@@ -1876,7 +1876,7 @@ gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
   map_data_float = (gfloat *) map.data;
   raw_data = raw_data_base;
 
-  /** 
+  /**
    * current assumption is that the all data is float and merged to form
    * a 1 dimension data. 2nd dimension comes from buffer capacity.
    * @todo introduce 3rd dimension from blocksize
index 44627f1..d6de7d4 100644 (file)
@@ -101,7 +101,6 @@ typedef struct _GstTensorSrcIIOChannelProperties
 struct _GstTensorSrcIIO
 {
   GstBaseSrc element; /**< parent class object */
-  GstPad *srcpad; /**< src pad for the element*/
 
   /** gstreamer related properties */
   gboolean silent; /**< true to print minimized log */
@@ -120,7 +119,7 @@ struct _GstTensorSrcIIO
   gboolean merge_channels_data; /**< merge channel data with same type/size */
   gboolean is_tensor; /**< False if tensors is used for data */
   guint buffer_capacity; /**< size of the buffer */
-  gulong sampling_frequency; /**< sampling frequncy for the device */
+  guint64 sampling_frequency; /**< sampling frequncy for the device */
 
   /** Only first element is filled when is_tensor is true */
   GstTensorsConfig *tensors_config; /**< tensors for storing data config */
index 30b8083..611f67e 100644 (file)
@@ -125,6 +125,7 @@ LOCAL_SRC_FILES := $(NNSTREAMER_GST_HOME)/nnstreamer.c \
        $(NNSTREAMER_GST_HOME)/tensor_reposrc/tensor_reposrc.c \
        $(NNSTREAMER_GST_HOME)/tensor_saveload/tensor_load.c \
        $(NNSTREAMER_GST_HOME)/tensor_sink/tensor_sink.c \
+       $(NNSTREAMER_GST_HOME)/tensor_source/tensor_src_iio.c \
        $(NNSTREAMER_GST_HOME)/tensor_split/gsttensorsplit.c \
        $(NNSTREAMER_GST_HOME)/tensor_transform/tensor_transform.c
 
@@ -140,6 +141,7 @@ LOCAL_C_INCLUDES := $(NNSTREAMER_GST_HOME)/ \
        $(NNSTREAMER_GST_HOME)/tensor_reposrc/ \
        $(NNSTREAMER_GST_HOME)/tensor_saveload/ \
        $(NNSTREAMER_GST_HOME)/tensor_sink/ \
+       $(NNSTREAMER_GST_HOME)/tensor_source/ \
        $(NNSTREAMER_GST_HOME)/tensor_split/ \
        $(NNSTREAMER_GST_HOME)/tensor_transform/
 
index 1f9fb4a..b42cccf 100644 (file)
@@ -86,6 +86,15 @@ if gtest_dep.found()
   )
 
   test('unittest_plugins', unittest_plugins, args: ['--gst-plugin-path=..'])
+
+  # Run unittest_src_iio
+  unittest_src_iio = executable('unittest_src_iio',
+    join_paths('nnstreamer_source', 'unittest_src_iio.cpp'),
+    dependencies: [nnstreamer_unittest_deps],
+    install: false
+  )
+
+  test('unittest_src_iio', unittest_src_iio, args: ['--gst-plugin-path=..'])
 endif
 
 # Tizen C-API
diff --git a/tests/nnstreamer_source/unittest_src_iio.cpp b/tests/nnstreamer_source/unittest_src_iio.cpp
new file mode 100644 (file)
index 0000000..a149da5
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * @file       unittest_src_iio.cpp
+ * @date       22 March 2019
+ * @brief      Unit test for tensor_src_iio
+ * @see                https://github.com/nnsuite/nnstreamer
+ * @author     Parichay Kapoor <pk.kapoor@samsung.com>
+ * @bug                No known bugs.
+ */
+#include <gtest/gtest.h>
+#include <gst/gst.h>
+#include <gst/check/gstharness.h>
+
+#define ELEMENT_NAME "tensor_src_iio"
+
+const guint DEFAULT_BUFFER_CAPACITY = 1;
+const gulong DEFAULT_FREQUENCY = 0;
+const gboolean DEFAULT_SILENT = TRUE;
+const gboolean DEFAULT_MERGE_CHANNELS = FALSE;
+
+const gchar *mode[] = { "one-shot", "continuous" };
+const gchar *channels[] = { "auto", "all" };
+
+/**
+ * @brief tests properties of tensor source IIO
+ */
+TEST (test_tensor_src_iio, properties)
+{
+  const gchar default_name[] = "tensorsrciio0";
+  const gchar device[] = "test-device-1";
+  const gchar trigger[] = "test-trigger-1";
+
+  GstHarness *hrnss = NULL;
+  GstElement *src_iio = NULL;
+  gchar *name;
+  gboolean silent;
+  guint buffer_capacity;
+  gulong frequency;
+  gboolean merge_channels;
+
+  gboolean ret_silent;
+  gchar *ret_mode;
+  gchar *ret_device;
+  gchar *ret_trigger;
+  gchar *ret_channels;
+  guint ret_buffer_capacity;
+  gulong ret_frequency;
+  gboolean ret_merge_channels;
+
+  /** setup */
+  hrnss = gst_harness_new_empty ();
+  ASSERT_TRUE (hrnss != NULL);
+  gst_harness_add_parse (hrnss, ELEMENT_NAME);
+  src_iio = gst_harness_find_element (hrnss, ELEMENT_NAME);
+  ASSERT_TRUE (src_iio != NULL);
+
+  /** check the default name */
+  name = gst_element_get_name (src_iio);
+  ASSERT_TRUE (name != NULL);
+  EXPECT_STREQ (default_name, name);
+  g_free (name);
+
+  /** silent mode test */
+  g_object_get (src_iio, "silent", &ret_silent, NULL);
+  EXPECT_EQ (ret_silent, DEFAULT_SILENT);
+  silent = FALSE;
+  g_object_set (src_iio, "silent", silent, NULL);
+  g_object_get (src_iio, "silent", &ret_silent, NULL);
+  EXPECT_EQ (ret_silent, silent);
+
+  /** operating mode test */
+  g_object_get (src_iio, "mode", &ret_mode, NULL);
+  EXPECT_STREQ (ret_mode, mode[1]);
+  g_object_set (src_iio, "mode", mode[0], NULL);
+  g_object_get (src_iio, "mode", &ret_mode, NULL);
+  EXPECT_STREQ (ret_mode, mode[0]);
+  g_object_set (src_iio, "mode", mode[1], NULL);
+  g_object_get (src_iio, "mode", &ret_mode, NULL);
+  EXPECT_STREQ (ret_mode, mode[1]);
+
+  /** setting device test */
+  g_object_set (src_iio, "device", device, NULL);
+  g_object_get (src_iio, "device", &ret_device, NULL);
+  EXPECT_STREQ (ret_device, device);
+
+  /** setting trigger test */
+  g_object_set (src_iio, "trigger", trigger, NULL);
+  g_object_get (src_iio, "trigger", &ret_trigger, NULL);
+  EXPECT_STREQ (ret_trigger, trigger);
+
+  /** setting channels test */
+  g_object_get (src_iio, "channels", &ret_channels, NULL);
+  EXPECT_STREQ (ret_channels, channels[0]);
+  g_object_set (src_iio, "channels", channels[1], NULL);
+  g_object_get (src_iio, "channels", &ret_channels, NULL);
+  EXPECT_STREQ (ret_channels, channels[1]);
+  g_object_set (src_iio, "channels", channels[0], NULL);
+  g_object_get (src_iio, "channels", &ret_channels, NULL);
+  EXPECT_STREQ (ret_channels, channels[0]);
+
+  /** buffer_capacity test */
+  g_object_get (src_iio, "buffer-capacity", &ret_buffer_capacity, NULL);
+  EXPECT_EQ (ret_buffer_capacity, DEFAULT_BUFFER_CAPACITY);
+  buffer_capacity = 100;
+  g_object_set (src_iio, "buffer-capacity", buffer_capacity, NULL);
+  g_object_get (src_iio, "buffer-capacity", &ret_buffer_capacity, NULL);
+  EXPECT_EQ (ret_buffer_capacity, buffer_capacity);
+
+  /** frequency test */
+  g_object_get (src_iio, "frequency", &ret_frequency, NULL);
+  EXPECT_EQ (ret_frequency, DEFAULT_FREQUENCY);
+  frequency = 100;
+  g_object_set (src_iio, "frequency", frequency, NULL);
+  g_object_get (src_iio, "frequency", &ret_frequency, NULL);
+  EXPECT_EQ (ret_frequency, frequency);
+
+  /** merge_channels mode test */
+  g_object_get (src_iio, "merge-channels-data", &ret_merge_channels, NULL);
+  EXPECT_EQ (ret_merge_channels, DEFAULT_MERGE_CHANNELS);
+  merge_channels = TRUE;
+  g_object_set (src_iio, "merge-channels-data", merge_channels, NULL);
+  g_object_get (src_iio, "merge-channels-data", &ret_merge_channels, NULL);
+  EXPECT_EQ (ret_merge_channels, merge_channels);
+
+  /* teardown */
+  gst_harness_teardown (hrnss);
+}
+
+/**
+ * @brief Main function for unit test.
+ */
+int
+main (int argc, char **argv)
+{
+  testing::InitGoogleTest (&argc, argv);
+
+  gst_init (&argc, &argv);
+
+  return RUN_ALL_TESTS ();
+}