#include <gst/gst.h>
#include <glib.h>
#include <string.h>
-#include <stdio.h>
#include <endian.h>
#include <unistd.h>
#include <errno.h>
/**
* @brief Default behavior on merging channels
*/
-#define DEFAULT_MERGE_CHANNELS FALSE
+#define DEFAULT_MERGE_CHANNELS TRUE
/**
* blocksize for buffer
*/
#define NAME_FILE "name"
#define AVAIL_FREQUENCY_FILE "sampling_frequency_available"
-
-/**
- * @brief IIO system paths
- */
-#define IIO_BASE_DIR "/sys/bus/iio/devices/"
-#define IIO_DEV_DIR "/dev/"
+#define SAMPLING_FREQUENCY "sampling_frequency"
/**
* @brief Template for src pad.
g_free (prop->generic_name);
g_free (prop->base_dir);
g_free (prop->base_file);
+ g_free (prop);
}
/**
list = *list_addr;
if (!channel->enabled) {
+ *list_addr = g_list_remove (list, data);
gst_tensor_src_iio_channel_properties_free (channel);
- *list_addr = g_list_remove (list, channel);
}
}
guint num_channels_enabled = 0;
gboolean generic_val, specific_val;
gchar *generic_type_filename;
+ GstTensorSrcIIOChannelProperties *channel_prop;
if (!g_file_test (dir_name, G_FILE_TEST_IS_DIR)) {
GST_ERROR_OBJECT (self, "No channels available.");
continue;
}
- GstTensorSrcIIOChannelProperties channel_prop;
- self->channels = g_list_prepend (self->channels, &channel_prop);
+ channel_prop = g_new (GstTensorSrcIIOChannelProperties, 1);
+ self->channels = g_list_prepend (self->channels, channel_prop);
/** set the name and base_dir */
- channel_prop.name = g_strndup (dir_entry->d_name,
+ channel_prop->name = g_strndup (dir_entry->d_name,
strlen (dir_entry->d_name) - strlen (EN_SUFFIX));
- channel_prop.base_dir = g_strdup (dir_name);
- channel_prop.base_file =
- g_build_filename (dir_name, channel_prop.name, NULL);
- channel_prop.generic_name =
- gst_tensor_src_iio_get_generic_name (channel_prop.name);
- silent_debug ("Generic name = %s", channel_prop.generic_name);
+ channel_prop->base_dir = g_strdup (dir_name);
+ channel_prop->base_file =
+ g_build_filename (dir_name, channel_prop->name, NULL);
+ channel_prop->generic_name =
+ gst_tensor_src_iio_get_generic_name (channel_prop->name);
+ silent_debug ("Generic name = %s", channel_prop->generic_name);
/** find and set the current state */
- filename = g_strdup_printf ("%s%s", channel_prop.base_file, EN_SUFFIX);
+ filename = g_strdup_printf ("%s%s", channel_prop->base_file, EN_SUFFIX);
if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
GST_ERROR_OBJECT (self, "Unable to read %s, error: %s.\n", filename,
error->message);
value = g_ascii_strtoull (file_contents, NULL, 10);
g_free (file_contents);
if (value == 1) {
- channel_prop.enabled = TRUE;
+ channel_prop->enabled = TRUE;
num_channels_enabled += 1;
} else if (value == 0) {
- channel_prop.enabled = FALSE;
+ channel_prop->enabled = FALSE;
} else {
GST_ERROR_OBJECT
(self,
"Enable bit %u (out of range) in current state of channel %s.\n",
- value, channel_prop.name);
+ value, channel_prop->name);
goto error_cleanup_list;
}
/** find and set the index */
- filename = g_strdup_printf ("%s%s", channel_prop.base_file, INDEX_SUFFIX);
+ filename =
+ g_strdup_printf ("%s%s", channel_prop->base_file, INDEX_SUFFIX);
if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
GST_ERROR_OBJECT (self, "Unable to read %s, error: %s.\n", filename,
error->message);
value = g_ascii_strtoull (file_contents, NULL, 10);
g_free (file_contents);
- channel_prop.index = value;
+ channel_prop->index = value;
/** find and set the type information */
- filename = g_strdup_printf ("%s%s", channel_prop.base_file, TYPE_SUFFIX);
+ filename = g_strdup_printf ("%s%s", channel_prop->base_file, TYPE_SUFFIX);
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
/** if specific type info unavailable, use generic type info */
g_free (filename);
generic_type_filename =
- g_strdup_printf ("%s%s", channel_prop.generic_name, TYPE_SUFFIX);
+ g_strdup_printf ("%s%s", channel_prop->generic_name, TYPE_SUFFIX);
filename =
- g_build_filename (channel_prop.base_dir, generic_type_filename,
+ g_build_filename (channel_prop->base_dir, generic_type_filename,
NULL);
g_free (generic_type_filename);
}
}
g_free (filename);
- if (!gst_tensor_src_iio_set_channel_type (&channel_prop, file_contents)) {
+ if (!gst_tensor_src_iio_set_channel_type (channel_prop, file_contents)) {
GST_ERROR_OBJECT (self,
"Error while setting up channel type for channel %s.\n",
- channel_prop.name);
+ channel_prop->name);
g_free (file_contents);
goto error_cleanup_list;
}
g_free (file_contents);
/** find and setup offset info */
- channel_prop.scale = 1.0;
+ channel_prop->scale = 1.0;
specific_val =
gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
- channel_prop.name, SCALE_SUFFIX, &channel_prop.scale);
+ channel_prop->name, SCALE_SUFFIX, &channel_prop->scale);
generic_val =
gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
- channel_prop.generic_name, SCALE_SUFFIX, &channel_prop.scale);
+ channel_prop->generic_name, SCALE_SUFFIX, &channel_prop->scale);
if (!specific_val || !generic_val) {
goto error_cleanup_list;
}
/** find and setup scale info */
- channel_prop.offset = 0.0;
+ channel_prop->offset = 0.0;
specific_val =
gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
- channel_prop.name, OFFSET_SUFFIX, &channel_prop.offset);
+ channel_prop->name, OFFSET_SUFFIX, &channel_prop->offset);
generic_val =
gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
- channel_prop.generic_name, OFFSET_SUFFIX, &channel_prop.offset);
+ channel_prop->generic_name, OFFSET_SUFFIX, &channel_prop->offset);
if (!specific_val || !generic_val) {
goto error_cleanup_list;
}
* @param[in] base_dir Device base directory (containing sampling freq file)
* @param[in] frequency Frequency specified by user (else 0)
* @return >0 if OK, represents sampling frequency to be set
- * 0 if any cannot find the matching frequency
+ * 0 if sampling frequency file does not exist, dont change anything
+ * -1 if any error occurs
*/
-static guint64
+static gint64
gst_tensor_src_iio_set_frequency (const gchar * base_dir,
const guint64 frequency)
{
gchar *filename = NULL;
gchar *file_contents = NULL;
gint i = 0;
- guint64 ret = 0, val = 0;
+ guint64 val = 0;
+ gint64 ret = 0;
/** get frequency list supported by the device */
filename = g_build_filename (base_dir, AVAIL_FREQUENCY_FILE, NULL);
+ if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ GST_WARNING ("Sampling frequency file does not exist for the file %s.\n",
+ base_dir);
+ goto del_filename;
+ }
if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
GST_ERROR ("Unable to read sampling frequency for device %s.\n", base_dir);
g_error_free (error);
+ ret = -1;
goto del_filename;
}
gint num = g_strv_length (freq_list);
if (num == 0) {
GST_ERROR ("No sampling frequencies for device %s.\n", base_dir);
+ ret = -1;
goto del_freq_list;
}
/**
GST_ERROR_OBJECT (self, "Unable to write to file %s.\n", filename);
goto error_close_file;
}
- if (!fclose (fd)) {
+ if (fclose (fd)) {
GST_ERROR_OBJECT (self, "Unable to close file %s after write.\n", filename);
goto error_free_filename;
}
if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
GST_ERROR_OBJECT (self, "Unable to read file %s with error %s.\n",
filename, error->message);
+ g_error_free (error);
goto error_free_filename;
} else {
if (!g_strcmp0 (contents, file_contents)) {
fclose (fd);
error_free_filename:
- g_error_free (error);
g_free (filename);
return ret;
}
/** compile tensor info data */
for (list = tensor_src_iio->channels; list != NULL; list = list->next) {
- channel_prop = (GstTensorSrcIIOChannelProperties *) list;
+ channel_prop = (GstTensorSrcIIOChannelProperties *) list->data;
if (!channel_prop->enabled)
continue;
info[info_idx].name = channel_prop->name;
GstTensorSrcIIO *self;
self = GST_TENSOR_SRC_IIO_CAST (src);
gint id;
- guint64 sampling_frequency;
+ gint64 sampling_frequency;
gchar *dirname = NULL;
gchar *filename = NULL;
+ gint num_channels_enabled;
/** Find the device */
id = gst_tensor_src_iio_get_id_by_name (IIO_BASE_DIR, self->device.name,
sampling_frequency =
gst_tensor_src_iio_set_frequency (self->device.base_dir,
self->sampling_frequency);
- if (0 == sampling_frequency) {
- GST_ERROR_OBJECT (self, "IIO device does not support %lu frequency.\n",
- (gulong) self->sampling_frequency);
+ if (-1 == sampling_frequency) {
+ GST_ERROR_OBJECT (self, "Error in setting frequency for device %s.\n",
+ self->device.name);
goto error_trigger_free;
+ } else if (0 == sampling_frequency) {
+ /** if sampling frequency file does not exist, no error */
+ GST_WARNING_OBJECT (self, "Cannot verify against sampling frequency list.");
} else {
- self->sampling_frequency = sampling_frequency;
- /** interface of frequency is kept long for outside but uint64 inside */
- gchar *sampling_frequency_char =
- 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,
- "Cannot set the sampling frequency for device: %s.\n",
- self->device.name);
+ /** check if sampling frequency can be set */
+ filename =
+ g_build_filename (self->device.base_dir, SAMPLING_FREQUENCY, NULL);
+ if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ GST_WARNING_OBJECT (self, "Cannot set sampling frequency.");
+ } else {
+ self->sampling_frequency = sampling_frequency;
+ /** interface of frequency is kept long for outside but uint64 inside */
+ gchar *sampling_frequency_char =
+ 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,
+ "Cannot set the sampling frequency for device: %s.\n",
+ self->device.name);
+ g_free (sampling_frequency_char);
+ goto error_trigger_free;
+ }
g_free (sampling_frequency_char);
- goto error_trigger_free;
}
- g_free (sampling_frequency_char);
+ g_free (filename);
}
/** once all these are set, set the buffer related thingies */
/** get all the channels that exist and then set enable on them */
dirname = g_build_filename (self->device.base_dir, CHANNELS, NULL);
- guint num_channels_enabled =
+ num_channels_enabled =
gst_tensor_src_iio_get_all_channel_info (self, dirname);
g_free (dirname);
if (G_UNLIKELY (num_channels_enabled == -1)) {
gst_tensor_set_all_channels (self, 0);
goto error_channels_free;
}
- /** filter out disabled channels */
- g_list_foreach (self->channels, gst_tensor_channel_list_filter_enabled,
- &self->channels);
- self->scan_size = gst_tensor_get_size_from_channels (self->channels);
}
- /** set source pad */
- GstCaps *prev_caps, *caps, *updated_caps;
- GstPad *pad;
+ /** filter out disabled channels */
+ g_list_foreach (self->channels, gst_tensor_channel_list_filter_enabled,
+ &self->channels);
+ self->scan_size = gst_tensor_get_size_from_channels (self->channels);
+ self->num_channels_enabled = g_list_length (self->channels);
- pad = src->srcpad;
- gst_pad_use_fixed_caps (pad);
+ /** set fixed caps for the src pad */
+ gst_pad_use_fixed_caps (src->srcpad);
- /**
- * We can update the caps of the pad in current NULL state
- * as the pad is activated in READY->PAUSED trainsition.
- */
+ /** create tensor_config */
if (!gst_tensor_src_iio_create_config (self)) {
GST_ERROR_OBJECT (self, "Error creating config.\n");
goto error_channels_free;
}
- if (self->is_tensor) {
- GstTensorConfig tensor_config;
- gst_tensor_info_copy (&tensor_config.info,
- &(self->tensors_config->info.info[0]));
- tensor_config.rate_n = self->tensors_config->rate_n;
- tensor_config.rate_d = self->tensors_config->rate_d;
- caps = gst_tensor_caps_from_config (&tensor_config);
- gst_tensor_info_free (&tensor_config.info);
- } else {
- caps = gst_tensors_caps_from_config (self->tensors_config);
- }
- if (caps == NULL) {
- GST_ERROR_OBJECT (self, "Error creating caps from config.\n");
- goto error_config_free;
- }
-
- /** get current caps, take intersection with it and then set the new ones */
- if (gst_pad_has_current_caps (pad)) {
- prev_caps = gst_pad_get_current_caps (pad);
- if (gst_caps_can_intersect (caps, prev_caps)) {
- updated_caps = gst_caps_intersect (caps, prev_caps);
- } else {
- GST_ERROR_OBJECT (self,
- "No intersection between new and current caps.\n");
- gst_caps_unref (prev_caps);
- gst_caps_unref (caps);
- goto error_config_free;
- }
- gst_caps_unref (caps);
- gst_caps_unref (prev_caps);
- } else {
- updated_caps = caps;
- }
-
- if (!gst_pad_set_caps (pad, updated_caps)) {
- GST_ERROR_OBJECT (self, "Unable to set caps for the pad.\n");
- gst_caps_unref (updated_caps);
- goto error_config_free;
- /** free this in stop as well */
- }
-
- silent_debug ("Finalization of caps while starting device");
- silent_debug ("caps = %" GST_PTR_FORMAT, updated_caps);
-
- gst_caps_unref (updated_caps);
-
/** enable the buffer for the data to be captured */
dirname = g_build_filename (self->device.base_dir, BUFFER, NULL);
if (G_UNLIKELY (!gst_tensor_write_sysfs_int (self, "enable", dirname, 1))) {
if (DBG) {
GstCaps *cur_caps = gst_pad_get_current_caps (pad);
- if (!gst_caps_is_subset (caps, cur_caps)) {
+ if (cur_caps != NULL && !gst_caps_is_subset (caps, cur_caps)) {
silent_debug ("Setting caps in source mismatch");
silent_debug ("caps = %" GST_PTR_FORMAT, caps);
silent_debug ("cur_caps = %" GST_PTR_FORMAT, cur_caps);
+ gst_caps_unref (cur_caps);
}
- gst_caps_unref (cur_caps);
}
if (!gst_pad_set_caps (pad, caps)) {
{
/**
* Caps are fixated based on the device source in _start().
- * Nothing to be handled here.
*/
- return gst_caps_fixate (caps);
+ GstTensorSrcIIO *self;
+ self = GST_TENSOR_SRC_IIO_CAST (src);
+ GstCaps *updated_caps, *fixated_caps;
+
+ if (self->is_tensor) {
+ GstTensorConfig tensor_config;
+ gst_tensor_info_copy (&tensor_config.info,
+ &(self->tensors_config->info.info[0]));
+ tensor_config.rate_n = self->tensors_config->rate_n;
+ tensor_config.rate_d = self->tensors_config->rate_d;
+ fixated_caps = gst_tensor_caps_from_config (&tensor_config);
+ gst_tensor_info_free (&tensor_config.info);
+ } else {
+ fixated_caps = gst_tensors_caps_from_config (self->tensors_config);
+ }
+
+ if (fixated_caps == NULL) {
+ GST_ERROR_OBJECT (self, "Error creating fixated caps from config.");
+ return NULL;
+ }
+ silent_debug ("Fixated caps from device = %" GST_PTR_FORMAT, fixated_caps);
+
+ if (gst_caps_can_intersect (caps, fixated_caps)) {
+ updated_caps = gst_caps_intersect (caps, fixated_caps);
+ } else {
+ GST_ERROR_OBJECT (self,
+ "No intersection while fixating caps of the element.");
+ gst_caps_unref (caps);
+ gst_caps_unref (fixated_caps);
+ return NULL;
+ }
+
+ gst_caps_unref (caps);
+ gst_caps_unref (fixated_caps);
+ return gst_caps_fixate (updated_caps);
}
/**
#include <gtest/gtest.h>
#include <gst/gst.h>
#include <gst/check/gstharness.h>
+#include <fcntl.h>
+#include <unistd.h>
+/**
+ * @brief element name to be tested
+ */
#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;
+/**
+ * @brief original location of iio to be modified for testing
+ */
+extern gchar *IIO_BASE_DIR;
+extern gchar *IIO_DEV_DIR;
+
+/**
+ * @brief to store the original location for iio
+ */
+gchar *PREV_IIO_BASE_DIR;
+gchar *PREV_IIO_DEV_DIR;
+
+/**
+ * @brief iio default and test values
+ */
+#define DEFAULT_BUFFER_CAPACITY 1
+#define DEFAULT_FREQUENCY 0
+#define DEFAULT_SILENT TRUE
+#define DEFAULT_MERGE_CHANNELS TRUE
+#define DEVICE_NAME "test-device-1"
+#define TRIGGER_NAME "test-trigger-1"
+#define SCALE 10.1
+#define OFFSET 1.1
+
+/**
+ * @brief iio states and values
+ */
const gchar *mode[] = { "one-shot", "continuous" };
const gchar *channels[] = { "auto", "all" };
+const gchar *samp_freq_avail[] = { "1000", "2000", "3000", NULL };
+
+/**
+ * @brief structure for iio device file/folder names
+ */
+typedef struct _iio_dev_dir_struct
+{
+ gchar *base_dir;
+ gchar *sys_dir;
+ gchar *bus_dir;
+ gchar *iio_dir;
+ gchar *iio_base_dir_sim;
+
+ gchar *device;
+ gchar *name;
+
+ gchar *trigger_dev;
+ gchar *trigger_name;
+
+ gchar *trigger;
+ gchar *cur_trig;
+
+ gchar *samp_freq;
+ gchar *samp_freq_avail;
+ gchar *buffer;
+ gchar *buf_en;
+ gchar *buf_length;
+ gchar *scale;
+ gchar *offset;
+
+ static const int num_scan_elements = 8;
+ gchar *scan_el;
+ gchar *scan_el_en[num_scan_elements];
+ gchar *scan_el_index[num_scan_elements];
+ gchar *scan_el_type[num_scan_elements];
+ gchar *scan_el_raw[num_scan_elements];
+ gchar *scan_el_time_en;
+ gchar *scan_el_time_index;
+ gchar *scan_el_time_type;
+
+ gchar *dev_dir;
+ gchar *dev_device_dir;
+} iio_dev_dir_struct;
+
+/**
+ * @brief make structure for iio device with all file names
+ * @param[in] num number assigned to the device
+ * @returns made structure (owned by the caller)
+ */
+static iio_dev_dir_struct *
+make_iio_dev_structure (int num)
+{
+ gchar *device_folder_name;
+ gchar *trigger_folder_name;
+ gchar *scan_element_name;
+ const gchar *_tmp_dir = g_get_tmp_dir ();
+ const gchar *_dirname = "nnst-src-XXXXXX";
+
+ iio_dev_dir_struct *iio_dev = g_new (iio_dev_dir_struct, 1);
+ iio_dev->base_dir = g_build_filename (_tmp_dir, _dirname, NULL);
+ iio_dev->base_dir = g_mkdtemp_full (iio_dev->base_dir, 0777);
+ rmdir (iio_dev->base_dir);
+
+ iio_dev->sys_dir = g_build_filename (iio_dev->base_dir, "sys", NULL);
+ iio_dev->bus_dir = g_build_filename (iio_dev->sys_dir, "bus", NULL);
+ iio_dev->iio_dir = g_build_filename (iio_dev->bus_dir, "iio", NULL);
+ iio_dev->iio_base_dir_sim =
+ g_build_filename (iio_dev->iio_dir, "devices", NULL);
+
+ PREV_IIO_BASE_DIR = IIO_BASE_DIR;
+ IIO_BASE_DIR = g_strdup (iio_dev->iio_base_dir_sim);
+
+ device_folder_name = g_strdup_printf ("%s%d", "iio:device", num);
+ iio_dev->device = g_build_filename (IIO_BASE_DIR, device_folder_name, NULL);
+ iio_dev->name = g_build_filename (iio_dev->device, "name", NULL);
+
+ trigger_folder_name = g_strdup_printf ("%s%d", "iio:trigger", num);
+ iio_dev->trigger_dev =
+ g_build_filename (IIO_BASE_DIR, trigger_folder_name, NULL);
+ iio_dev->trigger_name = g_build_filename (iio_dev->trigger_dev, "name", NULL);
+
+ iio_dev->trigger = g_build_filename (iio_dev->device, "trigger", NULL);
+ iio_dev->cur_trig =
+ g_build_filename (iio_dev->trigger, "current_trigger", NULL);
+
+ iio_dev->samp_freq =
+ g_build_filename (iio_dev->device, "sampling_frequency", NULL);
+ iio_dev->samp_freq_avail =
+ g_build_filename (iio_dev->device, "sampling_frequency_available", NULL);
+
+ iio_dev->buffer = g_build_filename (iio_dev->device, "buffer", NULL);
+ iio_dev->buf_en = g_build_filename (iio_dev->buffer, "enable", NULL);
+ iio_dev->buf_length = g_build_filename (iio_dev->buffer, "length", NULL);
+
+ iio_dev->scale = g_build_filename (iio_dev->device, "in_voltage_scale", NULL);
+ iio_dev->offset =
+ g_build_filename (iio_dev->device, "in_voltage_offset", NULL);
+
+ iio_dev->scan_el = g_build_filename (iio_dev->device, "scan_elements", NULL);
+ for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
+ scan_element_name = g_strdup_printf ("%s%d%s", "in_voltage", idx, "_en");
+ iio_dev->scan_el_en[idx] =
+ g_build_filename (iio_dev->scan_el, scan_element_name, NULL);
+ g_free (scan_element_name);
+ scan_element_name = g_strdup_printf ("%s%d%s", "in_voltage", idx, "_index");
+ iio_dev->scan_el_index[idx] =
+ g_build_filename (iio_dev->scan_el, scan_element_name, NULL);
+ g_free (scan_element_name);
+ scan_element_name = g_strdup_printf ("%s%d%s", "in_voltage", idx, "_type");
+ iio_dev->scan_el_type[idx] =
+ g_build_filename (iio_dev->scan_el, scan_element_name, NULL);
+ g_free (scan_element_name);
+ scan_element_name = g_strdup_printf ("%s%d%s", "in_voltage", idx, "_raw");
+ iio_dev->scan_el_raw[idx] =
+ g_build_filename (iio_dev->scan_el, scan_element_name, NULL);
+ g_free (scan_element_name);
+ }
+ iio_dev->scan_el_time_en =
+ g_build_filename (iio_dev->scan_el, "timestamp_en", NULL);
+ iio_dev->scan_el_time_index =
+ g_build_filename (iio_dev->scan_el, "timestamp_index", NULL);
+ iio_dev->scan_el_time_type =
+ g_build_filename (iio_dev->scan_el, "timestamp_type", NULL);
+
+ iio_dev->dev_dir = g_build_filename (iio_dev->base_dir, "dev", NULL);
+ iio_dev->dev_device_dir =
+ g_build_filename (iio_dev->dev_dir, device_folder_name, NULL);
+
+ PREV_IIO_DEV_DIR = IIO_DEV_DIR;
+ IIO_DEV_DIR = g_strdup (iio_dev->dev_dir);
+
+ g_free (device_folder_name);
+ g_free (trigger_folder_name);
+
+ return iio_dev;
+}
+
+/**
+ * @brief write string in to the file
+ * @param[in] filename Destination file for the data
+ * @param[in] contents Data to be written to the file
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+write_file_string (const gchar * filename, const gchar * contents)
+{
+ if (!g_file_set_contents (filename, contents, -1, NULL)) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * @brief write int in to the file
+ * @param[in] filename Destination file for the data
+ * @param[in] contents Data to be written to the file
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+write_file_int (const gchar * filename, const gint contents)
+{
+ g_autofree gchar *contents_char = NULL;
+ contents_char = g_strdup_printf ("%d", contents);
+
+ return write_file_string (filename, contents_char);
+}
+
+/**
+ * @brief write float in to the file
+ * @param[in] filename Destination file for the data
+ * @param[in] contents Data to be written to the file
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+write_file_float (const gchar * filename, const gfloat contents)
+{
+ g_autofree gchar *contents_char = NULL;
+ contents_char = g_strdup_printf ("%f", contents);
+
+ return write_file_string (filename, contents_char);
+}
+
+/**
+ * @brief create a file
+ * @param[in] filename name of the file to be created
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+touch_file (const gchar * filename)
+{
+ return write_file_string (filename, "");
+}
+
+/**
+ * @brief build base dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_base (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += g_mkdir_with_parents (iio_dev->device, 0777);
+ status += write_file_string (iio_dev->name, DEVICE_NAME);
+
+ return status;
+}
+
+/**
+ * @brief build dev data dir and fills it for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_dev_data (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += g_mkdir_with_parents (iio_dev->dev_dir, 0777);
+ /** @todo fill in proper data */
+ status += write_file_string (iio_dev->dev_device_dir, "FIXME");
+
+ return status;
+}
+
+/**
+ * @brief build buffer dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_buffer (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += g_mkdir_with_parents (iio_dev->buffer, 0777);
+ status += touch_file (iio_dev->buf_en);
+ status += touch_file (iio_dev->buf_length);
+
+ return status;
+}
+
+/**
+ * @brief build trigger dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_trigger (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += g_mkdir_with_parents (iio_dev->trigger, 0777);
+ status += touch_file (iio_dev->cur_trig);
+
+ return status;
+}
+
+/**
+ * @brief build trigger device dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_trigger_dev (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += g_mkdir_with_parents (iio_dev->trigger_dev, 0777);
+ status += write_file_string (iio_dev->trigger_name, TRIGGER_NAME);
+
+ return status;
+}
+
+/**
+ * @brief build sampling frequency for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_samp_freq (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += touch_file (iio_dev->samp_freq);
+
+ return status;
+}
+
+/**
+ * @brief build list of sampling frequency for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_samp_freq_avail (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+ gchar *samp_freq_avail_string = g_strjoinv (",", (char **) samp_freq_avail);
+
+ status +=
+ write_file_string (iio_dev->samp_freq_avail, samp_freq_avail_string);
+
+ g_free (samp_freq_avail_string);
+ return status;
+}
+
+/**
+ * @brief build scale and offset for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_scale_offset (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+
+ status += write_file_float (iio_dev->scale, SCALE);
+ status += write_file_float (iio_dev->offset, OFFSET);
+
+ return status;
+}
+
+/**
+ * @brief build raw data elements for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @param[in] skip skip some of the elements
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_raw_elements (const iio_dev_dir_struct * iio_dev, gboolean skip =
+ FALSE)
+{
+ gint status = 0;
+
+ for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
+ if (idx % 2 && skip) {
+ continue;
+ }
+ /** todo: verify what is the dtype of this data */
+ status += write_file_int (iio_dev->scan_el_raw[idx], 1000);
+ }
+
+ return status;
+}
+
+/**
+ * @brief build scan data elements dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @param[in] num_bits num of bits for storage of data
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_scan_elements (const iio_dev_dir_struct * iio_dev,
+ const guint num_bits)
+{
+ gint status = 0;
+ gchar *type_data;
+ gchar endianchar, signchar;
+ gint storage, used, shift;
+
+ if (!g_file_test (iio_dev->scan_el, G_FILE_TEST_IS_DIR)) {
+ status += g_mkdir_with_parents (iio_dev->scan_el, 0777);
+ }
+ /** total 8 possible cases */
+ for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
+ status += write_file_int (iio_dev->scan_el_en[idx], idx % 2);
+ status += write_file_int (iio_dev->scan_el_index[idx], idx);
+ /** form 4 possible combinations */
+ endianchar = 'b';
+ signchar = 's';
+ switch (idx % (iio_dev->num_scan_elements / 2)) {
+ case 0:
+ break;
+ case 1:
+ endianchar = 'l';
+ case 2:
+ signchar = 'u';
+ break;
+ case 3:
+ endianchar = 'l';
+ break;
+ }
+ storage = num_bits;
+ used = storage - 2 * (idx / (iio_dev->num_scan_elements / 2));
+ if (used <= 0) {
+ used = 1;
+ }
+ /** shift will be 0 or non-zero (2 in this case) */
+ shift = storage - used;
+ type_data =
+ g_strdup_printf ("%ce:%c%u/%u>>%u", endianchar, signchar, used, storage,
+ shift);
+ status += write_file_string (iio_dev->scan_el_type[idx], type_data);
+ g_free (type_data);
+ }
+
+ return status;
+}
+
+/**
+ * @brief build timestamp in scan data elements dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ * @returns 0 on success, non-zero on failure
+ */
+static gint
+build_dev_dir_timestamp (const iio_dev_dir_struct * iio_dev)
+{
+ gint status = 0;
+ gchar *type_data;
+ gchar endianchar, signchar;
+ gint storage, used, shift;
+
+ if (!g_file_test (iio_dev->scan_el, G_FILE_TEST_IS_DIR)) {
+ status += g_mkdir_with_parents (iio_dev->scan_el, 0777);
+ }
+ /** total 8 possible cases */
+ status += write_file_int (iio_dev->scan_el_time_en, 1);
+ status +=
+ write_file_int (iio_dev->scan_el_time_index, iio_dev->num_scan_elements);
+ endianchar = 'b';
+ signchar = 's';
+ storage = 64;
+ used = 64;
+ /** shift will be 0 or non-zero (2 in this case) */
+ shift = storage - used;
+ type_data =
+ g_strdup_printf ("%ce:%c%u/%u>>%u", endianchar, signchar, used, storage,
+ shift);
+ status += write_file_string (iio_dev->scan_el_time_type, type_data);
+ g_free (type_data);
+
+ return status;
+}
+
+/**
+ * @brief cleans memory of iio device structure
+ * @param[in] iio_dev struct of iio device
+ */
+static void
+clean_iio_dev_structure (iio_dev_dir_struct * iio_dev)
+{
+ g_free (IIO_BASE_DIR);
+ g_free (IIO_DEV_DIR);
+
+ IIO_BASE_DIR = PREV_IIO_BASE_DIR;
+ IIO_DEV_DIR = PREV_IIO_DEV_DIR;
+
+ g_free (iio_dev->base_dir);
+ g_free (iio_dev->sys_dir);
+ g_free (iio_dev->bus_dir);
+ g_free (iio_dev->iio_dir);
+ g_free (iio_dev->iio_base_dir_sim);
+ g_free (iio_dev->device);
+ g_free (iio_dev->name);
+ g_free (iio_dev->trigger_dev);
+ g_free (iio_dev->trigger_name);
+ g_free (iio_dev->trigger);
+ g_free (iio_dev->cur_trig);
+ g_free (iio_dev->samp_freq);
+ g_free (iio_dev->samp_freq_avail);
+ g_free (iio_dev->buffer);
+ g_free (iio_dev->buf_en);
+ g_free (iio_dev->buf_length);
+ g_free (iio_dev->scale);
+ g_free (iio_dev->offset);
+ g_free (iio_dev->scan_el);
+ g_free (iio_dev->scan_el_time_en);
+ g_free (iio_dev->scan_el_time_index);
+ g_free (iio_dev->scan_el_time_type);
+
+ for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
+ g_free (iio_dev->scan_el_en[idx]);
+ g_free (iio_dev->scan_el_index[idx]);
+ g_free (iio_dev->scan_el_type[idx]);
+ g_free (iio_dev->scan_el_raw[idx]);
+ }
+
+ g_free (iio_dev->dev_dir);
+ g_free (iio_dev->dev_device_dir);
+
+ g_free (iio_dev);
+ return;
+}
+
+/**
+ * @brief destroy dir for iio device simulation
+ * @param[in] iio_dev struct of iio device
+ */
+static void
+destroy_dev_dir (const iio_dev_dir_struct * iio_dev)
+{
+ for (int idx = 0; idx < iio_dev->num_scan_elements; idx++) {
+ remove (iio_dev->scan_el_en[idx]);
+ remove (iio_dev->scan_el_index[idx]);
+ remove (iio_dev->scan_el_type[idx]);
+ remove (iio_dev->scan_el_raw[idx]);
+ }
+ remove (iio_dev->scan_el_time_en);
+ remove (iio_dev->scan_el_time_index);
+ remove (iio_dev->scan_el_time_type);
+ rmdir (iio_dev->scan_el);
+
+ remove (iio_dev->buf_en);
+ remove (iio_dev->buf_length);
+ rmdir (iio_dev->buffer);
+
+ remove (iio_dev->cur_trig);
+ rmdir (iio_dev->trigger);
+
+ remove (iio_dev->scale);
+ remove (iio_dev->offset);
+ remove (iio_dev->samp_freq);
+ remove (iio_dev->samp_freq_avail);
+ remove (iio_dev->name);
+
+ remove (iio_dev->trigger_name);
+
+ rmdir (iio_dev->trigger_dev);
+ rmdir (iio_dev->device);
+ rmdir (iio_dev->iio_base_dir_sim);
+ rmdir (iio_dev->iio_dir);
+ rmdir (iio_dev->bus_dir);
+ rmdir (iio_dev->sys_dir);
+
+ remove (iio_dev->dev_device_dir);
+ rmdir (iio_dev->dev_dir);
+
+ rmdir (iio_dev->base_dir);
+}
/**
* @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;
EXPECT_STREQ (ret_mode, mode[1]);
/** setting device test */
- g_object_set (src_iio, "device", device, NULL);
+ g_object_set (src_iio, "device", DEVICE_NAME, NULL);
g_object_get (src_iio, "device", &ret_device, NULL);
- EXPECT_STREQ (ret_device, device);
+ EXPECT_STREQ (ret_device, DEVICE_NAME);
/** setting trigger test */
- g_object_set (src_iio, "trigger", trigger, NULL);
+ g_object_set (src_iio, "trigger", TRIGGER_NAME, NULL);
g_object_get (src_iio, "trigger", &ret_trigger, NULL);
- EXPECT_STREQ (ret_trigger, trigger);
+ EXPECT_STREQ (ret_trigger, TRIGGER_NAME);
/** setting channels test */
g_object_get (src_iio, "channels", &ret_channels, NULL);
g_object_get (src_iio, "merge-channels-data", &ret_merge_channels, NULL);
EXPECT_EQ (ret_merge_channels, merge_channels);
- /* teardown */
+ /** teardown */
gst_harness_teardown (hrnss);
}
/**
+ * @brief tests state change of tensor source IIO
+ */
+TEST (test_tensor_src_iio, start_stop)
+{
+ iio_dev_dir_struct *dev0;
+ GstHarness *hrnss = NULL;
+ GstElement *src_iio = NULL;
+ GstStateChangeReturn status;
+ GstState state;
+
+ /** build iio dummy device */
+ dev0 = make_iio_dev_structure (0);
+ ASSERT_EQ (build_dev_dir_base (dev0), 0);
+
+ /** build iio dummy trigger */
+ ASSERT_EQ (build_dev_dir_trigger_dev (dev0), 0);
+
+ /** add trigger support in device */
+ ASSERT_EQ (build_dev_dir_trigger (dev0), 0);
+
+ /** dir for continuous mode */
+ ASSERT_EQ (build_dev_dir_buffer (dev0), 0);
+ ASSERT_EQ (build_dev_dir_scan_elements (dev0, 32), 0);
+ ASSERT_EQ (build_dev_dir_timestamp (dev0), 0);
+ ASSERT_EQ (build_dev_dir_dev_data (dev0), 0);
+
+ /** dir for single-shot mode */
+ ASSERT_EQ (build_dev_dir_raw_elements (dev0), 0);
+
+ /** other attributes */
+ ASSERT_EQ (build_dev_dir_samp_freq (dev0), 0);
+ ASSERT_EQ (build_dev_dir_samp_freq_avail (dev0), 0);
+ ASSERT_EQ (build_dev_dir_scale_offset (dev0), 0);
+
+ /** 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);
+
+ /** setup properties */
+ g_object_set (src_iio, "device", DEVICE_NAME, NULL);
+ g_object_set (src_iio, "silent", FALSE, NULL);
+ g_object_set (src_iio, "trigger", TRIGGER_NAME, NULL);
+
+ /** silent mode test */
+ status = gst_element_set_state (src_iio, GST_STATE_NULL);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ EXPECT_EQ (state, GST_STATE_NULL);
+
+ status = gst_element_set_state (src_iio, GST_STATE_READY);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ EXPECT_EQ (state, GST_STATE_READY);
+
+ status = gst_element_set_state (src_iio, GST_STATE_PAUSED);
+ EXPECT_EQ (status, GST_STATE_CHANGE_NO_PREROLL);
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_NO_PREROLL);
+ EXPECT_EQ (state, GST_STATE_PAUSED);
+
+ status = gst_element_set_state (src_iio, GST_STATE_PLAYING);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ EXPECT_EQ (state, GST_STATE_PLAYING);
+
+ /** let a frames load */
+ g_usleep (50000);
+
+ /** this will be resolved once correct data has been fed */
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ EXPECT_EQ (state, GST_STATE_PLAYING);
+
+ status = gst_element_set_state (src_iio, GST_STATE_NULL);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ status = gst_element_get_state (src_iio, &state, NULL, GST_CLOCK_TIME_NONE);
+ EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
+ EXPECT_EQ (state, GST_STATE_NULL);
+
+ /** teardown */
+ gst_harness_teardown (hrnss);
+
+ /** delete device structure */
+ destroy_dev_dir (dev0);
+ clean_iio_dev_structure (dev0);
+}
+
+
+/**
* @brief Main function for unit test.
*/
int