blob: 6e0322967837b5b2f2c496b2b34468c848c75aa8 [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 */
Paul Cercueil8c29e412014-04-07 09:46:45 +020036 snprintf(str, len, "<attribute name=\"%s\" />", attr);
Paul Cercueil42090d12014-02-24 12:32:23 +010037 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{
Paul Cercueil8c29e412014-04-07 09:46:45 +020043 size_t len = sizeof("<device id=\"\" name=\"\" ></device>")
44 + strlen(dev->id) + (dev->name ? strlen(dev->name) : 0);
Paul Cercueil5822ab62014-04-04 13:29:17 +020045 char *ptr, *str, **attrs, **channels;
46 size_t *attrs_len, *channels_len;
Paul Cercueil8c29e412014-04-07 09:46:45 +020047 unsigned int i, j;
Paul Cercueil5822ab62014-04-04 13:29:17 +020048
49 attrs_len = malloc(dev->nb_attrs * sizeof(*attrs_len));
50 if (!attrs_len)
51 return NULL;
52
53 attrs = malloc(dev->nb_attrs * sizeof(*attrs));
54 if (!attrs)
55 goto err_free_attrs_len;
56
Paul Cercueil42090d12014-02-24 12:32:23 +010057 for (i = 0; i < dev->nb_attrs; i++) {
58 char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i]);
59 if (!xml)
60 goto err_free_attrs;
61 attrs[i] = xml;
62 len += attrs_len[i];
63 }
64
Paul Cercueil8c29e412014-04-07 09:46:45 +020065 channels_len = malloc(dev->nb_channels * sizeof(*channels_len));
66 if (!channels_len)
67 goto err_free_attrs;
68
69 channels = malloc(dev->nb_channels * sizeof(*channels));
70 if (!channels)
71 goto err_free_channels_len;
72
Paul Cercueil42090d12014-02-24 12:32:23 +010073 for (j = 0; j < dev->nb_channels; j++) {
74 char *xml = iio_channel_get_xml(dev->channels[j],
75 &channels_len[j]);
76 if (!xml)
77 goto err_free_channels;
78 channels[j] = xml;
79 len += channels_len[j];
80 }
81
Paul Cercueil42090d12014-02-24 12:32:23 +010082 str = malloc(len);
83 if (!str)
84 goto err_free_channels;
85
Paul Cercueil8c29e412014-04-07 09:46:45 +020086 snprintf(str, len, "<device id=\"%s\"", dev->id);
Paul Cercueil42090d12014-02-24 12:32:23 +010087 ptr = strrchr(str, '\0');
88
89 if (dev->name) {
90 sprintf(ptr, " name=\"%s\"", dev->name);
91 ptr = strrchr(ptr, '\0');
92 }
93
94 strcpy(ptr, " >");
95 ptr += 2;
96
97 for (i = 0; i < dev->nb_channels; i++) {
98 strcpy(ptr, channels[i]);
99 ptr += channels_len[i];
100 free(channels[i]);
101 }
102
Paul Cercueil5822ab62014-04-04 13:29:17 +0200103 free(channels);
104 free(channels_len);
105
Paul Cercueil42090d12014-02-24 12:32:23 +0100106 for (i = 0; i < dev->nb_attrs; i++) {
107 strcpy(ptr, attrs[i]);
108 ptr += attrs_len[i];
109 free(attrs[i]);
110 }
111
Paul Cercueil5822ab62014-04-04 13:29:17 +0200112 free(attrs);
113 free(attrs_len);
114
Paul Cercueil42090d12014-02-24 12:32:23 +0100115 strcpy(ptr, "</device>");
116 *length = ptr - str + sizeof("</device>") - 1;
117 return str;
118
119err_free_channels:
120 while (j--)
121 free(channels[j]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200122 free(channels);
123err_free_channels_len:
124 free(channels_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100125err_free_attrs:
126 while (i--)
127 free(attrs[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200128 free(attrs);
129err_free_attrs_len:
130 free(attrs_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100131 return NULL;
132}
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100133
134const char * iio_device_get_id(const struct iio_device *dev)
135{
136 return dev->id;
137}
138
139const char * iio_device_get_name(const struct iio_device *dev)
140{
141 return dev->name;
142}
143
144unsigned int iio_device_get_channels_count(const struct iio_device *dev)
145{
146 return dev->nb_channels;
147}
148
149struct iio_channel * iio_device_get_channel(const struct iio_device *dev,
150 unsigned int index)
151{
152 if (index >= dev->nb_channels)
153 return NULL;
154 else
155 return dev->channels[index];
156}
157
Paul Cercueil17512b02014-03-28 11:15:24 +0100158struct iio_channel * iio_device_find_channel(const struct iio_device *dev,
Paul Cercueil830a7f32014-03-28 13:09:31 +0100159 const char *name, bool output)
Paul Cercueil17512b02014-03-28 11:15:24 +0100160{
161 unsigned int i;
162 for (i = 0; i < dev->nb_channels; i++) {
163 struct iio_channel *chn = dev->channels[i];
Paul Cercueil830a7f32014-03-28 13:09:31 +0100164 if (iio_channel_is_output(chn) != output)
165 continue;
166
Paul Cercueil17512b02014-03-28 11:15:24 +0100167 if (!strcmp(chn->id, name) ||
168 (chn->name && !strcmp(chn->name, name)))
169 return chn;
170 }
171 return NULL;
172}
173
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100174unsigned int iio_device_get_attrs_count(const struct iio_device *dev)
175{
176 return dev->nb_attrs;
177}
178
179const char * iio_device_get_attr(const struct iio_device *dev,
180 unsigned int index)
181{
182 if (index >= dev->nb_attrs)
183 return NULL;
184 else
185 return dev->attrs[index];
186}
187
Paul Cercueil4f838d02014-03-28 11:26:15 +0100188const char * iio_device_find_attr(const struct iio_device *dev,
189 const char *name)
190{
191 unsigned int i;
192 for (i = 0; i < dev->nb_attrs; i++) {
193 const char *attr = dev->attrs[i];
194 if (!strcmp(attr, name))
195 return attr;
196 }
197 return NULL;
198}
199
Paul Cercueil3cc3a002014-03-24 13:44:11 +0100200static int iio_device_open_mask(const struct iio_device *dev,
Paul Cercueil93f17052014-04-02 13:56:27 +0200201 size_t samples_count, uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100202{
Paul Cercueilaaa8ee02014-03-28 16:43:02 +0100203 unsigned int i;
204 bool has_channels = false;
205
206 for (i = 0; !has_channels && i < words; i++)
207 has_channels = !!mask[i];
208 if (!has_channels)
209 return -EINVAL;
210
Paul Cercueilec1760d2014-02-21 11:31:20 +0100211 if (dev->ctx->ops->open)
Paul Cercueil93f17052014-04-02 13:56:27 +0200212 return dev->ctx->ops->open(dev, samples_count, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100213 else
214 return -ENOSYS;
215}
216
Paul Cercueil93f17052014-04-02 13:56:27 +0200217int iio_device_open(const struct iio_device *dev, size_t samples_count)
Paul Cercueile1311222014-03-12 15:46:16 +0100218{
219 size_t nb = (dev->nb_channels + 31) / 32;
220 uint32_t *mask = NULL;
221 unsigned int i;
222 int ret;
223
Paul Cercueilaaa8ee02014-03-28 16:43:02 +0100224 if (nb == 0)
225 return -EINVAL;
226
227 mask = calloc(nb, sizeof(*mask));
228 if (!mask)
229 return -ENOMEM;
Paul Cercueile1311222014-03-12 15:46:16 +0100230
231 for (i = 0; i < dev->nb_channels; i++) {
232 struct iio_channel *chn = dev->channels[i];
233 if (iio_channel_is_enabled(chn) && chn->index >= 0)
234 SET_BIT(mask, chn->index);
235 }
236
Paul Cercueil93f17052014-04-02 13:56:27 +0200237 ret = iio_device_open_mask(dev, samples_count, mask, nb);
Paul Cercueile1311222014-03-12 15:46:16 +0100238 free(mask);
239 return ret;
240}
241
Paul Cercueilec1760d2014-02-21 11:31:20 +0100242int iio_device_close(const struct iio_device *dev)
243{
244 if (dev->ctx->ops->close)
245 return dev->ctx->ops->close(dev);
246 else
247 return -ENOSYS;
248}
249
250ssize_t iio_device_read_raw(const struct iio_device *dev,
Paul Cercueil45c575d2014-03-20 15:14:01 +0100251 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueilec1760d2014-02-21 11:31:20 +0100252{
253 if (dev->ctx->ops->read)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100254 return dev->ctx->ops->read(dev, dst, len, mask, words);
Paul Cercueilec1760d2014-02-21 11:31:20 +0100255 else
256 return -ENOSYS;
257}
258
259ssize_t iio_device_write_raw(const struct iio_device *dev,
260 const void *src, size_t len)
261{
262 if (dev->ctx->ops->write)
263 return dev->ctx->ops->write(dev, src, len);
264 else
265 return -ENOSYS;
266}
267
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100268ssize_t iio_device_attr_read(const struct iio_device *dev,
269 const char *attr, char *dst, size_t len)
270{
Paul Cercueil6a013602014-02-19 12:37:39 +0100271 if (dev->ctx->ops->read_device_attr)
272 return dev->ctx->ops->read_device_attr(dev, attr, dst, len);
273 else
274 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100275}
276
277ssize_t iio_device_attr_write(const struct iio_device *dev,
278 const char *attr, const char *src)
279{
Paul Cercueil6a013602014-02-19 12:37:39 +0100280 if (dev->ctx->ops->write_device_attr)
281 return dev->ctx->ops->write_device_attr(dev, attr, src);
282 else
283 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100284}
Paul Cercueil00236242014-02-18 15:09:06 +0100285
Paul Cercueild96e61f2014-03-07 16:13:37 +0100286void iio_device_set_data(struct iio_device *dev, void *data)
287{
288 dev->userdata = data;
289}
290
291void * iio_device_get_data(const struct iio_device *dev)
292{
293 return dev->userdata;
294}
295
Paul Cercueil3156f632014-03-10 11:22:55 +0100296bool iio_device_is_trigger(const struct iio_device *dev)
297{
298 /* A trigger has a name, an id which starts by "trigger",
299 * and zero channels. */
300
301 unsigned int nb = iio_device_get_channels_count(dev);
302 const char *name = iio_device_get_name(dev),
303 *id = iio_device_get_id(dev);
304 return ((nb == 0) && !!name &&
305 !strncmp(id, "trigger", sizeof("trigger") - 1));
306}
307
Paul Cercueil24ffa532014-03-10 12:39:58 +0100308int iio_device_get_trigger(const struct iio_device *dev,
309 const struct iio_device **trigger)
310{
311 if (!trigger)
312 return -EINVAL;
313 else if (dev->ctx->ops->get_trigger)
314 return dev->ctx->ops->get_trigger(dev, trigger);
315 else
316 return -ENOSYS;
317}
318
319int iio_device_set_trigger(const struct iio_device *dev,
320 const struct iio_device *trigger)
321{
322 if (trigger && !iio_device_is_trigger(trigger))
323 return -EINVAL;
324 else if (dev->ctx->ops->set_trigger)
325 return dev->ctx->ops->set_trigger(dev, trigger);
326 else
327 return -ENOSYS;
328}
329
Paul Cercueil3156f632014-03-10 11:22:55 +0100330int iio_trigger_get_rate(const struct iio_device *trigger, unsigned long *rate)
331{
332 char buf[1024], *end;
333 ssize_t ret;
334 unsigned long value;
335
336 if (!iio_device_is_trigger(trigger))
337 return -EINVAL;
338
339 ret = iio_device_attr_read(trigger, "frequency", buf, sizeof(buf));
340 if (ret < 0)
341 return (int) ret;
342
343 value = strtoul(buf, &end, 10);
344 if (buf == end)
345 return -EBADF;
346
347 *rate = value;
348 return 0;
349}
350
351int iio_trigger_set_rate(const struct iio_device *trigger, unsigned long rate)
352{
353 char buf[1024];
354 ssize_t ret;
355
356 if (!iio_device_is_trigger(trigger))
357 return -EINVAL;
358
Paul Cercueil8c29e412014-04-07 09:46:45 +0200359 snprintf(buf, sizeof(buf), "%lu", rate);
Paul Cercueil3156f632014-03-10 11:22:55 +0100360 ret = iio_device_attr_write(trigger, "frequency", buf);
361 if (ret < 0)
362 return (int) ret;
363 else
364 return 0;
365}
366
Paul Cercueil00236242014-02-18 15:09:06 +0100367void free_device(struct iio_device *dev)
368{
369 unsigned int i;
370 for (i = 0; i < dev->nb_attrs; i++)
371 free((char *) dev->attrs[i]);
372 if (dev->nb_attrs)
373 free(dev->attrs);
374 for (i = 0; i < dev->nb_channels; i++)
375 free_channel(dev->channels[i]);
376 if (dev->nb_channels)
377 free(dev->channels);
Paul Cercueilff778232014-03-24 14:23:08 +0100378 if (dev->mask)
379 free(dev->mask);
Paul Cercueil00236242014-02-18 15:09:06 +0100380 if (dev->name)
381 free((char *) dev->name);
382 if (dev->id)
383 free((char *) dev->id);
384 free(dev);
385}
Paul Cercueil1a474732014-03-17 11:38:34 +0100386
Paul Cercueil645ab972014-03-24 14:36:12 +0100387ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev,
Paul Cercueil1a474732014-03-17 11:38:34 +0100388 uint32_t *mask, size_t words)
389{
390 ssize_t size = 0;
391 unsigned int i;
392
393 if (words != (dev->nb_channels + 31) / 32)
394 return -EINVAL;
395
396 for (i = 0; i < dev->nb_channels; i++) {
397 const struct iio_channel *chn = dev->channels[i];
398 unsigned int length = chn->format.length / 8;
399
400 if (chn->index < 0)
401 break;
402 if (!TEST_BIT(mask, chn->index))
403 continue;
404
405 if (size % length)
406 size += 2 * length - (size % length);
407 else
408 size += length;
409 }
410 return size;
411}
Paul Cercueil46825942014-03-18 14:28:49 +0100412
Paul Cercueil645ab972014-03-24 14:36:12 +0100413ssize_t iio_device_get_sample_size(const struct iio_device *dev)
414{
415 return iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
416}
417
Paul Cercueil46825942014-03-18 14:28:49 +0100418ssize_t iio_device_process_samples(const struct iio_device *dev,
419 uint32_t *mask, size_t words, void *buf, size_t len,
420 ssize_t (*cb)(const struct iio_channel *, void *, void *),
421 void *data)
422{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200423 uintptr_t ptr = (uintptr_t) buf, end = ptr + len;
Paul Cercueil46825942014-03-18 14:28:49 +0100424 unsigned int i;
425 ssize_t processed = 0,
Paul Cercueil645ab972014-03-24 14:36:12 +0100426 sample_size = iio_device_get_sample_size_mask(dev, mask, words);
Paul Cercueil46825942014-03-18 14:28:49 +0100427 if (sample_size <= 0)
428 return -EINVAL;
429
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200430 while (end - ptr >= (size_t) sample_size) {
Paul Cercueil46825942014-03-18 14:28:49 +0100431 for (i = 0; i < dev->nb_channels; i++) {
432 const struct iio_channel *chn = dev->channels[i];
433 unsigned int length = chn->format.length / 8;
434 ssize_t ret;
435
436 if (chn->index < 0) {
437 ERROR("Channel %s has negative index\n",
438 chn->id);
439 break;
440 }
441
442 if (!TEST_BIT(mask, chn->index))
443 continue;
444
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200445 if (ptr % length)
446 ptr += length - (ptr % length);
Paul Cercueil46825942014-03-18 14:28:49 +0100447
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200448 ret = cb(chn, (void *) ptr, data);
Paul Cercueil46825942014-03-18 14:28:49 +0100449 if (ret < 0)
450 return ret;
451 else
452 processed += ret;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200453 ptr += length;
Paul Cercueil46825942014-03-18 14:28:49 +0100454 }
455 }
456 return processed;
457}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200458
459int iio_device_attr_read_longlong(const struct iio_device *dev,
460 const char *attr, long long *val)
461{
462 char *end, buf[1024];
463 long long value;
464 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
465 if (ret < 0)
466 return (int) ret;
467
468 value = strtoll(buf, &end, 0);
469 if (end == buf)
470 return -EINVAL;
471 *val = value;
472 return 0;
473}
474
475int iio_device_attr_read_bool(const struct iio_device *dev,
476 const char *attr, bool *val)
477{
478 long long value;
479 int ret = iio_device_attr_read_longlong(dev, attr, &value);
480 if (ret < 0)
481 return ret;
482
483 *val = !!value;
484 return 0;
485}
486
487int iio_device_attr_read_double(const struct iio_device *dev,
488 const char *attr, double *val)
489{
490 char *end, buf[1024];
491 double value;
492 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
493 if (ret < 0)
494 return (int) ret;
495
496 value = strtod(buf, &end);
497 if (end == buf)
498 return -EINVAL;
499 *val = value;
500 return 0;
501}
502
503int iio_device_attr_write_longlong(const struct iio_device *dev,
504 const char *attr, long long val)
505{
506 char buf[1024];
507 snprintf(buf, sizeof(buf), "%lld", val);
508 return iio_device_attr_write(dev, attr, buf);
509}
510
511int iio_device_attr_write_double(const struct iio_device *dev,
512 const char *attr, double val)
513{
514 char buf[1024];
515 snprintf(buf, sizeof(buf), "%lf", val);
516 return iio_device_attr_write(dev, attr, buf);
517}
518
519int iio_device_attr_write_bool(const struct iio_device *dev,
520 const char *attr, bool val)
521{
522 if (val)
523 return iio_device_attr_write(dev, attr, "1");
524 else
525 return iio_device_attr_write(dev, attr, "0");
526}