iio: added event api
authorLay, Kuan Loon <kuan.loon.lay@intel.com>
Fri, 16 Oct 2015 01:18:32 +0000 (09:18 +0800)
committerBrendan Le Foll <brendan.le.foll@intel.com>
Tue, 15 Dec 2015 10:42:06 +0000 (10:42 +0000)
Signed-off-by: Lay, Kuan Loon <kuan.loon.lay@intel.com>
Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
api/mraa/iio.h [changed mode: 0644->0755]
api/mraa/iio_kernel_headers.h [new file with mode: 0755]
examples/iio_driver.c [changed mode: 0644->0755]
include/mraa_internal_types.h [changed mode: 0644->0755]
src/iio/iio.c [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 286a00f..a800f96
@@ -25,6 +25,7 @@
 #pragma once
 
 #include "common.h"
+#include "iio_kernel_headers.h"
 
 typedef struct {
     int index;
@@ -40,6 +41,11 @@ typedef struct {
     unsigned int location;
 } mraa_iio_channel;
 
+typedef struct {
+    char *name;
+       int enabled;
+} mraa_iio_event;
+
 /**
  * @file
  * @brief iio
@@ -96,6 +102,17 @@ mraa_result_t mraa_iio_write(mraa_iio_context dev, const char* attribute);
 
 mraa_result_t mraa_iio_get_channel_data(mraa_iio_context dev);
 
+mraa_result_t mraa_iio_get_event_data(mraa_iio_context dev);
+
+mraa_result_t mraa_iio_event_read(mraa_iio_context dev, const char* attribute, float* data);
+
+mraa_result_t mraa_iio_event_write(mraa_iio_context dev, const char* attribute, const char* data);
+
+mraa_result_t mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data);
+
+mraa_result_t mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args);
+
+mraa_result_t mraa_iio_event_extract_event(struct iio_event_data* event, int* chan_type, int* modifier, int* type, int* direction, int* channel, int* channel2, int* different);
 /**
  * De-inits an mraa_iio_context device
  *
diff --git a/api/mraa/iio_kernel_headers.h b/api/mraa/iio_kernel_headers.h
new file mode 100755 (executable)
index 0000000..5fbe81f
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Author: Lay, Kuan Loon <kuan.loon.lay@intel.com>
+ * Copyright (c) 2015 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+//For kernel 4.1+,
+//#include <linux/iio/types.h>
+//#include <linux/iio/events.h>
+
+//linux/iio/types.h
+enum iio_chan_type {
+        IIO_VOLTAGE,
+        IIO_CURRENT,
+        IIO_POWER,
+        IIO_ACCEL,
+        IIO_ANGL_VEL,
+        IIO_MAGN,
+        IIO_LIGHT,
+        IIO_INTENSITY,
+        IIO_PROXIMITY,
+        IIO_TEMP,
+        IIO_INCLI,
+        IIO_ROT,
+        IIO_ANGL,
+        IIO_TIMESTAMP,
+        IIO_CAPACITANCE,
+        IIO_ALTVOLTAGE,
+        IIO_CCT,
+        IIO_PRESSURE,
+        IIO_HUMIDITYRELATIVE,
+        IIO_ACTIVITY,
+        IIO_STEPS,
+        IIO_ENERGY,
+        IIO_DISTANCE,
+        IIO_VELOCITY,
+};
+
+enum iio_modifier {
+        IIO_NO_MOD,
+        IIO_MOD_X,
+        IIO_MOD_Y,
+        IIO_MOD_Z,
+        IIO_MOD_X_AND_Y,
+        IIO_MOD_X_AND_Z,
+        IIO_MOD_Y_AND_Z,
+        IIO_MOD_X_AND_Y_AND_Z,
+        IIO_MOD_X_OR_Y,
+        IIO_MOD_X_OR_Z,
+        IIO_MOD_Y_OR_Z,
+        IIO_MOD_X_OR_Y_OR_Z,
+        IIO_MOD_LIGHT_BOTH,
+        IIO_MOD_LIGHT_IR,
+        IIO_MOD_ROOT_SUM_SQUARED_X_Y,
+        IIO_MOD_SUM_SQUARED_X_Y_Z,
+        IIO_MOD_LIGHT_CLEAR,
+        IIO_MOD_LIGHT_RED,
+        IIO_MOD_LIGHT_GREEN,
+        IIO_MOD_LIGHT_BLUE,
+        IIO_MOD_QUATERNION,
+        IIO_MOD_TEMP_AMBIENT,
+        IIO_MOD_TEMP_OBJECT,
+        IIO_MOD_NORTH_MAGN,
+        IIO_MOD_NORTH_TRUE,
+        IIO_MOD_NORTH_MAGN_TILT_COMP,
+        IIO_MOD_NORTH_TRUE_TILT_COMP,
+        IIO_MOD_RUNNING,
+        IIO_MOD_JOGGING,
+        IIO_MOD_WALKING,
+        IIO_MOD_STILL,
+        IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
+};
+
+enum iio_event_type {
+        IIO_EV_TYPE_THRESH,
+        IIO_EV_TYPE_MAG,
+        IIO_EV_TYPE_ROC,
+        IIO_EV_TYPE_THRESH_ADAPTIVE,
+        IIO_EV_TYPE_MAG_ADAPTIVE,
+        IIO_EV_TYPE_CHANGE,
+};
+
+enum iio_event_direction {
+        IIO_EV_DIR_EITHER,
+        IIO_EV_DIR_RISING,
+        IIO_EV_DIR_FALLING,
+        IIO_EV_DIR_NONE,
+};
+
+//linux/iio/events.h
+#include <linux/ioctl.h>
+
+/**
+ * struct iio_event_data - The actual event being pushed to userspace
+ * @id:                event identifier
+ * @timestamp: best estimate of time of event occurrence (often from
+ *             the interrupt handler)
+ */
+struct iio_event_data {
+       unsigned long long int  id;
+       long long int   timestamp;
+};
+
+#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
+
+#define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
+
+#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F)
+
+#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
+
+/* Event code number extraction depends on which type of event we have.
+ * Perhaps review this function in the future*/
+#define IIO_EVENT_CODE_EXTRACT_CHAN(mask) ((short int)(mask & 0xFFFF))
+#define IIO_EVENT_CODE_EXTRACT_CHAN2(mask) ((short int)(((mask) >> 16) & 0xFFFF))
+
+#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
+#define IIO_EVENT_CODE_EXTRACT_DIFF(mask) (((mask) >> 55) & 0x1)
old mode 100644 (file)
new mode 100755 (executable)
index e2ca3e3..810a001
@@ -47,6 +47,7 @@ printword(uint16_t input, mraa_iio_channel *chan)
 }
 
 mraa_iio_context iio_device0;
+mraa_iio_context iio_device6;
 
 void
 interrupt(char* data)
@@ -65,6 +66,20 @@ interrupt(char* data)
     }
 }
 
