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 <inttypes.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <math.h>
21 #include <poll.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <dirent.h>
25 #include <sys/select.h>
26 #include <dlfcn.h>
27 
28 #include <cutils/log.h>
29 
30 #include "AkmSensor.h"
31 
32 #define AKMD_DEFAULT_INTERVAL	200000000
33 
34 /*****************************************************************************/
35 
AkmSensor()36 AkmSensor::AkmSensor()
37 : SensorBase(NULL, "compass"),
38       mPendingMask(0),
39       mInputReader(32)
40 {
41 	for (int i=0; i<numSensors; i++) {
42 		mEnabled[i] = 0;
43 		mDelay[i] = -1;
44 	}
45     memset(mPendingEvents, 0, sizeof(mPendingEvents));
46 
47     mPendingEvents[Accelerometer].version = sizeof(sensors_event_t);
48     mPendingEvents[Accelerometer].sensor = ID_A;
49     mPendingEvents[Accelerometer].type = SENSOR_TYPE_ACCELEROMETER;
50     mPendingEvents[Accelerometer].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
51 
52     mPendingEvents[MagneticField].version = sizeof(sensors_event_t);
53     mPendingEvents[MagneticField].sensor = ID_M;
54     mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD;
55     mPendingEvents[MagneticField].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH;
56 
57     mPendingEvents[Orientation  ].version = sizeof(sensors_event_t);
58     mPendingEvents[Orientation  ].sensor = ID_O;
59     mPendingEvents[Orientation  ].type = SENSOR_TYPE_ORIENTATION;
60     mPendingEvents[Orientation  ].orientation.status = SENSOR_STATUS_ACCURACY_HIGH;
61 
62     if (data_fd) {
63 		strcpy(input_sysfs_path, "/sys/class/compass/akm8975/");
64 		input_sysfs_path_len = strlen(input_sysfs_path);
65 	} else {
66 		input_sysfs_path[0] = '\0';
67 		input_sysfs_path_len = 0;
68 	}
69 }
70 
~AkmSensor()71 AkmSensor::~AkmSensor()
72 {
73 	for (int i=0; i<numSensors; i++) {
74 		setEnable(i, 0);
75 	}
76 }
77 
setEnable(int32_t handle,int enabled)78 int AkmSensor::setEnable(int32_t handle, int enabled)
79 {
80 	int id = handle2id(handle);
81 	int err = 0;
82 	char buffer[2];
83 
84 	switch (id) {
85 	case Accelerometer:
86 		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_acc");
87 		break;
88 	case MagneticField:
89 		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_mag");
90 		break;
91 	case Orientation:
92 		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable_ori");
93 		break;
94 	default:
95 		ALOGE("AkmSensor: unknown handle (%d)", handle);
96 		return -EINVAL;
97 	}
98 
99 	buffer[0] = '\0';
100 	buffer[1] = '\0';
101 
102 	if (mEnabled[id] <= 0) {
103 		if(enabled) buffer[0] = '1';
104 	} else if (mEnabled[id] == 1) {
105 		if(!enabled) buffer[0] = '0';
106 	}
107 
108     if (buffer[0] != '\0') {
109 		err = write_sys_attribute(input_sysfs_path, buffer, 1);
110 		if (err != 0) {
111 			return err;
112 		}
113 		ALOGD("AkmSensor: set %s to %s",
114 			&input_sysfs_path[input_sysfs_path_len], buffer);
115 
116 		/* for AKMD specification */
117 		if (buffer[0] == '1') {
118 			setDelay(handle, AKMD_DEFAULT_INTERVAL);
119 		} else {
120 			setDelay(handle, -1);
121 		}
122     }
123 
124 	if (enabled) {
125 		(mEnabled[id])++;
126 		if (mEnabled[id] > 32767) mEnabled[id] = 32767;
127 	} else {
128 		(mEnabled[id])--;
129 		if (mEnabled[id] < 0) mEnabled[id] = 0;
130 	}
131 	ALOGD("AkmSensor: mEnabled[%d] = %d", id, mEnabled[id]);
132 
133     return err;
134 }
135 
setDelay(int32_t handle,int64_t ns)136 int AkmSensor::setDelay(int32_t handle, int64_t ns)
137 {
138 	int id = handle2id(handle);
139 	int err = 0;
140 	char buffer[32];
141 	int bytes;
142 
143 	if (ns < -1 || 2147483647 < ns) {
144 		ALOGE("AkmSensor: invalid delay (%" PRIi64 ")", ns);
145 		return -EINVAL;
146 	}
147 
148     switch (id) {
149         case Accelerometer:
150 			strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_acc");
151 			break;
152         case MagneticField:
153 			strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_mag");
154 			break;
155         case Orientation:
156 			strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_ori");
157 			break;
158 		default:
159 			ALOGE("AkmSensor: unknown handle (%d)", handle);
160 			return -EINVAL;
161     }
162 
163 	if (ns != mDelay[id]) {
164 		bytes = sprintf(buffer, "%" PRIi64, ns);
165 		err = write_sys_attribute(input_sysfs_path, buffer, bytes);
166 		if (err == 0) {
167 			mDelay[id] = ns;
168 			ALOGD("AkmSensor: set %s to %f ms.",
169 				&input_sysfs_path[input_sysfs_path_len], ns/1000000.0f);
170 		}
171 	}
172 
173     return err;
174 }
175 
getDelay(int32_t handle)176 int64_t AkmSensor::getDelay(int32_t handle)
177 {
178 	int id = handle2id(handle);
179 	if (id > 0) {
180 		return mDelay[id];
181 	} else {
182 		return 0;
183 	}
184 }
185 
getEnable(int32_t handle)186 int AkmSensor::getEnable(int32_t handle)
187 {
188 	int id = handle2id(handle);
189 	if (id >= 0) {
190 		return mEnabled[id];
191 	} else {
192 		return 0;
193 	}
194 }
195 
readEvents(sensors_event_t * data,int count)196 int AkmSensor::readEvents(sensors_event_t* data, int count)
197 {
198     if (count < 1)
199         return -EINVAL;
200 
201     ssize_t n = mInputReader.fill(data_fd);
202     if (n < 0)
203         return n;
204 
205     int numEventReceived = 0;
206     input_event const* event;
207 
208     while (count && mInputReader.readEvent(&event)) {
209         int type = event->type;
210         if (type == EV_ABS) {
211             processEvent(event->code, event->value);
212             mInputReader.next();
213         } else if (type == EV_SYN) {
214             int64_t time = timevalToNano(event->time);
215             for (int j=0 ; count && mPendingMask && j<numSensors ; j++) {
216                 if (mPendingMask & (1<<j)) {
217                     mPendingMask &= ~(1<<j);
218                     mPendingEvents[j].timestamp = time;
219 					//ALOGD("data=%8.5f,%8.5f,%8.5f",
220 						//mPendingEvents[j].data[0],
221 						//mPendingEvents[j].data[1],
222 						//mPendingEvents[j].data[2]);
223                     if (mEnabled[j]) {
224                         *data++ = mPendingEvents[j];
225                         count--;
226                         numEventReceived++;
227                     }
228                 }
229             }
230             if (!mPendingMask) {
231                 mInputReader.next();
232             }
233         } else {
234             ALOGE("AkmSensor: unknown event (type=%d, code=%d)",
235                     type, event->code);
236             mInputReader.next();
237         }
238     }
239     return numEventReceived;
240 }
241 
setAccel(sensors_event_t * data)242 int AkmSensor::setAccel(sensors_event_t* data)
243 {
244 	int err;
245 	int16_t acc[3];
246 
247 	acc[0] = (int16_t)(data->acceleration.x / GRAVITY_EARTH * AKSC_LSG);
248 	acc[1] = (int16_t)(data->acceleration.y / GRAVITY_EARTH * AKSC_LSG);
249 	acc[2] = (int16_t)(data->acceleration.z / GRAVITY_EARTH * AKSC_LSG);
250 
251 	strcpy(&input_sysfs_path[input_sysfs_path_len], "accel");
252 	err = write_sys_attribute(input_sysfs_path, (char*)acc, 6);
253 	if (err < 0) {
254 		ALOGD("AkmSensor: %s write failed.",
255 			&input_sysfs_path[input_sysfs_path_len]);
256 	}
257 	return err;
258 }
259 
handle2id(int32_t handle)260 int AkmSensor::handle2id(int32_t handle)
261 {
262     switch (handle) {
263         case ID_A:
264 			return Accelerometer;
265         case ID_M:
266 			return MagneticField;
267         case ID_O:
268 			return Orientation;
269 		default:
270 			ALOGE("AkmSensor: unknown handle (%d)", handle);
271 			return -EINVAL;
272     }
273 }
274 
processEvent(int code,int value)275 void AkmSensor::processEvent(int code, int value)
276 {
277     switch (code) {
278         case EVENT_TYPE_ACCEL_X:
279             mPendingMask |= 1<<Accelerometer;
280             mPendingEvents[Accelerometer].acceleration.x = value * CONVERT_A;
281             break;
282         case EVENT_TYPE_ACCEL_Y:
283             mPendingMask |= 1<<Accelerometer;
284             mPendingEvents[Accelerometer].acceleration.y = value * CONVERT_A;
285             break;
286         case EVENT_TYPE_ACCEL_Z:
287             mPendingMask |= 1<<Accelerometer;
288             mPendingEvents[Accelerometer].acceleration.z = value * CONVERT_A;
289             break;
290 
291         case EVENT_TYPE_MAGV_X:
292             mPendingMask |= 1<<MagneticField;
293             mPendingEvents[MagneticField].magnetic.x = value * CONVERT_M;
294             break;
295         case EVENT_TYPE_MAGV_Y:
296             mPendingMask |= 1<<MagneticField;
297             mPendingEvents[MagneticField].magnetic.y = value * CONVERT_M;
298             break;
299         case EVENT_TYPE_MAGV_Z:
300             mPendingMask |= 1<<MagneticField;
301             mPendingEvents[MagneticField].magnetic.z = value * CONVERT_M;
302             break;
303         case EVENT_TYPE_MAGV_STATUS:
304             mPendingMask |= 1<<MagneticField;
305             mPendingEvents[MagneticField].magnetic.status = value;
306             break;
307 
308         case EVENT_TYPE_YAW:
309             mPendingMask |= 1<<Orientation;
310             mPendingEvents[Orientation].orientation.azimuth = value * CONVERT_O;
311             break;
312         case EVENT_TYPE_PITCH:
313             mPendingMask |= 1<<Orientation;
314             mPendingEvents[Orientation].orientation.pitch = value * CONVERT_O;
315             break;
316         case EVENT_TYPE_ROLL:
317             mPendingMask |= 1<<Orientation;
318             mPendingEvents[Orientation].orientation.roll = value * CONVERT_O;
319             break;
320         case EVENT_TYPE_ORIENT_STATUS:
321             mPendingMask |= 1<<Orientation;
322             mPendingEvents[Orientation].orientation.status = value;
323             break;
324     }
325 }
326