blob: d1373a46fecb96c9ab9d48fff8a376f5e77cf6de [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)
Paul Cercueil50c762a2014-04-14 15:55:43 +0200272 return dev->ctx->ops->read_device_attr(dev,
273 attr, dst, len, false);
Paul Cercueil6a013602014-02-19 12:37:39 +0100274 else
275 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100276}
277
278ssize_t iio_device_attr_write(const struct iio_device *dev,
279 const char *attr, const char *src)
280{
Paul Cercueil6a013602014-02-19 12:37:39 +0100281 if (dev->ctx->ops->write_device_attr)
Paul Cercueil50c762a2014-04-14 15:55:43 +0200282 return dev->ctx->ops->write_device_attr(dev,
283 attr, src, false);
Paul Cercueil6a013602014-02-19 12:37:39 +0100284 else
285 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100286}
Paul Cercueil00236242014-02-18 15:09:06 +0100287
Paul Cercueild96e61f2014-03-07 16:13:37 +0100288void iio_device_set_data(struct iio_device *dev, void *data)
289{
290 dev->userdata = data;
291}
292
293void * iio_device_get_data(const struct iio_device *dev)
294{
295 return dev->userdata;
296}
297
Paul Cercueil3156f632014-03-10 11:22:55 +0100298bool iio_device_is_trigger(const struct iio_device *dev)
299{
300 /* A trigger has a name, an id which starts by "trigger",
301 * and zero channels. */
302
303 unsigned int nb = iio_device_get_channels_count(dev);
304 const char *name = iio_device_get_name(dev),
305 *id = iio_device_get_id(dev);
306 return ((nb == 0) && !!name &&
307 !strncmp(id, "trigger", sizeof("trigger") - 1));
308}
309
Paul Cercueil24ffa532014-03-10 12:39:58 +0100310int iio_device_get_trigger(const struct iio_device *dev,
311 const struct iio_device **trigger)
312{
313 if (!trigger)
314 return -EINVAL;
315 else if (dev->ctx->ops->get_trigger)
316 return dev->ctx->ops->get_trigger(dev, trigger);
317 else
318 return -ENOSYS;
319}
320
321int iio_device_set_trigger(const struct iio_device *dev,
322 const struct iio_device *trigger)
323{
324 if (trigger && !iio_device_is_trigger(trigger))
325 return -EINVAL;
326 else if (dev->ctx->ops->set_trigger)
327 return dev->ctx->ops->set_trigger(dev, trigger);
328 else
329 return -ENOSYS;
330}
331
Paul Cercueil00236242014-02-18 15:09:06 +0100332void free_device(struct iio_device *dev)
333{
334 unsigned int i;
335 for (i = 0; i < dev->nb_attrs; i++)
336 free((char *) dev->attrs[i]);
337 if (dev->nb_attrs)
338 free(dev->attrs);
339 for (i = 0; i < dev->nb_channels; i++)
340 free_channel(dev->channels[i]);
341 if (dev->nb_channels)
342 free(dev->channels);
Paul Cercueilff778232014-03-24 14:23:08 +0100343 if (dev->mask)
344 free(dev->mask);
Paul Cercueil00236242014-02-18 15:09:06 +0100345 if (dev->name)
346 free((char *) dev->name);
347 if (dev->id)
348 free((char *) dev->id);
349 free(dev);
350}
Paul Cercueil1a474732014-03-17 11:38:34 +0100351
Paul Cercueil645ab972014-03-24 14:36:12 +0100352ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev,
Paul Cercueil1a474732014-03-17 11:38:34 +0100353 uint32_t *mask, size_t words)
354{
355 ssize_t size = 0;
356 unsigned int i;
357
358 if (words != (dev->nb_channels + 31) / 32)
359 return -EINVAL;
360
361 for (i = 0; i < dev->nb_channels; i++) {
362 const struct iio_channel *chn = dev->channels[i];
363 unsigned int length = chn->format.length / 8;
364
365 if (chn->index < 0)
366 break;
367 if (!TEST_BIT(mask, chn->index))
368 continue;
369
370 if (size % length)
371 size += 2 * length - (size % length);
372 else
373 size += length;
374 }
375 return size;
376}
Paul Cercueil46825942014-03-18 14:28:49 +0100377
Paul Cercueil645ab972014-03-24 14:36:12 +0100378ssize_t iio_device_get_sample_size(const struct iio_device *dev)
379{
380 return iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
381}
382
Paul Cercueil46825942014-03-18 14:28:49 +0100383ssize_t iio_device_process_samples(const struct iio_device *dev,
384 uint32_t *mask, size_t words, void *buf, size_t len,
385 ssize_t (*cb)(const struct iio_channel *, void *, void *),
386 void *data)
387{
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200388 uintptr_t ptr = (uintptr_t) buf, end = ptr + len;
Paul Cercueil46825942014-03-18 14:28:49 +0100389 unsigned int i;
390 ssize_t processed = 0,
Paul Cercueil645ab972014-03-24 14:36:12 +0100391 sample_size = iio_device_get_sample_size_mask(dev, mask, words);
Paul Cercueil46825942014-03-18 14:28:49 +0100392 if (sample_size <= 0)
393 return -EINVAL;
394
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200395 while (end - ptr >= (size_t) sample_size) {
Paul Cercueil46825942014-03-18 14:28:49 +0100396 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 ssize_t ret;
400
401 if (chn->index < 0) {
402 ERROR("Channel %s has negative index\n",
403 chn->id);
404 break;
405 }
406
407 if (!TEST_BIT(mask, chn->index))
408 continue;
409
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200410 if (ptr % length)
411 ptr += length - (ptr % length);
Paul Cercueil46825942014-03-18 14:28:49 +0100412
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200413 ret = cb(chn, (void *) ptr, data);
Paul Cercueil46825942014-03-18 14:28:49 +0100414 if (ret < 0)
415 return ret;
416 else
417 processed += ret;
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200418 ptr += length;
Paul Cercueil46825942014-03-18 14:28:49 +0100419 }
420 }
421 return processed;
422}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200423
424int iio_device_attr_read_longlong(const struct iio_device *dev,
425 const char *attr, long long *val)
426{
427 char *end, buf[1024];
428 long long value;
429 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
430 if (ret < 0)
431 return (int) ret;
432
433 value = strtoll(buf, &end, 0);
434 if (end == buf)
435 return -EINVAL;
436 *val = value;
437 return 0;
438}
439
440int iio_device_attr_read_bool(const struct iio_device *dev,
441 const char *attr, bool *val)
442{
443 long long value;
444 int ret = iio_device_attr_read_longlong(dev, attr, &value);
445 if (ret < 0)
446 return ret;
447
448 *val = !!value;
449 return 0;
450}
451
452int iio_device_attr_read_double(const struct iio_device *dev,
453 const char *attr, double *val)
454{
455 char *end, buf[1024];
456 double value;
457 ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf));
458 if (ret < 0)
459 return (int) ret;
460
461 value = strtod(buf, &end);
462 if (end == buf)
463 return -EINVAL;
464 *val = value;
465 return 0;
466}
467
468int iio_device_attr_write_longlong(const struct iio_device *dev,
469 const char *attr, long long val)
470{
471 char buf[1024];
472 snprintf(buf, sizeof(buf), "%lld", val);
473 return iio_device_attr_write(dev, attr, buf);
474}
475
476int iio_device_attr_write_double(const struct iio_device *dev,
477 const char *attr, double val)
478{
479 char buf[1024];
480 snprintf(buf, sizeof(buf), "%lf", val);
481 return iio_device_attr_write(dev, attr, buf);
482}
483
484int iio_device_attr_write_bool(const struct iio_device *dev,
485 const char *attr, bool val)
486{
487 if (val)
488 return iio_device_attr_write(dev, attr, "1");
489 else
490 return iio_device_attr_write(dev, attr, "0");
491}