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,
{
/** 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);
} 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;
}
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;
}
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);
}
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);
}
}
+ /** 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);
}
/**
+ * @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