From ed02e81650ab383f11622c42bb1bfdd125e511f1 Mon Sep 17 00:00:00 2001 From: Clément Bénier Date: Thu, 7 Jun 2018 12:43:27 +0200 Subject: binding iiodevices: handles 3 iiodevices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handle accel, magn et anglvel iiodevices args key indicates the desired coordinates at subcription frequency can be also specified at subscription Example for subscription: - iiodevices subscribe { "event": "accel", "uid": "1", "args": "xyz", "frequency": "0.1" } - iiodevices subscribe { "event": "magn", "uid": "1", "args": "xz", "frequency": "0.1" } Change-Id: I7f300f56b5d69506434f31fbb6e552c7afdf7489 Signed-off-by: Clément Bénier Signed-off-by: clement benier --- binding/CMakeLists.txt | 14 +- binding/accelero-binding.c | 167 ------------- binding/config_iiodevices.c | 51 ++++ binding/config_iiodevices.h | 28 +++ binding/iiodevices-binding.c | 571 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 656 insertions(+), 175 deletions(-) delete mode 100644 binding/accelero-binding.c create mode 100644 binding/config_iiodevices.c create mode 100644 binding/config_iiodevices.h create mode 100644 binding/iiodevices-binding.c (limited to 'binding') diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt index 05992ff..4731dc5 100644 --- a/binding/CMakeLists.txt +++ b/binding/CMakeLists.txt @@ -18,13 +18,15 @@ ########################################################################### # Add target to project dependency list -PROJECT_TARGET_ADD(accelero-binding) +PROJECT_TARGET_ADD(iiodevices-binding) # Define project Targets - set(accelero_SOURCES - accelero-binding.c) + set(iiodevices_SOURCES + iiodevices-binding.c + config_iiodevices.c + ) - add_library(${TARGET_NAME} MODULE ${accelero_SOURCES}) + add_library(${TARGET_NAME} MODULE ${iiodevices_SOURCES}) # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES @@ -36,7 +38,3 @@ PROJECT_TARGET_ADD(accelero-binding) # Library dependencies (include updates automatically) TARGET_LINK_LIBRARIES(${TARGET_NAME} ${link_libraries}) - - # installation directory - INSTALL(TARGETS ${TARGET_NAME} - LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) diff --git a/binding/accelero-binding.c b/binding/accelero-binding.c deleted file mode 100644 index d7f05e9..0000000 --- a/binding/accelero-binding.c +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#define AFB_BINDING_VERSION 2 -#include - -#define IIODEVICE "/sys/bus/iio/devices/iio:device" -#define IIODEVICE0 "/sys/bus/iio/devices/iio:device0/" -#define IIODEVICE1 "/sys/bus/iio/devices/iio:device1/" - -static struct afb_event accel_event; -static struct afb_event magn_event; -static struct afb_event anglvel_event; - -static pthread_t thread; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -static void get_buffer(const char *iio_file, const char *sub_name, - void *buffer, size_t count) -{ - int fd; - fd = open(iio_file, O_RDONLY); - if(fd < 0) { - AFB_ERROR("Cannot open %s\n", iio_file); - return; - } - if(read(fd, buffer, count) < 0){ - AFB_ERROR("cannot read %s\n", iio_file); - return; - } - close(fd); -} - -static void get_subdata_string(const char * iio_device_path, const char *sub_name, - json_object *jresp) { - char iio_file[100]; - sprintf(iio_file, "%s%s", iio_device_path, sub_name); - size_t buffer_size = 1000; - char buffer[buffer_size]; - - get_buffer(iio_file, sub_name, buffer, buffer_size); - - json_object *value = json_object_new_string(buffer); - if(jresp) - json_object_object_add(jresp, sub_name, value); -} - -static void get_subdata_int(const char * iio_device_path, const char *sub_name, - json_object *jresp) { - char iio_file[100]; - sprintf(iio_file, "%s%s", iio_device_path, sub_name); - AFB_INFO("iio_file=%s", iio_file); - size_t buffer_size = 1000; - char buffer[buffer_size]; - - get_buffer(iio_file, sub_name, buffer, buffer_size); - - json_object *value = json_object_new_int(atoi(buffer)); - if(jresp) - json_object_object_add(jresp, sub_name, value); -} - -static void get_data(const char *name, const int iio_device, json_object *jresp) { - char iio_device_path[100]; - sprintf(iio_device_path, IIODEVICE"%d/in_%s_", iio_device, name); - - get_subdata_string(iio_device_path, "scale", jresp); - get_subdata_string(iio_device_path, "scale_available", jresp); - get_subdata_int(iio_device_path, "x_raw", jresp); - get_subdata_int(iio_device_path, "y_raw", jresp); - get_subdata_int(iio_device_path, "z_raw", jresp); -} - -static int treat_event(const char *name, const int device_number, - struct afb_event event) -{ - json_object *jresp = json_object_new_object(); - get_data(name, device_number, jresp); - AFB_INFO("push event %s\n", name); - pthread_mutex_lock(&mutex); - afb_event_push(event, json_object_get(jresp)); - pthread_mutex_unlock(&mutex); - return 0; -} - -gboolean data_poll(gpointer ptr) -{ - AFB_INFO("data_poll"); - treat_event("accel", 0, accel_event); - treat_event("magn", 0, magn_event); - treat_event("anglvel", 1, anglvel_event); - return TRUE; -} - -static void *data_thread(void *ptr) -{ - g_timeout_add_seconds(1, data_poll, NULL); - g_main_loop_run(g_main_loop_new(NULL, FALSE)); - return NULL; -} - -static void subscribe(struct afb_req request) -{ - const char *value = afb_req_value(request, "event"); - if(value) { - if(!strcasecmp(value, "accel")) { - afb_req_subscribe(request, accel_event); - } else if(!strcasecmp(value, "magn")) { - afb_req_subscribe(request, magn_event); - } else if(!strcasecmp(value, "anglvel")) { - afb_req_subscribe(request, anglvel_event); - } else { - afb_req_fail(request, "failed", "Invalid event"); - return; - } - } - afb_req_success(request, NULL, NULL); -} - -static void unsubscribe(struct afb_req request) -{ - const char *value = afb_req_value(request, "value"); - if(value) { - if(!strcasecmp(value, "accel")) { - afb_req_unsubscribe(request, accel_event); - } else if(!strcasecmp(value, "magn")) { - afb_req_unsubscribe(request, magn_event); - } else { - afb_req_fail(request, "failed", "Invalid event"); - return; - } - } - afb_req_success(request, NULL, NULL); -} - -const afb_verb_v2 verbs[] = { - { .verb = "subscribe", .session = AFB_SESSION_NONE, .callback = subscribe, .info = "Subscribe for an event" }, - { .verb = "unsubscribe", .session = AFB_SESSION_NONE, .callback = unsubscribe, .info = "Unsubscribe for an event" }, - { .verb=NULL } -}; - -static int init() -{ - accel_event = afb_daemon_make_event("accel"); - magn_event = afb_daemon_make_event("magn"); - anglvel_event = afb_daemon_make_event("anglvel"); - - pthread_create(&thread, NULL, &data_thread, NULL); - - return 0; -} - -const afb_binding_v2 afbBindingV2 = { - .info = "accelero service", - .api = "accelero", - .verbs = verbs, - .init = init, -}; diff --git a/binding/config_iiodevices.c b/binding/config_iiodevices.c new file mode 100644 index 0000000..d8f9d9e --- /dev/null +++ b/binding/config_iiodevices.c @@ -0,0 +1,51 @@ +#include "config_iiodevices.h" + +#include +#include +#include + +#define AFB_BINDING_VERSION 2 +#include + +void set_channel_name(char *name, enum iio_elements iioelts) +{ + switch(iioelts) { + case X: + strcat(name, "_x"); break; + case Y: + strcat(name, "_y"); break; + case Z: + strcat(name, "_z"); break; + default: + AFB_WARNING("cannot set channel name, no matching iio_elements found: %d", iioelts); + } +} + +enum iio_elements treat_iio_elts(const char *iioelts_string) +{ + enum iio_elements iioelts = 0; + if(!iioelts_string || !strcasecmp(iioelts_string, "")) + iioelts = X | Y | Z; + else { + if(strchr(iioelts_string, 'x') || strchr(iioelts_string, 'X')) + iioelts = iioelts | X; + if(strchr(iioelts_string, 'y') || strchr(iioelts_string, 'Y')) + iioelts = iioelts | Y; + if(strchr(iioelts_string, 'z') || strchr(iioelts_string, 'Z')) + iioelts = iioelts | Z; + } + AFB_INFO("ENUMERATION::: %s %d", iioelts_string, iioelts); + return iioelts; +} + +int get_iio_nb(enum iio_elements iioelts) +{ + int nb_iioelts = 0; + int tmp_mask = 1; + while(tmp_mask <= iioelts) { //the number of channels is the number of elements + if((iioelts & tmp_mask) == tmp_mask) + nb_iioelts++; + tmp_mask = tmp_mask << 1; + } + return nb_iioelts; +} diff --git a/binding/config_iiodevices.h b/binding/config_iiodevices.h new file mode 100644 index 0000000..9e99045 --- /dev/null +++ b/binding/config_iiodevices.h @@ -0,0 +1,28 @@ +#ifndef _CONFIG_IIODEVICES_ +#define _CONFIG_IIODEVICES_ + +#include +#include + +#define IIODEVICE "/sys/bus/iio/devices/" + +struct iio_info { + const char *dev_name; + const char *id; +}; + +#define IIO_INFOS_SIZE 3 +static struct iio_info iio_infos[IIO_INFOS_SIZE] = { + { "16-001d", "accel"}, + { "16-001d", "magn"}, + { "16-006b", "anglvel"} +}; + +enum iio_elements { X = 1, Y = 2, Z = 4 }; + +void set_channel_name(char *name, enum iio_elements iioelts); +enum iio_elements treat_iio_elts(const char *iioelts_string); +enum iio_infos treat_iio_infos(const char *infos); +int get_iio_nb(enum iio_elements iioelts); + +#endif //_CONFIG_IIODEVICES_ diff --git a/binding/iiodevices-binding.c b/binding/iiodevices-binding.c new file mode 100644 index 0000000..cb233e2 --- /dev/null +++ b/binding/iiodevices-binding.c @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define AFB_BINDING_VERSION 2 +#include + +#include + +#include "config_iiodevices.h" + +/*structure in order to handle client_channels connections*/ +struct client_channels { + struct iio_channel *chn; + int index; + char uid[100]; + int fd; + uint64_t u_period; + enum iio_elements iioelts; + char name[100]; + struct iio_device *dev; + struct afb_event *event; + struct iio_info *infos; + json_object *jobject; + struct client_channels *first; + struct client_channels *next; +}; + +struct s_channels { + struct client_channels *channels; + unsigned int nb; +}; + +/*gather all afb_event*/ +struct event +{ + struct event *next; + struct afb_event event; + unsigned int nb_subscribers; + char tag[100]; +}; + +static struct event *events = 0; +static struct iio_context *ctx = NULL; +static struct s_channels channels = { NULL, 0 }; + +static struct event *event_get_event(const struct afb_event *event) +{ + struct event *e = events; + while(&e->event != event) { + e = e->next; + } + return e; +} + +static void event_add_subscriber(struct afb_event *event) +{ + struct event *e; + e = event_get_event(event); + if(e) + e->nb_subscribers++; + else + AFB_WARNING("event not found"); +} + +/* searchs the event of tag */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/* creates the event of tag */ +static struct afb_event* event_add(const char *tag) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return NULL; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return NULL; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_daemon_make_event(tag); + if (!e->event.closure) { free(e); return NULL; } + + /* link */ + e->next = events; + e->nb_subscribers++; + events = e; + return &e->event; +} + +/* deletes the event of event */ +static int event_del(struct afb_event *event) +{ + struct event *e, **p; + + /* check exists */ + e = event_get_event(event); + if (!e) return -1; + + e->nb_subscribers--; + if(e->nb_subscribers > 0) + return 0; + else { + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_unref(e->event); + free(e); + } + return 0; +} + +int init_context() +{ + ctx = iio_create_local_context(); + if(!ctx) + { + AFB_ERROR("cannot create local iio context"); + return -1; + } + return 0; +} + +static struct iio_device *init_dev(const char *dev_name) +{ + if(!ctx) + init_context(); + struct iio_device *dev = iio_context_find_device(ctx, dev_name); + if(!dev) { + AFB_ERROR("No %s device found", dev_name); + return NULL; + } + return dev; +} + +static int read_infos(struct client_channels *cl_chn) +{ + if(!cl_chn) { + AFB_ERROR("cl_chn is null"); + return -1; + } + struct iio_channel *chn = cl_chn->chn; + json_object *jobject = cl_chn->jobject; + char val[100]; + + //read all infos + for(int i = 0; i < iio_channel_get_attrs_count(chn); i++) { + const char *id_attr = iio_channel_get_attr(chn, i); + if(strcasecmp(id_attr, "raw")) { //do not take raw infos + iio_channel_attr_read(chn, id_attr, val, 100); + json_object *value = json_object_new_string(val); + json_object_object_add(jobject, id_attr, value); + } + } + return 0; +} + +static void deinit_channels(struct client_channels *cl_chn) +{ + if(!cl_chn || !channels.channels || channels.nb == 0) { + AFB_ERROR("null pointer"); + return; + } + + int i = 0; + while(&channels.channels[i] != cl_chn->first) //looking for index matching cl_chn + i++; + + int offset = 0; + while(channels.channels[i + offset].next) { //looking for number of channels a client + iio_channel_disable(channels.channels[i + offset].chn); + offset++; + } + + while(i < channels.nb - offset) { //move above all remained channels + channels.channels[i] = channels.channels[i + offset + 1]; + i++; + } + + channels.nb -= offset + 1; + channels.channels = realloc(channels.channels, channels.nb * sizeof(struct client_channels)); + + if(channels.nb == 0) + channels.channels = NULL; + AFB_DEBUG("deinit channel: size=%d", channels.nb); +} + +static void close_fd(struct client_channels *cl_chn) +{ + if(!cl_chn) { + AFB_ERROR("null pointer"); + return; + } + + close(cl_chn->fd); +} + +static void desallocate_channels(sd_event_source* src, + struct client_channels *cl_chn) +{ + afb_event_drop(*cl_chn->event); + if(src) { + sd_event_source_set_enabled(src, SD_EVENT_OFF); + sd_event_source_unref(src); + } + close_fd(cl_chn); + event_del(cl_chn->event); + deinit_channels(cl_chn); +} + +static int read_data(struct client_channels *cl_chn, sd_event_source* src) +{ + if(!cl_chn) { + AFB_ERROR("cl_chn is null"); + return -1; + } + struct iio_channel *chn = NULL; + json_object *jobject = cl_chn->jobject; + char val[10]; + + struct client_channels *p_cl_chn = cl_chn->first; + AFB_DEBUG("TOTOTO %p", p_cl_chn); + while(p_cl_chn) { + chn = p_cl_chn->chn; + if(!chn) { + AFB_ERROR("chn is null for cl_chn=%s", p_cl_chn->name); + return -1; + } + iio_channel_attr_read(chn, "raw", val, 10); + int data = (int)strtol(val, NULL, 10); + AFB_DEBUG("read_data: %s %d", iio_channel_get_id(chn), data); + json_object *value = json_object_new_int(data); + json_object_object_add(jobject, p_cl_chn->name, value); + p_cl_chn = p_cl_chn->next; + } + + /*if no more subscribers -> desallocate*/ + if(afb_event_push(*cl_chn->event, json_object_get(cl_chn->jobject)) <= 0) + desallocate_channels(src, cl_chn); + return 0; +} + +static int read_data_push(sd_event_source* src, int fd, uint32_t revents, void* userdata) +{ + struct client_channels *cl_chn = (struct client_channels *)userdata; + read_data(cl_chn, src); + return 0; +} + +static int read_data_timer(sd_event_source* src, uint64_t usec, void *userdata) +{ + struct client_channels *cl_chn = (struct client_channels *)userdata; + + /*set next time to trigger*/ + uint64_t usecs; + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usecs); + usecs += cl_chn->u_period; + sd_event_source_set_time(src, usecs); + + read_data(cl_chn, src); + return 0; +} + +static void init_event_io(struct iio_device *dev, struct client_channels *cl_chn) +{ + if(!dev || !cl_chn) { + AFB_ERROR("dev or cl_chn is null"); + return; + } + read_infos(cl_chn); //get unchanged infos + sd_event_source *source = NULL; + if(cl_chn->u_period <= 0) { //no given frequency + char filename[100]; + sprintf(filename, IIODEVICE"%s/%s", iio_device_get_id(dev), + iio_channel_attr_get_filename(cl_chn->chn, "raw")); + if((cl_chn->fd = open(filename, O_RDONLY)) < 0) { + AFB_ERROR("cannot open %s file", filename); + return; + } + + sd_event_add_io(afb_daemon_get_event_loop(), &source, cl_chn->fd, EPOLLIN, read_data_push, cl_chn); + } + else { + sd_event_add_time(afb_daemon_get_event_loop(), &source, CLOCK_MONOTONIC, 0, 1, read_data_timer, cl_chn); + sd_event_source_set_enabled(source, SD_EVENT_ON); + } +} + +/*initialise channel_fd*/ +static struct client_channels *set_channel(const int index, + enum iio_elements i, struct client_channels *first) +{ + int g_index = channels.nb + index; + char *channel_name = channels.channels[g_index].name; + + /*initialise structure*/ + channels.channels[g_index].infos = first->infos; + channels.channels[g_index].next = NULL; + channels.channels[g_index].first = first; + channels.channels[g_index].fd = -1; + channels.channels[g_index].iioelts = i; + channels.channels[g_index].index = first->index; + channels.channels[g_index].u_period = first->u_period; + channels.channels[g_index].jobject = first->jobject; + channels.channels[g_index].dev = first->dev; + + /*set channel name with iio_elements*/ + strcpy(channel_name, first->infos->id); + set_channel_name(channel_name, i); + + if(!(channels.channels[g_index].chn = iio_device_find_channel(first->dev, channel_name, false))) { + AFB_ERROR("cannot find %s channel", channel_name); + return NULL; + } + if(g_index > channels.nb) { + channels.channels[g_index].event = channels.channels[channels.nb].event; + channels.channels[g_index - 1].next = &channels.channels[g_index]; + strcpy(channels.channels[g_index].uid, first->uid); + } + iio_channel_enable(channels.channels[g_index].chn); + return &channels.channels[g_index]; +} + +static enum iio_elements get_all_iioets(struct client_channels *cl_chn) +{ + if(!cl_chn) { + AFB_ERROR("cl_chn is null"); + return 0; + } + enum iio_elements iioelts = 0; + struct client_channels *it_cl_chn = cl_chn->first; + while(it_cl_chn) { + iioelts |= it_cl_chn->iioelts; + it_cl_chn = it_cl_chn->next; + } + return iioelts; +} + +static struct afb_event* is_allocation_needed(struct iio_info *infos, + enum iio_elements *iioelts, struct client_channels **first) +{ + struct client_channels *cl_chn = channels.channels; + //check if already allocated + while(cl_chn) { + if(cl_chn->infos == infos) { + *iioelts = ~get_all_iioets(cl_chn) & *iioelts; + if(*iioelts == 0) { //iio elts already treated + AFB_DEBUG("iioelts is already treated"); + return cl_chn->event; + } + else { + *first = cl_chn->first; + } + break; + } + cl_chn += sizeof(struct client_channels); + } + return NULL; +} + +static void init_channel(struct iio_device *dev, + struct iio_info *infos, const int iioelts, struct client_channels **first, + const uint64_t u_period, const char* uid) +{ + if(!dev || !infos) { + AFB_ERROR("dev=%p or infos=%p is null", dev, infos); + return; + } + char event_name[100]; + const char *name = infos->id; + int nb_iioelts = get_iio_nb(iioelts); + + AFB_INFO("size of channels=%d", nb_iioelts); + channels.channels = realloc(channels.channels, (channels.nb + nb_iioelts) * sizeof(struct client_channels)); + if(!channels.channels) { + AFB_ERROR("alloc failed for channels"); + return; + } + + if(!*first) { //first channel for this client + int index_cl_chn + = channels.nb == 0 ? 0 : channels.channels[channels.nb - 1].index + 1; + sprintf(event_name, "%s%d", name, index_cl_chn); + channels.channels[channels.nb].index = index_cl_chn; + channels.channels[channels.nb].event = event_add(event_name); + channels.channels[channels.nb].jobject = json_object_new_object(); + channels.channels[channels.nb].u_period = u_period; + channels.channels[channels.nb].dev = dev; + channels.channels[channels.nb].infos = infos; + strcpy(channels.channels[channels.nb].uid, uid); + *first = &channels.channels[channels.nb]; + } + else + event_add_subscriber((*first)->event); + channels.channels[channels.nb].first = *first; + + int index = 0; + for(int i = 1; i <= iioelts; i = i << 1) { //iterate on enumerations + if(i == (i & iioelts)) { + set_channel(index, i, *first); + index++; + } + } + channels.nb = channels.nb + nb_iioelts; +} + +static uint64_t get_period(const char* freq) +{ + double frequency = 0; + if(freq) + frequency = strtod(freq, NULL); + return (frequency == 0) ? 0 : (uint64_t)((1.0 / frequency) * 1000000); +} + +static bool is_new_event_needed(struct iio_info *infos, const uint64_t u_period) +{ + if(channels.nb == 0) + return true; + + for(int i = 0; i < channels.nb; i++) { + if(channels.channels[i].infos == infos) + if(channels.channels[i].u_period == u_period) //no need for new event + return false; + } + return true; +} + +struct client_channels *looking_for_chn(struct iio_info *infos, const char* uid) +{ + struct client_channels *cl_chn = NULL; + int i = 0; + while(i < channels.nb) { + cl_chn = &channels.channels[i]; + if(!strcasecmp(uid, cl_chn->uid) && cl_chn->infos == infos) + return cl_chn; + i++; + } + return NULL; +} + +static bool is_uid_used(struct iio_info *infos, const char* uid) +{ + return looking_for_chn(infos, uid); +} + +static void subscribe(struct afb_req request) +{ + const char *value = afb_req_value(request, "event"); + const char *uid = afb_req_value(request, "uid"); + const char *s_iioelts = afb_req_value(request, "args"); + const char *freq = afb_req_value(request, "frequency"); + + if(!value || !uid || !s_iioelts) { + afb_req_fail(request, "failed", "please, fill 'event', 'uid' and 'args' fields"); + return; + } + + AFB_INFO("subscription with: value=%s, uid=%s, s_iioelts=%s, freq=%s", + value, uid, s_iioelts, freq); + + bool found = false; + for(int i = 0; i < IIO_INFOS_SIZE; i++) { + if(!strcasecmp(value, iio_infos[i].id)) { + found = true; + if(is_uid_used(&iio_infos[i], uid)) { + afb_req_fail(request, "failed", "uid is already used for this event, please changed"); + return; + } + + struct iio_device *dev = init_dev(iio_infos[i].dev_name); + + uint64_t u_period = get_period( freq); + enum iio_elements iioelts = (int)treat_iio_elts(s_iioelts); + + struct client_channels *first = NULL; + struct afb_event* p_event = NULL; + bool event_needed = is_new_event_needed(&iio_infos[i], u_period); + if(!event_needed) { + /*is new client_channel needed*/ + p_event = is_allocation_needed(&iio_infos[i], + &iioelts, &first); + } + if(!p_event || event_needed) { //new cl_chn or event_needed + init_channel(dev, &iio_infos[i], iioelts, &first, u_period, + uid); + if(!first) { + AFB_ERROR("first is null"); + return; + } + init_event_io(dev, first); + p_event = first->event; + } + + if(afb_req_subscribe(request, *p_event) != 0) { + afb_req_fail(request, "failed", "subscription failed"); + return; + } + } + } + if(!found) { + afb_req_fail(request, "failed", "Invalid event"); + return; + } + afb_req_success(request, NULL, NULL); +} + +static void unsubscribe(struct afb_req request) +{ + const char *value = afb_req_value(request, "event"); + const char *uid = afb_req_value(request, "uid"); + if(!value || !uid) { + afb_req_fail(request, "failed", "please, fill 'event', 'uid' fields"); + return; + } + + bool found = false; + if(value) { + for(int i = 0; i < IIO_INFOS_SIZE; i++) { + if(!strcasecmp(value, iio_infos[i].id)) { + found = true; + struct client_channels *cl_chn = looking_for_chn(&iio_infos[i], uid); + if(!cl_chn) { + AFB_ERROR("cannot find %s event with uid=%s", value, uid); + return; + } + if(afb_req_unsubscribe(request, *cl_chn->event) != 0) { + afb_req_fail(request, "failed", "unsubscription failed"); + return; + } + } + } + if(!found) { + afb_req_fail(request, "failed", "Invalid event"); + return; + } + } + afb_req_success(request, NULL, NULL); +} + +const afb_verb_v2 verbs[] = { + { .verb = "subscribe", .session = AFB_SESSION_NONE, .callback = subscribe, .info = "Subscribe for an event" }, + { .verb = "unsubscribe", .session = AFB_SESSION_NONE, .callback = unsubscribe, .info = "Unsubscribe for an event" }, + { .verb=NULL } +}; + +const afb_binding_v2 afbBindingV2 = { + .info = "iio devices service", + .api = "iiodevices", + .verbs = verbs +}; -- cgit 1.2.3-korg