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
AdxlSensor()35 AdxlSensor::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
~AdxlSensor()59 AdxlSensor::~AdxlSensor() {
60 if (mEnabled) {
61 setEnable(0, 0);
62 }
63 }
64
setInitialState()65 int 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
hasPendingEvents() const82 bool AdxlSensor::hasPendingEvents() const {
83 return mHasPendingEvent;
84 }
85
setEnable(int32_t handle,int enabled)86 int 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
setDelay(int32_t handle,int64_t delay_ns)126 int 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
getDelay(int32_t handle)168 int64_t AdxlSensor::getDelay(int32_t handle)
169 {
170 return (handle == ID_A) ? mDelay : 0;
171 }
172
getEnable(int32_t handle)173 int AdxlSensor::getEnable(int32_t handle)
174 {
175 return (handle == ID_A) ? mEnabled : 0;
176 }
177
readEvents(sensors_event_t * data,int count)178 int 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