From c6f3077fce086843befd0daefdbb79e7785bbc1b Mon Sep 17 00:00:00 2001 From: Parichay Kapoor Date: Mon, 25 Mar 2019 15:50:49 +0900 Subject: [PATCH] [IIO] register iio source and add test cases 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 --- gst/nnstreamer/nnstreamer.c | 2 + gst/nnstreamer/tensor_source/tensor_src_iio.c | 40 ++++---- gst/nnstreamer/tensor_source/tensor_src_iio.h | 3 +- jni/Android-nnstreamer.mk | 2 + tests/meson.build | 9 ++ tests/nnstreamer_source/unittest_src_iio.cpp | 139 ++++++++++++++++++++++++++ 6 files changed, 173 insertions(+), 22 deletions(-) create mode 100644 tests/nnstreamer_source/unittest_src_iio.cpp diff --git a/gst/nnstreamer/nnstreamer.c b/gst/nnstreamer/nnstreamer.c index 86a178d..4a6e73e 100644 --- a/gst/nnstreamer/nnstreamer.c +++ b/gst/nnstreamer/nnstreamer.c @@ -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); diff --git a/gst/nnstreamer/tensor_source/tensor_src_iio.c b/gst/nnstreamer/tensor_source/tensor_src_iio.c index 82acd59..d58644d 100644 --- a/gst/nnstreamer/tensor_source/tensor_src_iio.c +++ b/gst/nnstreamer/tensor_source/tensor_src_iio.c @@ -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 diff --git a/gst/nnstreamer/tensor_source/tensor_src_iio.h b/gst/nnstreamer/tensor_source/tensor_src_iio.h index 44627f1..d6de7d4 100644 --- a/gst/nnstreamer/tensor_source/tensor_src_iio.h +++ b/gst/nnstreamer/tensor_source/tensor_src_iio.h @@ -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 */ diff --git a/jni/Android-nnstreamer.mk b/jni/Android-nnstreamer.mk index 30b8083..611f67e 100644 --- a/jni/Android-nnstreamer.mk +++ b/jni/Android-nnstreamer.mk @@ -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/ diff --git a/tests/meson.build b/tests/meson.build index 1f9fb4a..b42cccf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -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 index 0000000..a149da5 --- /dev/null +++ b/tests/nnstreamer_source/unittest_src_iio.cpp @@ -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 + * @bug No known bugs. + */ +#include +#include +#include + +#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 (); +} -- 2.7.4