From 7a87d0f0ba76464322a832495ccb9ae5f705c9d5 Mon Sep 17 00:00:00 2001 From: Matt Fornero Date: Thu, 30 Nov 2017 14:36:37 -0500 Subject: [PATCH] device: Add support for buffer attributes Add support for reading/writing buffer attributes, similar to device and debug attributes. Signed-off-by: Matt Fornero --- context.c | 4 +- device.c | 349 +++++++++++++++++++++++++++++++++++++++++++------- iio-private.h | 10 +- iio.h | 182 ++++++++++++++++++++++++++ iiod-client.c | 84 ++++++++---- iiod-client.h | 6 +- local.c | 106 +++++++++++---- network.c | 8 +- serial.c | 8 +- usb.c | 8 +- xml.c | 52 +++++--- 11 files changed, 688 insertions(+), 129 deletions(-) diff --git a/context.c b/context.c index 4f68cd7b7..b124801c0 100644 --- a/context.c +++ b/context.c @@ -32,11 +32,12 @@ static const char xml_header[] = "" "" "" -"" +"" "" "" "" "" +"" "" "" "" @@ -44,6 +45,7 @@ static const char xml_header[] = "" "" "" "" +"" "]>"; /* Returns a string containing the XML representation of this context */ diff --git a/device.c b/device.c index 0fc88bcfd..7f181694d 100644 --- a/device.c +++ b/device.c @@ -24,19 +24,41 @@ #include #include -static char *get_attr_xml(const char *attr, size_t *length, bool is_debug) +static char *get_attr_xml(const char *attr, size_t *length, enum iio_attr_type type) { - size_t len = sizeof("") + strlen(attr) - + (!is_debug ? 0 : sizeof("debug-") - 1); - char *str = malloc(len); + size_t len = sizeof("") + strlen(attr); + char *str; + + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + break; + case IIO_ATTR_TYPE_DEBUG: + len += (sizeof("debug-") - 1); + break; + case IIO_ATTR_TYPE_BUFFER: + len += (sizeof("buffer-") - 1); + break; + default: + return NULL; + } + + str = malloc(len); if (!str) return NULL; *length = len - 1; /* Skip the \0 */ - if (is_debug) - iio_snprintf(str, len, "", attr); - else - iio_snprintf(str, len, "", attr); + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + iio_snprintf(str, len, "", attr); + break; + case IIO_ATTR_TYPE_DEBUG: + iio_snprintf(str, len, "", attr); + break; + case IIO_ATTR_TYPE_BUFFER: + iio_snprintf(str, len, "", attr); + break; + } + return str; } @@ -45,8 +67,8 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) { size_t len = sizeof("") + strlen(dev->id) + (dev->name ? strlen(dev->name) : 0); - char *ptr, *str, **attrs, **channels, **debug_attrs; - size_t *attrs_len, *channels_len, *debug_attrs_len; + char *ptr, *str, **attrs, **channels, **buffer_attrs, **debug_attrs; + size_t *attrs_len, *channels_len, *buffer_attrs_len, *debug_attrs_len; unsigned int i, j, k; attrs_len = malloc(dev->nb_attrs * sizeof(*attrs_len)); @@ -58,7 +80,7 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) goto err_free_attrs_len; for (i = 0; i < dev->nb_attrs; i++) { - char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i], false); + char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i], IIO_ATTR_TYPE_DEVICE); if (!xml) goto err_free_attrs; attrs[i] = xml; @@ -82,10 +104,28 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) len += channels_len[j]; } + buffer_attrs_len = malloc(dev->nb_buffer_attrs * + sizeof(*buffer_attrs_len)); + if (!buffer_attrs_len) + goto err_free_channels; + + buffer_attrs = malloc(dev->nb_buffer_attrs * sizeof(*buffer_attrs)); + if (!buffer_attrs) + goto err_free_buffer_attrs_len; + + for (k = 0; k < dev->nb_buffer_attrs; k++) { + char *xml = get_attr_xml(dev->buffer_attrs[k], + &buffer_attrs_len[k], IIO_ATTR_TYPE_BUFFER); + if (!xml) + goto err_free_buffer_attrs; + buffer_attrs[k] = xml; + len += buffer_attrs_len[k]; + } + debug_attrs_len = malloc(dev->nb_debug_attrs * sizeof(*debug_attrs_len)); if (!debug_attrs_len) - goto err_free_channels; + goto err_free_buffer_attrs; debug_attrs = malloc(dev->nb_debug_attrs * sizeof(*debug_attrs)); if (!debug_attrs) @@ -93,7 +133,7 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) for (k = 0; k < dev->nb_debug_attrs; k++) { char *xml = get_attr_xml(dev->debug_attrs[k], - &debug_attrs_len[k], true); + &debug_attrs_len[k], IIO_ATTR_TYPE_DEBUG); if (!xml) goto err_free_debug_attrs; debug_attrs[k] = xml; @@ -133,6 +173,15 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) free(attrs); free(attrs_len); + for (i = 0; i < dev->nb_buffer_attrs; i++) { + strcpy(ptr, buffer_attrs[i]); + ptr += buffer_attrs_len[i]; + free(buffer_attrs[i]); + } + + free(buffer_attrs); + free(buffer_attrs_len); + for (i = 0; i < dev->nb_debug_attrs; i++) { strcpy(ptr, debug_attrs[i]); ptr += debug_attrs_len[i]; @@ -152,6 +201,12 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) free(debug_attrs); err_free_debug_attrs_len: free(debug_attrs_len); +err_free_buffer_attrs: + while (k--) + free(buffer_attrs[k]); + free(buffer_attrs); +err_free_buffer_attrs_len: + free(buffer_attrs_len); err_free_channels: while (j--) free(channels[j]); @@ -233,6 +288,32 @@ const char * iio_device_find_attr(const struct iio_device *dev, return NULL; } +unsigned int iio_device_get_buffer_attrs_count(const struct iio_device *dev) +{ + return dev->nb_buffer_attrs; +} + +const char * iio_device_get_buffer_attr(const struct iio_device *dev, + unsigned int index) +{ + if (index >= dev->nb_buffer_attrs) + return NULL; + else + return dev->buffer_attrs[index]; +} + +const char * iio_device_find_buffer_attr(const struct iio_device *dev, + const char *name) +{ + unsigned int i; + for (i = 0; i < dev->nb_buffer_attrs; i++) { + const char *attr = dev->buffer_attrs[i]; + if (!strcmp(attr, name)) + return attr; + } + return NULL; +} + const char * iio_device_find_debug_attr(const struct iio_device *dev, const char *name) { @@ -322,7 +403,7 @@ ssize_t iio_device_attr_read(const struct iio_device *dev, { if (dev->ctx->ops->read_device_attr) return dev->ctx->ops->read_device_attr(dev, - attr, dst, len, false); + attr, dst, len, IIO_ATTR_TYPE_DEVICE); else return -ENOSYS; } @@ -332,7 +413,7 @@ ssize_t iio_device_attr_write_raw(const struct iio_device *dev, { if (dev->ctx->ops->write_device_attr) return dev->ctx->ops->write_device_attr(dev, - attr, src, len, false); + attr, src, len, IIO_ATTR_TYPE_DEVICE); else return -ENOSYS; } @@ -343,6 +424,32 @@ ssize_t iio_device_attr_write(const struct iio_device *dev, return iio_device_attr_write_raw(dev, attr, src, strlen(src) + 1); } +ssize_t iio_device_buffer_attr_read(const struct iio_device *dev, + const char *attr, char *dst, size_t len) +{ + if (dev->ctx->ops->read_device_attr) + return dev->ctx->ops->read_device_attr(dev, + attr, dst, len, IIO_ATTR_TYPE_BUFFER); + else + return -ENOSYS; +} + +ssize_t iio_device_buffer_attr_write_raw(const struct iio_device *dev, + const char *attr, const void *src, size_t len) +{ + if (dev->ctx->ops->write_device_attr) + return dev->ctx->ops->write_device_attr(dev, + attr, src, len, IIO_ATTR_TYPE_BUFFER); + else + return -ENOSYS; +} + +ssize_t iio_device_buffer_attr_write(const struct iio_device *dev, + const char *attr, const char *src) +{ + return iio_device_buffer_attr_write_raw(dev, attr, src, strlen(src) + 1); +} + void iio_device_set_data(struct iio_device *dev, void *data) { dev->userdata = data; @@ -542,12 +649,88 @@ int iio_device_attr_write_bool(const struct iio_device *dev, return ret < 0 ? ret : 0; } +int iio_device_buffer_attr_read_longlong(const struct iio_device *dev, + const char *attr, long long *val) +{ + char *end, buf[1024]; + long long value; + ssize_t ret = iio_device_buffer_attr_read(dev, attr, buf, sizeof(buf)); + if (ret < 0) + return (int) ret; + + value = strtoll(buf, &end, 0); + if (end == buf) + return -EINVAL; + *val = value; + return 0; +} + +int iio_device_buffer_attr_read_bool(const struct iio_device *dev, + const char *attr, bool *val) +{ + long long value; + int ret = iio_device_buffer_attr_read_longlong(dev, attr, &value); + if (ret < 0) + return ret; + + *val = !!value; + return 0; +} + +int iio_device_buffer_attr_read_double(const struct iio_device *dev, + const char *attr, double *val) +{ + char buf[1024]; + ssize_t ret = iio_device_buffer_attr_read(dev, attr, buf, sizeof(buf)); + if (ret < 0) + return (int) ret; + else + return read_double(buf, val); +} + +int iio_device_buffer_attr_write_longlong(const struct iio_device *dev, + const char *attr, long long val) +{ + ssize_t ret; + char buf[1024]; + + iio_snprintf(buf, sizeof(buf), "%lld", val); + ret = iio_device_buffer_attr_write(dev, attr, buf); + + return ret < 0 ? ret : 0; +} + +int iio_device_buffer_attr_write_double(const struct iio_device *dev, + const char *attr, double val) +{ + ssize_t ret; + char buf[1024]; + + ret = (ssize_t) write_double(buf, sizeof(buf), val); + if (!ret) + ret = iio_device_buffer_attr_write(dev, attr, buf); + return ret < 0 ? ret : 0; +} + +int iio_device_buffer_attr_write_bool(const struct iio_device *dev, + const char *attr, bool val) +{ + ssize_t ret; + + if (val) + ret = iio_device_buffer_attr_write(dev, attr, "1"); + else + ret = iio_device_buffer_attr_write(dev, attr, "0"); + + return ret < 0 ? ret : 0; +} + ssize_t iio_device_debug_attr_read(const struct iio_device *dev, const char *attr, char *dst, size_t len) { if (dev->ctx->ops->read_device_attr) return dev->ctx->ops->read_device_attr(dev, - attr, dst, len, true); + attr, dst, len, IIO_ATTR_TYPE_DEBUG); else return -ENOSYS; } @@ -557,7 +740,7 @@ ssize_t iio_device_debug_attr_write_raw(const struct iio_device *dev, { if (dev->ctx->ops->write_device_attr) return dev->ctx->ops->write_device_attr(dev, - attr, src, len, true); + attr, src, len, IIO_ATTR_TYPE_DEBUG); else return -ENOSYS; } @@ -730,7 +913,7 @@ int iio_device_reg_read(struct iio_device *dev, return ret; } -static int read_each_attr(struct iio_device *dev, bool is_debug, +static int read_each_attr(struct iio_device *dev, enum iio_attr_type type, int (*cb)(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) @@ -744,13 +927,26 @@ static int read_each_attr(struct iio_device *dev, bool is_debug, if (!buf) return -ENOMEM; - if (is_debug) { - count = iio_device_get_debug_attrs_count(dev); - ret = (int) iio_device_debug_attr_read(dev, - NULL, buf, 0x100000); - } else { - count = iio_device_get_attrs_count(dev); - ret = (int) iio_device_attr_read(dev, NULL, buf, 0x100000); + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + count = iio_device_get_attrs_count(dev); + ret = (int) iio_device_attr_read(dev, + NULL, buf, 0x100000); + break; + case IIO_ATTR_TYPE_DEBUG: + count = iio_device_get_debug_attrs_count(dev); + ret = (int) iio_device_debug_attr_read(dev, + NULL, buf, 0x100000); + break; + case IIO_ATTR_TYPE_BUFFER: + count = iio_device_get_buffer_attrs_count(dev); + ret = (int) iio_device_buffer_attr_read(dev, + NULL, buf, 0x100000); + break; + default: + ret = -EINVAL; + count = 0; + break; } if (ret < 0) @@ -762,10 +958,20 @@ static int read_each_attr(struct iio_device *dev, bool is_debug, const char *attr; int32_t len = (int32_t) iio_be32toh(*(uint32_t *) ptr); - if (is_debug) - attr = iio_device_get_debug_attr(dev, i); - else - attr = iio_device_get_attr(dev, i); + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + attr = iio_device_get_attr(dev, i); + break; + case IIO_ATTR_TYPE_DEBUG: + attr = iio_device_get_debug_attr(dev, i); + break; + case IIO_ATTR_TYPE_BUFFER: + attr = iio_device_get_buffer_attr(dev, i); + break; + default: + attr = NULL; + break; + } ptr += 4; if (len > 0) { @@ -784,7 +990,7 @@ static int read_each_attr(struct iio_device *dev, bool is_debug, return ret < 0 ? ret : 0; } -static int write_each_attr(struct iio_device *dev, bool is_debug, +static int write_each_attr(struct iio_device *dev, enum iio_attr_type type, ssize_t (*cb)(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) @@ -801,18 +1007,38 @@ static int write_each_attr(struct iio_device *dev, bool is_debug, ptr = buf; - if (is_debug) - count = iio_device_get_debug_attrs_count(dev); - else - count = iio_device_get_attrs_count(dev); + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + count = iio_device_get_attrs_count(dev); + break; + case IIO_ATTR_TYPE_DEBUG: + count = iio_device_get_debug_attrs_count(dev); + break; + case IIO_ATTR_TYPE_BUFFER: + count = iio_device_get_buffer_attrs_count(dev); + break; + default: + ret = -EINVAL; + goto err_free_buf; + } for (i = 0; i < count; i++) { const char *attr; - if (is_debug) - attr = iio_device_get_debug_attr(dev, i); - else - attr = iio_device_get_attr(dev, i); + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + attr = iio_device_get_attr(dev, i); + break; + case IIO_ATTR_TYPE_DEBUG: + attr = iio_device_get_debug_attr(dev, i); + break; + case IIO_ATTR_TYPE_BUFFER: + attr = iio_device_get_buffer_attr(dev, i); + break; + default: + attr = NULL; + break; + } ret = (int) cb(dev, attr, ptr + 4, len - 4, data); if (ret < 0) @@ -830,12 +1056,23 @@ static int write_each_attr(struct iio_device *dev, bool is_debug, } } - if (is_debug) - ret = (int) iio_device_debug_attr_write_raw(dev, - NULL, buf, ptr - buf); - else - ret = (int) iio_device_attr_write_raw(dev, - NULL, buf, ptr - buf); + switch(type){ + case IIO_ATTR_TYPE_DEVICE: + ret = (int) iio_device_attr_write_raw(dev, + NULL, buf, ptr - buf); + break; + case IIO_ATTR_TYPE_DEBUG: + ret = (int) iio_device_debug_attr_write_raw(dev, + NULL, buf, ptr - buf); + break; + case IIO_ATTR_TYPE_BUFFER: + ret = (int) iio_device_buffer_attr_write_raw(dev, + NULL, buf, ptr - buf); + break; + default: + ret = -EINVAL; + break; + } err_free_buf: free(buf); @@ -847,7 +1084,15 @@ int iio_device_debug_attr_read_all(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { - return read_each_attr(dev, true, cb, data); + return read_each_attr(dev, IIO_ATTR_TYPE_DEBUG, cb, data); +} + +int iio_device_buffer_attr_read_all(struct iio_device *dev, + int (*cb)(struct iio_device *dev, + const char *attr, const char *val, size_t len, void *d), + void *data) +{ + return read_each_attr(dev, IIO_ATTR_TYPE_BUFFER, cb, data); } int iio_device_attr_read_all(struct iio_device *dev, @@ -855,7 +1100,7 @@ int iio_device_attr_read_all(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { - return read_each_attr(dev, false, cb, data); + return read_each_attr(dev, IIO_ATTR_TYPE_DEVICE ,cb, data); } int iio_device_debug_attr_write_all(struct iio_device *dev, @@ -863,7 +1108,15 @@ int iio_device_debug_attr_write_all(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { - return write_each_attr(dev, true, cb, data); + return write_each_attr(dev, IIO_ATTR_TYPE_DEBUG, cb, data); +} + +int iio_device_buffer_attr_write_all(struct iio_device *dev, + ssize_t (*cb)(struct iio_device *dev, + const char *attr, void *buf, size_t len, void *d), + void *data) +{ + return write_each_attr(dev, IIO_ATTR_TYPE_BUFFER, cb, data); } int iio_device_attr_write_all(struct iio_device *dev, @@ -871,7 +1124,7 @@ int iio_device_attr_write_all(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { - return write_each_attr(dev, false, cb, data); + return write_each_attr(dev, IIO_ATTR_TYPE_DEVICE, cb, data); } const struct iio_context * iio_device_get_context(const struct iio_device *dev) diff --git a/iio-private.h b/iio-private.h index 295bbd891..a4d17d465 100644 --- a/iio-private.h +++ b/iio-private.h @@ -89,6 +89,12 @@ static inline void *zalloc(size_t size) return calloc(1, size); } +enum iio_attr_type { + IIO_ATTR_TYPE_DEVICE = 0, + IIO_ATTR_TYPE_DEBUG, + IIO_ATTR_TYPE_BUFFER, +}; + struct iio_backend_ops { struct iio_context * (*clone)(const struct iio_context *ctx); ssize_t (*read)(const struct iio_device *dev, void *dst, size_t len, @@ -110,10 +116,10 @@ struct iio_backend_ops { uint32_t *mask, size_t words); ssize_t (*read_device_attr)(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug); + const char *attr, char *dst, size_t len, enum iio_attr_type); ssize_t (*write_device_attr)(const struct iio_device *dev, const char *attr, const char *src, - size_t len, bool is_debug); + size_t len, enum iio_attr_type); ssize_t (*read_channel_attr)(const struct iio_channel *chn, const char *attr, char *dst, size_t len); ssize_t (*write_channel_attr)(const struct iio_channel *chn, diff --git a/iio.h b/iio.h index efa55ef0d..5d8ca5a99 100644 --- a/iio.h +++ b/iio.h @@ -511,6 +511,11 @@ __api __pure unsigned int iio_device_get_channels_count( __api __pure unsigned int iio_device_get_attrs_count( const struct iio_device *dev); +/** @brief Enumerate the buffer-specific attributes of the given device + * @param dev A pointer to an iio_device structure + * @return The number of buffer-specific attributes found */ +__api __pure unsigned int iio_device_get_buffer_attrs_count( + const struct iio_device *dev); /** @brief Get the channel present at the given index * @param dev A pointer to an iio_device structure @@ -529,6 +534,13 @@ __api __pure struct iio_channel * iio_device_get_channel( __api __pure const char * iio_device_get_attr( const struct iio_device *dev, unsigned int index); +/** @brief Get the buffer-specific attribute present at the given index + * @param dev A pointer to an iio_device structure + * @param index The index corresponding to the attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned */ +__api __pure const char * iio_device_get_buffer_attr( + const struct iio_device *dev, unsigned int index); /** @brief Try to find a channel structure by its name of ID * @param dev A pointer to an iio_device structure @@ -556,6 +568,19 @@ __api __pure struct iio_channel * iio_device_find_channel( __api __pure const char * iio_device_find_attr( const struct iio_device *dev, const char *name); +/** @brief Try to find a buffer-specific attribute by its name + * @param dev A pointer to an iio_device structure + * @param name A NULL-terminated string corresponding to the name of the + * attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any known attribute of the given + * device, NULL is returned + * + * NOTE: This function is useful to detect the presence of an attribute. + * It can also be used to retrieve the name of an attribute as a pointer to a + * static string from a dynamically allocated string. */ +__api __pure const char * iio_device_find_buffer_attr( + const struct iio_device *dev, const char *name); /** @brief Read the content of the given device-specific attribute * @param dev A pointer to an iio_device structure @@ -713,6 +738,163 @@ __api int iio_device_attr_write_longlong(const struct iio_device *dev, __api int iio_device_attr_write_double(const struct iio_device *dev, const char *attr, double val); +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the value read will be stored + * @param len The available length of the memory area, in bytes + * @return On success, the number of bytes written to the buffer + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_buffer_attr_read, it is now possible to read all of the attributes + * of a device. + * + * The buffer is filled with one block of data per attribute of the buffer, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, it corresponds to the errno code that were + * returned when reading the attribute; if positive, it corresponds to the + * length of the data read. In that case, the rest of the block contains + * the data. */ + __api ssize_t iio_device_buffer_attr_read(const struct iio_device *dev, + const char *attr, char *dst, size_t len); + +/** @brief Read the content of all buffer-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the buffer-specific attributes are read in one single + * command. */ +__api int iio_device_buffer_attr_read_all(struct iio_device *dev, + int (*cb)(struct iio_device *dev, const char *attr, + const char *value, size_t len, void *d), + void *data); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a bool variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_read_bool(const struct iio_device *dev, + const char *attr, bool *val); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a long long variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_read_longlong(const struct iio_device *dev, + const char *attr, long long *val); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a double variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_read_double(const struct iio_device *dev, + const char *attr, double *val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A NULL-terminated string to set the attribute to + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_buffer_attr_write, it is now possible to write all of the + * attributes of a device. + * + * The buffer must contain one block of data per attribute of the buffer, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, the attribute is not written; if positive, + * it corresponds to the length of the data to write. In that case, the rest + * of the block must contain the data. */ +__api ssize_t iio_device_buffer_attr_write(const struct iio_device *dev, + const char *attr, const char *src); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A pointer to the data to be written + * @param len The number of bytes that should be written + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned */ +__api ssize_t iio_device_buffer_attr_write_raw(const struct iio_device *dev, + const char *attr, const void *src, size_t len); + + +/** @brief Set the values of all buffer-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the buffer-specific attributes are written in one single + * command. */ +__api int iio_device_buffer_attr_write_all(struct iio_device *dev, + ssize_t (*cb)(struct iio_device *dev, + const char *attr, void *buf, size_t len, void *d), + void *data); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A bool value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_write_bool(const struct iio_device *dev, + const char *attr, bool val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A long long value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_write_longlong(const struct iio_device *dev, + const char *attr, long long val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A double value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api int iio_device_buffer_attr_write_double(const struct iio_device *dev, + const char *attr, double val); + /** @brief Associate a pointer to an iio_device structure * @param dev A pointer to an iio_device structure diff --git a/iiod-client.c b/iiod-client.c index d65ae9a0a..1798cd653 100644 --- a/iiod-client.c +++ b/iiod-client.c @@ -333,7 +333,7 @@ static int iiod_client_discard(struct iiod_client *client, void *desc, ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc, const struct iio_device *dev, const struct iio_channel *chn, - const char *attr, char *dest, size_t len, bool is_debug) + const char *attr, char *dest, size_t len, enum iio_attr_type type) { const char *id = iio_device_get_id(dev); char buf[1024]; @@ -343,12 +343,23 @@ ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc, if (chn) { if (!iio_channel_find_attr(chn, attr)) return -ENOENT; - } else if (is_debug) { - if (!iio_device_find_debug_attr(dev, attr)) - return -ENOENT; } else { - if (!iio_device_find_attr(dev, attr)) - return -ENOENT; + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + if (!iio_device_find_attr(dev, attr)) + return -ENOENT; + break; + case IIO_ATTR_TYPE_DEBUG: + if (!iio_device_find_debug_attr(dev, attr)) + return -ENOENT; + break; + case IIO_ATTR_TYPE_BUFFER: + if (!iio_device_find_buffer_attr(dev, attr)) + return -ENOENT; + break; + default: + return -EINVAL; + } } } @@ -356,12 +367,21 @@ ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc, iio_snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id, iio_channel_is_output(chn) ? "OUTPUT" : "INPUT", iio_channel_get_id(chn), attr ? attr : ""); - } else if (is_debug) { - iio_snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n", - id, attr ? attr : ""); } else { - iio_snprintf(buf, sizeof(buf), "READ %s %s\r\n", - id, attr ? attr : ""); + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + iio_snprintf(buf, sizeof(buf), "READ %s %s\r\n", + id, attr ? attr : ""); + break; + case IIO_ATTR_TYPE_DEBUG: + iio_snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n", + id, attr ? attr : ""); + break; + case IIO_ATTR_TYPE_BUFFER: + iio_snprintf(buf, sizeof(buf), "READ %s BUFFER %s\r\n", + id, attr ? attr : ""); + break; + } } iio_mutex_lock(client->lock); @@ -394,7 +414,7 @@ ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc, ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc, const struct iio_device *dev, const struct iio_channel *chn, - const char *attr, const char *src, size_t len, bool is_debug) + const char *attr, const char *src, size_t len, enum iio_attr_type type) { struct iio_context_pdata *pdata = client->pdata; const struct iiod_client_ops *ops = client->ops; @@ -407,12 +427,23 @@ ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc, if (chn) { if (!iio_channel_find_attr(chn, attr)) return -ENOENT; - } else if (is_debug) { - if (!iio_device_find_debug_attr(dev, attr)) - return -ENOENT; } else { - if (!iio_device_find_attr(dev, attr)) - return -ENOENT; + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + if (!iio_device_find_attr(dev, attr)) + return -ENOENT; + break; + case IIO_ATTR_TYPE_DEBUG: + if (!iio_device_find_debug_attr(dev, attr)) + return -ENOENT; + break; + case IIO_ATTR_TYPE_BUFFER: + if (!iio_device_find_buffer_attr(dev, attr)) + return -ENOENT; + break; + default: + return -EINVAL; + } } } @@ -421,12 +452,21 @@ ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc, iio_channel_is_output(chn) ? "OUTPUT" : "INPUT", iio_channel_get_id(chn), attr ? attr : "", (unsigned long) len); - } else if (is_debug) { - iio_snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n", - id, attr ? attr : "", (unsigned long) len); } else { - iio_snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n", - id, attr ? attr : "", (unsigned long) len); + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + iio_snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n", + id, attr ? attr : "", (unsigned long) len); + break; + case IIO_ATTR_TYPE_DEBUG: + iio_snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n", + id, attr ? attr : "", (unsigned long) len); + break; + case IIO_ATTR_TYPE_BUFFER: + iio_snprintf(buf, sizeof(buf), "WRITE %s BUFFER %s %lu\r\n", + id, attr ? attr : "", (unsigned long) len); + break; + } } iio_mutex_lock(client->lock); diff --git a/iiod-client.h b/iiod-client.h index 61419b30a..dcf2482b4 100644 --- a/iiod-client.h +++ b/iiod-client.h @@ -19,7 +19,7 @@ #ifndef _IIOD_CLIENT_H #define _IIOD_CLIENT_H -#include "iio.h" +#include "iio-private.h" struct iio_mutex; struct iiod_client; @@ -51,10 +51,10 @@ int iiod_client_set_timeout(struct iiod_client *client, void *desc, unsigned int timeout); ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc, const struct iio_device *dev, const struct iio_channel *chn, - const char *attr, char *dest, size_t len, bool is_debug); + const char *attr, char *dest, size_t len, enum iio_attr_type type); ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc, const struct iio_device *dev, const struct iio_channel *chn, - const char *attr, const char *src, size_t len, bool is_debug); + const char *attr, const char *src, size_t len, enum iio_attr_type type); int iiod_client_open_unlocked(struct iiod_client *client, void *desc, const struct iio_device *dev, size_t samples_count, bool cyclic); diff --git a/local.c b/local.c index 48646cfe7..3992fb968 100644 --- a/local.c +++ b/local.c @@ -56,11 +56,11 @@ /* Forward declarations */ static ssize_t local_read_dev_attr(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug); + const char *attr, char *dst, size_t len, enum iio_attr_type type); static ssize_t local_read_chn_attr(const struct iio_channel *chn, const char *attr, char *dst, size_t len); static ssize_t local_write_dev_attr(const struct iio_device *dev, - const char *attr, const char *src, size_t len, bool is_debug); + const char *attr, const char *src, size_t len, enum iio_attr_type type); static ssize_t local_write_chn_attr(const struct iio_channel *chn, const char *attr, const char *src, size_t len); @@ -513,16 +513,34 @@ static ssize_t local_get_buffer(const struct iio_device *dev, } static ssize_t local_read_all_dev_attrs(const struct iio_device *dev, - char *dst, size_t len, bool is_debug) + char *dst, size_t len, enum iio_attr_type type) { - unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs; - char **attrs = is_debug ? dev->debug_attrs : dev->attrs; + unsigned int i, nb; + char **attrs; char *ptr = dst; + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + nb = dev->nb_attrs; + attrs = dev->attrs; + break; + case IIO_ATTR_TYPE_DEBUG: + nb = dev->nb_debug_attrs; + attrs = dev->debug_attrs; + break; + case IIO_ATTR_TYPE_BUFFER: + nb = dev->nb_buffer_attrs; + attrs = dev->buffer_attrs; + break; + default: + return -EINVAL; + break; + } + for (i = 0; len >= 4 && i < nb; i++) { /* Recursive! */ ssize_t ret = local_read_dev_attr(dev, attrs[i], - ptr + 4, len - 4, is_debug); + ptr + 4, len - 4, type); *(uint32_t *) ptr = iio_htobe32(ret); /* Align the length to 4 bytes */ @@ -586,12 +604,30 @@ static int local_buffer_analyze(unsigned int nb, const char *src, size_t len) } static ssize_t local_write_all_dev_attrs(const struct iio_device *dev, - const char *src, size_t len, bool is_debug) + const char *src, size_t len, enum iio_attr_type type) { - unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs; - char **attrs = is_debug ? dev->debug_attrs : dev->attrs; + unsigned int i, nb; + char **attrs; const char *ptr = src; + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + nb = dev->nb_attrs; + attrs = dev->attrs; + break; + case IIO_ATTR_TYPE_DEBUG: + nb = dev->nb_debug_attrs; + attrs = dev->debug_attrs; + break; + case IIO_ATTR_TYPE_BUFFER: + nb = dev->nb_buffer_attrs; + attrs = dev->buffer_attrs; + break; + default: + return -EINVAL; + break; + } + /* First step: Verify that the buffer is in the correct format */ if (local_buffer_analyze(nb, src, len)) return -EINVAL; @@ -602,7 +638,7 @@ static ssize_t local_write_all_dev_attrs(const struct iio_device *dev, ptr += 4; if (val > 0) { - local_write_dev_attr(dev, attrs[i], ptr, val, is_debug); + local_write_dev_attr(dev, attrs[i], ptr, val, type); /* Align the length to 4 bytes */ if (val & 3) @@ -643,21 +679,30 @@ static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn, } static ssize_t local_read_dev_attr(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug) + const char *attr, char *dst, size_t len, enum iio_attr_type type) { FILE *f; char buf[1024]; ssize_t ret; if (!attr) - return local_read_all_dev_attrs(dev, dst, len, is_debug); + return local_read_all_dev_attrs(dev, dst, len, type); - if (is_debug) { - iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s", - dev->id, attr); - } else { - iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s", - dev->id, attr); + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s", + dev->id, attr); + break; + case IIO_ATTR_TYPE_DEBUG: + iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s", + dev->id, attr); + break; + case IIO_ATTR_TYPE_BUFFER: + iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/buffer/%s", + dev->id, attr); + break; + default: + return -EINVAL; } f = fopen(buf, "re"); @@ -675,21 +720,30 @@ static ssize_t local_read_dev_attr(const struct iio_device *dev, } static ssize_t local_write_dev_attr(const struct iio_device *dev, - const char *attr, const char *src, size_t len, bool is_debug) + const char *attr, const char *src, size_t len, enum iio_attr_type type) { FILE *f; char buf[1024]; ssize_t ret; if (!attr) - return local_write_all_dev_attrs(dev, src, len, is_debug); + return local_write_all_dev_attrs(dev, src, len, type); - if (is_debug) { - iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s", - dev->id, attr); - } else { - iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s", - dev->id, attr); + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s", + dev->id, attr); + break; + case IIO_ATTR_TYPE_DEBUG: + iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s", + dev->id, attr); + break; + case IIO_ATTR_TYPE_BUFFER: + iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/buffer/%s", + dev->id, attr); + break; + default: + return -EINVAL; } f = fopen(buf, "we"); diff --git a/network.c b/network.c index d9b9731e0..0af5c18d3 100644 --- a/network.c +++ b/network.c @@ -1129,21 +1129,21 @@ static ssize_t network_get_buffer(const struct iio_device *dev, #endif static ssize_t network_read_dev_attr(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug) + const char *attr, char *dst, size_t len, enum iio_attr_type type) { struct iio_context_pdata *pdata = dev->ctx->pdata; return iiod_client_read_attr(pdata->iiod_client, - &pdata->io_ctx, dev, NULL, attr, dst, len, is_debug); + &pdata->io_ctx, dev, NULL, attr, dst, len, type); } static ssize_t network_write_dev_attr(const struct iio_device *dev, - const char *attr, const char *src, size_t len, bool is_debug) + const char *attr, const char *src, size_t len, enum iio_attr_type type) { struct iio_context_pdata *pdata = dev->ctx->pdata; return iiod_client_write_attr(pdata->iiod_client, - &pdata->io_ctx, dev, NULL, attr, src, len, is_debug); + &pdata->io_ctx, dev, NULL, attr, src, len, type); } static ssize_t network_read_chn_attr(const struct iio_channel *chn, diff --git a/serial.c b/serial.c index 5f0d5cecd..af424a2e2 100644 --- a/serial.c +++ b/serial.c @@ -137,23 +137,23 @@ static ssize_t serial_write(const struct iio_device *dev, } static ssize_t serial_read_dev_attr(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug) + const char *attr, char *dst, size_t len, enum iio_attr_type type) { const struct iio_context *ctx = iio_device_get_context(dev); struct iio_context_pdata *pdata = ctx->pdata; return iiod_client_read_attr(pdata->iiod_client, NULL, - dev, NULL, attr, dst, len, is_debug); + dev, NULL, attr, dst, len, type); } static ssize_t serial_write_dev_attr(const struct iio_device *dev, - const char *attr, const char *src, size_t len, bool is_debug) + const char *attr, const char *src, size_t len, enum iio_attr_type type) { const struct iio_context *ctx = iio_device_get_context(dev); struct iio_context_pdata *pdata = ctx->pdata; return iiod_client_write_attr(pdata->iiod_client, NULL, - dev, NULL, attr, src, len, is_debug); + dev, NULL, attr, src, len, type); } static ssize_t serial_read_chn_attr(const struct iio_channel *chn, diff --git a/usb.c b/usb.c index f6a381ca3..2a48744b5 100644 --- a/usb.c +++ b/usb.c @@ -337,23 +337,23 @@ static ssize_t usb_write(const struct iio_device *dev, } static ssize_t usb_read_dev_attr(const struct iio_device *dev, - const char *attr, char *dst, size_t len, bool is_debug) + const char *attr, char *dst, size_t len, enum iio_attr_type type) { struct iio_context_pdata *pdata = dev->ctx->pdata; return iiod_client_read_attr(pdata->iiod_client, &pdata->io_ctx, dev, NULL, attr, - dst, len, is_debug); + dst, len, type); } static ssize_t usb_write_dev_attr(const struct iio_device *dev, - const char *attr, const char *src, size_t len, bool is_debug) + const char *attr, const char *src, size_t len, enum iio_attr_type type) { struct iio_context_pdata *pdata = dev->ctx->pdata; return iiod_client_write_attr(pdata->iiod_client, &pdata->io_ctx, dev, NULL, attr, - src, len, is_debug); + src, len, type); } static ssize_t usb_read_chn_attr(const struct iio_channel *chn, diff --git a/xml.c b/xml.c index 51fdd5f74..fae5e75be 100644 --- a/xml.c +++ b/xml.c @@ -69,7 +69,7 @@ static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n) return -1; } -static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug) +static int add_attr_to_device(struct iio_device *dev, xmlNode *n, enum iio_attr_type type) { xmlAttr *attr; char **attrs, *name = NULL; @@ -88,22 +88,41 @@ static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug) goto err_free; } - if (is_debug) - attrs = realloc(dev->debug_attrs, - (1 + dev->nb_debug_attrs) * sizeof(char *)); - else - attrs = realloc(dev->attrs, - (1 + dev->nb_attrs) * sizeof(char *)); + switch(type) { + case IIO_ATTR_TYPE_DEBUG: + attrs = realloc(dev->debug_attrs, + (1 + dev->nb_debug_attrs) * sizeof(char *)); + break; + case IIO_ATTR_TYPE_DEVICE: + attrs = realloc(dev->attrs, + (1 + dev->nb_attrs) * sizeof(char *)); + break; + case IIO_ATTR_TYPE_BUFFER: + attrs = realloc(dev->buffer_attrs, + (1 + dev->nb_buffer_attrs) * sizeof(char *)); + break; + default: + attrs = NULL; + break; + } if (!attrs) goto err_free; - if (is_debug) { - attrs[dev->nb_debug_attrs++] = name; - dev->debug_attrs = attrs; - } else { - attrs[dev->nb_attrs++] = name; - dev->attrs = attrs; + switch(type) { + case IIO_ATTR_TYPE_DEBUG: + attrs[dev->nb_debug_attrs++] = name; + dev->debug_attrs = attrs; + break; + case IIO_ATTR_TYPE_DEVICE: + attrs[dev->nb_attrs++] = name; + dev->attrs = attrs; + break; + case IIO_ATTR_TYPE_BUFFER: + attrs[dev->nb_buffer_attrs++] = name; + dev->buffer_attrs = attrs; + break; } + return 0; err_free: @@ -254,10 +273,13 @@ static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n) chns[dev->nb_channels++] = chn; dev->channels = chns; } else if (!strcmp((char *) n->name, "attribute")) { - if (add_attr_to_device(dev, n, false) < 0) + if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEVICE) < 0) goto err_free_device; } else if (!strcmp((char *) n->name, "debug-attribute")) { - if (add_attr_to_device(dev, n, true) < 0) + if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEBUG) < 0) + goto err_free_device; + } else if (!strcmp((char *) n->name, "buffer-attribute")) { + if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_BUFFER) < 0) goto err_free_device; } else if (strcmp((char *) n->name, "text")) { WARNING("Unknown children \'%s\' in \n",