{"action":"created","comment":{"url":"https://api.github.com/repos/solettaproject/soletta/pulls/comments/36111195","id":36111195,"diff_hunk":"@@ -0,0 +1,990 @@\n+#include <ctype.h>\n+#include <dirent.h>\n+#include <errno.h>\n+#include <fcntl.h>\n+#include <limits.h>\n+#include <stdio.h>\n+#include <sys/stat.h>\n+#include <sys/types.h>\n+#include <unistd.h>\n+\n+#include <sol-log.h>\n+#include <sol-mainloop.h>\n+#include <sol-str-slice.h>\n+#include <sol-util.h>\n+#include <sol-util-linux.h>\n+#include <sol-vector.h>\n+\n+#include \"sol-iio.h\"\n+\n+struct sol_iio_device {\n+    char *trigger_name;\n+    sol_iio_reader_cb reader_cb;\n+    void *reader_cb_data;\n+    struct sol_fd *fd_handler;\n+    struct sol_ptr_vector channels;\n+    int device_id;\n+    int trigger_id;\n+    int fd;\n+    bool buffer_enabled : 1;\n+    bool manual_triggering : 1;\n+};\n+\n+struct sol_iio_channel {\n+    struct sol_iio_device *device;\n+    char *name;\n+    double scale;\n+    int index;\n+    int offset;\n+\n+    int storagebits;\n+    int bits;\n+    int shift;\n+    int offset_in_buffer;\n+\n+    bool little_endian : 1;\n+    bool is_signed : 1;\n+};\n+\n+struct sol_iio_buffer {\n+    size_t size;\n+    uint8_t *data;\n+};\n+\n+#define DEVICE_PATH \"/dev/iio:device%d\"\n+#define SYSFS_DEVICES_PATH \"/sys/bus/iio/devices\"\n+#define BUFFER_ENABLE_DEVICE_PATH \"/sys/bus/iio/devices/iio:device%d/buffer/enable\"\n+#define BUFFER_LENGHT_DEVICE_PATH \"/sys/bus/iio/devices/iio:device%d/buffer/length\"\n+#define CURRENT_TRIGGER_DEVICE_PATH \"/sys/bus/iio/devices/iio:device%d/trigger/current_trigger\"\n+\n+#define SYSFS_TRIGGER_NOW_PATH \"/sys/bus/iio/devices/%s/trigger_now\"\n+#define SYSFS_TRIGGER_NOW_BY_ID_PATH \"/sys/bus/iio/devices/trigger%d/trigger_now\"\n+#define SYSFS_TRIGGER_NAME_PATH \"/sys/bus/iio/devices/%s/name\"\n+#define SYSFS_TRIGGER_SYSFS_ADD_TRIGGER \"/sys/bus/iio/devices/iio_sysfs_trigger/add_trigger\"\n+#define SYSFS_TRIGGER_SYSFS_PATH \"/sys/bus/iio/devices/iio_sysfs_trigger\"\n+\n+#define CHANNEL_RAW_PATH \"/sys/bus/iio/devices/iio:device%d/%s_raw\"\n+#define CHANNEL_OFFSET_PATH \"/sys/bus/iio/devices/iio:device%d/%s_offset\"\n+#define CHANNEL_SCALE_PATH \"/sys/bus/iio/devices/iio:device%d/%s_scale\"\n+\n+#define CHANNEL_SCAN_ENABLE_PATH \"/sys/bus/iio/devices/iio:device%d/scan_elements/%s_en\"\n+#define CHANNEL_SCAN_INDEX_PATH \"/sys/bus/iio/devices/iio:device%d/scan_elements/%s_index\"\n+#define CHANNEL_SCAN_TYPE_PATH \"/sys/bus/iio/devices/iio:device%d/scan_elements/%s_type\"\n+\n+#define SAMPLING_FREQUENCY_DEVICE_PATH \"/sys/bus/iio/devices/iio:device%d/sampling_frequency\"\n+#define SAMPLING_FREQUENCY_BUFFER_PATH \"/sys/bus/iio/devices/iio:device%d/buffer/sampling_frequency\"\n+#define SAMPLING_FREQUENCY_TRIGGER_PATH \"/sys/bus/iio/devices/trigger%d/sampling_frequency\"\n+\n+static bool\n+craft_filename_path(char *path, size_t size, const char *base, ...)\n+{\n+    va_list args;\n+    int len;\n+\n+    va_start(args, base);\n+    len = vsnprintf(path, size, base, args);\n+    va_end(args);\n+\n+    return len >= 0 && len <= PATH_MAX;\n+}\n+\n+static bool\n+write_file(const char *path, const char *format, ...)\n+{\n+    va_list args;\n+    char *content;\n+    int fd;\n+    size_t len;\n+    bool result = true;\n+\n+    va_start(args, format);\n+    vasprintf(&content, format, args);\n+    va_end(args);\n+\n+    fd = open(path, O_WRONLY | O_CLOEXEC);\n+    if (fd < 0)\n+        result = false;\n+\n+    if (result) {\n+        len = strlen(content);\n+        result = write(fd, content, len) == (ssize_t)len;\n+    }\n+\n+    free(content);\n+    close(fd);\n+\n+    return result;\n+}\n+\n+static bool\n+check_trigger_now_file(const char *trigger_dir)\n+{\n+    int len;\n+    char path[PATH_MAX + 1];\n+    struct stat st;\n+\n+    len = snprintf(path, sizeof(path), SYSFS_TRIGGER_NOW_PATH, trigger_dir);\n+\n+    // TODO check permissions of file trigger_now too, not only existence\n+    return len > 0 && len <= PATH_MAX && !stat(path, &st);\n+}\n+\n+static bool\n+check_trigger_name(const char *trigger_dir, const char *trigger_name)\n+{\n+    char path[PATH_MAX + 1];\n+    char *name;\n+    int len;\n+    bool result;\n+\n+    len = snprintf(path, sizeof(path), SYSFS_TRIGGER_NAME_PATH, trigger_dir);\n+    if (len < 0 || len > PATH_MAX) {\n+        SOL_WRN(\"Could not open IIO trigger (%s) name on sysfs\", trigger_dir);\n+        return false;\n+    }\n+\n+    len = sol_util_read_file(path, \"%ms\", &name);\n+    if (len < 0) {\n+        SOL_WRN(\"Could not read IIO trigger (%s) name on sysfs\", trigger_dir);\n+        return false;\n+    }\n+\n+    result = streq(trigger_name, name);\n+    free(name);\n+\n+    return result;\n+}\n+\n+static bool\n+check_manual_triggering(struct sol_iio_device *device)\n+{\n+    DIR *dir;\n+    const struct dirent *ent;\n+\n+    /* The only way I've found to relact trigger name and trigger is\n+     * by opening all triggers on /sys/bus/iio/devices\n+     * and checking name by name =/ */\n+\n+    dir = opendir(SYSFS_DEVICES_PATH);\n+    if (!dir) {\n+        SOL_WRN(\"No IIO devices available\");\n+        return false;\n+    }\n+\n+    while (ent = readdir(dir), ent != NULL) {\n+        if (strstr(ent->d_name, \"trigger\") == ent->d_name) {\n+            if (check_trigger_name(ent->d_name, device->trigger_name)) {\n+                device->manual_triggering = check_trigger_now_file(ent->d_name);\n+                /* triggers dirs are of the form triggerX, so here we save X */\n+                device->trigger_id = atoi(ent->d_name + strlen(\"trigger\"));\n+                return true;\n+            }\n+        }\n+    }\n+\n+    return false;\n+}\n+\n+static bool\n+set_current_trigger(struct sol_iio_device *device, const char *trigger_name)\n+{\n+    char path[PATH_MAX + 1];\n+    int len;\n+\n+    len = snprintf(path, sizeof(path), CURRENT_TRIGGER_DEVICE_PATH, device->device_id);\n+    if (len < 0 || len > PATH_MAX) {\n+        SOL_WRN(\"Could not open device current_trigger file\");\n+        return false;\n+    }\n+\n+    if (!write_file(path, \"%s\", trigger_name)) {\n+        SOL_WRN(\"Could not write to device current_trigger file\");\n+        return false;\n+    }\n+\n+    return true;\n+}\n+\n+static bool\n+create_sysfs_trigger(struct sol_iio_device *device)\n+{\n+    int len, i;\n+    struct stat st;\n+    char *trigger_name;\n+    bool result = false;\n+\n+    /* First, check if 'iio_sysfs_trigger' is available */\n+    if (stat(SYSFS_TRIGGER_SYSFS_ADD_TRIGGER, &st)) {\n+        SOL_WRN(\"No 'iio_sysfs_tigger' under '/sys/bus/iio/devices'.\"\n+            \" Missing 'modprobe iio-trig-sysfs'?\");\n+        return false;\n+    }\n+\n+    /* TODO check available trigger indice instead of using a random one */\n+    /* Create new trigger */\n+    i = rand();\n+    if (!write_file(SYSFS_TRIGGER_SYSFS_ADD_TRIGGER, \"%d\", i))\n+        goto error;\n+\n+    /* Set device current trigger */\n+    len = asprintf(&trigger_name, \"sysfstrig%d\", i);\n+    if (len < 0)\n+        goto error;\n+    result = set_current_trigger(device, trigger_name);\n+\n+    if (result)\n+        device->trigger_name = strdup(trigger_name);\n+\n+    free(trigger_name);\n+\n+    return result;\n+\n+error:\n+    SOL_WRN(\"Could not create sysfs trigger.\");\n+\n+    return false;\n+}\n+\n+static bool\n+check_trigger(struct sol_iio_device *device)\n+{\n+    char path[PATH_MAX + 1];\n+    char *name = NULL;\n+    int len;\n+\n+    len = snprintf(path, sizeof(path), CURRENT_TRIGGER_DEVICE_PATH, device->device_id);\n+    if (len < 0 || len > PATH_MAX) {\n+        SOL_WRN(\"Could not open IIO device%d trigger on sysfs\", device->device_id);\n+        return false;\n+    }\n+\n+    len = sol_util_read_file(path, \"%ms\", &name);\n+    if (len < 0) {\n+        SOL_INF(\"No current trigger for iio:device%d. Creating a sysfs one.\",\n+            device->device_id);\n+        if (!create_sysfs_trigger(device))\n+            return false;\n+    } else\n+        device->trigger_name = name;\n+\n+    return check_manual_triggering(device);\n+}\n+\n+static void\n+set_buffer_size(struct sol_iio_device *device, int buffer_size)\n+{\n+    char path[PATH_MAX + 1];\n+\n+    if (craft_filename_path(path, sizeof(path), BUFFER_LENGHT_DEVICE_PATH, device->device_id)) {\n+        SOL_WRN(\"Could not set IIO device buffer size\");\n+        return;\n+    }\n+\n+    if (!write_file(path, \"%d\", buffer_size)) {\n+        SOL_WRN(\"Could not set IIO device buffer size\");\n+    }\n+\n+    return;\n+}\n+\n+static bool\n+set_buffer_enabled(struct sol_iio_device *device, bool enabled)\n+{\n+    char path[PATH_MAX + 1];\n+    int len;\n+\n+    len = snprintf(path, sizeof(path), BUFFER_ENABLE_DEVICE_PATH, device->device_id);\n+    if (len < 0 || len > PATH_MAX)\n+        return false;\n+\n+    if (!write_file(path, \"%d\", enabled))\n+        return false;\n+\n+    return true;\n+}\n+\n+static size_t\n+calc_buffer_size(struct sol_iio_device *device)\n+{\n+    struct sol_iio_channel *channel;\n+    int i;\n+    size_t size = 0;\n+\n+    SOL_PTR_VECTOR_FOREACH_IDX (&device->channels, channel, i) {\n+        size += channel->storagebits;\n+    }\n+\n+    return size / 8;\n+}\n+\n+static bool\n+device_reader_cb(void *data, int fd, unsigned int active_flags)\n+{\n+    struct sol_iio_device *device = data;\n+    bool result = true;\n+    size_t len = calc_buffer_size(device);\n+    uint8_t *buffer = NULL;\n+\n+    buffer = calloc(1, len);\n+    if (!buffer) {\n+        SOL_WRN(\"Could not allocate memory for read buffer\");\n+        result = false;\n+    }\n+\n+    if (result && active_flags & (SOL_FD_FLAGS_ERR | SOL_FD_FLAGS_HUP | SOL_FD_FLAGS_NVAL)) {\n+        SOL_WRN(\"Unexpected reading\");\n+        result = false;\n+    }\n+\n+    while (result) {\n+        ssize_t ret;\n+\n+        ret = read(fd, buffer, len);\n+        if (ret < 0) {\n+            if (errno == EINTR)\n+                continue;\n+            else if (errno == EAGAIN || errno == EWOULDBLOCK)\n+                break;\n+            else {\n+                result = false;\n+                break;\n+            }\n+        }\n+\n+        if ((size_t)ret == len) {\n+            if (device->reader_cb) {\n+                struct sol_iio_buffer iio_buffer;\n+\n+                iio_buffer.size = len;\n+                iio_buffer.data = buffer;\n+                device->reader_cb(device, &iio_buffer, device->reader_cb_data);\n+            }\n+        }\n+    }\n+\n+    free(buffer);\n+\n+    return result;\n+}\n+\n+static bool\n+setup_device_reader(struct sol_iio_device *device)\n+{\n+    int len, fd;\n+    char path[PATH_MAX + 1];\n+\n+    len = snprintf(path, sizeof(path), DEVICE_PATH, device->device_id);\n+    if (len < 0 || len > PATH_MAX) {\n+        SOL_WRN(\"Could not open IIO device%d: Device does not exist\", device->device_id);\n+        return false;\n+    }\n+\n+    fd = open(path, O_RDONLY | O_CLOEXEC | O_NONBLOCK);\n+    if (fd < 0) {\n+        SOL_WRN(\"Could not open IIO device%d: Device does not exist\", device->device_id);\n+        return false;\n+    }\n+\n+    device->fd_handler = sol_fd_add(fd, SOL_FD_FLAGS_IN | SOL_FD_FLAGS_PRI | SOL_FD_FLAGS_ERR, device_reader_cb, device);\n+    if (!device->fd_handler) {\n+        SOL_WRN(\"Could not setup reader for device%d\", device->device_id);\n+        close(fd);\n+        return false;\n+    }\n+\n+    device->fd = fd;\n+\n+    return true;\n+}\n+\n+struct sol_iio_device *\n+sol_iio_open(int device_id, int buffer_size, const char *trigger_name)\n+{\n+    int len;\n+    char path[PATH_MAX + 1];\n+    struct stat st;\n+    struct sol_iio_device *device = NULL;\n+\n+    len = snprintf(path, sizeof(path), DEVICE_PATH, device_id);\n+    if (len < 0 || len > PATH_MAX || stat(path, &st)) {\n+        SOL_WRN(\"Could not open IIO device%d: Device does not exist\", device_id);\n+        return NULL;\n+    }\n+\n+    device = calloc(1, sizeof(struct sol_iio_device));\n+    SOL_NULL_CHECK(device, NULL);\n+\n+    device->device_id = device_id;\n+    sol_ptr_vector_init(&device->channels);\n+    device->fd = -1;\n+\n+    if (buffer_size > -1) {\n+        if (trigger_name && trigger_name[0] != '\\0') {\n+            if (!set_current_trigger(device, trigger_name)) {\n+                SOL_WRN(\"Could not set device current trigger\");\n+                goto error;\n+            }\n+        }\n+\n+        if (!check_trigger(device)) {\n+            SOL_WRN(\"No trigger available for device\");\n+            goto error;\n+        }\n+\n+        if (buffer_size != 0)\n+            set_buffer_size(device, buffer_size);\n+\n+        if (!device->manual_triggering) {\n+            SOL_WRN(\"No 'trigger_now' file on device%d current trigger. \"\n+                \"It won't be possible to manually trigger a reading on device\",\n+                device->device_id);\n+        }\n+\n+        if (!setup_device_reader(device)) {\n+            SOL_WRN(\"Could not setup device%d reading\", device->device_id);\n+            goto error;\n+        }\n+        device->buffer_enabled = true;\n+    } else {\n+        /* buffer_size == -1 means that user doesn't want to use the buffer */\n+        device->buffer_enabled = false;\n+        if (!set_buffer_enabled(device, false)) {\n+            SOL_WRN(\"Could not enable buffer for device\");\n+            goto error;\n+        }\n+    }\n+\n+    SOL_DBG(\"iio device created. device%d - buffer_enabled: %d - manual_trigger: %d\"\n+        \" - trigger_name: %s - trigger_id: %d\", device->device_id,\n+        device->buffer_enabled, device->manual_triggering, device->trigger_name,\n+        device->trigger_id);\n+\n+    return device;\n+\n+error:\n+    sol_iio_close(device);\n+\n+    return NULL;\n+}\n+\n+static bool\n+enable_channel_scan(struct sol_iio_channel *channel)\n+{\n+    struct sol_iio_device *device = channel->device;\n+    char path[PATH_MAX + 1];\n+    int current_value;\n+\n+    if (!craft_filename_path(path, sizeof(path), CHANNEL_SCAN_ENABLE_PATH,\n+        device->device_id, channel->name)) {\n+\n+        return false;\n+    }\n+\n+    /* First, check if not already enabled */\n+    sol_util_read_file(path, \"%d\", &current_value);\n+    if (current_value != 1)\n+        return write_file(path, \"%d\", 1);\n+\n+    return true;\n+}\n+\n+static bool\n+read_channel_scan_info(struct sol_iio_channel *channel)\n+{\n+    struct sol_iio_device *device = channel->device;\n+    char path[PATH_MAX + 1];\n+    char *type, *original_type;\n+    int len;\n+    bool crafted;\n+\n+    crafted = craft_filename_path(path, sizeof(path), CHANNEL_SCAN_TYPE_PATH,\n+        device->device_id, channel->name);\n+    if (!crafted || sol_util_read_file(path, \"%ms\", &type) < 0)\n+        return false;\n+\n+    original_type = type;\n+    /* Form of type is [be|le]:[s|u]bits/storagebits[>>shift] */\n+    if (strstr(type, \"be:\")) {\n+        channel->little_endian = false;\n+        type += 3;\n+    } else if (strstr(type, \"le:\")) {\n+        channel->little_endian = true;\n+        type += 3;\n+    } else\n+        channel->little_endian = true;\n+\n+    if (type[0] == 's') {\n+        channel->is_signed = true;\n+        type++;\n+    } else if (type[0] == 'u') {\n+        channel->is_signed = false;\n+        type++;\n+    } else\n+        channel->is_signed = true; /* TODO check if signed is the default */\n+\n+    channel->shift = 0;\n+    len = sscanf(type, \"%d/%d>>%d\", &channel->bits, &channel->storagebits, &channel->shift);\n+\n+    free(original_type);\n+\n+    if (len < 0)\n+        return false;\n+\n+    return true;\n+}\n+\n+/* Some channels are named on the form  <type>[_x|_y|_z]\n+ * This function shall return the name without <x|y|z> components.\n+ * The form <type>[Y][_modifier] is also common (Y is a number), and this function\n+ * remove numbers too, in an attempt to get the 'pure' name.\n+ * TODO there are other esoteric combinations - for them, if we care about,\n+ * we will probably need API calls to get the 'scale' and 'offset' file names */\n+static char *\n+channel_get_pure_name(struct sol_iio_channel *channel)\n+{\n+    size_t channel_name_len, i;\n+    char *channel_pure_name, *channel_name_suffix, *original_channel_pure_name;\n+    bool modified = false;\n+\n+    channel_name_len = strlen(channel->name);\n+    if (channel_name_len > 2) {\n+        channel_name_suffix = channel->name + channel_name_len - 2;\n+        if (streq(channel_name_suffix,  \"_x\") ||\n+            streq(channel_name_suffix,  \"_y\") || streq(channel_name_suffix,  \"_z\")) {\n+\n+            channel_pure_name = malloc(channel_name_len - 1);\n+            strncpy(channel_pure_name, channel->name, channel_name_len - 2);\n+            channel_pure_name[channel_name_len - 2] = '\\0';\n+            return channel_pure_name;\n+        } else {\n+            /* Recreate channel name without Y_ components (Y is a number).\n+             * Idea is 's/[0-9]+//' */\n+            channel_pure_name = calloc(1, channel_name_len + 1);\n+            original_channel_pure_name = channel_pure_name;\n+            for (i = 0; i < channel_name_len; i++) {\n+                if (isalpha(channel->name[i]) || channel->name[i] == '-' || channel->name[i] == '_')\n+                    *channel_pure_name++ = channel->name[i];\n+                else if (isdigit(channel->name[i])) {\n+                    modified = true;\n+                    continue;\n+                }\n+            }\n+            if (modified)\n+                return original_channel_pure_name;\n+            else\n+                free(original_channel_pure_name);\n+        }\n+    }\n+\n+    return NULL;\n+}\n+\n+static void\n+channel_get_scale(struct sol_iio_channel *channel)\n+{\n+    char path[PATH_MAX + 1];\n+    int len;\n+    char *channel_pure_name = NULL;\n+    struct sol_iio_device *device = channel->device;\n+\n+#define GET_SCALE(_name) \\\n+    do { \\\n+        len = snprintf(path, sizeof(path), CHANNEL_SCALE_PATH, device->device_id, \\\n+            _name); \\\n+        if (len > 0 && sol_util_read_file(path, \"%lf\", &channel->scale) > 0) { \\\n+            goto end; \\\n+        } \\\n+    } while (0)\n+\n+    GET_SCALE(channel->name);\n+    /* No scale. If channel has x, y, z or Y component, look for scale file without it */\n+    channel_pure_name = channel_get_pure_name(channel);\n+    GET_SCALE(channel_pure_name);\n+\n+    SOL_INF(\"Could not get scale for channel [%s] in device%d. Assuming 1.0\",\n+        channel->name, device->device_id);\n+    channel->scale = 1.0;\n+\n+#undef GET_SCALE\n+\n+end:\n+    free(channel_pure_name);\n+}\n+\n+static void\n+channel_get_offset(struct sol_iio_channel *channel)\n+{\n+    char path[PATH_MAX + 1];\n+    int len;\n+    char *channel_pure_name = NULL;\n+    struct sol_iio_device *device = channel->device;\n+\n+#define GET_OFFSET(_name) \\\n+    do { \\\n+        len = snprintf(path, sizeof(path), CHANNEL_OFFSET_PATH, device->device_id, \\\n+            _name); \\\n+        if (len > 0 && sol_util_read_file(path, \"%d\", &channel->offset) > 0) { \\\n+            goto end; \\\n+        } \\\n+    } while (0)\n+\n+    GET_OFFSET(channel->name);\n+    /* No scale. If channel has x, y or z component, look for scale file without it */\n+    channel_pure_name = channel_get_pure_name(channel);\n+    GET_OFFSET(channel_pure_name);\n+\n+    SOL_INF(\"Could not get offset for channel [%s] in device%d. Assuming 0\",\n+        channel->name, device->device_id);\n+    channel->offset = 0;\n+\n+#undef GET_OFFSET\n+\n+end:\n+    free(channel_pure_name);\n+}\n+\n+static void\n+iio_del_channel(struct sol_iio_channel *channel)\n+{\n+    free(channel->name);\n+\n+    free(channel);\n+}\n+\n+void\n+sol_iio_close(struct sol_iio_device *device)\n+{\n+    int i;\n+    struct sol_iio_channel *channel;\n+\n+    SOL_PTR_VECTOR_FOREACH_REVERSE_IDX (&device->channels, channel, i) {\n+        iio_del_channel(channel);\n+        sol_ptr_vector_del(&device->channels, i);\n+    }\n+\n+    if (device->fd_handler) sol_fd_del(device->fd_handler);\n+    if (device->fd > -1) close(device->fd);\n+    free(device->trigger_name);\n+    free(device);\n+}\n+\n+static bool\n+read_channel_index_in_buffer(struct sol_iio_channel *channel)\n+{\n+    struct sol_iio_device *device = channel->device;\n+    char path[PATH_MAX + 1];\n+    int len;\n+\n+    len = snprintf(path, sizeof(path), CHANNEL_SCAN_INDEX_PATH,\n+        device->device_id, channel->name);\n+    if (len < 0 || sol_util_read_file(path, \"%d\", &channel->index) < 0)\n+        return false;\n+\n+    return true;\n+}\n+\n+struct sol_iio_channel *\n+sol_iio_add_channel(struct sol_iio_device *device, const char *name)\n+{\n+    char path[PATH_MAX + 1];\n+    struct sol_iio_channel *channel;\n+    struct stat st;\n+    int len;\n+\n+    len = snprintf(path, sizeof(path), CHANNEL_RAW_PATH, device->device_id,\n+        name);\n+    if (len < 0 || len > PATH_MAX || stat(path, &st)) {\n+        SOL_WRN(\"Could not find channel [%s] for device%d\", name,\n+            device->device_id);\n+        return NULL;\n+    }\n+\n+    channel = calloc(1, sizeof(struct sol_iio_channel));\n+    SOL_NULL_CHECK(channel, NULL);\n+\n+    channel->name = strdup(name);\n+    channel->device = device;\n+\n+    channel_get_scale(channel);\n+    channel_get_offset(channel);\n+\n+    if (device->buffer_enabled) {\n+        if (!enable_channel_scan(channel)) {\n+            SOL_WRN(\"Could not enable scanning of channel [%s] in device%d\",\n+                channel->name, device->device_id);\n+            goto error;\n+        }\n+\n+        if (!read_channel_scan_info(channel)) {\n+            SOL_WRN(\"Could not read scanning info of channel [%s] in device%d\",\n+                channel->name, device->device_id);\n+            goto error;\n+        }\n+\n+        if (!read_channel_index_in_buffer(channel)) {\n+            SOL_WRN(\"Could not read index in buffer of channel [%s] in device%d\",\n+                channel->name, device->device_id);\n+            goto error;\n+        }\n+\n+        channel->offset_in_buffer = -1;\n+    }\n+\n+    sol_ptr_vector_append(&channel->device->channels, channel);\n+\n+    SOL_DBG(\"channel %s added. scale: %lf - offset: %d - storagebits: %d\",\n+        channel->name, channel->scale, channel->offset, channel->storagebits);\n+\n+    return channel;\n+\n+error:\n+    iio_del_channel(channel);\n+\n+    return NULL;\n+}\n+\n+bool\n+sol_iio_read_channel_value(struct sol_iio_channel *channel, double *value)\n+{\n+    int len, raw_value;\n+    char path[PATH_MAX + 1];\n+    struct sol_iio_device *device = channel->device;\n+\n+    if (device->buffer_enabled) {\n+        SOL_WRN(\"device%d is using buffer - use iio_read_buffer_channel_value() instead\",\n+            device->device_id);","path":"src/shared/sol-iio.c","position":755,"original_position":755,"commit_id":"d3c810c43fa7ab3f51f5bf5618779573d96e8140","original_commit_id":"d3c810c43fa7ab3f51f5bf5618779573d96e8140","user":{"login":"edersondisouza","id":3177551,"avatar_url":"https://avatars.githubusercontent.com/u/3177551?v=3","gravatar_id":"","url":"https://api.github.com/users/edersondisouza","html_url":"https://github.com/edersondisouza","followers_url":"https://api.github.com/users/edersondisouza/followers","following_url":"https://api.github.com/users/edersondisouza/following{/other_user}","gists_url":"https://api.github.com/users/edersondisouza/gists{/gist_id}","starred_url":"https://api.github.com/users/edersondisouza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edersondisouza/subscriptions","organizations_url":"https://api.github.com/users/edersondisouza/orgs","repos_url":"https://api.github.com/users/edersondisouza/repos","events_url":"https://api.github.com/users/edersondisouza/events{/privacy}","received_events_url":"https://api.github.com/users/edersondisouza/received_events","type":"User","site_admin":false},"body":"`iio_read_buffer_channel_value()` needs the buffer sent on the callback. Is it worth reading from the last buffer we got? Aren't we hiding the truth from user?","created_at":"2015-08-03T17:54:38Z","updated_at":"2015-08-03T17:54:38Z","html_url":"https://github.com/solettaproject/soletta/pull/412#discussion_r36111195","pull_request_url":"https://api.github.com/repos/solettaproject/soletta/pulls/412","_links":{"self":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/comments/36111195"},"html":{"href":"https://github.com/solettaproject/soletta/pull/412#discussion_r36111195"},"pull_request":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/412"}}},"pull_request":{"url":"https://api.github.com/repos/solettaproject/soletta/pulls/412","id":41376028,"html_url":"https://github.com/solettaproject/soletta/pull/412","diff_url":"https://github.com/solettaproject/soletta/pull/412.diff","patch_url":"https://github.com/solettaproject/soletta/pull/412.patch","issue_url":"https://api.github.com/repos/solettaproject/soletta/issues/412","number":412,"state":"open","locked":false,"title":"Iio","user":{"login":"edersondisouza","id":3177551,"avatar_url":"https://avatars.githubusercontent.com/u/3177551?v=3","gravatar_id":"","url":"https://api.github.com/users/edersondisouza","html_url":"https://github.com/edersondisouza","followers_url":"https://api.github.com/users/edersondisouza/followers","following_url":"https://api.github.com/users/edersondisouza/following{/other_user}","gists_url":"https://api.github.com/users/edersondisouza/gists{/gist_id}","starred_url":"https://api.github.com/users/edersondisouza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edersondisouza/subscriptions","organizations_url":"https://api.github.com/users/edersondisouza/orgs","repos_url":"https://api.github.com/users/edersondisouza/repos","events_url":"https://api.github.com/users/edersondisouza/events{/privacy}","received_events_url":"https://api.github.com/users/edersondisouza/received_events","type":"User","site_admin":false},"body":"Adding some support functions to ease creation of Linux Industrial I/O nodes. Also added a node for iio-gyroscope, that tests the code.","created_at":"2015-07-31T20:07:13Z","updated_at":"2015-08-03T17:54:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9d817de1f50a3601192b9fe8394bd1f9d992da85","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/solettaproject/soletta/pulls/412/commits","review_comments_url":"https://api.github.com/repos/solettaproject/soletta/pulls/412/comments","review_comment_url":"https://api.github.com/repos/solettaproject/soletta/pulls/comments{/number}","comments_url":"https://api.github.com/repos/solettaproject/soletta/issues/412/comments","statuses_url":"https://api.github.com/repos/solettaproject/soletta/statuses/d3c810c43fa7ab3f51f5bf5618779573d96e8140","head":{"label":"edersondisouza:iio","ref":"iio","sha":"d3c810c43fa7ab3f51f5bf5618779573d96e8140","user":{"login":"edersondisouza","id":3177551,"avatar_url":"https://avatars.githubusercontent.com/u/3177551?v=3","gravatar_id":"","url":"https://api.github.com/users/edersondisouza","html_url":"https://github.com/edersondisouza","followers_url":"https://api.github.com/users/edersondisouza/followers","following_url":"https://api.github.com/users/edersondisouza/following{/other_user}","gists_url":"https://api.github.com/users/edersondisouza/gists{/gist_id}","starred_url":"https://api.github.com/users/edersondisouza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edersondisouza/subscriptions","organizations_url":"https://api.github.com/users/edersondisouza/orgs","repos_url":"https://api.github.com/users/edersondisouza/repos","events_url":"https://api.github.com/users/edersondisouza/events{/privacy}","received_events_url":"https://api.github.com/users/edersondisouza/received_events","type":"User","site_admin":false},"repo":{"id":37655085,"name":"soletta","full_name":"edersondisouza/soletta","owner":{"login":"edersondisouza","id":3177551,"avatar_url":"https://avatars.githubusercontent.com/u/3177551?v=3","gravatar_id":"","url":"https://api.github.com/users/edersondisouza","html_url":"https://github.com/edersondisouza","followers_url":"https://api.github.com/users/edersondisouza/followers","following_url":"https://api.github.com/users/edersondisouza/following{/other_user}","gists_url":"https://api.github.com/users/edersondisouza/gists{/gist_id}","starred_url":"https://api.github.com/users/edersondisouza/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edersondisouza/subscriptions","organizations_url":"https://api.github.com/users/edersondisouza/orgs","repos_url":"https://api.github.com/users/edersondisouza/repos","events_url":"https://api.github.com/users/edersondisouza/events{/privacy}","received_events_url":"https://api.github.com/users/edersondisouza/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/edersondisouza/soletta","description":"Soletta Project is a framework for making IoT devices.  With Soletta Project's libraries developers can easily write software for devices that control actuators/sensors and communicate using standard technologies. It enables adding smartness even on the smallest edge devices.  ","fork":true,"url":"https://api.github.com/repos/edersondisouza/soletta","forks_url":"https://api.github.com/repos/edersondisouza/soletta/forks","keys_url":"https://api.github.com/repos/edersondisouza/soletta/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edersondisouza/soletta/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edersondisouza/soletta/teams","hooks_url":"https://api.github.com/repos/edersondisouza/soletta/hooks","issue_events_url":"https://api.github.com/repos/edersondisouza/soletta/issues/events{/number}","events_url":"https://api.github.com/repos/edersondisouza/soletta/events","assignees_url":"https://api.github.com/repos/edersondisouza/soletta/assignees{/user}","branches_url":"https://api.github.com/repos/edersondisouza/soletta/branches{/branch}","tags_url":"https://api.github.com/repos/edersondisouza/soletta/tags","blobs_url":"https://api.github.com/repos/edersondisouza/soletta/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edersondisouza/soletta/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edersondisouza/soletta/git/refs{/sha}","trees_url":"https://api.github.com/repos/edersondisouza/soletta/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edersondisouza/soletta/statuses/{sha}","languages_url":"https://api.github.com/repos/edersondisouza/soletta/languages","stargazers_url":"https://api.github.com/repos/edersondisouza/soletta/stargazers","contributors_url":"https://api.github.com/repos/edersondisouza/soletta/contributors","subscribers_url":"https://api.github.com/repos/edersondisouza/soletta/subscribers","subscription_url":"https://api.github.com/repos/edersondisouza/soletta/subscription","commits_url":"https://api.github.com/repos/edersondisouza/soletta/commits{/sha}","git_commits_url":"https://api.github.com/repos/edersondisouza/soletta/git/commits{/sha}","comments_url":"https://api.github.com/repos/edersondisouza/soletta/comments{/number}","issue_comment_url":"https://api.github.com/repos/edersondisouza/soletta/issues/comments{/number}","contents_url":"https://api.github.com/repos/edersondisouza/soletta/contents/{+path}","compare_url":"https://api.github.com/repos/edersondisouza/soletta/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edersondisouza/soletta/merges","archive_url":"https://api.github.com/repos/edersondisouza/soletta/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edersondisouza/soletta/downloads","issues_url":"https://api.github.com/repos/edersondisouza/soletta/issues{/number}","pulls_url":"https://api.github.com/repos/edersondisouza/soletta/pulls{/number}","milestones_url":"https://api.github.com/repos/edersondisouza/soletta/milestones{/number}","notifications_url":"https://api.github.com/repos/edersondisouza/soletta/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edersondisouza/soletta/labels{/name}","releases_url":"https://api.github.com/repos/edersondisouza/soletta/releases{/id}","created_at":"2015-06-18T11:16:56Z","updated_at":"2015-06-18T11:16:57Z","pushed_at":"2015-08-03T16:01:23Z","git_url":"git://github.com/edersondisouza/soletta.git","ssh_url":"git@github.com:edersondisouza/soletta.git","clone_url":"https://github.com/edersondisouza/soletta.git","svn_url":"https://github.com/edersondisouza/soletta","homepage":"","size":2182,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"solettaproject:master","ref":"master","sha":"21de9bf60c8e7b09a1b49406b4e87b4bd06473fb","user":{"login":"solettaproject","id":12736897,"avatar_url":"https://avatars.githubusercontent.com/u/12736897?v=3","gravatar_id":"","url":"https://api.github.com/users/solettaproject","html_url":"https://github.com/solettaproject","followers_url":"https://api.github.com/users/solettaproject/followers","following_url":"https://api.github.com/users/solettaproject/following{/other_user}","gists_url":"https://api.github.com/users/solettaproject/gists{/gist_id}","starred_url":"https://api.github.com/users/solettaproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/solettaproject/subscriptions","organizations_url":"https://api.github.com/users/solettaproject/orgs","repos_url":"https://api.github.com/users/solettaproject/repos","events_url":"https://api.github.com/users/solettaproject/events{/privacy}","received_events_url":"https://api.github.com/users/solettaproject/received_events","type":"Organization","site_admin":false},"repo":{"id":37087063,"name":"soletta","full_name":"solettaproject/soletta","owner":{"login":"solettaproject","id":12736897,"avatar_url":"https://avatars.githubusercontent.com/u/12736897?v=3","gravatar_id":"","url":"https://api.github.com/users/solettaproject","html_url":"https://github.com/solettaproject","followers_url":"https://api.github.com/users/solettaproject/followers","following_url":"https://api.github.com/users/solettaproject/following{/other_user}","gists_url":"https://api.github.com/users/solettaproject/gists{/gist_id}","starred_url":"https://api.github.com/users/solettaproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/solettaproject/subscriptions","organizations_url":"https://api.github.com/users/solettaproject/orgs","repos_url":"https://api.github.com/users/solettaproject/repos","events_url":"https://api.github.com/users/solettaproject/events{/privacy}","received_events_url":"https://api.github.com/users/solettaproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/solettaproject/soletta","description":"Soletta Project is a framework for making IoT devices.  With Soletta Project's libraries developers can easily write software for devices that control actuators/sensors and communicate using standard technologies. It enables adding smartness even on the smallest edge devices.  ","fork":false,"url":"https://api.github.com/repos/solettaproject/soletta","forks_url":"https://api.github.com/repos/solettaproject/soletta/forks","keys_url":"https://api.github.com/repos/solettaproject/soletta/keys{/key_id}","collaborators_url":"https://api.github.com/repos/solettaproject/soletta/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/solettaproject/soletta/teams","hooks_url":"https://api.github.com/repos/solettaproject/soletta/hooks","issue_events_url":"https://api.github.com/repos/solettaproject/soletta/issues/events{/number}","events_url":"https://api.github.com/repos/solettaproject/soletta/events","assignees_url":"https://api.github.com/repos/solettaproject/soletta/assignees{/user}","branches_url":"https://api.github.com/repos/solettaproject/soletta/branches{/branch}","tags_url":"https://api.github.com/repos/solettaproject/soletta/tags","blobs_url":"https://api.github.com/repos/solettaproject/soletta/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/solettaproject/soletta/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/solettaproject/soletta/git/refs{/sha}","trees_url":"https://api.github.com/repos/solettaproject/soletta/git/trees{/sha}","statuses_url":"https://api.github.com/repos/solettaproject/soletta/statuses/{sha}","languages_url":"https://api.github.com/repos/solettaproject/soletta/languages","stargazers_url":"https://api.github.com/repos/solettaproject/soletta/stargazers","contributors_url":"https://api.github.com/repos/solettaproject/soletta/contributors","subscribers_url":"https://api.github.com/repos/solettaproject/soletta/subscribers","subscription_url":"https://api.github.com/repos/solettaproject/soletta/subscription","commits_url":"https://api.github.com/repos/solettaproject/soletta/commits{/sha}","git_commits_url":"https://api.github.com/repos/solettaproject/soletta/git/commits{/sha}","comments_url":"https://api.github.com/repos/solettaproject/soletta/comments{/number}","issue_comment_url":"https://api.github.com/repos/solettaproject/soletta/issues/comments{/number}","contents_url":"https://api.github.com/repos/solettaproject/soletta/contents/{+path}","compare_url":"https://api.github.com/repos/solettaproject/soletta/compare/{base}...{head}","merges_url":"https://api.github.com/repos/solettaproject/soletta/merges","archive_url":"https://api.github.com/repos/solettaproject/soletta/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/solettaproject/soletta/downloads","issues_url":"https://api.github.com/repos/solettaproject/soletta/issues{/number}","pulls_url":"https://api.github.com/repos/solettaproject/soletta/pulls{/number}","milestones_url":"https://api.github.com/repos/solettaproject/soletta/milestones{/number}","notifications_url":"https://api.github.com/repos/solettaproject/soletta/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/solettaproject/soletta/labels{/name}","releases_url":"https://api.github.com/repos/solettaproject/soletta/releases{/id}","created_at":"2015-06-08T19:13:18Z","updated_at":"2015-07-12T18:54:34Z","pushed_at":"2015-08-03T17:30:19Z","git_url":"git://github.com/solettaproject/soletta.git","ssh_url":"git@github.com:solettaproject/soletta.git","clone_url":"https://github.com/solettaproject/soletta.git","svn_url":"https://github.com/solettaproject/soletta","homepage":"","size":6231,"stargazers_count":39,"watchers_count":39,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":30,"mirror_url":null,"open_issues_count":22,"forks":30,"open_issues":22,"watchers":39,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/412"},"html":{"href":"https://github.com/solettaproject/soletta/pull/412"},"issue":{"href":"https://api.github.com/repos/solettaproject/soletta/issues/412"},"comments":{"href":"https://api.github.com/repos/solettaproject/soletta/issues/412/comments"},"review_comments":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/412/comments"},"review_comment":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/solettaproject/soletta/pulls/412/commits"},"statuses":{"href":"https://api.github.com/repos/solettaproject/soletta/statuses/d3c810c43fa7ab3f51f5bf5618779573d96e8140"}}}}