-
Notifications
You must be signed in to change notification settings - Fork 333
/
Copy pathstream.c
145 lines (120 loc) · 3.34 KB
/
stream.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libiio - Library for interfacing industrial I/O (IIO) devices
*
* Copyright (C) 2022 Analog Devices, Inc.
* Author: Paul Cercueil <[email protected]>
*/
#include "iio-private.h"
#include <errno.h>
#include <iio/iio-debug.h>
#include <stdbool.h>
#include <stdlib.h>
struct iio_stream {
struct iio_buffer *buffer;
struct iio_block **blocks;
size_t nb_blocks;
bool started, buf_enabled, all_enqueued;
unsigned int curr;
};
struct iio_stream *
iio_buffer_create_stream(struct iio_buffer *buffer, size_t nb_blocks,
size_t samples_count)
{
struct iio_stream *stream;
size_t i, sample_size, buf_size;
int err;
if (!nb_blocks || !samples_count)
return iio_ptr(-EINVAL);
stream = zalloc(sizeof(*stream));
if (!stream)
return iio_ptr(-ENOMEM);
stream->blocks = calloc(nb_blocks, sizeof(*stream->blocks));
if (!stream->blocks) {
err = -ENOMEM;
goto err_free_stream;
}
sample_size = iio_device_get_sample_size(buffer->dev, buffer->mask);
buf_size = samples_count * sample_size;
for (i = 0; i < nb_blocks; i++) {
stream->blocks[i] = iio_buffer_create_block(buffer, buf_size);
err = iio_err(stream->blocks[i]);
if (err) {
stream->blocks[i] = NULL;
goto err_free_stream_blocks;
}
}
stream->buffer = buffer;
stream->nb_blocks = nb_blocks;
return stream;
err_free_stream_blocks:
for (i = 0; i < nb_blocks; i++)
if (stream->blocks[i])
iio_block_destroy(stream->blocks[i]);
free(stream->blocks);
err_free_stream:
free(stream);
return iio_ptr(err);
}
void iio_stream_destroy(struct iio_stream *stream)
{
size_t i;
for (i = 0; i < stream->nb_blocks; i++)
if (stream->blocks[i]) {
/* Make sure to dequeue any possible in flight block
* before destroying it. Note that if the block is not
* enqueued, this returns an error but we really don't
* care about it. Making sure the block is dequeued makes
* for a much cleaner exit specially in cases where freeing
* the blocks is deferred to the default client.
*/
iio_block_dequeue(stream->blocks[i], false);
iio_block_destroy(stream->blocks[i]);
}
free(stream->blocks);
free(stream);
}
const struct iio_block *
iio_stream_get_next_block(struct iio_stream *stream)
{
const struct iio_device *dev = stream->buffer->dev;
bool is_tx = iio_device_is_tx(dev);
unsigned int i;
int err;
if (!stream->started) {
for (i = 1; !is_tx && i < stream->nb_blocks; i++) {
err = iio_block_enqueue(stream->blocks[i], 0, false);
if (err) {
dev_perror(dev, err, "Unable to enqueue block");
return iio_ptr(err);
}
}
stream->started = true;
if (is_tx)
return stream->blocks[0];
stream->all_enqueued = true;
}
err = iio_block_enqueue(stream->blocks[stream->curr], 0, false);
if (err < 0) {
dev_perror(dev, err, "Unable to enqueue block");
return iio_ptr(err);
}
if (!stream->buf_enabled) {
err = iio_buffer_enable(stream->buffer);
if (err) {
dev_perror(dev, err, "Unable to enable buffer");
return iio_ptr(err);
}
stream->buf_enabled = true;
}
stream->curr = (stream->curr + 1) % stream->nb_blocks;
stream->all_enqueued |= stream->curr == 0;
if (stream->all_enqueued) {
err = iio_block_dequeue(stream->blocks[stream->curr], false);
if (err < 0) {
dev_perror(dev, err, "Unable to dequeue block");
return iio_ptr(err);
}
}
return stream->blocks[stream->curr];
}