Analog Devices / Mbed OS tinyiiod-example

Files at this revision

API Documentation at this revision

Comitter:
adisuciu
Date:
Fri Dec 13 22:21:29 2019 +0000
Commit message:
Initial revision

Changed in this revision

compat.h Show annotated file Show diff for this revision Revisions of this file
example.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
parser.cpp Show annotated file Show diff for this revision Revisions of this file
tinyiiod-private.h Show annotated file Show diff for this revision Revisions of this file
tinyiiod.cpp Show annotated file Show diff for this revision Revisions of this file
tinyiiod.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compat.h	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,70 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2019 Analog Devices, Inc.
+ * Author: Cristian Pop <cristian.pop@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+//#define _USE_STD_INT_TYPES
+#define TINYIIOD_VERSION_MAJOR 0
+#define TINYIIOD_VERSION_MINOR 0
+#define TINYIIOD_VERSION_PATCH 1
+#define TINYIIOD_VERSION_GIT "v0.1"
+#define IIOD_BUFFER_SIZE 0x1000
+
+#define _USE_STD_INT_TYPES
+
+#ifdef _USE_STD_INT_TYPES
+#include <stddef.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+typedef int ssize_t;
+#else // _USE_STD_INT_TYPES
+#if !defined(__ssize_t_defined) && !defined(_SSIZE_T_DEFINED)
+#include <stddef.h>
+typedef long int ssize_t;
+//typedef unsigned long int size_t;
+#define __ssize_t_defined
+#define _SSIZE_T_DEFINED
+#endif
+
+typedef long int32_t;
+typedef unsigned long uint32_t;
+typedef int bool;
+
+#define true 1
+#define false 0
+
+#define NULL (void*)0
+
+#define ENOENT      2   /* No such file or directory */
+#define EIO     5   /* I/O error */
+#define ENODEV      19  /* No such device */
+#define EINVAL      22  /* Invalid argument */
+#define ENOSYS      38  /* Function not implemented */
+
+#define PRIi32      "li"
+# define PRIx32     "x"
+# define PRIu16     "u"
+#endif //_USE_STD_INT_TYPES
+
+#endif /* COMPAT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example.cpp	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,217 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2016 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "mbed.h"
+#include "platform/mbed_thread.h"
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include "tinyiiod.h"
+
+Serial pc(USBTX, USBRX, 115200);
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+
+
+static ssize_t read_data(char *buf, size_t len)
+{
+    // get data from UART
+    for(int i=0;i<len;i++)
+        buf[i]=pc.getc();
+    return len;
+}
+
+static ssize_t write_data(const char *buf, size_t len)
+{
+    // send data over UART
+    for(int i=0;i<len;i++)
+        pc.putc(buf[i]);
+    return len;
+}
+
+static ssize_t read_attr(const char *device, const char *attr,
+                         char *buf, size_t len, bool debug)
+{
+    // dispatcher method for read device attr
+    if (!strcmp(device, "adc") || !strcmp(device, "0")) {
+        if (debug) {
+            if (!strcmp(attr, "direct_reg_access"))
+                return (ssize_t) snprintf(buf, len, "0");
+        } else {
+            if (!strcmp(attr, "sample_rate"))
+                return (ssize_t) snprintf(buf, len, "1000");
+        }
+    }
+
+    return -ENOENT;
+}
+
+static ssize_t write_attr(const char *device, const char *attr,
+                          const char *buf, size_t len, bool debug)
+{
+    // dispatcher method for write device attr
+    return -ENOSYS;
+}
+
+static ssize_t ch_read_attr(const char *device, const char *channel,
+                            bool ch_out, const char *attr, char *buf, size_t len)
+{
+    
+    // dispatcher method for channel read attr
+    int temp;
+    if (!strcmp(device, "adc") || !strcmp(device, "0")) {
+        if (ch_out)
+            return -ENOENT;
+
+        if (!strcmp(channel, "voltage0")) {
+            if (!strcmp(attr, "scale"))
+                return (ssize_t) snprintf(buf, len, "0.033");
+            else if (!strcmp(attr, "led"))
+            {
+                temp=led1;
+                return (ssize_t) snprintf(buf, len, "%d",temp);
+                }
+                
+        } else if (!strcmp(channel, "voltage1")) {
+            if (!strcmp(attr, "scale"))
+                return (ssize_t) snprintf(buf, len, "0.033");
+            else if (!strcmp(attr, "led2"))
+                {temp=led2;
+                return (ssize_t) snprintf(buf, len, "%d",temp);
+                    }
+        }
+    }
+
+    return -ENOENT;
+}
+
+static ssize_t ch_write_attr(const char *device, const char *channel,
+                             bool ch_out, const char *attr, const char *buf, size_t len)
+{
+    // dispatcher method for write channel attribute
+    ssize_t retval;
+    int temp;
+    if (!strcmp(device, "adc") || !strcmp(device, "0")) {
+        if (ch_out)
+            return -ENOENT;
+
+        if (!strcmp(channel, "voltage0")) {
+            if (!strcmp(attr, "scale"))
+                return -ENOSYS;
+            else if (!strcmp(attr, "led"))
+            {
+            //    return (ssize_t) snprintf(buf, len, "%d",led1);
+                retval = (ssize_t) sscanf(buf,"%d",&temp);
+                led1=temp;
+                return retval;
+            
+            }
+        } else if (!strcmp(channel, "voltage1")) {
+            if (!strcmp(attr, "scale"))
+                return -ENOSYS;
+            else if (!strcmp(attr, "led2"))
+                {
+                    retval = (ssize_t) sscanf(buf,"%d",&temp);
+                led2=temp;
+                return retval;
+                    }
+        }
+    }
+    return -ENOSYS;
+}
+
+// XML describes the IIO context hierarchy
+static const char * const xml =
+    "<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE context [<!ELEMENT context "
+    "(device)*><!ELEMENT device (channel | attribute | debug-attribute)*><!ELEMENT "
+    "channel (scan-element?, attribute*)><!ELEMENT attribute EMPTY><!ELEMENT "
+    "scan-element EMPTY><!ELEMENT debug-attribute EMPTY><!ATTLIST context name "
+    "CDATA #REQUIRED description CDATA #IMPLIED><!ATTLIST device id CDATA "
+    "#REQUIRED name CDATA #IMPLIED><!ATTLIST channel id CDATA #REQUIRED type "
+    "(input|output) #REQUIRED name CDATA #IMPLIED><!ATTLIST scan-element index "
+    "CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED><!ATTLIST "
+    "attribute name CDATA #REQUIRED filename CDATA #IMPLIED><!ATTLIST "
+    "debug-attribute name CDATA #REQUIRED>]><context name=\"tiny\" "
+    "description=\"Tiny IIOD\" >"
+    "<device id=\"0\" name=\"adc\" >"
+    "<channel id=\"voltage0\" type=\"input\" >"
+    "<attribute name=\"scale\" /><attribute name=\"led\" /></channel>"
+    "<channel id=\"voltage1\" type=\"input\" >"
+    "<attribute name=\"scale\" /><attribute name=\"led2\" /></channel>"
+    "<attribute name=\"sample_rate\" />"
+    "<debug-attribute name=\"direct_reg_access\" />"
+    "</device></context>";
+
+static ssize_t get_xml(char **outxml)
+{
+
+    *outxml = (char*)calloc(1, strlen(xml) + 1);
+    if (!(*outxml))
+        return -ENOMEM;
+    memcpy(*outxml, xml, strlen(xml));
+
+    return 0;
+}
+
+struct tinyiiod_ops ops = {
+    .read = read_data,
+    .write = write_data,
+
+    .read_attr = read_attr,
+    .write_attr = write_attr,
+    .ch_read_attr = ch_read_attr,
+    .ch_write_attr = ch_write_attr,
+    .get_xml = get_xml,
+};
+
+static bool stop;
+
+static void set_handler(int32_t signal_nb, void (*handler)(int32_t))
+{
+    // error handling commented out due to errors with mbed
+    /*
+    struct sigaction sig;
+    sigaction(signal_nb, NULL, &sig);
+    sig.sa_handler = handler;
+    sigaction(signal_nb, &sig, NULL);*/
+}
+
+static void quit_all(int32_t sig)
+{
+    stop = true;
+}
+
+int32_t main(void)
+{
+    struct tinyiiod *iiod = tinyiiod_create(&ops);
+    led1=1;
+
+    // error handling commented out
+    /*set_handler(SIGHUP, &quit_all);
+    set_handler(SIGPIPE, &quit_all);
+    set_handler(SIGINT, &quit_all);
+    set_handler(SIGSEGV, &quit_all);
+    set_handler(SIGTERM, &quit_all);*/
+
+    while (!stop)
+        tinyiiod_read_command(iiod);
+
+    tinyiiod_destroy(iiod);
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#3a57ec7401a77b8b98f6356a1498cb154229483f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.cpp	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,213 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2016 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "tinyiiod-private.h"
+
+#include "compat.h"
+
+static int32_t parse_rw_string(struct tinyiiod *iiod, char *str, bool write)
+{
+    char *device, *channel, *attr, *ptr;
+    bool is_channel = false, output = false, debug = false;
+    long bytes;
+
+    ptr = strchr(str, ' ');
+    if (!ptr)
+        return -EINVAL;
+
+    *ptr = '\0';
+    device = str;
+    str = ptr + 1;
+
+    if (!strncmp(str, "INPUT ", sizeof("INPUT ") - 1)) {
+        is_channel = true;
+        str += sizeof("INPUT ") - 1;
+    } else if (!strncmp(str, "OUTPUT ", sizeof("OUTPUT ") - 1)) {
+        is_channel = true;
+        output = true;
+        str += sizeof("OUTPUT ") - 1;
+    } else if (!strncmp(str, "DEBUG ", sizeof("DEBUG ") - 1)) {
+        debug = true;
+        str += sizeof("DEBUG ") - 1;
+    }
+
+    if (is_channel) {
+        ptr = strchr(str, ' ');
+        if (!ptr)
+            return -EINVAL;
+
+        *ptr = '\0';
+        channel = str;
+        str = ptr + 1;
+    } else {
+        channel = NULL;
+    }
+
+    ptr = strchr(str, ' ');
+    if ((!!ptr) ^ write)
+        return -EINVAL;
+
+    attr = str;
+
+    if (write) {
+        *ptr = '\0';
+        str = ptr + 1;
+    } else {
+        tinyiiod_do_read_attr(iiod, device, channel,
+                      output, attr, debug);
+        return 0;
+    }
+
+    bytes = strtol(str, &ptr, 10);
+    if (str == ptr || bytes < 0)
+        return -EINVAL;
+
+    tinyiiod_do_write_attr(iiod, device, channel,
+                   output, attr, (size_t) bytes, debug);
+
+    return 0;
+}
+
+static int32_t parse_open_string(struct tinyiiod *iiod, char *str)
+{
+    char *device, *ptr;
+    long samples_count;
+    uint32_t mask = 0;
+
+    ptr = strchr(str, ' ');
+    if (!ptr)
+        return -EINVAL;
+
+    *ptr = '\0';
+    device = str;
+    str = ptr + 1;
+
+    samples_count = strtol(str, &ptr, 10);
+    if (str == ptr || *ptr != ' ' || samples_count < 0)
+        return -EINVAL;
+
+    str = ptr + 1;
+
+    mask = strtoul(str, NULL, 16);
+
+    tinyiiod_do_open(iiod, device, (size_t) samples_count, mask);
+
+    return 0;
+}
+
+static int32_t parse_timeout_string(struct tinyiiod *iiod, char *str)
+{
+    uint32_t timeout = strtoul(str, NULL, 10);
+
+    return tinyiiod_set_timeout(iiod, timeout);
+}
+
+static int32_t parse_writebuf_string(struct tinyiiod *iiod, char *str)
+{
+    char *device, *ptr;
+    long bytes_count;
+
+    ptr = strchr(str, ' ');
+    if (!ptr)
+        return -EINVAL;
+
+    *ptr = '\0';
+    device = str;
+    str = ptr + 1;
+
+    bytes_count = strtol(str, &ptr, 10);
+    if (str == ptr || *ptr != '\0' || bytes_count < 0)
+        return -EINVAL;
+
+    return tinyiiod_do_writebuf(iiod, device, (size_t) bytes_count);
+}
+
+static int32_t parse_readbuf_string(struct tinyiiod *iiod, char *str)
+{
+    char *device, *ptr;
+    long bytes_count;
+
+    ptr = strchr(str, ' ');
+    if (!ptr)
+        return -EINVAL;
+
+    *ptr = '\0';
+    device = str;
+    str = ptr + 1;
+
+    bytes_count = strtol(str, &ptr, 10);
+    if (str == ptr || *ptr != '\0' || bytes_count < 0)
+        return -EINVAL;
+
+    return tinyiiod_do_readbuf(iiod, device, (size_t) bytes_count);
+}
+
+int32_t tinyiiod_parse_string(struct tinyiiod *iiod, char *str)
+{
+    while (*str == '\n' || *str == '\r')
+        str++;
+
+    if (str[0] == '\0')
+        return 0;
+
+    if (!strncmp(str, "VERSION", sizeof("VERSION"))) {
+        char buf[32];
+
+        snprintf(buf, sizeof(buf), "%"PRIu16".%"PRIu16".%-7.7s\n",
+             TINYIIOD_VERSION_MAJOR,
+             TINYIIOD_VERSION_MINOR,
+             TINYIIOD_VERSION_GIT);
+        tinyiiod_write_string(iiod, buf);
+        return 0;
+    }
+
+    if (!strncmp(str, "PRINT", sizeof("PRINT"))) {
+        tinyiiod_write_xml(iiod);
+        return 0;
+    }
+
+    if (!strncmp(str, "READ ", sizeof("READ ") - 1))
+        return parse_rw_string(iiod, str + sizeof("READ ") - 1, false);
+
+    if (!strncmp(str, "WRITE ", sizeof("WRITE ") -1))
+        return parse_rw_string(iiod, str + sizeof("WRITE ") - 1, true);
+
+    if (!strncmp(str, "OPEN ", sizeof("OPEN ") -1))
+        return parse_open_string(iiod, str + sizeof("OPEN ") - 1);
+
+    if (!strncmp(str, "CLOSE ", sizeof("CLOSE ") -1)) {
+        tinyiiod_do_close(iiod, str + sizeof("CLOSE ") - 1);
+        return 0;
+    }
+
+    if (!strncmp(str, "READBUF ", sizeof("READBUF ") -1))
+        return parse_readbuf_string(iiod, str + sizeof("READBUF ") - 1);
+
+    if (!strncmp(str, "TIMEOUT ", sizeof("TIMEOUT ") - 1))
+        return parse_timeout_string(iiod, str + sizeof("TIMEOUT ") - 1);
+
+    if (!strncmp(str, "WRITEBUF ", sizeof("WRITEBUF ") -1))
+        return parse_writebuf_string(iiod, str + sizeof("WRITEBUF ") - 1);
+
+    if (!strncmp(str, "EXIT", sizeof("EXIT") - 1))
+        return tinyiiod_do_close_instance(iiod);
+
+    if (!strncmp(str, "GETTRIG", sizeof("GETTRIG") - 1))
+        return tinyiiod_write_value(iiod, -ENODEV);
+
+    return -EINVAL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tinyiiod-private.h	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,59 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2016 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef TINYIIOD_PRIVATE_H
+#define TINYIIOD_PRIVATE_H
+
+#include "tinyiiod.h"
+
+char tinyiiod_read_char(struct tinyiiod *iiod);
+ssize_t tinyiiod_read(struct tinyiiod *iiod, char *buf, size_t len);
+ssize_t tinyiiod_read_line(struct tinyiiod *iiod, char *buf, size_t len);
+
+ssize_t tinyiiod_write_char(struct tinyiiod *iiod, char c);
+ssize_t tinyiiod_write(struct tinyiiod *iiod, const char *data, size_t len);
+ssize_t tinyiiod_write_string(struct tinyiiod *iiod, const char *str);
+ssize_t tinyiiod_write_value(struct tinyiiod *iiod, int32_t value);
+
+void tinyiiod_write_xml(struct tinyiiod *iiod);
+
+void tinyiiod_do_read_attr(struct tinyiiod *iiod, const char *device,
+               const char *channel, bool ch_out, const char *attr, bool debug);
+
+void tinyiiod_do_write_attr(struct tinyiiod *iiod, const char *device,
+                const char *channel, bool ch_out, const char *attr,
+                size_t bytes, bool debug);
+
+void tinyiiod_do_open(struct tinyiiod *iiod, const char *device,
+              size_t sample_size, uint32_t mask);
+void tinyiiod_do_close(struct tinyiiod *iiod, const char *device);
+
+int32_t tinyiiod_do_open_instance(struct tinyiiod *iiod);
+
+int32_t tinyiiod_do_close_instance(struct tinyiiod *iiod);
+
+int32_t tinyiiod_do_readbuf(struct tinyiiod *iiod,
+                const char *device, size_t bytes_count);
+
+int32_t tinyiiod_do_writebuf(struct tinyiiod *iiod, const char *device,
+                 size_t bytes_count);
+
+int32_t tinyiiod_parse_string(struct tinyiiod *iiod, char *str);
+
+int32_t tinyiiod_set_timeout(struct tinyiiod *iiod, uint32_t timeout);
+
+#endif /* TINYIIOD_PRIVATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tinyiiod.cpp	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,276 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2016 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "tinyiiod-private.h"
+
+#include "compat.h"
+
+struct tinyiiod {
+    struct tinyiiod_ops *ops;
+    char *buf;
+};
+
+struct tinyiiod * tinyiiod_create(struct tinyiiod_ops *ops)
+{
+    struct tinyiiod *iiod =(struct tinyiiod*) malloc(sizeof(*iiod));
+
+    if (!iiod)
+        return NULL;
+
+    iiod->buf = (char*)malloc(IIOD_BUFFER_SIZE);
+    iiod->ops = ops;
+
+    return iiod;
+}
+
+void tinyiiod_destroy(struct tinyiiod *iiod)
+{
+    free(iiod->ops);
+    free(iiod->buf);
+    free(iiod);
+}
+
+int32_t tinyiiod_read_command(struct tinyiiod *iiod)
+{
+    char buf[128];
+    int32_t ret;
+
+    ret = tinyiiod_read_line(iiod, buf, sizeof(buf));
+    if (ret < 0)
+        return ret;
+
+    ret = tinyiiod_parse_string(iiod, buf);
+    if (ret < 0)
+        tinyiiod_write_value(iiod, ret);
+
+    return ret;
+}
+
+char tinyiiod_read_char(struct tinyiiod *iiod)
+{
+    char c;
+
+    iiod->ops->read(&c, 1);
+    return c;
+}
+
+ssize_t tinyiiod_read(struct tinyiiod *iiod, char *buf, size_t len)
+{
+    return iiod->ops->read(buf, len);
+}
+
+ssize_t tinyiiod_read_line(struct tinyiiod *iiod, char *buf, size_t len)
+{
+    uint32_t i;
+    bool found = false;
+
+    if (iiod->ops->read_line)
+        return iiod->ops->read_line(buf, len);
+
+    for (i = 0; i < len - 1; i++) {
+        buf[i] = tinyiiod_read_char(iiod);
+
+        if (buf[i] != '\n')
+            found = true;
+        else if (found)
+            break;
+    }
+
+    if (!found || i == len - 1) {
+        /* No \n found -> garbage data */
+        return -EIO;
+    }
+
+    buf[i - 1] = '\0';
+
+    return i;
+}
+
+ssize_t tinyiiod_write_char(struct tinyiiod *iiod, char c)
+{
+    return iiod->ops->write(&c, 1);
+}
+
+ssize_t tinyiiod_write(struct tinyiiod *iiod, const char *data, size_t len)
+{
+    return iiod->ops->write(data, len);
+}
+
+ssize_t tinyiiod_write_string(struct tinyiiod *iiod, const char *str)
+{
+    return tinyiiod_write(iiod, str, strlen(str));
+}
+
+ssize_t tinyiiod_write_value(struct tinyiiod *iiod, int32_t value)
+{
+    char buf[16];
+
+    snprintf(buf, sizeof(buf), "%"PRIi32"\n", value);
+    return tinyiiod_write_string(iiod, buf);
+}
+
+void tinyiiod_write_xml(struct tinyiiod *iiod)
+{
+    char *xml;
+    iiod->ops->get_xml(&xml);
+    size_t len = strlen(xml);
+
+    tinyiiod_write_value(iiod, len);
+    tinyiiod_write(iiod, xml, len);
+    tinyiiod_write_char(iiod, '\n');
+    free(xml);
+}
+
+void tinyiiod_do_read_attr(struct tinyiiod *iiod, const char *device,
+               const char *channel, bool ch_out, const char *attr, bool debug)
+{
+    ssize_t ret;
+
+    if (channel)
+        ret = iiod->ops->ch_read_attr(device, channel,
+                          ch_out, attr, iiod->buf, IIOD_BUFFER_SIZE);
+    else
+        ret = iiod->ops->read_attr(device, attr,
+                       iiod->buf, IIOD_BUFFER_SIZE, debug);
+
+    tinyiiod_write_value(iiod, (int32_t) ret);
+    if (ret > 0) {
+        iiod->buf[ret] = '\n';
+        tinyiiod_write(iiod, iiod->buf, (size_t) ret + 1);
+    }
+}
+
+void tinyiiod_do_write_attr(struct tinyiiod *iiod, const char *device,
+                const char *channel, bool ch_out, const char *attr,
+                size_t bytes, bool debug)
+{
+    ssize_t ret;
+
+    if (bytes > IIOD_BUFFER_SIZE - 1)
+        bytes = IIOD_BUFFER_SIZE - 1;
+
+    tinyiiod_read(iiod, iiod->buf, bytes);
+    iiod->buf[bytes] = '\0';
+
+    if (channel)
+        ret = iiod->ops->ch_write_attr(device, channel, ch_out,
+                           attr, iiod->buf, bytes);
+    else
+        ret = iiod->ops->write_attr(device, attr, iiod->buf, bytes, debug);
+
+    tinyiiod_write_value(iiod, (int32_t) ret);
+}
+
+void tinyiiod_do_open(struct tinyiiod *iiod, const char *device,
+              size_t sample_size, uint32_t mask)
+{
+    int32_t ret = iiod->ops->open(device, sample_size, mask);
+    tinyiiod_write_value(iiod, ret);
+}
+
+void tinyiiod_do_close(struct tinyiiod *iiod, const char *device)
+{
+    int32_t ret = iiod->ops->close(device);
+    tinyiiod_write_value(iiod, ret);
+}
+
+int32_t tinyiiod_do_open_instance(struct tinyiiod *iiod)
+{
+    return iiod->ops->open_instance();
+}
+
+int32_t tinyiiod_do_close_instance(struct tinyiiod *iiod)
+{
+    return iiod->ops->close_instance();
+}
+
+int32_t tinyiiod_do_writebuf(struct tinyiiod *iiod,
+                 const char *device, size_t bytes_count)
+{
+    size_t bytes, offset = 0, total_bytes = bytes_count;
+    char buf[256];
+    int32_t ret;
+
+    tinyiiod_write_value(iiod, bytes_count);
+    while (bytes_count) {
+        bytes = bytes_count > sizeof(buf) ? sizeof(buf) : bytes_count;
+        ret = tinyiiod_read(iiod, buf, bytes);
+        if (ret > 0) {
+            ret = iiod->ops->write_data(device, buf, offset, ret);
+            offset += ret;
+            if (ret < 0)
+                return ret;
+            bytes_count -= ret;
+        } else
+            return ret;
+    }
+    if (iiod->ops->transfer_mem_to_dev)
+        ret = iiod->ops->transfer_mem_to_dev(device, total_bytes);
+    tinyiiod_write_value(iiod, (int) total_bytes);
+
+    return ret;
+}
+
+int32_t tinyiiod_do_readbuf(struct tinyiiod *iiod,
+                const char *device, size_t bytes_count)
+{
+    int32_t ret;
+    char buf[256];
+    uint32_t mask;
+    bool print_mask = true;
+    size_t offset = 0;
+
+    ret = iiod->ops->get_mask(device, &mask);
+    if (ret < 0) {
+        return ret;
+    }
+    if (iiod->ops->transfer_dev_to_mem)
+        ret = iiod->ops->transfer_dev_to_mem(device, bytes_count);
+    while (bytes_count) {
+        size_t bytes = bytes_count > sizeof(buf) ? sizeof(buf) : bytes_count;
+
+        ret = (int) iiod->ops->read_data(device, buf, offset, bytes);
+        offset += bytes;
+        tinyiiod_write_value(iiod, ret);
+        if (ret < 0)
+            return ret;
+
+        if (print_mask) {
+            char buf_mask[10];
+
+            snprintf(buf_mask, sizeof(buf_mask), "%08"PRIx32"\n", mask);
+            tinyiiod_write_string(iiod, buf_mask);
+            print_mask = false;
+        }
+
+        tinyiiod_write(iiod, buf, (size_t) ret);
+        bytes_count -= (size_t) ret;
+    }
+
+    return ret;
+}
+
+int32_t tinyiiod_set_timeout(struct tinyiiod *iiod, uint32_t timeout)
+{
+    int32_t ret = 0;
+
+    if (iiod->ops->set_timeout)
+        ret = iiod->ops->set_timeout(timeout);
+    tinyiiod_write_value(iiod, ret);
+
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tinyiiod.h	Fri Dec 13 22:21:29 2019 +0000
@@ -0,0 +1,70 @@
+/*
+ * libtinyiiod - Tiny IIO Daemon Library
+ *
+ * Copyright (C) 2016 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef TINYIIOD_H
+#define TINYIIOD_H
+
+#include "compat.h"
+
+struct tinyiiod;
+
+struct tinyiiod_ops {
+    /* Read from the input stream */
+    ssize_t (*read)(char *buf, size_t len);
+
+    /* Write to the output stream */
+    ssize_t (*write)(const char *buf, size_t len);
+    ssize_t (*read_line)(char *buf, size_t len);
+
+    ssize_t (*open_instance)();
+
+    ssize_t (*close_instance)();
+
+    ssize_t (*read_attr)(const char *device, const char *attr,
+                 char *buf, size_t len, bool debug);
+    ssize_t (*write_attr)(const char *device, const char *attr,
+                  const char *buf, size_t len, bool debug);
+
+    ssize_t (*ch_read_attr)(const char *device, const char *channel,
+                bool ch_out, const char *attr, char *buf, size_t len);
+    ssize_t (*ch_write_attr)(const char *device, const char *channel,
+                 bool ch_out, const char *attr,
+                 const char *buf, size_t len);
+
+    int32_t (*open)(const char *device, size_t sample_size, uint32_t mask);
+    int32_t (*close)(const char *device);
+
+    ssize_t (*transfer_dev_to_mem)(const char *device, size_t bytes_count);
+    ssize_t (*read_data)(const char *device, char *buf, size_t offset,
+                 size_t bytes_count);
+
+    ssize_t (*transfer_mem_to_dev)(const char *device, size_t bytes_count);
+    ssize_t (*write_data)(const char *device, const char *buf, size_t offset,
+                  size_t bytes_count);
+
+    int32_t (*get_mask)(const char *device, uint32_t *mask);
+
+    int32_t (*set_timeout)(uint32_t timeout);
+
+    ssize_t (*get_xml)(char **outxml);
+};
+
+struct tinyiiod * tinyiiod_create(struct tinyiiod_ops *ops);
+void tinyiiod_destroy(struct tinyiiod *iiod);
+int32_t tinyiiod_read_command(struct tinyiiod *iiod);
+
+#endif /* TINYIIOD_H */