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