2 * HDAPS accelerometer sensor
4 * Copyright (C) 2011 The Android-x86 Open Source Project
6 * by Stefan Seidel <stefans@android-x86.org>
7 * Adaptation by Tanguy Pruvot <tpruvot@github>
9 * Licensed under GPLv2 or later
13 /* #define LOG_NDEBUG 0 */
14 #define LOG_TAG "HdapsSensors"
27 #include <linux/input.h>
29 #include <cutils/atomic.h>
30 #include <cutils/log.h>
31 #include <cutils/properties.h>
32 #include <hardware/sensors.h>
34 #define INPUT_DIR "/dev/input"
35 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
36 #define ID_ACCELERATION (SENSORS_HANDLE_BASE + 0)
38 #define AMIN(a,b) (((a)<(fabs(b)))?(a):(b))
39 #define SQUARE(x) ((x)*(x))
40 #define COS_ASIN(m,x) (sqrt(SQUARE(m)-SQUARE(AMIN(m,x))))
41 #define COS_ASIN_2D(m,x,y) (COS_ASIN(m,x)*COS_ASIN(m,y)/(m))
50 /* precision, result data should give GRAVITY_EARTH ~9.8 */
51 #define CONVERT (GRAVITY_EARTH / 156.0f)
52 #define CONVERT_PEGA (GRAVITY_EARTH / 256.0f)
53 #define CONVERT_LIS (GRAVITY_EARTH / 1024.0f)
55 /* axis swap for tablet pcs, X=0, Y=1, Z=2 */
56 #define NO_SWAP { 0, 1, 2 }
57 #define SWAP_YXZ { 1, 0, 2 }
58 #define SWAP_ZXY { 2, 0, 1 }
60 static accel_params accel_list[] = {
61 { "hdaps", { CONVERT, -CONVERT, 0 }, NO_SWAP, 1 },
62 { "Pegatron Lucid Tablet Accelerometer", { CONVERT_PEGA, CONVERT_PEGA, CONVERT_PEGA }, NO_SWAP, 4 },
63 // { "ST LIS3LV02DL Accelerometer", { -CONVERT_LIS, CONVERT_LIS, CONVERT_LIS }, SWAP_YXZ, 2 }, /* tablet mode */
64 { "ST LIS3LV02DL Accelerometer", { CONVERT_LIS, -CONVERT_LIS, CONVERT_LIS }, SWAP_ZXY, 2 }, /* pc mode */
67 static accel_params accelerometer;
68 static sensors_vec_t *events_q = NULL;
69 static int event_cnt = 0;
70 static unsigned int forced_delay = 0;
72 struct sensors_poll_context_t {
73 struct sensors_poll_device_1 device;
77 static int common__close(struct hw_device_t *dev) {
78 struct sensors_poll_context_t *ctx = (struct sensors_poll_context_t *) dev;
86 static int device__activate(struct sensors_poll_device_t *dev, int handle,
92 static int device__set_delay(struct sensors_poll_device_t *device, int handle,
94 forced_delay = ns / 1000;
99 static int device__poll(struct sensors_poll_device_t *device,
100 sensors_event_t *data, int count) {
102 struct input_event event;
103 struct sensors_poll_context_t *dev =
104 (struct sensors_poll_context_t *) device;
107 char prop[PROPERTY_VALUE_MAX] = "";
114 // dynamic axis tuning, expect "1,-1,-1" format
115 if (property_get("hal.sensors.axis.revert", prop, 0)) {
116 sscanf(prop, "%d,%d,%d", &x, &y, &z);
117 ALOGD("axis signs set to %d %d %d", x, y, z);
121 signs.conv[ABS_X] = accelerometer.conv[ABS_X] * x;
122 signs.conv[ABS_Y] = accelerometer.conv[ABS_Y] * y;
123 signs.conv[ABS_Z] = accelerometer.conv[ABS_Z] * z;
125 ALOGV("axis convert set to %.6f %.6f %.6f",
126 signs.conv[ABS_X], signs.conv[ABS_Y] ,signs.conv[ABS_Z]);
128 // dynamic axis swap, expect "0,1,2" format
129 if (property_get("hal.sensors.axis.order", prop, 0)) {
130 sscanf(prop, "%d,%d,%d", &x, &y, &z);
131 ALOGD("axis order set to %c %c %c", 'x'+x, 'x'+y, 'x'+z);
133 // use default values (accel_params)
134 x = accelerometer.swap[0];
135 y = accelerometer.swap[1];
136 z = accelerometer.swap[2];
139 while (read(dev->fd, &event, sizeof(event)) > 0) {
141 ALOGV("gsensor event %d - %d - %d", event.type, event.code, event.value);
143 if (event.type == EV_ABS) {
144 switch (event.code) {
145 // Even though this mapping results in wrong results with some apps,
146 // it just means that these apps are broken, i.e. they rely on the
147 // fact that phone have portrait displays. Laptops/tablets however
148 // have landscape displays, and the axes are relative to the default
149 // screen orientation, not relative to portrait orientation.
150 // See the nVidia Tegra accelerometer docs if you want to know for sure.
154 val = signs.conv[event.code] * event.value;
155 if (event.code == ABS_X)
156 events_q[event_cnt].v[x] = val;
157 else if (event.code == ABS_Y)
158 events_q[event_cnt].v[y] = val;
159 else if (event.code == ABS_Z)
160 events_q[event_cnt].v[z] = val;
163 } else if (event.type == EV_SYN) {
165 data->timestamp = (int64_t) ((int64_t) event.time.tv_sec
166 * 1000000000 + (int64_t) event.time.tv_usec * 1000);
167 // hdaps doesn't have z-axis, so simulate it by rotation matrix solution
168 if (signs.conv[2] == 0)
169 events_q[event_cnt].z = COS_ASIN_2D(GRAVITY_EARTH, events_q[event_cnt].x, events_q[event_cnt].y);
170 memset(&data->acceleration, 0, sizeof(sensors_vec_t));
171 for (i = 0; i < accelerometer.avg_cnt; ++i) {
172 data->acceleration.x += events_q[i].x;
173 data->acceleration.y += events_q[i].y;
174 data->acceleration.z += events_q[i].z;
176 data->sensor = ID_ACCELERATION;
177 data->type = SENSOR_TYPE_ACCELEROMETER;
178 data->acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
179 if (++event_cnt >= accelerometer.avg_cnt)
182 // spare the CPU if desired
184 usleep(forced_delay);
192 static int device__batch(struct sensors_poll_device_1* dev, int sensor_handle,
193 int flags, int64_t sampling_period_ns, int64_t max_report_latency_ns) {
194 ALOGD("%s: dev=%p sensor_handle=%d flags=%d sampling_period_ns=%" PRId64 " max_report_latency_ns=%" PRId64,
195 __FUNCTION__, dev, sensor_handle, flags, sampling_period_ns, max_report_latency_ns);
196 forced_delay = sampling_period_ns / 1000;
200 static int device__flush(struct sensors_poll_device_1* dev, int sensor_handle) {
201 ALOGD("%s: dev=%p sensor_handle=%d", __FUNCTION__, dev, sensor_handle);
205 static int open_input_device(void) {
212 dir = opendir(INPUT_DIR);
216 strcpy(devname, INPUT_DIR);
217 filename = devname + strlen(devname);
220 while ((de = readdir(dir))) {
223 if (de->d_name[0] == '.')
225 strcpy(filename, de->d_name);
226 f = open(devname, O_RDONLY);
231 if (ioctl(f, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
235 ALOGV("%s name is %s", devname, name);
237 for (i = 0; i < ARRAY_SIZE(accel_list); ++i) {
238 if (!strcmp(name, accel_list[i].name)) {
239 int c = accel_list[i].avg_cnt;
240 memcpy(&accelerometer, &accel_list[i], sizeof(accel_params));
241 accelerometer.conv[0] = accel_list[i].conv[0] / c;
242 accelerometer.conv[1] = accel_list[i].conv[1] / c;
243 accelerometer.conv[2] = accel_list[i].conv[2] / c;
244 events_q = calloc(c, sizeof(sensors_vec_t));
245 ALOGI("found %s at %s", name, devname);
260 static const struct sensor_t sSensorList[] = {
261 { .name = "HDAPS accelerometer",
262 .vendor = "Linux kernel",
264 .handle = ID_ACCELERATION,
265 .type = SENSOR_TYPE_ACCELEROMETER,
266 .maxRange = (GRAVITY_EARTH * 6.0f),
267 .resolution = (GRAVITY_EARTH * 6.0f) / 1024.0f,
273 static int open_sensors(const struct hw_module_t* module, const char* name,
274 struct hw_device_t** device);
276 static int sensors__get_sensors_list(struct sensors_module_t* module,
277 struct sensor_t const** list) {
280 return ARRAY_SIZE(sSensorList);
283 static struct hw_module_methods_t sensors_module_methods = {
287 struct sensors_module_t HAL_MODULE_INFO_SYM = {
289 .tag = HARDWARE_MODULE_TAG,
290 .module_api_version = 2,
291 .hal_api_version = 0,
292 .id = SENSORS_HARDWARE_MODULE_ID,
293 .name = "hdaps accelerometer sensor",
294 .author = "Stefan Seidel",
295 .methods = &sensors_module_methods,
299 .get_sensors_list = sensors__get_sensors_list
302 static int open_sensors(const struct hw_module_t* module, const char* name,
303 struct hw_device_t** device) {
304 int status = -EINVAL;
306 struct sensors_poll_context_t *dev = calloc(1,
307 sizeof(struct sensors_poll_context_t));
309 dev->device.common.tag = HARDWARE_DEVICE_TAG;
310 dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
311 dev->device.common.module = (struct hw_module_t*) module;
312 dev->device.common.close = common__close;
313 dev->device.activate = device__activate;
314 dev->device.setDelay = device__set_delay;
315 dev->device.poll = device__poll;
316 dev->device.batch = device__batch;
317 dev->device.flush = device__flush;
319 if ((dev->fd = open_input_device()) < 0) {
320 ALOGE("GSensor get class path error");
322 *device = &dev->device.common;