OSDN Git Service

[Activity HAL] Added activity HAL source files
authorCristina Ciocan <cristina.ciocan@intel.com>
Tue, 10 Feb 2015 16:50:43 +0000 (18:50 +0200)
committerAdriana Reus <adriana.reus@intel.com>
Fri, 27 Feb 2015 16:25:16 +0000 (18:25 +0200)
The activity_event_entry file is the implementation of the activity recognition
HAL, as described in hardware/libhardware/include/hardware/activity_recognition.h .

In order to test the HAL, run the activity test program. Running activity
without parameters will list a summary of the program usage.

Change-Id: I1717c3882340ec40016f303880e55b0b9bba45f8
Signed-off-by: Cristina Ciocan <cristina.ciocan@intel.com>
Reviewed-on: https://android.intel.com:443/331750

Android.mk
Makefile
activity.c [new file with mode: 0644]
activity_event_entry.c [new file with mode: 0644]
activity_event_utils.h [new file with mode: 0644]
common.h
control.c
discovery.c

index 5021cdb..37dcf60 100644 (file)
@@ -48,4 +48,41 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libdl
 LOCAL_SRC_FILES := sens.c
 LOCAL_MODULE_TAGS := eng
 include $(BUILD_EXECUTABLE)
+
+endif
+
+
+# Activity HAL module implementation
+
+ifeq ($(USE_INTEL_ACTIVITY_RECOGNITION_HAL),true)
+
+include $(CLEAR_VARS)
+
+src_path := .
+activity_src_files := $(src_path)/activity_event_entry.c \
+                     $(src_path)/discovery.c \
+                     $(src_path)/utils.c \
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH) vendor/intel/hardware/iio-sensors
+LOCAL_MODULE := activity.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_OWNER := intel
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DLOG_TAG=\"Activity\" -fvisibility=hidden
+LOCAL_LDFLAGS := -Wl,--gc-sections
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_PRELINK_MODULE := false
+LOCAL_SRC_FILES := $(activity_src_files)
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES += $(LOCAL_PATH) vendor/intel/hardware/iio-sensors
+LOCAL_MODULE := activity
+LOCAL_CFLAGS := -DLOG_TAG=\"Activity\" -fvisibility=hidden
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdl
+LOCAL_SRC_FILES := activity.c
+LOCAL_MODULE_TAGS := eng
+include $(BUILD_EXECUTABLE)
+
 endif
index 8389e51..1a3d398 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,26 @@
 USE_INTEL_SENSOR_HAL := true
+USE_INTEL_ACTIVITY_RECOGNITION_HAL := true
 include Android.mk
 
 LIBHARDWARE?=../../../../hardware/libhardware/
 CFLAGS=-DLOG_TAG=\"sens\" -I$(LIBHARDWARE)include/ -I./linux -fPIC -Wall
 LDFLAGS=-ldl -lpthread -lm -lrt
 
-all: sensors.gmin.so sens
+all: sensors.gmin.so sens activity.gmin.so activity
 
 linux_src = linux/log.o
 
 sens: sens.o $(linux_src)
        cc -o $@ $^ $(LDFLAGS)
 
+activity: activity.o $(linux_src)
+       cc -o $@ $^ $(LDFLAGS)
+
 sensors.gmin.so: $(patsubst %.c,%.o,$(src_files) $(linux_src))
        cc -o $@ $^ $(LDFLAGS) -shared
 
+activity.gmin.so: $(patsubst %.c,%.o,$(activity_src_files) $(linux_src))
+       cc -o $@ $^ $(LDFLAGS) -shared
+
 clean:
