/* * Copyright (C) 2008-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <ctype.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <math.h> #include <poll.h> #include <pthread.h> #include <stdlib.h> #include <sys/select.h> #include <unistd.h> #define LOG_TAG "CwMcuSensor" #include <cutils/log.h> #include <cutils/properties.h> #include "CwMcuSensor.h" #define REL_Significant_Motion REL_WHEEL #define LIGHTSENSOR_LEVEL 10 #define DEBUG_DATA 0 #define COMPASS_CALIBRATION_DATA_SIZE 26 #define G_SENSOR_CALIBRATION_DATA_SIZE 3 #define NS_PER_MS 1000000LL #define EXHAUSTED_MAGIC 0x77 /*****************************************************************************/ #define IIO_MAX_BUFF_SIZE 4096 #define IIO_MAX_DATA_SIZE 24 #define IIO_MAX_NAME_LENGTH 30 #define IIO_BUF_SIZE_RETRY 8 #define INT32_CHAR_LEN 12 #define INIT_TRIGGER_RETRY 5 static const char iio_dir[] = "/sys/bus/iio/devices/"; static int min(int a, int b) { return (a < b) ? a : b; } static int chomp(char *buf, size_t len) { if (buf == NULL) return -1; while (len > 0 && isspace(buf[len-1])) { buf[len - 1] = '\0'; len--; } return 0; } int CwMcuSensor::sysfs_set_input_attr(const char *attr, char *value, size_t len) { char fname[PATH_MAX]; int fd; int rc; snprintf(fname, sizeof(fname), "%s/%s", mDevPath, attr); fname[sizeof(fname) - 1] = '\0'; fd = open(fname, O_WRONLY); if (fd < 0) { ALOGE("%s: fname = %s, fd = %d, failed: %s\n", __func__, fname, fd, strerror(errno)); return -EACCES; } rc = write(fd, value, (size_t)len); if (rc < 0) { ALOGE("%s: write failed: fd = %d, rc = %d, strerr = %s\n", __func__, fd, rc, strerror(errno)); close(fd); return -EIO; } close(fd); return 0; } int CwMcuSensor::sysfs_set_input_attr_by_int(const char *attr, int value) { char buf[INT32_CHAR_LEN]; size_t n = snprintf(buf, sizeof(buf), "%d", value); if (n > sizeof(buf)) { return -1; } return sysfs_set_input_attr(attr, buf, n); } static inline int find_type_by_name(const char *name, const char *type) { const struct dirent *ent; int number, numstrlen; DIR *dp; char thisname[IIO_MAX_NAME_LENGTH]; char *filename; size_t size; size_t typeLen = strlen(type); size_t nameLen = strlen(name); if (nameLen >= sizeof(thisname) - 1) { return -ERANGE; } dp = opendir(iio_dir); if (dp == NULL) { return -ENODEV; } while (ent = readdir(dp), ent != NULL) { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0 && strlen(ent->d_name) > typeLen && strncmp(ent->d_name, type, typeLen) == 0) { numstrlen = sscanf(ent->d_name + typeLen, "%d", &number); /* verify the next character is not a colon */ if (ent->d_name[strlen(type) + numstrlen] != ':') { size = sizeof(iio_dir) - 1 + typeLen + numstrlen + 6; filename = (char *)malloc(size); if (filename == NULL) return -ENOMEM; snprintf(filename, size, "%s%s%d/name", iio_dir, type, number); int fd = open(filename, O_RDONLY); free(filename); if (fd < 0) { continue; } size = read(fd, thisname, sizeof(thisname) - 1); close(fd); if (size < nameLen) { continue; } thisname[size] = '\0'; if (strncmp(name, thisname, nameLen)) { continue; } // check for termination or whitespace if (!thisname[nameLen] || isspace(thisname[nameLen])) { return number; } } } } return -ENODEV; } int fill_block_debug = 0; pthread_mutex_t sys_fs_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t sync_timestamp_algo_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t last_timestamp_mutex = PTHREAD_MUTEX_INITIALIZER; void CwMcuSensor::sync_time_thread_in_class(void) { int fd; char buf[24]; int err; uint64_t mcu_current_time; uint64_t cpu_current_time; int open_errno; ALOGV("sync_time_thread_in_class++:\n"); pthread_mutex_lock(&sys_fs_mutex); strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "batch_enable"); fd = open(fixed_sysfs_path, O_RDWR); open_errno = errno; pthread_mutex_unlock(&sys_fs_mutex); if (fd >= 0) { err = read(fd, buf, sizeof(buf) - 1); cpu_current_time = getTimestamp(); if (err < 0) { ALOGE("sync_time_thread_in_class: read fail, err = %d\n", err); } else { buf[err] = '\0'; mcu_current_time = strtoull(buf, NULL, 10) * NS_PER_US; if (errno == ERANGE) { ALOGE("sync_time_thread_in_class: strtoll fails, strerr = %s, buf = %s\n", strerror(errno), buf); } else { pthread_mutex_lock(&sync_timestamp_algo_mutex); if (mcu_current_time == 0) { // Do a recovery mechanism of timestamp estimation when the sensor_hub reset happened ALOGE("Sync: sensor hub is on reset\n"); time_slope = 1; memset(last_mcu_timestamp, 0, sizeof(last_mcu_timestamp)); memset(last_cpu_timestamp, 0, sizeof(last_cpu_timestamp)); } else if ((mcu_current_time <= last_mcu_sync_time) || (last_mcu_sync_time == 0)) { ALOGV("Sync: time_slope was not estimated yet\n"); time_slope = 1; time_offset = cpu_current_time - mcu_current_time; } else { time_slope = (float)(cpu_current_time - last_cpu_sync_time) / (float)(mcu_current_time - last_mcu_sync_time); time_offset = cpu_current_time - mcu_current_time; } for (int i=0; i<numSensors; i++) { offset_reset[i] = true; } ALOGV("Sync: time_offset = %" PRId64 ", time_slope = %f\n", time_offset, time_slope); ALOGV("Sync: mcu_current_time = %" PRId64 ", last_mcu_sync_time = %" PRId64 "\n", mcu_current_time, last_mcu_sync_time); ALOGV("Sync: cpu_current_time = %" PRId64 ", last_cpu_sync_time = %" PRId64 "\n", cpu_current_time, last_cpu_sync_time); last_mcu_sync_time = mcu_current_time; last_cpu_sync_time = cpu_current_time; pthread_mutex_unlock(&sync_timestamp_algo_mutex); } } close(fd); } else { ALOGE("sync_time_thread_in_class: open failed, path = .../batch_enable, fd = %d," " strerr = %s\n", fd, strerror(open_errno)); } ALOGV("sync_time_thread_in_class--:\n"); } void *sync_time_thread_run(void *context) { CwMcuSensor *myClass = (CwMcuSensor *)context; while (1) { ALOGV("sync_time_thread_run++:\n"); myClass->sync_time_thread_in_class(); sleep(PERIODIC_SYNC_TIME_SEC); ALOGV("sync_time_thread_run--:\n"); } return NULL; } CwMcuSensor::CwMcuSensor() : SensorBase(NULL, "CwMcuSensor") , mEnabled(0) , mInputReader(IIO_MAX_BUFF_SIZE) , time_slope(1) , time_offset(0) , init_trigger_done(false) { int rc; memset(last_mcu_timestamp, 0, sizeof(last_mcu_timestamp)); memset(last_cpu_timestamp, 0, sizeof(last_cpu_timestamp)); for (int i=0; i<numSensors; i++) { offset_reset[i] = true; } mPendingEvents[CW_ACCELERATION].version = sizeof(sensors_event_t); mPendingEvents[CW_ACCELERATION].sensor = ID_A; mPendingEvents[CW_ACCELERATION].type = SENSOR_TYPE_ACCELEROMETER; mPendingEvents[CW_ACCELERATION].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_MAGNETIC].version = sizeof(sensors_event_t); mPendingEvents[CW_MAGNETIC].sensor = ID_M; mPendingEvents[CW_MAGNETIC].type = SENSOR_TYPE_MAGNETIC_FIELD; mPendingEvents[CW_GYRO].version = sizeof(sensors_event_t); mPendingEvents[CW_GYRO].sensor = ID_GY; mPendingEvents[CW_GYRO].type = SENSOR_TYPE_GYROSCOPE; mPendingEvents[CW_GYRO].gyro.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_LIGHT].version = sizeof(sensors_event_t); mPendingEvents[CW_LIGHT].sensor = ID_L; mPendingEvents[CW_LIGHT].type = SENSOR_TYPE_LIGHT; memset(mPendingEvents[CW_LIGHT].data, 0, sizeof(mPendingEvents[CW_LIGHT].data)); mPendingEvents[CW_PRESSURE].version = sizeof(sensors_event_t); mPendingEvents[CW_PRESSURE].sensor = ID_PS; mPendingEvents[CW_PRESSURE].type = SENSOR_TYPE_PRESSURE; memset(mPendingEvents[CW_PRESSURE].data, 0, sizeof(mPendingEvents[CW_PRESSURE].data)); mPendingEvents[CW_ORIENTATION].version = sizeof(sensors_event_t); mPendingEvents[CW_ORIENTATION].sensor = ID_O; mPendingEvents[CW_ORIENTATION].type = SENSOR_TYPE_ORIENTATION; mPendingEvents[CW_ORIENTATION].orientation.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_ROTATIONVECTOR].version = sizeof(sensors_event_t); mPendingEvents[CW_ROTATIONVECTOR].sensor = ID_RV; mPendingEvents[CW_ROTATIONVECTOR].type = SENSOR_TYPE_ROTATION_VECTOR; mPendingEvents[CW_LINEARACCELERATION].version = sizeof(sensors_event_t); mPendingEvents[CW_LINEARACCELERATION].sensor = ID_LA; mPendingEvents[CW_LINEARACCELERATION].type = SENSOR_TYPE_LINEAR_ACCELERATION; mPendingEvents[CW_GRAVITY].version = sizeof(sensors_event_t); mPendingEvents[CW_GRAVITY].sensor = ID_G; mPendingEvents[CW_GRAVITY].type = SENSOR_TYPE_GRAVITY; mPendingEvents[CW_MAGNETIC_UNCALIBRATED].version = sizeof(sensors_event_t); mPendingEvents[CW_MAGNETIC_UNCALIBRATED].sensor = ID_CW_MAGNETIC_UNCALIBRATED; mPendingEvents[CW_MAGNETIC_UNCALIBRATED].type = SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED; mPendingEvents[CW_GYROSCOPE_UNCALIBRATED].version = sizeof(sensors_event_t); mPendingEvents[CW_GYROSCOPE_UNCALIBRATED].sensor = ID_CW_GYROSCOPE_UNCALIBRATED; mPendingEvents[CW_GYROSCOPE_UNCALIBRATED].type = SENSOR_TYPE_GYROSCOPE_UNCALIBRATED; mPendingEvents[CW_GAME_ROTATION_VECTOR].version = sizeof(sensors_event_t); mPendingEvents[CW_GAME_ROTATION_VECTOR].sensor = ID_CW_GAME_ROTATION_VECTOR; mPendingEvents[CW_GAME_ROTATION_VECTOR].type = SENSOR_TYPE_GAME_ROTATION_VECTOR; mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR].version = sizeof(sensors_event_t); mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR].sensor = ID_CW_GEOMAGNETIC_ROTATION_VECTOR; mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR].type = SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR; mPendingEvents[CW_SIGNIFICANT_MOTION].version = sizeof(sensors_event_t); mPendingEvents[CW_SIGNIFICANT_MOTION].sensor = ID_CW_SIGNIFICANT_MOTION; mPendingEvents[CW_SIGNIFICANT_MOTION].type = SENSOR_TYPE_SIGNIFICANT_MOTION; mPendingEvents[CW_STEP_DETECTOR].version = sizeof(sensors_event_t); mPendingEvents[CW_STEP_DETECTOR].sensor = ID_CW_STEP_DETECTOR; mPendingEvents[CW_STEP_DETECTOR].type = SENSOR_TYPE_STEP_DETECTOR; mPendingEvents[CW_STEP_COUNTER].version = sizeof(sensors_event_t); mPendingEvents[CW_STEP_COUNTER].sensor = ID_CW_STEP_COUNTER; mPendingEvents[CW_STEP_COUNTER].type = SENSOR_TYPE_STEP_COUNTER; mPendingEvents[CW_ACCELERATION_W].version = sizeof(sensors_event_t); mPendingEvents[CW_ACCELERATION_W].sensor = ID_A_W; mPendingEvents[CW_ACCELERATION_W].type = SENSOR_TYPE_ACCELEROMETER; mPendingEvents[CW_ACCELERATION_W].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_MAGNETIC_W].version = sizeof(sensors_event_t); mPendingEvents[CW_MAGNETIC_W].sensor = ID_M_W; mPendingEvents[CW_MAGNETIC_W].type = SENSOR_TYPE_MAGNETIC_FIELD; mPendingEvents[CW_GYRO_W].version = sizeof(sensors_event_t); mPendingEvents[CW_GYRO_W].sensor = ID_GY_W; mPendingEvents[CW_GYRO_W].type = SENSOR_TYPE_GYROSCOPE; mPendingEvents[CW_GYRO_W].gyro.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_PRESSURE_W].version = sizeof(sensors_event_t); mPendingEvents[CW_PRESSURE_W].sensor = ID_PS_W; mPendingEvents[CW_PRESSURE_W].type = SENSOR_TYPE_PRESSURE; memset(mPendingEvents[CW_PRESSURE_W].data, 0, sizeof(mPendingEvents[CW_PRESSURE_W].data)); mPendingEvents[CW_ORIENTATION_W].version = sizeof(sensors_event_t); mPendingEvents[CW_ORIENTATION_W].sensor = ID_O_W; mPendingEvents[CW_ORIENTATION_W].type = SENSOR_TYPE_ORIENTATION; mPendingEvents[CW_ORIENTATION_W].orientation.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[CW_ROTATIONVECTOR_W].version = sizeof(sensors_event_t); mPendingEvents[CW_ROTATIONVECTOR_W].sensor = ID_RV_W; mPendingEvents[CW_ROTATIONVECTOR_W].type = SENSOR_TYPE_ROTATION_VECTOR; mPendingEvents[CW_LINEARACCELERATION_W].version = sizeof(sensors_event_t); mPendingEvents[CW_LINEARACCELERATION_W].sensor = ID_LA_W; mPendingEvents[CW_LINEARACCELERATION_W].type = SENSOR_TYPE_LINEAR_ACCELERATION; mPendingEvents[CW_GRAVITY_W].version = sizeof(sensors_event_t); mPendingEvents[CW_GRAVITY_W].sensor = ID_G_W; mPendingEvents[CW_GRAVITY_W].type = SENSOR_TYPE_GRAVITY; mPendingEvents[CW_MAGNETIC_UNCALIBRATED_W].version = sizeof(sensors_event_t); mPendingEvents[CW_MAGNETIC_UNCALIBRATED_W].sensor = ID_CW_MAGNETIC_UNCALIBRATED_W; mPendingEvents[CW_MAGNETIC_UNCALIBRATED_W].type = SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED; mPendingEvents[CW_GYROSCOPE_UNCALIBRATED_W].version = sizeof(sensors_event_t); mPendingEvents[CW_GYROSCOPE_UNCALIBRATED_W].sensor = ID_CW_GYROSCOPE_UNCALIBRATED_W; mPendingEvents[CW_GYROSCOPE_UNCALIBRATED_W].type = SENSOR_TYPE_GYROSCOPE_UNCALIBRATED; mPendingEvents[CW_GAME_ROTATION_VECTOR_W].version = sizeof(sensors_event_t); mPendingEvents[CW_GAME_ROTATION_VECTOR_W].sensor = ID_CW_GAME_ROTATION_VECTOR_W; mPendingEvents[CW_GAME_ROTATION_VECTOR_W].type = SENSOR_TYPE_GAME_ROTATION_VECTOR; mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR_W].version = sizeof(sensors_event_t); mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR_W].sensor = ID_CW_GEOMAGNETIC_ROTATION_VECTOR_W; mPendingEvents[CW_GEOMAGNETIC_ROTATION_VECTOR_W].type = SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR; mPendingEvents[CW_STEP_DETECTOR_W].version = sizeof(sensors_event_t); mPendingEvents[CW_STEP_DETECTOR_W].sensor = ID_CW_STEP_DETECTOR_W; mPendingEvents[CW_STEP_DETECTOR_W].type = SENSOR_TYPE_STEP_DETECTOR; mPendingEvents[CW_STEP_COUNTER_W].version = sizeof(sensors_event_t); mPendingEvents[CW_STEP_COUNTER_W].sensor = ID_CW_STEP_COUNTER_W; mPendingEvents[CW_STEP_COUNTER_W].type = SENSOR_TYPE_STEP_COUNTER; mPendingEventsFlush.version = META_DATA_VERSION; mPendingEventsFlush.sensor = 0; mPendingEventsFlush.type = SENSOR_TYPE_META_DATA; char buffer_access[PATH_MAX]; const char *device_name = "CwMcuSensor"; int rate = 20, dev_num, enabled = 0, i; dev_num = find_type_by_name(device_name, "iio:device"); if (dev_num < 0) dev_num = 0; snprintf(buffer_access, sizeof(buffer_access), "/dev/iio:device%d", dev_num); data_fd = open(buffer_access, O_RDWR); if (data_fd < 0) { ALOGE("CwMcuSensor::CwMcuSensor: open file '%s' failed: %s\n", buffer_access, strerror(errno)); } if (data_fd >= 0) { int i; int fd; int iio_buf_size; ALOGV("%s: 11 Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: 11 Acquired pthread_mutex_lock()\n", __func__); strcpy(fixed_sysfs_path,"/sys/class/htc_sensorhub/sensor_hub/"); fixed_sysfs_path_len = strlen(fixed_sysfs_path); snprintf(mDevPath, sizeof(mDevPath), "%s%s", fixed_sysfs_path, "iio"); snprintf(mTriggerName, sizeof(mTriggerName), "%s-dev%d", device_name, dev_num); ALOGV("CwMcuSensor::CwMcuSensor: mTriggerName = %s\n", mTriggerName); if (sysfs_set_input_attr_by_int("buffer/enable", 0) < 0) { ALOGE("CwMcuSensor::CwMcuSensor: set IIO buffer enable failed00: %s\n", strerror(errno)); } // This is a piece of paranoia that retry for current_trigger for (i = 0; i < INIT_TRIGGER_RETRY; i++) { rc = sysfs_set_input_attr("trigger/current_trigger", mTriggerName, strlen(mTriggerName)); if (rc < 0) { if (sysfs_set_input_attr_by_int("buffer/enable", 0) < 0) { ALOGE("CwMcuSensor::CwMcuSensor: set IIO buffer enable failed11: %s\n", strerror(errno)); } ALOGE("CwMcuSensor::CwMcuSensor: set current trigger failed: rc = %d, strerr() = %s" ", i = %d\n", rc, strerror(errno), i); } else { init_trigger_done = true; break; } } iio_buf_size = IIO_MAX_BUFF_SIZE; for (i = 0; i < IIO_BUF_SIZE_RETRY; i++) { if (sysfs_set_input_attr_by_int("buffer/length", iio_buf_size) < 0) { ALOGE("CwMcuSensor::CwMcuSensor: set IIO buffer length (%d) failed: %s\n", iio_buf_size, strerror(errno)); } else { if (sysfs_set_input_attr_by_int("buffer/enable", 1) < 0) { ALOGE("CwMcuSensor::CwMcuSensor: set IIO buffer enable failed22: %s, " "i = %d, iio_buf_size = %d\n", strerror(errno), i, iio_buf_size); } else { ALOGI("CwMcuSensor::CwMcuSensor: set IIO buffer length success: %d\n", iio_buf_size); break; } } iio_buf_size /= 2; } strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "calibrator_en"); fd = open(fixed_sysfs_path, O_RDWR); if (fd >= 0) { static const char buf[] = "12"; rc = write(fd, buf, sizeof(buf) - 1); if (rc < 0) { ALOGE("%s: write buf = %s, failed: %s", __func__, buf, strerror(errno)); } close(fd); } else { ALOGE("%s open %s failed: %s", __func__, fixed_sysfs_path, strerror(errno)); } pthread_mutex_unlock(&sys_fs_mutex); ALOGV("%s: data_fd = %d", __func__, data_fd); ALOGV("%s: iio_device_path = %s", __func__, buffer_access); ALOGV("%s: ctrl sysfs_path = %s", __func__, fixed_sysfs_path); setEnable(0, 1); // Inside this function call, we use sys_fs_mutex } int gs_temp_data[G_SENSOR_CALIBRATION_DATA_SIZE] = {0}; int compass_temp_data[COMPASS_CALIBRATION_DATA_SIZE] = {0}; ALOGV("%s: 22 Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: 22 Acquired pthread_mutex_lock()\n", __func__); //Sensor Calibration init . Waiting for firmware ready rc = cw_read_calibrator_file(CW_MAGNETIC, SAVE_PATH_MAG, compass_temp_data); if (rc == 0) { ALOGD("Get compass calibration data from data/misc/ x is %d ,y is %d ,z is %d\n", compass_temp_data[0], compass_temp_data[1], compass_temp_data[2]); strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "calibrator_data_mag"); cw_save_calibrator_file(CW_MAGNETIC, fixed_sysfs_path, compass_temp_data); } else { ALOGI("Compass calibration data does not exist\n"); } rc = cw_read_calibrator_file(CW_ACCELERATION, SAVE_PATH_ACC, gs_temp_data); if (rc == 0) { ALOGD("Get g-sensor user calibration data from data/misc/ x is %d ,y is %d ,z is %d\n", gs_temp_data[0],gs_temp_data[1],gs_temp_data[2]); strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "calibrator_data_acc"); if(!(gs_temp_data[0] == 0 && gs_temp_data[1] == 0 && gs_temp_data[2] == 0 )) { cw_save_calibrator_file(CW_ACCELERATION, fixed_sysfs_path, gs_temp_data); } } else { ALOGI("G-Sensor user calibration data does not exist\n"); } pthread_mutex_unlock(&sys_fs_mutex); pthread_create(&sync_time_thread, (const pthread_attr_t *) NULL, sync_time_thread_run, (void *)this); } CwMcuSensor::~CwMcuSensor() { if (!mEnabled.isEmpty()) { setEnable(0, 0); } } float CwMcuSensor::indexToValue(size_t index) const { static const float luxValues[LIGHTSENSOR_LEVEL] = { 0.0, 10.0, 40.0, 90.0, 160.0, 225.0, 320.0, 640.0, 1280.0, 2600.0 }; const size_t maxIndex = (LIGHTSENSOR_LEVEL - 1); if (index > maxIndex) { index = maxIndex; } return luxValues[index]; } int CwMcuSensor::find_handle(int32_t sensors_id) { switch (sensors_id) { case CW_ACCELERATION: return ID_A; case CW_MAGNETIC: return ID_M; case CW_GYRO: return ID_GY; case CW_PRESSURE: return ID_PS; case CW_ORIENTATION: return ID_O; case CW_ROTATIONVECTOR: return ID_RV; case CW_LINEARACCELERATION: return ID_LA; case CW_GRAVITY: return ID_G; case CW_MAGNETIC_UNCALIBRATED: return ID_CW_MAGNETIC_UNCALIBRATED; case CW_GYROSCOPE_UNCALIBRATED: return ID_CW_GYROSCOPE_UNCALIBRATED; case CW_GAME_ROTATION_VECTOR: return ID_CW_GAME_ROTATION_VECTOR; case CW_GEOMAGNETIC_ROTATION_VECTOR: return ID_CW_GEOMAGNETIC_ROTATION_VECTOR; case CW_LIGHT: return ID_L; case CW_SIGNIFICANT_MOTION: return ID_CW_SIGNIFICANT_MOTION; case CW_STEP_DETECTOR: return ID_CW_STEP_DETECTOR; case CW_STEP_COUNTER: return ID_CW_STEP_COUNTER; case CW_ACCELERATION_W: return ID_A_W; case CW_MAGNETIC_W: return ID_M_W; case CW_GYRO_W: return ID_GY_W; case CW_PRESSURE_W: return ID_PS_W; case CW_ORIENTATION_W: return ID_O_W; case CW_ROTATIONVECTOR_W: return ID_RV_W; case CW_LINEARACCELERATION_W: return ID_LA_W; case CW_GRAVITY_W: return ID_G_W; case CW_MAGNETIC_UNCALIBRATED_W: return ID_CW_MAGNETIC_UNCALIBRATED_W; case CW_GYROSCOPE_UNCALIBRATED_W: return ID_CW_GYROSCOPE_UNCALIBRATED_W; case CW_GAME_ROTATION_VECTOR_W: return ID_CW_GAME_ROTATION_VECTOR_W; case CW_GEOMAGNETIC_ROTATION_VECTOR_W: return ID_CW_GEOMAGNETIC_ROTATION_VECTOR_W; case CW_STEP_DETECTOR_W: return ID_CW_STEP_DETECTOR_W; case CW_STEP_COUNTER_W: return ID_CW_STEP_COUNTER_W; default: return 0xFF; } } bool CwMcuSensor::is_batch_wake_sensor(int32_t handle) { switch (handle) { case ID_A_W: case ID_M_W: case ID_GY_W: case ID_PS_W: case ID_O_W: case ID_RV_W: case ID_LA_W: case ID_G_W: case ID_CW_MAGNETIC_UNCALIBRATED_W: case ID_CW_GYROSCOPE_UNCALIBRATED_W: case ID_CW_GAME_ROTATION_VECTOR_W: case ID_CW_GEOMAGNETIC_ROTATION_VECTOR_W: case ID_CW_STEP_DETECTOR_W: case ID_CW_STEP_COUNTER_W: return true; default: return false; } } int CwMcuSensor::find_sensor(int32_t handle) { int what = -1; switch (handle) { case ID_A: what = CW_ACCELERATION; break; case ID_A_W: what = CW_ACCELERATION_W; break; case ID_M: what = CW_MAGNETIC; break; case ID_M_W: what = CW_MAGNETIC_W; break; case ID_GY: what = CW_GYRO; break; case ID_GY_W: what = CW_GYRO_W; break; case ID_PS: what = CW_PRESSURE; break; case ID_PS_W: what = CW_PRESSURE_W; break; case ID_O: what = CW_ORIENTATION; break; case ID_O_W: what = CW_ORIENTATION_W; break; case ID_RV: what = CW_ROTATIONVECTOR; break; case ID_RV_W: what = CW_ROTATIONVECTOR_W; break; case ID_LA: what = CW_LINEARACCELERATION; break; case ID_LA_W: what = CW_LINEARACCELERATION_W; break; case ID_G: what = CW_GRAVITY; break; case ID_G_W: what = CW_GRAVITY_W; break; case ID_CW_MAGNETIC_UNCALIBRATED: what = CW_MAGNETIC_UNCALIBRATED; break; case ID_CW_MAGNETIC_UNCALIBRATED_W: what = CW_MAGNETIC_UNCALIBRATED_W; break; case ID_CW_GYROSCOPE_UNCALIBRATED: what = CW_GYROSCOPE_UNCALIBRATED; break; case ID_CW_GYROSCOPE_UNCALIBRATED_W: what = CW_GYROSCOPE_UNCALIBRATED_W; break; case ID_CW_GAME_ROTATION_VECTOR: what = CW_GAME_ROTATION_VECTOR; break; case ID_CW_GAME_ROTATION_VECTOR_W: what = CW_GAME_ROTATION_VECTOR_W; break; case ID_CW_GEOMAGNETIC_ROTATION_VECTOR: what = CW_GEOMAGNETIC_ROTATION_VECTOR; break; case ID_CW_GEOMAGNETIC_ROTATION_VECTOR_W: what = CW_GEOMAGNETIC_ROTATION_VECTOR_W; break; case ID_CW_SIGNIFICANT_MOTION: what = CW_SIGNIFICANT_MOTION; break; case ID_CW_STEP_DETECTOR: what = CW_STEP_DETECTOR; break; case ID_CW_STEP_DETECTOR_W: what = CW_STEP_DETECTOR_W; break; case ID_CW_STEP_COUNTER: what = CW_STEP_COUNTER; break; case ID_CW_STEP_COUNTER_W: what = CW_STEP_COUNTER_W; break; case ID_L: what = CW_LIGHT; break; } return what; } int CwMcuSensor::getEnable(int32_t handle) { ALOGV("CwMcuSensor::getEnable: handle = %d\n", handle); return 0; } int CwMcuSensor::setEnable(int32_t handle, int en) { int what; int err = 0; int flags = !!en; int fd; char buf[10]; int temp_data[COMPASS_CALIBRATION_DATA_SIZE]; char value[PROPERTY_VALUE_MAX] = {0}; int rc; ALOGV("%s: Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__); property_get("debug.sensorhal.fill.block", value, "0"); ALOGV("CwMcuSensor::setEnable: debug.sensorhal.fill.block= %s", value); fill_block_debug = atoi(value) == 1; what = find_sensor(handle); ALOGV("CwMcuSensor::setEnable: " "[v13-Dynamic adjust the IIO buffer], handle = %d, en = %d, what = %d\n", handle, en, what); if (uint32_t(what) >= numSensors) { pthread_mutex_unlock(&sys_fs_mutex); return -EINVAL; } if (en) offset_reset[what] = true; strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "enable"); fd = open(fixed_sysfs_path, O_RDWR); if (fd >= 0) { int n = snprintf(buf, sizeof(buf), "%d %d\n", what, flags); err = write(fd, buf, min(n, sizeof(buf))); if (err < 0) { ALOGE("%s: write failed: %s", __func__, strerror(errno)); } close(fd); if (flags) { mEnabled.markBit(what); } else { mEnabled.clearBit(what); } if (mEnabled.isEmpty()) { if (sysfs_set_input_attr_by_int("buffer/enable", 0) < 0) { ALOGE("CwMcuSensor::setEnable: set buffer disable failed: %s\n", strerror(errno)); } else { ALOGV("CwMcuSensor::setEnable: set IIO buffer enable = 0\n"); } } } else { ALOGE("%s open failed: %s", __func__, strerror(errno)); } // Sensor Calibration init. Waiting for firmware ready if (!flags && ((what == CW_MAGNETIC) || (what == CW_ORIENTATION) || (what == CW_ROTATIONVECTOR))) { ALOGV("Save Compass calibration data"); strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "calibrator_data_mag"); rc = cw_read_calibrator_file(CW_MAGNETIC, fixed_sysfs_path, temp_data); if (rc== 0) { cw_save_calibrator_file(CW_MAGNETIC, SAVE_PATH_MAG, temp_data); } else { ALOGI("Compass calibration data from driver fails\n"); } } pthread_mutex_unlock(&sys_fs_mutex); return 0; } int CwMcuSensor::batch(int handle, int flags, int64_t period_ns, int64_t timeout) { int what; int fd; char buf[32] = {0}; int err; int delay_ms; int timeout_ms; bool dryRun = false; ALOGV("CwMcuSensor::batch++: handle = %d, flags = %d, period_ns = %" PRId64 ", timeout = %" PRId64 "\n", handle, flags, period_ns, timeout); what = find_sensor(handle); delay_ms = period_ns/NS_PER_MS; // int64_t is being dropped to an int type timeout_ms = timeout/NS_PER_MS; // int64_t is being dropped to an int type if(flags & SENSORS_BATCH_DRY_RUN) { dryRun = true; } if (uint32_t(what) >= CW_SENSORS_ID_END) { return -EINVAL; } if(is_batch_wake_sensor(handle)) { flags |= SENSORS_BATCH_WAKE_UPON_FIFO_FULL; ALOGV("CwMcuSensor::batch: SENSORS_BATCH_WAKE_UPON_FIFO_FULL~!!\n"); } else flags &= ~SENSORS_BATCH_WAKE_UPON_FIFO_FULL; switch (what) { case CW_LIGHT: case CW_SIGNIFICANT_MOTION: if (timeout > 0) { ALOGI("CwMcuSensor::batch: handle = %d, not support batch mode", handle); return -EINVAL; } break; default: break; } if (dryRun == true) { ALOGV("CwMcuSensor::batch: SENSORS_BATCH_DRY_RUN is set\n"); return 0; } ALOGV("%s: Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__); if (mEnabled.isEmpty()) { int i; int iio_buf_size; if (!init_trigger_done) { err = sysfs_set_input_attr("trigger/current_trigger", mTriggerName, strlen(mTriggerName)); if (err < 0) { ALOGE("CwMcuSensor::batch: set current trigger failed: err = %d, strerr() = %s\n", err, strerror(errno)); } else { init_trigger_done = true; } } iio_buf_size = IIO_MAX_BUFF_SIZE; for (i = 0; i < IIO_BUF_SIZE_RETRY; i++) { if (sysfs_set_input_attr_by_int("buffer/length", iio_buf_size) < 0) { ALOGE("CwMcuSensor::batch: set IIO buffer length (%d) failed: %s\n", iio_buf_size, strerror(errno)); } else { if (sysfs_set_input_attr_by_int("buffer/enable", 1) < 0) { ALOGE("CwMcuSensor::batch: set IIO buffer enable failed: %s, i = %d, " "iio_buf_size = %d\n", strerror(errno), i , iio_buf_size); } else { ALOGI("CwMcuSensor::batch: set IIO buffer length = %d, success\n", iio_buf_size); break; } } iio_buf_size /= 2; } } strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "batch_enable"); fd = open(fixed_sysfs_path, O_RDWR); if (fd < 0) { err = -errno; } else { int n = snprintf(buf, sizeof(buf), "%d %d %d %d\n", what, flags, delay_ms, timeout_ms); err = write(fd, buf, min(n, sizeof(buf))); if (err < 0) { err = -errno; } else { err = 0; } close(fd); } pthread_mutex_unlock(&sys_fs_mutex); ALOGV("CwMcuSensor::batch: fd = %d, sensors_id = %d, flags = %d, delay_ms= %d," " timeout_ms = %d, path = %s, err = %d\n", fd , what, flags, delay_ms, timeout_ms, fixed_sysfs_path, err); return err; } int CwMcuSensor::flush(int handle) { int what; int fd; char buf[10] = {0}; int err; what = find_sensor(handle); if (uint32_t(what) >= CW_SENSORS_ID_END) { return -EINVAL; } ALOGV("%s: Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__); strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "flush"); fd = open(fixed_sysfs_path, O_RDWR); if (fd >= 0) { int n = snprintf(buf, sizeof(buf), "%d\n", what); err = write(fd, buf, min(n, sizeof(buf))); if (err < 0) { err = -errno; } else { err = 0; } close(fd); } else { ALOGI("CwMcuSensor::flush: flush not supported\n"); err = -EINVAL; } pthread_mutex_unlock(&sys_fs_mutex); ALOGI("CwMcuSensor::flush: fd = %d, sensors_id = %d, path = %s, err = %d\n", fd, what, fixed_sysfs_path, err); return err; } bool CwMcuSensor::hasPendingEvents() const { return !mPendingMask.isEmpty(); } int CwMcuSensor::setDelay(int32_t handle, int64_t delay_ns) { char buf[80]; int fd; int what; int rc; ALOGV("%s: Before pthread_mutex_lock()\n", __func__); pthread_mutex_lock(&sys_fs_mutex); ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__); ALOGV("CwMcuSensor::setDelay: handle = %" PRId32 ", delay_ns = %" PRId64 "\n", handle, delay_ns); what = find_sensor(handle); if (uint32_t(what) >= numSensors) { pthread_mutex_unlock(&sys_fs_mutex); return -EINVAL; } strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "delay_ms"); fd = open(fixed_sysfs_path, O_RDWR); if (fd >= 0) { size_t n = snprintf(buf, sizeof(buf), "%d %lld\n", what, (delay_ns/NS_PER_MS)); write(fd, buf, min(n, sizeof(buf))); close(fd); } pthread_mutex_unlock(&sys_fs_mutex); return 0; } void CwMcuSensor::calculate_rv_4th_element(int sensors_id) { switch (sensors_id) { case CW_ROTATIONVECTOR: case CW_GAME_ROTATION_VECTOR: case CW_GEOMAGNETIC_ROTATION_VECTOR: case CW_ROTATIONVECTOR_W: case CW_GAME_ROTATION_VECTOR_W: case CW_GEOMAGNETIC_ROTATION_VECTOR_W: float q0, q1, q2, q3; q1 = mPendingEvents[sensors_id].data[0]; q2 = mPendingEvents[sensors_id].data[1]; q3 = mPendingEvents[sensors_id].data[2]; q0 = 1 - q1*q1 - q2*q2 - q3*q3; q0 = (q0 > 0) ? (float)sqrt(q0) : 0; mPendingEvents[sensors_id].data[3] = q0; break; default: break; } } int CwMcuSensor::readEvents(sensors_event_t* data, int count) { uint64_t mtimestamp; if (count < 1) { return -EINVAL; } ALOGD_IF(fill_block_debug == 1, "CwMcuSensor::readEvents: Before fill\n"); ssize_t n = mInputReader.fill(data_fd); ALOGD_IF(fill_block_debug == 1, "CwMcuSensor::readEvents: After fill, n = %zd\n", n); if (n < 0) { return n; } cw_event const* event; uint8_t data_temp[24]; int id; int numEventReceived = 0; while (count && mInputReader.readEvent(&event)) { memcpy(data_temp, event->data, sizeof(data_temp)); id = processEvent(data_temp); if (id == CW_META_DATA) { *data++ = mPendingEventsFlush; count--; numEventReceived++; ALOGV("CwMcuSensor::readEvents: metadata = %d\n", mPendingEventsFlush.meta_data.sensor); } else if ((id == TIME_DIFF_EXHAUSTED) || (id == CW_TIME_BASE)) { ALOGV("readEvents: id = %d\n", id); } else { /*** The algorithm which parsed mcu_time into cpu_time for each event ***/ uint64_t event_mcu_time = mPendingEvents[id].timestamp; uint64_t event_cpu_time; if (event_mcu_time < last_mcu_timestamp[id]) { ALOGE("Do syncronization due to wrong delta mcu_timestamp\n"); ALOGE("curr_ts = %" PRIu64 " ns, last_ts = %" PRIu64 " ns", event_mcu_time, last_mcu_timestamp[id]); sync_time_thread_in_class(); } pthread_mutex_lock(&sync_timestamp_algo_mutex); if (offset_reset[id]) { ALOGV("offset changed, id = %d, offset = %" PRId64 "\n", id, time_offset); offset_reset[id] = false; event_cpu_time = event_mcu_time + time_offset; if (event_cpu_time <= last_cpu_timestamp[id]) { int64_t event_mcu_diff = (event_mcu_time - last_mcu_timestamp[id]); int64_t event_cpu_diff = event_mcu_diff * time_slope; event_cpu_time = last_cpu_timestamp[id] + event_cpu_diff; } } else { int64_t event_mcu_diff = (event_mcu_time - last_mcu_timestamp[id]); int64_t event_cpu_diff = event_mcu_diff * time_slope; event_cpu_time = last_cpu_timestamp[id] + event_cpu_diff; } pthread_mutex_unlock(&sync_timestamp_algo_mutex); pthread_mutex_lock(&last_timestamp_mutex); mtimestamp = getTimestamp(); ALOGV("readEvents: id = %d, accuracy = %d\n" , id , mPendingEvents[id].acceleration.status); ALOGV("readEvents: id = %d," " mcu_time = %" PRId64 " ms," " cpu_time = %" PRId64 " ns," " delta = %" PRId64 " us," " HALtime = %" PRId64 " ns\n", id, event_mcu_time / NS_PER_MS, event_cpu_time, (event_cpu_time - last_cpu_timestamp[id]) / NS_PER_US, mtimestamp); event_cpu_time = (mtimestamp > event_cpu_time) ? event_cpu_time : mtimestamp; last_mcu_timestamp[id] = event_mcu_time; last_cpu_timestamp[id] = event_cpu_time; pthread_mutex_unlock(&last_timestamp_mutex); /*** The algorithm which parsed mcu_time into cpu_time for each event ***/ mPendingEvents[id].timestamp = event_cpu_time; if (mEnabled.hasBit(id)) { if (id == CW_SIGNIFICANT_MOTION) { setEnable(ID_CW_SIGNIFICANT_MOTION, 0); } calculate_rv_4th_element(id); *data++ = mPendingEvents[id]; count--; numEventReceived++; } } mInputReader.next(); } return numEventReceived; } int CwMcuSensor::processEvent(uint8_t *event) { int sensorsid = 0; int16_t data[3]; int16_t bias[3]; int64_t time; sensorsid = (int)event[0]; memcpy(data, &event[1], 6); memcpy(bias, &event[7], 6); memcpy(&time, &event[13], 8); mPendingEvents[sensorsid].timestamp = time * NS_PER_MS; switch (sensorsid) { case CW_ORIENTATION: case CW_ORIENTATION_W: mPendingMask.markBit(sensorsid); if ((sensorsid == CW_ORIENTATION) || (sensorsid == CW_ORIENTATION_W)) { mPendingEvents[sensorsid].orientation.status = bias[0]; } mPendingEvents[sensorsid].data[0] = (float)data[0] * CONVERT_10; mPendingEvents[sensorsid].data[1] = (float)data[1] * CONVERT_10; mPendingEvents[sensorsid].data[2] = (float)data[2] * CONVERT_10; break; case CW_ACCELERATION: case CW_MAGNETIC: case CW_GYRO: case CW_LINEARACCELERATION: case CW_GRAVITY: case CW_ACCELERATION_W: case CW_MAGNETIC_W: case CW_GYRO_W: case CW_LINEARACCELERATION_W: case CW_GRAVITY_W: mPendingMask.markBit(sensorsid); if ((sensorsid == CW_MAGNETIC) || (sensorsid == CW_MAGNETIC_W)) { mPendingEvents[sensorsid].magnetic.status = bias[0]; ALOGV("CwMcuSensor::processEvent: magnetic accuracy = %d\n", mPendingEvents[sensorsid].magnetic.status); } mPendingEvents[sensorsid].data[0] = (float)data[0] * CONVERT_100; mPendingEvents[sensorsid].data[1] = (float)data[1] * CONVERT_100; mPendingEvents[sensorsid].data[2] = (float)data[2] * CONVERT_100; break; case CW_PRESSURE: case CW_PRESSURE_W: mPendingMask.markBit(sensorsid); // .pressure is data[0] and the unit is hectopascal (hPa) mPendingEvents[sensorsid].pressure = ((float)*(int32_t *)(&data[0])) * CONVERT_100; // data[1] is not used, and data[2] is the temperature mPendingEvents[sensorsid].data[2] = ((float)data[2]) * CONVERT_100; break; case CW_ROTATIONVECTOR: case CW_GAME_ROTATION_VECTOR: case CW_GEOMAGNETIC_ROTATION_VECTOR: case CW_ROTATIONVECTOR_W: case CW_GAME_ROTATION_VECTOR_W: case CW_GEOMAGNETIC_ROTATION_VECTOR_W: mPendingMask.markBit(sensorsid); mPendingEvents[sensorsid].data[0] = (float)data[0] * CONVERT_10000; mPendingEvents[sensorsid].data[1] = (float)data[1] * CONVERT_10000; mPendingEvents[sensorsid].data[2] = (float)data[2] * CONVERT_10000; break; case CW_MAGNETIC_UNCALIBRATED: case CW_GYROSCOPE_UNCALIBRATED: case CW_MAGNETIC_UNCALIBRATED_W: case CW_GYROSCOPE_UNCALIBRATED_W: mPendingMask.markBit(sensorsid); mPendingEvents[sensorsid].data[0] = (float)data[0] * CONVERT_100; mPendingEvents[sensorsid].data[1] = (float)data[1] * CONVERT_100; mPendingEvents[sensorsid].data[2] = (float)data[2] * CONVERT_100; mPendingEvents[sensorsid].data[3] = (float)bias[0] * CONVERT_100; mPendingEvents[sensorsid].data[4] = (float)bias[1] * CONVERT_100; mPendingEvents[sensorsid].data[5] = (float)bias[2] * CONVERT_100; break; case CW_SIGNIFICANT_MOTION: mPendingMask.markBit(sensorsid); mPendingEvents[sensorsid].data[0] = 1.0; ALOGV("SIGNIFICANT timestamp = %" PRIu64 "\n", mPendingEvents[sensorsid].timestamp); break; case CW_LIGHT: mPendingMask.markBit(sensorsid); mPendingEvents[sensorsid].light = indexToValue(data[0]); break; case CW_STEP_DETECTOR: case CW_STEP_DETECTOR_W: mPendingMask.markBit(sensorsid); mPendingEvents[sensorsid].data[0] = data[0]; ALOGV("STEP_DETECTOR, timestamp = %" PRIu64 "\n", mPendingEvents[sensorsid].timestamp); break; case CW_STEP_COUNTER: case CW_STEP_COUNTER_W: mPendingMask.markBit(sensorsid); // We use 4 bytes in SensorHUB mPendingEvents[sensorsid].u64.step_counter = *(uint32_t *)&data[0]; mPendingEvents[sensorsid].u64.step_counter += 0x100000000LL * (*(uint32_t *)&bias[0]); ALOGV("processEvent: step counter = %" PRId64 "\n", mPendingEvents[sensorsid].u64.step_counter); break; case CW_META_DATA: mPendingEventsFlush.meta_data.what = META_DATA_FLUSH_COMPLETE; mPendingEventsFlush.meta_data.sensor = find_handle(data[0]); ALOGV("CW_META_DATA: meta_data.sensor = %d, data[0] = %d\n", mPendingEventsFlush.meta_data.sensor, data[0]); break; default: ALOGW("%s: Unknown sensorsid = %d\n", __func__, sensorsid); break; } return sensorsid; } void CwMcuSensor::cw_save_calibrator_file(int type, const char * path, int* str) { FILE *fp_file; int i; int rc; ALOGV("CwMcuSensor::cw_save_calibrator_file: path = %s\n", path); fp_file = fopen(path, "w+"); if (!fp_file) { ALOGE("CwMcuSensor::cw_save_calibrator_file: open file '%s' failed: %s\n", path, strerror(errno)); return; } if ((type == CW_GYRO) || (type == CW_ACCELERATION)) { fprintf(fp_file, "%d %d %d\n", str[0], str[1], str[2]); } else if(type == CW_MAGNETIC) { for (i = 0; i < COMPASS_CALIBRATION_DATA_SIZE; i++) { ALOGV("CwMcuSensor::cw_save_calibrator_file: str[%d] = %d\n", i, str[i]); rc = fprintf(fp_file, "%d%c", str[i], (i == (COMPASS_CALIBRATION_DATA_SIZE-1)) ? '\n' : ' '); if (rc < 0) { ALOGE("CwMcuSensor::cw_save_calibrator_file: fprintf fails, rc = %d\n", rc); } } } fclose(fp_file); return; } int CwMcuSensor::cw_read_calibrator_file(int type, const char * path, int* str) { FILE *fp; int readBytes; int data[COMPASS_CALIBRATION_DATA_SIZE] = {0}; unsigned int i; int my_errno; ALOGV("CwMcuSensor::cw_read_calibrator_file: path = %s\n", path); fp = fopen(path, "r"); if (!fp) { ALOGE("CwMcuSensor::cw_read_calibrator_file: open file '%s' failed: %s\n", path, strerror(errno)); // errno is reset to 0 before return return -1; } if (type == CW_GYRO || type == CW_ACCELERATION) { readBytes = fscanf(fp, "%d %d %d\n", &str[0], &str[1], &str[2]); my_errno = errno; if (readBytes != 3) { ALOGE("CwMcuSensor::cw_read_calibrator_file: fscanf3, readBytes = %d, strerror = %s\n", readBytes, strerror(my_errno)); } } else if (type == CW_MAGNETIC) { ALOGV("CwMcuSensor::cw_read_calibrator_file: COMPASS_CALIBRATION_DATA_SIZE = %d\n", COMPASS_CALIBRATION_DATA_SIZE); // COMPASS_CALIBRATION_DATA_SIZE is 26 for (i = 0; i < COMPASS_CALIBRATION_DATA_SIZE; i++) { readBytes = fscanf(fp, "%d ", &str[i]); my_errno = errno; ALOGV("CwMcuSensor::cw_read_calibrator_file: str[%d] = %d\n", i, str[i]); if (readBytes < 1) { ALOGE("CwMcuSensor::cw_read_calibrator_file: fscanf26, readBytes = %d, strerror = %s\n", readBytes, strerror(my_errno)); fclose(fp); return readBytes; } } } fclose(fp); return 0; }