summaryrefslogtreecommitdiffstats
path: root/sensors/orientationd
diff options
context:
space:
mode:
Diffstat (limited to 'sensors/orientationd')
-rw-r--r--sensors/orientationd/input.c335
-rw-r--r--sensors/orientationd/orientationd.c327
-rw-r--r--sensors/orientationd/orientationd.h86
-rw-r--r--sensors/orientationd/smb380.c85
-rw-r--r--sensors/orientationd/yas529.c85
5 files changed, 918 insertions, 0 deletions
diff --git a/sensors/orientationd/input.c b/sensors/orientationd/input.c
new file mode 100644
index 0000000..1afa2b8
--- /dev/null
+++ b/sensors/orientationd/input.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <linux/ioctl.h>
+#include <linux/input.h>
+#include <linux/uinput.h>
+
+#define LOG_TAG "orientationd"
+#include <utils/Log.h>
+
+#include "orientationd.h"
+
+void input_event_set(struct input_event *event, int type, int code, int value)
+{
+ if (event == NULL)
+ return;
+
+ memset(event, 0, sizeof(struct input_event));
+
+ event->type = type,
+ event->code = code;
+ event->value = value;
+
+ gettimeofday(&event->time, NULL);
+}
+
+long int timestamp(struct timeval *time)
+{
+ if (time == NULL)
+ return -1;
+
+ return time->tv_sec * 1000000000LL + time->tv_usec * 1000;
+}
+
+long int input_timestamp(struct input_event *event)
+{
+ if (event == NULL)
+ return -1;
+
+ return timestamp(&event->time);
+}
+
+int uinput_rel_create(const char *name)
+{
+ struct uinput_user_dev uinput_dev;
+ int uinput_fd;
+ int rc;
+
+ if (name == NULL)
+ return -1;
+
+ uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+ if (uinput_fd < 0) {
+ ALOGE("%s: Unable to open uinput device", __func__);
+ goto error;
+ }
+
+ memset(&uinput_dev, 0, sizeof(uinput_dev));
+
+ strncpy(uinput_dev.name, name, sizeof(uinput_dev.name));
+ uinput_dev.id.bustype = BUS_I2C;
+ uinput_dev.id.vendor = 0;
+ uinput_dev.id.product = 0;
+ uinput_dev.id.version = 0;
+
+ rc = 0;
+ rc |= ioctl(uinput_fd, UI_SET_EVBIT, EV_REL);
+ rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_X);
+ rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_Y);
+ rc |= ioctl(uinput_fd, UI_SET_RELBIT, REL_Z);
+ rc |= ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN);
+
+ if (rc < 0) {
+ ALOGE("%s: Unable to set uinput bits", __func__);
+ goto error;
+ }
+
+ rc = write(uinput_fd, &uinput_dev, sizeof(uinput_dev));
+ if (rc < 0) {
+ ALOGE("%s: Unable to write uinput device", __func__);
+ goto error;
+ }
+
+ rc = ioctl(uinput_fd, UI_DEV_CREATE);
+ if (rc < 0) {
+ ALOGE("%s: Unable to create uinput device", __func__);
+ goto error;
+ }
+
+ usleep(3000);
+
+ return uinput_fd;
+
+error:
+ if (uinput_fd >= 0)
+ close(uinput_fd);
+
+ return -1;
+}
+
+void uinput_destroy(int uinput_fd)
+{
+ if (uinput_fd < 0)
+ return;
+
+ ioctl(uinput_fd, UI_DEV_DESTROY);
+}
+
+int input_open(char *name)
+{
+ DIR *d;
+ struct dirent *di;
+
+ char input_name[80] = { 0 };
+ char path[PATH_MAX];
+ char *c;
+ int fd;
+ int rc;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ d = opendir("/dev/input");
+ if (d == NULL)
+ return -1;
+
+ while ((di = readdir(d))) {
+ if (di == NULL || strcmp(di->d_name, ".") == 0 || strcmp(di->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, PATH_MAX, "/dev/input/%s", di->d_name);
+ fd = open(path, O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ continue;
+
+ rc = ioctl(fd, EVIOCGNAME(sizeof(input_name) - 1), &input_name);
+ if (rc < 0)
+ continue;
+
+ c = strstr((char *) &input_name, "\n");
+ if (c != NULL)
+ *c = '\0';
+
+ if (strcmp(input_name, name) == 0)
+ return fd;
+ else
+ close(fd);
+ }
+
+ return -1;
+}
+
+int sysfs_path_prefix(char *name, char *path_prefix)
+{
+ DIR *d;
+ struct dirent *di;
+
+ char input_name[80] = { 0 };
+ char path[PATH_MAX];
+ char *c;
+ int fd;
+
+ if (name == NULL || path_prefix == NULL)
+ return -EINVAL;
+
+ d = opendir("/sys/class/input");
+ if (d == NULL)
+ return -1;
+
+ while ((di = readdir(d))) {
+ if (di == NULL || strcmp(di->d_name, ".") == 0 || strcmp(di->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, PATH_MAX, "/sys/class/input/%s/name", di->d_name);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ continue;
+
+ read(fd, &input_name, sizeof(input_name));
+ close(fd);
+
+ c = strstr((char *) &input_name, "\n");
+ if (c != NULL)
+ *c = '\0';
+
+ if (strcmp(input_name, name) == 0) {
+ snprintf(path_prefix, PATH_MAX, "/sys/class/input/%s", di->d_name);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int sysfs_value_read(char *path)
+{
+ char buffer[100];
+ int value;
+ int fd = -1;
+ int rc;
+
+ if (path == NULL)
+ return -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto error;
+
+ rc = read(fd, &buffer, sizeof(buffer));
+ if (rc <= 0)
+ goto error;
+
+ value = atoi(buffer);
+ goto complete;
+
+error:
+ value = -1;
+
+complete:
+ if (fd >= 0)
+ close(fd);
+
+ return value;
+}
+
+int sysfs_value_write(char *path, int value)
+{
+ char buffer[100];
+ int fd = -1;
+ int rc;
+
+ if (path == NULL)
+ return -1;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ goto error;
+
+ snprintf((char *) &buffer, sizeof(buffer), "%d\n", value);
+
+ rc = write(fd, buffer, strlen(buffer));
+ if (rc < (int) strlen(buffer))
+ goto error;
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (fd >= 0)
+ close(fd);
+
+ return rc;
+}
+
+int sysfs_string_read(char *path, char *buffer, size_t length)
+{
+ int fd = -1;
+ int rc;
+
+ if (path == NULL || buffer == NULL || length == 0)
+ return -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto error;
+
+ rc = read(fd, buffer, length);
+ if (rc <= 0)
+ goto error;
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (fd >= 0)
+ close(fd);
+
+ return rc;
+}
+
+int sysfs_string_write(char *path, char *buffer, size_t length)
+{
+ int fd = -1;
+ int rc;
+
+ if (path == NULL || buffer == NULL || length == 0)
+ return -1;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ goto error;
+
+ rc = write(fd, buffer, length);
+ if (rc <= 0)
+ goto error;
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (fd >= 0)
+ close(fd);
+
+ return rc;
+}
diff --git a/sensors/orientationd/orientationd.c b/sensors/orientationd/orientationd.c
new file mode 100644
index 0000000..e63e7c2
--- /dev/null
+++ b/sensors/orientationd/orientationd.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include <math.h>
+#include <linux/input.h>
+
+#include <hardware/sensors.h>
+#include <hardware/hardware.h>
+
+#define LOG_TAG "orientationd"
+#include <utils/Log.h>
+
+#include "orientationd.h"
+
+struct orientationd_handlers *orientationd_handlers[] = {
+ &smb380,
+ &yas529,
+};
+
+int orientationd_handlers_count = sizeof(orientationd_handlers) /
+ sizeof(struct orientationd_handlers *);
+
+static float rad2deg(float v)
+{
+ return (v * 180.0f / 3.1415926535f);
+}
+
+static float vector_scalar(sensors_vec_t *v, sensors_vec_t *d)
+{
+ return v->x * d->x + v->y * d->y + v->z * d->z;
+}
+
+static float vector_length(sensors_vec_t *v)
+{
+ return sqrtf(vector_scalar(v, v));
+}
+
+int orientation_calculate(struct orientationd_data *data)
+{
+ sensors_vec_t *a, *m, *o;
+ float azimuth, pitch, roll;
+ float la, sinp, cosp, sinr, cosr, x, y;
+
+ if (data == NULL)
+ return -EINVAL;
+
+ a = &data->acceleration;
+ m = &data->magnetic;
+ o = &data->orientation;
+
+ la = vector_length(a);
+ pitch = asinf(-(a->y) / la);
+ roll = asinf((a->x) / la);
+
+ sinp = sinf(pitch);
+ cosp = cosf(pitch);
+ sinr = sinf(roll);
+ cosr = cosf(roll);
+
+ y = -(m->x) * cosr + m->z * sinr;
+ x = m->x * sinp * sinr + m->y * cosp + m->z * sinp * cosr;
+ azimuth = atan2f(y, x);
+
+ o->azimuth = rad2deg(azimuth);
+ o->pitch = rad2deg(pitch);
+ o->roll = rad2deg(roll);
+
+ if (o->azimuth < 0)
+ o->azimuth += 360.0f;
+
+ return 0;
+}
+
+void *orientationd_thread(void *thread_data)
+{
+ struct orientationd_data *data;
+ struct input_event event;
+ struct timeval time;
+ long int before, after;
+ int diff;
+ int input_fd;
+ int rc;
+
+ if (thread_data == NULL)
+ return NULL;
+
+ data = (struct orientationd_data *) thread_data;
+
+ input_fd = data->input_fd;
+ if (input_fd < 0)
+ return NULL;
+
+ while (data->thread_continue) {
+ pthread_mutex_lock(&data->mutex);
+ if (!data->thread_continue)
+ break;
+
+ while (data->activated) {
+ gettimeofday(&time, NULL);
+ before = timestamp(&time);
+
+ rc = orientation_calculate(data);
+ if (rc < 0) {
+ ALOGE("%s: Unable to calculate orientation", __func__);
+ goto next;
+ }
+
+ input_event_set(&event, EV_REL, REL_X, (int) (data->orientation.azimuth * 1000));
+ write(input_fd, &event, sizeof(event));
+ input_event_set(&event, EV_REL, REL_Y, (int) (data->orientation.pitch * 1000));
+ write(input_fd, &event, sizeof(event));
+ input_event_set(&event, EV_REL, REL_Z, (int) (data->orientation.roll * 1000));
+ write(input_fd, &event, sizeof(event));
+ input_event_set(&event, EV_SYN, 0, 0);
+ write(input_fd, &event, sizeof(event));
+
+next:
+ gettimeofday(&time, NULL);
+ after = timestamp(&time);
+
+ diff = (int) (data->delay * 1000000 - (after - before)) / 1000;
+ if (diff <= 0)
+ continue;
+
+ usleep(diff);
+ }
+ }
+ return NULL;
+}
+
+int orientation_get_data(struct orientationd_data *data)
+{
+ struct input_event input_event;
+ int input_fd;
+ int activated;
+ unsigned int delay;
+ int rc;
+
+ if (data == NULL)
+ return -EINVAL;
+
+ input_fd = data->input_fd;
+ if (input_fd < 0)
+ return -1;
+
+ do {
+ rc = read(input_fd, &input_event, sizeof(input_event));
+ if (rc < (int) sizeof(input_event))
+ break;
+
+ if (input_event.type == EV_REL) {
+ switch (input_event.code) {
+ case REL_RZ:
+ data->activated = input_event.value & (1 << 16) ? 1 : 0;
+ data->delay = input_event.value & ~(1 << 16);
+
+ pthread_mutex_unlock(&data->mutex);
+ break;
+ default:
+ continue;
+ }
+ }
+ } while (input_event.type != EV_SYN);
+
+ return 0;
+}
+
+int orientationd_poll(struct orientationd_data *data)
+{
+ int count;
+ int i, j;
+ int rc;
+
+ if (data == NULL)
+ return -EINVAL;
+
+ ALOGD("Starting orientationd poll");
+
+ while (1) {
+ if (data->activated)
+ count = data->poll_fds_count;
+ else
+ count = 1;
+
+ rc = poll(data->poll_fds, count, -1);
+ if (rc < 0) {
+ ALOGE("%s: poll failure", __func__);
+ goto error;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (data->poll_fds[i].revents & POLLIN) {
+ data->poll_fds[i].revents = 0;
+
+ if (data->poll_fds[i].fd == data->input_fd) {
+ orientation_get_data(data);
+ continue;
+ }
+
+ for (j = 0; j < data->handlers_count; j++)
+ if (data->handlers[j] != NULL && data->handlers[j]->poll_fd == data->poll_fds[i].fd && data->handlers[j]->get_data != NULL)
+ data->handlers[j]->get_data(data->handlers[j], data);
+ }
+ }
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ return rc;
+}
+
+int main(int argc, char *argv[])
+{
+ struct orientationd_data *orientationd_data = NULL;
+ pthread_attr_t thread_attr;
+ int input_fd = -1;
+ int poll_fd;
+ int p, i;
+ int rc;
+
+ orientationd_data = (struct orientationd_data *)
+ calloc(1, sizeof(struct orientationd_data));
+ orientationd_data->handlers = orientationd_handlers;
+ orientationd_data->handlers_count = orientationd_handlers_count;
+ orientationd_data->activated = 0;
+ orientationd_data->poll_fds = (struct pollfd *)
+ calloc(1, (orientationd_handlers_count + 1) * sizeof(struct pollfd));
+
+ p = 0;
+
+ input_fd = input_open("orientation_sensor");
+ if (input_fd < 0) {
+ ALOGE("%s: Unable to open input", __func__);
+ goto error;
+ }
+
+ orientationd_data->input_fd = input_fd;
+
+ orientationd_data->poll_fds[p].fd = input_fd;
+ orientationd_data->poll_fds[p].events = POLLIN;
+ p++;
+
+ for (i = 0; i < orientationd_handlers_count; i++) {
+ if (orientationd_handlers[i] == NULL || orientationd_handlers[i]->input_name == NULL)
+ continue;
+
+ poll_fd = input_open(orientationd_handlers[i]->input_name);
+ if (poll_fd < 0) {
+ ALOGE("%s: Unable to open input %s", __func__, orientationd_handlers[i]->input_name);
+ continue;
+ }
+
+ orientationd_handlers[i]->poll_fd = poll_fd;
+ orientationd_data->poll_fds[p].fd = poll_fd;
+ orientationd_data->poll_fds[p].events = POLLIN;
+ p++;
+ }
+
+ orientationd_data->poll_fds_count = p;
+
+ orientationd_data->thread_continue = 1;
+
+ pthread_mutex_init(&orientationd_data->mutex, NULL);
+ pthread_mutex_lock(&orientationd_data->mutex);
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+ rc = pthread_create(&orientationd_data->thread, &thread_attr, orientationd_thread, (void *) orientationd_data);
+ if (rc < 0) {
+ ALOGE("%s: Unable to create orientationd thread", __func__);
+ goto error;
+ }
+
+ rc = orientationd_poll(orientationd_data);
+ if (rc < 0)
+ goto error;
+
+ rc = 0;
+ goto complete;
+
+error:
+ while (1)
+ sleep(3600);
+
+ rc = 1;
+
+complete:
+ if (input_fd >= 0)
+ close(input_fd);
+
+ if (orientationd_data != NULL) {
+ orientationd_data->thread_continue = 0;
+ pthread_mutex_destroy(&orientationd_data->mutex);
+
+ if (orientationd_data->poll_fds != NULL)
+ free(orientationd_data->poll_fds);
+
+ free(orientationd_data);
+ }
+
+ return rc;
+}
diff --git a/sensors/orientationd/orientationd.h b/sensors/orientationd/orientationd.h
new file mode 100644
index 0000000..887e698
--- /dev/null
+++ b/sensors/orientationd/orientationd.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <poll.h>
+#include <linux/input.h>
+
+#include <hardware/sensors.h>
+#include <hardware/hardware.h>
+
+#ifndef _ORIENTATIOND_H_
+#define _ORIENTATIOND_H_
+
+struct orientationd_data;
+
+struct orientationd_handlers {
+ char *input_name;
+ int handle;
+ int poll_fd;
+
+ int (*get_data)(struct orientationd_handlers *handlers,
+ struct orientationd_data *data);
+};
+
+struct orientationd_data {
+ struct orientationd_handlers **handlers;
+ int handlers_count;
+
+ struct pollfd *poll_fds;
+ int poll_fds_count;
+
+ sensors_vec_t orientation;
+ sensors_vec_t acceleration;
+ sensors_vec_t magnetic;
+
+ unsigned int delay;
+ int input_fd;
+
+ int activated;
+
+ pthread_t thread;
+ pthread_mutex_t mutex;
+ int thread_continue;
+};
+
+extern struct orientationd_handlers *orientationd_handlers[];
+extern int orientationd_handlers_count;
+
+/*
+ * Input
+ */
+
+void input_event_set(struct input_event *event, int type, int code, int value);
+long int timestamp(struct timeval *time);
+long int input_timestamp(struct input_event *event);
+int uinput_rel_create(const char *name);
+void uinput_destroy(int uinput_fd);
+int input_open(char *name);
+int sysfs_path_prefix(char *name, char *path_prefix);
+int sysfs_value_read(char *path);
+int sysfs_value_write(char *path, int value);
+int sysfs_string_read(char *path, char *buffer, size_t length);
+int sysfs_string_write(char *path, char *buffer, size_t length);
+
+/*
+ * Sensors
+ */
+
+extern struct orientationd_handlers smb380;
+extern struct orientationd_handlers yas529;
+
+#endif
diff --git a/sensors/orientationd/smb380.c b/sensors/orientationd/smb380.c
new file mode 100644
index 0000000..4566d94
--- /dev/null
+++ b/sensors/orientationd/smb380.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <linux/ioctl.h>
+#include <linux/input.h>
+
+#include <hardware/sensors.h>
+#include <hardware/hardware.h>
+
+#define LOG_TAG "orientationd"
+#include <utils/Log.h>
+
+#include "orientationd.h"
+
+float smb380_convert(int value)
+{
+ return value * (GRAVITY_EARTH / 256.0f);
+}
+
+int smb380_get_data(struct orientationd_handlers *handlers,
+ struct orientationd_data *data)
+{
+ struct input_event input_event;
+ int input_fd;
+ int rc;
+
+ if (handlers == NULL || data == NULL)
+ return -EINVAL;
+
+ input_fd = handlers->poll_fd;
+ if (input_fd < 0)
+ return -1;
+
+ do {
+ rc = read(input_fd, &input_event, sizeof(input_event));
+ if (rc < (int) sizeof(input_event))
+ break;
+
+ if (input_event.type == EV_REL) {
+ switch (input_event.code) {
+ case REL_X:
+ data->acceleration.x = smb380_convert(input_event.value);
+ break;
+ case REL_Y:
+ data->acceleration.y = smb380_convert(input_event.value);
+ break;
+ case REL_Z:
+ data->acceleration.z = smb380_convert(input_event.value);
+ break;
+ default:
+ continue;
+ }
+ }
+ } while (input_event.type != EV_SYN);
+
+ return 0;
+}
+
+struct orientationd_handlers smb380 = {
+ .input_name = "accelerometer_sensor",
+ .handle = SENSOR_TYPE_ACCELEROMETER,
+ .poll_fd = -1,
+ .get_data = smb380_get_data,
+};
diff --git a/sensors/orientationd/yas529.c b/sensors/orientationd/yas529.c
new file mode 100644
index 0000000..50b304d
--- /dev/null
+++ b/sensors/orientationd/yas529.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <linux/ioctl.h>
+#include <linux/input.h>
+
+#include <hardware/sensors.h>
+#include <hardware/hardware.h>
+
+#define LOG_TAG "orientationd"
+#include <utils/Log.h>
+
+#include "orientationd.h"
+
+float yas529_convert(int value)
+{
+ return value / 1000.0f;
+}
+
+int yas529_get_data(struct orientationd_handlers *handlers,
+ struct orientationd_data *data)
+{
+ struct input_event input_event;
+ int input_fd;
+ int rc;
+
+ if (handlers == NULL || data == NULL)
+ return -EINVAL;
+
+ input_fd = handlers->poll_fd;
+ if (input_fd < 0)
+ return -1;
+
+ do {
+ rc = read(input_fd, &input_event, sizeof(input_event));
+ if (rc < (int) sizeof(input_event))
+ break;
+
+ if (input_event.type == EV_REL) {
+ switch (input_event.code) {
+ case REL_X:
+ data->magnetic.x = yas529_convert(input_event.value);
+ break;
+ case REL_Y:
+ data->magnetic.y = yas529_convert(input_event.value);
+ break;
+ case REL_Z:
+ data->magnetic.z = yas529_convert(input_event.value);
+ break;
+ default:
+ continue;
+ }
+ }
+ } while (input_event.type != EV_SYN);
+
+ return 0;
+}
+
+struct orientationd_handlers yas529 = {
+ .input_name = "magnetic_sensor",
+ .handle = SENSOR_TYPE_MAGNETIC_FIELD,
+ .poll_fd = -1,
+ .get_data = yas529_get_data,
+};