-       -rm $(patsubst %.c,%.o,$(src_files) $(linux_src) sens.c) sens sensors.gmin.so 2>/dev/null
+       -rm $(patsubst %.c,%.o,$(src_files) $(activity_src_files) $(linux_src) sens.c activity.c) sens sensors.gmin.so activity activity.gmin.so 2>/dev/null
diff --git a/activity.c b/activity.c
new file mode 100644 (file)
index 0000000..55e0d9d
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2015 Intel Corporation.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <hardware/activity_recognition.h>
+#include <hardware/sensors.h>
+#include <utils/Log.h>
+
+#include "activity_event_utils.h"
+
+/* Return error codes */
+#define ARGV_ERR       1
+#define HAL_ACCESS_ERR 1
+#define HAL_OPEN_ERR   2
+#define HAL_SYMBOL_ERR 3
+
+#define START_CMD              "start"
+#define STOP_CMD               "stop"
+#define REGISTER_CMD           "register_callback"
+#define ENABLE_CMD             "enable"
+#define DISABLE_CMD            "disable"
+#define LIST_CMD               "list"
+#define FLUSH_CMD              "flush"
+#define MONITOR_START_CMD      "monitor_start"
+#define MONITOR_STOP_CMD       "monitor_stop"
+
+#define MAX_CMD_SIZE   512
+#define MAX_ARGS       8
+
+#define CMD_SEPARATOR  " "
+
+#define ACK_FLAG               1
+#define MONITOR_START_FLAG     2
+#define MONITOR_STOP_FLAG      3
+
+/* We define a default latency since current HAL does not use this latency */
+#define DEFAULT_LATENCY        0
+
+static struct activity_recognition_module *hmi;
+static struct hw_device_t *device;
+
+static FILE *client, *monitor_client;
+static int monitor_connection = -1;
+
+#ifdef ANDROID
+#define ACTIVITY_SERVER_NAME   "/dev/socket/activity-server"
+#else
+#define ACTIVITY_SERVER_NAME   "/tmp/activity-server"
+#endif
+
+#define CLIENT_ERR(f, fmt...)                                  \
+        { if (f) { fprintf(f, fmt); fprintf(f, "\n"); } ALOGE(fmt); }
+
+struct sockaddr_un server_addr = {
+       .sun_family     = AF_UNIX,
+       .sun_path       = ACTIVITY_SERVER_NAME,
+};
+
+/* Event types are indexed so that a type is positioned at an index represented
+ * by its value in the ACTIVITY_TYPE_* enum in activity_recognition.h .
+ */
+static const char* event_types[] = {
+       "FLUSH_COMPLETE",
+       "ENTER",
+       "EXIT",
+};
+
+static void dummy_activity_callback(const activity_recognition_callback_procs_t *procs __attribute((unused)),
+                                   const activity_event_t *events, int count)
+{
+       int i;
+
+       /* Exit if nobody is monitoring */
+       if (monitor_client == NULL)
+               return;
+
+       fprintf(monitor_client, "No. of activity events: %d\n", count);
+
+       for (i = 0; i < count; i++)
+               fprintf(monitor_client, "\t<activity [%d], event %s> occurred at %lld (ns)\n",
+                       events[i].activity,
+                       event_types[events[i].event_type],
+                       events[i].timestamp);
+}
+
+static activity_recognition_callback_procs_t dummy_callback_procs = {
+       .activity_callback = dummy_activity_callback
+};
+
+/* We register a dummy callback that just prints the events reported from HAL. */
+static void register_activity_callback(void)
+{
+       struct activity_recognition_device *activity_dev =
+               (struct activity_recognition_device *) device;
+
+       activity_dev->register_activity_callback(activity_dev, &dummy_callback_procs);
+}
+
+static int enable_activity_event(uint32_t handle, uint32_t event_type)
+{
+       struct activity_recognition_device *activity_dev =
+               (struct activity_recognition_device *) device;
+
+       return activity_dev->enable_activity_event(activity_dev, handle,
+                                                  event_type, DEFAULT_LATENCY);
+}
+
+static int disable_activity_event(uint32_t handle, uint32_t event_type)
+{
+       struct activity_recognition_device *activity_dev =
+               (struct activity_recognition_device*) device;
+
+       return activity_dev->disable_activity_event(activity_dev, handle, event_type);
+}
+
+static int flush(void)
+{
+       struct activity_recognition_device *activity_dev =
+               (struct activity_recognition_device *) device;
+
+       return activity_dev->flush(activity_dev);
+}
+
+static int print_usage(void)
+{
+       fprintf(stderr, "Program usage:\n");
+       fprintf(stderr, "\tactivity %s\n", START_CMD);
+       fprintf(stderr, "\tactivity %s\n", STOP_CMD);
+       fprintf(stderr, "\tactivity %s\n", REGISTER_CMD);
+       fprintf(stderr, "\tactivity %s\n", LIST_CMD);
+       fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", ENABLE_CMD);
+       fprintf(stderr, "\tactivity %s <activity_id> <event_type>\n", DISABLE_CMD);
+       fprintf(stderr, "\tactivity %s\n", FLUSH_CMD);
+       fprintf(stderr, "\tactivity %s\n", MONITOR_START_CMD);
+       fprintf(stderr, "\tactivity %s\n", MONITOR_STOP_CMD);
+       fprintf(stderr, "\t* <activity_id> is the index of the activity as shown by running \"activity list\"\n");
+       fprintf(stderr, "\t* <event_type> is one of the following:\n");
+       fprintf(stderr, "\t\t%d => activity event ENTER\n", ACTIVITY_EVENT_ENTER);
+       fprintf(stderr, "\t\t%d => activity event EXIT\n", ACTIVITY_EVENT_EXIT);
+       fprintf(stderr, "\t\t%d => activity event FLUSH COMPLETE\n", ACTIVITY_EVENT_FLUSH_COMPLETE);
+
+       return ARGV_ERR;
+}
+
+static int parse_cmd(char buffer[])
+{
+       char *tmp, *args[MAX_ARGS];
+       int count;
+
+       tmp = strtok(buffer, CMD_SEPARATOR);
+       count = 0;
+       while (tmp) {
+               args[count++]   = tmp;
+               tmp             = strtok(NULL, CMD_SEPARATOR);
+       }
+
+       if (!count) {
+               CLIENT_ERR(client, "Invalid command %s", buffer);
+               return -1;
+       }
+
+       if (strncmp(args[0], STOP_CMD, sizeof(STOP_CMD)) == 0) {
+               if (count != 1) {
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s'", STOP_CMD);
+               } else {
+                       fprintf(client, "Stopping server\n");
+                       fflush(client);
+               }
+
+               unlink(ACTIVITY_SERVER_NAME);
+
+               exit(EXIT_SUCCESS);
+       }
+
+       if (strncmp(args[0], LIST_CMD, sizeof(LIST_CMD)) == 0) {
+               const char * const* activities;
+               int size, i;
+
+               if (count != 1)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s'", LIST_CMD);
+               size = hmi->get_supported_activities_list(hmi, &activities);
+               if (client) {
+                       fprintf(client, "Activities list:\n");
+                       for (i = 0; i < size; i++)
+                               fprintf(client, "\t[%d] %s\n", i + 1, activities[i]);
+               }
+
+               return 0;
+       }
+
+       if (strncmp(args[0], REGISTER_CMD, sizeof(REGISTER_CMD)) == 0) {
+               if (count != 1)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s'", REGISTER_CMD);
+               register_activity_callback();
+
+               return 0;
+       }
+
+       if (strncmp(args[0], ENABLE_CMD, sizeof(ENABLE_CMD)) == 0) {
+               if (count > 3)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s %s %s'", ENABLE_CMD, args[1], args[2])
+               else if (count != 3) {
+                       CLIENT_ERR(client, "Insufficient arguments. Command should be \
+                                  'activity %s <activity_handle> <event_type>'", ENABLE_CMD);
+                       return -1;
+               }
+
+               return enable_activity_event(atoi(args[1]), atoi(args[2]));
+       }
+
+       if (strncmp(args[0], DISABLE_CMD, sizeof(DISABLE_CMD)) == 0) {
+               if (count > 3)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s %s %s'", DISABLE_CMD, args[1], args[2])
+               else if (count != 3) {
+                       CLIENT_ERR(client, "Insufficient arguments. Command should be \
+                                  'activity %s <activity_handle> <event_type>'", DISABLE_CMD);
+                       return -1;
+               }
+
+               return disable_activity_event(atoi(args[1]), atoi(args[2]));
+       }
+
+       if (strncmp(args[0], FLUSH_CMD, sizeof(FLUSH_CMD)) == 0) {
+               if (count != 1)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command down to \
+                                  'activity %s'", FLUSH_CMD);
+
+               return flush();
+       }
+
+       if (strncmp(args[0], MONITOR_START_CMD, sizeof(MONITOR_START_CMD)) == 0) {
+               if (count != 1)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command \
+                                  down to 'activity %s'", MONITOR_START_CMD);
+               return MONITOR_START_FLAG;
+       }
+
+       if (strncmp(args[0], MONITOR_STOP_CMD, sizeof(MONITOR_STOP_CMD)) == 0) {
+               if (count != 1)
+                       CLIENT_ERR(client, "Too many arguments. Trimming command \
+                                  down to 'activity %s'", MONITOR_STOP_CMD);
+               return MONITOR_STOP_FLAG;
+       }
+
+       CLIENT_ERR(client, "Invalid command %s", buffer);
+
+       return -1;
+}
+
+static void stop_monitoring(int *flag)
+{
+       int current_flag = ACK_FLAG;
+
+       /* Send ACK to client */
+       write(monitor_connection, &current_flag, sizeof(current_flag));
+
+       /* Cleanup */
+       fclose(monitor_client);
+       close(monitor_connection);
+       monitor_client          = NULL;
+       monitor_connection      = -1;
+
+       *flag = ACK_FLAG;
+}
+
+static void start_monitoring(int conn, int *flag)
+{
+       /* Stop other started monitor if that's the case */
+       if (monitor_client != NULL)
+               stop_monitoring(flag);
+
+       monitor_client          = client;
+       monitor_connection      = conn;
+       *flag                   = MONITOR_START_FLAG;
+
+}
+
+static void start_server(void)
+{
+       int sock, conn, ret;
+       int flag;
+
+       /* Just to make sure we do not have more than one server instance */
+       unlink(ACTIVITY_SERVER_NAME);
+
+       sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+       if (sock == -1) {
+               ALOGE("Error %s creating socket\n", strerror(errno));
+               exit(1);
+       }
+
+       ret = bind(sock, (struct sockaddr *) &server_addr, sizeof(server_addr));
+       if (ret == -1) {
+               ALOGE("Error %s binding socket\n", strerror(errno));
+               exit(1);
+       }
+
+       ret = listen(sock, 1);
+       if (ret == -1)
+               ALOGW("Error %s setting socket to listening state\n", strerror(errno));
+
+       /* Accept commands and send them to HAL */
+       while (1) {
+               char buffer[526], cmsg_buffer[526];
+               struct sockaddr_un from;
+               struct iovec recv_buff = {
+                       .iov_base       = buffer,
+                       .iov_len        = sizeof(buffer),
+               };
+               struct msghdr msg = {
+                       .msg_name       = &from,
+                       .msg_namelen    = sizeof(from),
+                       .msg_iov        = &recv_buff,
+                       .msg_iovlen     = 1,
+                       .msg_control    = cmsg_buffer,
+                       .msg_controllen = sizeof(cmsg_buffer),
+               };
+               struct cmsghdr *cmsg;
+               bool close_now = true;
+
+               conn = accept(sock, NULL, NULL);
+               if (conn == -1) {
+                       ALOGE("Error %s accepting connection\n", strerror(errno));
+                       continue;
+               }
+
+               ret = recvmsg(conn, &msg, 0);
+               if (ret == -1) {
+                       ALOGE("Error %s in receiving message, conn = %d\n", strerror(errno), conn);
+                       close(conn);
+
+                       continue;
+               }
+
+               if (!ret)
+                       continue;
+
+               /* Check for shutdown from the peer */
+               if (ret == 0)
+                       break;
+
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+                               int *received_fd = (int *)CMSG_DATA(cmsg);
+                               client = fdopen(*received_fd, "w");
+                               break;
+                       }
+               }
+
+               ret = parse_cmd(buffer);
+               if (ret < 0) {
+                       close(conn);
+                       continue;
+               }
+               if (ret == MONITOR_START_FLAG) {
+                       start_monitoring(conn, &flag);
+                       close_now = false;
+               } else if (ret == MONITOR_STOP_FLAG)
+                       stop_monitoring(&flag);
+               else
+                       flag = ACK_FLAG;
+
+               /* Confirm succesfull dispatch */
+               write(conn, &flag, sizeof(flag));
+
+               if (close_now) {
+                       fclose(client);
+                       close(conn);
+               }
+       }
+}
+
+static const char *hal_paths[] ={
+       "./activity.gmin.so",
+       "/lib/activity.gmin.so",
+       "/system/lib/hw/activity.gmin.so",
+};
+
+static int start_hal(void)
+{
+       void *hal;
+       int i, ret, no_paths;
+       const char *path = NULL;
+       pid_t child;
+
+       no_paths = sizeof(hal_paths)/sizeof(const char*);
+       for (i = 0; i < no_paths; i++) {
+               if (access(hal_paths[i], R_OK) == 0) {
+                       path = hal_paths[i];
+                       break;
+               }
+       }
+
+       if (!path) {
+               fprintf(stderr, "Unable to find HAL\n");
+               exit(1);
+       }
+
+       hal = dlopen(path, RTLD_NOW);
+       if (!hal) {
+               fprintf(stderr, "Error \"%s\" opening activity HAL\n", dlerror());
+               return HAL_OPEN_ERR;
+       }
+
+       hmi = dlsym(hal, HAL_MODULE_INFO_SYM_AS_STR);
+       if (!hmi) {
+               fprintf(stderr, "Error \"%s\" finding entry symbol\n", dlerror());
+               return HAL_SYMBOL_ERR;
+       }
+
+       printf("Activity HAL loaded: name %s vendor %s version %d.%d id %s\n",
+              hmi->common.name, hmi->common.author,
+              hmi->common.version_major, hmi->common.version_minor,
+              hmi->common.id);
+
+       /* Daemonize it */
+       child = fork();
+       if (child) {
+               usleep(100);
+               return 0;
+       }
+
+       if (setsid() == (pid_t)-1) {
+               fprintf(stderr, "failed to send process to background\n");
+               exit(1);
+       }
+
+       /* Close stdio */
+       close(0); close(1); close(2);
+
+       ALOGI("Proceeding to HAL initialization\n");
+
+       ret = hmi->common.methods->open((struct hw_module_t *) hmi,
+                                       ACTIVITY_RECOGNITION_HARDWARE_INTERFACE,
+                                       &device);
+       if (ret) {
+               ALOGE("Error %d occurred at HAL module opening\n", ret);
+               exit(1);
+       }
+
+       start_server();
+
+       return 0;
+}
+
+static int send_cmd(int argc, char **argv)
+{
+       char cmd[MAX_CMD_SIZE];
+       int i, sock, ret, flag;
+       struct iovec rcv_buffer = {
+               .iov_base       = cmd,
+               .iov_len        = sizeof(cmd) + 1,
+       };
+       struct cmsg_fd {
+               struct cmsghdr hdr;
+               int fd;
+       } cmsg_buff = {
+               .hdr = {
+                       .cmsg_level     = SOL_SOCKET,
+                       .cmsg_type      = SCM_RIGHTS,
+                       .cmsg_len       = CMSG_LEN(sizeof(int)),
+               },
+               .fd = 1,
+       };
+       struct msghdr msg = {
+               .msg_name       = NULL,
+               .msg_namelen    = 0,
+               .msg_iov        = &rcv_buffer,
+               .msg_iovlen     = 1,
+               .msg_control    = &cmsg_buff,
+               .msg_controllen = sizeof(cmsg_buff),
+       };
+
+       strcpy(cmd, argv[1]);
+       for (i = 2; i < argc; i++) {
+               strncat(cmd, CMD_SEPARATOR, sizeof(CMD_SEPARATOR));
+               strcat(cmd, argv[i]);
+       }
+
+       sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+       if (sock == -1) {
+               fprintf(stderr, "Error \"%s\" creating socket\n", strerror(errno));
+               return errno;
+       }
+
+       ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
+       if (ret == -1) {
+               fprintf(stderr, "Error \"%s\" connecting to server\n", strerror(errno));
+               return errno;
+       }
+
+       ret = sendmsg(sock, &msg, 0);
+       if (ret == -1) {
+               fprintf(stderr, "Error \"%s\" sending message to server\n", strerror(errno));
+               return errno;
+       }
+
+       ret = read(sock, &flag, sizeof(flag));
+       if (ret == -1) {
+               fprintf(stderr, "Error \"%s\" getting answer from server\n", strerror(errno));
+               return errno;
+       }
+
+       /* Check for ACK or monitoring */
+       if (flag == MONITOR_START_FLAG) {
+               do {
+                       ret = read(sock, &flag, sizeof(flag));
+               } while (ret > 0 && flag != ACK_FLAG);
+       } else if (flag != ACK_FLAG)
+               fprintf(stderr, "Error answer from HAL server: %d. Check logs for more details\n", flag);
+
+       close(sock);
+
+       return 0;
+}
+
+static int run_cmd(int argc, char **argv)
+{
+       if (strncmp(argv[1], START_CMD, sizeof(START_CMD)) == 0) {
+               if (argc == 2)
+                       return start_hal();
+               return print_usage();
+       }
+
+       /* Send user command to HAL server socket */
+       return send_cmd(argc, argv);
+}
+
+int main(int argc, char **argv)
+{
+       if (argc < 2)
+               return print_usage();
+
+       return run_cmd(argc, argv);
+}
diff --git a/activity_event_entry.c b/activity_event_entry.c
new file mode 100644 (file)
index 0000000..35e24e4
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This file represents the entry point for the activity recognition HAL module.
+ */
+
+#include <utils/Log.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <hardware/sensors.h>
+
+#include "common.h"
+#include "activity_event_utils.h"
+
+#define MODULE_VERSION         1
+#define HAL_VERSION            0
+
+#define MODULE_NAME            "Activity recognition HAL"
+#define MODULE_AUTHOR          "Intel"
+
+#define CONTROL_FD             (-1)
+#define EXIT_FD                        (-2)
+
+/*
+ * This table maps syfs entries in scan_elements directories to sensor types,
+ * and will also be used to determine other sysfs names as well as the iio
+ * device number associated to a specific sensor.
+ */
+sensor_catalog_entry_t sensor_catalog[] = {
+       {
+               .tag            = "activity",
+               .type           = SENSOR_TYPE_SIGNIFICANT_MOTION,
+               .num_channels   = 3,
+               .is_virtual     = 0,
+               .channel        = {
+                       {
+                               DECLARE_VOID_CHANNEL("still")
+                               .num_events = 2,
+                               .event = {
+                                       { DECLARE_GENERIC_EVENT("activity", "still", "thresh", "rising") },
+                                       { DECLARE_GENERIC_EVENT("activity", "still", "thresh", "falling") },
+                               },
+                       },
+                       {
+                               DECLARE_VOID_CHANNEL("walking")
+                               .num_events = 2,
+                               .event = {
+                                       { DECLARE_GENERIC_EVENT("activity", "walking", "thresh", "rising") },
+                                       { DECLARE_GENERIC_EVENT("activity", "walking", "thresh", "falling") },
+                               },
+                       },
+                       {
+                               DECLARE_VOID_CHANNEL("running")
+                               .num_events = 2,
+                               .event = {
+                                       { DECLARE_GENERIC_EVENT("activity", "running", "thresh", "rising") },
+                                       { DECLARE_GENERIC_EVENT("activity", "running", "thresh", "falling") },
+                               },
+                       },
+               },
+       },
+};
+
+unsigned int catalog_size = ARRAY_SIZE(sensor_catalog);
+
+/* All possible activities - see activity_recognition.h */
+static char const* sysfs_activity_names[MAX_ACTIVITIES] = {
+       "in_vehicle",
+       "on_bicycle",
+       "walking",
+       "running",
+       "still",
+       "tilting",
+};
+
+/* Internal HAL info */
+static struct activity_event_info supported_activities[MAX_ACTIVITIES + 1];
+/* Android framework level description (activities' name). The element on the
+ * first position (0) is reserved for the FLUSH COMPLETE event, thus we have
+ * (MAX_ACTIVITIES + 1) possible activities.
+ */
+static char const* supported_activity_names[MAX_ACTIVITIES + 1];
+/* Supported activities count */
+static unsigned int count;
+
+static int poll_fd, control_fd, exit_fd;
+static pthread_t control_thread;
+
+static activity_recognition_callback_procs_t activity_dev_callback;
+static pthread_mutex_t callback_mutex;
+
+static int instances_count;
+
+static void register_activity_callback(const struct activity_recognition_device *dev __attribute((unused)),
+                                      const activity_recognition_callback_procs_t* callback)
+{
+       pthread_mutex_lock(&callback_mutex);
+       activity_dev_callback.activity_callback = callback->activity_callback;
+       pthread_mutex_unlock(&callback_mutex);
+}
+
+static bool check_activity_event(uint32_t activity_handle, uint32_t event_type)
+{
+       if (activity_handle > count)
+               return false;
+
+       /* Also return false if the handle is 0 - this is reserved for flush
+        * event, that is currently not supported. */
+       if (activity_handle == 0)
+               return 0;
+
+       switch (event_type) {
+               case ACTIVITY_EVENT_ENTER:
+               case ACTIVITY_EVENT_EXIT:
+                       return true;
+               case ACTIVITY_EVENT_FLUSH_COMPLETE:
+                       /* Not supported yet */
+               default:
+                       return false;
+       }
+}
+
+static int set_activity_event_state(const struct activity_recognition_device *dev __attribute((unused)),
+                                   uint32_t activity_handle, uint32_t event_type,
+                                   char const *action)
+{
+       uint64_t control_code;
+       int ret;
+
+       /* Check received index boundaries */
+       if (!check_activity_event(activity_handle, event_type)) {
+               ALOGE("Received invalid <activity %d, event %d> %s request\n",
+                     activity_handle, event_type, action);
+               return -EINVAL;
+       }
+
+       control_code = get_control_code((uint8_t) 1,
+                                       (uint8_t) activity_handle,
+                                       (uint8_t) event_type);
+
+       ret = write(control_fd, &control_code, sizeof(control_code));
+       if (ret < 0) {
+               ALOGE("Error writing to control fd to %s activity event\n", action);
+               return errno;
+       }
+
+       ALOGI("Sent %s <%s, %i> request\n", action, supported_activity_names[activity_handle], event_type);
+
+       return 0;
+}
+
+static int enable_activity_event(const struct activity_recognition_device *dev,
+                                uint32_t activity_handle, uint32_t event_type,
+                                int64_t max_batch_report_latency_ns __attribute((unused)))
+{
+       return set_activity_event_state(dev, activity_handle, event_type, "enable");
+}
+
+static int disable_activity_event(const struct activity_recognition_device *dev,
+                                 uint32_t activity_handle, uint32_t event_type)
+{
+       return set_activity_event_state(dev, activity_handle, event_type, "disable");
+}
+
+/**
+ * For now, just report that the function call has been made, since we yet do
+ * not have a batch FIFO device.
+ */
+static int flush(const struct activity_recognition_device *dev __attribute((unused)))
+{
+       ALOGV("Flushing...\n");
+
+       return 0;
+}
+
+static void process_disabling_activity_ev(uint8_t activity, uint8_t event);
+
+static int close_device(struct hw_device_t *device __attribute((unused)))
+{
+       int j, ret, exit_ping;
+       unsigned int i;
+
+       if (!instances_count)
+               return -EINVAL;
+
+       instances_count--;
+
+       if (instances_count)
+               return 0;
+
+       /* Send exit request to the worker thread and close resources. We can
+        * write anything to the exit fd, we just need the event.
+        */
+       exit_ping = 1;
+       write(exit_fd, &exit_ping, sizeof(exit_ping));
+
+       /* Wait for worker thread to finish in order to release shared
+        * resources.
+        */
+       pthread_join(control_thread, NULL);
+
+       /* Close exit fd after sending the canceling request. */
+       ret = epoll_ctl(poll_fd, EPOLL_CTL_DEL, exit_fd, NULL);
+       if (ret == -1)
+               ALOGE("Error deleting exit fd from polling pool\n");
+       close(exit_fd);
+
+       /* Clean control data. */
+       ret = epoll_ctl(poll_fd, EPOLL_CTL_DEL, control_fd, NULL);
+       if (ret == -1)
+               ALOGE("Error deleting control fd from polling pool\n");
+       close(control_fd);
+
+       /* Disable all monitored <activity, event> pairs. This step should be
+        * the last one, after worker thread has ended in order to avoid
+        * supported_activities data corruption and avoid using another lock.
+        */
+       for (i = 1; i <= count; i++)
+               for (j = 0; j < MAX_EVENTS_PER_ACTIVITY; j++)
+                       if (supported_activities[i].monitored[j])
+                               process_disabling_activity_ev(
+                                                             (uint8_t) i,
+                                                             supported_activities[i].event[j]->event_type);
+
+       close(poll_fd);
+
+       pthread_mutex_destroy(&callback_mutex);
+
+       ALOGI("Successfully closed device\n");
+
+       return 0;
+}
+
+/*
+ * Finds the event given by type in the sensor's channel structure and retrieves
+ * its index.
+ * Equivalence (activity HAL naming - sensor HAL naming):
+ *     ACTIVITY_EVENT_ENTER - "rising"
+ *     ACTIVITY_EVENT_EXIT - "falling"
+ */
+static int get_ev_index(int ev_type, channel_descriptor_t *chann)
+{
+       int i;
+       char const *ev_dir;
+
+       switch (ev_type) {
+               case ACTIVITY_EVENT_ENTER:
+                       ev_dir = "rising";
+                       break;
+               case ACTIVITY_EVENT_EXIT:
+                       ev_dir = "falling";
+                       break;
+               default:
+                       ev_dir = NULL;
+                       return -1;
+       }
+
+       for (i = 0; i < chann->num_events; i++) {
+               if (strcmp(ev_dir, chann->event[i].dir) == 0)
+                       return i;
+       }
+
+       return -1;
+}
+
+static int set_event_enabling(int dev_num, const char *en_path, int value)
+{
+       char path[PATH_MAX];
+       int ret;
+
+       ret = snprintf(path, sizeof(EVENTS_PATH) + sizeof(en_path), EVENTS_PATH "%s", dev_num, en_path);
+       if (ret < 0)
+               return ret;
+
+       return sysfs_write_int(path, value);
+
+}
+
+static void process_enabling_activity_ev(uint8_t activity, uint8_t event)
+{
+       struct activity_event_info *activ = supported_activities + activity;
+       channel_descriptor_t *chann;
+       struct activity_event *ev;
+       char path[PATH_MAX];
+       struct epoll_event ev_data;
+       int dev_fd, ev_index, ret;
+       unsigned int i;
+       bool open_now = false;
+
+       /* Allocate event structure and populate it */
+       ev = malloc(sizeof(*ev));
+       if (!ev) {
+               ALOGE("Error allocating activity event for enabling\n");
+               return;
+       }
+
+       ev->event_type  = (uint32_t) event;
+       ev->activity    = (uint32_t) activity;
+       ev->timestamp   = -1;
+
+       /* The event fd is one per device, so we need to check if we have not
+        * retrieved it already when monitoring another <activity, event> pair.
+        * If it has not been retrieved, get it and update all other activities
+        * associated with the same device.
+        */
+       if (activ->event_fd == -1) {
+               ret = snprintf(path, sizeof(DEV_FILE_PATH), DEV_FILE_PATH, activ->dev_num);
+               if (ret < 0)
+                       goto dev_err;
+
+               dev_fd = open(path, O_RDONLY | O_NONBLOCK);
+               if (dev_fd < 0)
+                       goto dev_err;
+
+               ret = ioctl(dev_fd, IIO_GET_EVENT_FD_IOCTL, &activ->event_fd);
+               close(dev_fd);
+               if (ret < 0)
+                       goto dev_err;
+
+               open_now = true;
+
+               ev_data.events  = EPOLLIN;
+               ev_data.data.fd = activ->event_fd;
+               ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, activ->event_fd, &ev_data);
+               if (ret == -1)
+                       goto event_err;
+
+               /* Update all other activities generated by this device */
+               for (i = 1; i <= count; i++)
+                       if (supported_activities[i].dev_num == activ->dev_num)
+                               supported_activities[i].event_fd = activ->event_fd;
+       }
+
+       /* Activate the event */
+       chann = sensor_catalog[activ->sensor_catalog_index].channel + activ->channel_index;
+       ev_index = get_ev_index((int)event, chann);
+       if (ev_index < 0) {
+               ALOGE("Invalid event index: %d\n", ev_index);
+               goto event_err;
+       }
+       ret = set_event_enabling(activ->dev_num, chann->event[ev_index].ev_en_path, 1);
+       if (ret < 0)
+               goto event_err;
+
+       /* Internally mark that the <activity, event> pair is being monitored.
+        * We keep the same event index in our activity structure as is in the
+        * channel descriptor structure.
+        */
+       activ->event[ev_index]          = ev;
+       activ->monitored[ev_index]      = true;
+       activ->event_count++;
+
+       return;
+
+event_err:
+       if (open_now) {
+               close(activ->event_fd);
+               for (i = 1; i <= count; i++)
+                       if (supported_activities[i].dev_num == activ->dev_num)
+                               supported_activities[i].event_fd = -1;
+       }
+dev_err:
+       free(ev);
+}
+
+static bool device_not_monitored(int dev_num)
+{
+       unsigned int i;
+
+       for (i = 1; i <= count; i++)
+               if (supported_activities[i].dev_num == dev_num &&
+                   supported_activities[i].event_count > 0) {
+                       return false;
+               }
+
+       return true;
+}
+
+static void process_disabling_activity_ev(uint8_t activity, uint8_t event)
+{
+       struct activity_event_info *activ = supported_activities + activity;
+       channel_descriptor_t *chann;
+       int ev_index, ret;
+       unsigned int i;
+
+       /* Deactivate the event. */
+       chann = sensor_catalog[activ->sensor_catalog_index].channel + activ->channel_index;
+       ev_index = get_ev_index((int)event, chann);
+       if (ev_index < 0)
+               ALOGE("Invalid event index: %d\n", ev_index);
+       else {
+               ret = set_event_enabling(activ->dev_num, chann->event[ev_index].ev_en_path, 0);
+               if (ret < 0)
+                       ALOGE("Could not deactivate event - writing error\n");
+       }
+
+       /* Mark that the <activity, event> pair is not monitored any longer. */
+       activ->monitored[ev_index] = false;
+       activ->event_count--;
+
+       /* Close the event fd if this is the last pair monitored for the given
+        * device and remove it from the polling pool.
+        */
+       if (device_not_monitored(activ->dev_num)) {
+               ret = epoll_ctl(poll_fd, EPOLL_CTL_DEL, activ->event_fd, NULL);
+               if (ret == -1) {
+                       ALOGE("Error removing event fd from polling pool\n");
+                       return;
+               }
+
+               close(activ->event_fd);
+               for (i = 1; i <= count; i++)
+                       if (supported_activities[i].dev_num == activ->dev_num)
+                               supported_activities[i].event_fd = -1;
+       }
+
+       /* Free resources. */
+       free(activ->event[ev_index]);
+       activ->event[ev_index] = NULL;
+}
+
+static void process_control_event(void)
+{
+       struct control_event_data control_data;
+       uint64_t control_code;
+       ssize_t ret;
+
+       /* Read control data from the control fd and interpret it */
+       ret = read(control_fd, &control_code, sizeof(control_code));
+       if (ret < 0) {
+               ALOGW("Error reading from control fd\n");
+               return;
+       }
+
+       get_control_data(control_code, &control_data);
+
+       if (control_data.enable)
+               process_enabling_activity_ev(control_data.activity, control_data.event);
+       else
+               process_disabling_activity_ev(control_data.activity, control_data.event);
+}
+
+static int get_activity_index(int modifier)
+{
+       unsigned int i;
+
+       /* Start from 1 since 0 is reserved for FLUSH_COMPLETE event. */
+       for (i = 1; i <= count; i++)
+               if (supported_activities[i].modifier == modifier)
+                       return i;
+
+       return -1;
+}
+
+static void process_activity_event(int fd, struct activity_event events[], int *count)
+{
+       struct iio_event_data event;
+       int ret, chann_type, ev_type, ev_dir, ev_modifier, index, activity_index;
+
+       /* Retrieve event. */
+       ret = read(fd, &event, sizeof(event));
+       if (ret < 0) {
+               ALOGE("Error reading event\n");
+               return;
+       }
+
+       /* Extract fields we are interested in and check the generated event. */
+       chann_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event.id);
+       if (chann_type != IIO_ACTIVITY) {
+               ALOGW("Event came from other than an activity channel\n");
+               return;
+       }
+
+       ev_modifier = IIO_EVENT_CODE_EXTRACT_MODIFIER(event.id);
+       switch (ev_modifier) {
+               case IIO_MOD_STILL:
+               case IIO_MOD_WALKING:
+               case IIO_MOD_RUNNING:
+                       activity_index = get_activity_index(ev_modifier);
+                       if (activity_index >= 0)
+                               break;
+               default:
+                       ALOGW("Incompatible modifier - none of the supported activities is present\n");
+                       return;
+       }
+
+       ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event.id);
+       if (ev_type != IIO_EV_TYPE_THRESH) {
+               ALOGW("Event type is not threshold\n");
+               return;
+       }
+
+       ev_dir = IIO_EVENT_CODE_EXTRACT_DIR(event.id);
+       switch (ev_dir) {
+               case IIO_EV_DIR_RISING:
+                       ev_dir = ACTIVITY_EVENT_ENTER;
+                       break;
+               case IIO_EV_DIR_FALLING:
+                       ev_dir = ACTIVITY_EVENT_EXIT;
+                       break;
+               default:
+                       ALOGW("Incompatible event direction - only RISING and FALLING supported\n");
+                       return;
+       }
+
+       /* Add the activity event to the array for further processing. */
+       index = *count;
+       events[index].event_type        = ev_dir;
+       events[index].activity          = activity_index;
+       events[index].timestamp         = event.timestamp;
+
+       index++;
+       *count = index;
+}
+
+static void* events_routine(void *arg __attribute((unused)))
+{
+       struct epoll_event events[MAX_ACTIVITIES + 2];
+       struct activity_event data_events[MAX_ACTIVITIES];
+       int no_events, i, no_activity_events;
+
+       while (1) {
+               ALOGV("Waiting for sensor events ...\n");
+
+               no_activity_events = 0;
+               no_events = epoll_wait(poll_fd, events, MAX_ACTIVITIES + 2, -1);
+               if (no_events == -1) {
+                       ALOGE("epoll_wait error %s\n", strerror(errno));
+                       continue;
+               }
+
+               for (i = 0; i < no_events; i++)
+                       if (events[i].events == EPOLLIN) {
+                               int data = events[i].data.fd;
+
+                               if (data >= 0)
+                                       process_activity_event(data,
+                                                              data_events,
+                                                              &no_activity_events);
+                               else switch (data) {
+                                       case CONTROL_FD:
+                                               process_control_event();
+                                               break;
+                                       case EXIT_FD:
+                                               return NULL;
+                                       default:
+                                               ALOGW("Invalid event user data: %d \n", events[i].data.fd);
+                                               break;
+                               }
+                       } else
+                               ALOGW("Epoll events %i not expected\n", events[i].events);
+
+               /* Call the callback function for the retrieved events (if it
+                * has been set).
+                */
+               pthread_mutex_lock(&callback_mutex);
+               if (activity_dev_callback.activity_callback) {
+                       activity_dev_callback.activity_callback(
+                                                               &activity_dev_callback,
+                                                               data_events,
+                                                               no_activity_events);
+               }
+               pthread_mutex_unlock(&callback_mutex);
+       }
+}
+
+static int set_up_control_data(void)
+{
+       struct epoll_event control_ev, exit_ev;
+       int ret = 0;
+
+       ret = pthread_mutex_init(&callback_mutex, NULL);
+       if (ret)
+               return ret;
+
+       /* Maximum fds is maximum activities + 1 control fd + 1 exit fd */
+       poll_fd = epoll_create(MAX_ACTIVITIES + 2);
+       if (poll_fd == -1)
+               return errno;
+       if (ret)
+               goto poll_control_err;
+
+       control_fd = eventfd(0, 0);
+       if (control_fd == -1) {
+               ret = errno;
+               goto poll_control_err;
+       }
+
+       control_ev.events = EPOLLIN;
+       /* Set data field to event file descriptor */
+       control_ev.data.fd = CONTROL_FD;
+       ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, control_fd, &control_ev);
+       if (ret == -1)
+               goto control_data_err;
+
+       exit_fd = eventfd(0, 0);
+       if (exit_fd == -1) {
+               ALOGE("Error allocating exit fd\n");
+               goto exit_control_err;
+       }
+       exit_ev.events  = EPOLLIN;
+       exit_ev.data.fd = EXIT_FD;
+       ret = epoll_ctl(poll_fd, EPOLL_CTL_ADD, exit_fd, &exit_ev);
+       if (ret == -1) {
+               ALOGE("Error adding exit fd to the polling pool\n");
+               goto exit_err;
+       }
+
+       /* Start worker thread to wait on all event sources */
+       ret = pthread_create(&control_thread, NULL, events_routine, NULL);
+       if (ret)
+               goto thread_err;
+
+       return 0;
+
+thread_err:
+       epoll_ctl(poll_fd, EPOLL_CTL_DEL, exit_fd, NULL);
+exit_err:
+       close(exit_fd);
+exit_control_err:
+       epoll_ctl(poll_fd, EPOLL_CTL_DEL, control_fd, NULL);
+control_data_err:
+       close(control_fd);
+poll_control_err:
+       close(poll_fd);
+
+       return ret;
+}
+
+/* Returns the IIO_MOD_* equivalent to the given name. */
+static int get_modifier_as_int(const char* mod)
+{
+       if (strncmp(mod, "still", sizeof("still")) == 0)
+               return IIO_MOD_STILL;
+
+       if (strncmp(mod, "walking", sizeof("walking")) == 0)
+               return IIO_MOD_WALKING;
+
+       if (strncmp(mod, "running", sizeof("running")) == 0)
+               return IIO_MOD_RUNNING;
+
+       return -1;
+}
+
+static void add_activity(int sensor_catalog_index, int channel_index,
+                        int dev_num, const char *name)
+{
+       int index, i, modifier;
+
+       if (count == MAX_ACTIVITIES) {
+               ALOGE("Trying to add more than supported activities!\n");
+               return;
+       }
+
+       modifier = get_modifier_as_int(name);
+       if (modifier < 0) {
+               ALOGE("Invalid channel name as modifier: %s\n", name);
+               return;
+       }
+
+       index = ++count;
+
+       for (i = 0; i < MAX_EVENTS_PER_ACTIVITY; i++) {
+               supported_activities[index].event[i]            = NULL;
+               supported_activities[index].monitored[i]        = false;
+       }
+       supported_activities[index].modifier                    = modifier;
+       supported_activities[index].event_count                 = 0;
+       supported_activities[index].sensor_catalog_index        = sensor_catalog_index;
+       supported_activities[index].channel_index               = channel_index;
+       supported_activities[index].dev_num                     = dev_num;
+       supported_activities[index].event_fd                    = -1;
+
+       supported_activity_names[index] = name;
+}
+
+static bool is_activity_valid(const char *activity_name)
+{
+       unsigned int i;
+
+       /* Look if this activity has not been already added */
+       for (i = 1; i <= count; i++)
+               if (strcmp(supported_activity_names[i], activity_name) == 0)
+                       return false;
+
+       /* Check that the found activity is recognized by this API */
+       for (i = 0; i < MAX_ACTIVITIES; i++)
+               if (strcmp(sysfs_activity_names[i], activity_name) == 0)
+                       return true;
+
+       return false;
+}
+
+/* Get all possible activities provided by the IIO sensors */
+static void discover_activity_events(void)
+{
+       channel_descriptor_t *chann;
+       int i, num_channels, dev_num;
+       unsigned int index;
+       char event_sensors[catalog_size];
+
+       /* Discover event sensors */
+       for (dev_num = 0; dev_num < MAX_DEVICES; dev_num++) {
+               discover_sensors(dev_num, EVENTS_PATH, event_sensors, check_event_sensors);
+               for (index = 0; index < catalog_size; index++) {
+                       if (!event_sensors[index])
+                               continue;
+
+                       num_channels = sensor_catalog[index].num_channels;
+                       for (i = 0; i < num_channels; i++) {
+                               chann = sensor_catalog[index].channel + i;
+
+                               if (is_activity_valid(chann->name))
+                                       add_activity(index, i, dev_num, chann->name);
+                       }
+               }
+       }
+
+       ALOGI("Discovered %d activities\n", count);
+}
+
+static int open_module(const struct hw_module_t *module, const char *id,
+                      struct hw_device_t **device)
+{
+       static struct activity_recognition_device activity_dev;
+       int ret = 0;
+
+       if (strncmp(id, ACTIVITY_RECOGNITION_HARDWARE_INTERFACE, sizeof(ACTIVITY_RECOGNITION_HARDWARE_INTERFACE)) != 0)
+               return -EINVAL;
+
+       activity_dev.common.tag         = HARDWARE_DEVICE_TAG;
+       activity_dev.common.version     = ACTIVITY_RECOGNITION_API_VERSION_0_1;
+       activity_dev.common.module      = (struct hw_module_t *) module;
+       activity_dev.common.close       = close_device;
+
+       activity_dev.register_activity_callback = register_activity_callback;
+       activity_dev.enable_activity_event      = enable_activity_event;
+       activity_dev.disable_activity_event     = disable_activity_event;
+       activity_dev.flush                      = flush;
+
+       *device = &activity_dev.common;
+
+       if (instances_count == 0) {
+               discover_activity_events();
+               ret = set_up_control_data();
+
+               ALOGI("Initialized activity recognition HAL (exit code %i)\n", ret);
+       }
+
+       instances_count++;
+
+       return ret;
+}
+
+static struct hw_module_methods_t module_methods = {
+       .open = open_module
+};
+
+
+static int get_supported_activities_list(struct activity_recognition_module *module __attribute((unused)),
+                                        char const* const* *activity_list)
+{
+       *activity_list = supported_activity_names + 1;
+
+       return count;
+}
+
+/* Module descriptor visible to the Android framework. */
+struct activity_recognition_module __attribute__ ((visibility ("default")))
+       HAL_MODULE_INFO_SYM = {
+               .common = {
+                       .tag                    = HARDWARE_MODULE_TAG,
+                       .module_api_version     = MODULE_VERSION,
+                       .hal_api_version        = HAL_VERSION,
+                       .id                     = ACTIVITY_RECOGNITION_HARDWARE_MODULE_ID,
+                       .name                   = MODULE_NAME,
+                       .author                 = MODULE_AUTHOR,
+                       .methods                = &module_methods,
+               },
+               .get_supported_activities_list = get_supported_activities_list
+
+};
diff --git a/activity_event_utils.h b/activity_event_utils.h
new file mode 100644 (file)
index 0000000..e77d166
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Intel Corporation.
+ */
+
+#ifndef __ACTIVITY_EVENT_UTILS_H__
+#define __ACTIVITY_EVENT_UTILS_H__
+
+#include <hardware/activity_recognition.h>
+
+#include "utils.h"
+
+#define MAX_ACTIVITIES         6
+#define MAX_EVENTS_PER_ACTIVITY        2
+
+typedef unsigned bool;
+#define true   1
+#define false  0
+
+/* For each activity in activity_recognition.h we can monitor 2 events at most :
+ * ENTER and EXIT */
+struct activity_event_info {
+       struct activity_event   *event[MAX_EVENTS_PER_ACTIVITY];
+       int                     modifier;
+       int                     sensor_catalog_index;
+       int                     channel_index;
+       int                     dev_num;
+       int                     event_fd;
+       int                     event_count;
+       bool                    monitored[MAX_EVENTS_PER_ACTIVITY];
+};
+
+struct control_event_data {
+       uint8_t enable;
+       uint8_t activity;
+       uint8_t event;
+};
+
+/**
+ * Creates a control event identifier:
+ *     [unused]      EVENT      ACTIVITY   ENABLE
+ *     63 ... 24   23 ... 16    15 ... 8   7 ... 0
+ * @enable:    Says if the <activity, event> pair needs to be enabled or disabled (0 or 1)
+ * @activity:  What activity are we working on - index in the list returned by
+ *             get_supported_activities_list()
+ * @event:     What type of event to asociate with the given activity (one of
+ *             the ACTIVITY_EVENT_* enum)
+ */
+static inline uint64_t get_control_code(uint8_t enable, uint8_t activity, uint8_t event)
+{
+       return ((uint64_t)enable << 56) |
+               ((uint64_t)activity << 48) |
+               ((uint64_t)event << 40);
+}
+
+/**
+ * Parses the given control identifier and retrieves the control data.
+ * @control_code:      the unified control data
+ * @control_data:      extracted data from the control code
+ */
+static inline void get_control_data(uint64_t control_code,
+                                   struct control_event_data *control_data)
+{
+       control_data->enable    = (uint8_t)(control_code >> 56);
+       control_data->activity  = (uint8_t)(control_code >> 48 & 0xFF);
+       control_data->event     = (uint8_t)(control_code >> 40 & 0xFF);
+}
+
+#endif
index 809400b..757eab2 100644 (file)
--- a/common.h
+++ b/common.h
 #define MODE_TRIGGER   2
 #define MODE_EVENT     3
 
