[IIO] Custom channel index number as input
authorParichay Kapoor <pk.kapoor@samsung.com>
Wed, 10 Apr 2019 05:25:33 +0000 (14:25 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 12 Apr 2019 07:27:53 +0000 (16:27 +0900)
Added the option for user to specify custom channel number as input
to enable specific channels.
Added test case for custom channel index as well.

V2:
Using hash table for custom channel setting

V3:
Updated property description spec with better format

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

index c6ab58c..12c1e90 100644 (file)
@@ -312,9 +312,10 @@ gst_tensor_src_iio_class_init (GstTensorSrcIIOClass * klass)
 
   g_object_class_install_property (gobject_class, PROP_CHANNELS,
       g_param_spec_string ("channels", "Channels to be enabled",
-          "Enable channels -"
-          "auto: enable all channels when no channels are enabled automatically"
-          "all: enable all channels",
+          "Specify channels to be enabled:"
+          " 1) auto: enable all channels when no channels are enabled automatically,"
+          " 2) all: enable all channels,"
+          " 3) x,y,z: list the idx of the channels to be enabled",
           DEFAULT_OPERATING_CHANNELS_ENABLED, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class, PROP_BUFFER_CAPACITY,
@@ -399,7 +400,8 @@ gst_tensor_src_iio_init (GstTensorSrcIIO * self)
 {
   /** init properties */
   self->configured = FALSE;
-  self->channels = DEFAULT_PROP_STRING;
+  self->channels = NULL;
+  self->custom_channel_table = NULL;
   self->mode = g_strdup (DEFAULT_OPERATING_MODE);
   self->channels_enabled = CHANNELS_ENABLED_AUTO;
   gst_tensor_src_iio_device_properties_init (&self->trigger);
@@ -1078,6 +1080,36 @@ gst_tensor_src_iio_set_property (GObject * object, guint prop_id,
       } else if (!g_ascii_strncasecmp (param, CHANNELS_ENABLED_AUTO_CHAR,
               strlen (CHANNELS_ENABLED_AUTO_CHAR))) {
         self->channels_enabled = CHANNELS_ENABLED_AUTO;
+      } else {
+        gint i;
+        gint64 val;
+        gchar **strv;
+        gchar *endptr = NULL;
+
+        /**
+         * using direct as we only need to store keys
+         * and keys form a unique set
+         */
+        self->custom_channel_table =
+            g_hash_table_new (g_direct_hash, g_direct_equal);
+        strv = g_strsplit_set (param, ",;", -1);
+        gint num = g_strv_length (strv);
+        for (i = 0; i < num; i++) {
+          val = g_ascii_strtoull (strv[i], &endptr, 10);
+          if (errno == ERANGE || errno == EINVAL || (endptr == strv[i]
+                  && val == 0)) {
+            GST_ERROR_OBJECT (self, "Cannot parse received custom channels %s",
+                param);
+            g_hash_table_destroy (self->custom_channel_table);
+            self->custom_channel_table = NULL;
+            break;
+          }
+          g_assert (g_hash_table_insert (self->custom_channel_table,
+                  GINT_TO_POINTER (val), NULL));
+        }
+        self->channels_enabled = CHANNELS_ENABLED_CUSTOM;
+        g_strfreev (strv);
+        break;
       }
       break;
     }
@@ -1145,6 +1177,24 @@ gst_tensor_src_iio_get_property (GObject * object, guint prop_id,
         g_value_set_string (value, CHANNELS_ENABLED_ALL_CHAR);
       } else if (self->channels_enabled == CHANNELS_ENABLED_AUTO) {
         g_value_set_string (value, CHANNELS_ENABLED_AUTO_CHAR);
+      } else {
+        GHashTableIter iter;
+        gpointer key;
+        gchar *p = NULL;
+        GPtrArray *arr = g_ptr_array_new ();
+        gchar **strings;
+
+        g_hash_table_iter_init (&iter, self->custom_channel_table);
+        while (g_hash_table_iter_next (&iter, &key, NULL)) {
+          g_ptr_array_add (arr, g_strdup_printf ("%u", GPOINTER_TO_INT (key)));
+        }
+        g_ptr_array_add (arr, NULL);
+
+        strings = (gchar **) g_ptr_array_free (arr, FALSE);
+        p = g_strjoinv (",", strings);
+        g_strfreev (strings);
+        g_value_take_string (value, p);
+        break;
       }
       break;
     }
@@ -1184,6 +1234,9 @@ gst_tensor_src_iio_finalize (GObject * object)
   g_free (self->mode);
   g_free (self->device.name);
   g_free (self->trigger.name);
+  if (self->custom_channel_table) {
+    g_hash_table_destroy (self->custom_channel_table);
+  }
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -1604,8 +1657,13 @@ error_return:
 static gboolean
 gst_tensor_src_iio_setup_scan_channels (GstTensorSrcIIO * self)
 {
-  gchar *dirname = NULL;
+  gchar *dirname = NULL, *filename = NULL;
   gint num_channels_enabled;
+  GList *ch_list;
+  gboolean item_in_table = FALSE;
+  gint channel_en;
+  GstTensorSrcIIOChannelProperties *channel_prop;
+
 
   /** get all the channels that exist and then set enable on them */
   dirname = g_build_filename (self->device.base_dir, CHANNELS, NULL);
@@ -1630,6 +1688,33 @@ gst_tensor_src_iio_setup_scan_channels (GstTensorSrcIIO * self)
     }
   }
 
+  /** enable the custom channels and disable the rest */
+  if (self->channels_enabled == CHANNELS_ENABLED_CUSTOM) {
+    for (ch_list = self->channels; ch_list != NULL; ch_list = ch_list->next) {
+      channel_prop = (GstTensorSrcIIOChannelProperties *) ch_list->data;
+      item_in_table = g_hash_table_contains (self->custom_channel_table,
+          GINT_TO_POINTER (channel_prop->index));
+      channel_en = -1;
+      if (item_in_table == FALSE && channel_prop->enabled == TRUE) {
+        channel_en = 0;
+        channel_prop->enabled = FALSE;
+      } else if (item_in_table != FALSE && channel_prop->enabled == FALSE) {
+        channel_en = 1;
+        channel_prop->enabled = TRUE;
+      }
+      if (channel_en >= 0) {
+        filename = g_strdup_printf ("%s%s", channel_prop->name, EN_SUFFIX);
+        if (!gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
+                channel_en)) {
+          GST_ERROR_OBJECT (self, "Error enabling/disabling channel.");
+          g_free (filename);
+          goto error_channels_free;
+        }
+        g_free (filename);
+      }
+    }
+  }
+
   /** filter out disabled channels */
   g_list_foreach (self->channels, gst_tensor_channel_list_filter_enabled,
       &self->channels);
