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 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 115 CompassSensor::~CompassSensor() 116 { 117 VFUNC_LOG; 118 119 free(pathP); 120 if( compass_fd > 0) 121 close(compass_fd); 122 } 123 124 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 */ 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 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 **/ 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) 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 213 void CompassSensor::getOrientationMatrix(signed char *orient) 214 { 215 VFUNC_LOG; 216 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation)); 217 } 218 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 */ 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 */ 274 int64_t CompassSensor::getDelay(int32_t handle) 275 { 276 VFUNC_LOG; 277 return mDelay; 278 } 279 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 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