blob: 42ac77630a778a2617ceb0617d6c8dd03dfd2b1e [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 Cercueil8c29e412014-04-07 09:46:45 +020044 "type=\"output\" ></channel>")
45 + 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
78 sprintf(ptr, " type=\"%s\" >", chn->is_output ? "output" : "input");
79 ptr = strrchr(ptr, '\0');
80
81 for (i = 0; i < chn->nb_attrs; i++) {
82 strcpy(ptr, attrs[i]);
83 ptr += attrs_len[i];
84 free(attrs[i]);
85 }
86
Paul Cercueil5822ab62014-04-04 13:29:17 +020087 free(attrs);
88 free(attrs_len);
Paul Cercueil8c29e412014-04-07 09:46:45 +020089
Paul Cercueil42090d12014-02-24 12:32:23 +010090 strcpy(ptr, "</channel>");
91 *length = ptr - str + sizeof("</channel>") - 1;
92 return str;
93
94err_free_attrs:
95 while (i--)
96 free(attrs[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +020097 free(attrs);
98err_free_attrs_len:
99 free(attrs_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100100 return NULL;
101}
102
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100103const char * iio_channel_get_id(const struct iio_channel *chn)
104{
105 return chn->id;
106}
107
108const char * iio_channel_get_name(const struct iio_channel *chn)
109{
110 return chn->name;
111}
112
Paul Cercueil35a01312014-02-20 10:56:57 +0100113bool iio_channel_is_output(const struct iio_channel *chn)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100114{
Paul Cercueil35a01312014-02-20 10:56:57 +0100115 return chn->is_output;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100116}
117
118unsigned int iio_channel_get_attrs_count(const struct iio_channel *chn)
119{
120 return chn->nb_attrs;
121}
122
123const char * iio_channel_get_attr(const struct iio_channel *chn,
124 unsigned int index)
125{
126 if (index >= chn->nb_attrs)
127 return NULL;
128 else
129 return chn->attrs[index];
130}
131
Paul Cercueil4f838d02014-03-28 11:26:15 +0100132const char * iio_channel_find_attr(const struct iio_channel *chn,
133 const char *name)
134{
135 unsigned int i;
136 for (i = 0; i < chn->nb_attrs; i++) {
137 const char *attr = chn->attrs[i];
138 if (!strcmp(attr, name))
139 return attr;
140 }
141 return NULL;
142}
143
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100144ssize_t iio_channel_attr_read(const struct iio_channel *chn,
145 const char *attr, char *dst, size_t len)
146{
Paul Cercueil6a013602014-02-19 12:37:39 +0100147 if (chn->dev->ctx->ops->read_channel_attr)
148 return chn->dev->ctx->ops->read_channel_attr(chn,
149 attr, dst, len);
150 else
151 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100152}
153
154ssize_t iio_channel_attr_write(const struct iio_channel *chn,
155 const char *attr, const char *src)
156{
Paul Cercueil6a013602014-02-19 12:37:39 +0100157 if (chn->dev->ctx->ops->write_channel_attr)
158 return chn->dev->ctx->ops->write_channel_attr(chn, attr, src);
159 else
160 return -ENOSYS;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100161}
Paul Cercueil00236242014-02-18 15:09:06 +0100162
Paul Cercueild96e61f2014-03-07 16:13:37 +0100163void iio_channel_set_data(struct iio_channel *chn, void *data)
164{
165 chn->userdata = data;
166}
167
168void * iio_channel_get_data(const struct iio_channel *chn)
169{
170 return chn->userdata;
171}
172
Paul Cercueilae88fde2014-03-12 11:47:10 +0100173long iio_channel_get_index(const struct iio_channel *chn)
174{
175 return chn->index;
176}
177
Paul Cercueileb5ce552014-03-14 17:05:35 +0100178const struct iio_data_format * iio_channel_get_data_format(
179 const struct iio_channel *chn)
180{
181 return &chn->format;
182}
183
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100184bool iio_channel_is_enabled(const struct iio_channel *chn)
185{
Paul Cercueilff778232014-03-24 14:23:08 +0100186 return chn->index >= 0 && chn->dev->mask &&
187 TEST_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100188}
189
190void iio_channel_enable(struct iio_channel *chn)
191{
Paul Cercueilff778232014-03-24 14:23:08 +0100192 if (chn->index >= 0 && chn->dev->mask)
193 SET_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100194}
195
196void iio_channel_disable(struct iio_channel *chn)
197{
Paul Cercueilff778232014-03-24 14:23:08 +0100198 if (chn->index >= 0 && chn->dev->mask)
199 CLEAR_BIT(chn->dev->mask, chn->index);
Paul Cercueil9b5827e2014-03-12 15:31:51 +0100200}
201
Paul Cercueil00236242014-02-18 15:09:06 +0100202void free_channel(struct iio_channel *chn)
203{
204 unsigned int i;
205 for (i = 0; i < chn->nb_attrs; i++)
206 free((char *) chn->attrs[i]);
207 if (chn->nb_attrs)
208 free(chn->attrs);
209 if (chn->name)
210 free((char *) chn->name);
211 if (chn->id)
212 free((char *) chn->id);
213 free(chn);
214}
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100215
216static void byte_swap(uint8_t *dst, const uint8_t *src, size_t len)
217{
218 unsigned int i;
219 for (i = 0; i < len; i++)
220 dst[i] = src[len - i - 1];
221}
222
223static void shift_bits(uint8_t *dst, size_t shift, size_t len)
224{
225 unsigned int i;
226 size_t shift_bytes = shift / 8;
227 shift %= 8;
228
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200229#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100230 if (shift_bytes) {
231 memmove(dst, dst + shift_bytes, len - shift_bytes);
232 memset(dst + len - shift_bytes, 0, shift_bytes);
233 }
234 if (shift) {
235 for (i = 0; i < len; i++) {
236 dst[i] >>= shift;
237 if (i < len - 1)
238 dst[i] |= dst[i + 1] << (8 - shift);
239 }
240 }
241#else
242 /* XXX: untested */
243 if (shift_bytes) {
244 memmove(dst + shift_bytes, dst, len - shift_bytes);
245 memset(dst, 0, shift_bytes);
246 }
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200247 if (shift) {
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100248 for (i = len; i > 0; i--) {
249 dst[i - 1] >>= shift;
250 if (i > 1)
251 dst[i - 1] |= dst[i - 2] << (8 - shift);
252 }
253 }
254#endif
255}
256
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100257static void sign_extend(uint8_t *dst, size_t bits, size_t len)
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100258{
259 size_t upper_bytes = ((len * 8 - bits) / 8);
260 uint8_t msb, msb_bit = 1 << ((bits - 1) % 8);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100261
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200262#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100263 msb = dst[len - 1 - upper_bytes] & msb_bit;
264 if (upper_bytes)
265 memset(dst + len - upper_bytes, msb ? 0xff : 0x00, upper_bytes);
266 if (msb)
267 dst[len - 1 - upper_bytes] |= ~(msb_bit - 1);
268#else
269 /* XXX: untested */
270 msb = dst[upper_bytes] & msb_bit;
271 if (upper_bytes)
272 memset(dst, msb ? 0xff : 0x00, upper_bytes);
273 if (msb)
274 dst[upper_bytes] |= ~(msb_bit - 1);
275#endif
276}
277
278void iio_channel_convert(const struct iio_channel *chn,
279 void *dst, const void *src)
280{
281 unsigned int len = chn->format.length / 8;
Paul Cercueil5ecb8ac2014-04-04 12:38:21 +0200282#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100283 bool swap = chn->format.is_be;
284#else
285 bool swap = !chn->format.is_be;
286#endif
287
288 if (len == 1 || !swap)
289 memcpy(dst, src, len);
290 else
291 byte_swap(dst, src, len);
292
293 if (chn->format.shift)
294 shift_bits(dst, chn->format.shift, len);
295 if (chn->format.is_signed)
Paul Cercueil0524d0a2014-03-25 11:57:24 +0100296 sign_extend(dst, chn->format.bits, len);
Paul Cercueil2917ffb2014-03-21 15:47:12 +0100297}
Paul Cercueil3dbd47d2014-03-31 11:19:40 +0200298
299int iio_channel_attr_read_longlong(const struct iio_channel *chn,
300 const char *attr, long long *val)
301{
302 char *end, buf[1024];
303 long long value;
304 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
305 if (ret < 0)
306 return (int) ret;
307
308 value = strtoll(buf, &end, 0);
309 if (end == buf)
310 return -EINVAL;
311 *val = value;
312 return 0;
313}
314
315int iio_channel_attr_read_bool(const struct iio_channel *chn,
316 const char *attr, bool *val)
317{
318 long long value;
319 int ret = iio_channel_attr_read_longlong(chn, attr, &value);
320 if (ret < 0)
321 return ret;
322
323 *val = !!value;
324 return 0;
325}
326
327int iio_channel_attr_read_double(const struct iio_channel *chn,
328 const char *attr, double *val)
329{
330 char *end, buf[1024];
331 double value;
332 ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
333 if (ret < 0)
334 return (int) ret;
335
336 value = strtod(buf, &end);
337 if (end == buf)
338 return -EINVAL;
339 *val = value;
340 return 0;
341}
342
343int iio_channel_attr_write_longlong(const struct iio_channel *chn,
344 const char *attr, long long val)
345{
346 char buf[1024];
347 snprintf(buf, sizeof(buf), "%lld", val);
348 return iio_channel_attr_write(chn, attr, buf);
349}
350
351int iio_channel_attr_write_double(const struct iio_channel *chn,
352 const char *attr, double val)
353{
354 char buf[1024];
355 snprintf(buf, sizeof(buf), "%lf", val);
356 return iio_channel_attr_write(chn, attr, buf);
357}
358
359int iio_channel_attr_write_bool(const struct iio_channel *chn,
360 const char *attr, bool val)
361{
362 if (val)
363 return iio_channel_attr_write(chn, attr, "1");
364 else
365 return iio_channel_attr_write(chn, attr, "0");
366}