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 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 res = write_sysfs_int(compassSysFs.compass_enable, en); 146 return res; 147 } 148 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 168 int CompassSensor::turnOffCompassFifo(void) 169 { 170 int i, res = 0, tempFd; 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 177 int CompassSensor::turnOnCompassFifo(void) 178 { 179 int i, res = 0, tempFd; 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 **/ 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) 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 221 void CompassSensor::getOrientationMatrix(signed char *orient) 222 { 223 VFUNC_LOG; 224 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation)); 225 } 226 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 */ 246 int CompassSensor::readSample(long *data, int64_t *timestamp) 247 { 248 VHANDLER_LOG; 249 250 int numEventReceived = 0, 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 */ 282 int64_t CompassSensor::getDelay(int32_t handle) 283 { 284 VFUNC_LOG; 285 return mDelay; 286 } 287 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 345 int CompassSensor::inv_init_sysfs_attributes(void) 346 { 347 VFUNC_LOG; 348 349 unsigned char i = 0; 350 char sysfs_path[MAX_SYSFS_NAME_LEN]; 351 char iio_trigger_path[MAX_SYSFS_NAME_LEN], tbuf[2]; 352 char *sptr; 353 char **dptr; 354 int num; 355 356 pathP = (char*)malloc( 357 sizeof(char[COMPASS_MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN])); 358 sptr = pathP; 359 dptr = (char**)&compassSysFs; 360 if (sptr == NULL) 361 return -1; 362 363 memset(sysfs_path, 0, sizeof(sysfs_path)); 364 memset(iio_trigger_path, 0, sizeof(iio_trigger_path)); 365 366 do { 367 *dptr++ = sptr; 368 memset(sptr, 0, sizeof(sptr)); 369 sptr += sizeof(char[MAX_SYSFS_NAME_LEN]); 370 } while (++i < COMPASS_MAX_SYSFS_ATTRB); 371 372 // get proper (in absolute/relative) IIO path & build MPU's sysfs paths 373 // inv_get_sysfs_abs_path(sysfs_path); 374 inv_get_sysfs_path(sysfs_path); 375 inv_get_iio_trigger_path(iio_trigger_path); 376 377 if (strcmp(sysfs_path, "") == 0 || strcmp(iio_trigger_path, "") == 0) 378 return 0; 379 380 #if defined COMPASS_AK8975 381 inv_get_input_number(dev_name, &num); 382 tbuf[0] = num + 0x30; 383 tbuf[1] = 0; 384 sprintf(sysfs_path, "%s%s", "sys/class/input/input", tbuf); 385 strcat(sysfs_path, "/ak8975"); 386 387 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/enable"); 388 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/rate"); 389 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/scale"); 390 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix"); 391 #else 392 sprintf(compassSysFs.compass_enable, "%s%s", sysfs_path, "/compass_enable"); 393 sprintf(compassSysFs.compass_fifo_enable, "%s%s", sysfs_path, "/compass_fifo_enable"); 394 sprintf(compassSysFs.compass_rate, "%s%s", sysfs_path, "/compass_rate"); 395 sprintf(compassSysFs.compass_scale, "%s%s", sysfs_path, "/in_magn_scale"); 396 sprintf(compassSysFs.compass_orient, "%s%s", sysfs_path, "/compass_matrix"); 397 #endif 398 399 #if 0 400 // test print sysfs paths 401 dptr = (char**)&compassSysFs; 402 for (i = 0; i < COMPASS_MAX_SYSFS_ATTRB; i++) { 403 LOGE("HAL:sysfs path: %s", *dptr++); 404 } 405 #endif 406 return 0; 407 } 408