blob: cebe58955b792f74dc265b51b9768c1f7f5d2b10 [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>");
Paul Cercueil5822ab62014-04-04 13:29:17 +020044 char *ptr, *str, **attrs, **channels;
45 size_t *attrs_len, *channels_len;
46 unsigned int i = 0, j;
47
48 attrs_len = malloc(dev->nb_attrs * sizeof(*attrs_len));
49 if (!attrs_len)
50 return NULL;
51
52 attrs = malloc(dev->nb_attrs * sizeof(*attrs));
53 if (!attrs)
54 goto err_free_attrs_len;
55
56 channels_len = malloc(dev->nb_channels * sizeof(*channels_len));
57 if (!channels_len)
58 goto err_free_attrs;
59
60 channels = malloc(dev->nb_channels * sizeof(*channels));
61 if (!channels)
62 goto err_free_channels_len;
Paul Cercueil42090d12014-02-24 12:32:23 +010063
64 for (i = 0; i < dev->nb_attrs; i++) {
65 char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i]);
66 if (!xml)
67 goto err_free_attrs;
68 attrs[i] = xml;
69 len += attrs_len[i];
70 }
71
72 for (j = 0; j < dev->nb_channels; j++) {
73 char *xml = iio_channel_get_xml(dev->channels[j],
74 &channels_len[j]);
75 if (!xml)
76 goto err_free_channels;
77 channels[j] = xml;
78 len += channels_len[j];
79 }
80
81 len += strlen(dev->id);
82 if (dev->name)
83 len += strlen(dev->name);
84
85 str = malloc(len);
86 if (!str)
87 goto err_free_channels;
88
89 sprintf(str, "<device id=\"%s\"", dev->id);
90 ptr = strrchr(str, '\0');
91
92 if (dev->name) {
93 sprintf(ptr, " name=\"%s\"", dev->name);
94 ptr = strrchr(ptr, '\0');
95 }
96
97 strcpy(ptr, " >");
98 ptr += 2;
99
100 for (i = 0; i < dev->nb_channels; i++) {
101 strcpy(ptr, channels[i]);
102 ptr += channels_len[i];
103 free(channels[i]);
104 }
105
Paul Cercueil5822ab62014-04-04 13:29:17 +0200106 free(channels);
107 free(channels_len);
108
Paul Cercueil42090d12014-02-24 12:32:23 +0100109 for (i = 0; i < dev->nb_attrs; i++) {
110 strcpy(ptr, attrs[i]);
111 ptr += attrs_len[i];
112 free(attrs[i]);
113 }
114
Paul Cercueil5822ab62014-04-04 13:29:17 +0200115 free(attrs);
116 free(attrs_len);
117
Paul Cercueil42090d12014-02-24 12:32:23 +0100118 strcpy(ptr, "</device>");
119 *length = ptr - str + sizeof("</device>") - 1;
120 return str;
121
122err_free_channels:
123 while (j--)
124 free(channels[j]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200125 free(channels);
126err_free_channels_len:
127 free(channels_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100128err_free_attrs:
129 while (i--)
130 free(attrs[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200131 free(attrs);
132err_free_attrs_len:
133 free(attrs_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100134 return NULL;
135}
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100136
137const char * iio_device_get_id(const struct iio_device *dev)
138{
139 return dev->id;
140}
141
142const char * iio_device_get_name(const struct iio_device *dev)
143{
144 return dev->name;
145}
146
147unsigned int iio_device_get_channels_count(const struct iio_device *dev)
148{
149 return dev->nb_channels;
150}
151
152struct iio_channel * iio_device_get_channel(const struct iio_device *dev,
153 unsigned int index)
154{
155 if (index >= dev->nb_channels)
156 return NULL;
157 else
158 return dev->channels[index];
159}
160
Paul Cercueil17512b02014-03-28 11:15:24 +0100161struct iio_channel * iio_device_find_channel(const struct iio_device *dev,
Paul Cercueil830a7f32014-03-28 13:09:31 +0100162 const char *name, bool output)
Paul Cercueil17512b02014-03-28 11:15:24 +0100163{
164 unsigned int i;
165 for (i = 0; i < dev->nb_channels; i++) {
166 struct iio_channel *chn = dev->channels[i];
Paul Cercueil830a7f32014-03-28 13:09:31 +0100167 if (iio_channel_is_output(chn) != output)
168 continue;
169
Paul Cercueil17512b02014-03-28 11:15:24 +0100170 if (!strcmp(chn->id, name) ||
171 (chn->name && !strcmp(chn->name, name)))
172 return chn;
173 }
174 return NULL;
175}
176
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100177unsigned int iio_device_get_attrs_count(const struct iio_device *dev)
178{
179 return dev->nb_attrs;
180}
181
182const char * iio_device_get_attr(const struct iio_device *dev,
183 unsigned int index)
184{
185 if (index >= dev->nb_attrs)
186 return NULL;
187 else
188 return dev->attrs[index];
189}
190
Paul Cercueil4f838d02014-03-28 11:26:15 +0100191const char * iio_device_find_attr(const struct iio_device *dev,
192 const char *name)
193{
194 unsigned int i;
195 for (i = 0; i < dev->nb_attrs; i++) {
196 const char *attr = dev->attrs[i];
197 if (!strcmp(attr, name))
198 return attr;
199 }
200 return NULL;
201}
202
Paul Cercueil3cc3a002014-03-24 13:44:11 +0100203static int iio_device_open_mask(const struct iio_device *dev,
Paul Cercueil93f17052014-04-02 13:56:27 +0200204 size_t samples_count, uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100205{
Paul Cercueilaaa8ee02014-03-28 16:43:02 +0100206 unsigned int i;
207 bool has_channels = false;
208
209 for (i = 0; !has_channels && i < words; i++)
210 has_channels = !!mask[i];
211 if (!has_channels)
212 return -EINVAL;
213
Paul Cercueilec1760d2014-02-21 11:31:20 +0100214 if (dev->ctx->ops->open)
Paul Cercueil93f17052014-04-02 13:56:27 +0200215 return dev->ctx->ops->open(dev, samples_count, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100216 else
217 return -ENOSYS;
218}
219
Paul Cercueil93f17052014-04-02 13:56:27 +0200220int iio_device_open(const struct iio_device *dev, size_t samples_count)
Paul Cercueile1311222014-03-12 15:46:16 +0100221{
222 size_t nb = (dev->nb_channels + 31) / 32;
223 uint32_t *mask = NULL;
224 unsigned int i;
225 int ret;
226
Paul Cercueilaaa8ee02014-03-28 16:43:02 +0100227 if (nb == 0)
228 return -EINVAL;
229
230 mask = calloc(nb, sizeof(*mask));
231 if (!mask)
232 return -ENOMEM;
Paul Cercueile1311222014-03-12 15:46:16 +0100233
234 for (i = 0; i < dev->nb_channels; i++) {
235 struct iio_channel *chn = dev->channels[i];
236 if (iio_channel_is_enabled(chn) && chn->index >= 0)
237 SET_BIT(mask, chn->index);
238 }
239
Paul Cercueil93f17052014-04-02 13:56:27 +0200240 ret = iio_device_open_mask(dev, samples_count, mask, nb);
Paul Cercueile1311222014-03-12 15:46:16 +0100241 free(mask);
242 return ret;
243}
244
Paul Cercueilec1760d2014-02-21 11:31:20 +0100245int iio_device_close(const struct iio_device *dev)
246{
247 if (dev->ctx->ops->close)
248 return dev->ctx->ops->close(dev);
249 else
250 return -ENOSYS;
251}
252
253ssize_t iio_device_read_raw(const struct iio_device *dev,
Paul Cercueil45c575d2014-03-20 15:14:01 +0100254 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100255{
256 if (dev->ctx->ops->read)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100257 return dev->ctx->ops->read(dev, dst, len, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100258 else
259 return -ENOSYS;
260}
261
262ssize_t iio_device_write_raw(const struct iio_device *dev,
263 const void *src, size_t len)
264{
265 if (dev->ctx->ops->write)
266 return dev->ctx->ops->write(dev, src, len);
267 else
268 return -ENOSYS;
269}
270
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100271ssize_t iio_device_attr_read(const struct iio_device *dev,
272 const char *attr, char *dst, size_t len)
273{
Paul Cercueil6a013602014-02-19 12:37:39 +0100274 if (dev->ctx->ops->read_device_attr)
275 return dev->ctx->ops->read_device_attr(dev, attr, dst, len);
276 else
277 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100278}
279
280ssize_t iio_device_attr_write(const struct iio_device *dev,
281 const char *attr, const char *src)
282{
Paul Cercueil6a013602014-02-19 12:37:39 +0100283 if (dev->ctx->ops->write_device_attr)
284 return dev->ctx->ops->write_device_attr(dev, attr, src);
285 else
286 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100287}
Paul Cercueil00236242014-02-18 15:09:06 +0100288
Paul Cercueild96e61f2014-03-07 16:13:37 +0100289void iio_device_set_data(struct iio_device *dev, void *data)
290{
291 dev->userdata = data;
292}
293
294void * iio_device_get_data(const struct iio_device *dev)
295{
296 return dev->userdata;
297}
298
Paul Cercueil3156f632014-03-10 11:22:55 +0100299bool iio_device_is_trigger(const struct iio_device *dev)
300{
301 /* A trigger has a name, an id which starts by "trigger",
302 * and zero channels. */
303
304 unsigned int nb = iio_device_get_channels_count(dev);
305 const char *name = iio_device_get_name(dev),
306 *id = iio_device_get_id(dev);
307 return ((nb == 0) && !!name &&
308 !strncmp(id, "trigger", sizeof("trigger") - 1));
309}
310
Paul Cercueil24ffa532014-03-10 12:39:58 +0100311int iio_device_get_trigger(const struct iio_device *dev,
312 const struct iio_device **trigger)
313{
314 if (!trigger)
315 return -EINVAL;
316 else if (dev->ctx->ops->get_trigger)
317 return dev->ctx->ops->get_trigger(dev, trigger);
318 else
319 return -ENOSYS;
320}
321
322int iio_device_set_trigger(const struct iio_device *dev,
323 const struct iio_device *trigger)
324{
325 if (trigger && !iio_device_is_trigger(trigger))
326 return -EINVAL;
327 else if (dev->ctx->ops->set_trigger)
328 return dev->ctx->ops->set_trigger(dev, trigger);
329 else
330 return -ENOSYS;
331}
332
Paul Cercueil3156f632014-03-10 11:22:55 +0100333int iio_trigger_get_rate(const struct iio_device *trigger, unsigned long *rate)
334{
335 char buf[1024], *end;
336 ssize_t ret;
337 unsigned long value;
338
339 if (!iio_device_is_trigger(trigger))
340 return -EINVAL;
341
342 ret = iio_device_attr_read(trigger, "frequency", buf, sizeof(buf));
343 if (ret < 0)
344 return (int) ret;
345
346 value = strtoul(buf, &end, 10);
347 if (buf == end)
348 return -EBADF;
349
350 *rate = value;
351 return 0;
352}
353
354int iio_trigger_set_rate(const struct iio_device *trigger, unsigned long rate)
355{
356 char buf[1024];
357 ssize_t ret;
358
359 if (!iio_device_is_trigger(trigger))
360 return -EINVAL;
361
362 sprintf(buf, "%lu", rate);
363 ret = iio_device_attr_write(trigger, "frequency", buf);
364 if (ret < 0)
365 return (int) ret;
366 else
367 return 0;
368}
369
Paul Cercueil00236242014-02-18 15:09:06 +0100370void free_device(struct iio_device *dev)
371{
372 unsigned int i;
373 for (i = 0; i < dev->nb_attrs; i++)
374 free((char *) dev->attrs[i]);
375 if (dev->nb_attrs)
376 free(dev->attrs);
377 for (i = 0; i < dev->nb_channels; i++)
378 free_channel(dev->channels[i]);
379 if (dev->nb_channels)
380 free(dev->channels);
Paul Cercueilff778232014-03-24 14:23:08 +0100381 if (dev->mask)
382 free(dev->mask);
Paul Cercueil00236242014-02-18 15:09:06 +0100383 if (dev->name)
384 free((char *) dev->name);
385 if (dev->id)
386 free((char *) dev->id);
387 free(dev);
388}
Paul Cercueil1a474732014-03-17 11:38:34 +0100389
Paul Cercueil645ab972014-03-24 14:36:12 +0100390ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev,
Paul Cercueil1a474732014-03-17 11:38:34 +0100391 uint32_t *mask, size_t words)
392{
393 ssize_t size = 0;
394 unsigned int i;
395
396 if (words != (dev->nb_channels + 31) / 32)
397 return -EINVAL;
398
399 for (i = 0; i < dev->nb_channels; i++) {
400 const struct iio_channel *chn = dev->channels[i];
401 unsigned int length = chn->format.length / 8;
402
403 if (chn->index < 0)
404 break;
405 if (!TEST_BIT(mask, chn->index))
406 continue;
407
408 if (size % length)
409 size += 2 * length - (size % length);
410 else
411 size += length;
412 }
413 return size;
414}
Paul Cercueil46825942014-03-18 14:28:49 +0100415
Paul Cercueil645ab972014-03-24 14:36:12 +0100416ssize_t iio_device_get_sample_size(const struct iio_device *dev)
417{
418 return iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
419}
420
Paul Cercueil46825942014-03-18 14:28:49 +0100421ssize_t iio_device_process_samples(const struct iio_device *dev,
422 uint32_t *mask, size_t words, void *buf, size_t len,
423 ssize_t (*cb)(const struct iio_channel *, void *, void *),
424 void *data)
425{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200426 uintptr_t ptr = (uintptr_t) buf, end = ptr + len;
Paul Cercueil46825942014-03-18 14:28:49 +0100427 unsigned int i;
428 ssize_t processed = 0,
Paul Cercueil645ab972014-03-24 14:36:12 +0100429 sample_size = iio_device_get_sample_size_mask(dev, mask, words);
Paul Cercueil46825942014-03-18 14:28:49 +0100430 if (sample_size <= 0)
431 return -EINVAL;
432
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200433 while (end - ptr >= (size_t) sample_size) {
Paul Cercueil46825942014-03-18 14:28:49 +0100434 for (i = 0; i < dev->nb_channels; i++) {
435 const struct iio_channel *chn = dev->channels[i];
436 unsigned int length = chn->format.length / 8;
437 ssize_t ret;
438
439 if (chn->index < 0) {
440 ERROR("Channel %s has negative index\n",
441 chn->id);
442 break;
443 }
444
445 if (!TEST_BIT(mask, chn->index))
446 continue;
447
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200448 if (ptr % length)
449 ptr += length - (ptr % length);
Paul Cercueil46825942014-03-18 14:28:49 +0100450
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200451 ret = cb(chn, (void *) ptr, data);
Paul Cercueil46825942014-03-18 14:28:49 +0100452 if (ret < 0)
453 return ret;
454 else
455 processed += ret;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200456 ptr += length;
Paul Cercueil46825942014-03-18 14:28:49 +0100457 }
458 }
459 return processed;
460}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200461
462int iio_device_attr_read_longlong(const struct iio_device *dev,
463 const char *attr, long long *val)
464{
465 char *end, buf[1024];
466 long long value;
467 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
468 if (ret < 0)
469 return (int) ret;
470
471 value = strtoll(buf, &end, 0);
472 if (end == buf)
473 return -EINVAL;
474 *val = value;
475 return 0;
476}
477
478int iio_device_attr_read_bool(const struct iio_device *dev,
479 const char *attr, bool *val)
480{
481 long long value;
482 int ret = iio_device_attr_read_longlong(dev, attr, &value);
483 if (ret < 0)
484 return ret;
485
486 *val = !!value;
487 return 0;
488}
489
490int iio_device_attr_read_double(const struct iio_device *dev,
491 const char *attr, double *val)
492{
493 char *end, buf[1024];
494 double value;
495 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
496 if (ret < 0)
497 return (int) ret;
498
499 value = strtod(buf, &end);
500 if (end == buf)
501 return -EINVAL;
502 *val = value;
503 return 0;
504}
505
506int iio_device_attr_write_longlong(const struct iio_device *dev,
507 const char *attr, long long val)
508{
509 char buf[1024];
510 snprintf(buf, sizeof(buf), "%lld", val);
511 return iio_device_attr_write(dev, attr, buf);
512}
513
514int iio_device_attr_write_double(const struct iio_device *dev,
515 const char *attr, double val)
516{
517 char buf[1024];
518 snprintf(buf, sizeof(buf), "%lf", val);
519 return iio_device_attr_write(dev, attr, buf);
520}
521
522int iio_device_attr_write_bool(const struct iio_device *dev,
523 const char *attr, bool val)
524{
525 if (val)
526 return iio_device_attr_write(dev, attr, "1");
527 else
528 return iio_device_attr_write(dev, attr, "0");
529}