blob: 0aa717901f826e6e664baa34d8871e6fd9a8f904 [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 Cercueil4c6729d2014-04-04 17:24:41 +020022#include <errno.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010023#include <string.h>
24
25static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
26"<!DOCTYPE context ["
27"<!ELEMENT context (device)*>"
28"<!ELEMENT device (channel | attribute)*>"
29"<!ELEMENT channel (attribute)*>"
30"<!ELEMENT attribute EMPTY>"
31"<!ATTLIST context name CDATA #REQUIRED>"
32"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
33"<!ATTLIST channel id CDATA #REQUIRED type CDATA #REQUIRED name CDATA #IMPLIED>"
34"<!ATTLIST attribute name CDATA #REQUIRED>"
35"]>";
36
37/* Returns a string containing the XML representation of this context */
Paul Cercueil4c6729d2014-04-04 17:24:41 +020038static char * context_create_xml(const struct iio_context *ctx)
Paul Cercueil42090d12014-02-24 12:32:23 +010039{
Paul Cercueil9aab0192014-04-07 11:04:30 +020040 size_t len = strlen(ctx->name) + sizeof(xml_header) - 1 +
Paul Cercueil42090d12014-02-24 12:32:23 +010041 sizeof("<context name=\"\" ></context>");
Paul Cercueil5822ab62014-04-04 13:29:17 +020042 size_t *devices_len;
43 char *str, *ptr, **devices;
Paul Cercueil42090d12014-02-24 12:32:23 +010044 unsigned int i;
45
Paul Cercueil9aab0192014-04-07 11:04:30 +020046 if (!ctx->nb_devices) {
47 str = malloc(len);
48 if (str)
49 snprintf(str, len, "%s<context name=\"%s\" ></context>",
50 xml_header, ctx->name);
51 return str;
52 }
53
Paul Cercueil5822ab62014-04-04 13:29:17 +020054 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
55 if (!devices_len)
56 return NULL;
57
58 devices = malloc(ctx->nb_devices * sizeof(*devices));
59 if (!devices)
60 goto err_free_devices_len;
61
Paul Cercueil42090d12014-02-24 12:32:23 +010062 for (i = 0; i < ctx->nb_devices; i++) {
63 char *xml = iio_device_get_xml(ctx->devices[i],
64 &devices_len[i]);
65 if (!xml)
66 goto err_free_devices;
67 devices[i] = xml;
68 len += devices_len[i];
69 }
70
71 str = malloc(len);
72 if (!str)
73 goto err_free_devices;
74
Paul Cercueil8c29e412014-04-07 09:46:45 +020075 snprintf(str, len, "%s<context name=\"%s\" >", xml_header, ctx->name);
Paul Cercueil42090d12014-02-24 12:32:23 +010076 ptr = strrchr(str, '\0');
77
78 for (i = 0; i < ctx->nb_devices; i++) {
79 strcpy(ptr, devices[i]);
80 ptr += devices_len[i];
81 free(devices[i]);
82 }
83
Paul Cercueil5822ab62014-04-04 13:29:17 +020084 free(devices);
85 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010086 strcpy(ptr, "</context>");
87 return str;
88
89err_free_devices:
90 while (i--)
91 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +020092 free(devices);
93err_free_devices_len:
94 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010095 return NULL;
96}
97
Paul Cercueil4c6729d2014-04-04 17:24:41 +020098const char * iio_context_get_xml(const struct iio_context *ctx)
99{
100 return ctx->xml;
101}
102
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100103const char * iio_context_get_name(const struct iio_context *ctx)
104{
105 return ctx->name;
106}
107
108void iio_context_destroy(struct iio_context *ctx)
109{
Paul Cercueil50363542014-02-18 16:04:28 +0100110 unsigned int i;
111 if (ctx->ops->shutdown)
112 ctx->ops->shutdown(ctx);
113
114 for (i = 0; i < ctx->nb_devices; i++)
115 free_device(ctx->devices[i]);
116 if (ctx->nb_devices)
117 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200118 if (ctx->xml)
119 free(ctx->xml);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100120 free(ctx);
121}
122
123unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
124{
125 return ctx->nb_devices;
126}
127
128struct iio_device * iio_context_get_device(const struct iio_context *ctx,
129 unsigned int index)
130{
131 if (index >= ctx->nb_devices)
132 return NULL;
133 else
134 return ctx->devices[index];
135}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100136
Paul Cercueil17512b02014-03-28 11:15:24 +0100137struct iio_device * iio_context_find_device(const struct iio_context *ctx,
138 const char *name)
139{
140 unsigned int i;
141 for (i = 0; i < ctx->nb_devices; i++) {
142 struct iio_device *dev = ctx->devices[i];
143 if (!strcmp(dev->id, name) ||
144 (dev->name && !strcmp(dev->name, name)))
145 return dev;
146 }
147 return NULL;
148}
149
Paul Cercueilae88fde2014-03-12 11:47:10 +0100150static void init_index(struct iio_channel *chn)
151{
152 char buf[1024];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100153 long ret = (long) iio_channel_attr_read(chn, "index", buf, sizeof(buf));
Paul Cercueilae88fde2014-03-12 11:47:10 +0100154 if (ret < 0)
155 chn->index = ret;
156 else
157 chn->index = strtol(buf, NULL, 0);
158}
159
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100160static void init_data_format(struct iio_channel *chn)
161{
162 char buf[1024];
163 int ret = iio_channel_attr_read(chn, "type", buf, sizeof(buf));
164 if (ret < 0) {
165 chn->format.length = 0;
166 } else {
167 char endian, sign;
168 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
169 &chn->format.bits,
170 &chn->format.length,
171 &chn->format.shift);
172 chn->format.is_signed = sign == 's';
173 chn->format.is_be = endian == 'b';
174 }
175
176 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
177 if (ret < 0) {
178 chn->format.with_scale = false;
179 } else {
180 chn->format.with_scale = true;
181 chn->format.scale = strtod(buf, NULL);
182 }
183}
184
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100185static void reorder_channels(struct iio_device *dev)
186{
187 bool found;
188 unsigned int i;
189
190 /* Reorder channels by index */
191 do {
192 found = false;
193 for (i = 1; i < dev->nb_channels; i++) {
194 struct iio_channel **channels = dev->channels;
195 long ch1 = channels[i - 1]->index;
196 long ch2 = channels[i]->index;
197
198 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
199 struct iio_channel *bak = channels[i];
200 channels[i] = channels[i - 1];
201 channels[i - 1] = bak;
202 found = true;
203 }
204 }
205 } while (found);
206}
207
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200208int iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100209{
210 unsigned int i;
211 for (i = 0; i < ctx->nb_devices; i++) {
212 unsigned int j;
213 struct iio_device *dev = ctx->devices[i];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100214 for (j = 0; j < dev->nb_channels; j++) {
Paul Cercueilae88fde2014-03-12 11:47:10 +0100215 init_index(dev->channels[j]);
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100216 init_data_format(dev->channels[j]);
217 }
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100218
219 reorder_channels(dev);
Paul Cercueilae88fde2014-03-12 11:47:10 +0100220 }
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200221
222 ctx->xml = context_create_xml(ctx);
223 return ctx->xml ? 0 : -ENOMEM;
Paul Cercueilae88fde2014-03-12 11:47:10 +0100224}