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 62CompassSensor::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 118CompassSensor::~CompassSensor() 119{ 120 VFUNC_LOG; 121 free(pathP); 122 if( compass_fd > 0) 123 close(compass_fd); 124} 125 126int 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 */ 141int 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 149int 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 168int 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 177int 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**/ 190int 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) 198void 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 221void CompassSensor::getOrientationMatrix(signed char *orient) 222{ 223 VFUNC_LOG; 224 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation)); 225} 226 227long 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 */ 246int 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 */ 282int64_t CompassSensor::getDelay(int32_t handle) 283{ 284 VFUNC_LOG; 285 return mDelay; 286} 287 288void 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 345int 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