LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer/elements - gsttensor_srciio.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 78.9 % 1139 899
Test Date: 2025-03-14 05:36:58 Functions: 100.0 % 47 47

            Line data    Source code
       1              : /**
       2              :  * GStreamer Tensor_Source_IIO
       3              :  * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
       4              :  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
       5              :  * Copyright (C) 2019 Parichay Kapoor <pk.kapoor@samsung.com>
       6              :  *
       7              :  * This library is free software; you can redistribute it and/or
       8              :  * modify it under the terms of the GNU Library General Public
       9              :  * License as published by the Free Software Foundation;
      10              :  * version 2.1 of the License.
      11              :  *
      12              :  * This library is distributed in the hope that it will be useful,
      13              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              :  * Library General Public License for more details.
      16              :  *
      17              :  */
      18              : /**
      19              :  * @file        gsttensor_srciio.c
      20              :  * @date        27 Feb 2019
      21              :  * @brief       GStreamer plugin to capture sensor data as tensor(s)
      22              :  * @see         http://github.com/nnstreamer/nnstreamer
      23              :  * @author      Parichay Kapoor <pk.kapoor@samsung.com>
      24              :  * @bug         No known bugs except for NYI items
      25              :  * @todo  support specific channels as input
      26              :  * @todo  handle timestamp received from device
      27              :  *
      28              :  *
      29              :  * This is the plugin to capture data from sensors
      30              :  * and convert them to tensor format.
      31              :  * Current implementation will support accelerators, light and gyro sensors.
      32              :  *
      33              :  */
      34              : 
      35              : /**
      36              :  * SECTION:element-tensor_src_iio
      37              :  *
      38              :  * #tensor_src_iio extends #gstbasesrc source element to handle Linux
      39              :  * Industrial I/O sensors as input. IIO sources are only supported in buffered
      40              :  * mode. Source elements only support push mode scheduling as a live source.
      41              :  *
      42              :  * #tensor_src_iio supports configuring the device as well as the trigger via
      43              :  * properties. Buffer capacity, frequency and scan channels to be read can
      44              :  * be configured before PLAYING the stream. The configuration is supported only
      45              :  * in states <= READY. Setting the state back to NULL restores the original
      46              :  * configuration of the IIO device. The source can be configured to work with
      47              :  * trigger for the source or read the data from the device at regular time
      48              :  * intervals. Device name/number is the only necessary configuration needed to
      49              :  * run the element (other configuration parameters is optional).
      50              :  *
      51              :  * The output caps is either of
      52              :  * other/tensor or other/tensors.
      53              :  *
      54              :  * Data from various channels can be merged to form 1 other/tensor. Final caps
      55              :  * of the src pad is of the following format:
      56              :  * <itemizedlist>
      57              :  *   <listitem><para>Dimension 0 : Channel number</listitem></para>
      58              :  *   <listitem><para>Dimension 1 : buffer capacity</listitem></para>
      59              :  * </itemizedlist>
      60              :  * Other dimensions are not utilized. The data in the dimension 0 is sorted on
      61              :  * the basis of the indexing of the channels provided by the IIO device.
      62              :  *
      63              :  * The enabling of buffer for data capture is performed when transitioning from
      64              :  * PAUSED to PLAYING state. This leads to automated synchronization handled by
      65              :  * gstreamer. Buffer duration and timestamps set by #gstbasesrc remain in sync
      66              :  * with linux IIO timestamps.
      67              :  *
      68              :  * <refsect2>
      69              :  * <title>Example launch line</title>
      70              :  * |[
      71              :  * gst-launch -v -m tensor_src_iio device-number=0 ! fakesink
      72              :  * ]|
      73              :  * </refsect2>
      74              :  */
      75              : 
      76              : #ifdef HAVE_CONFIG_H
      77              : #include <config.h>
      78              : #endif
      79              : 
      80              : #include <gst/gstinfo.h>
      81              : #include <gst/gst.h>
      82              : #include <glib.h>
      83              : #include <glib/gstdio.h>
      84              : #include <string.h>
      85              : #include <endian.h>
      86              : #include <fcntl.h>
      87              : #include <unistd.h>
      88              : #include <errno.h>
      89              : 
      90              : #include <nnstreamer_util.h>
      91              : #include "gsttensor_srciio.h"
      92              : 
      93              : /**
      94              :  * @brief Macro for debug mode.
      95              :  */
      96              : #ifndef DBG
      97              : #define DBG (!self->silent)
      98              : #endif
      99              : 
     100              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_src_iio_debug);
     101              : #define GST_CAT_DEFAULT gst_tensor_src_iio_debug
     102              : 
     103              : /**
     104              :  * @brief Macro to generate data processing functions for various types
     105              :  */
     106              : #define PROCESS_SCANNED_DATA(DTYPE_UNSIGNED, DTYPE_SIGNED) \
     107              : /**
     108              :  * @brief process scanned data to float based on type info from channel
     109              :  * @param[in] prop Property of the channel whose data is processed
     110              :  * @param[in] value Raw value scanned from the channel
     111              :  * @returns processed value in float
     112              :  */ \
     113              : static gfloat \
     114              : gst_tensor_src_iio_process_scanned_data_from_##DTYPE_UNSIGNED ( \
     115              :     GstTensorSrcIIOChannelProperties *prop, DTYPE_UNSIGNED value_unsigned) { \
     116              :   gfloat value_float; \
     117              :   \
     118              :   g_assert (sizeof (DTYPE_UNSIGNED) == sizeof (DTYPE_SIGNED)); \
     119              :   \
     120              :   value_unsigned >>= prop->shift; \
     121              :   value_unsigned &= prop->mask; \
     122              :   if (prop->is_signed) { \
     123              :     DTYPE_SIGNED value_signed; \
     124              :     guint shift_value; \
     125              :     shift_value = ((guint) (sizeof (DTYPE_UNSIGNED) * 8)) - prop->used_bits; \
     126              :     value_signed = ((DTYPE_SIGNED) (value_unsigned << shift_value)) >> shift_value; \
     127              :     value_float = ((gfloat) value_signed + prop->offset) * prop->scale; \
     128              :   } else { \
     129              :     value_float = ((gfloat) value_unsigned + prop->offset) * prop->scale; \
     130              :   } \
     131              :   return value_float; \
     132              : }
     133              : 
     134              : /**
     135              :  * @brief tensor_src_iio properties.
     136              :  */
     137              : enum
     138              : {
     139              :   PROP_0,
     140              :   PROP_MODE,
     141              :   PROP_SILENT,
     142              :   PROP_BASE_DIRECTORY,
     143              :   PROP_DEV_DIRECTORY,
     144              :   PROP_DEVICE,
     145              :   PROP_DEVICE_NUM,
     146              :   PROP_TRIGGER,
     147              :   PROP_TRIGGER_NUM,
     148              :   PROP_CHANNELS,
     149              :   PROP_BUFFER_CAPACITY,
     150              :   PROP_FREQUENCY,
     151              :   PROP_MERGE_CHANNELS,
     152              :   PROP_POLL_TIMEOUT
     153              : };
     154              : 
     155              : /**
     156              :  * @brief IIO system paths
     157              :  */
     158              : #define DEFAULT_PROP_BASE_DIRECTORY "/sys/bus/iio/devices"
     159              : #define DEFAULT_PROP_DEV_DIRECTORY "/dev"
     160              : 
     161              : /**
     162              :  * @brief iio device channel enabled mode
     163              :  */
     164              : #define CHANNELS_ENABLED_AUTO_CHAR "auto"
     165              : #define CHANNELS_ENABLED_ALL_CHAR "all"
     166              : #define DEFAULT_OPERATING_CHANNELS_ENABLED CHANNELS_ENABLED_AUTO_CHAR
     167              : 
     168              : /**
     169              :  * @brief tensor_src_iio device modes
     170              :  */
     171              : #define MODE_ONE_SHOT "one-shot"
     172              : #define MODE_CONTINUOUS "continuous"
     173              : #define DEFAULT_OPERATING_MODE MODE_CONTINUOUS
     174              : 
     175              : /**
     176              :  * @brief Flag to print minimized log.
     177              :  */
     178              : #define DEFAULT_PROP_SILENT TRUE
     179              : 
     180              : /**
     181              :  * @brief Flag for general default value of string
     182              :  */
     183              : #define DEFAULT_PROP_STRING NULL
     184              : 
     185              : /**
     186              :  * @brief Minimum and maximum buffer length for iio
     187              :  */
     188              : #define MIN_BUFFER_CAPACITY 1
     189              : #define MAX_BUFFER_CAPACITY G_MAXUINT
     190              : #define DEFAULT_BUFFER_CAPACITY 1
     191              : 
     192              : /**
     193              :  * @brief Minimum and maximum operating frequency for the device
     194              :  * Frequency 0 chooses the first available frequency supported by device
     195              :  */
     196              : #define MIN_FREQUENCY 0
     197              : #define MAX_FREQUENCY G_MAXULONG
     198              : #define DEFAULT_FREQUENCY 0
     199              : 
     200              : /**
     201              :  * @brief Minimum and maximum polling timeout for the buffered reading
     202              :  */
     203              : #define MIN_POLL_TIMEOUT -1
     204              : #define MAX_POLL_TIMEOUT G_MAXINT
     205              : #define DEFAULT_POLL_TIMEOUT 10000
     206              : 
     207              : /**
     208              :  * @brief Default behavior on merging channels
     209              :  */
     210              : #define DEFAULT_MERGE_CHANNELS TRUE
     211              : 
     212              : /**
     213              :  * @brief default trigger and device numbers
     214              :  */
     215              : #define DEFAULT_PROP_DEVICE_NUM -1
     216              : #define DEFAULT_PROP_TRIGGER_NUM -1
     217              : 
     218              : /**
     219              :  * blocksize for buffer
     220              :  */
     221              : #define BLOCKSIZE 1
     222              : 
     223              : /**
     224              :  * @brief IIO devices/triggers
     225              :  */
     226              : #define DEVICE "device"
     227              : #define BUFFER "buffer"
     228              : #define TRIGGER "trigger"
     229              : #define CHANNELS "scan_elements"
     230              : #define IIO "iio:"
     231              : #define TIMESTAMP "timestamp"
     232              : #define DEVICE_PREFIX IIO DEVICE
     233              : #define TRIGGER_PREFIX IIO TRIGGER
     234              : #define CURRENT_TRIGGER "current_trigger"
     235              : 
     236              : /**
     237              :  * @brief IIO device channels
     238              :  */
     239              : #define EN_SUFFIX "_en"
     240              : #define INDEX_SUFFIX "_index"
     241              : #define TYPE_SUFFIX "_type"
     242              : #define SCALE_SUFFIX "_scale"
     243              : #define OFFSET_SUFFIX "_offset"
     244              : 
     245              : /**
     246              :  * @brief filenames for IIO devices/triggers characteristics
     247              :  */
     248              : #define NAME_FILE "name"
     249              : #define AVAIL_FREQUENCY_FILE "sampling_frequency_available"
     250              : #define SAMPLING_FREQUENCY "sampling_frequency"
     251              : 
     252              : /** Define data processing functions for various types */
     253           24 : PROCESS_SCANNED_DATA (guint8, gint8);
     254          135 : PROCESS_SCANNED_DATA (guint16, gint16);
     255           24 : PROCESS_SCANNED_DATA (guint32, gint32);
     256           48 : PROCESS_SCANNED_DATA (guint64, gint64);
     257              : 
     258              : /** GObject method implementation */
     259              : static void gst_tensor_src_iio_set_property (GObject * object, guint prop_id,
     260              :     const GValue * value, GParamSpec * pspec);
     261              : static void gst_tensor_src_iio_get_property (GObject * object, guint prop_id,
     262              :     GValue * value, GParamSpec * pspec);
     263              : static void gst_tensor_src_iio_finalize (GObject * object);
     264              : 
     265              : /** GstBaseSrc method implementation */
     266              : static gboolean gst_tensor_src_iio_start (GstBaseSrc * src);
     267              : static gboolean gst_tensor_src_iio_stop (GstBaseSrc * src);
     268              : static GstStateChangeReturn gst_tensor_src_iio_change_state (GstElement *
     269              :     element, GstStateChange transition);
     270              : static gboolean gst_tensor_src_iio_event (GstBaseSrc * src, GstEvent * event);
     271              : static gboolean gst_tensor_src_iio_set_caps (GstBaseSrc * src, GstCaps * caps);
     272              : static GstCaps *gst_tensor_src_iio_get_caps (GstBaseSrc * src,
     273              :     GstCaps * filter);
     274              : static GstCaps *gst_tensor_src_iio_fixate (GstBaseSrc * src, GstCaps * caps);
     275              : static gboolean gst_tensor_src_iio_is_seekable (GstBaseSrc * src);
     276              : static GstFlowReturn gst_tensor_src_iio_create (GstBaseSrc * src,
     277              :     guint64 offset, guint size, GstBuffer ** buf);
     278              : static GstFlowReturn gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
     279              :     guint size, GstBuffer * buf);
     280              : static void gst_tensor_src_iio_get_times (GstBaseSrc * basesrc,
     281              :     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
     282              : 
     283              : /** internal functions */
     284              : 
     285              : #define gst_tensor_src_iio_parent_class parent_class
     286         1139 : G_DEFINE_TYPE (GstTensorSrcIIO, gst_tensor_src_iio, GST_TYPE_BASE_SRC);
     287              : 
     288              : /**
     289              :  * @brief initialize the tensor_src_iio class.
     290              :  */
     291              : static void
     292            1 : gst_tensor_src_iio_class_init (GstTensorSrcIIOClass * klass)
     293              : {
     294              :   GObjectClass *gobject_class;
     295              :   GstElementClass *gstelement_class;
     296              :   GstBaseSrcClass *bsrc_class;
     297              :   GstPadTemplate *pad_template;
     298              :   GstCaps *pad_caps;
     299              : 
     300            1 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_src_iio_debug, "tensor_src_iio", 0,
     301              :       "Source element to handle Linux Industrial I/O sensors as input");
     302              : 
     303            1 :   gobject_class = G_OBJECT_CLASS (klass);
     304            1 :   gstelement_class = GST_ELEMENT_CLASS (klass);
     305            1 :   bsrc_class = GST_BASE_SRC_CLASS (klass);
     306              : 
     307              :   /** GObject methods */
     308            1 :   gobject_class->set_property = gst_tensor_src_iio_set_property;
     309            1 :   gobject_class->get_property = gst_tensor_src_iio_get_property;
     310            1 :   gobject_class->finalize = gst_tensor_src_iio_finalize;
     311              : 
     312            1 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     313              :       g_param_spec_boolean ("silent", "Silent",
     314              :           "Produce verbose output", DEFAULT_PROP_SILENT,
     315              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     316              : 
     317            1 :   g_object_class_install_property (gobject_class, PROP_MODE,
     318              :       g_param_spec_string ("mode", "Operating mode",
     319              :           "Mode for the device to run in - one-shot or continuous",
     320              :           DEFAULT_OPERATING_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     321              : 
     322            1 :   g_object_class_install_property (gobject_class, PROP_BASE_DIRECTORY,
     323              :       g_param_spec_string ("iio-base-dir", "IIO Base Dir",
     324              :           "Base directory for IIO devices", DEFAULT_PROP_BASE_DIRECTORY,
     325              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     326              : 
     327            1 :   g_object_class_install_property (gobject_class, PROP_DEV_DIRECTORY,
     328              :       g_param_spec_string ("dev-dir", "Dev Dir",
     329              :           "Directory for device files", DEFAULT_PROP_DEV_DIRECTORY,
     330              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     331              : 
     332            1 :   g_object_class_install_property (gobject_class, PROP_DEVICE,
     333              :       g_param_spec_string ("device", "Device Name",
     334              :           "Name of the device to be opened", DEFAULT_PROP_STRING,
     335              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     336              : 
     337            1 :   g_object_class_install_property (gobject_class, PROP_DEVICE_NUM,
     338              :       g_param_spec_int ("device-number", "Device Number",
     339              :           "Number (numeric id) of the device to be opened",
     340              :           -1, G_MAXINT, DEFAULT_PROP_DEVICE_NUM, G_PARAM_READWRITE));
     341              : 
     342            1 :   g_object_class_install_property (gobject_class, PROP_TRIGGER,
     343              :       g_param_spec_string ("trigger", "Trigger Name",
     344              :           "Name of the trigger to be used", DEFAULT_PROP_STRING,
     345              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     346              : 
     347            1 :   g_object_class_install_property (gobject_class, PROP_TRIGGER_NUM,
     348              :       g_param_spec_int ("trigger-number", "Trigger Number",
     349              :           "Number (numeric id) of the trigger to be opened",
     350              :           -1, G_MAXINT, DEFAULT_PROP_TRIGGER_NUM, G_PARAM_READWRITE));
     351              : 
     352            1 :   g_object_class_install_property (gobject_class, PROP_CHANNELS,
     353              :       g_param_spec_string ("channels", "Channels to be enabled",
     354              :           "Specify channels to be enabled:"
     355              :           " 1) auto: enable all channels when no channels are enabled automatically,"
     356              :           " 2) all: enable all channels,"
     357              :           " 3) x,y,z: list the idx of the channels to be enabled",
     358              :           DEFAULT_OPERATING_CHANNELS_ENABLED, G_PARAM_READWRITE));
     359              : 
     360            1 :   g_object_class_install_property (gobject_class, PROP_BUFFER_CAPACITY,
     361              :       g_param_spec_uint ("buffer-capacity", "Buffer Capacity",
     362              :           "Capacity of the data buffer", MIN_BUFFER_CAPACITY,
     363              :           MAX_BUFFER_CAPACITY, DEFAULT_BUFFER_CAPACITY,
     364              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     365              : 
     366            1 :   g_object_class_install_property (gobject_class, PROP_FREQUENCY,
     367              :       g_param_spec_ulong ("frequency", "Frequency",
     368              :           "Operating frequency of the device", MIN_FREQUENCY, MAX_FREQUENCY,
     369              :           DEFAULT_FREQUENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     370              : 
     371            1 :   g_object_class_install_property (gobject_class, PROP_MERGE_CHANNELS,
     372              :       g_param_spec_boolean ("merge-channels-data", "Merge Channels Data",
     373              :           "Merge the data of channels into single tensor",
     374              :           DEFAULT_MERGE_CHANNELS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     375              : 
     376            1 :   g_object_class_install_property (gobject_class, PROP_POLL_TIMEOUT,
     377              :       g_param_spec_int ("poll-timeout", "Poll Timeout",
     378              :           "Timeout for polling in milliseconds", MIN_POLL_TIMEOUT,
     379              :           MAX_POLL_TIMEOUT, DEFAULT_POLL_TIMEOUT, G_PARAM_READWRITE));
     380              : 
     381            1 :   gst_element_class_set_static_metadata (gstelement_class,
     382              :       "TensorSrcIIO",
     383              :       "Source/Tensor/Device",
     384              :       "Src element to support linux IIO",
     385              :       "Parichay Kapoor <pk.kapoor@samsung.com>");
     386              : 
     387              :   /** pad template */
     388            1 :   pad_caps = gst_caps_from_string (GST_TENSOR_CAP_DEFAULT "; "
     389              :       GST_TENSORS_CAP_DEFAULT);
     390            1 :   pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
     391              :       pad_caps);
     392            1 :   gst_element_class_add_pad_template (gstelement_class, pad_template);
     393            1 :   gst_caps_unref (pad_caps);
     394              : 
     395            1 :   gstelement_class->change_state =
     396            1 :       GST_DEBUG_FUNCPTR (gst_tensor_src_iio_change_state);
     397              : 
     398              :   /** GstBaseSrcIIO methods */
     399            1 :   bsrc_class->start = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_start);
     400            1 :   bsrc_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_stop);
     401            1 :   bsrc_class->event = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_event);
     402            1 :   bsrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_set_caps);
     403            1 :   bsrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_get_caps);
     404            1 :   bsrc_class->fixate = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_fixate);
     405            1 :   bsrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_is_seekable);
     406            1 :   bsrc_class->create = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_create);
     407            1 :   bsrc_class->fill = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_fill);
     408            1 :   bsrc_class->get_times = GST_DEBUG_FUNCPTR (gst_tensor_src_iio_get_times);
     409            1 : }
     410              : 
     411              : /**
     412              :  * @brief delete GstTensorSrcIIODeviceProperties structure
     413              :  * @param[in] data Data pointer to be freed
     414              :  */
     415              : static void
     416          120 : gst_tensor_src_iio_channel_properties_free (gpointer data)
     417              : {
     418          120 :   GstTensorSrcIIOChannelProperties *prop =
     419              :       (GstTensorSrcIIOChannelProperties *) data;
     420          120 :   g_free (prop->name);
     421          120 :   g_free (prop->generic_name);
     422          120 :   g_free (prop->base_dir);
     423          120 :   g_free (prop->base_file);
     424          120 :   g_free (prop);
     425          120 : }
     426              : 
     427              : /**
     428              :  * @brief initialize GstTensorSrcIIODeviceProperties structure
     429              :  * @param[in] data Device properties pointer to be initialized
     430              :  */
     431              : static void
     432           36 : gst_tensor_src_iio_device_properties_init (GstTensorSrcIIODeviceProperties *
     433              :     prop)
     434              : {
     435           36 :   prop->name = NULL;
     436           36 :   prop->base_dir = NULL;
     437           36 :   prop->id = -1;
     438           36 : }
     439              : 
     440              : /**
     441              :  * @brief initialize tensor_src_iio element.
     442              :  */
     443              : static void
     444           18 : gst_tensor_src_iio_init (GstTensorSrcIIO * self)
     445              : {
     446              :   /** init properties */
     447           18 :   self->configured = FALSE;
     448           18 :   self->channels = NULL;
     449           18 :   self->custom_channel_table = NULL;
     450           18 :   self->mode = g_strdup (DEFAULT_OPERATING_MODE);
     451           18 :   self->channels_enabled = CHANNELS_ENABLED_AUTO;
     452           18 :   self->base_dir = g_strdup (DEFAULT_PROP_BASE_DIRECTORY);
     453           18 :   self->dev_dir = g_strdup (DEFAULT_PROP_DEV_DIRECTORY);
     454           18 :   gst_tensor_src_iio_device_properties_init (&self->trigger);
     455           18 :   gst_tensor_src_iio_device_properties_init (&self->device);
     456           18 :   self->silent = DEFAULT_PROP_SILENT;
     457           18 :   self->buffer_capacity = DEFAULT_BUFFER_CAPACITY;
     458           18 :   self->sampling_frequency = DEFAULT_FREQUENCY;
     459           18 :   self->merge_channels_data = DEFAULT_MERGE_CHANNELS;
     460           18 :   self->is_tensor = FALSE;
     461           18 :   self->tensors_config = NULL;
     462           18 :   self->default_sampling_frequency = 0;
     463           18 :   self->default_buffer_capacity = 0;
     464           18 :   self->default_trigger = NULL;
     465           18 :   self->poll_timeout = DEFAULT_POLL_TIMEOUT;
     466              : 
     467              :   /**
     468              :    * format of the source since IIO device as a source is live and operates
     469              :    * at a fixed frequency, GST_FORMAT_TIME is used
     470              :    */
     471           18 :   gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
     472              :   /** set the source to be live */
     473           18 :   gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
     474              :   /** set the timestamps on each buffer */
     475           18 :   gst_base_src_set_do_timestamp (GST_BASE_SRC (self), TRUE);
     476              :   /**
     477              :    * set async is necessary to make state change async
     478              :    * sync state changes does not need calling _start_complete() from _start()
     479              :    */
     480           18 :   gst_base_src_set_async (GST_BASE_SRC (self), TRUE);
     481           18 : }
     482              : 
     483              : /**
     484              :  * @brief merge multiple other/tensor
     485              :  * @note they should have matching type and shape to form 1 other/tensors
     486              :  * @note extra dimension should be available for other/tensors
     487              :  * @note order of merge is stable
     488              :  * @note merging into 1 tensor only supported using innermost dimension.
     489              :  * @param[in/out] info Tensor info to be merged
     490              :  * @param[in] size Info array size
     491              :  * @param[in] dir Innermost/outermost/innermost-outer (0/1/2) available dimension
     492              :  * @returns >=0 number of valid entries in the info after merge
     493              :  *         -1 failed due to missing extra dimension/mismatch shape/type
     494              :  */
     495              : static gint
     496           13 : gst_tensor_src_merge_tensor_by_type (GstTensorInfo * info, guint size,
     497              :     guint dir)
     498              : {
     499              :   guint info_idx, base_idx;
     500              :   gint dim_idx;
     501           13 :   gboolean mismatch = FALSE, dim_avail = FALSE;
     502           13 :   gint merge_dim = -1;
     503              : 
     504              :   /** base error control check */
     505           13 :   g_return_val_if_fail (size > 0, 0);
     506           13 :   base_idx = 0;
     507              : 
     508              :   /** verify extra dimension (innermost to outermost) */
     509          221 :   for (dim_idx = 0; dim_idx < NNS_TENSOR_RANK_LIMIT; dim_idx++) {
     510          208 :     if (info[base_idx].dimension[dim_idx] == 1) {
     511           26 :       dim_avail = TRUE;
     512              :     }
     513              :   }
     514              : 
     515              :   /** verify that all the types and shapes match */
     516           91 :   for (info_idx = 0; info_idx < size; info_idx++) {
     517           78 :     if (!gst_tensor_info_is_equal (info + base_idx, info + info_idx)) {
     518            0 :       mismatch = TRUE;
     519            0 :       break;
     520              :     }
     521              :   }
     522              : 
     523              :   /** return original if cant be merged and size within limits */
     524           13 :   if (mismatch || !dim_avail) {
     525            0 :     if (size > NNS_TENSOR_SIZE_LIMIT) {
     526            0 :       return -1;
     527              :     } else {
     528            0 :       return size;
     529              :     }
     530              :   }
     531              : 
     532              :   /**
     533              :    * If there are multiple available dimensions to merge along, we use dir
     534              :    * to choose which the dimension to merge. If there is just 1 dimension,
     535              :    * dir variable has no effect
     536              :    */
     537           13 :   if (dir == 0) {
     538           13 :     for (dim_idx = 0; dim_idx < NNS_TENSOR_RANK_LIMIT; dim_idx++) {
     539           13 :       if (info[base_idx].dimension[dim_idx] == 1) {
     540           13 :         merge_dim = dim_idx;
     541           13 :         break;
     542              :       }
     543              :     }
     544            0 :   } else if (dir == 1) {
     545            0 :     for (dim_idx = NNS_TENSOR_RANK_LIMIT - 1; dim_idx >= 0; dim_idx--) {
     546            0 :       if (info[base_idx].dimension[dim_idx] == 1) {
     547            0 :         merge_dim = dim_idx;
     548            0 :         break;
     549              :       }
     550              :     }
     551            0 :   } else if (dir == 2) {
     552            0 :     for (dim_idx = NNS_TENSOR_RANK_LIMIT - 1; dim_idx >= 0; dim_idx--) {
     553            0 :       if (info[base_idx].dimension[dim_idx] != 1) {
     554            0 :         merge_dim = dim_idx + 1;
     555            0 :         break;
     556              :       }
     557              :     }
     558              :   } else {
     559            0 :     return -1;
     560              :   }
     561              : 
     562              :   /** No outer dimension available to merge */
     563           13 :   if (merge_dim >= NNS_TENSOR_RANK_LIMIT || merge_dim < 0) {
     564            0 :     return size;
     565              :   }
     566              : 
     567              :   /** Now merge into 1 tensor using the selected dimension*/
     568           13 :   info[0].dimension[merge_dim] = size;
     569           13 :   return 1;
     570              : }
     571              : 
     572              : /**
     573              :  * @brief check if device/trigger with the given name exists
     574              :  * @param[in] dir_name Directory containing all the devices
     575              :  * @param[in] name Name of the device to be found
     576              :  * @param[in] prefix Prefix to match with the filename of the device
     577              :  * @return >=0 if OK, represents device/trigger number
     578              :  *         -1  if returned with error
     579              :  */
     580              : static gint
     581           14 : gst_tensor_src_iio_get_id_by_name (const gchar * dir_name, const gchar * name,
     582              :     const gchar * prefix)
     583              : {
     584           14 :   DIR *dptr = NULL;
     585           14 :   GError *error = NULL;
     586              :   struct dirent *dir_entry;
     587           14 :   gchar *filename = NULL;
     588           14 :   gint id = -1;
     589           14 :   gchar *file_contents = NULL;
     590           14 :   gint ret = -1;
     591              : 
     592           14 :   if (!g_file_test (dir_name, G_FILE_TEST_IS_DIR)) {
     593            1 :     GST_ERROR ("No channels available.");
     594           14 :     return ret;
     595              :   }
     596           13 :   dptr = opendir (dir_name);
     597           13 :   if (G_UNLIKELY (NULL == dptr)) {
     598            0 :     GST_ERROR ("Error in opening directory %s.\n", dir_name);
     599            0 :     return ret;
     600              :   }
     601              : 
     602           35 :   while ((dir_entry = readdir (dptr)) != NULL) {
     603              :     /** check for prefix and the next digit should be a number */
     604           35 :     if (g_str_has_prefix (dir_entry->d_name, prefix) &&
     605           13 :         g_ascii_isdigit (dir_entry->d_name[strlen (prefix)])) {
     606              : 
     607           13 :       id = (gint) g_ascii_strtoll (dir_entry->d_name + strlen (prefix), NULL,
     608              :           10);
     609              :       filename =
     610           13 :           g_build_filename (dir_name, dir_entry->d_name, NAME_FILE, NULL);
     611              : 
     612           13 :       if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
     613            0 :         GST_ERROR ("Unable to read %s, error: %s.\n", filename, error->message);
     614            0 :         g_error_free (error);
     615            0 :         goto error_free_filename;
     616              :       }
     617           13 :       g_free (filename);
     618              : 
     619           13 :       if (g_strcmp0 (file_contents, name) == 0) {
     620           13 :         ret = id;
     621           13 :         g_free (file_contents);
     622           13 :         break;
     623              :       }
     624            0 :       g_free (file_contents);
     625              :     }
     626              :   }
     627              : 
     628           13 :   closedir (dptr);
     629           13 :   return ret;
     630              : 
     631            0 : error_free_filename:
     632            0 :   g_free (filename);
     633            0 :   closedir (dptr);
     634            0 :   return ret;
     635              : }
     636              : 
     637              : /**
     638              :  * @brief check if device/trigger with the given id exists
     639              :  * @param[in] dir_name Directory containing all the devices
     640              :  * @param[in] id ID of the device to be found
     641              :  * @param[in] prefix Prefix to match with the filename of the device
     642              :  * @return name on success (owned by caller), else NULL
     643              :  */
     644              : static gchar *
     645            7 : gst_tensor_src_iio_get_name_by_id (const gchar * dir_name, const gint id,
     646              :     const gchar * prefix)
     647              : {
     648            7 :   GError *error = NULL;
     649            7 :   gchar *filename = NULL;
     650            7 :   gchar *dev_dirname = NULL;
     651            7 :   gchar *file_contents = NULL;
     652              : 
     653            7 :   dev_dirname = g_strdup_printf ("%s%d", prefix, id);
     654            7 :   filename = g_build_filename (dir_name, dev_dirname, NAME_FILE, NULL);
     655            7 :   g_free (dev_dirname);
     656              : 
     657            7 :   if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
     658            0 :     GST_ERROR ("No device available with id %d.", id);
     659            0 :     goto exit_free_filename;
     660              :   }
     661              : 
     662            7 :   if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
     663            0 :     GST_ERROR ("Unable to read %s, error: %s.\n", filename, error->message);
     664            0 :     g_error_free (error);
     665            0 :     goto exit_free_filename;
     666              :   }
     667              : 
     668            7 : exit_free_filename:
     669            7 :   g_free (filename);
     670            7 :   return file_contents;
     671              : }
     672              : 
     673              : /**
     674              :  * @brief parse float value from the file
     675              :  * @param[in] dirname Directory containing the file
     676              :  * @param[in] name Filename of the file
     677              :  * @param[in] suffix Suffix to be attached to the filename
     678              :  * @param[in/out] value Output value returned via value
     679              :  * @return FALSE on errors, else TRUE
     680              :  */
     681              : static gboolean
     682          480 : gst_tensor_src_iio_get_float_from_file (const gchar * dirname,
     683              :     const gchar * name, const gchar * suffix, gfloat * value)
     684              : {
     685          480 :   gchar *filename, *filepath, *file_contents = NULL;
     686              : 
     687          480 :   errno = 0;
     688          480 :   filename = g_strdup_printf ("%s%s", name, suffix);
     689          480 :   filepath = g_build_filename (dirname, filename, NULL);
     690              : 
     691          480 :   if (!g_file_get_contents (filepath, &file_contents, NULL, NULL)) {
     692          240 :     GST_INFO ("Unable to retrieve data from file %s.", filename);
     693              :   } else {
     694          240 :     *value = (gfloat) g_ascii_strtod (file_contents, NULL);
     695          240 :     if (errno != 0) {
     696            0 :       GST_ERROR ("Error in parsing float.");
     697            0 :       goto failure;
     698              :     }
     699          240 :     g_free (file_contents);
     700              :   }
     701          480 :   g_free (filename);
     702          480 :   g_free (filepath);
     703              : 
     704          480 :   return TRUE;
     705              : 
     706            0 : failure:
     707            0 :   g_free (file_contents);
     708            0 :   g_free (filename);
     709            0 :   g_free (filepath);
     710            0 :   return FALSE;
     711              : }
     712              : 
     713              : /**
     714              :  * @brief get type info about the channel from the string
     715              :  * @param[in/out] prop Channel properties where type info will be set
     716              :  * @param[in] contents Contains type unparsed information to be set
     717              :  * @return True if info was successfully set, false is info is not be parsed
     718              :  *         correctly
     719              :  * @detail The format for the contents is expected to be of format
     720              :  *         [be|le]:[s|u]bits/storagebits[>>shift]
     721              :  */
     722              : static gboolean
     723          120 : gst_tensor_src_iio_set_channel_type (GstTensorSrcIIOChannelProperties * prop,
     724              :     const gchar * contents)
     725              : {
     726          120 :   gchar endianchar = '\0', signchar = '\0';
     727              :   gchar *start, *end;
     728          120 :   guint base = 10;
     729          120 :   errno = 0;
     730              : 
     731              :   /** check endian */
     732          120 :   endianchar = contents[0];
     733          120 :   if (endianchar == 'b') {
     734           60 :     prop->big_endian = TRUE;
     735           60 :   } else if (endianchar == 'l') {
     736           60 :     prop->big_endian = FALSE;
     737              :   } else {
     738            0 :     goto exit_fail;
     739              :   }
     740              : 
     741              :   /** verify static parts of the contents */
     742          240 :   g_return_val_if_fail (contents[1] == 'e', FALSE);
     743          120 :   g_return_val_if_fail (contents[2] == ':', FALSE);
     744              : 
     745              :   /** check sign */
     746          120 :   signchar = contents[3];
     747          120 :   if (signchar == 's') {
     748           60 :     prop->is_signed = TRUE;
     749           60 :   } else if (signchar == 'u') {
     750           60 :     prop->is_signed = FALSE;
     751              :   } else {
     752            0 :     goto exit_fail;
     753              :   }
     754              : 
     755              :   /** used bits */
     756          120 :   start = (gchar *) contents + 4;
     757          120 :   prop->used_bits = (guint) g_ascii_strtoull (start, &end, base);
     758          120 :   if (errno != 0) {
     759            0 :     goto exit_fail;
     760              :   }
     761              :   /** verify static parts of the contents */
     762          120 :   g_return_val_if_fail (end[0] == '/', FALSE);
     763          120 :   prop->mask = G_MAXUINT64 >> (64 - prop->used_bits);
     764              : 
     765              :   /** storage bits */
     766          120 :   start = &end[1];
     767          120 :   prop->storage_bits = (guint) g_ascii_strtoull (start, &end, base);
     768          120 :   if (errno != 0) {
     769            0 :     goto exit_fail;
     770              :   }
     771              :   /** verify static parts of the contents */
     772          120 :   g_return_val_if_fail (end[0] == '>', FALSE);
     773          120 :   g_return_val_if_fail (end[1] == '>', FALSE);
     774          120 :   g_return_val_if_fail (prop->storage_bits >= prop->used_bits, FALSE);
     775              : 
     776          120 :   if (prop->storage_bits > 0) {
     777          120 :     prop->storage_bytes = ((prop->storage_bits - 1) >> 3) + 1;
     778          120 :     g_return_val_if_fail (prop->storage_bytes <= 8, FALSE);
     779              :   } else {
     780            0 :     GST_WARNING ("Storage bits are 0 for channel %s.", prop->name);
     781            0 :     prop->storage_bytes = 0;
     782              :   }
     783              : 
     784          120 :   start = &end[2];
     785          120 :   prop->shift = (guint) g_ascii_strtoull (start, &end, base);
     786          120 :   if (errno != 0) {
     787            0 :     goto exit_fail;
     788              :   }
     789          120 :   g_return_val_if_fail (prop->storage_bits > prop->shift, FALSE);
     790              : 
     791          120 :   return TRUE;
     792              : 
     793            0 : exit_fail:
     794            0 :   return FALSE;
     795              : }
     796              : 
     797              : /**
     798              :  * @brief get generic name for channel from the string
     799              :  * @param[in] channel_name Name of the channel with its id embedded in it
     800              :  * @return Ptr to the generic name of the channel, caller should free the
     801              :  *         returned string
     802              :  */
     803              : static gchar *
     804          120 : gst_tensor_src_iio_get_generic_name (const gchar * channel_name)
     805              : {
     806          120 :   gsize digit_len = 1;
     807              :   gchar *generic_name;
     808          120 :   gsize channel_name_len = strlen (channel_name);
     809              : 
     810          240 :   while (g_ascii_isdigit (channel_name[channel_name_len - digit_len])) {
     811          120 :     digit_len++;
     812              :   }
     813          120 :   generic_name = g_strndup (channel_name, channel_name_len - digit_len + 1);
     814              : 
     815          120 :   return generic_name;
     816              : }
     817              : 
     818              : /**
     819              :  * @brief compare channels for sort based on their indices
     820              :  * @param[in] a First param to be compared
     821              :  * @param[in] b Second param to be compared
     822              :  * @return negative if a<b
     823              :  *         zero if a==b
     824              :  *         positive if a>b
     825              :  */
     826              : static gint
     827          240 : gst_tensor_channel_list_sort_cmp (gconstpointer a, gconstpointer b)
     828              : {
     829          240 :   const GstTensorSrcIIOChannelProperties *a_ch = a;
     830          240 :   const GstTensorSrcIIOChannelProperties *b_ch = b;
     831          240 :   gint compare_result = a_ch->index - b_ch->index;
     832          240 :   return compare_result;
     833              : }
     834              : 
     835              : /**
     836              :  * @brief compare channels for filtering if enabled
     837              :  * @param[in] data Pointer of the data of the element
     838              :  * @param[in/out] user_data Pointer to the address of the list to be filtered
     839              :  */
     840              : static void
     841          120 : gst_tensor_channel_list_filter_enabled (gpointer data, gpointer user_data)
     842              : {
     843              :   GstTensorSrcIIOChannelProperties *channel;
     844              :   GList **list_addr;
     845              :   GList *list;
     846              : 
     847          120 :   channel = (GstTensorSrcIIOChannelProperties *) data;
     848          120 :   list_addr = (GList **) user_data;
     849          120 :   list = *list_addr;
     850              : 
     851          120 :   if (!channel->enabled) {
     852           31 :     *list_addr = g_list_remove (list, data);
     853           31 :     gst_tensor_src_iio_channel_properties_free (channel);
     854              :   }
     855          120 : }
     856              : 
     857              : /**
     858              :  * @brief get info about all the channels in the device
     859              :  * @param[in/out] self Tensor src IIO object
     860              :  * @param[in] dir_name Directory name with all the scan elements for device
     861              :  * @return >=0 number of enabled channels
     862              :  *         -1  if any error when scanning channels
     863              :  */
     864              : static gint
     865           15 : gst_tensor_src_iio_get_all_channel_info (GstTensorSrcIIO * self,
     866              :     const gchar * dir_name)
     867              : {
     868           15 :   DIR *dptr = NULL;
     869           15 :   GError *error = NULL;
     870              :   const struct dirent *dir_entry;
     871           15 :   gchar *filename = NULL;
     872           15 :   gchar *file_contents = NULL;
     873           15 :   gint ret = -1;
     874              :   guint value;
     875           15 :   guint num_channels_enabled = 0;
     876              :   gboolean generic_val, specific_val;
     877              :   gchar *generic_type_filename;
     878              :   GstTensorSrcIIOChannelProperties *channel_prop;
     879              : 
     880           15 :   if (!g_file_test (dir_name, G_FILE_TEST_IS_DIR)) {
     881            0 :     GST_ERROR_OBJECT (self, "No channels available.");
     882           15 :     return ret;
     883              :   }
     884           15 :   dptr = opendir (dir_name);
     885           15 :   if (G_UNLIKELY (NULL == dptr)) {
     886            0 :     GST_ERROR_OBJECT (self, "Error in opening directory %s.\n", dir_name);
     887            0 :     return ret;
     888              :   }
     889              : 
     890          465 :   while ((dir_entry = readdir (dptr)) != NULL) {
     891              :     /** check for enable */
     892          435 :     if (g_str_has_suffix (dir_entry->d_name, EN_SUFFIX)) {
     893              :       /** not enabling and handling buffer timestamps for now */
     894          135 :       if (g_str_has_prefix (dir_entry->d_name, TIMESTAMP)) {
     895           15 :         continue;
     896              :       }
     897              : 
     898          120 :       channel_prop = g_new0 (GstTensorSrcIIOChannelProperties, 1);
     899          120 :       if (channel_prop == NULL) {
     900            0 :         GST_ERROR_OBJECT (self, "Failed to allocate for channel property.");
     901            0 :         goto error_cleanup_list;
     902              :       }
     903              : 
     904          120 :       self->channels = g_list_prepend (self->channels, channel_prop);
     905              : 
     906              :       /** set the name and base_dir */
     907          120 :       channel_prop->name = g_strndup (dir_entry->d_name,
     908          120 :           strlen (dir_entry->d_name) - strlen (EN_SUFFIX));
     909          120 :       channel_prop->base_dir = g_strdup (dir_name);
     910          120 :       channel_prop->base_file =
     911          120 :           g_build_filename (dir_name, channel_prop->name, NULL);
     912          120 :       channel_prop->generic_name =
     913          120 :           gst_tensor_src_iio_get_generic_name (channel_prop->name);
     914          120 :       silent_debug (self, "Generic name = %s", channel_prop->generic_name);
     915              : 
     916              :       /** find and set the current state */
     917          120 :       filename = g_strdup_printf ("%s%s", channel_prop->base_file, EN_SUFFIX);
     918          120 :       if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
     919            0 :         GST_ERROR_OBJECT (self, "Unable to read %s, error: %s.\n", filename,
     920              :             error->message);
     921            0 :         goto error_free_filename;
     922              :       }
     923          120 :       g_free (filename);
     924              : 
     925          120 :       value = (guint) g_ascii_strtoull (file_contents, NULL, 10);
     926          120 :       g_free (file_contents);
     927          120 :       if (value == 1) {
     928           92 :         channel_prop->enabled = TRUE;
     929           92 :         channel_prop->pre_enabled = TRUE;
     930           92 :         num_channels_enabled += 1;
     931           28 :       } else if (value == 0) {
     932           28 :         channel_prop->enabled = FALSE;
     933           28 :         channel_prop->pre_enabled = FALSE;
     934              :       } else {
     935            0 :         GST_ERROR_OBJECT
     936              :             (self,
     937              :             "Enable bit %u (out of range) in current state of channel %s.\n",
     938              :             value, channel_prop->name);
     939            0 :         goto error_cleanup_list;
     940              :       }
     941              : 
     942              :       /** find and set the index */
     943              :       filename =
     944          120 :           g_strdup_printf ("%s%s", channel_prop->base_file, INDEX_SUFFIX);
     945          120 :       if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
     946            0 :         GST_ERROR_OBJECT (self, "Unable to read %s, error: %s.\n", filename,
     947              :             error->message);
     948            0 :         goto error_free_filename;
     949              :       }
     950          120 :       g_free (filename);
     951              : 
     952          120 :       value = (guint) g_ascii_strtoull (file_contents, NULL, 10);
     953          120 :       g_free (file_contents);
     954          120 :       channel_prop->index = value;
     955              : 
     956              :       /** find and set the type information */
     957          120 :       filename = g_strdup_printf ("%s%s", channel_prop->base_file, TYPE_SUFFIX);
     958          120 :       if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
     959              :         /** if specific type info unavailable, use generic type info */
     960            1 :         g_free (filename);
     961              :         generic_type_filename =
     962            1 :             g_strdup_printf ("%s%s", channel_prop->generic_name, TYPE_SUFFIX);
     963              :         filename =
     964            1 :             g_build_filename (channel_prop->base_dir, generic_type_filename,
     965              :             NULL);
     966            1 :         g_free (generic_type_filename);
     967              :       }
     968          120 :       if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
     969            0 :         GST_ERROR_OBJECT (self, "Unable to read %s, error: %s.\n", filename,
     970              :             error->message);
     971            0 :         goto error_free_filename;
     972              :       }
     973          120 :       g_free (filename);
     974              : 
     975          120 :       if (!gst_tensor_src_iio_set_channel_type (channel_prop, file_contents)) {
     976            0 :         GST_ERROR_OBJECT (self,
     977              :             "Error while setting up channel type for channel %s.\n",
     978              :             channel_prop->name);
     979            0 :         g_free (file_contents);
     980            0 :         goto error_cleanup_list;
     981              :       }
     982          120 :       g_free (file_contents);
     983              : 
     984              :       /** find and setup offset info */
     985          120 :       channel_prop->scale = 1.0;
     986              : 
     987              :       specific_val =
     988          240 :           gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
     989          120 :           channel_prop->name, SCALE_SUFFIX, &channel_prop->scale);
     990              :       generic_val =
     991          240 :           gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
     992          120 :           channel_prop->generic_name, SCALE_SUFFIX, &channel_prop->scale);
     993          120 :       if (!specific_val || !generic_val) {
     994            0 :         goto error_cleanup_list;
     995              :       }
     996              : 
     997              :       /** find and setup scale info */
     998          120 :       channel_prop->offset = 0.0;
     999              : 
    1000              :       specific_val =
    1001          240 :           gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
    1002          120 :           channel_prop->name, OFFSET_SUFFIX, &channel_prop->offset);
    1003              :       generic_val =
    1004          240 :           gst_tensor_src_iio_get_float_from_file (self->device.base_dir,
    1005          120 :           channel_prop->generic_name, OFFSET_SUFFIX, &channel_prop->offset);
    1006          120 :       if (!specific_val || !generic_val) {
    1007            0 :         goto error_cleanup_list;
    1008              :       }
    1009              :     }
    1010              :   }
    1011              : 
    1012              :   /** sort the list with the order of the indices */
    1013           15 :   self->channels =
    1014           15 :       g_list_sort (self->channels, gst_tensor_channel_list_sort_cmp);
    1015           15 :   ret = num_channels_enabled;
    1016              : 
    1017           15 :   closedir (dptr);
    1018           15 :   return ret;
    1019              : 
    1020            0 : error_free_filename:
    1021            0 :   g_error_free (error);
    1022            0 :   g_free (filename);
    1023              : 
    1024            0 : error_cleanup_list:
    1025            0 :   g_list_free_full (self->channels, gst_tensor_src_iio_channel_properties_free);
    1026            0 :   self->channels = NULL;
    1027              : 
    1028            0 :   closedir (dptr);
    1029            0 :   return ret;
    1030              : }
    1031              : 
    1032              : /**
    1033              :  * @brief return sampling frequency given the frequency input from user
    1034              :  * @param[in] base_dir Device base directory (containing sampling freq file)
    1035              :  * @param[in] frequency Frequency specified by user (else 0)
    1036              :  * @return >0 if OK, represents sampling frequency to be set
    1037              :  *         0  if sampling frequency file does not exist, dont change anything
    1038              :  *         -1 if any error occurs
    1039              :  */
    1040              : static gint64
    1041           16 : gst_tensor_src_iio_get_available_frequency (const gchar * base_dir,
    1042              :     const guint64 frequency)
    1043              : {
    1044           16 :   GError *error = NULL;
    1045           16 :   gchar *filename = NULL;
    1046           16 :   gchar *file_contents = NULL;
    1047           16 :   gint i = 0;
    1048           16 :   guint64 val = 0;
    1049           16 :   gint64 ret = 0;
    1050           16 :   gchar **freq_list = NULL;
    1051           16 :   gint num = 0;
    1052              : 
    1053              :   /** get frequency list supported by the device */
    1054           16 :   filename = g_build_filename (base_dir, AVAIL_FREQUENCY_FILE, NULL);
    1055           16 :   if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
    1056            0 :     GST_WARNING ("Sampling frequency file does not exist for the file %s.\n",
    1057              :         base_dir);
    1058            0 :     goto del_filename;
    1059              :   }
    1060           16 :   if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
    1061            0 :     GST_ERROR ("Unable to read sampling frequency for device %s.\n", base_dir);
    1062            0 :     g_error_free (error);
    1063            0 :     ret = -1;
    1064            0 :     goto del_filename;
    1065              :   }
    1066              : 
    1067           16 :   freq_list = g_strsplit (file_contents, " ", -1);
    1068           16 :   num = g_strv_length (freq_list);
    1069           16 :   if (num == 0) {
    1070            0 :     GST_ERROR ("No sampling frequencies for device %s.\n", base_dir);
    1071            0 :     ret = -1;
    1072            0 :     goto del_freq_list;
    1073              :   }
    1074              :   /**
    1075              :    * if the frequency is set 0, set the first available frequency
    1076              :    * else verify the frequency received from user is supported by the device
    1077              :    */
    1078           16 :   if (frequency == 0) {
    1079           13 :     ret = g_ascii_strtoll (freq_list[0], NULL, 10);
    1080              :   } else {
    1081            8 :     for (i = 0; i < num; i++) {
    1082            7 :       val = g_ascii_strtoull (freq_list[i], NULL, 10);
    1083            7 :       if (frequency == val) {
    1084            2 :         ret = frequency;
    1085            2 :         break;
    1086              :       }
    1087              :     }
    1088              :   }
    1089              : 
    1090            1 : del_freq_list:
    1091           16 :   g_strfreev (freq_list);
    1092              : 
    1093           16 : del_filename:
    1094           16 :   g_free (file_contents);
    1095           16 :   g_free (filename);
    1096           16 :   return ret;
    1097              : }
    1098              : 
    1099              : /**
    1100              :  * @brief set tensor_src_iio properties
    1101              :  */
    1102              : static void
    1103           94 : gst_tensor_src_iio_set_property (GObject * object, guint prop_id,
    1104              :     const GValue * value, GParamSpec * pspec)
    1105              : {
    1106              :   GstTensorSrcIIO *self;
    1107              :   GstStateChangeReturn ret;
    1108              :   GstState state;
    1109              : 
    1110           94 :   self = GST_TENSOR_SRC_IIO (object);
    1111              : 
    1112              :   /**
    1113              :    * No support for setting properties in PAUSED/PLAYING state as it needs to
    1114              :    * reset the device. To change the properties, user should stop the pipeline
    1115              :    * and set element state to READY/NULL and then change the properties
    1116              :    */
    1117           94 :   ret = gst_element_get_state (GST_ELEMENT (self), &state, NULL,
    1118              :       GST_CLOCK_TIME_NONE);
    1119           94 :   if (ret == GST_STATE_CHANGE_FAILURE || ret == GST_STATE_CHANGE_ASYNC
    1120           94 :       || state == GST_STATE_PLAYING || state == GST_STATE_PAUSED) {
    1121            1 :     GST_ERROR_OBJECT (self, "Can only set property in NULL or READY state.");
    1122            1 :     return;
    1123              :   }
    1124              : 
    1125           93 :   switch (prop_id) {
    1126           16 :     case PROP_SILENT:
    1127           16 :       self->silent = g_value_get_boolean (value);
    1128           16 :       break;
    1129              : 
    1130           18 :     case PROP_BASE_DIRECTORY:
    1131              :     {
    1132           18 :       const gchar *base_dir = g_value_get_string (value);
    1133              : 
    1134           18 :       if (g_path_is_absolute (base_dir)) {
    1135           17 :         g_free (self->base_dir);
    1136           17 :         self->base_dir = g_strdup (base_dir);
    1137              :       } else {
    1138            1 :         GST_ERROR_OBJECT (self, "%s is not an absolute path.", base_dir);
    1139              :       }
    1140              : 
    1141           18 :       break;
    1142              :     }
    1143           17 :     case PROP_DEV_DIRECTORY:
    1144              :     {
    1145           17 :       const gchar *dev_dir = g_value_get_string (value);
    1146              : 
    1147           17 :       if (g_path_is_absolute (dev_dir)) {
    1148           16 :         g_free (self->dev_dir);
    1149           16 :         self->dev_dir = g_strdup (dev_dir);
    1150              :       } else {
    1151            1 :         GST_ERROR_OBJECT (self, "%s is not an absolute path.", dev_dir);
    1152              :       }
    1153              : 
    1154           17 :       break;
    1155              :     }
    1156            2 :     case PROP_MODE:
    1157              :     {
    1158            2 :       if (self->mode != NULL) {
    1159            2 :         g_free (self->mode);
    1160              :       }
    1161            2 :       self->mode = g_value_dup_string (value);
    1162            2 :       break;
    1163              :     }
    1164              : 
    1165           14 :     case PROP_DEVICE:
    1166              :     {
    1167           14 :       if (self->device.name != NULL) {
    1168            1 :         g_free (self->device.name);
    1169              :       }
    1170           14 :       self->device.name = g_value_dup_string (value);
    1171           14 :       break;
    1172              :     }
    1173              : 
    1174            6 :     case PROP_DEVICE_NUM:
    1175            6 :       self->device.id = g_value_get_int (value);
    1176            6 :       break;
    1177              : 
    1178            4 :     case PROP_TRIGGER:
    1179              :     {
    1180            4 :       if (self->trigger.name != NULL) {
    1181            1 :         g_free (self->trigger.name);
    1182              :       }
    1183            4 :       self->trigger.name = g_value_dup_string (value);
    1184            4 :       break;
    1185              :     }
    1186              : 
    1187            3 :     case PROP_TRIGGER_NUM:
    1188            3 :       self->trigger.id = g_value_get_int (value);
    1189            3 :       break;
    1190              : 
    1191            4 :     case PROP_CHANNELS:
    1192              :     {
    1193            4 :       const gchar *param = g_value_get_string (value);
    1194            4 :       if (g_ascii_strncasecmp (param, CHANNELS_ENABLED_ALL_CHAR,
    1195              :               strlen (CHANNELS_ENABLED_ALL_CHAR)) == 0) {
    1196            1 :         self->channels_enabled = CHANNELS_ENABLED_ALL;
    1197            3 :       } else if (g_ascii_strncasecmp (param, CHANNELS_ENABLED_AUTO_CHAR,
    1198              :               strlen (CHANNELS_ENABLED_AUTO_CHAR)) == 0) {
    1199            1 :         self->channels_enabled = CHANNELS_ENABLED_AUTO;
    1200              :       } else {
    1201              :         gint i, num;
    1202              :         gint64 val;
    1203              :         gchar **strv;
    1204            2 :         gchar *endptr = NULL;
    1205            2 :         gboolean status = TRUE;
    1206              : 
    1207              :         /**
    1208              :          * using direct as we only need to store keys
    1209              :          * and keys form a unique set
    1210              :          */
    1211            2 :         self->custom_channel_table =
    1212            2 :             g_hash_table_new (g_direct_hash, g_direct_equal);
    1213            2 :         strv = g_strsplit_set (param, ",;", -1);
    1214            2 :         num = g_strv_length (strv);
    1215            7 :         for (i = 0; i < num; i++) {
    1216            5 :           val = g_ascii_strtoll (strv[i], &endptr, 10);
    1217            5 :           if (errno == ERANGE || errno == EINVAL || (endptr == strv[i]
    1218            0 :                   && val == 0)) {
    1219            0 :             GST_ERROR_OBJECT (self,
    1220              :                 "Cannot parse received custom channels %s. The property values for CHANNELS are ignored.",
    1221              :                 param);
    1222            0 :             g_hash_table_destroy (self->custom_channel_table);
    1223            0 :             self->custom_channel_table = NULL;
    1224            0 :             status = FALSE;
    1225            0 :             break;
    1226              :           }
    1227            5 :           if (!g_hash_table_insert (self->custom_channel_table,
    1228              :                   GINT_TO_POINTER (val), NULL)) {
    1229              :             /** this means val is duplicated. just skip it, then. */
    1230            0 :             ml_logw
    1231              :                 ("tensor-src-iio's CHANNELS property value has a duplicated entry, '%s', which is registered only once.\n",
    1232              :                 strv[i]);
    1233              :           }
    1234              :         }
    1235            2 :         if (status)
    1236            2 :           self->channels_enabled = CHANNELS_ENABLED_CUSTOM;
    1237            2 :         g_strfreev (strv);
    1238            2 :         break;
    1239              :       }
    1240            2 :       break;
    1241              :     }
    1242              : 
    1243            1 :     case PROP_BUFFER_CAPACITY:
    1244            1 :       self->buffer_capacity = g_value_get_uint (value);
    1245            1 :       break;
    1246              : 
    1247            4 :     case PROP_FREQUENCY:
    1248            4 :       self->sampling_frequency = (guint64) g_value_get_ulong (value);
    1249            4 :       break;
    1250              : 
    1251            3 :     case PROP_MERGE_CHANNELS:
    1252            3 :       self->merge_channels_data = g_value_get_boolean (value);
    1253            3 :       break;
    1254              : 
    1255            1 :     case PROP_POLL_TIMEOUT:
    1256            1 :       self->poll_timeout = g_value_get_int (value);
    1257            1 :       break;
    1258              : 
    1259            0 :     default:
    1260            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    1261            0 :       break;
    1262              :   }
    1263              : }
    1264              : 
    1265              : /**
    1266              :  * @brief get tensor_src_iio properties
    1267              :  */
    1268              : static void
    1269           27 : gst_tensor_src_iio_get_property (GObject * object, guint prop_id,
    1270              :     GValue * value, GParamSpec * pspec)
    1271              : {
    1272              :   GstTensorSrcIIO *self;
    1273           27 :   self = GST_TENSOR_SRC_IIO (object);
    1274              : 
    1275           27 :   switch (prop_id) {
    1276            2 :     case PROP_SILENT:
    1277            2 :       g_value_set_boolean (value, self->silent);
    1278            2 :       break;
    1279              : 
    1280            3 :     case PROP_MODE:
    1281            3 :       g_value_set_string (value, self->mode);
    1282            3 :       break;
    1283              : 
    1284            1 :     case PROP_BASE_DIRECTORY:
    1285            1 :       g_value_set_string (value, self->base_dir);
    1286            1 :       break;
    1287              : 
    1288            1 :     case PROP_DEV_DIRECTORY:
    1289            1 :       g_value_set_string (value, self->dev_dir);
    1290            1 :       break;
    1291              : 
    1292            3 :     case PROP_DEVICE:
    1293            3 :       g_value_set_string (value, self->device.name);
    1294            3 :       break;
    1295              : 
    1296            1 :     case PROP_DEVICE_NUM:
    1297            1 :       g_value_set_int (value, self->device.id);
    1298            1 :       break;
    1299              : 
    1300            2 :     case PROP_TRIGGER:
    1301            2 :       g_value_set_string (value, self->trigger.name);
    1302            2 :       break;
    1303              : 
    1304            1 :     case PROP_TRIGGER_NUM:
    1305            1 :       g_value_set_int (value, self->trigger.id);
    1306            1 :       break;
    1307              : 
    1308            4 :     case PROP_CHANNELS:
    1309              :     {
    1310            4 :       if (self->channels_enabled == CHANNELS_ENABLED_ALL) {
    1311            1 :         g_value_set_string (value, CHANNELS_ENABLED_ALL_CHAR);
    1312            3 :       } else if (self->channels_enabled == CHANNELS_ENABLED_AUTO) {
    1313            2 :         g_value_set_string (value, CHANNELS_ENABLED_AUTO_CHAR);
    1314              :       } else {
    1315              :         GHashTableIter iter;
    1316              :         gpointer key;
    1317            1 :         gchar *p = NULL;
    1318            1 :         GPtrArray *arr = g_ptr_array_new ();
    1319              :         gchar **strings;
    1320              : 
    1321            1 :         g_hash_table_iter_init (&iter, self->custom_channel_table);
    1322            4 :         while (g_hash_table_iter_next (&iter, &key, NULL)) {
    1323            3 :           g_ptr_array_add (arr, g_strdup_printf ("%u", GPOINTER_TO_INT (key)));
    1324              :         }
    1325            1 :         g_ptr_array_add (arr, NULL);
    1326              : 
    1327            1 :         strings = (gchar **) g_ptr_array_free (arr, FALSE);
    1328            1 :         p = g_strjoinv (",", strings);
    1329            1 :         g_strfreev (strings);
    1330            1 :         g_value_take_string (value, p);
    1331            1 :         break;
    1332              :       }
    1333            3 :       break;
    1334              :     }
    1335              : 
    1336            2 :     case PROP_BUFFER_CAPACITY:
    1337            2 :       g_value_set_uint (value, self->buffer_capacity);
    1338            2 :       break;
    1339              : 
    1340            3 :     case PROP_FREQUENCY:
    1341              :       /** interface of frequency is kept long for outside but uint64 inside */
    1342            3 :       g_value_set_ulong (value, (gulong) self->sampling_frequency);
    1343            3 :       break;
    1344              : 
    1345            2 :     case PROP_MERGE_CHANNELS:
    1346            2 :       g_value_set_boolean (value, self->merge_channels_data);
    1347            2 :       break;
    1348              : 
    1349            2 :     case PROP_POLL_TIMEOUT:
    1350            2 :       g_value_set_int (value, self->poll_timeout);
    1351            2 :       break;
    1352              : 
    1353            0 :     default:
    1354            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    1355            0 :       break;
    1356              :   }
    1357           27 : }
    1358              : 
    1359              : /**
    1360              :  * @brief finalize the instance
    1361              :  */
    1362              : static void
    1363           18 : gst_tensor_src_iio_finalize (GObject * object)
    1364              : {
    1365              :   GstTensorSrcIIO *self;
    1366           18 :   self = GST_TENSOR_SRC_IIO (object);
    1367              : 
    1368           18 :   g_free (self->mode);
    1369           18 :   g_free (self->device.name);
    1370           18 :   g_free (self->trigger.name);
    1371           18 :   g_free (self->base_dir);
    1372           18 :   g_free (self->dev_dir);
    1373           18 :   if (self->custom_channel_table) {
    1374            2 :     g_hash_table_destroy (self->custom_channel_table);
    1375              :   }
    1376              : 
    1377           18 :   G_OBJECT_CLASS (parent_class)->finalize (object);
    1378           18 : }
    1379              : 
    1380              : /**
    1381              :  * @brief write the string in to the file
    1382              :  * @param[in] self Tensor src IIO object
    1383              :  * @param[in] file Destination file for the data
    1384              :  * @param[in] base_dir Directory containing the file
    1385              :  * @param[in] contents Data to be written to the file
    1386              :  * @return True if write was successful, false on failure
    1387              :  */
    1388              : static gboolean
    1389          192 : gst_tensor_write_sysfs_string (GstTensorSrcIIO * self, const gchar * file,
    1390              :     const gchar * base_dir, const gchar * contents)
    1391              : {
    1392          192 :   gchar *filename = NULL;
    1393          192 :   gboolean ret = FALSE;
    1394          192 :   guint bytes_printed = 0;
    1395          192 :   FILE *fd = NULL;
    1396          192 :   GError *error = NULL;
    1397              : 
    1398          192 :   filename = g_build_filename (base_dir, file, NULL);
    1399          192 :   fd = g_fopen (filename, "w");
    1400          192 :   if (fd == NULL) {
    1401            0 :     GST_ERROR_OBJECT (self, "Unable to open file to write %s.\n", filename);
    1402            0 :     goto error_free_filename;
    1403              :   }
    1404              : 
    1405          192 :   bytes_printed = fprintf (fd, "%s", contents);
    1406          192 :   if (bytes_printed != strlen (contents)) {
    1407            0 :     GST_ERROR_OBJECT (self, "Unable to write to file %s.\n", filename);
    1408            0 :     goto error_close_file;
    1409              :   }
    1410          192 :   if (fclose (fd) != 0) {
    1411            0 :     GST_ERROR_OBJECT (self, "Unable to close file %s after write.\n", filename);
    1412            0 :     goto error_free_filename;
    1413              :   }
    1414          192 :   ret = TRUE;
    1415              : 
    1416          192 :   if (DBG) {
    1417          192 :     gchar *file_contents = NULL;
    1418          192 :     ret = FALSE;
    1419          192 :     if (!g_file_get_contents (filename, &file_contents, NULL, &error)) {
    1420            0 :       GST_ERROR_OBJECT (self, "Unable to read file %s with error %s.\n",
    1421              :           filename, error->message);
    1422            0 :       g_error_free (error);
    1423            0 :       goto error_free_filename;
    1424              :     } else {
    1425          192 :       if (g_strcmp0 (contents, file_contents) == 0) {
    1426          192 :         ret = TRUE;
    1427              :       }
    1428          192 :       g_free (file_contents);
    1429              :     }
    1430              :   }
    1431              : 
    1432          192 :   g_free (filename);
    1433          192 :   return ret;
    1434              : 
    1435            0 : error_close_file:
    1436            0 :   if (fclose (fd) != 0) {
    1437            0 :     GST_ERROR_OBJECT (self, "Unable to close file %s.\n", filename);
    1438              :   }
    1439              : 
    1440            0 : error_free_filename:
    1441            0 :   g_free (filename);
    1442            0 :   return ret;
    1443              : }
    1444              : 
    1445              : /**
    1446              :  * @brief write the int in to the file
    1447              :  * @param[in] self Tensor src IIO object
    1448              :  * @param[in] file Destination file for the data
    1449              :  * @param[in] base_dir Directory containing the file
    1450              :  * @param[in] contents Data to be written to the file
    1451              :  * @return True if write was successful, false on failure
    1452              :  */
    1453              : static gboolean
    1454          154 : gst_tensor_write_sysfs_int (GstTensorSrcIIO * self, const gchar * file,
    1455              :     const gchar * base_dir, const gint contents)
    1456              : {
    1457          154 :   gchar *contents_char = NULL;
    1458              :   gboolean ret;
    1459              : 
    1460          154 :   contents_char = g_strdup_printf ("%d", contents);
    1461          154 :   ret = gst_tensor_write_sysfs_string (self, file, base_dir, contents_char);
    1462              : 
    1463          154 :   g_free (contents_char);
    1464          154 :   return ret;
    1465              : }
    1466              : 
    1467              : /**
    1468              :  * @brief set value to all the channels
    1469              :  * @param[in] self Tensor src IIO object
    1470              :  * @param[in] contents Data to be written to the file
    1471              :  * @return True if write was successful, false if failure on any channel
    1472              :  */
    1473              : static gboolean
    1474            1 : gst_tensor_set_all_channels (GstTensorSrcIIO * self, const gint contents)
    1475              : {
    1476              :   GList *ch_list;
    1477            1 :   gchar *filename = NULL;
    1478            1 :   GstTensorSrcIIOChannelProperties *channel_prop = NULL;
    1479            1 :   gboolean ret = TRUE;
    1480              : 
    1481            9 :   for (ch_list = self->channels; ch_list != NULL; ch_list = ch_list->next) {
    1482            8 :     channel_prop = (GstTensorSrcIIOChannelProperties *) ch_list->data;
    1483            8 :     filename = g_strdup_printf ("%s%s", channel_prop->name, EN_SUFFIX);
    1484            8 :     if (gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
    1485              :             contents)) {
    1486            8 :       channel_prop->enabled = TRUE;
    1487              :     } else {
    1488            0 :       ret = FALSE;
    1489              :     }
    1490            8 :     g_free (filename);
    1491              :   }
    1492              : 
    1493            1 :   return ret;
    1494              : }
    1495              : 
    1496              : /**
    1497              :  * @brief get the size of the combined data from channels
    1498              :  * @param[in] channels List of all the channels
    1499              :  * @return Size of one scan of data combined from all the channels
    1500              :  *
    1501              :  * Also evaluates the location of each channel in the buffer
    1502              :  */
    1503              : static guint
    1504           15 : gst_tensor_get_size_from_channels (GList * channels)
    1505              : {
    1506           15 :   guint size_bytes = 0;
    1507           15 :   guint remain = 0;
    1508              :   GList *list;
    1509           15 :   GstTensorSrcIIOChannelProperties *channel_prop = NULL;
    1510              : 
    1511          104 :   for (list = channels; list != NULL; list = list->next) {
    1512           89 :     channel_prop = (GstTensorSrcIIOChannelProperties *) list->data;
    1513           89 :     remain = size_bytes % channel_prop->storage_bytes;
    1514           89 :     if (remain == 0) {
    1515           89 :       channel_prop->location = size_bytes;
    1516              :     } else {
    1517            0 :       channel_prop->location =
    1518            0 :           size_bytes - remain + channel_prop->storage_bytes;
    1519              :     }
    1520           89 :     size_bytes = channel_prop->location + channel_prop->storage_bytes;
    1521              :   }
    1522              : 
    1523           15 :   return size_bytes;
    1524              : }
    1525              : 
    1526              : /**
    1527              :  * @brief create the structure for the caps to update the src pad caps
    1528              :  * @param[in/out] structure Caps structure which will filled
    1529              :  * @returns True if structure is created and filled, False for any error
    1530              :  */
    1531              : static gboolean
    1532           15 : gst_tensor_src_iio_create_config (GstTensorSrcIIO * tensor_src_iio)
    1533              : {
    1534              :   GList *list;
    1535              :   GstTensorSrcIIOChannelProperties *channel_prop;
    1536              :   gint tensor_info_merged_size;
    1537           15 :   guint info_idx = 0;
    1538              :   GstTensorInfo *info, *dest;
    1539              :   GstTensorsConfig *config;
    1540              : 
    1541              :   /**
    1542              :    * create a bigger array, insert info in it and
    1543              :    * then merge tensors with same type+size
    1544              :    */
    1545           15 :   info = g_new0 (GstTensorInfo, tensor_src_iio->num_channels_enabled);
    1546           15 :   if (info == NULL) {
    1547            0 :     GST_ERROR_OBJECT (tensor_src_iio, "Failed to allocate caps config data.");
    1548            0 :     return FALSE;
    1549              :   }
    1550              : 
    1551              :   /** compile tensor info data */
    1552          104 :   for (list = tensor_src_iio->channels; list != NULL; list = list->next) {
    1553           89 :     gst_tensor_info_init (&info[info_idx]);
    1554              : 
    1555           89 :     channel_prop = (GstTensorSrcIIOChannelProperties *) list->data;
    1556           89 :     if (!channel_prop->enabled)
    1557            0 :       continue;
    1558           89 :     info[info_idx].name = channel_prop->name;
    1559           89 :     info[info_idx].type = _NNS_FLOAT32;
    1560           89 :     info[info_idx].dimension[0] = 1;
    1561           89 :     info[info_idx].dimension[1] = tensor_src_iio->buffer_capacity;
    1562           89 :     info_idx += 1;
    1563              :   }
    1564              : 
    1565           15 :   if (info_idx != tensor_src_iio->num_channels_enabled) {
    1566            0 :     GST_ERROR_OBJECT (tensor_src_iio, "The number of channel is different.");
    1567            0 :     goto error_ret;
    1568              :   }
    1569              : 
    1570              :   /** merge info about the tensors with same type */
    1571           15 :   tensor_info_merged_size = tensor_src_iio->num_channels_enabled;
    1572           15 :   if (tensor_src_iio->merge_channels_data) {
    1573              :     tensor_info_merged_size =
    1574           13 :         gst_tensor_src_merge_tensor_by_type (info,
    1575              :         tensor_src_iio->num_channels_enabled, 0);
    1576              :   }
    1577              : 
    1578              :   /** verify the merging of the array */
    1579           15 :   if (tensor_info_merged_size < 0) {
    1580            0 :     GST_ERROR_OBJECT (tensor_src_iio, "Mismatch while merging tensor");
    1581            0 :     goto error_ret;
    1582           15 :   } else if (tensor_info_merged_size == 0) {
    1583            0 :     GST_ERROR_OBJECT (tensor_src_iio, "No info to be merged");
    1584            0 :     goto error_ret;
    1585           15 :   } else if (tensor_info_merged_size > NNS_TENSOR_SIZE_LIMIT) {
    1586            0 :     GST_ERROR_OBJECT (tensor_src_iio,
    1587              :         "Number of tensors required %u for data exceed the max limit",
    1588              :         tensor_info_merged_size);
    1589            0 :     goto error_ret;
    1590              :   }
    1591              : 
    1592              :   /** tensors config data */
    1593           15 :   tensor_src_iio->is_tensor = (tensor_info_merged_size == 1);
    1594           15 :   config = g_new (GstTensorsConfig, 1);
    1595           15 :   if (config == NULL) {
    1596            0 :     goto error_ret;
    1597              :   }
    1598           15 :   gst_tensors_config_init (config);
    1599           39 :   for (info_idx = 0; info_idx < (guint) tensor_info_merged_size; info_idx++) {
    1600           24 :     dest = gst_tensors_info_get_nth_info (&config->info, info_idx);
    1601           24 :     gst_tensor_info_copy (dest, &info[info_idx]);
    1602              :   }
    1603              : 
    1604              :   /**
    1605              :    * buffer_capacity number of data samples are captured at once, packed
    1606              :    * together and sent downstream
    1607              :    */
    1608           15 :   config->rate_n = tensor_src_iio->sampling_frequency;
    1609           15 :   config->rate_d = tensor_src_iio->buffer_capacity;
    1610           15 :   config->info.num_tensors = tensor_info_merged_size;
    1611              : 
    1612           15 :   tensor_src_iio->tensors_config = config;
    1613              : 
    1614           15 :   g_free (info);
    1615           15 :   return TRUE;
    1616              : 
    1617            0 : error_ret:
    1618            0 :   g_free (info);
    1619            0 :   return FALSE;
    1620              : }
    1621              : 
    1622              : /**
    1623              :  * @brief setup device using name/id
    1624              :  * @param[in/out] self Tensor src iio object
    1625              :  * @returns TRUE on success, FALSE on failure
    1626              :  */
    1627              : static gboolean
    1628           17 : gst_tensor_src_iio_setup_device_properties (GstTensorSrcIIO * self)
    1629              : {
    1630           17 :   gchar *dirname = NULL;
    1631              : 
    1632              :   /** Find the device */
    1633           17 :   if (self->device.name != NULL) {
    1634           12 :     self->device.id =
    1635           12 :         gst_tensor_src_iio_get_id_by_name (self->base_dir, self->device.name,
    1636              :         DEVICE_PREFIX);
    1637            5 :   } else if (self->device.id >= 0) {
    1638            5 :     self->device.name = gst_tensor_src_iio_get_name_by_id (self->base_dir,
    1639              :         self->device.id, DEVICE_PREFIX);
    1640              :   } else {
    1641            0 :     GST_ERROR_OBJECT (self, "IIO device information not provided.");
    1642            0 :     goto error_return;
    1643              :   }
    1644           17 :   if (G_UNLIKELY (self->device.name == NULL || self->device.id < 0)) {
    1645            1 :     GST_ERROR_OBJECT (self, "Cannot find the specified IIO device.");
    1646            1 :     goto error_return;
    1647              :   }
    1648           16 :   dirname = g_strdup_printf ("%s%d", DEVICE_PREFIX, self->device.id);
    1649           16 :   self->device.base_dir = g_build_filename (self->base_dir, dirname, NULL);
    1650           16 :   g_free (dirname);
    1651              : 
    1652           16 :   return TRUE;
    1653              : 
    1654            1 : error_return:
    1655            1 :   return FALSE;
    1656              : }
    1657              : 
    1658              : /**
    1659              :  * @brief setup trigger using name/id
    1660              :  * @param[in/out] self Tensor src iio object
    1661              :  * @returns TRUE on success, FALSE on failure
    1662              :  */
    1663              : static gboolean
    1664           16 : gst_tensor_src_iio_setup_trigger_properties (GstTensorSrcIIO * self)
    1665              : {
    1666           16 :   gchar *dirname = NULL;
    1667           16 :   gchar *trigger_device_dir = NULL;
    1668           16 :   gchar *filename = NULL;
    1669              : 
    1670              :   /** register the trigger */
    1671           16 :   if (self->trigger.name != NULL || self->trigger.id >= 0) {
    1672              :     /** verify if trigger is supported by our device */
    1673              :     trigger_device_dir =
    1674            4 :         g_build_filename (self->device.base_dir, TRIGGER, NULL);
    1675            4 :     if (!g_file_test (trigger_device_dir, G_FILE_TEST_IS_DIR)) {
    1676            0 :       GST_ERROR_OBJECT (self, "IIO device %s does not supports trigger.\n",
    1677              :           self->device.name);
    1678            0 :       g_free (trigger_device_dir);
    1679            0 :       goto error_return;
    1680              :     }
    1681            4 :     g_free (trigger_device_dir);
    1682              : 
    1683              :     /** find if the provided trigger exists */
    1684            4 :     if (self->trigger.name != NULL) {
    1685            2 :       self->trigger.id =
    1686            2 :           gst_tensor_src_iio_get_id_by_name (self->base_dir, self->trigger.name,
    1687              :           TRIGGER_PREFIX);
    1688              :     } else {
    1689            2 :       self->trigger.name =
    1690            2 :           gst_tensor_src_iio_get_name_by_id (self->base_dir, self->trigger.id,
    1691              :           TRIGGER_PREFIX);
    1692              :     }
    1693            4 :     if (G_UNLIKELY (self->trigger.name == NULL || self->trigger.id < 0)) {
    1694            0 :       GST_ERROR_OBJECT (self, "Cannot find the specified IIO trigger.");
    1695            0 :       goto error_return;
    1696              :     }
    1697            4 :     dirname = g_strdup_printf ("%s%d", TRIGGER_PREFIX, self->trigger.id);
    1698            4 :     self->trigger.base_dir = g_build_filename (self->base_dir, dirname, NULL);
    1699            4 :     g_free (dirname);
    1700              : 
    1701              :     /** get the default trigger, if any */
    1702              :     filename =
    1703            4 :         g_build_filename (self->device.base_dir, TRIGGER, CURRENT_TRIGGER,
    1704              :         NULL);
    1705            4 :     if (!g_file_get_contents (filename, &self->default_trigger, NULL, NULL)) {
    1706            0 :       GST_WARNING_OBJECT (self, "Unable to read default set trigger.");
    1707              :     }
    1708            4 :     g_free (filename);
    1709              :     /** set the trigger */
    1710            4 :     filename = g_build_filename (TRIGGER, CURRENT_TRIGGER, NULL);
    1711            4 :     if (G_UNLIKELY (!gst_tensor_write_sysfs_string (self, filename,
    1712              :                 self->device.base_dir, self->trigger.name))) {
    1713            0 :       GST_ERROR_OBJECT (self,
    1714              :           "Cannot set the IIO device trigger: %s for device: %s.\n",
    1715              :           self->trigger.name, self->device.name);
    1716            0 :       g_free (filename);
    1717            0 :       goto error_trigger_free;
    1718              :     }
    1719            4 :     g_free (filename);
    1720              :   }
    1721              : 
    1722           16 :   return TRUE;
    1723              : 
    1724            0 : error_trigger_free:
    1725            0 :   g_free (self->trigger.base_dir);
    1726            0 :   g_free (self->default_trigger);
    1727            0 :   self->trigger.base_dir = NULL;
    1728            0 :   self->default_trigger = NULL;
    1729              : 
    1730            0 : error_return:
    1731            0 :   return FALSE;
    1732              : }
    1733              : 
    1734              : /**
    1735              :  * @brief setup device sampling frequency
    1736              :  * @param[in/out] self Tensor src iio object
    1737              :  * @returns TRUE on success, FALSE on failure
    1738              :  */
    1739              : static gboolean
    1740           16 : gst_tensor_src_iio_setup_sampling_frequency (GstTensorSrcIIO * self)
    1741              : {
    1742           16 :   gchar *filename = NULL;
    1743           16 :   gchar *file_contents = NULL;
    1744           16 :   gchar *sampling_frequency_char = NULL;
    1745              :   gint64 sampling_frequency;
    1746           16 :   gboolean sampling_frequency_file_exist = TRUE;
    1747              : 
    1748              :   /** check if sampling frequency file exists */
    1749           16 :   filename = g_build_filename (self->device.base_dir, SAMPLING_FREQUENCY, NULL);
    1750              :   sampling_frequency_file_exist =
    1751           16 :       g_file_test (filename, G_FILE_TEST_IS_REGULAR);
    1752           16 :   if (!sampling_frequency_file_exist) {
    1753            0 :     GST_WARNING_OBJECT (self, "Cannot set sampling frequency, resetting it.");
    1754              :     /** reset the sampling frequency set by the user if any, as it cant be set */
    1755            0 :     self->sampling_frequency = 0;
    1756              :   } else {
    1757              :     /** store the default frequency */
    1758           16 :     if (!g_file_get_contents (filename, &file_contents, NULL, NULL)) {
    1759            0 :       GST_WARNING_OBJECT (self, "Unable to read default sampling frequency.");
    1760           16 :     } else if (file_contents != NULL) {
    1761           16 :       self->default_sampling_frequency =
    1762           16 :           g_ascii_strtoull (file_contents, NULL, 10);
    1763              :     }
    1764           16 :     g_free (file_contents);
    1765              :   }
    1766           16 :   g_free (filename);
    1767              : 
    1768              :   /**
    1769              :    * verify the frequency given by the user if any from the list of available
    1770              :    * sampling frequencies
    1771              :    */
    1772              :   sampling_frequency =
    1773           16 :       gst_tensor_src_iio_get_available_frequency (self->device.base_dir,
    1774              :       self->sampling_frequency);
    1775              : 
    1776           16 :   if (-1 == sampling_frequency) {
    1777            0 :     GST_ERROR_OBJECT (self, "Error in verifying frequency for device %s.",
    1778              :         self->device.name);
    1779            0 :     goto error_return;
    1780           16 :   } else if (sampling_frequency == 0 && self->default_sampling_frequency == 0) {
    1781            1 :     GST_ERROR_OBJECT (self, "Sampling frequency unknown. Unknown stream rate.");
    1782            1 :     goto error_return;
    1783              :   } else {
    1784           15 :     if (0 == sampling_frequency) {
    1785              :       /** if sampling frequency file does not exist, no error */
    1786            0 :       GST_WARNING_OBJECT (self,
    1787              :           "Cannot verify against sampling frequency list.");
    1788            0 :       self->sampling_frequency = self->default_sampling_frequency;
    1789              :     } else {
    1790           15 :       self->sampling_frequency = sampling_frequency;
    1791              :       /**
    1792              :        * if sampling frequency file does not exist, sampling frequency is first
    1793              :        * value from the list of available sampling frequencies. So, we can
    1794              :        * ignore setting it
    1795              :        */
    1796           15 :       if (sampling_frequency_file_exist) {
    1797              :         /** interface of frequency is kept long for outside but uint64 inside */
    1798              :         sampling_frequency_char =
    1799           15 :             g_strdup_printf ("%lu", (gulong) self->sampling_frequency);
    1800           15 :         if (G_UNLIKELY (!gst_tensor_write_sysfs_string (self,
    1801              :                     SAMPLING_FREQUENCY, self->device.base_dir,
    1802              :                     sampling_frequency_char))) {
    1803            0 :           GST_ERROR_OBJECT (self,
    1804              :               "Cannot set the sampling frequency for device: %s.\n",
    1805              :               self->device.name);
    1806            0 :           g_free (sampling_frequency_char);
    1807            0 :           goto error_return;
    1808              :         }
    1809           15 :         g_free (sampling_frequency_char);
    1810              :       }
    1811              :     }
    1812              :   }
    1813              : 
    1814           15 :   g_assert (self->sampling_frequency > 0);
    1815           16 :   return TRUE;
    1816              : 
    1817            1 : error_return:
    1818            1 :   return FALSE;
    1819              : }
    1820              : 
    1821              : /**
    1822              :  * @brief setup scan channels for the device
    1823              :  * @param[in/out] self Tensor src iio object
    1824              :  * @returns TRUE on success, FALSE on failure
    1825              :  */
    1826              : static gboolean
    1827           15 : gst_tensor_src_iio_setup_scan_channels (GstTensorSrcIIO * self)
    1828              : {
    1829           15 :   gchar *dirname = NULL, *filename = NULL;
    1830              :   gint num_channels_enabled;
    1831              :   GList *ch_list;
    1832           15 :   gboolean item_in_table = FALSE;
    1833              :   gint channel_en;
    1834              :   GstTensorSrcIIOChannelProperties *channel_prop;
    1835              : 
    1836              : 
    1837              :   /** get all the channels that exist and then set enable on them */
    1838           15 :   dirname = g_build_filename (self->device.base_dir, CHANNELS, NULL);
    1839              :   num_channels_enabled =
    1840           15 :       gst_tensor_src_iio_get_all_channel_info (self, dirname);
    1841           15 :   g_free (dirname);
    1842           15 :   if (G_UNLIKELY (num_channels_enabled == -1)) {
    1843            0 :     GST_ERROR_OBJECT (self, "Error while scanning channels for device: %s.\n",
    1844              :         self->device.name);
    1845            0 :     goto error_return;
    1846              :   }
    1847              : 
    1848           15 :   if ((num_channels_enabled != (gint) g_list_length (self->channels)) &&
    1849              :       (num_channels_enabled == 0
    1850            5 :           || self->channels_enabled == CHANNELS_ENABLED_ALL)) {
    1851            1 :     if (!gst_tensor_set_all_channels (self, 1)) {
    1852              :       /** if enabling all channels failed, disable all channels */
    1853            0 :       GST_ERROR_OBJECT (self, "Enabling all channels failed for device: %s,"
    1854              :           "disabling all the channels.\n", self->device.name);
    1855            0 :       gst_tensor_set_all_channels (self, 0);
    1856            0 :       goto error_channels_free;
    1857              :     }
    1858              :   }
    1859              : 
    1860              :   /** enable the custom channels and disable the rest */
    1861           15 :   if (self->channels_enabled == CHANNELS_ENABLED_CUSTOM) {
    1862           18 :     for (ch_list = self->channels; ch_list != NULL; ch_list = ch_list->next) {
    1863           16 :       channel_prop = (GstTensorSrcIIOChannelProperties *) ch_list->data;
    1864           32 :       item_in_table = g_hash_table_contains (self->custom_channel_table,
    1865           16 :           GINT_TO_POINTER (channel_prop->index));
    1866           16 :       channel_en = -1;
    1867           16 :       if (!item_in_table && channel_prop->enabled) {
    1868           11 :         channel_en = 0;
    1869           11 :         channel_prop->enabled = FALSE;
    1870            5 :       } else if (item_in_table && !channel_prop->enabled) {
    1871            0 :         channel_en = 1;
    1872            0 :         channel_prop->enabled = TRUE;
    1873              :       }
    1874           16 :       if (channel_en >= 0) {
    1875           11 :         filename = g_strdup_printf ("%s%s", channel_prop->name, EN_SUFFIX);
    1876           11 :         if (!gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
    1877              :                 channel_en)) {
    1878            0 :           GST_ERROR_OBJECT (self, "Error enabling/disabling channel.");
    1879            0 :           g_free (filename);
    1880            0 :           goto error_channels_free;
    1881              :         }
    1882           11 :         g_free (filename);
    1883              :       }
    1884              :     }
    1885              :   }
    1886              : 
    1887              :   /** filter out disabled channels */
    1888           15 :   g_list_foreach (self->channels, gst_tensor_channel_list_filter_enabled,
    1889           15 :       &self->channels);
    1890           15 :   self->scan_size = gst_tensor_get_size_from_channels (self->channels);
    1891           15 :   self->num_channels_enabled = g_list_length (self->channels);
    1892              : 
    1893              :   /** set fixed caps for the src pad */
    1894           15 :   gst_pad_use_fixed_caps (GST_BASE_SRC (self)->srcpad);
    1895              : 
    1896              :   /** create tensor_config */
    1897           15 :   if (!gst_tensor_src_iio_create_config (self)) {
    1898            0 :     GST_ERROR_OBJECT (self, "Error creating config.\n");
    1899            0 :     goto error_channels_free;
    1900              :   }
    1901              : 
    1902           15 :   return TRUE;
    1903              : 
    1904            0 : error_channels_free:
    1905            0 :   g_list_free_full (self->channels, gst_tensor_src_iio_channel_properties_free);
    1906            0 :   self->channels = NULL;
    1907              : 
    1908            0 : error_return:
    1909            0 :   return FALSE;
    1910              : }
    1911              : 
    1912              : /**
    1913              :  * @brief setup device using name/id
    1914              :  * @param[in/out] self Tensor src iio object
    1915              :  * @returns TRUE on success, FALSE on failure
    1916              :  */
    1917              : static gboolean
    1918           15 : gst_tensor_src_iio_setup_device_buffer (GstTensorSrcIIO * self)
    1919              : {
    1920           15 :   gchar *dirname = NULL;
    1921           15 :   gchar *filename = NULL;
    1922           15 :   gchar *file_contents = NULL;
    1923           15 :   gsize length = 0;
    1924           15 :   gchar *device_name = NULL;
    1925              : 
    1926              :   /** once all these are set, set the buffer related thingies */
    1927           15 :   dirname = g_build_filename (self->device.base_dir, BUFFER, NULL);
    1928           15 :   filename = g_build_filename (dirname, "length", NULL);
    1929           15 :   if (!g_file_get_contents (filename, &file_contents, &length, NULL)) {
    1930            0 :     GST_WARNING_OBJECT (self, "Unable to read default buffer capacity.");
    1931           15 :   } else if (file_contents != NULL && length > 0) {
    1932            1 :     self->default_buffer_capacity =
    1933            1 :         (guint) g_ascii_strtoull (file_contents, NULL, 10);
    1934              :   }
    1935           15 :   g_free (file_contents);
    1936           15 :   g_free (filename);
    1937              : 
    1938           15 :   if (G_UNLIKELY (!gst_tensor_write_sysfs_int (self, "length", dirname,
    1939              :               self->buffer_capacity))) {
    1940            0 :     GST_ERROR_OBJECT (self,
    1941              :         "Cannot set the IIO device buffer capacity for device: %s.\n",
    1942              :         self->device.name);
    1943            0 :     g_free (dirname);
    1944            0 :     goto error_return;
    1945              :   }
    1946           15 :   g_free (dirname);
    1947              : 
    1948              :   /** open the buffer to read and ready the file descriptor */
    1949           15 :   device_name = g_strdup_printf ("%s%d", DEVICE_PREFIX, self->device.id);
    1950           15 :   filename = g_build_filename (self->dev_dir, device_name, NULL);
    1951           15 :   g_free (device_name);
    1952              : 
    1953           15 :   self->buffer_data_fp = g_new (struct pollfd, 1);
    1954           15 :   if (self->buffer_data_fp == NULL) {
    1955            0 :     GST_ERROR_OBJECT (self, "Failed to allocate the file descriptor.");
    1956            0 :     g_free (filename);
    1957            0 :     goto error_return;
    1958              :   }
    1959              : 
    1960           15 :   self->buffer_data_fp->events = POLLIN;
    1961           15 :   self->buffer_data_fp->fd = open (filename, O_RDONLY | O_NONBLOCK);
    1962           15 :   if (self->buffer_data_fp->fd < 0) {
    1963            0 :     GST_ERROR_OBJECT (self, "Failed to open buffer %s for device %s.\n",
    1964              :         filename, self->device.name);
    1965            0 :     g_free (filename);
    1966            0 :     g_free (self->buffer_data_fp);
    1967            0 :     goto error_return;
    1968              :   }
    1969           15 :   g_free (filename);
    1970              : 
    1971           15 :   return TRUE;
    1972              : 
    1973            0 : error_return:
    1974            0 :   return FALSE;
    1975              : }
    1976              : 
    1977              : /**
    1978              :  * @brief start function, called when state changed null to ready.
    1979              :  * load the device and init the device resources
    1980              :  */
    1981              : static gboolean
    1982           17 : gst_tensor_src_iio_start (GstBaseSrc * src)
    1983              : {
    1984              :   /** load and init resources */
    1985              :   GstTensorSrcIIO *self;
    1986           17 :   self = GST_TENSOR_SRC_IIO_CAST (src);
    1987              : 
    1988              :   /** no support one shot mode for now */
    1989           17 :   if (g_ascii_strncasecmp (self->mode, MODE_ONE_SHOT,
    1990              :           strlen (MODE_ONE_SHOT)) == 0) {
    1991            0 :     GST_ERROR_OBJECT (self, "One-shot mode not yet supported.");
    1992            0 :     goto error_return;
    1993              :   }
    1994              : 
    1995           17 :   if (!gst_tensor_src_iio_setup_device_properties (self)) {
    1996            1 :     GST_ERROR_OBJECT (self, "Error setting up IIO device.");
    1997            1 :     goto error_return;
    1998              :   }
    1999              : 
    2000           16 :   if (!gst_tensor_src_iio_setup_trigger_properties (self)) {
    2001            0 :     GST_ERROR_OBJECT (self, "Error setting up IIO trigger for device.");
    2002            0 :     goto error_device_free;
    2003              :   }
    2004              : 
    2005           16 :   if (!gst_tensor_src_iio_setup_sampling_frequency (self)) {
    2006            1 :     GST_ERROR_OBJECT (self, "Error setting up sampling frequency for device.");
    2007            1 :     goto error_trigger_free;
    2008              :   }
    2009              : 
    2010           15 :   if (!gst_tensor_src_iio_setup_scan_channels (self)) {
    2011            0 :     GST_ERROR_OBJECT (self, "Error setting up scan channels for device.");
    2012            0 :     goto error_trigger_free;
    2013              :   }
    2014              : 
    2015           15 :   if (!gst_tensor_src_iio_setup_device_buffer (self)) {
    2016            0 :     GST_ERROR_OBJECT (self, "Error setting up data buffer for device.");
    2017            0 :     goto error_config_free;
    2018              :   }
    2019              : 
    2020           15 :   self->configured = TRUE;
    2021              :   /** bytes every buffer will be fixed */
    2022           15 :   gst_base_src_set_dynamic_size (src, FALSE);
    2023              :   /** complete the start of the base src */
    2024           15 :   gst_base_src_start_complete (src, GST_FLOW_OK);
    2025           15 :   return TRUE;
    2026              : 
    2027            0 : error_config_free:
    2028            0 :   gst_tensors_config_free (self->tensors_config);
    2029            0 :   g_free (self->tensors_config);
    2030              : 
    2031            0 :   g_list_free_full (self->channels, gst_tensor_src_iio_channel_properties_free);
    2032            0 :   self->channels = NULL;
    2033              : 
    2034            1 : error_trigger_free:
    2035            1 :   g_free (self->trigger.base_dir);
    2036            1 :   g_free (self->default_trigger);
    2037            1 :   self->trigger.base_dir = NULL;
    2038            1 :   self->default_trigger = NULL;
    2039              : 
    2040            1 : error_device_free:
    2041            1 :   g_free (self->device.base_dir);
    2042            1 :   self->device.base_dir = NULL;
    2043              : 
    2044            2 : error_return:
    2045              :   /** complete the start of the base src */
    2046            2 :   gst_base_src_start_complete (src, GST_FLOW_ERROR);
    2047            2 :   return FALSE;
    2048              : }
    2049              : 
    2050              : /**
    2051              :  * @brief restore the iio device to its original device.
    2052              :  */
    2053              : static void
    2054           15 : gst_tensor_src_restore_iio_device (GstTensorSrcIIO * self)
    2055              : {
    2056              :   GList *ch_list;
    2057           15 :   gchar *filename = NULL, *dirname = NULL, *file_contents = NULL;
    2058           15 :   GstTensorSrcIIOChannelProperties *channel_prop = NULL;
    2059              : 
    2060              :   /** reset enabled channels */
    2061          104 :   for (ch_list = self->channels; ch_list != NULL; ch_list = ch_list->next) {
    2062           89 :     channel_prop = (GstTensorSrcIIOChannelProperties *) ch_list->data;
    2063           89 :     filename = g_strdup_printf ("%s%s", channel_prop->name, EN_SUFFIX);
    2064           89 :     gst_tensor_write_sysfs_int (self, filename, channel_prop->base_dir,
    2065           89 :         (int) channel_prop->pre_enabled);
    2066           89 :     g_free (filename);
    2067              :   }
    2068              : 
    2069              :   /** reset sampling_frequency */
    2070           15 :   if (self->default_sampling_frequency > 0) {
    2071              :     /** converting to long as setting interface to device */
    2072              :     file_contents =
    2073            1 :         g_strdup_printf ("%lu", (gulong) self->default_sampling_frequency);
    2074            1 :     gst_tensor_write_sysfs_string (self, "sampling_frequency",
    2075            1 :         self->device.base_dir, file_contents);
    2076            1 :     g_free (file_contents);
    2077              :   }
    2078              : 
    2079              :   /** reset buffer_capacity */
    2080           15 :   dirname = g_build_filename (self->device.base_dir, BUFFER, NULL);
    2081           15 :   if (self->default_buffer_capacity > 0) {
    2082            1 :     gst_tensor_write_sysfs_int (self, "length", dirname,
    2083            1 :         self->default_buffer_capacity);
    2084              :   } else {
    2085           14 :     gst_tensor_write_sysfs_string (self, "length", dirname, "");
    2086              :   }
    2087           15 :   g_free (dirname);
    2088              : 
    2089              :   /** reset current trigger */
    2090           15 :   if (self->default_trigger != NULL) {
    2091            4 :     filename = g_build_filename (TRIGGER, CURRENT_TRIGGER, NULL);
    2092            4 :     gst_tensor_write_sysfs_string (self, filename, self->device.base_dir,
    2093            4 :         self->default_trigger);
    2094            4 :     g_free (filename);
    2095              :   }
    2096           15 : }
    2097              : 
    2098              : /**
    2099              :  * @brief stop function, called when state changed ready to null.
    2100              :  */
    2101              : static gboolean
    2102           15 : gst_tensor_src_iio_stop (GstBaseSrc * src)
    2103              : {
    2104              :   /** free resources related to the device */
    2105              :   GstTensorSrcIIO *self;
    2106           15 :   self = GST_TENSOR_SRC_IIO_CAST (src);
    2107              : 
    2108           15 :   self->configured = FALSE;
    2109              : 
    2110              :   /** restore the iio device */
    2111           15 :   gst_tensor_src_restore_iio_device (self);
    2112              : 
    2113           15 :   close (self->buffer_data_fp->fd);
    2114           15 :   g_free (self->buffer_data_fp);
    2115              : 
    2116           15 :   gst_tensors_config_free (self->tensors_config);
    2117           15 :   g_free (self->tensors_config);
    2118              : 
    2119           15 :   g_list_free_full (self->channels, gst_tensor_src_iio_channel_properties_free);
    2120           15 :   self->channels = NULL;
    2121              : 
    2122           15 :   g_free (self->trigger.base_dir);
    2123           15 :   g_free (self->default_trigger);
    2124           15 :   self->trigger.base_dir = NULL;
    2125           15 :   self->default_trigger = NULL;
    2126              : 
    2127           15 :   g_free (self->device.base_dir);
    2128           15 :   self->device.base_dir = NULL;
    2129              : 
    2130           15 :   return TRUE;
    2131              : }
    2132              : 
    2133              : /**
    2134              :  * @brief handle events
    2135              :  */
    2136              : static gboolean
    2137           14 : gst_tensor_src_iio_event (GstBaseSrc * src, GstEvent * event)
    2138              : {
    2139              :   /** No events to be handled yet */
    2140           14 :   return GST_BASE_SRC_CLASS (parent_class)->event (src, event);
    2141              : }
    2142              : 
    2143              : /**
    2144              :  * @brief set new caps
    2145              :  */
    2146              : static gboolean
    2147           15 : gst_tensor_src_iio_set_caps (GstBaseSrc * src, GstCaps * caps)
    2148              : {
    2149              :   GstPad *pad;
    2150              : 
    2151           15 :   pad = src->srcpad;
    2152           15 :   if (!gst_pad_set_caps (pad, caps)) {
    2153            0 :     return FALSE;
    2154              :   }
    2155              : 
    2156           15 :   return TRUE;
    2157              : }
    2158              : 
    2159              : /**
    2160              :  * @brief get caps of subclass
    2161              :  * @note basesrc _get_caps returns the caps from the pad_template
    2162              :  * however, we set the caps manually and needs to returned here
    2163              :  */
    2164              : static GstCaps *
    2165           48 : gst_tensor_src_iio_get_caps (GstBaseSrc * src, GstCaps * filter)
    2166              : {
    2167              :   GstCaps *caps;
    2168              :   GstPad *pad;
    2169              : 
    2170           48 :   pad = src->srcpad;
    2171           48 :   caps = gst_pad_get_current_caps (pad);
    2172           48 :   if (caps == NULL) {
    2173           48 :     caps = gst_pad_get_pad_template_caps (pad);
    2174              :   }
    2175              : 
    2176           48 :   if (filter) {
    2177              :     GstCaps *intersection;
    2178              :     intersection =
    2179            0 :         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    2180            0 :     gst_caps_unref (caps);
    2181            0 :     caps = intersection;
    2182              :   }
    2183              : 
    2184           48 :   return caps;
    2185              : }
    2186              : 
    2187              : /**
    2188              :  * @brief fixate the caps when needed during negotiation
    2189              :  */
    2190              : static GstCaps *
    2191           15 : gst_tensor_src_iio_fixate (GstBaseSrc * src, GstCaps * caps)
    2192              : {
    2193              :   /**
    2194              :    * Caps are fixated based on the device source in _start().
    2195              :    */
    2196              :   GstTensorSrcIIO *self;
    2197              :   GstCaps *updated_caps, *fixated_caps;
    2198              : 
    2199           15 :   self = GST_TENSOR_SRC_IIO_CAST (src);
    2200              : 
    2201           15 :   if (self->is_tensor) {
    2202           13 :     fixated_caps = gst_tensor_caps_from_config (self->tensors_config);
    2203              :   } else {
    2204            2 :     fixated_caps = gst_tensors_caps_from_config (self->tensors_config);
    2205              :   }
    2206              : 
    2207           15 :   if (fixated_caps == NULL) {
    2208            0 :     GST_ERROR_OBJECT (self, "Error creating fixated caps from config.");
    2209            0 :     return NULL;
    2210              :   }
    2211           15 :   silent_debug (self, "Fixated caps from device = %" GST_PTR_FORMAT,
    2212              :       fixated_caps);
    2213              : 
    2214           15 :   if (gst_caps_can_intersect (caps, fixated_caps)) {
    2215           15 :     updated_caps = gst_caps_intersect (caps, fixated_caps);
    2216              :   } else {
    2217            0 :     GST_ERROR_OBJECT (self,
    2218              :         "No intersection while fixating caps of the element.");
    2219            0 :     gst_caps_unref (caps);
    2220            0 :     gst_caps_unref (fixated_caps);
    2221            0 :     return NULL;
    2222              :   }
    2223              : 
    2224           15 :   gst_caps_unref (caps);
    2225           15 :   gst_caps_unref (fixated_caps);
    2226           15 :   return gst_caps_fixate (updated_caps);
    2227              : }
    2228              : 
    2229              : /**
    2230              :  * @brief Perform state change.
    2231              :  */
    2232              : static GstStateChangeReturn
    2233           98 : gst_tensor_src_iio_change_state (GstElement * element,
    2234              :     GstStateChange transition)
    2235              : {
    2236              :   GstTensorSrcIIO *self;
    2237              :   GstStateChangeReturn ret;
    2238           98 :   gboolean buffer_state_change_success = TRUE;
    2239           98 :   gchar *dirname = NULL;
    2240              : 
    2241           98 :   self = GST_TENSOR_SRC_IIO (element);
    2242              : 
    2243           98 :   switch (transition) {
    2244           15 :     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
    2245              :     {
    2246              :       /** enable the buffer for the data to be captured */
    2247           15 :       dirname = g_build_filename (self->device.base_dir, BUFFER, NULL);
    2248           15 :       if (G_UNLIKELY (!gst_tensor_write_sysfs_int (self, "enable", dirname, 1))) {
    2249            0 :         GST_ERROR_OBJECT (self,
    2250              :             "Cannot enable the IIO device buffer for device: %s.\n",
    2251              :             self->device.name);
    2252            0 :         buffer_state_change_success = FALSE;
    2253              :       }
    2254           15 :       g_free (dirname);
    2255           15 :       break;
    2256              :     }
    2257           83 :     default:
    2258           83 :       break;
    2259              :   }
    2260              : 
    2261           98 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    2262              : 
    2263           98 :   switch (transition) {
    2264           15 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
    2265              :     {
    2266              :       /** disable the buffer */
    2267           15 :       dirname = g_build_filename (self->device.base_dir, BUFFER, NULL);
    2268           15 :       if (G_UNLIKELY (!gst_tensor_write_sysfs_int (self, "enable", dirname, 0))) {
    2269            0 :         GST_ERROR_OBJECT (self,
    2270              :             "Error in disabling the IIO device buffer for device: %s.\n",
    2271              :             self->device.name);
    2272            0 :         buffer_state_change_success = FALSE;
    2273              :       }
    2274           15 :       g_free (dirname);
    2275           15 :       break;
    2276              :     }
    2277           83 :     default:
    2278           83 :       break;
    2279              :   }
    2280              : 
    2281           98 :   if (!buffer_state_change_success) {
    2282            0 :     ret = GST_STATE_CHANGE_FAILURE;
    2283              :   }
    2284              : 
    2285           98 :   return ret;
    2286              : }
    2287              : 
    2288              : /**
    2289              :  * @brief check if source supports seeking
    2290              :  */
    2291              : static gboolean
    2292           15 : gst_tensor_src_iio_is_seekable (GstBaseSrc * src)
    2293              : {
    2294              :   UNUSED (src);
    2295              :   /** iio sensors are live source without any support for seeking */
    2296           15 :   return FALSE;
    2297              : }
    2298              : 
    2299              : /**
    2300              :  * @brief returns the time for the buffers
    2301              :  */
    2302              : static void
    2303           27 : gst_tensor_src_iio_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
    2304              :     GstClockTime * start, GstClockTime * end)
    2305              : {
    2306              :   GstClockTime timestamp;
    2307              :   GstClockTime duration;
    2308              :   UNUSED (basesrc);
    2309              : 
    2310           27 :   timestamp = GST_BUFFER_DTS (buffer);
    2311           27 :   duration = GST_BUFFER_DURATION (buffer);
    2312              : 
    2313              :   /** can't sync using DTS, use PTS */
    2314           27 :   if (!GST_CLOCK_TIME_IS_VALID (timestamp))
    2315           27 :     timestamp = GST_BUFFER_PTS (buffer);
    2316              : 
    2317           27 :   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
    2318            0 :     *start = timestamp;
    2319            0 :     if (GST_CLOCK_TIME_IS_VALID (duration)) {
    2320            0 :       *end = timestamp + duration;
    2321              :     }
    2322              :   }
    2323           27 : }
    2324              : 
    2325              : /**
    2326              :  * @brief create a buffer with requested size and offset
    2327              :  * @note offset, size ignored as the tensor src iio does not support pull mode
    2328              :  */
    2329              : static GstFlowReturn
    2330           37 : gst_tensor_src_iio_create (GstBaseSrc * src, guint64 offset,
    2331              :     guint size, GstBuffer ** buffer)
    2332              : {
    2333              :   GstTensorSrcIIO *self;
    2334           37 :   GstFlowReturn ret = GST_FLOW_ERROR;
    2335              :   GstBuffer *buf;
    2336              :   GstMemory *mem;
    2337              :   GstTensorInfo *_info;
    2338              :   gsize buffer_size;
    2339           37 :   guint idx = 0;
    2340              :   UNUSED (size);
    2341              : 
    2342           37 :   self = GST_TENSOR_SRC_IIO_CAST (src);
    2343           37 :   buf = gst_buffer_new ();
    2344           37 :   buffer_size = gst_tensors_info_get_size (&self->tensors_config->info, 0);
    2345              : 
    2346          118 :   for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
    2347              :     /** all the data, if unermged should be of the same size*/
    2348           81 :     _info = gst_tensors_info_get_nth_info (&self->tensors_config->info, idx);
    2349           81 :     g_assert (buffer_size == gst_tensor_info_get_size (_info));
    2350              : 
    2351           81 :     mem = gst_allocator_alloc (NULL, buffer_size, NULL);
    2352           81 :     if (mem == NULL) {
    2353            0 :       GST_ERROR_OBJECT (self, "Error allocating memory for buffer.");
    2354            0 :       goto error;
    2355              :     }
    2356              : 
    2357           81 :     gst_tensor_buffer_append_memory (buf, mem, _info);
    2358              :   }
    2359              : 
    2360           37 :   ret = gst_tensor_src_iio_fill (src, offset, (guint) buffer_size, buf);
    2361              : 
    2362           37 : error:
    2363           37 :   if (ret == GST_FLOW_OK)
    2364           36 :     *buffer = buf;
    2365              :   else
    2366            1 :     gst_buffer_unref (buf);
    2367              : 
    2368           37 :   return ret;
    2369              : }
    2370              : 
    2371              : /**
    2372              :  * @brief process the scanned data from IIO device
    2373              :  * @param[in] prop Properties of one of the enabled channels
    2374              :  * @param[in] data Data read from the IIO device
    2375              :  * @param[in/out] buffer_map Gst buffer map to write data to
    2376              :  * @returns FALSE if fail, else TRUE
    2377              :  *
    2378              :  * assumes each data starting point is byte aligned
    2379              :  */
    2380              : static gboolean
    2381          231 : gst_tensor_src_iio_process_scanned_data (GstTensorSrcIIOChannelProperties *
    2382              :     prop, gchar * data, gfloat * buffer_map)
    2383              : {
    2384              :   guint64 storage_mask;
    2385          231 :   switch (prop->storage_bytes) {
    2386           24 :     case 1:
    2387              :     {
    2388           24 :       guint8 value = *(guint8 *) (data + prop->location);
    2389              :         /** right shift the extra storage bits */
    2390           24 :       value >>= (8 - prop->storage_bits);
    2391           24 :       *buffer_map =
    2392           24 :           gst_tensor_src_iio_process_scanned_data_from_guint8 (prop, value);
    2393           24 :       break;
    2394              :     }
    2395          135 :     case 2:
    2396              :     {
    2397          135 :       guint16 value = *(guint16 *) (data + prop->location);
    2398          135 :       if (prop->big_endian) {
    2399           68 :         value = GUINT16_FROM_BE (value);
    2400              :           /** right shift the extra storage bits for big endian */
    2401           68 :         value >>= (16 - prop->storage_bits);
    2402              :       } else {
    2403           67 :         value = GUINT16_FROM_LE (value);
    2404              :           /** mask out the extra storage bits for little endian */
    2405           67 :         storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
    2406           67 :         value &= storage_mask;
    2407              :       }
    2408          135 :       *buffer_map =
    2409          135 :           gst_tensor_src_iio_process_scanned_data_from_guint16 (prop, value);
    2410          135 :       break;
    2411              :     }
    2412           24 :     case 3:
    2413              :       /** follow through */
    2414              :     case 4:
    2415              :     {
    2416           24 :       guint32 value = *(guint32 *) (data + prop->location);
    2417           24 :       if (prop->big_endian) {
    2418           16 :         value = GUINT32_FROM_BE (value);
    2419              :           /** right shift the extra storage bits for big endian */
    2420           16 :         value >>= (32 - prop->storage_bits);
    2421              :       } else {
    2422            8 :         value = GUINT32_FROM_LE (value);
    2423              :           /** mask out the extra storage bits for little endian */
    2424            8 :         storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
    2425            8 :         value &= storage_mask;
    2426              :       }
    2427           24 :       *buffer_map =
    2428           24 :           gst_tensor_src_iio_process_scanned_data_from_guint32 (prop, value);
    2429           24 :       break;
    2430              :     }
    2431           48 :     case 5:
    2432              :       /** follow through */
    2433              :     case 6:
    2434              :       /** follow through */
    2435              :     case 7:
    2436              :       /** follow through */
    2437              :     case 8:
    2438              :     {
    2439           48 :       guint64 value = *(guint64 *) (data + prop->location);
    2440           48 :       if (prop->big_endian) {
    2441           32 :         value = GUINT64_FROM_BE (value);
    2442              :           /** right shift the extra storage bits for big endian */
    2443           32 :         value >>= (64 - prop->storage_bits);
    2444              :       } else {
    2445           16 :         value = GUINT64_FROM_LE (value);
    2446              :           /** mask out the extra storage bits for little endian */
    2447           16 :         storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
    2448           16 :         value &= storage_mask;
    2449              :       }
    2450           48 :       *buffer_map =
    2451           48 :           gst_tensor_src_iio_process_scanned_data_from_guint64 (prop, value);
    2452           48 :       break;
    2453              :     }
    2454            0 :     default:
    2455            0 :       GST_ERROR ("Storage bytes for channel %s out of bounds", prop->name);
    2456            0 :       return FALSE;
    2457              :   }
    2458          231 :   return TRUE;
    2459              : }
    2460              : 
    2461              : /**
    2462              :  * @brief fill the buffer with data
    2463              :  * @note ignore offset,size as there is pull mode
    2464              :  * @note buffer timestamp is already handled by gstreamer with gst clock
    2465              :  */
    2466              : static GstFlowReturn
    2467           37 : gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset, guint size,
    2468              :     GstBuffer * buffer)
    2469              : {
    2470              :   GstTensorSrcIIO *self;
    2471           37 :   GstFlowReturn ret = GST_FLOW_ERROR;
    2472              :   gint status, bytes_to_read;
    2473              :   guint idx, ch_idx, num_mapped;
    2474              :   gchar *raw_data_base, *raw_data;
    2475              :   gfloat *map_data_float;
    2476              :   GstMemory *mem[NNS_TENSOR_SIZE_LIMIT];
    2477              :   GstMapInfo map[NNS_TENSOR_SIZE_LIMIT];
    2478              :   guint64 time_to_end, cur_time;
    2479              :   guint64 safe_multiply;
    2480              :   GList *channels;
    2481              :   UNUSED (offset);
    2482              :   UNUSED (size);
    2483              : 
    2484           37 :   self = GST_TENSOR_SRC_IIO (src);
    2485              : 
    2486              :   /** Only supporting tensors made of 1 tensor for now */
    2487           37 :   g_assert (gst_tensor_buffer_get_count (buffer) ==
    2488              :       self->tensors_config->info.num_tensors);
    2489              : 
    2490              :   /** get writable buffer */
    2491           37 :   num_mapped = 0;
    2492          118 :   for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
    2493           81 :     mem[idx] = gst_tensor_buffer_get_nth_memory (buffer, idx);
    2494           81 :     if (!gst_memory_map (mem[idx], &map[idx], GST_MAP_WRITE)) {
    2495            0 :       for (ch_idx = 0; ch_idx < num_mapped; ch_idx++) {
    2496            0 :         gst_memory_unmap (mem[ch_idx], &map[ch_idx]);
    2497            0 :         gst_memory_unref (mem[ch_idx]);
    2498              :       }
    2499            0 :       gst_memory_unref (mem[idx]);
    2500           37 :       return GST_FLOW_ERROR;
    2501              :     }
    2502           81 :     num_mapped = idx + 1;
    2503              :   }
    2504              :   /** memory to data from file */
    2505           37 :   bytes_to_read = self->scan_size * self->buffer_capacity;
    2506           37 :   raw_data_base = g_malloc (bytes_to_read);
    2507           37 :   if (raw_data_base == NULL) {
    2508            0 :     GST_ERROR_OBJECT (self, "Failed to allocate memory to read raw data.");
    2509            0 :     goto error_data_free;
    2510              :   }
    2511              : 
    2512              :   /** wait for the data to arrive */
    2513           37 :   time_to_end = g_get_real_time () + self->poll_timeout * 1000;
    2514              :   while (TRUE) {
    2515         9663 :     if (self->trigger.name != NULL) {
    2516           15 :       status = poll (self->buffer_data_fp, 1, self->poll_timeout);
    2517           15 :       if (status < 0) {
    2518            0 :         GST_ERROR_OBJECT (self, "Error %d while polling the buffer.", status);
    2519            0 :         goto error_data_free;
    2520           15 :       } else if (status == 0) {
    2521            0 :         GST_ERROR_OBJECT (self, "Timeout while polling the buffer.");
    2522            0 :         goto error_data_free;
    2523           15 :       } else if (!(self->buffer_data_fp->revents & POLLIN)) {
    2524            0 :         GST_ERROR_OBJECT (self, "Poll succeeded on an unexpected event %d.",
    2525              :             self->buffer_data_fp->revents);
    2526            0 :         goto error_data_free;
    2527              :       }
    2528           15 :       self->buffer_data_fp->revents = 0;
    2529              :     } else {
    2530              :       /** sleep for a device tick */
    2531         9648 :       if (g_uint64_checked_mul (&safe_multiply, G_USEC_PER_SEC,
    2532              :               self->buffer_capacity)) {
    2533         9648 :         g_usleep (MAX (1, safe_multiply / self->sampling_frequency));
    2534              :       } else {
    2535            0 :         g_usleep (MAX (1,
    2536              :                 (self->buffer_capacity / self->sampling_frequency) *
    2537              :                 G_USEC_PER_SEC));
    2538              :       }
    2539              :     }
    2540              : 
    2541              :     /** using read for non-blocking access */
    2542         9663 :     status = read (self->buffer_data_fp->fd, raw_data_base, bytes_to_read);
    2543         9663 :     if (status < bytes_to_read) {
    2544         9627 :       if (errno == EAGAIN) {
    2545         9627 :         GST_WARNING_OBJECT (self, "EAGAIN error, try again.");
    2546         9627 :         cur_time = g_get_real_time ();
    2547         9627 :         if (time_to_end >= cur_time) {
    2548         9626 :           continue;
    2549              :         } else {
    2550            1 :           GST_ERROR_OBJECT (self, "EAGAIN timeout expired.");
    2551            1 :           goto error_data_free;
    2552              :         }
    2553              :       }
    2554            0 :       GST_ERROR_OBJECT (self,
    2555              :           "Error no %d: read %d/%d bytes while reading from the buffer fd.",
    2556              :           errno, status, bytes_to_read);
    2557            0 :       goto error_data_free;
    2558              :     }
    2559           36 :     break;
    2560              :   }
    2561              : 
    2562              :   /** parse the read data */
    2563           36 :   raw_data = raw_data_base;
    2564              : 
    2565              :   /**
    2566              :    * current assumption is that the all data is float and merged to form
    2567              :    * a 1 dimension data. 2nd dimension comes from buffer capacity.
    2568              :    */
    2569           72 :   for (idx = 0; idx < self->buffer_capacity; idx++) {
    2570           36 :     for (channels = self->channels, ch_idx = 0;
    2571          267 :         ch_idx < self->num_channels_enabled;
    2572          231 :         ch_idx++, channels = channels->next) {
    2573          231 :       if (self->tensors_config->info.num_tensors == 1) {
    2574              :         /** for other/tensor, only 1 map exist as there is only 1 mem */
    2575          180 :         map_data_float =
    2576          180 :             ((gfloat *) map[0].data) + idx * self->num_channels_enabled +
    2577              :             ch_idx;
    2578              :       } else {
    2579              :         /** for other/tensors, multiple maps exist as there are multiple mem */
    2580           51 :         map_data_float = ((gfloat *) map[ch_idx].data) + idx;
    2581              :       }
    2582          231 :       if (!gst_tensor_src_iio_process_scanned_data (channels->data, raw_data,
    2583              :               map_data_float)) {
    2584            0 :         GST_ERROR_OBJECT (self, "Error while processing scanned data.");
    2585            0 :         goto error_data_free;
    2586              :       }
    2587              :     }
    2588           36 :     raw_data += self->scan_size;
    2589              :   }
    2590              : 
    2591           36 :   ret = GST_FLOW_OK;
    2592              : 
    2593           37 : error_data_free:
    2594           37 :   g_free (raw_data_base);
    2595          118 :   for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
    2596           81 :     gst_memory_unmap (mem[idx], &map[idx]);
    2597           81 :     gst_memory_unref (mem[idx]);
    2598              :   }
    2599              : 
    2600           37 :   return ret;
    2601              : }
        

Generated by: LCOV version 2.0-1