/*
* Copyright (C) 2013 Paul Kocialkowski
*
* Orientation calculation based on AK8975_FS:
* Copyright (C) 2012 Asahi Kasei Microdevices Corporation, Japan
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "orientationd.h"
#include
#define ABS_CONTROL_REPORT (ABS_THROTTLE)
#define FLAG_X (1 << 0)
#define FLAG_Y (1 << 1)
#define FLAG_Z (1 << 2)
#define FLAG_ALL (FLAG_X | FLAG_Y | FLAG_Z)
struct sensor_device {
char *name;
int handle;
float (*get_data)(int value);
int (*set_data)(float value);
int fd;
};
struct sensor_data {
vector v;
int flags;
};
float rad2deg(float v)
{
return (v * 180.0f / 3.1415926535f);
}
void orientation_calculate(vector *a, vector *m, vector *o)
{
float azimuth, pitch, roll;
float la, sinp, cosp, sinr, cosr, x, y;
if (a == NULL || m == NULL || o == NULL)
return;
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->x = rad2deg(azimuth);
o->y = rad2deg(pitch);
o->z = rad2deg(roll);
if (o->x < 0)
o->x += 360.0f;
}
float bma250_acceleration(int value)
{
return (float) (value * GRAVITY_EARTH) / 256.0f;
}
float yas530c_magnetic(int value)
{
return (float) value / 1000.0f;
}
int yas_orientation(float value)
{
return (int) (value * 1000);
}
struct sensor_device bma250_device = {
.name = "accelerometer",
.handle = SENSOR_TYPE_ACCELEROMETER,
.get_data = bma250_acceleration,
.set_data = NULL,
.fd = -1,
};
struct sensor_device yas530c_device = {
.name = "geomagnetic",
.handle = SENSOR_TYPE_MAGNETIC_FIELD,
.get_data = yas530c_magnetic,
.set_data = NULL,
.fd = -1,
};
struct sensor_device yas_orientation_device = {
.name = "orientation",
.handle = SENSOR_TYPE_ORIENTATION,
.get_data = NULL,
.set_data = yas_orientation,
.fd = -1,
};
struct sensor_device *sensor_devices[] = {
&bma250_device,
&yas530c_device,
&yas_orientation_device,
};
int sensors_devices_count = sizeof(sensor_devices) / sizeof(struct sensor_device *);
int sensor_device_open(struct sensor_device *dev)
{
int fd;
if (dev == NULL || dev->name == NULL)
return -EINVAL;
printf("Opening %s\n", dev->name);
fd = input_open(dev->name, dev->handle == SENSOR_TYPE_ORIENTATION ? 1 : 0);
if (fd < 0)
return -1;
dev->fd = fd;
return 0;
}
void sensor_device_close(struct sensor_device *dev)
{
if (dev == NULL || dev->fd < 0)
return;
close(dev->fd);
dev->fd = -1;
}
struct sensor_device *sensor_device_find_handle(int handle)
{
int i;
for (i=0 ; i < sensors_devices_count ; i++) {
if (sensor_devices[i]->handle == handle)
return sensor_devices[i];
}
return NULL;
}
struct sensor_device *sensor_device_find_fd(int fd)
{
int i;
for (i=0 ; i < sensors_devices_count ; i++) {
if (sensor_devices[i]->fd == fd)
return sensor_devices[i];
}
return NULL;
}
int sensor_device_get_data(struct sensor_device *dev, struct sensor_data *d,
struct input_event *e)
{
if (dev == NULL || d == NULL || e == NULL || dev->get_data == NULL)
return -EINVAL;
if (e->type == EV_ABS) {
switch (e->code) {
case ABS_X:
d->v.x = dev->get_data(e->value);
d->flags |= FLAG_X;
return 0;
case ABS_Y:
d->v.y = dev->get_data(e->value);
d->flags |= FLAG_Y;
return 0;
case ABS_Z:
d->v.z = dev->get_data(e->value);
d->flags |= FLAG_Z;
return 0;
}
}
return -1;
}
int sensor_device_set_data(struct sensor_device *dev, struct sensor_data *d)
{
struct input_event event;
if (dev == NULL || d == NULL || dev->set_data == NULL)
return -EINVAL;
event.type = EV_ABS;
event.code = ABS_X;
event.value = dev->set_data(d->v.x);
gettimeofday(&event.time, NULL);
write(dev->fd, &event, sizeof(event));
event.type = EV_ABS;
event.code = ABS_Y;
event.value = dev->set_data(d->v.y);
gettimeofday(&event.time, NULL);
write(dev->fd, &event, sizeof(event));
event.type = EV_ABS;
event.code = ABS_Z;
event.value = dev->set_data(d->v.z);
gettimeofday(&event.time, NULL);
write(dev->fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
gettimeofday(&event.time, NULL);
write(dev->fd, &event, sizeof(event));
return 0;
}
int sensor_device_control(struct sensor_device *dev, struct input_event *e)
{
int enabled;
if (dev == NULL || e == NULL)
return -EINVAL;
if (e->type == EV_ABS && e->code == ABS_CONTROL_REPORT) {
enabled = e->value & (1 << 16);
if (enabled)
return 1;
else
return 0;
}
return -1;
}
int main(int argc, char *argv[])
{
struct input_event event;
struct sensor_data a, m, o;
struct sensor_device *dev;
struct pollfd *poll_fds;
int enabled, data;
int index;
int rc, c, i;
memset(&a, 0, sizeof(a));
memset(&m, 0, sizeof(m));
memset(&o, 0, sizeof(o));
poll_fds = (struct pollfd *) calloc(1, sizeof(struct pollfd) * sensors_devices_count);
index = -1;
c = 0;
for (i=0 ; i < sensors_devices_count ; i++) {
rc = sensor_device_open(sensor_devices[i]);
if (rc < 0)
continue;
poll_fds[c].fd = sensor_devices[i]->fd;
poll_fds[c].events = POLLIN;
if (sensor_devices[i]->handle == SENSOR_TYPE_ORIENTATION && index < 0)
index = c;
c++;
}
if (c <= 0 || index <= 0)
goto exit;
printf("Starting main loop\n");
enabled = 0;
while (1) {
data = 0;
if (enabled)
rc = poll(poll_fds, c, -1);
else
rc = poll(&poll_fds[index], 1, -1);
if (rc < 0)
goto exit;
for (i=0 ; i < c ; i++) {
if (poll_fds[i].revents & POLLIN) {
dev = sensor_device_find_fd(poll_fds[i].fd);
if (dev == NULL)
continue;
read(dev->fd, &event, sizeof(event));
switch (dev->handle) {
case SENSOR_TYPE_ACCELEROMETER:
rc = sensor_device_get_data(dev, &a, &event);
if (rc >= 0)
data = 1;
break;
case SENSOR_TYPE_MAGNETIC_FIELD:
rc = sensor_device_get_data(dev, &m, &event);
if (rc >= 0)
data = 1;
break;
case SENSOR_TYPE_ORIENTATION:
rc = sensor_device_control(dev, &event);
if (rc == 1)
enabled = 1;
else if (rc == 0)
enabled = 0;
break;
}
}
if (data && a.flags & FLAG_ALL && m.flags & FLAG_ALL) {
dev = sensor_device_find_handle(SENSOR_TYPE_ORIENTATION);
if (dev == NULL)
continue;
orientation_calculate(&a.v, &m.v, &o.v);
sensor_device_set_data(dev, &o);
}
}
}
exit:
for (i=0 ; i < sensors_devices_count ; i++)
sensor_device_close(sensor_devices[i]);
while (1) {
sleep(3600);
}
return 0;
}