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