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