+void event_interrupt(struct iio_event_data* data)
+{
+    int chan_type;
+    int modifier;
+    int type;
+    int direction;
+    int channel;
+    int channel2;
+    int different;
+    mraa_iio_event_extract_event(data, &chan_type, &modifier, &type, &direction, &channel, &channel2, &different);
+
+    printf("event time %lld id %lld extracted chan_type %d modifier %d type %d direction %d channel %d channel2 %d different %d\n", data->timestamp, data->id, chan_type, modifier, type, direction, channel, channel2, different);
+}
+
 int
 main()
 {
@@ -85,6 +100,25 @@ main()
         return EXIT_SUCCESS;
     }
 
+    /*
+    struct iio_event_data event;
+    iio_device6 = mraa_iio_init(6);
+    if (iio_device6 == NULL) {
+        return EXIT_FAILURE;
+    }
+    mraa_iio_event_write(iio_device6, "in_proximity2_thresh_either_en", "1");
+
+
+    // Blocking until event fired
+    if (mraa_iio_event_poll(iio_device6, &event) == MRAA_SUCCESS) {
+        event_interrupt(&event); //just to show data
+    }
+
+    if (mraa_iio_event_setup_callback(iio_device6, event_interrupt, NULL) == MRAA_SUCCESS) {
+        sleep(100);
+        return EXIT_SUCCESS;
+    }*/
+
     //! [Interesting]
     return EXIT_FAILURE;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 3eb54f8..70d4197
@@ -136,11 +136,15 @@ struct _iio {
     int num; /**< IIO device number */
     char* name; /**< IIO device name */
     int fp; /**< IIO device in /dev */
+    int fp_event;  /**<  event file descriptor for IIO device */
     void (* isr)(char* data); /**< the interupt service request */
     void *isr_args; /**< args return when interupt service request triggered */
+    void (* isr_event)(struct iio_event_data* data); /**< the event interupt service request */
     int chan_num;
     pthread_t thread_id; /**< the isr handler thread id */
     mraa_iio_channel* channels;
+    int event_num;
+    mraa_iio_event* events;
     int datasize;
 };
 
old mode 100644 (file)
new mode 100755 (executable)
index 366c4ed..8297ff5
@@ -33,6 +33,7 @@
 #define IIO_SCAN_ELEM "scan_elements"
 #define IIO_SLASH_DEV "/dev/"IIO_DEVICE
 #define IIO_SYSFS_DEVICE "/sys/bus/iio/devices/"IIO_DEVICE
+#define IIO_EVENTS "events"
 
 mraa_iio_context
 mraa_iio_init(int device)
@@ -42,6 +43,8 @@ mraa_iio_init(int device)
     }
 
     mraa_iio_get_channel_data(&plat_iio->iio_devices[device]);
+    mraa_iio_get_event_data(&plat_iio->iio_devices[device]);
+
     return &plat_iio->iio_devices[device];
 }
 
@@ -271,6 +274,191 @@ mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* ar
     return MRAA_SUCCESS;
 }
 
