summaryrefslogtreecommitdiffstats
path: root/binding
diff options
context:
space:
mode:
authorclement benier <clement.benier@iot.bzh>2018-06-20 12:03:22 +0200
committercle©mentbeénier <clement.benier@iot.bzh>2018-06-21 14:23:38 +0200
commit11d7505b3318f44871eec69d214306608189ef43 (patch)
treef834effe7957bd718be040657528400e92d6e855 /binding
parent1fc63a30ca5bd00f0f6c9805f0ff0c0c7ac29c1e (diff)
add client_sub structure: split channel_fd structure into channel and client_sub
Change-Id: I1bd0cea12128ac3d78d6f4c4ee472cd74e69469d Signed-off-by: clement benier <clement.benier@iot.bzh>
Diffstat (limited to 'binding')
-rw-r--r--binding/iiodevices-binding.c491
1 files changed, 252 insertions, 239 deletions
diff --git a/binding/iiodevices-binding.c b/binding/iiodevices-binding.c
index 45d0f61..0bd692a 100644
--- a/binding/iiodevices-binding.c
+++ b/binding/iiodevices-binding.c
@@ -18,25 +18,26 @@
#include "config_iiodevices.h"
-/*structure in order to handle client_channels connections*/
-struct client_channels {
+/*structure in order to handle channels connections*/
+struct channels {
struct iio_channel *chn;
+ enum iio_elements iioelts;
+ char name[100];
+ struct channels *next;
+};
+
+/*handle client subscription*/
+struct client_sub {
+ struct channels *channels;
int index;
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;
+ struct client_sub *next;
};
/*gather all afb_event*/
@@ -44,14 +45,19 @@ struct event
{
struct event *next;
struct afb_event event;
- unsigned int nb_subscribers;
char tag[100];
};
+/*events*/
static struct event *events = 0;
+/*iio context*/
static struct iio_context *ctx = NULL;
-static struct s_channels channels = { NULL, 0 };
+/*clients*/
+static struct client_sub * clients = NULL;
+/*save last registered client*/
+static struct client_sub * last_client = NULL;
+/*get event by afb_event*/
static struct event *event_get_event(const struct afb_event *event)
{
struct event *e = events;
@@ -61,16 +67,6 @@ static struct event *event_get_event(const struct afb_event *event)
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)
{
@@ -100,7 +96,6 @@ static struct afb_event* event_add(const char *tag)
/* link */
e->next = events;
- e->nb_subscribers++;
events = e;
return &e->event;
}
@@ -111,25 +106,21 @@ static int event_del(struct afb_event *event)
struct event *e, **p;
/* check exists */
- e = event_get_event(event);
- if (!e) return -1;
+ 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;
+ /* unlink */
+ p = &events;
+ while(*p != e) p = &(*p)->next;
+ *p = e->next;
- /* destroys */
- afb_event_unref(e->event);
- free(e);
- }
+ /* destroys */
+ afb_event_unref(e->event);
+ free(e);
return 0;
}
+/*initialse iio context*/
int init_context()
{
ctx = iio_create_local_context();
@@ -141,26 +132,33 @@ int init_context()
return 0;
}
-static struct iio_device *init_dev(const char *dev_name)
+/*initialise device: find by its name*/
+static void init_dev(struct client_sub *client)
{
+ if(!client) {
+ AFB_ERROR("client is null");
+ return NULL;
+ }
+
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);
+ AFB_DEBUG("iio_context_find_device %s", client->infos->dev_name);
+ client->dev = iio_context_find_device(ctx, client->infos->dev_name);
+ if(!client->dev) {
+ AFB_ERROR("No %s device found", client->infos->dev_name);
return NULL;
}
- return dev;
}
-static int read_infos(struct client_channels *cl_chn)
+/*read static infos from channels*/
+static int read_infos(struct client_sub* client)
{
- if(!cl_chn) {
- AFB_ERROR("cl_chn is null");
+ if(!client || !client->channels || !client->channels->chn) {
+ AFB_ERROR("client=%p or client->channels=%p or client->channels->chn=%p is null", client, client->channels, client->channels->chn);
return -1;
}
- struct iio_channel *chn = cl_chn->chn;
- json_object *jobject = cl_chn->jobject;
+ struct iio_channel *chn = client->channels->chn;
+ json_object *jobject = client->jobject;
char val[100];
//read all infos
@@ -175,252 +173,226 @@ static int read_infos(struct client_channels *cl_chn)
return 0;
}
-static void deinit_channels(struct client_channels *cl_chn)
+/*close file descriptor*/
+static void close_fd(struct client_sub *client)
{
- if(!cl_chn || !channels.channels || channels.nb == 0) {
- AFB_ERROR("null pointer");
+ if(!client) {
+ AFB_ERROR("client is null pointer");
return;
}
- int i = 0;
- while(&channels.channels[i] != cl_chn->first) //looking for index matching cl_chn
- i++;
+ if(client->fd >= 0)
+ close(client->fd);
+}
- 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++;
+/*deinit client channels*/
+static void deinit_channels(struct client_sub *client)
+{
+ if(!client->channels) {
+ AFB_ERROR("client->channels is null pointer");
+ return;
}
- while(i < channels.nb - offset) { //move above all remained channels
- channels.channels[i] = channels.channels[i + offset + 1];
- i++;
+ struct channels *it_chn = client->channels;
+ while(it_chn) {
+ struct channels *tmp = it_chn->next;
+ AFB_DEBUG("free it_chn=%s", it_chn->name);
+ free(it_chn);
+ it_chn = tmp;
}
+ client->channels = NULL;
+}
- 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);
+/*looking for previous client: if client is first returns client*/
+static struct client_sub* looking_for_previous(struct client_sub *client)
+{
+ if(!client || !clients) {
+ AFB_ERROR("client or clients is null pointer");
+ return;
+ }
+ struct client_sub* prev = clients;
+ while(prev->next != client) {
+ prev = prev->next;
+ }
+ return prev;
}
-static void close_fd(struct client_channels *cl_chn)
+/*deinit client sub*/
+static void deinit_client_sub(struct client_sub *client)
{
- if(!cl_chn) {
- AFB_ERROR("null pointer");
+ if(!client) {
+ AFB_ERROR("client is null pointer");
return;
}
- close(cl_chn->fd);
+ struct client_sub *prev_client;
+ if(client == clients) {//first one
+ clients = client->next;
+ }
+ else {
+ prev_client = looking_for_previous(client);
+ if(!prev_client) {
+ AFB_ERROR("cannot find previous client");
+ exit(-1);
+ }
+ prev_client->next = client->next;
+ }
+ AFB_DEBUG("free client for %s", client->infos->id);
+ free(client);
}
+/*desallocate channels*/
static void desallocate_channels(sd_event_source* src,
- struct client_channels *cl_chn)
+ struct client_sub *client)
{
- afb_event_drop(*cl_chn->event);
+ afb_event_drop(*client->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);
+ close_fd(client);
+ event_del(client->event);
+ deinit_channels(client);
+ deinit_client_sub(client);
}
-static int read_data(struct client_channels *cl_chn, sd_event_source* src)
+/*!read data from channels*/
+static int read_data(struct client_sub *client, sd_event_source* src)
{
- if(!cl_chn) {
- AFB_ERROR("cl_chn is null");
+ if(!client) {
+ AFB_ERROR("client 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;
- while(p_cl_chn) {
- chn = p_cl_chn->chn;
- if(!chn) {
- AFB_ERROR("chn is null for cl_chn=%s", p_cl_chn->name);
+ char val[10];
+ struct channels *channel = client->channels;
+ while(channel) { //iterate on client channels
+ if(!channel->chn) {
+ AFB_ERROR("chn is null for cl_chn=%s", channel->name);
return -1;
}
- iio_channel_attr_read(chn, "raw", val, 10);
+
+ iio_channel_attr_read(channel->chn, "raw", val, 10);
int data = (int)strtol(val, NULL, 10);
- AFB_DEBUG("read_data: %s %d", iio_channel_get_id(chn), data);
+ AFB_DEBUG("read_data: %s %d", iio_channel_get_id(channel->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;
+ json_object_object_add(client->jobject, channel->name, value);
+ channel = channel->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);
+ int nb_subscribers = afb_event_push(*client->event, json_object_get(client->jobject));
+ AFB_DEBUG("nb_subscribers for %s is %d", afb_event_name(*client->event), nb_subscribers);
+ if(nb_subscribers <= 0)
+ desallocate_channels(src, client);
return 0;
}
+/*read data from file descriptor*/
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);
+ struct client_sub * client= (struct client_sub *)userdata;
+ read_data(client, src);
return 0;
}
+/*read data from timer*/
static int read_data_timer(sd_event_source* src, uint64_t usec, void *userdata)
{
- struct client_channels *cl_chn = (struct client_channels *)userdata;
+ struct client_sub *client = (struct client_sub *)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;
+ usecs += client->u_period;
sd_event_source_set_time(src, usecs);
- read_data(cl_chn, src);
+ read_data(client, src);
return 0;
}
-static void init_event_io(struct iio_device *dev, struct client_channels *cl_chn)
+/*init event io: depending on the frequency, if no filled, triggered on file
+ * descriptor */
+static void init_event_io(struct client_sub *client)
{
- if(!dev || !cl_chn) {
- AFB_ERROR("dev or cl_chn is null");
+ if(!client) {
+ AFB_ERROR("client is null");
return;
}
- read_infos(cl_chn); //get unchanged infos
+ read_infos(client); //get unchanged infos
sd_event_source *source = NULL;
- if(cl_chn->u_period <= 0) { //no given frequency
+ if(client->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) {
+ sprintf(filename, IIODEVICE"%s/%s", iio_device_get_id(client->dev),
+ iio_channel_attr_get_filename(client->channels->chn, "raw"));
+ if((client->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);
+ sd_event_add_io(afb_daemon_get_event_loop(), &source, client->fd, EPOLLIN, read_data_push, client);
}
- else {
- sd_event_add_time(afb_daemon_get_event_loop(), &source, CLOCK_MONOTONIC, 0, 1, read_data_timer, cl_chn);
+ else { //frequency specified
+ sd_event_add_time(afb_daemon_get_event_loop(), &source, CLOCK_MONOTONIC, 0, 1, read_data_timer, client);
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)
+/*initialise client channel*/
+static struct channels* set_channel(
+ struct client_sub* client, struct channels *prev_chn, const enum iio_elements i)
{
- 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;
+ prev_chn->next = malloc(sizeof(struct channels));
+ if(!prev_chn->next) {
+ AFB_ERROR("alloc failed for channels");
+ return;
+ }
+
+ struct channels *chn = prev_chn->next;
+ chn->next = NULL;
+ chn->iioelts = i;
/*set channel name with iio_elements*/
- strcpy(channel_name, first->infos->id);
- set_channel_name(channel_name, i);
+ strcpy(chn->name, client->infos->id);
+ set_channel_name(chn->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);
+ if(!(chn->chn = iio_device_find_channel(client->dev, chn->name, false))) {
+ AFB_ERROR("cannot find %s channel", chn->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];
- }
- 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;
+ iio_channel_enable(chn->chn);
+ return chn;
}
-static struct afb_event* is_allocation_needed(struct iio_info *infos,
- enum iio_elements *iioelts, struct client_channels **first)
+static void init_channel(struct client_sub* client, const unsigned int iioelts)
{
- 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)
-{
- if(!dev || !infos) {
- AFB_ERROR("dev=%p or infos=%p is null", dev, infos);
+ if(!client) {
+ AFB_ERROR("client is null");
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;
+ const char *name = client->infos->id;
+ AFB_DEBUG("size of channels=%d", get_iio_nb(iioelts));
+
+ /*looking for the last channel: could be the first*/
+ struct channels pre_index;
+ pre_index.next = client->channels;
+ struct channels *it_chn = &pre_index;
+ while(it_chn->next) {
+ it_chn = it_chn->next;
}
- 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;
- *first = &channels.channels[channels.nb];
- }
- else
- event_add_subscriber((*first)->event);
- channels.channels[channels.nb].first = *first;
-
- int index = 0;
+ /*set channel*/
for(int i = 1; i <= iioelts; i = i << 1) { //iterate on enumerations
if(i == (i & iioelts)) {
- set_channel(index, i, *first);
- index++;
+ it_chn = set_channel(client, it_chn, i);
}
}
- channels.nb = channels.nb + nb_iioelts;
+ client->channels = pre_index.next;
}
+/*get period in microseconds from a frequency*/
static uint64_t get_period(const char* freq)
{
double frequency = 0;
@@ -429,19 +401,66 @@ static uint64_t get_period(const char* freq)
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)
+/*check if it is needed to create a new client: if NULL return it is needed,
+ * else it is no needed but can be needed to add channels if rest_iioelts > 0*/
+static struct client_sub* is_new_client_sub_needed(struct iio_info* infos,
+ uint64_t u_period, enum iio_elements *rest_iioelts)
{
- if(channels.nb == 0)
- return true;
+ struct client_sub *it_client = clients;
+ while(it_client) {
+ if(it_client->infos == infos && u_period == it_client->u_period) {
+ AFB_DEBUG("a client is matching");
+ *rest_iioelts = ~it_client->iioelts & *rest_iioelts;
+ it_client->iioelts |= *rest_iioelts;
+ return it_client;
+ }
+ it_client = it_client->next;
+ }
+ return NULL;
+}
- 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;
+/*add new client with new event*/
+static struct client_sub *add_new_client(const struct iio_info *infos,
+ const enum iio_elements iioelts, const uint64_t u_period)
+{
+ struct client_sub *client = malloc(sizeof(struct client_sub));
+ if(!client) {
+ AFB_ERROR("cannot allocate client");
+ return NULL;
+ }
+ //initialise client
+ if(!clients) {
+ clients = client;
+ client->index = 0;
+ }
+ else {
+ if(!last_client) {
+ AFB_ERROR("last_client should not be null");
+ return NULL;
+ }
+ last_client->next = client;
+ client->index = last_client->index + 1;
}
- return true;
+
+ char event_name[100];
+ sprintf(event_name, "%s%d", infos->id, client->index);
+ AFB_DEBUG("add_new_client with event_name=%s", event_name);
+
+ client->channels = NULL;
+ client->jobject = json_object_new_object();
+ client->iioelts = iioelts;
+ client->u_period = u_period;
+ client->infos = infos;
+ client->fd = -1;
+ client->next = NULL;
+ client->dev = NULL;
+ client->event = event_add(event_name);
+
+ last_client = client;
+ return client;
}
+/*subscribe verb*/
static void subscribe(struct afb_req request)
{
const char *value = afb_req_value(request, "event");
@@ -457,35 +476,25 @@ static void subscribe(struct afb_req request)
value, s_iioelts, freq);
bool found = false;
- for(int i = 0; i < IIO_INFOS_SIZE; i++) {
+ for(int i = 0; i < sizeof(iio_infos)/sizeof(iio_infos[0]); i++) {
if(!strcasecmp(value, iio_infos[i].id)) {
found = true;
- struct iio_device *dev = init_dev(iio_infos[i].dev_name);
-
- uint64_t u_period = get_period( freq);
+ 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);
- if(!first) {
- AFB_ERROR("first is null");
- return;
- }
- init_event_io(dev, first);
- p_event = first->event;
+ struct client_sub* client = is_new_client_sub_needed(&iio_infos[i],
+ u_period, &iioelts);
+ if(!client || iioelts > 0) { //no client found or new channels
+ if(!client)
+ client = add_new_client(&iio_infos[i], iioelts, u_period);
+ init_dev(client);
+ init_channel(client, iioelts);
+ init_event_io(client);
}
- afb_req_context_set(request, first, NULL);
+ //stored client in order to be get in unsubscription
+ afb_req_context_set(request, client, NULL);
- if(afb_req_subscribe(request, *p_event) != 0) {
+ if(afb_req_subscribe(request, *client->event) != 0) {
afb_req_fail(request, "failed", "subscription failed");
return;
}
@@ -498,6 +507,7 @@ static void subscribe(struct afb_req request)
afb_req_success(request, NULL, NULL);
}
+/*unsubscribe verb*/
static void unsubscribe(struct afb_req request)
{
const char *value = afb_req_value(request, "event");
@@ -508,16 +518,17 @@ static void unsubscribe(struct afb_req request)
bool found = false;
if(value) {
- for(int i = 0; i < IIO_INFOS_SIZE; i++) {
+ for(int i = 0; i < sizeof(iio_infos)/sizeof(iio_infos[0]); i++) {
if(!strcasecmp(value, iio_infos[i].id)) {
found = true;
- struct client_channels *cl_chn = (struct client_channels *)afb_req_context_get(request);
- if(!cl_chn) {
+ struct client_sub *client
+ = (struct client_sub *)afb_req_context_get(request);
+ if(!client) {
AFB_ERROR("cannot find %s event, it seems that there was \
no subscription", value);
return;
}
- if(afb_req_unsubscribe(request, *cl_chn->event) != 0) {
+ if(afb_req_unsubscribe(request, *client->event) != 0) {
afb_req_fail(request, "failed", "unsubscription failed");
return;
}
@@ -531,12 +542,14 @@ static void unsubscribe(struct afb_req request)
afb_req_success(request, NULL, NULL);
}
+/*list of api verbs*/
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 }
};
+/*binding configuration*/
const afb_binding_v2 afbBindingV2 = {
.info = "iio devices service",
.api = "iiodevices",