From 313cadedfacb497eab462c364dce983a40aa3656 Mon Sep 17 00:00:00 2001 From: Parichay Kapoor Date: Wed, 10 Apr 2019 14:25:33 +0900 Subject: [PATCH] [IIO] Custom channel index number as input 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 --- gst/nnstreamer/tensor_source/tensor_src_iio.c | 95 +++++++++++++++++++++++++-- gst/nnstreamer/tensor_source/tensor_src_iio.h | 4 +- tests/nnstreamer_source/unittest_src_iio.cpp | 85 ++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 6 deletions(-) diff --git a/gst/nnstreamer/tensor_source/tensor_src_iio.c b/gst/nnstreamer/tensor_source/tensor_src_iio.c index c6ab58c..12c1e90 100644 --- a/gst/nnstreamer/tensor_source/tensor_src_iio.c +++ b/gst/nnstreamer/tensor_source/tensor_src_iio.c @@ -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); diff --git a/gst/nnstreamer/tensor_source/tensor_src_iio.h b/gst/nnstreamer/tensor_source/tensor_src_iio.h index a22bdbe..aad0895 100644 --- a/gst/nnstreamer/tensor_source/tensor_src_iio.h +++ b/gst/nnstreamer/tensor_source/tensor_src_iio.h @@ -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 */ diff --git a/tests/nnstreamer_source/unittest_src_iio.cpp b/tests/nnstreamer_source/unittest_src_iio.cpp index a102ee4..e1d1f91 100644 --- a/tests/nnstreamer_source/unittest_src_iio.cpp +++ b/tests/nnstreamer_source/unittest_src_iio.cpp @@ -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 -- 2.7.4