blob: b4e04b24f6bbc1c375bd42660408d960dde82bd7 [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 Cercueil42090d12014-02-24 12:32:23 +010026static 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 channel */
41char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
42{
43 size_t len = sizeof("<channel id=\"\" name=\"\" "
Paul Cercueil85aaf482014-04-24 16:39:09 +020044 "type=\"output\" scan_element=\"false\" ></channel>")
Paul Cercueil8c29e412014-04-07 09:46:45 +020045 + strlen(chn->id) + (chn->name ? strlen(chn->name) : 0);
Paul Cercueil5822ab62014-04-04 13:29:17 +020046 char *ptr, *str, **attrs;
47 size_t *attrs_len;
Paul Cercueil42090d12014-02-24 12:32:23 +010048 unsigned int i;
49
Paul Cercueil5822ab62014-04-04 13:29:17 +020050 attrs_len = malloc(chn->nb_attrs * sizeof(*attrs_len));
51 if (!attrs_len)
52 return NULL;
53
54 attrs = malloc(chn->nb_attrs * sizeof(*attrs));
55 if (!attrs)
56 goto err_free_attrs_len;
57
Paul Cercueil42090d12014-02-24 12:32:23 +010058 for (i = 0; i < chn->nb_attrs; i++) {
59 char *xml = get_attr_xml(chn->attrs[i], &attrs_len[i]);
60 if (!xml)
61 goto err_free_attrs;
62 attrs[i] = xml;
63 len += attrs_len[i];
64 }
65
Paul Cercueil42090d12014-02-24 12:32:23 +010066 str = malloc(len);
67 if (!str)
68 goto err_free_attrs;
69
Paul Cercueil8c29e412014-04-07 09:46:45 +020070 snprintf(str, len, "<channel id=\"%s\"", chn->id);
Paul Cercueil42090d12014-02-24 12:32:23 +010071 ptr = strrchr(str, '\0');
72
73 if (chn->name) {
74 sprintf(ptr, " name=\"%s\"", chn->name);
75 ptr = strrchr(ptr, '\0');
76 }
77
Paul Cercueil85aaf482014-04-24 16:39:09 +020078 sprintf(ptr, " type=\"%s\" scan_element=\"%s\" >",
79 chn->is_output ? "output" : "input",
80 chn->is_scan_element ? "true" : "false");
Paul Cercueil42090d12014-02-24 12:32:23 +010081 ptr = strrchr(ptr, '\0');
82
83 for (i = 0; i < chn->nb_attrs; i++) {
84 strcpy(ptr, attrs[i]);
85 ptr += attrs_len[i];
86 free(attrs[i]);
87 }
88
Paul Cercueil5822ab62014-04-04 13:29:17 +020089 free(attrs);
90 free(attrs_len);
Paul Cercueil8c29e412014-04-07 09:46:45 +020091
Paul Cercueil42090d12014-02-24 12:32:23 +010092 strcpy(ptr, "</channel>");
93 *length = ptr - str + sizeof("</channel>") - 1;
94 return str;
95
96err_free_attrs:
97 while (i--)
98 free(attrs[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +020099 free(attrs);
100err_free_attrs_len:
101 free(attrs_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100102 return NULL;
103}
104
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100105const char * iio_channel_get_id(const struct iio_channel *chn)
106{
107 return chn->id;
108}
109
110const char * iio_channel_get_name(const struct iio_channel *chn)
111{
112 return chn->name;
113}
114
Paul Cercueil35a01312014-02-20 10:56:57 +0100115bool iio_channel_is_output(const struct iio_channel *chn)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100116{
Paul Cercueil35a01312014-02-20 10:56:57 +0100117 return chn->is_output;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100118}
119
Paul Cercueil85aaf482014-04-24 16:39:09 +0200120bool iio_channel_is_scan_element(const struct iio_channel *chn)
121{
122 return chn->is_scan_element;
123}
124
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100125unsigned int iio_channel_get_attrs_count(const struct iio_channel *chn)
126{
127 return chn->nb_attrs;
128}
129
130const char * iio_channel_get_attr(const struct iio_channel *chn,
131 unsigned int index)
132{
133 if (index >= chn->nb_attrs)
134 return NULL;
135 else
136 return chn->attrs[index];
137}
138
Paul Cercueil4f838d02014-03-28 11:26:15 +0100139const char * iio_channel_find_attr(const struct iio_channel *chn,
140 const char *name)
141{
142 unsigned int i;
143 for (i = 0; i < chn->nb_attrs; i++) {
144 const char *attr = chn->attrs[i];
145 if (!strcmp(attr, name))
146 return attr;
147 }
148 return NULL;
149}
150
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100151ssize_t iio_channel_attr_read(const struct iio_channel *chn,
152 const char *attr, char *dst, size_t len)
153{
Paul Cercueil6a013602014-02-19 12:37:39 +0100154 if (chn->dev->ctx->ops->read_channel_attr)
155 return chn->dev->ctx->ops->read_channel_attr(chn,
156 attr, dst, len);
157 else
158 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100159}
160
161ssize_t iio_channel_attr_write(const struct iio_channel *chn,
162 const char *attr, const char *src)
163{
Paul Cercueil6a013602014-02-19 12:37:39 +0100164 if (chn->dev->ctx->ops->write_channel_attr)
165 return chn->dev->ctx->ops->write_channel_attr(chn, attr, src);
166 else
167 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100168}
Paul Cercueil00236242014-02-18 15:09:06 +0100169
Paul Cercueild96e61f2014-03-07 16:13:37 +0100170void iio_channel_set_data(struct iio_channel *chn, void *data)
171{
172 chn->userdata = data;
173}
174
175void * iio_channel_get_data(const struct iio_channel *chn)
176{
177 return chn->userdata;
178}
179
Paul Cercueilae88fde2014-03-12 11:47:10 +0100180long iio_channel_get_index(const struct iio_channel *chn)
181{
182 return chn->index;
183}
184
Paul Cercueileb5ce552014-03-14 17:05:35 +0100185const struct iio_data_format * iio_channel_get_data_format(
186 const struct iio_channel *chn)
187{
188 return &chn->format;
189}
190
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100191bool iio_channel_is_enabled(const struct iio_channel *chn)
192{
Paul Cercueilff778232014-03-24 14:23:08 +0100193 return chn->index >= 0 && chn->dev->mask &&
194 TEST_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100195}
196
197void iio_channel_enable(struct iio_channel *chn)
198{
Paul Cercueilff778232014-03-24 14:23:08 +0100199 if (chn->index >= 0 && chn->dev->mask)
200 SET_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100201}
202
203void iio_channel_disable(struct iio_channel *chn)
204{
Paul Cercueilff778232014-03-24 14:23:08 +0100205 if (chn->index >= 0 && chn->dev->mask)
206 CLEAR_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100207}
208
Paul Cercueil00236242014-02-18 15:09:06 +0100209void free_channel(struct iio_channel *chn)
210{
211 unsigned int i;
212 for (i = 0; i < chn->nb_attrs; i++)
213 free((char *) chn->attrs[i]);
214 if (chn->nb_attrs)
215 free(chn->attrs);
216 if (chn->name)
217 free((char *) chn->name);
218 if (chn->id)
219 free((char *) chn->id);
220 free(chn);
221}
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100222
223static void byte_swap(uint8_t *dst, const uint8_t *src, size_t len)
224{
225 unsigned int i;
226 for (i = 0; i < len; i++)
227 dst[i] = src[len - i - 1];
228}
229
Paul Cercueild840d4c2014-04-07 19:38:58 +0200230static void shift_bits(uint8_t *dst, size_t shift, size_t len, bool left)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100231{
232 unsigned int i;
233 size_t shift_bytes = shift / 8;
234 shift %= 8;
235
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200236#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueild840d4c2014-04-07 19:38:58 +0200237 if (!left)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100238#else
Paul Cercueild840d4c2014-04-07 19:38:58 +0200239 if (left)
240#endif
241 {
242 if (shift_bytes) {
243 memmove(dst, dst + shift_bytes, len - shift_bytes);
244 memset(dst + len - shift_bytes, 0, shift_bytes);
245 }
246 if (shift) {
247 for (i = 0; i < len; i++) {
248#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
249 dst[i] >>= shift;
250 if (i < len - 1)
251 dst[i] |= dst[i + 1] << (8 - shift);
252#else
253 dst[i] <<= shift;
254 if (i < len - 1)
255 dst[i] |= dst[i + 1] >> (8 - shift);
256#endif
257 }
258 }
259 } else {
260 if (shift_bytes) {
261 memmove(dst + shift_bytes, dst, len - shift_bytes);
262 memset(dst, 0, shift_bytes);
263 }
264 if (shift) {
265 for (i = len; i > 0; i--) {
266#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
267 dst[i - 1] <<= shift;
268 if (i > 1)
269 dst[i - 1] |= dst[i - 2] >> (8 - shift);
270#else
271 dst[i - 1] >>= shift;
272 if (i > 1)
273 dst[i - 1] |= dst[i - 2] << (8 - shift);
274#endif
275 }
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100276 }
277 }
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100278}
279
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100280static void sign_extend(uint8_t *dst, size_t bits, size_t len)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100281{
282 size_t upper_bytes = ((len * 8 - bits) / 8);
283 uint8_t msb, msb_bit = 1 << ((bits - 1) % 8);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100284
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200285#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100286 msb = dst[len - 1 - upper_bytes] & msb_bit;
287 if (upper_bytes)
288 memset(dst + len - upper_bytes, msb ? 0xff : 0x00, upper_bytes);
289 if (msb)
290 dst[len - 1 - upper_bytes] |= ~(msb_bit - 1);
291#else
292 /* XXX: untested */
293 msb = dst[upper_bytes] & msb_bit;
294 if (upper_bytes)
295 memset(dst, msb ? 0xff : 0x00, upper_bytes);
296 if (msb)
297 dst[upper_bytes] |= ~(msb_bit - 1);
298#endif
299}
300
301void iio_channel_convert(const struct iio_channel *chn,
302 void *dst, const void *src)
303{
304 unsigned int len = chn->format.length / 8;
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200305#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100306 bool swap = chn->format.is_be;
307#else
308 bool swap = !chn->format.is_be;
309#endif
310
311 if (len == 1 || !swap)
312 memcpy(dst, src, len);
313 else
314 byte_swap(dst, src, len);
315
316 if (chn->format.shift)
Paul Cercueild840d4c2014-04-07 19:38:58 +0200317 shift_bits(dst, chn->format.shift, len, false);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100318 if (chn->format.is_signed)
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100319 sign_extend(dst, chn->format.bits, len);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100320}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200321
Paul Cercueild840d4c2014-04-07 19:38:58 +0200322void iio_channel_convert_inverse(const struct iio_channel *chn,
323 void *dst, const void *src)
324{
325 unsigned int len = chn->format.length / 8;
326 unsigned int bits = chn->format.bits;
327 unsigned int i;
328#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
329 bool swap = chn->format.is_be;
330#else
331 bool swap = !chn->format.is_be;
332#endif
333 uint8_t buf[1024];
334
335 /* Somehow I doubt we will have samples of 8192 bits each. */
336 if (len > sizeof(buf))
337 return;
338
339 memcpy(buf, src, len);
340
341 /* Clear upper bits */
342 if (bits % 8)
343 buf[bits / 8] &= (1 << (bits % 8)) - 1;
344
345 /* Clear upper bytes */
346 for (i = (bits + 7) / 8; i < len; i++)
347 buf[i] = 0;
348
349 if (chn->format.shift)
350 shift_bits(buf, chn->format.shift, len, true);
351
352 if (len == 1 || !swap)
353 memcpy(dst, buf, len);
354 else
355 byte_swap(dst, buf, len);
356}
357
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200358size_t iio_channel_read_raw(const struct iio_channel *chn,
359 struct iio_buffer *buf, void *dst, size_t len)
360{
361 uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
362 unsigned int length = chn->format.length / 8;
363
364 for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
365 src_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200366 dst_ptr + length <= end;
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200367 src_ptr += iio_buffer_step(buf),
368 dst_ptr += length)
369 memcpy((void *) dst_ptr, (const void *) src_ptr, length);
370 return dst_ptr - (uintptr_t) dst;
371}
372
Paul Cercueilbf221692014-04-07 19:40:53 +0200373size_t iio_channel_read(const struct iio_channel *chn,
374 struct iio_buffer *buf, void *dst, size_t len)
375{
376 uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
377 unsigned int length = chn->format.length / 8;
378
379 for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
380 src_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200381 dst_ptr + length <= end;
Paul Cercueilbf221692014-04-07 19:40:53 +0200382 src_ptr += iio_buffer_step(buf),
383 dst_ptr += length)
384 iio_channel_convert(chn,
385 (void *) dst_ptr, (const void *) src_ptr);
386 return dst_ptr - (uintptr_t) dst;
387}
388
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200389size_t iio_channel_write_raw(const struct iio_channel *chn,
390 struct iio_buffer *buf, const void *src, size_t len)
391{
392 uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
393 unsigned int length = chn->format.length / 8;
394
395 for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
396 dst_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200397 src_ptr + length <= end;
Paul Cercueil58fad3b2014-04-11 13:18:16 +0200398 dst_ptr += iio_buffer_step(buf),
399 src_ptr += length)
Paul Cercueil59a7d4c2014-04-07 17:34:53 +0200400 memcpy((void *) dst_ptr, (const void *) src_ptr, length);
401 return src_ptr - (uintptr_t) src;
402}
403
Paul Cercueilbf221692014-04-07 19:40:53 +0200404size_t iio_channel_write(const struct iio_channel *chn,
405 struct iio_buffer *buf, const void *src, size_t len)
406{
407 uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
408 unsigned int length = chn->format.length / 8;
409
410 for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
411 dst_ptr < (uintptr_t) iio_buffer_end(buf) &&
Paul Cercueil43e36ed2014-04-23 17:05:14 +0200412 src_ptr + length <= end;
Paul Cercueil58fad3b2014-04-11 13:18:16 +0200413 dst_ptr += iio_buffer_step(buf),
414 src_ptr += length)
Paul Cercueilbf221692014-04-07 19:40:53 +0200415 iio_channel_convert_inverse(chn,
416 (void *) dst_ptr, (const void *) src_ptr);
417 return src_ptr - (uintptr_t) src;
418}
419
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200420int iio_channel_attr_read_longlong(const struct iio_channel *chn,
421 const char *attr, long long *val)
422{
423 char *end, buf[1024];
424 long long value;
425 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
426 if (ret < 0)
427 return (int) ret;
428
429 value = strtoll(buf, &end, 0);
430 if (end == buf)
431 return -EINVAL;
432 *val = value;
433 return 0;
434}
435
436int iio_channel_attr_read_bool(const struct iio_channel *chn,
437 const char *attr, bool *val)
438{
439 long long value;
440 int ret = iio_channel_attr_read_longlong(chn, attr, &value);
441 if (ret < 0)
442 return ret;
443
444 *val = !!value;
445 return 0;
446}
447
448int iio_channel_attr_read_double(const struct iio_channel *chn,
449 const char *attr, double *val)
450{
451 char *end, buf[1024];
452 double value;
453 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
454 if (ret < 0)
455 return (int) ret;
456
457 value = strtod(buf, &end);
458 if (end == buf)
459 return -EINVAL;
460 *val = value;
461 return 0;
462}
463
464int iio_channel_attr_write_longlong(const struct iio_channel *chn,
465 const char *attr, long long val)
466{
467 char buf[1024];
468 snprintf(buf, sizeof(buf), "%lld", val);
469 return iio_channel_attr_write(chn, attr, buf);
470}
471
472int iio_channel_attr_write_double(const struct iio_channel *chn,
473 const char *attr, double val)
474{
475 char buf[1024];
476 snprintf(buf, sizeof(buf), "%lf", val);
477 return iio_channel_attr_write(chn, attr, buf);
478}
479
480int iio_channel_attr_write_bool(const struct iio_channel *chn,
481 const char *attr, bool val)
482{
483 if (val)
484 return iio_channel_attr_write(chn, attr, "1");
485 else
486 return iio_channel_attr_write(chn, attr, "0");
487}