1 /*
2 * Copyright (C) 2012 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 #define LOG_NDEBUG 0
18
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <math.h>
22 #include <unistd.h>
23 #include <dirent.h>
24 #include <sys/select.h>
25 #include <cutils/log.h>
26 #include <linux/input.h>
27 #include <string.h>
28
29 #include "CompassSensor.IIO.9150.h"
30 #include "sensors.h"
31 #include "MPLSupport.h"
32 #include "sensor_params.h"
33 #include "ml_sysfs_helper.h"
34 #include "local_log_def.h"
35
36 #define COMPASS_MAX_SYSFS_ATTRB sizeof(compassSysFs) / sizeof(char*)
37
38 #if defined COMPASS_YAS53x
39 # warning "Invensense compass cal with YAS53x IIO on secondary bus"
40 # define USE_MPL_COMPASS_HAL (1)
41 # define COMPASS_NAME "INV_YAS530"
42 #elif defined COMPASS_AK8975
43 # warning "Invensense compass cal with AK8975 on primary bus"
44 # define USE_MPL_COMPASS_HAL (1)
45 # define COMPASS_NAME "INV_AK8975"
46 #elif defined INVENSENSE_COMPASS_CAL
47 # warning "Invensense compass cal with compass IIO on secondary bus"
48 # define USE_MPL_COMPASS_HAL (1)
49 # define COMPASS_NAME "INV_COMPASS"
50 #else
51 # warning "third party compass cal HAL"
52 # define USE_MPL_COMPASS_HAL (0)
53 // TODO: change to vendor's name
54 # define COMPASS_NAME "AKM8975"
55 #endif
56
57
58 /*****************************************************************************/
59
CompassSensor()60 CompassSensor::CompassSensor()
61 : SensorBase(NULL, NULL),
62 compass_fd(-1),
63 mCompassTimestamp(0),
64 mCompassInputReader(8)
65 {
66 VFUNC_LOG;
67
68 if(inv_init_sysfs_attributes()) {
69 LOGE("Error Instantiating Compass\n");
70 return;
71 }
72
73 if (!strcmp(COMPASS_NAME, "INV_COMPASS")) {
74 mI2CBus = COMPASS_BUS_SECONDARY;
75 } else {
76 mI2CBus = COMPASS_BUS_PRIMARY;
77 }
78
79 memset(mCachedCompassData, 0, sizeof(mCachedCompassData));
80
81 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
82 compassSysFs.compass_orient, getTimestamp());
83 FILE *fptr;
84 fptr = fopen(compassSysFs.compass_orient, "r");
85 if (fptr != NULL) {
86 int om[9];
87 fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d",
88 &om[0], &om[1], &om[2], &om[3], &om[4], &om[5],
89 &om[6], &om[7], &om[8]);
90 fclose(fptr);
91
92 LOGV_IF(EXTRA_VERBOSE,
93 "HAL:compass mounting matrix: "
94 "%+d %+d %+d %+d %+d %+d %+d %+d %+d",
95 om[0], om[1], om[2], om[3], om[4], om[5], om[6], om[7], om[8]);
96
97 mCompassOrientation[0] = om[0];
98 mCompassOrientation[1] = om[1];
99 mCompassOrientation[2] = om[2];
100 mCompassOrientation[3] = om[3];
101 mCompassOrientation[4] = om[4];
102 mCompassOrientation[5] = om[5];
103 mCompassOrientation[6] = om[6];
104 mCompassOrientation[7] = om[7];
105 mCompassOrientation[8] = om[8];
106 } else {
107 LOGE("HAL:Couldn't read compass mounting matrix");
108 }
109
110 if (!isIntegrated()) {
111 enable(ID_M, 0);
112 }
113 }
114
~CompassSensor()115 CompassSensor::~CompassSensor()
116 {
117 VFUNC_LOG;
118
119 free(pathP);
120 if( compass_fd > 0)
121 close(compass_fd);
122 }
123
getFd() const124 int CompassSensor::getFd() const
125 {
126 VHANDLER_LOG;
127 return compass_fd;
128 }
129
130 /**
131 * @brief This function will enable/disable sensor.
132 * @param[in] handle
133 * which sensor to enable/disable.
134 * @param[in] en
135 * en=1, enable;
136 * en=0, disable
137 * @return if the operation is successful.
138 */
enable(int32_t,int en)139 int CompassSensor::enable(int32_t /*handle*/, int en)
140 {
141 VFUNC_LOG;
142
143 mEnable = en;
144 int res;
145
146 res = write_sysfs_int(compassSysFs.compass_enable, en);
147 LOGE_IF(res < 0, "HAL:enable compass failed");
148
149 if (en) {
150 res = write_sysfs_int(compassSysFs.compass_x_fifo_enable, en);
151 res = write_sysfs_int(compassSysFs.compass_y_fifo_enable, en);
152 res = write_sysfs_int(compassSysFs.compass_z_fifo_enable, en);
153 }
154
155 return res;
156 }
157
setDelay(int32_t,int64_t ns)158 int CompassSensor::setDelay(int32_t /*handle*/, int64_t ns)
159 {
160 VFUNC_LOG;
161 int tempFd;
162 int res;
163
164 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)",
165 1000000000.f / ns, compassSysFs.compass_rate, getTimestamp());
166 mDelay = ns;
167 if (ns == 0)
168 return -1;
169 tempFd = open(compassSysFs.compass_rate, O_RDWR);
170 res = write_attribute_sensor(tempFd, 1000000000.f / ns);
171 if(res < 0) {
172 LOGE("HAL:Compass update delay error");
173 }
174 return res;
175 }
176
177
178 /**
179 @brief This function will return the state of the sensor.
180 @return 1=enabled; 0=disabled
181 **/
getEnable(int32_t)182 int CompassSensor::getEnable(int32_t /*handle*/)
183 {
184 VFUNC_LOG;
185 return mEnable;
186 }
187
188 /* use for Invensense compass calibration */
189 #define COMPASS_EVENT_DEBUG (0)
processCompassEvent(const input_event * event)190 void CompassSensor::processCompassEvent(const input_event *event)
191 {
192 VHANDLER_LOG;
193
194 switch (event->code) {
195 case EVENT_TYPE_ICOMPASS_X:
196 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_X\n");
197 mCachedCompassData[0] = event->value;
198 break;
199 case EVENT_TYPE_ICOMPASS_Y:
200 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Y\n");
201 mCachedCompassData[1] = event->value;
202 break;
203 case EVENT_TYPE_ICOMPASS_Z:
204 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Z\n");
205 mCachedCompassData[2] = event->value;
206 break;
207 }
208
209 mCompassTimestamp =
210 (int64_t)event->time.tv_sec * 1000000000L + event->time.tv_usec * 1000L;
211 }
212
getOrientationMatrix(signed char * orient)213 void CompassSensor::getOrientationMatrix(signed char *orient)
214 {
215 VFUNC_LOG;
216 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation));
217 }
218
getSensitivity()219 long CompassSensor::getSensitivity()
220 {
221 VFUNC_LOG;
222
223 long sensitivity;
224 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)",
225 compassSysFs.compass_scale, getTimestamp());
226 inv_read_data(compassSysFs.compass_scale, &sensitivity);
227 return sensitivity;
228 }
229
230 /**
231 @brief This function is called by sensors_mpl.cpp
232 to read sensor data from the driver.
233 @param[out] data sensor data is stored in this variable. Scaled such that
234 1 uT = 2^16
235 @para[in] timestamp data's timestamp
236 @return 1, if 1 sample read, 0, if not, negative if error
237 */
readSample(long * data,int64_t * timestamp)238 int CompassSensor::readSample(long *data, int64_t *timestamp)
239 {
240 VHANDLER_LOG;
241
242 int numEventReceived = 0, done = 0;
243
244 ssize_t n = mCompassInputReader.fill(compass_fd);
245 if (n < 0) {
246 LOGE("HAL:no compass events read");
247 return n;
248 }
249
250 input_event const* event;
251
252 while (done == 0 && mCompassInputReader.readEvent(&event)) {
253 int type = event->type;
254 if (type == EV_REL) {
255 processCompassEvent(event);
256 } else if (type == EV_SYN) {
257 *timestamp = mCompassTimestamp;
258 memcpy(data, mCachedCompassData, sizeof(mCachedCompassData));
259 done = 1;
260 } else {
261 LOGE("HAL:Compass Sensor: unknown event (type=%d, code=%d)",
262 type, event->code);
263 }
264 mCompassInputReader.next();
265 }
266
267 return done;
268 }
269
270 /**
271 * @brief This function will return the current delay for this sensor.
272 * @return delay in nanoseconds.
273 */
getDelay(int32_t)274 int64_t CompassSensor::getDelay(int32_t /*handle*/)
275 {
276 VFUNC_LOG;
277 return mDelay;
278 }
279
fillList(struct sensor_t * list)280 void CompassSensor::fillList(struct sensor_t *list)
281 {
282 VFUNC_LOG;
283
284 const char *compass = COMPASS_NAME;
285
286 if (compass) {
287 if(!strcmp(compass, "INV_COMPASS")) {
288 list->maxRange = COMPASS_MPU9150_RANGE;
289 /* since target platform would use AK8963 instead of AK8975,
290 need to adopt AK8963's resolution here */
291 // list->resolution = COMPASS_MPU9150_RESOLUTION;
292 list->resolution = COMPASS_AKM8963_RESOLUTION;
293 list->power = COMPASS_MPU9150_POWER;
294 list->minDelay = COMPASS_MPU9150_MINDELAY;
295 return;
296 }
297 if(!strcmp(compass, "compass")
298 || !strcmp(compass, "INV_AK8975") ) {
299 list->maxRange = COMPASS_AKM8975_RANGE;
300 list->resolution = COMPASS_AKM8975_RESOLUTION;
301 list->power = COMPASS_AKM8975_POWER;
302 list->minDelay = COMPASS_AKM8975_MINDELAY;
303 return;
304 }
305 if(!strcmp(compass, "INV_YAS530")) {
306 list->maxRange = COMPASS_YAS53x_RANGE;
307 list->resolution = COMPASS_YAS53x_RESOLUTION;
308 list->power = COMPASS_YAS53x_POWER;
309 list->minDelay = COMPASS_YAS53x_MINDELAY;
310 return;
311 }
312 if(!strcmp(compass, "INV_AMI306")) {
313 list->maxRange = COMPASS_AMI306_RANGE;
314 list->resolution = COMPASS_AMI306_RESOLUTION;
315 list->power = COMPASS_AMI306_POWER;
316 list->minDelay = COMPASS_AMI306_MINDELAY;
317 return;
318 }
319 }
320
321 LOGE("HAL:unknown compass id %s -- "
322 "params default to ak8975 and might be wrong.",
323 compass);
324 list->maxRange = COMPASS_AKM8975_RANGE;
325 list->resolution = COMPASS_AKM8975_RESOLUTION;
326 list->power = COMPASS_AKM8975_POWER;
327 list->minDelay = COMPASS_AKM8975_MINDELAY;
328 }
329
inv_init_sysfs_attributes(void)330 int CompassSensor::inv_init_sysfs_attributes(void)
331 {
332 VFUNC_LOG;
333
334 unsigned char i = 0;
335 char sysfs_path[MAX_SYSFS_NAME_LEN], iio_trigger_path[MAX_SYSFS_NAME_LEN], tbuf[2];
336 char *sptr;
337 char **dptr;
338 int num;
339
340 pathP = (char*)malloc(
341 sizeof(char[COMPASS_MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN]));
342 sptr = pathP;
343 dptr = (char**)&compassSysFs;
344 if (sptr == NULL)
345 return -1;
346
347 do {
348 *dptr++ = sptr;
349 sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
350 } while (++i < COMPASS_MAX_SYSFS_ATTRB);
351
352 // get proper (in absolute/relative) IIO path & build MPU's sysfs paths
353 // inv_get_sysfs_abs_path(sysfs_path);
354 if(INV_SUCCESS != inv_get_sysfs_path(sysfs_path)) {
355 ALOGE("CompassSensor failed get sysfs path");
356 return -1;
357 }
358
359 inv_get_iio_trigger_path(iio_trigger_path);
360
361 #if defined COMPASS_AK8975
362 inv_get_input_number(COMPASS_NAME, &num);
363 tbuf[0] = num + 0x30;
364 tbuf[1] = 0;
365 sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf);
366 strcat(sysfs_path, "/ak8975");
367
368 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable");
369 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate");
370 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale");
371 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
372 #else
373 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/compass_enable");
374 sprintf(compassSysFs.compass_x_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_x_en");
375 sprintf(compassSysFs.compass_y_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_y_en");
376 sprintf(compassSysFs.compass_z_fifo_enable, "%s%s", sysfs_path, "/scan_elements/in_magn_z_en");
377 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/sampling_frequency");
378 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale");
379 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix");
380 #endif
381
382 #if SYSFS_VERBOSE
383 // test print sysfs paths
384 dptr = (char**)&compassSysFs;
385 for (i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) {
386 LOGE("HAL:sysfs path: %s", *dptr++);
387 }
388 #endif
389 return 0;
390 }
391