1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <errno.h>
19#include <math.h>
20#include <poll.h>
21#include <unistd.h>
22#include <dirent.h>
23#include <sys/select.h>
24#include <cutils/log.h>
25
26#include "AdxlSensor.h"
27
28#define ADXL_DATA_NAME				"ADXL34x accelerometer"
29#define ADXL_MAX_SAMPLE_RATE_VAL	11 /* 200 Hz */
30
31#define ADXL_UNIT_CONVERSION(value) ((value) * GRAVITY_EARTH / (256.0f))
32
33/*****************************************************************************/
34
35AdxlSensor::AdxlSensor()
36    : SensorBase(NULL, ADXL_DATA_NAME),
37      mEnabled(0),
38      mDelay(-1),
39      mInputReader(4),
40      mHasPendingEvent(false)
41{
42    mPendingEvent.version = sizeof(sensors_event_t);
43    mPendingEvent.sensor = ID_A;
44    mPendingEvent.type = SENSOR_TYPE_ACCELEROMETER;
45    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
46
47    if (data_fd >= 0) {
48        strcpy(input_sysfs_path, "/sys/class/input/");
49        strcat(input_sysfs_path, input_name);
50        strcat(input_sysfs_path, "/device/device/");
51        input_sysfs_path_len = strlen(input_sysfs_path);
52		ALOGD("AdxlSensor: sysfs_path=%s", input_sysfs_path);
53    } else {
54		input_sysfs_path[0] = '\0';
55		input_sysfs_path_len = 0;
56	}
57}
58
59AdxlSensor::~AdxlSensor() {
60    if (mEnabled) {
61        setEnable(0, 0);
62    }
63}
64
65int AdxlSensor::setInitialState() {
66    struct input_absinfo absinfo;
67
68	if (mEnabled) {
69    	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo)) {
70			mPendingEvent.acceleration.x = ADXL_UNIT_CONVERSION(absinfo.value);
71		}
72    	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) {
73			mPendingEvent.acceleration.y = ADXL_UNIT_CONVERSION(absinfo.value);
74		}
75		if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) {
76			mPendingEvent.acceleration.z = ADXL_UNIT_CONVERSION(absinfo.value);
77		}
78	}
79    return 0;
80}
81
82bool AdxlSensor::hasPendingEvents() const {
83    return mHasPendingEvent;
84}
85
86int AdxlSensor::setEnable(int32_t handle, int enabled) {
87    int err = 0;
88	char buffer[2];
89
90	/* handle check */
91	if (handle != ID_A) {
92		ALOGE("AdxlSensor: Invalid handle (%d)", handle);
93		return -EINVAL;
94	}
95
96	buffer[0] = '\0';
97	buffer[1] = '\0';
98
99	if (mEnabled <= 0) {
100		if(enabled) buffer[0] = '0';
101	} else if (mEnabled == 1) {
102		if(!enabled) buffer[0] = '1';
103	}
104    if (buffer[0] != '\0') {
105        strcpy(&input_sysfs_path[input_sysfs_path_len], "disable");
106		err = write_sys_attribute(input_sysfs_path, buffer, 1);
107		if (err != 0) {
108			return err;
109		}
110		ALOGD("AdxlSensor: Control set %s", buffer);
111   		setInitialState();
112    }
113
114	if (enabled) {
115		mEnabled++;
116		if (mEnabled > 32767) mEnabled = 32767;
117	} else {
118		mEnabled--;
119		if (mEnabled < 0) mEnabled = 0;
120	}
121	ALOGD("AdxlSensor: mEnabled = %d", mEnabled);
122
123    return err;
124}
125
126int AdxlSensor::setDelay(int32_t handle, int64_t delay_ns)
127{
128	int err = 0;
129	int rate_val;
130	int32_t us;
131	char buffer[16];
132	int bytes;
133
134	/* handle check */
135	if (handle != ID_A) {
136		ALOGE("AdxlSensor: Invalid handle (%d)", handle);
137		return -EINVAL;
138	}
139
140	if (mDelay != delay_ns) {
141		/*
142	 	* The ADXL34x Supports 16 sample rates ranging from 3200Hz-0.098Hz
143	 	* Calculate best fit and limit to max 200Hz (rate_val 11)
144	 	*/
145
146		us = (int32_t)(delay_ns / 1000);
147		for (rate_val = 0; rate_val < 16; rate_val++)
148			if (us  >= ((10000000) >> rate_val))
149				break;
150
151		if (rate_val > ADXL_MAX_SAMPLE_RATE_VAL) {
152			rate_val = ADXL_MAX_SAMPLE_RATE_VAL;
153		}
154
155    	strcpy(&input_sysfs_path[input_sysfs_path_len], "rate");
156   		bytes = sprintf(buffer, "%d", rate_val);
157		err = write_sys_attribute(input_sysfs_path, buffer, bytes);
158		if (err == 0) {
159			mDelay = delay_ns;
160			ALOGD("AdxlSensor: Control set delay %f ms requetsed, using %f ms",
161				delay_ns/1000000.0f, 1e6 / (3200000 >> (15 - rate_val)));
162		}
163	}
164
165	return err;
166}
167
168int64_t AdxlSensor::getDelay(int32_t handle)
169{
170	return (handle == ID_A) ? mDelay : 0;
171}
172
173int AdxlSensor::getEnable(int32_t handle)
174{
175	return (handle == ID_A) ? mEnabled : 0;
176}
177
178int AdxlSensor::readEvents(sensors_event_t* data, int count)
179{
180    if (count < 1)
181        return -EINVAL;
182
183    if (mHasPendingEvent) {
184        mHasPendingEvent = false;
185        mPendingEvent.timestamp = getTimestamp();
186        *data = mPendingEvent;
187        return mEnabled ? 1 : 0;
188    }
189
190    ssize_t n = mInputReader.fill(data_fd);
191    if (n < 0)
192        return n;
193
194    int numEventReceived = 0;
195    input_event const* event;
196
197    while (count && mInputReader.readEvent(&event)) {
198        int type = event->type;
199        if (type == EV_ABS) {
200            float value = event->value;
201            if (event->code == EVENT_TYPE_ACCEL_X) {
202                mPendingEvent.acceleration.x = ADXL_UNIT_CONVERSION(value);
203            } else if (event->code == EVENT_TYPE_ACCEL_Y) {
204                mPendingEvent.acceleration.y = ADXL_UNIT_CONVERSION(value);
205            } else if (event->code == EVENT_TYPE_ACCEL_Z) {
206                mPendingEvent.acceleration.z = ADXL_UNIT_CONVERSION(value);
207            }
208        } else if (type == EV_SYN) {
209            mPendingEvent.timestamp = timevalToNano(event->time);
210            if (mEnabled) {
211                *data++ = mPendingEvent;
212                count--;
213                numEventReceived++;
214            }
215        } else {
216            ALOGE("AdxlSensor: unknown event (type=%d, code=%d)",
217                    type, event->code);
218        }
219        mInputReader.next();
220    }
221
222    return numEventReceived;
223}
224
225