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", 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 126 CompassSensor::~CompassSensor() 127 { 128 VFUNC_LOG; 129 130 free(pathP); 131 if( compass_fd > 0) 132 close(compass_fd); 133 } 134 135 int 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 */ 150 int 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 161 int 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 **/ 185 int 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) 193 void 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 216 void CompassSensor::getOrientationMatrix(signed char *orient) 217 { 218 VFUNC_LOG; 219 memcpy(orient, mCompassOrientation, sizeof(mCompassOrientation)); 220 } 221 222 long 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 */ 241 int 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 */ 277 int64_t CompassSensor::getDelay(int32_t handle) 278 { 279 VFUNC_LOG; 280 return mDelay; 281 } 282 283 void 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 331 int 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