1 /* 2 * Copyright (C) 2014 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 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 118 CompassSensor::~CompassSensor() 119 { 120 VFUNC_LOG; 121 free(pathP); 122 if( compass_fd > 0) 123 close(compass_fd); 124 } 125 126 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 */ 141 int CompassSensor::enable(int32_t handle, int en) 142 { 143 VFUNC_LOG; 144 int res = 0; 145 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", 146 en, compassSysFs.compass_enable, getTimestamp()); 147 res = write_sysfs_int(compassSysFs.compass_enable, en); 148 return res; 149 } 150 151 int CompassSensor::setDelay(int32_t handle, int64_t ns) 152 { 153 VFUNC_LOG; 154 int tempFd; 155 int res; 156 157 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", 158 1000000000.f / ns, compassSysFs.compass_rate, getTimestamp()); 159 mDelay = ns; 160 if (ns == 0) 161 return -1; 162 tempFd = open(compassSysFs.compass_rate, O_RDWR); 163 res = write_attribute_sensor(tempFd, 1000000000.f / ns); 164 if(res < 0) { 165 LOGE("HAL:Compass update delay error"); 166 } 167 return res; 168 } 169 170 int CompassSensor::turnOffCompassFifo(void) 171 { 172 int i, res = 0, tempFd; 173 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", 174 0, compassSysFs.compass_fifo_enable, getTimestamp()); 175 res += write_sysfs_int(compassSysFs.compass_fifo_enable, 0); 176 return res; 177 } 178 179 int CompassSensor::turnOnCompassFifo(void) 180 { 181 int i, res = 0, tempFd; 182 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", 183 1, compassSysFs.compass_fifo_enable, getTimestamp()); 184 res += write_sysfs_int(compassSysFs.compass_fifo_enable, 1); 185 return res; 186 } 187 188 /** 189 @brief This function will return the state of the sensor. 190 @return 1=enabled; 0=disabled 191 **/ 192 int CompassSensor::getEnable(int32_t handle) 193 { 194 VFUNC_LOG; 195 return mEnable; 196 } 197 198 /* use for Invensense compass calibration */ 199 #define COMPASS_EVENT_DEBUG (0) 200 void CompassSensor::processCompassEvent(const input_event *event) 201 { 202 VHANDLER_LOG; 203 204 switch (event->code) { 205 case EVENT_TYPE_ICOMPASS_X: 206 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_X\n"); 207 mCachedCompassData[0] = event->value; 208 break; 209 case EVENT_TYPE_ICOMPASS_Y: 210 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Y\n"); 211 mCachedCompassData[1] = event->value; 212 break; 213 case EVENT_TYPE_ICOMPASS_Z: 214 LOGV_IF(COMPASS_EVENT_DEBUG, "EVENT_TYPE_ICOMPASS_Z\n"); 215 mCachedCompassData[2] = event->value; 216 break; 217 } 218 219 mCompassTimestamp = 220 (int64_t)event->time.tv_sec * 1000000000L + event->time.tv_usec * 1000L; 221 } 222 223 void CompassSensor::getOrientationMatrix(signed char *orient) 224 { 225 VFUNC_LOG; 226 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation)); 227 } 228 229 long CompassSensor::getSensitivity() 230 { 231 VFUNC_LOG; 232 233 long sensitivity; 234 LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)", 235 compassSysFs.compass_scale, getTimestamp()); 236 inv_read_data(compassSysFs.compass_scale, &sensitivity); 237 return sensitivity; 238 } 239 240 /** 241 @brief This function is called by sensors_mpl.cpp 242 to read sensor data from the driver. 243 @param[out] data sensor data is stored in this variable. Scaled such that 244 1 uT = 2^16 245 @para[in] timestamp data's timestamp 246 @return 1, if 1 sample read, 0, if not, negative if error 247 */ 248 int CompassSensor::readSample(long *data, int64_t *timestamp) 249 { 250 VHANDLER_LOG; 251 252 int numEventReceived = 0, done = 0; 253 254 ssize_t n = mCompassInputReader.fill(compass_fd); 255 if (n < 0) { 256 LOGE("HAL:no compass events read"); 257 return n; 258 } 259 260 input_event const* event; 261 262 while (done == 0 && mCompassInputReader.readEvent(&event)) { 263 int type = event->type; 264 if (type == EV_REL) { 265 processCompassEvent(event); 266 } else if (type == EV_SYN) { 267 *timestamp = mCompassTimestamp; 268 memcpy(data, mCachedCompassData, sizeof(mCachedCompassData)); 269 done = 1; 270 } else { 271 LOGE("HAL:Compass Sensor: unknown event (type=%d, code=%d)", 272 type, event->code); 273 } 274 mCompassInputReader.next(); 275 } 276 277 return done; 278 } 279 280 /** 281 * @brief This function will return the current delay for this sensor. 282 * @return delay in nanoseconds. 283 */ 284 int64_t CompassSensor::getDelay(int32_t handle) 285 { 286 VFUNC_LOG; 287 return mDelay; 288 } 289 290 void CompassSensor::fillList(struct sensor_t *list) 291 { 292 VFUNC_LOG; 293 294 const char *compass = sensor_name; 295 296 if (compass) { 297 if(!strcmp(compass, "INV_COMPASS")) { 298 list->maxRange = COMPASS_MPU9150_RANGE; 299 list->resolution = COMPASS_MPU9150_RESOLUTION; 300 list->power = COMPASS_MPU9150_POWER; 301 list->minDelay = COMPASS_MPU9150_MINDELAY; 302 return; 303 } 304 if(!strcmp(compass, "compass") 305 || !strcmp(compass, "INV_AK8975") 306 || !strcmp(compass, "AK8975") 307 || !strcmp(compass, "ak8975")) { 308 list->maxRange = COMPASS_AKM8975_RANGE; 309 list->resolution = COMPASS_AKM8975_RESOLUTION; 310 list->power = COMPASS_AKM8975_POWER; 311 list->minDelay = COMPASS_AKM8975_MINDELAY; 312 return; 313 } 314 if(!strcmp(compass, "compass") 315 || !strcmp(compass, "INV_AK8963") 316 || !strcmp(compass, "AK8963") 317 || !strcmp(compass, "ak8963")) { 318 list->maxRange = COMPASS_AKM8963_RANGE; 319 list->resolution = COMPASS_AKM8963_RESOLUTION; 320 list->power = COMPASS_AKM8963_POWER; 321 list->minDelay = COMPASS_AKM8963_MINDELAY; 322 return; 323 } 324 if(!strcmp(compass, "compass") 325 || !strcmp(compass, "INV_AK09911") 326 || !strcmp(compass, "AK09911") 327 || !strcmp(compass, "ak09911")) { 328 list->maxRange = COMPASS_AKM9911_RANGE; 329 list->resolution = COMPASS_AKM9911_RESOLUTION; 330 list->power = COMPASS_AKM9911_POWER; 331 list->minDelay = COMPASS_AKM9911_MINDELAY; 332 return; 333 } 334 if(!strcmp(compass, "compass") 335 || !strncmp(compass, "mlx90399",3) 336 || !strncmp(compass, "MLX90399",3)) { 337 list->maxRange = COMPASS_MPU9350_RANGE; 338 list->resolution = COMPASS_MPU9350_RESOLUTION; 339 list->power = COMPASS_MPU9350_POWER; 340 list->minDelay = COMPASS_MPU9350_MINDELAY; 341 return; 342 } 343 if(!strcmp(compass, "INV_YAS530")) { 344 list->maxRange = COMPASS_YAS53x_RANGE; 345 list->resolution = COMPASS_YAS53x_RESOLUTION; 346 list->power = COMPASS_YAS53x_POWER; 347 list->minDelay = COMPASS_YAS53x_MINDELAY; 348 return; 349 } 350 if(!strcmp(compass, "INV_AMI306")) { 351 list->maxRange = COMPASS_AMI306_RANGE; 352 list->resolution = COMPASS_AMI306_RESOLUTION; 353 list->power = COMPASS_AMI306_POWER; 354 list->minDelay = COMPASS_AMI306_MINDELAY; 355 return; 356 } 357 } 358 LOGE("HAL:unknown compass id %s -- " 359 "params default to ak8975 and might be wrong.", 360 compass); 361 list->maxRange = COMPASS_AKM8975_RANGE; 362 list->resolution = COMPASS_AKM8975_RESOLUTION; 363 list->power = COMPASS_AKM8975_POWER; 364 list->minDelay = COMPASS_AKM8975_MINDELAY; 365 } 366 367 int CompassSensor::inv_init_sysfs_attributes(void) 368 { 369 VFUNC_LOG; 370 371 unsigned char i = 0; 372 char sysfs_path[MAX_SYSFS_NAME_LEN]; 373 char iio_trigger_path[MAX_SYSFS_NAME_LEN], tbuf[2]; 374 char *sptr; 375 char **dptr; 376 int num; 377 378 pathP = (char*)malloc( 379 sizeof(char[COMPASS_MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN])); 380 sptr = pathP; 381 dptr = (char**)&compassSysFs; 382 if (sptr == NULL) 383 return -1; 384 385 memset(sysfs_path, 0, sizeof(sysfs_path)); 386 memset(iio_trigger_path, 0, sizeof(iio_trigger_path)); 387 388 do { 389 *dptr++ = sptr; 390 memset(sptr, 0, sizeof(sptr)); 391 sptr += sizeof(char[MAX_SYSFS_NAME_LEN]); 392 } while (++i < COMPASS_MAX_SYSFS_ATTRB); 393 394 // get proper (in absolute/relative) IIO path & build MPU's sysfs paths 395 // inv_get_sysfs_abs_path(sysfs_path); 396 inv_get_sysfs_path(sysfs_path); 397 inv_get_iio_trigger_path(iio_trigger_path); 398 399 #if defined COMPASS_AK8975 400 inv_get_input_number(dev_name, &num); 401 tbuf[0] = num + 0x30; 402 tbuf[1] = 0; 403 sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf); 404 strcat(sysfs_path, "/ak8975"); 405 406 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable"); 407 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate"); 408 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale"); 409 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix"); 410 #else 411 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/compass_enable"); 412 sprintf(compassSysFs.compass_fifo_enable, "%s%s", sysfs_path, "/compass_fifo_enable"); 413 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/compass_rate"); 414 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale"); 415 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix"); 416 #endif 417 418 #if 0 419 // test print sysfs paths 420 dptr = (char**)&compassSysFs; 421 for (i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) { 422 LOGE("HAL:sysfs path: %s", *dptr++); 423 } 424 #endif 425 return 0; 426 } 427