blob: ae9fe2090fbb4054a40ac5f2d52d39453e99994b [file] [log] [blame]
Paul Cercueilc7bad0f2014-03-03 17:06:48 +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
19#include "debug.h"
20#include "iio-private.h"
21
22#include <errno.h>
23#include <netdb.h>
Paul Cercueile60c3ed2014-03-04 11:23:56 +010024#include <stdbool.h>
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010025#include <string.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <unistd.h>
29
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010030#define _STRINGIFY(x) #x
31#define STRINGIFY(x) _STRINGIFY(x)
32
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010033#define IIOD_PORT 30431
Paul Cercueil2e38bbe2014-03-19 15:27:15 +010034#define IIOD_PORT_STR STRINGIFY(IIOD_PORT)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010035
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +010036struct iio_context_pdata {
37 int fd;
38};
39
Paul Cercueilc7bad0f2014-03-03 17:06:48 +010040static ssize_t write_all(const void *src, size_t len, int fd)
41{
42 const void *ptr = src;
43 while (len) {
44 ssize_t ret = send(fd, ptr, len, 0);
45 if (ret < 0)
46 return -errno;
47 ptr += ret;
48 len -= ret;
49 }
50 return ptr - src;
51}
52
53static ssize_t read_all(void *dst, size_t len, int fd)
54{
55 void *ptr = dst;
56 while (len) {
57 ssize_t ret = recv(fd, ptr, len, 0);
58 if (ret < 0)
59 return -errno;
60 ptr += ret;
61 len -= ret;
62 }
63 return ptr - dst;
64}
65
Paul Cercueile60c3ed2014-03-04 11:23:56 +010066static int read_integer(int fd, long *val)
67{
68 unsigned int i;
69 char buf[1024], *ptr;
70 ssize_t ret;
71 bool found = false;
72
73 for (i = 0; i < sizeof(buf) - 1; i++) {
74 ret = read_all(buf + i, 1, fd);
75 if (ret < 0)
76 return (int) ret;
77
78 /* Skip the eventual first few carriage returns */
79 if (buf[i] != '\n')
80 found = true;
81 else if (found)
82 break;
83 }
84
85 buf[i] = '\0';
86 ret = (ssize_t) strtol(buf, &ptr, 10);
87 if (ptr == buf)
88 return -EINVAL;
89 *val = (long) ret;
90 return 0;
91}
92
Paul Cercueilbb76bf92014-03-11 10:20:18 +010093static ssize_t write_command(const char *cmd, int fd)
94{
95 ssize_t ret;
96
97 DEBUG("Writing command: %s\n", cmd);
98 ret = write_all(cmd, strlen(cmd), fd);
99 if (ret < 0) {
100 char buf[1024];
101 strerror_r(-ret, buf, sizeof(buf));
102 ERROR("Unable to send command: %s\n", buf);
103 }
104 return ret;
105}
106
107static long exec_command(const char *cmd, int fd)
108{
109 long resp;
110 ssize_t ret = write_command(cmd, fd);
111 if (ret < 0)
112 return (long) ret;
113
114 DEBUG("Reading response\n");
115 ret = read_integer(fd, &resp);
116 if (ret < 0) {
117 char buf[1024];
118 strerror_r(-ret, buf, sizeof(buf));
119 ERROR("Unable to read response: %s\n", buf);
120 return (long) ret;
121 }
122
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100123#if LOG_LEVEL >= DEBUG_L
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100124 if (resp < 0) {
125 char buf[1024];
126 strerror_r(-resp, buf, sizeof(buf));
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100127 DEBUG("Server returned an error: %s\n", buf);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100128 }
Paul Cercueilc7fe2ea2014-03-28 11:38:45 +0100129#endif
130
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100131 return resp;
132}
133
Paul Cercueil3c407f82014-04-02 14:11:59 +0200134static int network_open(const struct iio_device *dev,
135 size_t samples_count, uint32_t *mask, size_t nb)
Paul Cercueilba059762014-03-14 11:02:02 +0100136{
137 char buf[1024], *ptr;
138 unsigned int i;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100139 int ret;
Paul Cercueilba059762014-03-14 11:02:02 +0100140
Paul Cercueilff778232014-03-24 14:23:08 +0100141 if (nb != dev->words)
Paul Cercueilba059762014-03-14 11:02:02 +0100142 return -EINVAL;
143
Paul Cercueil3c407f82014-04-02 14:11:59 +0200144 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
145 dev->id, (unsigned long) samples_count);
Paul Cercueilba059762014-03-14 11:02:02 +0100146 ptr = buf + strlen(buf);
147
148 for (i = nb; i > 0; i--) {
149 sprintf(ptr, "%08x", mask[i - 1]);
150 ptr += 8;
151 }
152 strcpy(ptr, "\r\n");
153
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100154 ret = (int) exec_command(buf, dev->ctx->pdata->fd);
155 if (ret < 0) {
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100156 return ret;
157 } else {
Paul Cercueilff778232014-03-24 14:23:08 +0100158 memcpy(dev->mask, mask, nb * sizeof(*mask));
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100159 return 0;
160 }
Paul Cercueilba059762014-03-14 11:02:02 +0100161}
162
163static int network_close(const struct iio_device *dev)
164{
165 char buf[1024];
166 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", dev->id);
Paul Cercueilff778232014-03-24 14:23:08 +0100167 return (int) exec_command(buf, dev->ctx->pdata->fd);
Paul Cercueilba059762014-03-14 11:02:02 +0100168}
169
Paul Cercueil45c575d2014-03-20 15:14:01 +0100170static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len,
171 uint32_t *mask, size_t words)
Paul Cercueilf9286452014-03-18 14:32:17 +0100172{
Paul Cercueil9945bc82014-03-05 14:07:29 +0100173 int fd = dev->ctx->pdata->fd;
Paul Cercueil45c575d2014-03-20 15:14:01 +0100174 ssize_t ret, read = 0;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100175 char buf[1024];
Paul Cercueil45c575d2014-03-20 15:14:01 +0100176 bool read_mask = true;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100177
Paul Cercueil45c575d2014-03-20 15:14:01 +0100178 if (!len || words != (dev->nb_channels + 31) / 32)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100179 return -EINVAL;
180
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100181 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
182 dev->id, (unsigned long) len);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100183 ret = write_command(buf, fd);
Paul Cercueil45c575d2014-03-20 15:14:01 +0100184 if (ret < 0)
Paul Cercueil9945bc82014-03-05 14:07:29 +0100185 return ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100186
187 do {
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100188 unsigned int i;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100189 long read_len;
190
191 DEBUG("Reading READ response\n");
192 ret = read_integer(fd, &read_len);
193 if (ret < 0) {
194 strerror_r(-ret, buf, sizeof(buf));
195 ERROR("Unable to read response to READ: %s\n", buf);
196 return read ?: ret;
197 }
198
199 if (read_len < 0) {
200 strerror_r(-read_len, buf, sizeof(buf));
201 ERROR("Server returned an error: %s\n", buf);
202 return read ?: read_len;
Paul Cercueila78b6eb2014-03-17 17:28:07 +0100203 } else if (read_len == 0) {
204 break;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100205 }
206
207 DEBUG("Bytes to read: %li\n", read_len);
208
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100209 if (read_mask) {
210 DEBUG("Reading mask\n");
211 buf[8] = '\0';
Paul Cercueil45c575d2014-03-20 15:14:01 +0100212 for (i = words; i > 0; i--) {
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100213 ret = read_all(buf, 8, fd);
214 if (ret < 0)
215 break;
216 sscanf(buf, "%08x", &mask[i - 1]);
217 DEBUG("mask[%i] = 0x%x\n", i - 1, mask[i - 1]);
Paul Cercueil43c1e6c2014-03-20 14:26:20 +0100218 }
219 read_mask = false;
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100220 }
221
222 if (ret > 0) {
223 char c;
224 ret = recv(fd, &c, 1, 0);
225 if (ret > 0 && c != '\n')
226 ret = -EIO;
227 }
228
229 if (ret < 0) {
230 strerror_r(-ret, buf, sizeof(buf));
231 ERROR("Unable to read mask: %s\n", buf);
Paul Cercueil5cab3ae2014-03-14 11:23:56 +0100232 return read ?: ret;
233 }
234
Paul Cercueil9945bc82014-03-05 14:07:29 +0100235 ret = read_all(dst, read_len, fd);
236 if (ret < 0) {
237 strerror_r(-ret, buf, sizeof(buf));
238 ERROR("Unable to read response to READ: %s\n", buf);
239 return read ?: ret;
240 }
241
Paul Cercueilf9286452014-03-18 14:32:17 +0100242 dst += ret;
243 read += ret;
Paul Cercueil9945bc82014-03-05 14:07:29 +0100244 len -= read_len;
245 } while (len);
246
247 return read;
248}
249
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100250static ssize_t network_read_attr_helper(int fd, const char *id,
251 const char *chn, const char *attr, char *dst, size_t len)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100252{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100253 long read_len;
254 ssize_t ret;
255 char buf[1024];
256
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100257 if (chn)
258 snprintf(buf, sizeof(buf), "READ %s %s %s\r\n", id, chn, attr);
259 else
260 snprintf(buf, sizeof(buf), "READ %s %s\r\n", id, attr);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100261 read_len = exec_command(buf, fd);
262 if (read_len < 0)
263 return (ssize_t) read_len;
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100264
265 if (read_len > len) {
266 ERROR("Value returned by server is too large\n");
267 return -EIO;
268 }
269
270 ret = read_all(dst, read_len, fd);
271 if (ret < 0) {
272 strerror_r(-ret, buf, sizeof(buf));
273 ERROR("Unable to read response to READ: %s\n", buf);
274 return ret;
275 }
276
277 dst[read_len] = '\0';
278 return read_len + 1;
279}
280
Paul Cercueil07897d32014-03-06 12:46:08 +0100281static ssize_t network_write_attr_helper(int fd, const char *id,
282 const char *chn, const char *attr, const char *src)
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100283{
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100284 char buf[1024];
285
Paul Cercueil07897d32014-03-06 12:46:08 +0100286 if (chn)
287 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s\r\n",
288 id, chn, attr, src);
289 else
290 snprintf(buf, sizeof(buf), "WRITE %s %s %s\r\n", id, attr, src);
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100291 return (ssize_t) exec_command(buf, fd);
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100292}
293
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100294static ssize_t network_read_dev_attr(const struct iio_device *dev,
295 const char *attr, char *dst, size_t len)
296{
297 return network_read_attr_helper(dev->ctx->pdata->fd, dev->id,
298 NULL, attr, dst, len);
299}
300
Paul Cercueil07897d32014-03-06 12:46:08 +0100301static ssize_t network_write_dev_attr(const struct iio_device *dev,
302 const char *attr, const char *src)
303{
304 return network_write_attr_helper(dev->ctx->pdata->fd, dev->id,
305 NULL, attr, src);
306}
307
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100308static ssize_t network_read_chn_attr(const struct iio_channel *chn,
309 const char *attr, char *dst, size_t len)
310{
311 return network_read_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
312 chn->id, attr, dst, len);
313}
314
Paul Cercueil07897d32014-03-06 12:46:08 +0100315static ssize_t network_write_chn_attr(const struct iio_channel *chn,
316 const char *attr, const char *src)
317{
318 return network_write_attr_helper(chn->dev->ctx->pdata->fd, chn->dev->id,
319 chn->id, attr, src);
320}
321
Paul Cercueildcab40c2014-03-11 10:59:14 +0100322static int network_get_trigger(const struct iio_device *dev,
323 const struct iio_device **trigger)
324{
325 struct iio_context_pdata *pdata = dev->ctx->pdata;
326 unsigned int i;
327 char buf[1024];
328 ssize_t ret;
329 long resp;
330
331 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", dev->id);
332 resp = exec_command(buf, pdata->fd);
333 if (resp < 0) {
334 return (int) resp;
335 } else if (resp == 0) {
336 *trigger = NULL;
337 return 0;
338 } else if (resp > sizeof(buf)) {
339 ERROR("Value returned by server is too large\n");
340 return -EIO;
341 }
342
343 ret = read_all(buf, resp, pdata->fd);
344 if (ret < 0) {
345 strerror_r(-ret, buf, sizeof(buf));
346 ERROR("Unable to read response to GETTRIG: %s\n", buf);
347 return ret;
348 }
349
350 for (i = 0; i < dev->ctx->nb_devices; i++) {
351 struct iio_device *cur = dev->ctx->devices[i];
352 if (iio_device_is_trigger(cur) &&
353 !strncmp(cur->name, buf, resp)) {
354 *trigger = cur;
355 return 0;
356 }
357 }
358
359 return -ENXIO;
360}
361
362static int network_set_trigger(const struct iio_device *dev,
363 const struct iio_device *trigger)
364{
365 char buf[1024];
366 if (trigger)
367 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
368 dev->id, trigger->id);
369 else
370 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n", dev->id);
371 return (int) exec_command(buf, dev->ctx->pdata->fd);
372}
373
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100374static void network_shutdown(struct iio_context *ctx)
375{
376 struct iio_context_pdata *pdata = ctx->pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100377 unsigned int i;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100378
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100379 write_command("\r\nEXIT\r\n", pdata->fd);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100380 close(pdata->fd);
381 free(pdata);
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100382
383 for (i = 0; i < ctx->nb_devices; i++) {
384 struct iio_device *dev = ctx->devices[i];
385 if (dev->pdata)
386 free(dev->pdata);
387 }
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100388}
389
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100390static struct iio_backend_ops network_ops = {
Paul Cercueilba059762014-03-14 11:02:02 +0100391 .open = network_open,
392 .close = network_close,
Paul Cercueil9945bc82014-03-05 14:07:29 +0100393 .read = network_read,
Paul Cercueil3e94a5b2014-03-04 13:00:41 +0100394 .read_device_attr = network_read_dev_attr,
395 .write_device_attr = network_write_dev_attr,
Paul Cercueil99cf3d42014-03-06 12:35:26 +0100396 .read_channel_attr = network_read_chn_attr,
Paul Cercueil07897d32014-03-06 12:46:08 +0100397 .write_channel_attr = network_write_chn_attr,
Paul Cercueildcab40c2014-03-11 10:59:14 +0100398 .get_trigger = network_get_trigger,
399 .set_trigger = network_set_trigger,
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100400 .shutdown = network_shutdown,
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100401};
402
403static struct iio_context * get_context(int fd)
404{
405 struct iio_context *ctx;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100406 char *xml;
Paul Cercueilbb76bf92014-03-11 10:20:18 +0100407 long xml_len = exec_command("PRINT\r\n", fd);
408 if (xml_len < 0)
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100409 return NULL;
Paul Cercueile60c3ed2014-03-04 11:23:56 +0100410
411 DEBUG("Server returned a XML string of length %li\n", xml_len);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100412 xml = malloc(xml_len);
413 if (!xml) {
414 ERROR("Unable to allocate data\n");
415 return NULL;
416 }
417
418 DEBUG("Reading XML string...\n");
419 read_all(xml, xml_len, fd);
420
421 DEBUG("Creating context from XML...\n");
422 ctx = iio_create_xml_context_mem(xml, xml_len);
423 free(xml);
424 return ctx;
425}
426
427struct iio_context * iio_create_network_context(const char *host)
428{
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100429 struct addrinfo hints, *res;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100430 struct iio_context *ctx;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100431 struct iio_context_pdata *pdata;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100432 unsigned int i;
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100433 int fd, ret;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100434
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100435 memset(&hints, 0, sizeof(hints));
436 hints.ai_family = AF_UNSPEC;
437 hints.ai_socktype = SOCK_STREAM;
438 ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
439 if (ret) {
440 ERROR("Unable to find IP address for host %s: %s\n",
441 host, gai_strerror(ret));
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100442 return NULL;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100443 }
444
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100445 fd = socket(res->ai_family, res->ai_socktype, 0);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100446 if (fd < 0) {
447 ERROR("Unable to open socket\n");
448 return NULL;
449 }
450
Paul Cercueil2e38bbe2014-03-19 15:27:15 +0100451 if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100452 ERROR("Unable to connect\n");
453 goto err_close_socket;
454 }
455
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100456 pdata = calloc(1, sizeof(*pdata));
457 if (!pdata) {
458 ERROR("Unable to allocate memory\n");
459 goto err_close_socket;
460 }
461
462 pdata->fd = fd;
463
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100464 DEBUG("Creating context...\n");
465 ctx = get_context(fd);
466 if (!ctx)
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100467 goto err_free_pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100468
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100469 for (i = 0; i < ctx->nb_devices; i++) {
470 struct iio_device *dev = ctx->devices[i];
Paul Cercueilff778232014-03-24 14:23:08 +0100471 uint32_t *mask = NULL;
472
473 dev->words = (dev->nb_channels + 31) / 32;
474 if (dev->words) {
475 mask = calloc(dev->words, sizeof(*mask));
476 if (!mask)
477 goto err_network_shutdown;
478 }
479
480 dev->mask = mask;
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100481 }
482
Paul Cercueilff778232014-03-24 14:23:08 +0100483
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100484 /* Override the name and low-level functions of the XML context
485 * with those corresponding to the network context */
486 ctx->name = "network";
487 ctx->ops = &network_ops;
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100488 ctx->pdata = pdata;
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100489
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100490 iio_context_init_channels(ctx);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100491 return ctx;
492
Paul Cercueil44ae11c2014-03-17 09:56:29 +0100493err_network_shutdown:
494 network_shutdown(ctx);
495 iio_context_destroy(ctx);
Paul Cercueil8fd9c8f2014-03-03 17:21:31 +0100496err_free_pdata:
497 free(pdata);
Paul Cercueilc7bad0f2014-03-03 17:06:48 +0100498err_close_socket:
499 close(fd);
500 return NULL;
501}