blob: 9d09bbc55ed903ee756f52e0700dea6858e1edc2 [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{
40 size_t len = strlen(ctx->name) +
41 sizeof(xml_header) - 1 +
42 sizeof("<context name=\"\" ></context>");
Paul Cercueil5822ab62014-04-04 13:29:17 +020043 size_t *devices_len;
44 char *str, *ptr, **devices;
Paul Cercueil42090d12014-02-24 12:32:23 +010045 unsigned int i;
46
Paul Cercueil5822ab62014-04-04 13:29:17 +020047 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
48 if (!devices_len)
49 return NULL;
50
51 devices = malloc(ctx->nb_devices * sizeof(*devices));
52 if (!devices)
53 goto err_free_devices_len;
54
Paul Cercueil42090d12014-02-24 12:32:23 +010055 for (i = 0; i < ctx->nb_devices; i++) {
56 char *xml = iio_device_get_xml(ctx->devices[i],
57 &devices_len[i]);
58 if (!xml)
59 goto err_free_devices;
60 devices[i] = xml;
61 len += devices_len[i];
62 }
63
64 str = malloc(len);
65 if (!str)
66 goto err_free_devices;
67
68 sprintf(str, "%s<context name=\"%s\" >", xml_header, ctx->name);
69 ptr = strrchr(str, '\0');
70
71 for (i = 0; i < ctx->nb_devices; i++) {
72 strcpy(ptr, devices[i]);
73 ptr += devices_len[i];
74 free(devices[i]);
75 }
76
Paul Cercueil5822ab62014-04-04 13:29:17 +020077 free(devices);
78 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010079 strcpy(ptr, "</context>");
80 return str;
81
82err_free_devices:
83 while (i--)
84 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +020085 free(devices);
86err_free_devices_len:
87 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010088 return NULL;
89}
90
Paul Cercueil4c6729d2014-04-04 17:24:41 +020091const char * iio_context_get_xml(const struct iio_context *ctx)
92{
93 return ctx->xml;
94}
95
Paul Cercueil0b2ce712014-02-17 15:04:18 +010096const char * iio_context_get_name(const struct iio_context *ctx)
97{
98 return ctx->name;
99}
100
101void iio_context_destroy(struct iio_context *ctx)
102{
Paul Cercueil50363542014-02-18 16:04:28 +0100103 unsigned int i;
104 if (ctx->ops->shutdown)
105 ctx->ops->shutdown(ctx);
106
107 for (i = 0; i < ctx->nb_devices; i++)
108 free_device(ctx->devices[i]);
109 if (ctx->nb_devices)
110 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200111 if (ctx->xml)
112 free(ctx->xml);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100113 free(ctx);
114}
115
116unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
117{
118 return ctx->nb_devices;
119}
120
121struct iio_device * iio_context_get_device(const struct iio_context *ctx,
122 unsigned int index)
123{
124 if (index >= ctx->nb_devices)
125 return NULL;
126 else
127 return ctx->devices[index];
128}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100129
Paul Cercueil17512b02014-03-28 11:15:24 +0100130struct iio_device * iio_context_find_device(const struct iio_context *ctx,
131 const char *name)
132{
133 unsigned int i;
134 for (i = 0; i < ctx->nb_devices; i++) {
135 struct iio_device *dev = ctx->devices[i];
136 if (!strcmp(dev->id, name) ||
137 (dev->name && !strcmp(dev->name, name)))
138 return dev;
139 }
140 return NULL;
141}
142
Paul Cercueilae88fde2014-03-12 11:47:10 +0100143static void init_index(struct iio_channel *chn)
144{
145 char buf[1024];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100146 long ret = (long) iio_channel_attr_read(chn, "index", buf, sizeof(buf));
Paul Cercueilae88fde2014-03-12 11:47:10 +0100147 if (ret < 0)
148 chn->index = ret;
149 else
150 chn->index = strtol(buf, NULL, 0);
151}
152
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100153static void init_data_format(struct iio_channel *chn)
154{
155 char buf[1024];
156 int ret = iio_channel_attr_read(chn, "type", buf, sizeof(buf));
157 if (ret < 0) {
158 chn->format.length = 0;
159 } else {
160 char endian, sign;
161 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
162 &chn->format.bits,
163 &chn->format.length,
164 &chn->format.shift);
165 chn->format.is_signed = sign == 's';
166 chn->format.is_be = endian == 'b';
167 }
168
169 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
170 if (ret < 0) {
171 chn->format.with_scale = false;
172 } else {
173 chn->format.with_scale = true;
174 chn->format.scale = strtod(buf, NULL);
175 }
176}
177
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100178static void reorder_channels(struct iio_device *dev)
179{
180 bool found;
181 unsigned int i;
182
183 /* Reorder channels by index */
184 do {
185 found = false;
186 for (i = 1; i < dev->nb_channels; i++) {
187 struct iio_channel **channels = dev->channels;
188 long ch1 = channels[i - 1]->index;
189 long ch2 = channels[i]->index;
190
191 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
192 struct iio_channel *bak = channels[i];
193 channels[i] = channels[i - 1];
194 channels[i - 1] = bak;
195 found = true;
196 }
197 }
198 } while (found);
199}
200
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200201int iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100202{
203 unsigned int i;
204 for (i = 0; i < ctx->nb_devices; i++) {
205 unsigned int j;
206 struct iio_device *dev = ctx->devices[i];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100207 for (j = 0; j < dev->nb_channels; j++) {
Paul Cercueilae88fde2014-03-12 11:47:10 +0100208 init_index(dev->channels[j]);
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100209 init_data_format(dev->channels[j]);
210 }
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100211
212 reorder_channels(dev);
Paul Cercueilae88fde2014-03-12 11:47:10 +0100213 }
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200214
215 ctx->xml = context_create_xml(ctx);
216 return ctx->xml ? 0 : -ENOMEM;
Paul Cercueilae88fde2014-03-12 11:47:10 +0100217}