index a22bdbe..aad0895 100644 (file)
@@ -60,7 +60,8 @@ gchar *IIO_DEV_DIR = "/dev/";
 typedef enum
 {
   CHANNELS_ENABLED_ALL,
-  CHANNELS_ENABLED_AUTO
+  CHANNELS_ENABLED_AUTO,
+  CHANNELS_ENABLED_CUSTOM
 } channels_enabled_options;
 
 /**
@@ -119,6 +120,7 @@ struct _GstTensorSrcIIO
   GstTensorSrcIIODeviceProperties device; /**< IIO device */
   GstTensorSrcIIODeviceProperties trigger; /**< IIO trigger */
   GList *channels; /**< list of enabled channels */
+  GHashTable *custom_channel_table; /**< table of idx of channels to be enabled */
   channels_enabled_options channels_enabled; /**< enabling which channels */
   guint scan_size; /**< size for a single scan of buffer length 1 */
   struct pollfd *buffer_data_fp; /**< pollfd for reading data buffer */
index a102ee4..e1d1f91 100644 (file)
@@ -1277,6 +1277,91 @@ TEST (test_tensor_src_iio, data_verify_trigger)
 }
 
 /**
+ * @brief tests tensor source IIO caps with custom channels
+ * @note data verification with/without all channels is verified in another test
+ */
+TEST (test_tensor_src_iio, data_verify_custom_channels)
+{
+  iio_dev_dir_struct *dev0;
+  GstElement *src_iio_pipeline;
+  GstElement *src_iio;
+  GstStateChangeReturn status;
+  GstState state;
+  gchar *parse_launch;
+  gint samp_freq;
+  gint data_value;
+  guint data_bits;
+  GstCaps *caps;
+  GstPad *src_pad;
+  GstStructure *structure;
+  GstTensorConfig config;
+  data_value = DATA;
+  data_bits = 16;
+  /** Make device */
+  dev0 = make_full_device (data_value, data_bits);
+  ASSERT_NE (dev0, nullptr);
+  /** 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-number=%d trigger=%s silent=FALSE channels=1,3,5 "
+      "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);
+  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], 3);
+  EXPECT_EQ (config.info.dimension[1], 1);
+  EXPECT_EQ (config.info.dimension[2], 1);
+  EXPECT_EQ (config.info.dimension[3], 1);
+
+  /** verify paused 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);
+
+  /** 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 tests tensor source IIO data with set frequency
  * @note verifies restoration of default values
  * @note verifies setting trigger using trigger number