+
+/* Couple of temporary defines until we get a suitable linux/iio/events.h include */
+
+struct iio_event_data {
+         __u64   id;
+         __s64   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) & 0xCF)
+#define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
+#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
+
+/* Couple of temporary defines until we get a suitable linux/iio/types.h include */
+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_CALORIES,
+       IIO_DISTANCE,
+       IIO_SPEED,
+};
+
+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,
+};
+
+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_INSTANCE,
+};
+
+enum iio_event_info {
+       IIO_EV_INFO_ENABLE,
+       IIO_EV_INFO_VALUE,
+       IIO_EV_INFO_HYSTERESIS,
+       IIO_EV_INFO_PERIOD,
+};
+
+enum iio_event_direction {
+       IIO_EV_DIR_EITHER,
+       IIO_EV_DIR_RISING,
+       IIO_EV_DIR_FALLING,
+       IIO_EV_DIR_NONE,
+};
+
+
 typedef struct
 {
        const char *type; /* event type; e.g: transition */
index 34a8f06..b8fdeab 100644 (file)
--- a/control.c
+++ b/control.c
 #include "description.h"
 #include "filtering.h"
 
-/* Couple of temporary defines until we get a suitable linux/iio/events.h include */
-
-struct iio_event_data {
-         __u64   id;
-         __s64   timestamp;
-};
-
-#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
-
 /* Currently active sensors count, per device */
 static int poll_sensors_per_dev[MAX_DEVICES];          /* poll-mode sensors                            */
 static int trig_sensors_per_dev[MAX_DEVICES];          /* trigger, event based                         */
index 640c3f9..7434c33 100644 (file)
@@ -30,7 +30,7 @@ void discover_sensors(int dev_num, char *sysfs_base_path, char map[catalog_size]
        /* Enumerate entries in this iio device's base folder */
 
        while ((d = readdir(dir))) {
-               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+               if (!strncmp(d->d_name, ".", sizeof(".")) || !strncmp(d->d_name, "..", sizeof("..")))
                        continue;
 
                /* If the name matches a catalog entry, flag it */