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 : }
|