2 * accelerometer - exports device orientation through property
4 * Copyright (C) 2011 Red Hat, Inc.
5 * Author: Bastien Nocera <hadess@hadess.net>
7 * orientation_calc() from the sensorfw package:
8 * Copyright (C) 2009-2010 Nokia Corporation
10 * Üstün Ergenoglu <ext-ustun.ergenoglu@nokia.com>
11 * Timo Rongas <ext-timo.2.rongas@nokia.com>
12 * Lihan Guo <lihan.guo@digia.com>
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with keymap; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32 #include <sys/types.h>
39 #include <linux/limits.h>
40 #include <linux/input.h>
43 #include "libudev-private.h"
45 /* we must use this kernel-compatible implementation */
46 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
47 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
48 #define OFF(x) ((x)%BITS_PER_LONG)
49 #define BIT(x) (1UL<<OFF(x))
50 #define LONG(x) ((x)/BITS_PER_LONG)
51 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
55 static void log_fn(struct udev *udev, int priority,
56 const char *file, int line, const char *fn,
57 const char *format, va_list args)
60 fprintf(stderr, "%s: ", fn);
61 vfprintf(stderr, format, args);
63 vsyslog(priority, format, args);
68 ORIENTATION_UNDEFINED,
70 ORIENTATION_BOTTOM_UP,
75 static const char *orientations[] = {
84 #define ORIENTATION_UP_UP ORIENTATION_NORMAL
86 #define DEFAULT_THRESHOLD 250
87 #define RADIANS_TO_DEGREES 180.0/M_PI
88 #define SAME_AXIS_LIMIT 5
90 #define THRESHOLD_LANDSCAPE 25
91 #define THRESHOLD_PORTRAIT 20
94 orientation_to_string (OrientationUp o)
96 return orientations[o];
100 string_to_orientation (const char *orientation)
104 if (orientation == NULL)
105 return ORIENTATION_UNDEFINED;
106 for (i = 0; orientations[i] != NULL; i++) {
107 if (strcmp (orientation, orientations[i]) == 0)
110 return ORIENTATION_UNDEFINED;
114 orientation_calc (OrientationUp prev,
118 OrientationUp ret = prev;
121 rotation = round(atan((double) x / sqrt(y * y + z * z)) * RADIANS_TO_DEGREES);
123 if (abs(rotation) > THRESHOLD_PORTRAIT) {
124 ret = (rotation < 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP;
126 /* Some threshold to switching between portrait modes */
127 if (prev == ORIENTATION_LEFT_UP || prev == ORIENTATION_RIGHT_UP) {
128 if (abs(rotation) < SAME_AXIS_LIMIT) {
134 /* Landscape check */
135 rotation = round(atan((double) y / sqrt(x * x + z * z)) * RADIANS_TO_DEGREES);
137 if (abs(rotation) > THRESHOLD_LANDSCAPE) {
138 ret = (rotation < 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL;
140 /* Some threshold to switching between landscape modes */
141 if (prev == ORIENTATION_BOTTOM_UP || prev == ORIENTATION_NORMAL) {
142 if (abs(rotation) < SAME_AXIS_LIMIT) {
153 get_prev_orientation(struct udev_device *dev)
157 value = udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER_ORIENTATION");
159 return ORIENTATION_UNDEFINED;
160 return string_to_orientation(value);
163 #define SET_AXIS(axis, code_) if (ev[i].code == code_) { if (got_##axis == 0) { axis = ev[i].value; got_##axis = 1; } }
166 static void test_orientation(struct udev *udev,
167 struct udev_device *dev,
170 OrientationUp old, new;
172 struct input_event ev[64];
174 int got_x, got_y, got_z;
175 int x = 0, y = 0, z = 0;
178 old = get_prev_orientation(dev);
180 if ((fd = open(devpath, O_RDONLY)) < 0)
183 got_x = got_y = got_z = 0;
188 r = read(fd, ev, sizeof(struct input_event) * 64);
190 if (r < (int) sizeof(struct input_event))
193 for (i = 0; i < r / (int) sizeof(struct input_event); i++) {
195 if (ev[i].type == EV_ABS) {
201 if (ev[i].type == EV_SYN && ev[i].code == SYN_REPORT) {
204 if (got_x && got_y && got_z)
212 if (!got_x || !got_y || !got_z)
215 new = orientation_calc(old, x, y, z);
216 snprintf(text, sizeof(text), "ID_INPUT_ACCELEROMETER_ORIENTATION=%s", orientation_to_string(new));
220 static void help(void)
222 printf("Usage: accelerometer [options] <device path>\n"
223 " --debug debug to stderr\n"
224 " --help print this help text\n\n");
227 int main (int argc, char** argv)
230 struct udev_device *dev;
232 static const struct option options[] = {
233 { "debug", no_argument, NULL, 'd' },
234 { "help", no_argument, NULL, 'h' },
238 char devpath[PATH_MAX];
241 struct udev_enumerate *enumerate;
242 struct udev_list_entry *list_entry;
248 udev_log_init("input_id");
249 udev_set_log_fn(udev, log_fn);
251 /* CLI argument parsing */
255 option = getopt_long(argc, argv, "dxh", options, NULL);
262 if (udev_get_log_priority(udev) < LOG_INFO)
263 udev_set_log_priority(udev, LOG_INFO);
273 if (argv[optind] == NULL) {
279 snprintf(devpath, sizeof(devpath), "%s/%s", udev_get_sys_path(udev), argv[optind]);
280 dev = udev_device_new_from_syspath(udev, devpath);
282 fprintf(stderr, "unable to access '%s'\n", devpath);
286 id_path = udev_device_get_property_value(dev, "ID_PATH");
287 if (id_path == NULL) {
288 fprintf (stderr, "unable to get property ID_PATH for '%s'", devpath);
292 /* Get the children devices and find the devnode
293 * FIXME: use udev_enumerate_add_match_children() instead
294 * when it's available */
296 enumerate = udev_enumerate_new(udev);
297 udev_enumerate_add_match_property(enumerate, "ID_PATH", id_path);
298 udev_enumerate_add_match_subsystem(enumerate, "input");
299 udev_enumerate_scan_devices(enumerate);
300 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
301 struct udev_device *device;
304 device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
305 udev_list_entry_get_name(list_entry));
308 /* Already found it */
309 if (devnode != NULL) {
310 udev_device_unref(device);
314 node = udev_device_get_devnode(device);
316 udev_device_unref(device);
319 /* Use the event sub-device */
320 if (strstr(node, "/event") == NULL) {
321 udev_device_unref(device);
325 devnode = strdup(node);
326 udev_device_unref(device);
329 if (devnode == NULL) {
330 fprintf(stderr, "unable to get device node for '%s'\n", devpath);
334 info(udev, "Opening accelerometer device %s\n", devnode);
335 test_orientation(udev, dev, devnode);