+mraa_result_t
+mraa_iio_get_event_data(mraa_iio_context dev)
+{
+    const struct dirent *ent;
+    DIR* dir;
+    int event_num = 0;
+    char buf[MAX_SIZE];
+    char readbuf[32];
+    int fd;
+    int ret = 0;
+    int padint = 0;
+    int curr_bytes = 0;
+    char shortbuf, signchar;
+    memset(buf, 0, MAX_SIZE);
+    snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS, dev->num);
+    dir = opendir(buf);
+    if (dir != NULL) {
+        while ((ent = readdir(dir)) != NULL) {
+            if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
+                event_num++;
+            }
+        }
+        dev->event_num = event_num;
+        mraa_iio_event* event;
+               dev->events = calloc(event_num, sizeof(mraa_iio_event));
+               if ( dev->events == NULL)
+               {
+                       closedir(dir);
+                       return MRAA_ERROR_UNSPECIFIED;
+               }
+               rewinddir(dir);
+               event_num = 0;
+               while ((ent = readdir(dir)) != NULL)
+               {
+            if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
+                               event = &dev->events[event_num];
+                event->name = strdup(ent->d_name);
+                               snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, ent->d_name);
+                               fd = open(buf, O_RDONLY);
+                               if (fd > 0) {
+                                       if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
+                                               break;
+                                       }
+                                       close(fd);
+                               }
+                event->enabled = ((int) strtol(readbuf, NULL, 10));
+                               //Todo, read other event info.
+                               event_num++;
+            }
+        }
+               closedir(dir);
+    }
+    return MRAA_SUCCESS;
+}
+
+mraa_result_t
+mraa_iio_event_read(mraa_iio_context dev, const char* attribute, float* data)
+{
+    char buf[64];
+    snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
+    int fd = open(buf, O_RDONLY);
+    if (fd != -1) {
+        int len = read(fd, &buf, 64);
+        *data = strtol(buf, NULL, 10);
+        return MRAA_SUCCESS;
+    }
+    return MRAA_ERROR_UNSPECIFIED;
+}
+
+mraa_result_t
+mraa_iio_event_write(mraa_iio_context dev, const char* attribute,  const char* data)
+{
+       int len;
+    char buf[128];
+    snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
+    int fd = open(buf, O_WRONLY);
+    if (fd != -1) {
+               int len = write(fd, data, ( strlen(data) +1 ));
+        return MRAA_SUCCESS;
+    }
+    return MRAA_ERROR_UNSPECIFIED;
+}
+
+static mraa_result_t
+mraa_iio_event_poll_nonblock(int fd, struct iio_event_data* data)
+{
+    struct pollfd pfd;
+
+    if (fd < 0) {
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
+
+    pfd.fd = fd;
+    pfd.events = POLLIN;
+
+    // Wait for it forever or until pthread_cancel
+    // poll is a cancelable point like sleep()
+    int x = poll(&pfd, 1, -1);
+
+    read(fd, data, sizeof(struct iio_event_data));
+
+    return MRAA_SUCCESS;
+}
+
+mraa_result_t
+mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data)
+{
+    char bu[MAX_SIZE];
+    int ret;
+       int event_fd;
+       int fd;
+
+       sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
+    fd = open(bu, 0);
+       ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
+       close(fd);
+
+       if (ret == -1 || event_fd == -1)
+               return MRAA_ERROR_UNSPECIFIED;
+
+       ret = read(event_fd, data, sizeof(struct iio_event_data));
+
+       close(event_fd);
+    return MRAA_SUCCESS;
+}
+
+static void*
+mraa_iio_event_handler(void* arg)
+{
+       struct iio_event_data data;
+    mraa_iio_context dev = (mraa_iio_context) arg;
+
+    for (;;) {
+        if (mraa_iio_event_poll_nonblock(dev->fp_event, &data) == MRAA_SUCCESS) {
+            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+            dev->isr_event(&data);
+            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+        } else {
+            // we must have got an error code so die nicely
+            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+            return NULL;
+        }
+    }
+}
+
+mraa_result_t
+mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args)
+{
+       int ret;
+    char bu[MAX_SIZE];
+    if (dev->thread_id != 0) {
+        return MRAA_ERROR_NO_RESOURCES;
+    }
+
+    sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
+    dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
+    if (dev->fp == -1) {
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
+       ret = ioctl(dev->fp, IIO_GET_EVENT_FD_IOCTL, &dev->fp_event);
+       close(dev->fp);
+
+       if (ret == -1 || dev->fp_event == -1)
+       {
+               return MRAA_ERROR_UNSPECIFIED;
+       }
+
+    dev->isr_event = fptr;
+    pthread_create(&dev->thread_id, NULL, mraa_iio_event_handler, (void*) dev);
+
+    return MRAA_SUCCESS;
+}
+
+mraa_result_t
+mraa_iio_event_extract_event(struct iio_event_data* event, int* chan_type, int* modifier, int* type, int* direction, int* channel, int* channel2, int* different)
+{
+       *chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
+       *modifier= IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
+       *type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
+       *direction = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
+       *channel = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
+       *channel2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
+       *different = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
+    return MRAA_SUCCESS;
+}
 #if 0
 // does stop make any sense on iio devices?
 mraa_result_t