blob: f55cd13a08dd25fcd8c1fcc45e5415ec8e329ba6 [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 Cercueil167d3112014-02-18 12:23:53 +010019#include "debug.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010020#include "iio-private.h"
21
Paul Cercueil167d3112014-02-18 12:23:53 +010022#include <errno.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010023#include <stdio.h>
Paul Cercueil167d3112014-02-18 12:23:53 +010024#include <string.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010025
Paul Cercueil42d12352014-05-05 16:11:58 +020026static char *get_attr_xml(struct iio_channel_attr *attr, size_t *length)
Paul Cercueil42090d12014-02-24 12:32:23 +010027{
Paul Cercueil42d12352014-05-05 16:11:58 +020028 char *str;
29 size_t len = strlen(attr->name) + sizeof("<attribute name=\"\" />");
30 if (attr->filename)
31 len += strlen(attr->filename) + sizeof("filename=\"\"");
32
33 str = malloc(len);
Paul Cercueil42090d12014-02-24 12:32:23 +010034 if (!str) {
35 ERROR("Unable to allocate memory\n");
36 return NULL;
37 }
38
39 *length = len - 1; /* Skip the \0 */
Paul Cercueil42d12352014-05-05 16:11:58 +020040 if (attr->filename)
41 snprintf(str, len, "<attribute name=\"%s\" filename=\"%s\" />",
42 attr->name, attr->filename);
43 else
44 snprintf(str, len, "<attribute name=\"%s\" />", attr->name);
Paul Cercueil42090d12014-02-24 12:32:23 +010045 return str;
46}
47
48/* Returns a string containing the XML representation of this channel */
49char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
50{
51 size_t len = sizeof("<channel id=\"\" name=\"\" "
Paul Cercueil85aaf482014-04-24 16:39:09 +020052 "type=\"output\" scan_element=\"false\" ></channel>")
Paul Cercueil8c29e412014-04-07 09:46:45 +020053 + strlen(chn->id) + (chn->name ? strlen(chn->name) : 0);
Paul Cercueil5822ab62014-04-04 13:29:17 +020054 char *ptr, *str, **attrs;
55 size_t *attrs_len;
Paul Cercueil42090d12014-02-24 12:32:23 +010056 unsigned int i;
57
Paul Cercueil5822ab62014-04-04 13:29:17 +020058 attrs_len = malloc(chn->nb_attrs * sizeof(*attrs_len));
59 if (!attrs_len)
60 return NULL;
61
62 attrs = malloc(chn->nb_attrs * sizeof(*attrs));
63 if (!attrs)
64 goto err_free_attrs_len;
65
Paul Cercueil42090d12014-02-24 12:32:23 +010066 for (i = 0; i < chn->nb_attrs; i++) {
Paul Cercueil42d12352014-05-05 16:11:58 +020067 char *xml = get_attr_xml(&chn->attrs[i], &attrs_len[i]);
Paul Cercueil42090d12014-02-24 12:32:23 +010068 if (!xml)
69 goto err_free_attrs;
70 attrs[i] = xml;
71 len += attrs_len[i];
72 }
73
Paul Cercueil42090d12014-02-24 12:32:23 +010074 str = malloc(len);
75 if (!str)
76 goto err_free_attrs;
77
Paul Cercueil8c29e412014-04-07 09:46:45 +020078 snprintf(str, len, "<channel id=\"%s\"", chn->id);
Paul Cercueil42090d12014-02-24 12:32:23 +010079 ptr = strrchr(str, '\0');
80
81 if (chn->name) {
82 sprintf(ptr, " name=\"%s\"", chn->name);
83 ptr = strrchr(ptr, '\0');
84 }
85
Paul Cercueil85aaf482014-04-24 16:39:09 +020086 sprintf(ptr, " type=\"%s\" scan_element=\"%s\" >",
87 chn->is_output ? "output" : "input",
88 chn->is_scan_element ? "true" : "false");
Paul Cercueil42090d12014-02-24 12:32:23 +010089 ptr = strrchr(ptr, '\0');
90
91 for (i = 0; i < chn->nb_attrs; i++) {
92 strcpy(ptr, attrs[i]);
93 ptr += attrs_len[i];
94 free(attrs[i]);
95 }
96
Paul Cercueil5822ab62014-04-04 13:29:17 +020097 free(attrs);
98 free(attrs_len);
Paul Cercueil8c29e412014-04-07 09:46:45 +020099
Paul Cercueil42090d12014-02-24 12:32:23 +0100100 strcpy(ptr, "</channel>");
101 *length = ptr - str + sizeof("</channel>") - 1;
102 return str;
103
104err_free_attrs:
105 while (i--)
106 free(attrs[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200107 free(attrs);
108err_free_attrs_len:
109 free(attrs_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100110 return NULL;
111}
112
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100113const char * iio_channel_get_id(const struct iio_channel *chn)
114{
115 return chn->id;
116}
117
118const char * iio_channel_get_name(const struct iio_channel *chn)
119{
120 return chn->name;
121}
122
Paul Cercueil35a01312014-02-20 10:56:57 +0100123bool iio_channel_is_output(const struct iio_channel *chn)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100124{
Paul Cercueil35a01312014-02-20 10:56:57 +0100125 return chn->is_output;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100126}
127
Paul Cercueil85aaf482014-04-24 16:39:09 +0200128bool iio_channel_is_scan_element(const struct iio_channel *chn)
129{
130 return chn->is_scan_element;
131}
132
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100133unsigned int iio_channel_get_attrs_count(const struct iio_channel *chn)
134{
135 return chn->nb_attrs;
136}
137
138const char * iio_channel_get_attr(const struct iio_channel *chn,
139 unsigned int index)
140{
141 if (index >= chn->nb_attrs)
142 return NULL;
143 else
Paul Cercueilb34e0222014-05-05 15:32:38 +0200144 return chn->attrs[index].name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100145}
146
Paul Cercueil4f838d02014-03-28 11:26:15 +0100147const char * iio_channel_find_attr(const struct iio_channel *chn,
148 const char *name)
149{
150 unsigned int i;
151 for (i = 0; i < chn->nb_attrs; i++) {
Paul Cercueilb34e0222014-05-05 15:32:38 +0200152 const char *attr = chn->attrs[i].name;
Paul Cercueil4f838d02014-03-28 11:26:15 +0100153 if (!strcmp(attr, name))
154 return attr;
155 }
156 return NULL;
157}
158
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100159ssize_t iio_channel_attr_read(const struct iio_channel *chn,
160 const char *attr, char *dst, size_t len)
161{
Paul Cercueil6a013602014-02-19 12:37:39 +0100162 if (chn->dev->ctx->ops->read_channel_attr)
163 return chn->dev->ctx->ops->read_channel_attr(chn,
164 attr, dst, len);
165 else
166 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100167}
168
Paul Cercueilcecda352014-05-06 18:14:29 +0200169ssize_t iio_channel_attr_write_raw(const struct iio_channel *chn,
170 const char *attr, const void *src, size_t len)
171{
172 if (chn->dev->ctx->ops->write_channel_attr)
173 return chn->dev->ctx->ops->write_channel_attr(chn,
174 attr, src, len);
175 else
176 return -ENOSYS;
177}
178
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100179ssize_t iio_channel_attr_write(const struct iio_channel *chn,
180 const char *attr, const char *src)
181{
Paul Cercueilcecda352014-05-06 18:14:29 +0200182 return iio_channel_attr_write_raw(chn, attr, src, strlen(src) + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100183}
Paul Cercueil00236242014-02-18 15:09:06 +0100184
Paul Cercueild96e61f2014-03-07 16:13:37 +0100185void iio_channel_set_data(struct iio_channel *chn, void *data)
186{
187 chn->userdata = data;
188}
189
190void * iio_channel_get_data(const struct iio_channel *chn)
191{
192 return chn->userdata;
193}
194
Paul Cercueilae88fde2014-03-12 11:47:10 +0100195long iio_channel_get_index(const struct iio_channel *chn)
196{
197 return chn->index;
198}
199
Paul Cercueileb5ce552014-03-14 17:05:35 +0100200const struct iio_data_format * iio_channel_get_data_format(
201 const struct iio_channel *chn)
202{
203 return &chn->format;
204}
205
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100206bool iio_channel_is_enabled(const struct iio_channel *chn)
207{
Paul Cercueilff778232014-03-24 14:23:08 +0100208 return chn->index >= 0 && chn->dev->mask &&
209 TEST_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100210}
211
212void iio_channel_enable(struct iio_channel *chn)
213{
Paul Cercueila2beb4c2014-04-24 17:23:21 +0200214 if (chn->is_scan_element && chn->index >= 0 && chn->dev->mask)
Paul Cercueilff778232014-03-24 14:23:08 +0100215 SET_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100216}
217
218void iio_channel_disable(struct iio_channel *chn)
219{
Paul Cercueilff778232014-03-24 14:23:08 +0100220 if (chn->index >= 0 && chn->dev->mask)
221 CLEAR_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100222}
223
Paul Cercueil00236242014-02-18 15:09:06 +0100224void free_channel(struct iio_channel *chn)
225{
226 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200227 for (i = 0; i < chn->nb_attrs; i++) {
228 free(chn->attrs[i].name);
229 free(chn->attrs[i].filename);
230 }
Paul Cercueil00236242014-02-18 15:09:06 +0100231 if (chn->nb_attrs)
232 free(chn->attrs);
233 if (chn->name)
Paul Cercueil42d12352014-05-05 16:11:58 +0200234 free(chn->name);
Paul Cercueil00236242014-02-18 15:09:06 +0100235 if (chn->id)
Paul Cercueil42d12352014-05-05 16:11:58 +0200236 free(chn->id);
Paul Cercueil00236242014-02-18 15:09:06 +0100237 free(chn);
238}
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100239
240static void byte_swap(uint8_t *dst, const uint8_t *src, size_t len)
241{
242 unsigned int i;
243 for (i = 0; i < len; i++)
244 dst[i] = src[len - i - 1];
245}
246
Paul Cercueild840d4c2014-04-07 19:38:58 +0200247static void shift_bits(uint8_t *dst, size_t shift, size_t len, bool left)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100248{
249 unsigned int i;
250 size_t shift_bytes = shift / 8;
251 shift %= 8;
252
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200253#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueild840d4c2014-04-07 19:38:58 +0200254 if (!left)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100255#else
Paul Cercueild840d4c2014-04-07 19:38:58 +0200256 if (left)
257#endif
258 {
259 if (shift_bytes) {
260 memmove(dst, dst + shift_bytes, len - shift_bytes);
261 memset(dst + len - shift_bytes, 0, shift_bytes);
262 }
263 if (shift) {
264 for (i = 0; i < len; i++) {
265#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
266 dst[i] >>= shift;
267 if (i < len - 1)
268 dst[i] |= dst[i + 1] << (8 - shift);
269#else
270 dst[i] <<= shift;
271 if (i < len - 1)
272 dst[i] |= dst[i + 1] >> (8 - shift);
273#endif
274 }
275 }
276 } else {
277 if (shift_bytes) {
278 memmove(dst + shift_bytes, dst, len - shift_bytes);
279 memset(dst, 0, shift_bytes);
280 }
281 if (shift) {
282 for (i = len; i > 0; i--) {
283#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
284 dst[i - 1] <<= shift;
285 if (i > 1)
286 dst[i - 1] |= dst[i - 2] >> (8 - shift);
287#else
288 dst[i - 1] >>= shift;
289 if (i > 1)
290 dst[i - 1] |= dst[i - 2] << (8 - shift);
291#endif
292 }
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100293 }
294 }
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100295}
296
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100297static void sign_extend(uint8_t *dst, size_t bits, size_t len)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100298{
299 size_t upper_bytes = ((len * 8 - bits) / 8);
300 uint8_t msb, msb_bit = 1 << ((bits - 1) % 8);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100301
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200302#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100303 msb = dst[len - 1 - upper_bytes] & msb_bit;
304 if (upper_bytes)
305 memset(dst + len - upper_bytes, msb ? 0xff : 0x00, upper_bytes);
306 if (msb)
307 dst[len - 1 - upper_bytes] |= ~(msb_bit - 1);
308#else
309 /* XXX: untested */
310 msb = dst[upper_bytes] & msb_bit;
311 if (upper_bytes)
312 memset(dst, msb ? 0xff : 0x00, upper_bytes);
313 if (msb)
314 dst[upper_bytes] |= ~(msb_bit - 1);
315#endif
316}
317
318void iio_channel_convert(const struct iio_channel *chn,
319 void *dst, const void *src)
320{
321 unsigned int len = chn->format.length / 8;
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200322#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100323 bool swap = chn->format.is_be;
324#else
325 bool swap = !chn->format.is_be;
326#endif
327
328 if (len == 1 || !swap)
329 memcpy(dst, src, len);
330 else
331 byte_swap(dst, src, len);
332
333 if (chn->format.shift)
Paul Cercueild840d4c2014-04-07 19:38:58 +0200334 shift_bits(dst, chn->format.shift, len, false);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100335 if (chn->format.is_signed)
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100336 sign_extend(dst, chn->format.bits, len);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100337}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200338
Paul Cercueild840d4c2014-04-07 19:38:58 +0200339void iio_channel_convert_inverse(const struct iio_channel *chn,
340 void *dst, const void *src)
341{
342 unsigned int len = chn->format.length / 8;
343 unsigned int bits = chn->format.bits;
344 unsigned int i;
345#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
346 bool swap = chn->format.is_be;
347#else
348 bool swap = !chn->format.is_be;
349#endif
350 uint8_t buf[1024];
351
352 /* Somehow I doubt we will have samples of 8192 bits each. */
353 if (len > sizeof(buf))
354 return;
355
356 memcpy(buf, src, len);
357
358 /* Clear upper bits */
359 if (bits % 8)
360 buf[bits / 8] &= (1 << (bits % 8)) - 1;
361
362 /* Clear upper bytes */
363 for (i = (bits + 7) / 8; i < len; i++)
364 buf[i] = 0;
365
366 if (chn->format.shift)
367 shift_bits(buf, chn->format.shift, len, true);
368
369 if (len == 1 || !swap)
370 memcpy(dst, buf, len);
371 else
372 byte_swap(dst, buf, len);
373}
374
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200375size_t iio_channel_read_raw(const struct iio_channel *chn,
376 struct iio_buffer *buf, void *dst, size_t len)
377{
378 uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
379 unsigned int length = chn->format.length / 8;
380
381 for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
382 src_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200383 dst_ptr + length <= end;
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200384 src_ptr += iio_buffer_step(buf),
385 dst_ptr += length)
386 memcpy((void *) dst_ptr, (const void *) src_ptr, length);
387 return dst_ptr - (uintptr_t) dst;
388}
389
Paul Cercueilbf221692014-04-07 19:40:53 +0200390size_t iio_channel_read(const struct iio_channel *chn,
391 struct iio_buffer *buf, void *dst, size_t len)
392{
393 uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
394 unsigned int length = chn->format.length / 8;
395
396 for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
397 src_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200398 dst_ptr + length <= end;
Paul Cercueilbf221692014-04-07 19:40:53 +0200399 src_ptr += iio_buffer_step(buf),
400 dst_ptr += length)
401 iio_channel_convert(chn,
402 (void *) dst_ptr, (const void *) src_ptr);
403 return dst_ptr - (uintptr_t) dst;
404}
405
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200406size_t iio_channel_write_raw(const struct iio_channel *chn,
407 struct iio_buffer *buf, const void *src, size_t len)
408{
409 uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
410 unsigned int length = chn->format.length / 8;
411
412 for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
413 dst_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200414 src_ptr + length <= end;
Paul Cercueil58fad3b2014-04-11 13:18:16 +0200415 dst_ptr += iio_buffer_step(buf),
416 src_ptr += length)
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200417 memcpy((void *) dst_ptr, (const void *) src_ptr, length);
418 return src_ptr - (uintptr_t) src;
419}
420
Paul Cercueilbf221692014-04-07 19:40:53 +0200421size_t iio_channel_write(const struct iio_channel *chn,
422 struct iio_buffer *buf, const void *src, size_t len)
423{
424 uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
425 unsigned int length = chn->format.length / 8;
426
427 for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
428 dst_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200429 src_ptr + length <= end;
Paul Cercueil58fad3b2014-04-11 13:18:16 +0200430 dst_ptr += iio_buffer_step(buf),
431 src_ptr += length)
Paul Cercueilbf221692014-04-07 19:40:53 +0200432 iio_channel_convert_inverse(chn,
433 (void *) dst_ptr, (const void *) src_ptr);
434 return src_ptr - (uintptr_t) src;
435}
436
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200437int iio_channel_attr_read_longlong(const struct iio_channel *chn,
438 const char *attr, long long *val)
439{
440 char *end, buf[1024];
441 long long value;
442 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
443 if (ret < 0)
444 return (int) ret;
445
446 value = strtoll(buf, &end, 0);
447 if (end == buf)
448 return -EINVAL;
449 *val = value;
450 return 0;
451}
452
453int iio_channel_attr_read_bool(const struct iio_channel *chn,
454 const char *attr, bool *val)
455{
456 long long value;
457 int ret = iio_channel_attr_read_longlong(chn, attr, &value);
458 if (ret < 0)
459 return ret;
460
461 *val = !!value;
462 return 0;
463}
464
465int iio_channel_attr_read_double(const struct iio_channel *chn,
466 const char *attr, double *val)
467{
468 char *end, buf[1024];
469 double value;
470 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
471 if (ret < 0)
472 return (int) ret;
473
474 value = strtod(buf, &end);
475 if (end == buf)
476 return -EINVAL;
477 *val = value;
478 return 0;
479}
480
481int iio_channel_attr_write_longlong(const struct iio_channel *chn,
482 const char *attr, long long val)
483{
484 char buf[1024];
485 snprintf(buf, sizeof(buf), "%lld", val);
486 return iio_channel_attr_write(chn, attr, buf);
487}
488
489int iio_channel_attr_write_double(const struct iio_channel *chn,
490 const char *attr, double val)
491{
492 char buf[1024];
493 snprintf(buf, sizeof(buf), "%lf", val);
494 return iio_channel_attr_write(chn, attr, buf);
495}
496
497int iio_channel_attr_write_bool(const struct iio_channel *chn,
498 const char *attr, bool val)
499{
500 if (val)
Paul Cercueilcecda352014-05-06 18:14:29 +0200501 return iio_channel_attr_write_raw(chn, attr, "1", 2);
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200502 else
Paul Cercueilcecda352014-05-06 18:14:29 +0200503 return iio_channel_attr_write_raw(chn, attr, "0", 2);
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200504}
Paul Cercueil6f8dbd42014-05-05 17:05:59 +0200505
506const char * iio_channel_attr_get_filename(
507 const struct iio_channel *chn, const char *attr)
508{
509 unsigned int i;
510 for (i = 0; i < chn->nb_attrs; i++) {
511 if (!strcmp(chn->attrs[i].name, attr))
512 return chn->attrs[i].filename;
513 }
514 return NULL;
515}