blob: fc4e549b7e461efa77c3ead5845d84040cb8e895 [file] [log] [blame]
Paul Cercueilbb4401d2014-02-28 16:10:49 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
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 * Lesser General Public License for more details.
16 *
17 * */
18
Paul Cercueil42090d12014-02-24 12:32:23 +010019#include "debug.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010020#include "iio-private.h"
21
Paul Cercueil6a013602014-02-19 12:37:39 +010022#include <errno.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010023#include <stdio.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010024#include <string.h>
25
26static char *get_attr_xml(const char *attr, size_t *length)
27{
28 size_t len = sizeof("<attribute name=\"\" />") + strlen(attr);
29 char *str = malloc(len);
30 if (!str) {
31 ERROR("Unable to allocate memory\n");
32 return NULL;
33 }
34
35 *length = len - 1; /* Skip the \0 */
36 sprintf(str, "<attribute name=\"%s\" />", attr);
37 return str;
38}
39
40/* Returns a string containing the XML representation of this device */
41char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
42{
43 size_t len = sizeof("<device id=\"\" name=\"\" ></device>");
44 char *ptr, *str, *attrs[dev->nb_attrs], *channels[dev->nb_channels];
45 size_t attrs_len[dev->nb_attrs], channels_len[dev->nb_channels];
46 unsigned int i, j;
47
48 for (i = 0; i < dev->nb_attrs; i++) {
49 char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i]);
50 if (!xml)
51 goto err_free_attrs;
52 attrs[i] = xml;
53 len += attrs_len[i];
54 }
55
56 for (j = 0; j < dev->nb_channels; j++) {
57 char *xml = iio_channel_get_xml(dev->channels[j],
58 &channels_len[j]);
59 if (!xml)
60 goto err_free_channels;
61 channels[j] = xml;
62 len += channels_len[j];
63 }
64
65 len += strlen(dev->id);
66 if (dev->name)
67 len += strlen(dev->name);
68
69 str = malloc(len);
70 if (!str)
71 goto err_free_channels;
72
73 sprintf(str, "<device id=\"%s\"", dev->id);
74 ptr = strrchr(str, '\0');
75
76 if (dev->name) {
77 sprintf(ptr, " name=\"%s\"", dev->name);
78 ptr = strrchr(ptr, '\0');
79 }
80
81 strcpy(ptr, " >");
82 ptr += 2;
83
84 for (i = 0; i < dev->nb_channels; i++) {
85 strcpy(ptr, channels[i]);
86 ptr += channels_len[i];
87 free(channels[i]);
88 }
89
90 for (i = 0; i < dev->nb_attrs; i++) {
91 strcpy(ptr, attrs[i]);
92 ptr += attrs_len[i];
93 free(attrs[i]);
94 }
95
96 strcpy(ptr, "</device>");
97 *length = ptr - str + sizeof("</device>") - 1;
98 return str;
99
100err_free_channels:
101 while (j--)
102 free(channels[j]);
103err_free_attrs:
104 while (i--)
105 free(attrs[i]);
106 return NULL;
107}
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100108
109const char * iio_device_get_id(const struct iio_device *dev)
110{
111 return dev->id;
112}
113
114const char * iio_device_get_name(const struct iio_device *dev)
115{
116 return dev->name;
117}
118
119unsigned int iio_device_get_channels_count(const struct iio_device *dev)
120{
121 return dev->nb_channels;
122}
123
124struct iio_channel * iio_device_get_channel(const struct iio_device *dev,
125 unsigned int index)
126{
127 if (index >= dev->nb_channels)
128 return NULL;
129 else
130 return dev->channels[index];
131}
132
133unsigned int iio_device_get_attrs_count(const struct iio_device *dev)
134{
135 return dev->nb_attrs;
136}
137
138const char * iio_device_get_attr(const struct iio_device *dev,
139 unsigned int index)
140{
141 if (index >= dev->nb_attrs)
142 return NULL;
143 else
144 return dev->attrs[index];
145}
146
Paul Cercueil3cc3a002014-03-24 13:44:11 +0100147static int iio_device_open_mask(const struct iio_device *dev,
Paul Cercueile1311222014-03-12 15:46:16 +0100148 uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100149{
150 if (dev->ctx->ops->open)
Paul Cercueile1311222014-03-12 15:46:16 +0100151 return dev->ctx->ops->open(dev, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100152 else
153 return -ENOSYS;
154}
155
Paul Cercueile1311222014-03-12 15:46:16 +0100156int iio_device_open(const struct iio_device *dev)
157{
158 size_t nb = (dev->nb_channels + 31) / 32;
159 uint32_t *mask = NULL;
160 unsigned int i;
161 int ret;
162
163 if (nb > 0) {
164 mask = calloc(nb, sizeof(*mask));
165 if (!mask)
166 return -ENOMEM;
167 }
168
169 for (i = 0; i < dev->nb_channels; i++) {
170 struct iio_channel *chn = dev->channels[i];
171 if (iio_channel_is_enabled(chn) && chn->index >= 0)
172 SET_BIT(mask, chn->index);
173 }
174
175 ret = iio_device_open_mask(dev, mask, nb);
176 free(mask);
177 return ret;
178}
179
Paul Cercueilec1760d2014-02-21 11:31:20 +0100180int iio_device_close(const struct iio_device *dev)
181{
182 if (dev->ctx->ops->close)
183 return dev->ctx->ops->close(dev);
184 else
185 return -ENOSYS;
186}
187
188ssize_t iio_device_read_raw(const struct iio_device *dev,
Paul Cercueil45c575d2014-03-20 15:14:01 +0100189 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100190{
191 if (dev->ctx->ops->read)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100192 return dev->ctx->ops->read(dev, dst, len, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100193 else
194 return -ENOSYS;
195}
196
197ssize_t iio_device_write_raw(const struct iio_device *dev,
198 const void *src, size_t len)
199{
200 if (dev->ctx->ops->write)
201 return dev->ctx->ops->write(dev, src, len);
202 else
203 return -ENOSYS;
204}
205
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100206ssize_t iio_device_attr_read(const struct iio_device *dev,
207 const char *attr, char *dst, size_t len)
208{
Paul Cercueil6a013602014-02-19 12:37:39 +0100209 if (dev->ctx->ops->read_device_attr)
210 return dev->ctx->ops->read_device_attr(dev, attr, dst, len);
211 else
212 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100213}
214
215ssize_t iio_device_attr_write(const struct iio_device *dev,
216 const char *attr, const char *src)
217{
Paul Cercueil6a013602014-02-19 12:37:39 +0100218 if (dev->ctx->ops->write_device_attr)
219 return dev->ctx->ops->write_device_attr(dev, attr, src);
220 else
221 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100222}
Paul Cercueil00236242014-02-18 15:09:06 +0100223
Paul Cercueild96e61f2014-03-07 16:13:37 +0100224void iio_device_set_data(struct iio_device *dev, void *data)
225{
226 dev->userdata = data;
227}
228
229void * iio_device_get_data(const struct iio_device *dev)
230{
231 return dev->userdata;
232}
233
Paul Cercueil3156f632014-03-10 11:22:55 +0100234bool iio_device_is_trigger(const struct iio_device *dev)
235{
236 /* A trigger has a name, an id which starts by "trigger",
237 * and zero channels. */
238
239 unsigned int nb = iio_device_get_channels_count(dev);
240 const char *name = iio_device_get_name(dev),
241 *id = iio_device_get_id(dev);
242 return ((nb == 0) && !!name &&
243 !strncmp(id, "trigger", sizeof("trigger") - 1));
244}
245
Paul Cercueil24ffa532014-03-10 12:39:58 +0100246int iio_device_get_trigger(const struct iio_device *dev,
247 const struct iio_device **trigger)
248{
249 if (!trigger)
250 return -EINVAL;
251 else if (dev->ctx->ops->get_trigger)
252 return dev->ctx->ops->get_trigger(dev, trigger);
253 else
254 return -ENOSYS;
255}
256
257int iio_device_set_trigger(const struct iio_device *dev,
258 const struct iio_device *trigger)
259{
260 if (trigger && !iio_device_is_trigger(trigger))
261 return -EINVAL;
262 else if (dev->ctx->ops->set_trigger)
263 return dev->ctx->ops->set_trigger(dev, trigger);
264 else
265 return -ENOSYS;
266}
267
Paul Cercueil3156f632014-03-10 11:22:55 +0100268int iio_trigger_get_rate(const struct iio_device *trigger, unsigned long *rate)
269{
270 char buf[1024], *end;
271 ssize_t ret;
272 unsigned long value;
273
274 if (!iio_device_is_trigger(trigger))
275 return -EINVAL;
276
277 ret = iio_device_attr_read(trigger, "frequency", buf, sizeof(buf));
278 if (ret < 0)
279 return (int) ret;
280
281 value = strtoul(buf, &end, 10);
282 if (buf == end)
283 return -EBADF;
284
285 *rate = value;
286 return 0;
287}
288
289int iio_trigger_set_rate(const struct iio_device *trigger, unsigned long rate)
290{
291 char buf[1024];
292 ssize_t ret;
293
294 if (!iio_device_is_trigger(trigger))
295 return -EINVAL;
296
297 sprintf(buf, "%lu", rate);
298 ret = iio_device_attr_write(trigger, "frequency", buf);
299 if (ret < 0)
300 return (int) ret;
301 else
302 return 0;
303}
304
Paul Cercueil00236242014-02-18 15:09:06 +0100305void free_device(struct iio_device *dev)
306{
307 unsigned int i;
308 for (i = 0; i < dev->nb_attrs; i++)
309 free((char *) dev->attrs[i]);
310 if (dev->nb_attrs)
311 free(dev->attrs);
312 for (i = 0; i < dev->nb_channels; i++)
313 free_channel(dev->channels[i]);
314 if (dev->nb_channels)
315 free(dev->channels);
Paul Cercueilff778232014-03-24 14:23:08 +0100316 if (dev->mask)
317 free(dev->mask);
Paul Cercueil00236242014-02-18 15:09:06 +0100318 if (dev->name)
319 free((char *) dev->name);
320 if (dev->id)
321 free((char *) dev->id);
322 free(dev);
323}
Paul Cercueil1a474732014-03-17 11:38:34 +0100324
Paul Cercueil645ab972014-03-24 14:36:12 +0100325ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev,
Paul Cercueil1a474732014-03-17 11:38:34 +0100326 uint32_t *mask, size_t words)
327{
328 ssize_t size = 0;
329 unsigned int i;
330
331 if (words != (dev->nb_channels + 31) / 32)
332 return -EINVAL;
333
334 for (i = 0; i < dev->nb_channels; i++) {
335 const struct iio_channel *chn = dev->channels[i];
336 unsigned int length = chn->format.length / 8;
337
338 if (chn->index < 0)
339 break;
340 if (!TEST_BIT(mask, chn->index))
341 continue;
342
343 if (size % length)
344 size += 2 * length - (size % length);
345 else
346 size += length;
347 }
348 return size;
349}
Paul Cercueil46825942014-03-18 14:28:49 +0100350
Paul Cercueil645ab972014-03-24 14:36:12 +0100351ssize_t iio_device_get_sample_size(const struct iio_device *dev)
352{
353 return iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
354}
355
Paul Cercueil46825942014-03-18 14:28:49 +0100356ssize_t iio_device_process_samples(const struct iio_device *dev,
357 uint32_t *mask, size_t words, void *buf, size_t len,
358 ssize_t (*cb)(const struct iio_channel *, void *, void *),
359 void *data)
360{
361 const void *end = buf + len;
362 unsigned int i;
363 ssize_t processed = 0,
Paul Cercueil645ab972014-03-24 14:36:12 +0100364 sample_size = iio_device_get_sample_size_mask(dev, mask, words);
Paul Cercueil46825942014-03-18 14:28:49 +0100365 if (sample_size <= 0)
366 return -EINVAL;
367
368 while (end - buf >= sample_size) {
369 for (i = 0; i < dev->nb_channels; i++) {
370 const struct iio_channel *chn = dev->channels[i];
371 unsigned int length = chn->format.length / 8;
372 ssize_t ret;
373
374 if (chn->index < 0) {
375 ERROR("Channel %s has negative index\n",
376 chn->id);
377 break;
378 }
379
380 if (!TEST_BIT(mask, chn->index))
381 continue;
382
383 if ((uintptr_t) buf % length)
384 buf += length - ((uintptr_t) buf % length);
385
386 ret = cb(chn, buf, data);
387 if (ret < 0)
388 return ret;
389 else
390 processed += ret;
391 buf += length;
392 }
393 }
394 return processed;
395}