blob: 64df8556cbb733925f6c2cbc01aca4231dbcca40 [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 */
36 sprintf(str, "<attribute name=\"%s\" />", attr);
37 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=\"\" "
44 "type=\"output\" ></channel>");
Paul Cercueil5822ab62014-04-04 13:29:17 +020045 char *ptr, *str, **attrs;
46 size_t *attrs_len;
Paul Cercueil42090d12014-02-24 12:32:23 +010047 unsigned int i;
48
Paul Cercueil5822ab62014-04-04 13:29:17 +020049 attrs_len = malloc(chn->nb_attrs * sizeof(*attrs_len));
50 if (!attrs_len)
51 return NULL;
52
53 attrs = malloc(chn->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 < chn->nb_attrs; i++) {
58 char *xml = get_attr_xml(chn->attrs[i], &attrs_len[i]);
59 if (!xml)
60 goto err_free_attrs;
61 attrs[i] = xml;
62 len += attrs_len[i];
63 }
64
65 len += strlen(chn->id);
66 if (chn->name)
67 len += strlen(chn->name);
68
69 str = malloc(len);
70 if (!str)
71 goto err_free_attrs;
72
73 sprintf(str, "<channel id=\"%s\"", chn->id);
74 ptr = strrchr(str, '\0');
75
76 if (chn->name) {
77 sprintf(ptr, " name=\"%s\"", chn->name);
78 ptr = strrchr(ptr, '\0');
79 }
80
81 sprintf(ptr, " type=\"%s\" >", chn->is_output ? "output" : "input");
82 ptr = strrchr(ptr, '\0');
83
84 for (i = 0; i < chn->nb_attrs; i++) {
85 strcpy(ptr, attrs[i]);
86 ptr += attrs_len[i];
87 free(attrs[i]);
88 }
89
Paul Cercueil5822ab62014-04-04 13:29:17 +020090 free(attrs);
91 free(attrs_len);
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
120unsigned int iio_channel_get_attrs_count(const struct iio_channel *chn)
121{
122 return chn->nb_attrs;
123}
124
125const char * iio_channel_get_attr(const struct iio_channel *chn,
126 unsigned int index)
127{
128 if (index >= chn->nb_attrs)
129 return NULL;
130 else
131 return chn->attrs[index];
132}
133
Paul Cercueil4f838d02014-03-28 11:26:15 +0100134const char * iio_channel_find_attr(const struct iio_channel *chn,
135 const char *name)
136{
137 unsigned int i;
138 for (i = 0; i < chn->nb_attrs; i++) {
139 const char *attr = chn->attrs[i];
140 if (!strcmp(attr, name))
141 return attr;
142 }
143 return NULL;
144}
145
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100146ssize_t iio_channel_attr_read(const struct iio_channel *chn,
147 const char *attr, char *dst, size_t len)
148{
Paul Cercueil6a013602014-02-19 12:37:39 +0100149 if (chn->dev->ctx->ops->read_channel_attr)
150 return chn->dev->ctx->ops->read_channel_attr(chn,
151 attr, dst, len);
152 else
153 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100154}
155
156ssize_t iio_channel_attr_write(const struct iio_channel *chn,
157 const char *attr, const char *src)
158{
Paul Cercueil6a013602014-02-19 12:37:39 +0100159 if (chn->dev->ctx->ops->write_channel_attr)
160 return chn->dev->ctx->ops->write_channel_attr(chn, attr, src);
161 else
162 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100163}
Paul Cercueil00236242014-02-18 15:09:06 +0100164
Paul Cercueild96e61f2014-03-07 16:13:37 +0100165void iio_channel_set_data(struct iio_channel *chn, void *data)
166{
167 chn->userdata = data;
168}
169
170void * iio_channel_get_data(const struct iio_channel *chn)
171{
172 return chn->userdata;
173}
174
Paul Cercueilae88fde2014-03-12 11:47:10 +0100175long iio_channel_get_index(const struct iio_channel *chn)
176{
177 return chn->index;
178}
179
Paul Cercueileb5ce552014-03-14 17:05:35 +0100180const struct iio_data_format * iio_channel_get_data_format(
181 const struct iio_channel *chn)
182{
183 return &chn->format;
184}
185
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100186bool iio_channel_is_enabled(const struct iio_channel *chn)
187{
Paul Cercueilff778232014-03-24 14:23:08 +0100188 return chn->index >= 0 && chn->dev->mask &&
189 TEST_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100190}
191
192void iio_channel_enable(struct iio_channel *chn)
193{
Paul Cercueilff778232014-03-24 14:23:08 +0100194 if (chn->index >= 0 && chn->dev->mask)
195 SET_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100196}
197
198void iio_channel_disable(struct iio_channel *chn)
199{
Paul Cercueilff778232014-03-24 14:23:08 +0100200 if (chn->index >= 0 && chn->dev->mask)
201 CLEAR_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100202}
203
Paul Cercueil00236242014-02-18 15:09:06 +0100204void free_channel(struct iio_channel *chn)
205{
206 unsigned int i;
207 for (i = 0; i < chn->nb_attrs; i++)
208 free((char *) chn->attrs[i]);
209 if (chn->nb_attrs)
210 free(chn->attrs);
211 if (chn->name)
212 free((char *) chn->name);
213 if (chn->id)
214 free((char *) chn->id);
215 free(chn);
216}
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100217
218static void byte_swap(uint8_t *dst, const uint8_t *src, size_t len)
219{
220 unsigned int i;
221 for (i = 0; i < len; i++)
222 dst[i] = src[len - i - 1];
223}
224
225static void shift_bits(uint8_t *dst, size_t shift, size_t len)
226{
227 unsigned int i;
228 size_t shift_bytes = shift / 8;
229 shift %= 8;
230
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200231#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100232 if (shift_bytes) {
233 memmove(dst, dst + shift_bytes, len - shift_bytes);
234 memset(dst + len - shift_bytes, 0, shift_bytes);
235 }
236 if (shift) {
237 for (i = 0; i < len; i++) {
238 dst[i] >>= shift;
239 if (i < len - 1)
240 dst[i] |= dst[i + 1] << (8 - shift);
241 }
242 }
243#else
244 /* XXX: untested */
245 if (shift_bytes) {
246 memmove(dst + shift_bytes, dst, len - shift_bytes);
247 memset(dst, 0, shift_bytes);
248 }
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200249 if (shift) {
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100250 for (i = len; i > 0; i--) {
251 dst[i - 1] >>= shift;
252 if (i > 1)
253 dst[i - 1] |= dst[i - 2] << (8 - shift);
254 }
255 }
256#endif
257}
258
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100259static void sign_extend(uint8_t *dst, size_t bits, size_t len)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100260{
261 size_t upper_bytes = ((len * 8 - bits) / 8);
262 uint8_t msb, msb_bit = 1 << ((bits - 1) % 8);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100263
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200264#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100265 msb = dst[len - 1 - upper_bytes] & msb_bit;
266 if (upper_bytes)
267 memset(dst + len - upper_bytes, msb ? 0xff : 0x00, upper_bytes);
268 if (msb)
269 dst[len - 1 - upper_bytes] |= ~(msb_bit - 1);
270#else
271 /* XXX: untested */
272 msb = dst[upper_bytes] & msb_bit;
273 if (upper_bytes)
274 memset(dst, msb ? 0xff : 0x00, upper_bytes);
275 if (msb)
276 dst[upper_bytes] |= ~(msb_bit - 1);
277#endif
278}
279
280void iio_channel_convert(const struct iio_channel *chn,
281 void *dst, const void *src)
282{
283 unsigned int len = chn->format.length / 8;
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200284#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100285 bool swap = chn->format.is_be;
286#else
287 bool swap = !chn->format.is_be;
288#endif
289
290 if (len == 1 || !swap)
291 memcpy(dst, src, len);
292 else
293 byte_swap(dst, src, len);
294
295 if (chn->format.shift)
296 shift_bits(dst, chn->format.shift, len);
297 if (chn->format.is_signed)
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100298 sign_extend(dst, chn->format.bits, len);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100299}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200300
301int iio_channel_attr_read_longlong(const struct iio_channel *chn,
302 const char *attr, long long *val)
303{
304 char *end, buf[1024];
305 long long value;
306 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
307 if (ret < 0)
308 return (int) ret;
309
310 value = strtoll(buf, &end, 0);
311 if (end == buf)
312 return -EINVAL;
313 *val = value;
314 return 0;
315}
316
317int iio_channel_attr_read_bool(const struct iio_channel *chn,
318 const char *attr, bool *val)
319{
320 long long value;
321 int ret = iio_channel_attr_read_longlong(chn, attr, &value);
322 if (ret < 0)
323 return ret;
324
325 *val = !!value;
326 return 0;
327}
328
329int iio_channel_attr_read_double(const struct iio_channel *chn,
330 const char *attr, double *val)
331{
332 char *end, buf[1024];
333 double value;
334 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
335 if (ret < 0)
336 return (int) ret;
337
338 value = strtod(buf, &end);
339 if (end == buf)
340 return -EINVAL;
341 *val = value;
342 return 0;
343}
344
345int iio_channel_attr_write_longlong(const struct iio_channel *chn,
346 const char *attr, long long val)
347{
348 char buf[1024];
349 snprintf(buf, sizeof(buf), "%lld", val);
350 return iio_channel_attr_write(chn, attr, buf);
351}
352
353int iio_channel_attr_write_double(const struct iio_channel *chn,
354 const char *attr, double val)
355{
356 char buf[1024];
357 snprintf(buf, sizeof(buf), "%lf", val);
358 return iio_channel_attr_write(chn, attr, buf);
359}
360
361int iio_channel_attr_write_bool(const struct iio_channel *chn,
362 const char *attr, bool val)
363{
364 if (val)
365 return iio_channel_attr_write(chn, attr, "1");
366 else
367 return iio_channel_attr_write(chn, attr, "0");
368}