blob: 44ddc8bfe704def06d536660f814fbe3106590b6 [file] [log] [blame]
Paul Cercueil1f75a8f2015-12-02 11:51:14 +01001#include "debug.h"
Paul Cercueil2cb884a2015-11-30 15:01:25 +01002#include "iiod-client.h"
3#include "iio-lock.h"
Paul Cercueilba870932015-12-01 18:17:57 +01004#include "iio-private.h"
Paul Cercueil2cb884a2015-11-30 15:01:25 +01005
6#include <errno.h>
7#include <string.h>
Paul Cercueil6a785882015-11-30 16:36:19 +01008#include <stdio.h>
Paul Cercueil2cb884a2015-11-30 15:01:25 +01009
10struct iiod_client {
11 struct iio_context_pdata *pdata;
12 const struct iiod_client_ops *ops;
13 struct iio_mutex *lock;
14};
15
Paul Cercueil6a785882015-11-30 16:36:19 +010016static ssize_t iiod_client_read_integer(struct iiod_client *client,
17 int desc, int *val)
18{
Paul Cercueil6a785882015-11-30 16:36:19 +010019 unsigned int i;
20 char buf[1024], *ptr = NULL, *end;
21 ssize_t ret;
22 int value;
23
24 do {
25 ret = client->ops->read_line(client->pdata,
26 desc, buf, sizeof(buf));
27 if (ret < 0)
28 return ret;
29
30 for (i = 0; i < (unsigned int) ret; i++) {
31 if (buf[i] != '\n') {
32 if (!ptr)
33 ptr = &buf[i];
34 } else if (!!ptr) {
35 break;
36 }
37 }
38 } while (!ptr);
39
40 buf[i] = '\0';
41
42 value = (int) strtol(ptr, &end, 10);
43 if (ptr == end)
44 return -EINVAL;
45
46 *val = value;
47 return 0;
48}
49
50static int iiod_client_exec_command(struct iiod_client *client,
51 int desc, const char *cmd)
52{
53 int resp;
54 ssize_t ret;
55
56 ret = client->ops->write(client->pdata, desc, cmd, strlen(cmd));
57 if (ret < 0)
58 return (int) ret;
59
60 ret = iiod_client_read_integer(client, desc, &resp);
61 return ret < 0 ? (int) ret : resp;
62}
63
Paul Cercueil408b9672015-11-30 18:39:31 +010064static ssize_t iiod_client_write_all(struct iiod_client *client,
65 int desc, const void *src, size_t len)
66{
67 struct iio_context_pdata *pdata = client->pdata;
68 const struct iiod_client_ops *ops = client->ops;
69 uintptr_t ptr = (uintptr_t) src;
70
71 while (len) {
72 ssize_t ret = ops->write(pdata, desc, (const void *) ptr, len);
73
74 if (ret < 0) {
75 if (ret == -EINTR)
76 continue;
77 else
78 return ret;
79 }
80
81 if (ret == 0)
82 return -EPIPE;
83
84 ptr += ret;
85 len -= ret;
86 }
87
88 return (ssize_t) (ptr - (uintptr_t) src);
89}
90
91static ssize_t iiod_client_read_all(struct iiod_client *client,
92 int desc, void *dst, size_t len)
93{
94 struct iio_context_pdata *pdata = client->pdata;
95 const struct iiod_client_ops *ops = client->ops;
96 uintptr_t ptr = (uintptr_t) dst;
97
98 while (len) {
99 ssize_t ret = ops->read(pdata, desc, (void *) ptr, len);
100
101 if (ret < 0) {
102 if (ret == -EINTR)
103 continue;
104 else
105 return ret;
106 }
107
108 if (ret == 0)
109 return -EPIPE;
110
111 ptr += ret;
112 len -= ret;
113 }
114
115 return (ssize_t) (ptr - (uintptr_t) dst);
116}
117
Paul Cercueil2cb884a2015-11-30 15:01:25 +0100118struct iiod_client * iiod_client_new(struct iio_context_pdata *pdata,
119 struct iio_mutex *lock, const struct iiod_client_ops *ops)
120{
121 struct iiod_client *client;
122
123 client = malloc(sizeof(*client));
124 if (!client) {
125 errno = ENOMEM;
126 return NULL;
127 }
128
129 client->lock = lock;
130 client->pdata = pdata;
131 client->ops = ops;
132 return client;
133}
134
135void iiod_client_destroy(struct iiod_client *client)
136{
137 free(client);
138}
139
140int iiod_client_get_version(struct iiod_client *client, int desc,
141 unsigned int *major, unsigned int *minor, char *git_tag)
142{
143 struct iio_context_pdata *pdata = client->pdata;
144 const struct iiod_client_ops *ops = client->ops;
145 char buf[256], *ptr = buf, *end;
146 long maj, min;
147 int ret;
148
149 iio_mutex_lock(client->lock);
150
151 ret = ops->write(pdata, desc, "VERSION\r\n", sizeof("VERSION\r\n") - 1);
152 if (ret < 0) {
153 iio_mutex_unlock(client->lock);
154 return ret;
155 }
156
Paul Cercueileb772192016-04-08 14:54:02 +0200157 ret = ops->read_line(pdata, desc, buf, sizeof(buf));
Paul Cercueil2cb884a2015-11-30 15:01:25 +0100158 iio_mutex_unlock(client->lock);
159
160 if (ret < 0)
161 return ret;
162
163 maj = strtol(ptr, &end, 10);
164 if (ptr == end)
165 return -EIO;
166
167 ptr = end + 1;
168 min = strtol(ptr, &end, 10);
169 if (ptr == end)
170 return -EIO;
171
172 ptr = end + 1;
173 if (buf + ret < ptr + 8)
174 return -EIO;
175
176 /* Strip the \n */
177 ptr[buf + ret - ptr - 1] = '\0';
178
179 if (major)
180 *major = (unsigned int) maj;
181 if (minor)
182 *minor = (unsigned int) min;
183 if (git_tag)
184 strncpy(git_tag, ptr, 8);
185 return 0;
186}
Paul Cercueil6a785882015-11-30 16:36:19 +0100187
188int iiod_client_get_trigger(struct iiod_client *client, int desc,
189 const struct iio_device *dev, const struct iio_device **trigger)
190{
Paul Cercueil6a785882015-11-30 16:36:19 +0100191 const struct iio_context *ctx = iio_device_get_context(dev);
192 unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
193 char buf[1024];
194 unsigned int name_len;
195 int ret;
196
197 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", iio_device_get_id(dev));
198
199 iio_mutex_lock(client->lock);
200 ret = iiod_client_exec_command(client, desc, buf);
201
202 if (ret == 0)
203 *trigger = NULL;
204 if (ret <= 0)
205 goto out_unlock;
206
Lars-Peter Clausenb3192d82016-01-28 14:25:57 +0100207 if ((unsigned int) ret > sizeof(buf) - 1) {
Paul Cercueil6a785882015-11-30 16:36:19 +0100208 ret = -EIO;
209 goto out_unlock;
210 }
211
212 name_len = ret;
213
Lars-Peter Clausen5bfba432016-02-03 15:24:08 +0100214 ret = (int) iiod_client_read_all(client, desc, buf, name_len + 1);
Paul Cercueil6a785882015-11-30 16:36:19 +0100215 if (ret < 0)
216 goto out_unlock;
217
218 ret = -ENXIO;
219
220 for (i = 0; i < nb_devices; i++) {
221 struct iio_device *cur = iio_context_get_device(ctx, i);
222
223 if (iio_device_is_trigger(cur)) {
224 const char *name = iio_device_get_name(cur);
225
226 if (!name)
227 continue;
228
229 if (!strncmp(name, buf, name_len)) {
230 *trigger = cur;
Lars-Peter Clausen9decc952016-01-15 12:39:50 +0100231 ret = 0;
232 goto out_unlock;
Paul Cercueil6a785882015-11-30 16:36:19 +0100233 }
234 }
235 }
236
237out_unlock:
238 iio_mutex_unlock(client->lock);
239 return ret;
240}
241
242int iiod_client_set_trigger(struct iiod_client *client, int desc,
243 const struct iio_device *dev, const struct iio_device *trigger)
244{
Paul Cercueil6a785882015-11-30 16:36:19 +0100245 char buf[1024];
246 int ret;
247
248 if (trigger)
249 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
250 iio_device_get_id(dev),
251 iio_device_get_id(trigger));
252 else
253 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n",
254 iio_device_get_id(dev));
255
256 iio_mutex_lock(client->lock);
257 ret = iiod_client_exec_command(client, desc, buf);
258 iio_mutex_unlock(client->lock);
259 return ret;
260}
Paul Cercueile7d4db32015-11-30 16:54:51 +0100261
262int iiod_client_set_kernel_buffers_count(struct iiod_client *client, int desc,
263 const struct iio_device *dev, unsigned int nb_blocks)
264{
265 int ret;
266 char buf[1024];
267
268 snprintf(buf, sizeof(buf), "SET %s BUFFERS_COUNT %u\r\n",
269 iio_device_get_id(dev), nb_blocks);
270
271 iio_mutex_lock(client->lock);
272 ret = iiod_client_exec_command(client, desc, buf);
273 iio_mutex_unlock(client->lock);
274 return ret;
275}
Paul Cercueil408b9672015-11-30 18:39:31 +0100276
Paul Cercueil3ce60382015-12-03 12:28:48 +0100277int iiod_client_set_timeout(struct iiod_client *client,
278 int desc, unsigned int timeout)
279{
280 int ret;
281 char buf[1024];
282
283 snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
284
285 iio_mutex_lock(client->lock);
286 ret = iiod_client_exec_command(client, desc, buf);
287 iio_mutex_unlock(client->lock);
288 return ret;
289}
290
Paul Cercueil408b9672015-11-30 18:39:31 +0100291ssize_t iiod_client_read_attr(struct iiod_client *client, int desc,
292 const struct iio_device *dev, const struct iio_channel *chn,
293 const char *attr, char *dest, size_t len, bool is_debug)
294{
Paul Cercueil408b9672015-11-30 18:39:31 +0100295 const char *id = iio_device_get_id(dev);
296 char buf[1024];
Paul Cercueil58bcbd42015-12-11 11:35:55 +0100297 ssize_t ret;
Paul Cercueil408b9672015-11-30 18:39:31 +0100298
299 if (attr) {
300 if (chn) {
301 if (!iio_channel_find_attr(chn, attr))
302 return -ENOENT;
303 } else if (is_debug) {
304 if (!iio_device_find_debug_attr(dev, attr))
305 return -ENOENT;
306 } else {
307 if (!iio_device_find_attr(dev, attr))
308 return -ENOENT;
309 }
310 }
311
312 if (chn)
313 snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
314 iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
315 iio_channel_get_id(chn), attr ? attr : "");
316 else if (is_debug)
317 snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
318 id, attr ? attr : "");
319 else
320 snprintf(buf, sizeof(buf), "READ %s %s\r\n",
321 id, attr ? attr : "");
322
323 iio_mutex_lock(client->lock);
324
325 ret = (ssize_t) iiod_client_exec_command(client, desc, buf);
326 if (ret < 0)
327 goto out_unlock;
328
329 if ((size_t) ret + 1 > len) {
330 ret = -EIO;
331 goto out_unlock;
332 }
333
334 /* +1: Also read the trailing \n */
335 ret = iiod_client_read_all(client, desc, dest, ret + 1);
336
Paul Cercueil08bb36b2015-12-18 10:51:13 +0100337 if (ret > 0) {
338 /* Discard the trailing \n */
339 ret--;
340
341 /* Replace it with a \0 just in case */
342 dest[ret] = '\0';
343 }
344
Paul Cercueil408b9672015-11-30 18:39:31 +0100345out_unlock:
346 iio_mutex_unlock(client->lock);
347 return ret;
348}
349
350ssize_t iiod_client_write_attr(struct iiod_client *client, int desc,
351 const struct iio_device *dev, const struct iio_channel *chn,
352 const char *attr, const char *src, size_t len, bool is_debug)
353{
354 struct iio_context_pdata *pdata = client->pdata;
355 const struct iiod_client_ops *ops = client->ops;
356 const char *id = iio_device_get_id(dev);
357 char buf[1024];
Paul Cercueil58bcbd42015-12-11 11:35:55 +0100358 ssize_t ret;
Paul Cercueil408b9672015-11-30 18:39:31 +0100359 int resp;
360
361 if (attr) {
362 if (chn) {
363 if (!iio_channel_find_attr(chn, attr))
364 return -ENOENT;
365 } else if (is_debug) {
366 if (!iio_device_find_debug_attr(dev, attr))
367 return -ENOENT;
368 } else {
369 if (!iio_device_find_attr(dev, attr))
370 return -ENOENT;
371 }
372 }
373
374 if (chn)
375 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n", id,
376 iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
377 iio_channel_get_id(chn), attr ? attr : "",
378 (unsigned long) len);
379 else if (is_debug)
380 snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
381 id, attr ? attr : "", (unsigned long) len);
382 else
383 snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
384 id, attr ? attr : "", (unsigned long) len);
385
386 iio_mutex_lock(client->lock);
387 ret = ops->write(pdata, desc, buf, strlen(buf));
388 if (ret < 0)
389 goto out_unlock;
390
391 ret = iiod_client_write_all(client, desc, src, len);
392 if (ret < 0)
393 goto out_unlock;
394
395 ret = iiod_client_read_integer(client, desc, &resp);
396 if (ret < 0)
397 goto out_unlock;
398
399 ret = (ssize_t) resp;
400
401out_unlock:
402 iio_mutex_unlock(client->lock);
403 return ret;
404}
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100405
406struct iio_context * iiod_client_create_context(
407 struct iiod_client *client, int desc)
408{
409 struct iio_context *ctx = NULL;
410 size_t xml_len;
Paul Cercueil221c0dd2016-02-09 15:17:20 +0000411 char *xml;
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100412 int ret;
413
414 iio_mutex_lock(client->lock);
415 ret = iiod_client_exec_command(client, desc, "PRINT\r\n");
416 if (ret < 0)
417 goto out_unlock;
418
419 xml_len = (size_t) ret;
Paul Cercueil221c0dd2016-02-09 15:17:20 +0000420 xml = malloc(xml_len + 1);
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100421 if (!xml) {
422 ret = -ENOMEM;
423 goto out_unlock;
424 }
425
Paul Cercueil221c0dd2016-02-09 15:17:20 +0000426 /* +1: Also read the trailing \n */
427 ret = (int) iiod_client_read_all(client, desc, xml, xml_len + 1);
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100428 if (ret < 0)
429 goto out_free_xml;
430
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100431 ctx = iio_create_xml_context_mem(xml, xml_len);
432 if (!ctx)
433 ret = -errno;
434
435out_free_xml:
436 free(xml);
437out_unlock:
438 iio_mutex_unlock(client->lock);
439 if (!ctx)
440 errno = -ret;
441 return ctx;
442}
Paul Cercueilba870932015-12-01 18:17:57 +0100443
444int iiod_client_open_unlocked(struct iiod_client *client, int desc,
445 const struct iio_device *dev, size_t samples_count, bool cyclic)
446{
447 char buf[1024], *ptr;
448 size_t i;
449
450 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
451 iio_device_get_id(dev), (unsigned long) samples_count);
452 ptr = buf + strlen(buf);
453
454 for (i = dev->words; i > 0; i--, ptr += 8)
455 snprintf(ptr, (ptr - buf) + i * 8, "%08x", dev->mask[i - 1]);
456
457 strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
458
459 return iiod_client_exec_command(client, desc, buf);
460}
461
462int iiod_client_close_unlocked(struct iiod_client *client, int desc,
463 const struct iio_device *dev)
464{
465 char buf[1024];
466
467 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", iio_device_get_id(dev));
468 return iiod_client_exec_command(client, desc, buf);
469}
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100470
471static int iiod_client_read_mask(struct iiod_client *client,
472 int desc, uint32_t *mask, size_t words)
473{
474 size_t i;
475 ssize_t ret;
476 char *buf, *ptr;
477
478 buf = malloc(words * 8 + 1);
479 if (!buf)
480 return -ENOMEM;
481
482 ret = iiod_client_read_all(client, desc, buf, words * 8 + 1);
483 if (ret < 0)
484 goto out_buf_free;
485 else
486 ret = 0;
487
Lars-Peter Clausenabd2c102016-02-22 11:33:32 +0100488 buf[words*8] = '\0';
489
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100490 DEBUG("Reading mask\n");
491
492 for (i = words, ptr = buf; i > 0; i--) {
493 sscanf(ptr, "%08x", &mask[i - 1]);
Paul Cercueil8835bbb2016-04-18 11:56:59 +0200494 DEBUG("mask[%lu] = 0x%08x\n",
495 (unsigned long)(i - 1), mask[i - 1]);
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100496
497 ptr = (char *) ((uintptr_t) ptr + 8);
498 }
499
500out_buf_free:
501 free(buf);
502 return (int) ret;
503}
504
505ssize_t iiod_client_read_unlocked(struct iiod_client *client, int desc,
506 const struct iio_device *dev, void *dst, size_t len,
507 uint32_t *mask, size_t words)
508{
509 unsigned int nb_channels = iio_device_get_channels_count(dev);
510 uintptr_t ptr = (uintptr_t) dst;
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100511 char buf[1024];
512 ssize_t ret, read = 0;
513
514 if (!len || words != (nb_channels + 31) / 32)
515 return -EINVAL;
516
517 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
518 iio_device_get_id(dev), (unsigned long) len);
519
520 ret = iiod_client_write_all(client, desc, buf, strlen(buf));
521 if (ret < 0)
522 return ret;
523
524 do {
525 int to_read;
526
527 ret = iiod_client_read_integer(client, desc, &to_read);
528 if (ret < 0)
529 return ret;
Lars-Peter Clausenc263f8e2016-04-12 15:24:10 +0200530 if (to_read < 0)
531 return (ssize_t) to_read;
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100532 if (!to_read)
533 break;
534
535 if (mask) {
536 ret = iiod_client_read_mask(client, desc, mask, words);
537 if (ret < 0)
538 return ret;
539
540 mask = NULL; /* We read the mask only once */
541 }
542
543 ret = iiod_client_read_all(client, desc, (char *) ptr, to_read);
544 if (ret < 0)
545 return ret;
546
547 ptr += ret;
548 read += ret;
549 len -= ret;
550 } while (len);
551
552 return read;
553}
Paul Cercueil90fd85c2015-12-02 17:57:07 +0100554
555ssize_t iiod_client_write_unlocked(struct iiod_client *client, int desc,
556 const struct iio_device *dev, const void *src, size_t len)
557{
Paul Cercueil90fd85c2015-12-02 17:57:07 +0100558 ssize_t ret;
559 char buf[1024];
560 int val;
561
562 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
563 dev->id, (unsigned long) len);
564
565 ret = iiod_client_write_all(client, desc, buf, strlen(buf));
566 if (ret < 0)
567 return ret;
568
569 ret = iiod_client_read_integer(client, desc, &val);
570 if (ret < 0)
571 return ret;
572 if (val < 0)
573 return (ssize_t) val;
574
575 ret = iiod_client_write_all(client, desc, src, len);
576 if (ret < 0)
577 return ret;
578
579 ret = iiod_client_read_integer(client, desc, &val);
580 if (ret < 0)
581 return ret;
582 if (val < 0)
583 return (ssize_t) val;
584
585 return (ssize_t) len;
586}