diff options
Diffstat (limited to '6515/libsensors_iio/MPLSensor.cpp')
-rw-r--r-- | 6515/libsensors_iio/MPLSensor.cpp | 6444 |
1 files changed, 6444 insertions, 0 deletions
diff --git a/6515/libsensors_iio/MPLSensor.cpp b/6515/libsensors_iio/MPLSensor.cpp new file mode 100644 index 0000000..9721734 --- /dev/null +++ b/6515/libsensors_iio/MPLSensor.cpp @@ -0,0 +1,6444 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* 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. +*/ + +#define LOG_NDEBUG 0 + +//see also the EXTRA_VERBOSE define in the MPLSensor.h header file + +#include <fcntl.h> +#include <errno.h> +#include <math.h> +#include <float.h> +#include <poll.h> +#include <unistd.h> +#include <dirent.h> +#include <stdlib.h> +#include <sys/select.h> +#include <sys/syscall.h> +#include <dlfcn.h> +#include <pthread.h> +#include <cutils/log.h> +#include <utils/KeyedVector.h> +#include <utils/String8.h> +#include <string.h> +#include <linux/input.h> +#include <utils/Atomic.h> + +#include "MPLSensor.h" +#include "PressureSensor.IIO.secondary.h" +#include "MPLSupport.h" +#include "sensor_params.h" + +#include "invensense.h" +#include "invensense_adv.h" +#include "ml_stored_data.h" +#include "ml_load_dmp.h" +#include "ml_sysfs_helper.h" + +#define ENABLE_MULTI_RATE +// #define TESTING +#define USE_LPQ_AT_FASTEST + +#ifdef THIRD_PARTY_ACCEL +#pragma message("HAL:build third party accel support") +#define USE_THIRD_PARTY_ACCEL (1) +#else +#define USE_THIRD_PARTY_ACCEL (0) +#endif + +#define MAX_SYSFS_ATTRB (sizeof(struct sysfs_attrbs) / sizeof(char*)) + +/******************************************************************************/ +/* MPL Interface */ +/******************************************************************************/ + +//#define INV_PLAYBACK_DBG +#ifdef INV_PLAYBACK_DBG +static FILE *logfile = NULL; +#endif + +/******************************************************************************* + * MPLSensor class implementation + ******************************************************************************/ + +static struct timespec mt_pre; + +// following extended initializer list would only be available with -std=c++11 +// or -std=gnu+11 +MPLSensor::MPLSensor(CompassSensor *compass, int (*m_pt2AccelCalLoadFunc)(long *)) + : SensorBase(NULL, NULL), + mMasterSensorMask(INV_ALL_SENSORS), + mLocalSensorMask(0), + mPollTime(-1), + mStepCountPollTime(-1), + mHaveGoodMpuCal(0), + mGyroAccuracy(0), + mAccelAccuracy(0), + mCompassAccuracy(0), + dmp_orient_fd(-1), + mDmpOrientationEnabled(0), + dmp_sign_motion_fd(-1), + mDmpSignificantMotionEnabled(0), + dmp_pedometer_fd(-1), + mDmpPedometerEnabled(0), + mDmpStepCountEnabled(0), + mEnabled(0), + mBatchEnabled(0), + mFlushSensorEnabled(-1), + mOldBatchEnabledMask(0), + mAccelInputReader(4), + mGyroInputReader(32), + mTempScale(0), + mTempOffset(0), + mTempCurrentTime(0), + mAccelScale(2), + mAccelSelfTestScale(2), + mGyroScale(2000), + mGyroSelfTestScale(2000), + mCompassScale(0), + mFactoryGyroBiasAvailable(false), + mGyroBiasAvailable(false), + mGyroBiasApplied(false), + mFactoryAccelBiasAvailable(false), + mAccelBiasAvailable(false), + mAccelBiasApplied(false), + mPendingMask(0), + mSensorMask(0), + mMplFeatureActiveMask(0), + mFeatureActiveMask(0), + mDmpOn(0), + mPedUpdate(0), + mPressureUpdate(0), + mQuatSensorTimestamp(0), + mStepSensorTimestamp(0), + mLastStepCount(0), + mLeftOverBufferSize(0), + mInitial6QuatValueAvailable(0), + mFlushBatchSet(0), + mSkipReadEvents(0), + mDataMarkerDetected(0), + mEmptyDataMarkerDetected(0) { + VFUNC_LOG; + + inv_error_t rv; + int i, fd; + char *port = NULL; + char *ver_str; + unsigned long mSensorMask; + int res; + FILE *fptr; + + mCompassSensor = compass; + + LOGV_IF(EXTRA_VERBOSE, + "HAL:MPLSensor constructor : NumSensors = %d", NumSensors); + + pthread_mutex_init(&mMplMutex, NULL); + pthread_mutex_init(&mHALMutex, NULL); + memset(mGyroOrientation, 0, sizeof(mGyroOrientation)); + memset(mAccelOrientation, 0, sizeof(mAccelOrientation)); + memset(mInitial6QuatValue, 0, sizeof(mInitial6QuatValue)); + + /* setup sysfs paths */ + inv_init_sysfs_attributes(); + + /* get chip name */ + if (inv_get_chip_name(chip_ID) != INV_SUCCESS) { + LOGE("HAL:ERR- Failed to get chip ID\n"); + } else { + LOGV_IF(PROCESS_VERBOSE, "HAL:Chip ID= %s\n", chip_ID); + } + + enable_iio_sysfs(); + + /* instantiate pressure sensor on secondary bus */ + mPressureSensor = new PressureSensor((const char*)mSysfsPath); + + /* reset driver master enable */ + masterEnable(0); + + /* Load DMP image if capable, ie. MPU6515 */ + loadDMP(); + + /* open temperature fd for temp comp */ + LOGV_IF(EXTRA_VERBOSE, "HAL:gyro temperature path: %s", mpu.temperature); + gyro_temperature_fd = open(mpu.temperature, O_RDONLY); + if (gyro_temperature_fd == -1) { + LOGE("HAL:could not open temperature node"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:temperature_fd opened: %s", mpu.temperature); + } + + /* read gyro FSR to calculate accel scale later */ + char gyroBuf[5]; + int count = 0; + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.gyro_fsr, getTimestamp()); + + fd = open(mpu.gyro_fsr, O_RDONLY); + if(fd < 0) { + LOGE("HAL:Error opening gyro FSR"); + } else { + memset(gyroBuf, 0, sizeof(gyroBuf)); + count = read_attribute_sensor(fd, gyroBuf, sizeof(gyroBuf)); + if(count < 1) { + LOGE("HAL:Error reading gyro FSR"); + } else { + count = sscanf(gyroBuf, "%ld", &mGyroScale); + if(count) + LOGV_IF(EXTRA_VERBOSE, "HAL:Gyro FSR used %ld", mGyroScale); + } + close(fd); + } + + /* read gyro self test scale used to calculate factory cal bias later */ + char gyroScale[5]; + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.in_gyro_self_test_scale, getTimestamp()); + fd = open(mpu.in_gyro_self_test_scale, O_RDONLY); + if(fd < 0) { + LOGE("HAL:Error opening gyro self test scale"); + } else { + memset(gyroBuf, 0, sizeof(gyroBuf)); + count = read_attribute_sensor(fd, gyroScale, sizeof(gyroScale)); + if(count < 1) { + LOGE("HAL:Error reading gyro self test scale"); + } else { + count = sscanf(gyroScale, "%ld", &mGyroSelfTestScale); + if(count) + LOGV_IF(EXTRA_VERBOSE, "HAL:Gyro self test scale used %ld", mGyroSelfTestScale); + } + close(fd); + } + + /* open Factory Gyro Bias fd */ + /* mFactoryGyBias contains bias values that will be used for device offset */ + memset(mFactoryGyroBias, 0, sizeof(mFactoryGyroBias)); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory gyro x offset path: %s", mpu.in_gyro_x_offset); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory gyro y offset path: %s", mpu.in_gyro_y_offset); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory gyro z offset path: %s", mpu.in_gyro_z_offset); + gyro_x_offset_fd = open(mpu.in_gyro_x_offset, O_RDWR); + gyro_y_offset_fd = open(mpu.in_gyro_y_offset, O_RDWR); + gyro_z_offset_fd = open(mpu.in_gyro_z_offset, O_RDWR); + if (gyro_x_offset_fd == -1 || + gyro_y_offset_fd == -1 || gyro_z_offset_fd == -1) { + LOGE("HAL:could not open factory gyro calibrated bias"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:gyro_offset opened"); + } + + /* open Gyro Bias fd */ + /* mGyroBias contains bias values that will be used for framework */ + /* mGyroChipBias contains bias values that will be used for dmp */ + memset(mGyroBias, 0, sizeof(mGyroBias)); + memset(mGyroChipBias, 0, sizeof(mGyroChipBias)); + LOGV_IF(EXTRA_VERBOSE, "HAL: gyro x dmp bias path: %s", mpu.in_gyro_x_dmp_bias); + LOGV_IF(EXTRA_VERBOSE, "HAL: gyro y dmp bias path: %s", mpu.in_gyro_y_dmp_bias); + LOGV_IF(EXTRA_VERBOSE, "HAL: gyro z dmp bias path: %s", mpu.in_gyro_z_dmp_bias); + gyro_x_dmp_bias_fd = open(mpu.in_gyro_x_dmp_bias, O_RDWR); + gyro_y_dmp_bias_fd = open(mpu.in_gyro_y_dmp_bias, O_RDWR); + gyro_z_dmp_bias_fd = open(mpu.in_gyro_z_dmp_bias, O_RDWR); + if (gyro_x_dmp_bias_fd == -1 || + gyro_y_dmp_bias_fd == -1 || gyro_z_dmp_bias_fd == -1) { + LOGE("HAL:could not open gyro DMP calibrated bias"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:gyro_dmp_bias opened"); + } + + /* read accel FSR to calcuate accel scale later */ + if (USE_THIRD_PARTY_ACCEL == 0) { + char buf[3]; + int count = 0; + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.accel_fsr, getTimestamp()); + + fd = open(mpu.accel_fsr, O_RDONLY); + if(fd < 0) { + LOGE("HAL:Error opening accel FSR"); + } else { + memset(buf, 0, sizeof(buf)); + count = read_attribute_sensor(fd, buf, sizeof(buf)); + if(count < 1) { + LOGE("HAL:Error reading accel FSR"); + } else { + count = sscanf(buf, "%d", &mAccelScale); + if(count) + LOGV_IF(EXTRA_VERBOSE, "HAL:Accel FSR used %d", mAccelScale); + } + close(fd); + } + + /* read accel self test scale used to calculate factory cal bias later */ + char accelScale[5]; + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.in_accel_self_test_scale, getTimestamp()); + fd = open(mpu.in_accel_self_test_scale, O_RDONLY); + if(fd < 0) { + LOGE("HAL:Error opening gyro self test scale"); + } else { + memset(buf, 0, sizeof(buf)); + count = read_attribute_sensor(fd, accelScale, sizeof(accelScale)); + if(count < 1) { + LOGE("HAL:Error reading accel self test scale"); + } else { + count = sscanf(accelScale, "%ld", &mAccelSelfTestScale); + if(count) + LOGV_IF(EXTRA_VERBOSE, "HAL:Accel self test scale used %ld", mAccelSelfTestScale); + } + close(fd); + } + + /* open Factory Accel Bias fd */ + /* mFactoryAccelBias contains bias values that will be used for device offset */ + memset(mFactoryAccelBias, 0, sizeof(mFactoryAccelBias)); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory accel x offset path: %s", mpu.in_accel_x_offset); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory accel y offset path: %s", mpu.in_accel_y_offset); + LOGV_IF(EXTRA_VERBOSE, "HAL:factory accel z offset path: %s", mpu.in_accel_z_offset); + accel_x_offset_fd = open(mpu.in_accel_x_offset, O_RDWR); + accel_y_offset_fd = open(mpu.in_accel_y_offset, O_RDWR); + accel_z_offset_fd = open(mpu.in_accel_z_offset, O_RDWR); + if (accel_x_offset_fd == -1 || + accel_y_offset_fd == -1 || accel_z_offset_fd == -1) { + LOGE("HAL:could not open factory accel calibrated bias"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:accel_offset opened"); + } + + /* open Accel Bias fd */ + /* mAccelBias contains bias that will be used for dmp */ + memset(mAccelBias, 0, sizeof(mAccelBias)); + LOGV_IF(EXTRA_VERBOSE, "HAL:accel x dmp bias path: %s", mpu.in_accel_x_dmp_bias); + LOGV_IF(EXTRA_VERBOSE, "HAL:accel y dmp bias path: %s", mpu.in_accel_y_dmp_bias); + LOGV_IF(EXTRA_VERBOSE, "HAL:accel z dmp bias path: %s", mpu.in_accel_z_dmp_bias); + accel_x_dmp_bias_fd = open(mpu.in_accel_x_dmp_bias, O_RDWR); + accel_y_dmp_bias_fd = open(mpu.in_accel_y_dmp_bias, O_RDWR); + accel_z_dmp_bias_fd = open(mpu.in_accel_z_dmp_bias, O_RDWR); + if (accel_x_dmp_bias_fd == -1 || + accel_y_dmp_bias_fd == -1 || accel_z_dmp_bias_fd == -1) { + LOGE("HAL:could not open accel DMP calibrated bias"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:accel_dmp_bias opened"); + } + } + + dmp_sign_motion_fd = open(mpu.event_smd, O_RDONLY | O_NONBLOCK); + if (dmp_sign_motion_fd < 0) { + LOGE("HAL:ERR couldn't open dmp_sign_motion node"); + } else { + LOGV_IF(ENG_VERBOSE, + "HAL:dmp_sign_motion_fd opened : %d", dmp_sign_motion_fd); + } +#if 1 + /* the following threshold can be modified for SMD sensitivity */ + int motionThreshold = 3000; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + motionThreshold, mpu.smd_threshold, getTimestamp()); + res = write_sysfs_int(mpu.smd_threshold, motionThreshold); +#endif + dmp_pedometer_fd = open(mpu.event_pedometer, O_RDONLY | O_NONBLOCK); + if (dmp_pedometer_fd < 0) { + LOGE("HAL:ERR couldn't open dmp_pedometer node"); + } else { + LOGV_IF(ENG_VERBOSE, + "HAL:dmp_pedometer_fd opened : %d", dmp_pedometer_fd); + } + + initBias(); + + (void)inv_get_version(&ver_str); + LOGI("%s\n", ver_str); + + /* setup MPL */ + inv_constructor_init(); + +#ifdef INV_PLAYBACK_DBG + LOGV_IF(PROCESS_VERBOSE, "HAL:inv_turn_on_data_logging"); + logfile = fopen("/data/playback.bin", "w+"); + if (logfile) + inv_turn_on_data_logging(logfile); +#endif + + /* setup orientation matrix and scale */ + inv_set_device_properties(); + + /* initialize sensor data */ + memset(mPendingEvents, 0, sizeof(mPendingEvents)); + + mPendingEvents[RotationVector].version = sizeof(sensors_event_t); + mPendingEvents[RotationVector].sensor = ID_RV; + mPendingEvents[RotationVector].type = SENSOR_TYPE_ROTATION_VECTOR; + mPendingEvents[RotationVector].acceleration.status + = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[GameRotationVector].version = sizeof(sensors_event_t); + mPendingEvents[GameRotationVector].sensor = ID_GRV; + mPendingEvents[GameRotationVector].type = SENSOR_TYPE_GAME_ROTATION_VECTOR; + mPendingEvents[GameRotationVector].acceleration.status + = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[LinearAccel].version = sizeof(sensors_event_t); + mPendingEvents[LinearAccel].sensor = ID_LA; + mPendingEvents[LinearAccel].type = SENSOR_TYPE_LINEAR_ACCELERATION; + mPendingEvents[LinearAccel].acceleration.status + = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[Gravity].version = sizeof(sensors_event_t); + mPendingEvents[Gravity].sensor = ID_GR; + mPendingEvents[Gravity].type = SENSOR_TYPE_GRAVITY; + mPendingEvents[Gravity].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[Gyro].version = sizeof(sensors_event_t); + mPendingEvents[Gyro].sensor = ID_GY; + mPendingEvents[Gyro].type = SENSOR_TYPE_GYROSCOPE; + mPendingEvents[Gyro].gyro.status = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[RawGyro].version = sizeof(sensors_event_t); + mPendingEvents[RawGyro].sensor = ID_RG; + mPendingEvents[RawGyro].type = SENSOR_TYPE_GYROSCOPE_UNCALIBRATED; + mPendingEvents[RawGyro].gyro.status = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[Accelerometer].version = sizeof(sensors_event_t); + mPendingEvents[Accelerometer].sensor = ID_A; + mPendingEvents[Accelerometer].type = SENSOR_TYPE_ACCELEROMETER; + mPendingEvents[Accelerometer].acceleration.status + = SENSOR_STATUS_ACCURACY_HIGH; + + /* Invensense compass calibration */ + mPendingEvents[MagneticField].version = sizeof(sensors_event_t); + mPendingEvents[MagneticField].sensor = ID_M; + mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD; + mPendingEvents[MagneticField].magnetic.status = + SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[RawMagneticField].version = sizeof(sensors_event_t); + mPendingEvents[RawMagneticField].sensor = ID_RM; + mPendingEvents[RawMagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED; + mPendingEvents[RawMagneticField].magnetic.status = + SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[Pressure].version = sizeof(sensors_event_t); + mPendingEvents[Pressure].sensor = ID_PS; + mPendingEvents[Pressure].type = SENSOR_TYPE_PRESSURE; + mPendingEvents[Pressure].magnetic.status = + SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[Orientation].version = sizeof(sensors_event_t); + mPendingEvents[Orientation].sensor = ID_O; + mPendingEvents[Orientation].type = SENSOR_TYPE_ORIENTATION; + mPendingEvents[Orientation].orientation.status + = SENSOR_STATUS_ACCURACY_HIGH; + + mPendingEvents[GeomagneticRotationVector].version = sizeof(sensors_event_t); + mPendingEvents[GeomagneticRotationVector].sensor = ID_GMRV; + mPendingEvents[GeomagneticRotationVector].type + = SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR; + mPendingEvents[GeomagneticRotationVector].acceleration.status + = SENSOR_STATUS_ACCURACY_HIGH; + + mSmEvents.version = sizeof(sensors_event_t); + mSmEvents.sensor = ID_SM; + mSmEvents.type = SENSOR_TYPE_SIGNIFICANT_MOTION; + mSmEvents.acceleration.status = SENSOR_STATUS_UNRELIABLE; + + mSdEvents.version = sizeof(sensors_event_t); + mSdEvents.sensor = ID_P; + mSdEvents.type = SENSOR_TYPE_STEP_DETECTOR; + mSdEvents.acceleration.status = SENSOR_STATUS_UNRELIABLE; + + mScEvents.version = sizeof(sensors_event_t); + mScEvents.sensor = ID_SC; + mScEvents.type = SENSOR_TYPE_STEP_COUNTER; + mScEvents.acceleration.status = SENSOR_STATUS_UNRELIABLE; + + /* Event Handlers for HW and Virtual Sensors */ + mHandlers[RotationVector] = &MPLSensor::rvHandler; + mHandlers[GameRotationVector] = &MPLSensor::grvHandler; + mHandlers[LinearAccel] = &MPLSensor::laHandler; + mHandlers[Gravity] = &MPLSensor::gravHandler; + mHandlers[Gyro] = &MPLSensor::gyroHandler; + mHandlers[RawGyro] = &MPLSensor::rawGyroHandler; + mHandlers[Accelerometer] = &MPLSensor::accelHandler; + mHandlers[MagneticField] = &MPLSensor::compassHandler; + mHandlers[RawMagneticField] = &MPLSensor::rawCompassHandler; + mHandlers[Orientation] = &MPLSensor::orienHandler; + mHandlers[GeomagneticRotationVector] = &MPLSensor::gmHandler; + mHandlers[Pressure] = &MPLSensor::psHandler; + + /* initialize delays to reasonable values */ + for (int i = 0; i < NumSensors; i++) { + mDelays[i] = 1000000000LL; + mBatchDelays[i] = 1000000000LL; + mBatchTimeouts[i] = 100000000000LL; + } + + /* initialize Compass Bias */ + memset(mCompassBias, 0, sizeof(mCompassBias)); + + /* initialize Factory Accel Bias */ + memset(mFactoryAccelBias, 0, sizeof(mFactoryAccelBias)); + + /* initialize Gyro Bias */ + memset(mGyroBias, 0, sizeof(mGyroBias)); + memset(mGyroChipBias, 0, sizeof(mGyroChipBias)); + + /* load calibration file from /data/inv_cal_data.bin */ + rv = inv_load_calibration(); + if(rv == INV_SUCCESS) { + LOGV_IF(PROCESS_VERBOSE, "HAL:Calibration file successfully loaded"); + /* Get initial values */ + getCompassBias(); + getGyroBias(); + if (mGyroBiasAvailable) { + setGyroBias(); + } + getAccelBias(); + getFactoryGyroBias(); + if (mFactoryGyroBiasAvailable) { + setFactoryGyroBias(); + } + getFactoryAccelBias(); + if (mFactoryAccelBiasAvailable) { + setFactoryAccelBias(); + } + } + else + LOGE("HAL:Could not open or load MPL calibration file (%d)", rv); + + /* takes external accel calibration load workflow */ + if( m_pt2AccelCalLoadFunc != NULL) { + long accel_offset[3]; + long tmp_offset[3]; + int result = m_pt2AccelCalLoadFunc(accel_offset); + if(result) + LOGW("HAL:Vendor accelerometer calibration file load failed %d\n", + result); + else { + LOGW("HAL:Vendor accelerometer calibration file successfully " + "loaded"); + inv_get_mpl_accel_bias(tmp_offset, NULL); + LOGV_IF(PROCESS_VERBOSE, + "HAL:Original accel offset, %ld, %ld, %ld\n", + tmp_offset[0], tmp_offset[1], tmp_offset[2]); + inv_set_accel_bias_mask(accel_offset, mAccelAccuracy,4); + inv_get_mpl_accel_bias(tmp_offset, NULL); + LOGV_IF(PROCESS_VERBOSE, "HAL:Set accel offset, %ld, %ld, %ld\n", + tmp_offset[0], tmp_offset[1], tmp_offset[2]); + } + } + /* end of external accel calibration load workflow */ + + /* disable all sensors and features */ + masterEnable(0); + enableGyro(0); + enableLowPowerAccel(0); + enableAccel(0); + enableCompass(0,0); + enablePressure(0); + enableBatch(0); + + if (isLowPowerQuatEnabled()) { + enableLPQuaternion(0); + } + + if (isDmpDisplayOrientationOn()) { + // open DMP Orient Fd + openDmpOrientFd(); + enableDmpOrientation(!isDmpScreenAutoRotationEnabled()); + } +} + +void MPLSensor::enable_iio_sysfs(void) +{ + VFUNC_LOG; + + char iio_device_node[MAX_CHIP_ID_LEN]; + FILE *tempFp = NULL; + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo 1 > %s (%lld)", + mpu.in_timestamp_en, getTimestamp()); + // Either fopen()/open() are okay for sysfs access + // developers could choose what they want + // with fopen(), the benefit is that fprintf()/fscanf() are available + tempFp = fopen(mpu.in_timestamp_en, "w"); + if (tempFp == NULL) { + LOGE("HAL:could not open timestamp enable"); + } else { + if(fprintf(tempFp, "%d", 1) < 0 || fclose(tempFp) < 0) { + LOGE("HAL:could not enable timestamp"); + } + } + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + IIO_BUFFER_LENGTH, mpu.buffer_length, getTimestamp()); + tempFp = fopen(mpu.buffer_length, "w"); + if (tempFp == NULL) { + LOGE("HAL:could not open buffer length"); + } else { + if (fprintf(tempFp, "%d", IIO_BUFFER_LENGTH) < 0 || fclose(tempFp) < 0) { + LOGE("HAL:could not write buffer length"); + } + } + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.chip_enable, getTimestamp()); + tempFp = fopen(mpu.chip_enable, "w"); + if (tempFp == NULL) { + LOGE("HAL:could not open chip enable"); + } else { + if (fprintf(tempFp, "%d", 1) < 0 || fclose(tempFp) < 0) { + LOGE("HAL:could not write chip enable"); + } + } + + inv_get_iio_device_node(iio_device_node); + iio_fd = open(iio_device_node, O_RDONLY); + if (iio_fd < 0) { + LOGE("HAL:could not open iio device node"); + } else { + LOGV_IF(ENG_VERBOSE, "HAL:iio iio_fd opened : %d", iio_fd); + } +} + +int MPLSensor::inv_constructor_init(void) +{ + VFUNC_LOG; + + inv_error_t result = inv_init_mpl(); + if (result) { + LOGE("HAL:inv_init_mpl() failed"); + return result; + } + result = inv_constructor_default_enable(); + result = inv_start_mpl(); + if (result) { + LOGE("HAL:inv_start_mpl() failed"); + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +int MPLSensor::inv_constructor_default_enable(void) +{ + VFUNC_LOG; + + inv_error_t result; + +/******************************************************************************* + +******************************************************************************** + +The InvenSense binary file (libmplmpu.so) is subject to Google's standard terms +and conditions as accepted in the click-through agreement required to download +this library. +The library includes, but is not limited to the following function calls: +inv_enable_quaternion(). + +ANY VIOLATION OF SUCH TERMS AND CONDITIONS WILL BE STRICTLY ENFORCED. + +******************************************************************************** + +*******************************************************************************/ + + result = inv_enable_quaternion(); + if (result) { + LOGE("HAL:Cannot enable quaternion\n"); + return result; + } + + result = inv_enable_in_use_auto_calibration(); + if (result) { + return result; + } + + result = inv_enable_fast_nomot(); + if (result) { + return result; + } + + result = inv_enable_gyro_tc(); + if (result) { + return result; + } + + result = inv_enable_hal_outputs(); + if (result) { + return result; + } + + if (!mCompassSensor->providesCalibration()) { + /* Invensense compass calibration */ + LOGV_IF(ENG_VERBOSE, "HAL:Invensense vector compass cal enabled"); + result = inv_enable_vector_compass_cal(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } else { + mMplFeatureActiveMask |= INV_COMPASS_CAL; + } + // specify MPL's trust weight, used by compass algorithms + inv_vector_compass_cal_sensitivity(3); + + /* disabled by default + result = inv_enable_compass_bias_w_gyro(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + */ + + result = inv_enable_heading_from_gyro(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_enable_magnetic_disturbance(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + //inv_enable_magnetic_disturbance_logging(); + } + + result = inv_enable_9x_sensor_fusion(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } else { + // 9x sensor fusion enables Compass fit + mMplFeatureActiveMask |= INV_COMPASS_FIT; + } + + result = inv_enable_no_gyro_fusion(); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/* TODO: create function pointers to calculate scale */ +void MPLSensor::inv_set_device_properties(void) +{ + VFUNC_LOG; + + unsigned short orient; + + inv_get_sensors_orientation(); + + inv_set_gyro_sample_rate(DEFAULT_MPL_GYRO_RATE); + inv_set_compass_sample_rate(DEFAULT_MPL_COMPASS_RATE); + + /* gyro setup */ + orient = inv_orientation_matrix_to_scalar(mGyroOrientation); + inv_set_gyro_orientation_and_scale(orient, mGyroScale << 15); + LOGI_IF(EXTRA_VERBOSE, "HAL: Set MPL Gyro Scale %ld", mGyroScale << 15); + + /* accel setup */ + orient = inv_orientation_matrix_to_scalar(mAccelOrientation); + /* use for third party accel input subsystem driver + inv_set_accel_orientation_and_scale(orient, 1LL << 22); + */ + inv_set_accel_orientation_and_scale(orient, (long)mAccelScale << 15); + LOGI_IF(EXTRA_VERBOSE, + "HAL: Set MPL Accel Scale %ld", (long)mAccelScale << 15); + + /* compass setup */ + signed char orientMtx[9]; + mCompassSensor->getOrientationMatrix(orientMtx); + orient = + inv_orientation_matrix_to_scalar(orientMtx); + long sensitivity; + sensitivity = mCompassSensor->getSensitivity(); + inv_set_compass_orientation_and_scale(orient, sensitivity); + mCompassScale = sensitivity; + LOGI_IF(EXTRA_VERBOSE, + "HAL: Set MPL Compass Scale %ld", mCompassScale); +} + +void MPLSensor::loadDMP(void) +{ + VFUNC_LOG; + + int res, fd; + FILE *fptr; + + if (isMpuNonDmp()) { + return; + } + + /* load DMP firmware */ + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.firmware_loaded, getTimestamp()); + fd = open(mpu.firmware_loaded, O_RDONLY); + if(fd < 0) { + LOGE("HAL:could not open dmp state"); + } else { + if(inv_read_dmp_state(fd) == 0) { + LOGV_IF(EXTRA_VERBOSE, "HAL:load dmp: %s", mpu.dmp_firmware); + fptr = fopen(mpu.dmp_firmware, "w"); + if(fptr == NULL) { + LOGE("HAL:could not open dmp_firmware"); + } else { + if (inv_load_dmp(fptr) < 0 || fclose(fptr) < 0) { + LOGE("HAL:load DMP failed"); + } else { + LOGV_IF(PROCESS_VERBOSE, "HAL:DMP loaded"); + } + } + } else { + LOGV_IF(ENG_VERBOSE, "HAL:DMP is already loaded"); + } + } + + // onDmp(1); //Can't enable here. See note onDmp() +} + +void MPLSensor::inv_get_sensors_orientation(void) +{ + VFUNC_LOG; + + FILE *fptr; + + // get gyro orientation + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.gyro_orient, getTimestamp()); + fptr = fopen(mpu.gyro_orient, "r"); + if (fptr != NULL) { + int om[9]; + if (fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d", + &om[0], &om[1], &om[2], &om[3], &om[4], &om[5], + &om[6], &om[7], &om[8]) < 0 || fclose(fptr) < 0) { + LOGE("HAL:Could not read gyro mounting matrix"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:gyro mounting matrix: " + "%+d %+d %+d %+d %+d %+d %+d %+d %+d", + om[0], om[1], om[2], om[3], om[4], om[5], om[6], om[7], om[8]); + + mGyroOrientation[0] = om[0]; + mGyroOrientation[1] = om[1]; + mGyroOrientation[2] = om[2]; + mGyroOrientation[3] = om[3]; + mGyroOrientation[4] = om[4]; + mGyroOrientation[5] = om[5]; + mGyroOrientation[6] = om[6]; + mGyroOrientation[7] = om[7]; + mGyroOrientation[8] = om[8]; + } + } + + // get accel orientation + LOGV_IF(SYSFS_VERBOSE, + "HAL:sysfs:cat %s (%lld)", mpu.accel_orient, getTimestamp()); + fptr = fopen(mpu.accel_orient, "r"); + if (fptr != NULL) { + int om[9]; + if (fscanf(fptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d", + &om[0], &om[1], &om[2], &om[3], &om[4], &om[5], + &om[6], &om[7], &om[8]) < 0 || fclose(fptr) < 0) { + LOGE("HAL:could not read accel mounting matrix"); + } else { + LOGV_IF(EXTRA_VERBOSE, + "HAL:accel mounting matrix: " + "%+d %+d %+d %+d %+d %+d %+d %+d %+d", + om[0], om[1], om[2], om[3], om[4], om[5], om[6], om[7], om[8]); + + mAccelOrientation[0] = om[0]; + mAccelOrientation[1] = om[1]; + mAccelOrientation[2] = om[2]; + mAccelOrientation[3] = om[3]; + mAccelOrientation[4] = om[4]; + mAccelOrientation[5] = om[5]; + mAccelOrientation[6] = om[6]; + mAccelOrientation[7] = om[7]; + mAccelOrientation[8] = om[8]; + } + } +} + +MPLSensor::~MPLSensor() +{ + VFUNC_LOG; + + /* Close open fds */ + if (iio_fd > 0) + close(iio_fd); + if( accel_fd > 0 ) + close(accel_fd ); + if (gyro_temperature_fd > 0) + close(gyro_temperature_fd); + if (sysfs_names_ptr) + free(sysfs_names_ptr); + + closeDmpOrientFd(); + + if (accel_x_dmp_bias_fd > 0) { + close(accel_x_dmp_bias_fd); + } + if (accel_y_dmp_bias_fd > 0) { + close(accel_y_dmp_bias_fd); + } + if (accel_z_dmp_bias_fd > 0) { + close(accel_z_dmp_bias_fd); + } + + if (gyro_x_dmp_bias_fd > 0) { + close(gyro_x_dmp_bias_fd); + } + if (gyro_y_dmp_bias_fd > 0) { + close(gyro_y_dmp_bias_fd); + } + if (gyro_z_dmp_bias_fd > 0) { + close(gyro_z_dmp_bias_fd); + } + + if (gyro_x_offset_fd > 0) { + close(gyro_x_dmp_bias_fd); + } + if (gyro_y_offset_fd > 0) { + close(gyro_y_offset_fd); + } + if (gyro_z_offset_fd > 0) { + close(accel_z_offset_fd); + } + + /* Turn off Gyro master enable */ + /* A workaround until driver handles it */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.master_enable, getTimestamp()); + write_sysfs_int(mpu.master_enable, 0); + +#ifdef INV_PLAYBACK_DBG + inv_turn_off_data_logging(); + if (fclose(logfile) < 0) { + LOGE("cannot close debug log file"); + } +#endif +} + +#define GY_ENABLED ((1 << ID_GY) & enabled_sensors) +#define RGY_ENABLED ((1 << ID_RG) & enabled_sensors) +#define A_ENABLED ((1 << ID_A) & enabled_sensors) +#define M_ENABLED ((1 << ID_M) & enabled_sensors) +#define RM_ENABLED ((1 << ID_RM) & enabled_sensors) +#define PS_ENABLED ((1 << ID_PS) & enabled_sensors) +#define O_ENABLED ((1 << ID_O) & enabled_sensors) +#define LA_ENABLED ((1 << ID_LA) & enabled_sensors) +#define GR_ENABLED ((1 << ID_GR) & enabled_sensors) +#define RV_ENABLED ((1 << ID_RV) & enabled_sensors) +#define GRV_ENABLED ((1 << ID_GRV) & enabled_sensors) +#define GMRV_ENABLED ((1 << ID_GMRV) & enabled_sensors) + +/* this applies to BMA250 Input Subsystem Driver only */ +int MPLSensor::setAccelInitialState() +{ + VFUNC_LOG; + + struct input_absinfo absinfo_x; + struct input_absinfo absinfo_y; + struct input_absinfo absinfo_z; + float value; + if (!ioctl(accel_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo_x) && + !ioctl(accel_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo_y) && + !ioctl(accel_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo_z)) { + value = absinfo_x.value; + mPendingEvents[Accelerometer].data[0] = value * CONVERT_A_X; + value = absinfo_y.value; + mPendingEvents[Accelerometer].data[1] = value * CONVERT_A_Y; + value = absinfo_z.value; + mPendingEvents[Accelerometer].data[2] = value * CONVERT_A_Z; + //mHasPendingEvent = true; + } + return 0; +} + +int MPLSensor::onDmp(int en) +{ + VFUNC_LOG; + + int res = -1; + int status; + mDmpOn = en; + + //Sequence to enable DMP + //1. Load DMP image if not already loaded + //2. Either Gyro or Accel must be enabled/configured before next step + //3. Enable DMP + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)", + mpu.firmware_loaded, getTimestamp()); + if(read_sysfs_int(mpu.firmware_loaded, &status) < 0){ + LOGE("HAL:ERR can't get firmware_loaded status"); + } else if (status == 1) { + //Write only if curr DMP state <> request + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)", + mpu.dmp_on, getTimestamp()); + if (read_sysfs_int(mpu.dmp_on, &status) < 0) { + LOGE("HAL:ERR can't read DMP state"); + } else if (status != en) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.dmp_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_on, en) < 0) { + LOGE("HAL:ERR can't write dmp_on"); + } else { + mDmpOn = en; + res = 0; //Indicate write successful + if(!en) { + setAccelBias(); + } + } + //Enable DMP interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.dmp_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_int_on, en) < 0) { + LOGE("HAL:ERR can't en/dis DMP interrupt"); + } + + // disable DMP event interrupt if needed + if (!en) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, en) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + } + } else { + mDmpOn = en; + res = 0; //DMP already set as requested + if(!en) { + setAccelBias(); + } + } + } else { + LOGE("HAL:ERR No DMP image"); + } + return res; +} + +int MPLSensor::setDmpFeature(int en) +{ + int res = 0; + + // set sensor engine and fifo + if ((mFeatureActiveMask & DMP_FEATURE_MASK) || en) { + if ((mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION) || + (mFeatureActiveMask & INV_DMP_PED_QUATERNION) || + (mFeatureActiveMask & INV_DMP_QUATERNION)) { + res = enableGyro(1); + if (res < 0) { + return res; + } + if (!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_GYRO)) { + res = turnOffGyroFifo(); + if (res < 0) { + return res; + } + } + } + res = enableAccel(1); + if (res < 0) { + return res; + } + if (!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_ACCEL)) { + res = turnOffAccelFifo(); + if (res < 0) { + return res; + } + } + } else { + if (!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_GYRO)) { + res = enableGyro(0); + if (res < 0) { + return res; + } + } + if (!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_ACCEL)) { + res = enableAccel(0); + if (res < 0) { + return res; + } + } + } + + // set sensor data interrupt + uint32_t dataInterrupt = (mEnabled || (mFeatureActiveMask & INV_DMP_BATCH_MODE)); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + !dataInterrupt, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, !dataInterrupt) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + return res; +} + +int MPLSensor::computeAndSetDmpState() +{ + int res = 0; + bool dmpState = 0; + + if (mFeatureActiveMask) { + dmpState = 1; + LOGV_IF(PROCESS_VERBOSE, "HAL:computeAndSetDmpState() mFeatureActiveMask = 1"); + } else if ((mEnabled & VIRTUAL_SENSOR_9AXES_MASK) + || (mEnabled & VIRTUAL_SENSOR_GYRO_6AXES_MASK)) { + if (checkLPQuaternion() && checkLPQRateSupported()) { + dmpState = 1; + LOGV_IF(PROCESS_VERBOSE, "HAL:computeAndSetDmpState() Sensor Fusion = 1"); + } + } /*else { + unsigned long sensor = mLocalSensorMask & mMasterSensorMask; + if (sensor & (INV_THREE_AXIS_ACCEL & INV_THREE_AXIS_GYRO)) { + dmpState = 1; + LOGV_IF(PROCESS_VERBOSE, "HAL:computeAndSetDmpState() accel and gyro = 1"); + } + }*/ + + // set Dmp state + res = onDmp(dmpState); + if (res < 0) + return res; + + if (dmpState) { + // set DMP rate to 200Hz + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 200, mpu.accel_fifo_rate, getTimestamp()); + if (write_sysfs_int(mpu.accel_fifo_rate, 200) < 0) { + res = -1; + LOGE("HAL:ERR can't set rate to 200Hz"); + return res; + } + } + LOGV_IF(PROCESS_VERBOSE, "HAL:DMP is set %s", (dmpState ? "on" : "off")); + return dmpState; +} + +/* called when batch and hw sensor enabled*/ +int MPLSensor::enablePedIndicator(int en) +{ + VFUNC_LOG; + + int res = 0; + if (en) { + if (!(mFeatureActiveMask & INV_DMP_PED_QUATERNION)) { + //Disable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, 0) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer Interrupt"); + res = -1; // indicate an err + return res; + } + } + } + + LOGV_IF(ENG_VERBOSE, "HAL:Toggling step indicator to %d", en); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.step_indicator_on, getTimestamp()); + if (write_sysfs_int(mpu.step_indicator_on, en) < 0) { + res = -1; + LOGE("HAL:ERR can't write to DMP step_indicator_on"); + } + return res; +} + +int MPLSensor::checkPedStandaloneEnabled(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_PED_STANDALONE)? 1:0); +} + +/* This feature is only used in batch mode */ +/* Stand-alone Step Detector */ +int MPLSensor::enablePedStandalone(int en) +{ + VFUNC_LOG; + + if (!en) { + enablePedStandaloneData(0); + mFeatureActiveMask &= ~INV_DMP_PED_STANDALONE; + if (mFeatureActiveMask == 0) { + onDmp(0); + } else if(mFeatureActiveMask & INV_DMP_PEDOMETER) { + //Re-enable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, 1) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer Interrupt"); + return (-1); + } + //Disable data interrupt if no continuous data + if (mEnabled == 0) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, 1) < 0) { + LOGE("HAL:ERR can't enable DMP event interrupt"); + return (-1); + } + } + } + LOGV_IF(ENG_VERBOSE, "HAL:Ped Standalone disabled"); + } else { + if (enablePedStandaloneData(1) < 0 || onDmp(1) < 0) { + LOGE("HAL:ERR can't enable Ped Standalone"); + } else { + mFeatureActiveMask |= INV_DMP_PED_STANDALONE; + //Disable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, 0) < 0) { + LOGE("HAL:ERR can't disable Android Pedometer Interrupt"); + return (-1); + } + //Enable Data Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, 0) < 0) { + LOGE("HAL:ERR can't enable DMP event interrupt"); + return (-1); + } + LOGV_IF(ENG_VERBOSE, "HAL:Ped Standalone enabled"); + } + } + return 0; +} + +int MPLSensor:: enablePedStandaloneData(int en) +{ + VFUNC_LOG; + + int res = 0; + + // Set DMP Ped standalone + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.step_detector_on, getTimestamp()); + if (write_sysfs_int(mpu.step_detector_on, en) < 0) { + LOGE("HAL:ERR can't write DMP step_detector_on"); + res = -1; //Indicate an err + } + + // Set DMP Step indicator + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.step_indicator_on, getTimestamp()); + if (write_sysfs_int(mpu.step_indicator_on, en) < 0) { + LOGE("HAL:ERR can't write DMP step_indicator_on"); + res = -1; //Indicate an err + } + + if (!en) { + LOGV_IF(ENG_VERBOSE, "HAL:Disabling ped standalone"); + //Disable Accel if no sensor needs it + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_ACCEL))) { + res = enableAccel(0); + if (res < 0) + return res; + } + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_GYRO))) { + res = enableGyro(0); + if (res < 0) + return res; + } + } else { + LOGV_IF(ENG_VERBOSE, "HAL:Enabling ped standalone"); + // enable accel engine + res = enableAccel(1); + if (res < 0) + return res; + LOGV_IF(EXTRA_VERBOSE, "mLocalSensorMask=0x%lx", mLocalSensorMask); + // disable accel FIFO + if (!((mLocalSensorMask & mMasterSensorMask) & INV_THREE_AXIS_ACCEL)) { + res = turnOffAccelFifo(); + if (res < 0) + return res; + } + } + + return res; +} + +int MPLSensor::checkPedQuatEnabled(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_PED_QUATERNION)? 1:0); +} + +/* This feature is only used in batch mode */ +/* Step Detector && Game Rotation Vector */ +int MPLSensor::enablePedQuaternion(int en) +{ + VFUNC_LOG; + + if (!en) { + enablePedQuaternionData(0); + mFeatureActiveMask &= ~INV_DMP_PED_QUATERNION; + if (mFeatureActiveMask == 0) { + onDmp(0); + } else if(mFeatureActiveMask & INV_DMP_PEDOMETER) { + //Re-enable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, 1) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer Interrupt"); + return (-1); + } + //Disable data interrupt if no continuous data + if (mEnabled == 0) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, en) < 0) { + LOGE("HAL:ERR can't enable DMP event interrupt"); + return (-1); + } + } + } + LOGV_IF(ENG_VERBOSE, "HAL:Ped Quat disabled"); + } else { + if (enablePedQuaternionData(1) < 0 || onDmp(1) < 0) { + LOGE("HAL:ERR can't enable Ped Quaternion"); + } else { + mFeatureActiveMask |= INV_DMP_PED_QUATERNION; + //Disable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, 0) < 0) { + LOGE("HAL:ERR can't disable Android Pedometer Interrupt"); + return (-1); + } + //Enable Data Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, 0) < 0) { + LOGE("HAL:ERR can't enable DMP event interrupt"); + return (-1); + } + LOGV_IF(ENG_VERBOSE, "HAL:Ped Quat enabled"); + } + } + return 0; +} + +int MPLSensor::enablePedQuaternionData(int en) +{ + VFUNC_LOG; + + int res = 0; + + // Enable DMP quaternion + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.ped_q_on, getTimestamp()); + if (write_sysfs_int(mpu.ped_q_on, en) < 0) { + LOGE("HAL:ERR can't write DMP ped_q_on"); + res = -1; //Indicate an err + } + + if (!en) { + LOGV_IF(ENG_VERBOSE, "HAL:Disabling ped quat"); + //Disable Accel if no sensor needs it + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_ACCEL))) { + res = enableAccel(0); + if (res < 0) + return res; + } + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_GYRO))) { + res = enableGyro(0); + if (res < 0) + return res; + } + if (mFeatureActiveMask & INV_DMP_QUATERNION) { + res = write_sysfs_int(mpu.gyro_fifo_enable, 1); + res += write_sysfs_int(mpu.accel_fifo_enable, 1); + if (res < 0) + return res; + } + // LOGV_IF(ENG_VERBOSE, "before mLocalSensorMask=0x%lx", mLocalSensorMask); + // reset global mask for buildMpuEvent() + if (mEnabled & (1 << GameRotationVector)) { + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else if (mEnabled & (1 << Accelerometer)) { + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else if ((mEnabled & ( 1 << Gyro)) || + (mEnabled & (1 << RawGyro))) { + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + } + //LOGV_IF(ENG_VERBOSE, "after mLocalSensorMask=0x%lx", mLocalSensorMask); + } else { + LOGV_IF(PROCESS_VERBOSE, "HAL:Enabling ped quat"); + // enable accel engine + res = enableAccel(1); + if (res < 0) + return res; + + // enable gyro engine + res = enableGyro(1); + if (res < 0) + return res; + LOGV_IF(EXTRA_VERBOSE, "mLocalSensorMask=0x%lx", mLocalSensorMask); + // disable accel FIFO + if ((!((mLocalSensorMask & mMasterSensorMask) & INV_THREE_AXIS_ACCEL)) || + !(mBatchEnabled & (1 << Accelerometer))) { + res = turnOffAccelFifo(); + if (res < 0) + return res; + mLocalSensorMask &= ~INV_THREE_AXIS_ACCEL; + } + + // disable gyro FIFO + if ((!((mLocalSensorMask & mMasterSensorMask) & INV_THREE_AXIS_GYRO)) || + !((mBatchEnabled & (1 << Gyro)) || (mBatchEnabled & (1 << RawGyro)))) { + res = turnOffGyroFifo(); + if (res < 0) + return res; + mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; + } + } + + return res; +} + +int MPLSensor::check6AxisQuatEnabled(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION)? 1:0); +} + +/* This is used for batch mode only */ +/* GRV is batched but not along with ped */ +int MPLSensor::enable6AxisQuaternion(int en) +{ + VFUNC_LOG; + + if (!en) { + enable6AxisQuaternionData(0); + mFeatureActiveMask &= ~INV_DMP_6AXIS_QUATERNION; + if (mFeatureActiveMask == 0) { + onDmp(0); + } + LOGV_IF(ENG_VERBOSE, "HAL:6 Axis Quat disabled"); + } else { + if (enable6AxisQuaternionData(1) < 0 || onDmp(1) < 0) { + LOGE("HAL:ERR can't enable 6 Axis Quaternion"); + } else { + mFeatureActiveMask |= INV_DMP_6AXIS_QUATERNION; + LOGV_IF(PROCESS_VERBOSE, "HAL:6 Axis Quat enabled"); + } + } + return 0; +} + +int MPLSensor::enable6AxisQuaternionData(int en) +{ + VFUNC_LOG; + + int res = 0; + + // Enable DMP quaternion + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.six_axis_q_on, getTimestamp()); + if (write_sysfs_int(mpu.six_axis_q_on, en) < 0) { + LOGE("HAL:ERR can't write DMP six_axis_q_on"); + res = -1; //Indicate an err + } + + if (!en) { + LOGV_IF(EXTRA_VERBOSE, "HAL:DMP six axis quaternion data was turned off"); + inv_quaternion_sensor_was_turned_off(); + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_ACCEL))) { + res = enableAccel(0); + if (res < 0) + return res; + } + if (!(mFeatureActiveMask & DMP_FEATURE_MASK) + && (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_GYRO))) { + res = enableGyro(0); + if (res < 0) + return res; + } + if (mFeatureActiveMask & INV_DMP_QUATERNION) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.gyro_fifo_enable, getTimestamp()); + res = write_sysfs_int(mpu.gyro_fifo_enable, 1); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.accel_fifo_enable, getTimestamp()); + res += write_sysfs_int(mpu.accel_fifo_enable, 1); + if (res < 0) + return res; + } + LOGV_IF(ENG_VERBOSE, " k=0x%lx", mLocalSensorMask); + // reset global mask for buildMpuEvent() + if (mEnabled & (1 << GameRotationVector)) { + if (!(mFeatureActiveMask & INV_DMP_PED_QUATERNION)) { + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + res = write_sysfs_int(mpu.gyro_fifo_enable, 1); + res += write_sysfs_int(mpu.accel_fifo_enable, 1); + if (res < 0) + return res; + } + } else if (mEnabled & (1 << Accelerometer)) { + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else if ((mEnabled & ( 1 << Gyro)) || + (mEnabled & (1 << RawGyro))) { + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + } + LOGV_IF(ENG_VERBOSE, "after mLocalSensorMask=0x%lx", mLocalSensorMask); + } else { + LOGV_IF(PROCESS_VERBOSE, "HAL:Enabling six axis quat"); + if (mEnabled & ( 1 << GameRotationVector)) { + // enable accel engine + res = enableAccel(1); + if (res < 0) + return res; + + // enable gyro engine + res = enableGyro(1); + if (res < 0) + return res; + LOGV_IF(EXTRA_VERBOSE, "before: mLocalSensorMask=0x%lx", mLocalSensorMask); + if ((!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_ACCEL)) || + (!(mBatchEnabled & (1 << Accelerometer)) || + (!(mEnabled & (1 << Accelerometer))))) { + res = turnOffAccelFifo(); + if (res < 0) + return res; + mLocalSensorMask &= ~INV_THREE_AXIS_ACCEL; + } + + if ((!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_GYRO)) || + (!(mBatchEnabled & (1 << Gyro)) || + (!(mEnabled & (1 << Gyro))))) { + if (!(mBatchEnabled & (1 << RawGyro)) || + (!(mEnabled & (1 << RawGyro)))) { + res = turnOffGyroFifo(); + if (res < 0) + return res; + mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; + } + } + LOGV_IF(ENG_VERBOSE, "after: mLocalSensorMask=0x%lx", mLocalSensorMask); + } + } + + return res; +} + +/* this is for batch mode only */ +int MPLSensor::checkLPQRateSupported(void) +{ + VFUNC_LOG; +#ifndef USE_LPQ_AT_FASTEST + return ((mDelays[GameRotationVector] <= RATE_200HZ) ? 0 :1); +#else + return 1; +#endif +} + +int MPLSensor::checkLPQuaternion(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_QUATERNION)? 1:0); +} + +int MPLSensor::enableLPQuaternion(int en) +{ + VFUNC_LOG; + + if (!en) { + enableQuaternionData(0); + mFeatureActiveMask &= ~INV_DMP_QUATERNION; + if (mFeatureActiveMask == 0) { + onDmp(0); + } + LOGV_IF(ENG_VERBOSE, "HAL:LP Quat disabled"); + } else { + if (enableQuaternionData(1) < 0 || onDmp(1) < 0) { + LOGE("HAL:ERR can't enable LP Quaternion"); + } else { + mFeatureActiveMask |= INV_DMP_QUATERNION; + LOGV_IF(ENG_VERBOSE, "HAL:LP Quat enabled"); + } + } + return 0; +} + +int MPLSensor::enableQuaternionData(int en) +{ + VFUNC_LOG; + + int res = 0; + + // Enable DMP quaternion + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.three_axis_q_on, getTimestamp()); + if (write_sysfs_int(mpu.three_axis_q_on, en) < 0) { + LOGE("HAL:ERR can't write DMP three_axis_q__on"); + res = -1; //Indicates an err + } + + if (!en) { + LOGV_IF(ENG_VERBOSE, "HAL:DMP quaternion data was turned off"); + inv_quaternion_sensor_was_turned_off(); + } else { + LOGV_IF(ENG_VERBOSE, "HAL:Enabling three axis quat"); + } + + return res; +} + +int MPLSensor::enableDmpPedometer(int en, int interruptMode) +{ + VFUNC_LOG; + int res = 0; + int enabled_sensors = mEnabled; + + if (isMpuNonDmp()) + return res; + + // reset master enable + res = masterEnable(0); + if (res < 0) { + return res; + } + + if (en == 1) { + //Enable DMP Pedometer Function + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.pedometer_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_on, en) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer"); + res = -1; // indicate an err + return res; + } + + if (interruptMode || (mFeatureActiveMask & INV_DMP_PEDOMETER)) { + //Enable DMP Pedometer Interrupt + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, en) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer Interrupt"); + res = -1; // indicate an err + return res; + } + } + + if (interruptMode) { + mFeatureActiveMask |= INV_DMP_PEDOMETER; + } + else { + mFeatureActiveMask |= INV_DMP_PEDOMETER_STEP; + mStepCountPollTime = 100000000LL; + } + + clock_gettime(CLOCK_MONOTONIC, &mt_pre); + } else { + if (interruptMode) { + mFeatureActiveMask &= ~INV_DMP_PEDOMETER; + } + else { + mFeatureActiveMask &= ~INV_DMP_PEDOMETER_STEP; + mStepCountPollTime = -1; + } + + /* if neither step detector or step count is on */ + if (!(mFeatureActiveMask & (INV_DMP_PEDOMETER | INV_DMP_PEDOMETER_STEP))) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.pedometer_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_on, en) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer"); + res = -1; + return res; + } + } + + /* if feature is not step detector */ + if (!(mFeatureActiveMask & INV_DMP_PEDOMETER)) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.pedometer_int_on, getTimestamp()); + if (write_sysfs_int(mpu.pedometer_int_on, en) < 0) { + LOGE("HAL:ERR can't enable Android Pedometer Interrupt"); + res = -1; + return res; + } + } + } + + if ((res = setDmpFeature(en)) < 0) + return res; + + if ((res = computeAndSetDmpState()) < 0) + return res; + + if (resetDataRates() < 0) + return res; + + if(en || enabled_sensors || mFeatureActiveMask) { + res = masterEnable(1); + } + return res; +} + +int MPLSensor::masterEnable(int en) +{ + VFUNC_LOG; + + int res = 0; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.master_enable, getTimestamp()); + res = write_sysfs_int(mpu.master_enable, en); + return res; +} + +int MPLSensor::enableGyro(int en) +{ + VFUNC_LOG; + + int res = 0; + + /* need to also turn on/off the master enable */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.gyro_enable, getTimestamp()); + res = write_sysfs_int(mpu.gyro_enable, en); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.gyro_fifo_enable, getTimestamp()); + res += write_sysfs_int(mpu.gyro_fifo_enable, en); + + if (!en) { + LOGV_IF(EXTRA_VERBOSE, "HAL:MPL:inv_gyro_was_turned_off"); + inv_gyro_was_turned_off(); + } + + return res; +} + +int MPLSensor::enableLowPowerAccel(int en) +{ + VFUNC_LOG; + + int res; + + /* need to also turn on/off the master enable */ + res = write_sysfs_int(mpu.motion_lpa_on, en); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.motion_lpa_on, getTimestamp()); + return res; +} + +int MPLSensor::enableAccel(int en) +{ + VFUNC_LOG; + + int res; + + /* need to also turn on/off the master enable */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.accel_enable, getTimestamp()); + res = write_sysfs_int(mpu.accel_enable, en); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.accel_fifo_enable, getTimestamp()); + res += write_sysfs_int(mpu.accel_fifo_enable, en); + + if (!en) { + LOGV_IF(EXTRA_VERBOSE, "HAL:MPL:inv_accel_was_turned_off"); + inv_accel_was_turned_off(); + } + + return res; +} + +int MPLSensor::enableCompass(int en, int rawSensorRequested) +{ + VFUNC_LOG; + + int res = 0; + /* TODO: handle ID_RM if third party compass cal is used */ + if (rawSensorRequested && mCompassSensor->providesCalibration()) { + res = mCompassSensor->enable(ID_RM, en); + } else { + res = mCompassSensor->enable(ID_M, en); + } + if (en == 0 || res != 0) { + LOGV_IF(EXTRA_VERBOSE, "HAL:MPL:inv_compass_was_turned_off %d", res); + inv_compass_was_turned_off(); + } + + return res; +} + +int MPLSensor::enablePressure(int en) +{ + VFUNC_LOG; + + int res = 0; + + if (mPressureSensor) + res = mPressureSensor->enable(ID_PS, en); + + return res; +} + +/* use this function for initialization */ +int MPLSensor::enableBatch(int64_t timeout) +{ + VFUNC_LOG; + + int res = 0; + + res = write_sysfs_int(mpu.batchmode_timeout, timeout); + if (timeout == 0) { + res = write_sysfs_int(mpu.six_axis_q_on, 0); + res = write_sysfs_int(mpu.ped_q_on, 0); + res = write_sysfs_int(mpu.step_detector_on, 0); + res = write_sysfs_int(mpu.step_indicator_on, 0); + } + + if (timeout == 0) { + LOGV_IF(EXTRA_VERBOSE, "HAL:MPL:batchmode timeout is zero"); + } + + return res; +} + +void MPLSensor::computeLocalSensorMask(int enabled_sensors) +{ + VFUNC_LOG; + + do { + /* Invensense Pressure on secondary bus */ + if (PS_ENABLED) { + LOGV_IF(ENG_VERBOSE, "PS ENABLED"); + mLocalSensorMask |= INV_ONE_AXIS_PRESSURE; + } else { + LOGV_IF(ENG_VERBOSE, "PS DISABLED"); + mLocalSensorMask &= ~INV_ONE_AXIS_PRESSURE; + } + + if (LA_ENABLED || GR_ENABLED || RV_ENABLED || O_ENABLED + || (GRV_ENABLED && GMRV_ENABLED)) { + LOGV_IF(ENG_VERBOSE, "FUSION ENABLED"); + mLocalSensorMask |= ALL_MPL_SENSORS_NP; + break; + } + + if (GRV_ENABLED) { + if (!(mFeatureActiveMask & INV_DMP_BATCH_MODE) || + !(mBatchEnabled & (1 << GameRotationVector))) { + LOGV_IF(ENG_VERBOSE, "6 Axis Fusion ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else { + if (GY_ENABLED || RGY_ENABLED) { + LOGV_IF(ENG_VERBOSE, "G ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + } else { + LOGV_IF(ENG_VERBOSE, "G DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; + } + if (A_ENABLED) { + LOGV_IF(ENG_VERBOSE, "A ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else { + LOGV_IF(ENG_VERBOSE, "A DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_ACCEL; + } + } + /* takes care of MAG case */ + if (M_ENABLED || RM_ENABLED) { + LOGV_IF(1, "M ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_COMPASS; + } else { + LOGV_IF(1, "M DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_COMPASS; + } + break; + } + + if (GMRV_ENABLED) { + LOGV_IF(ENG_VERBOSE, "6 Axis Geomagnetic Fusion ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + mLocalSensorMask |= INV_THREE_AXIS_COMPASS; + + /* takes care of Gyro case */ + if (GY_ENABLED || RGY_ENABLED) { + LOGV_IF(1, "G ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + } else { + LOGV_IF(1, "G DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; + } + break; + } + + if(!A_ENABLED && !M_ENABLED && !RM_ENABLED && + !GRV_ENABLED && !GMRV_ENABLED && !GY_ENABLED && !RGY_ENABLED && + !PS_ENABLED) { + /* Invensense compass cal */ + LOGV_IF(ENG_VERBOSE, "ALL DISABLED"); + mLocalSensorMask = 0; + break; + } + + if (GY_ENABLED || RGY_ENABLED) { + LOGV_IF(ENG_VERBOSE, "G ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_GYRO; + } else { + LOGV_IF(ENG_VERBOSE, "G DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; + } + + if (A_ENABLED) { + LOGV_IF(ENG_VERBOSE, "A ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_ACCEL; + } else { + LOGV_IF(ENG_VERBOSE, "A DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_ACCEL; + } + + /* Invensense compass calibration */ + if (M_ENABLED || RM_ENABLED) { + LOGV_IF(ENG_VERBOSE, "M ENABLED"); + mLocalSensorMask |= INV_THREE_AXIS_COMPASS; + } else { + LOGV_IF(ENG_VERBOSE, "M DISABLED"); + mLocalSensorMask &= ~INV_THREE_AXIS_COMPASS; + } + } while (0); +} + +int MPLSensor::enableSensors(unsigned long sensors, int en, uint32_t changed) +{ + VFUNC_LOG; + + inv_error_t res = -1; + int on = 1; + int off = 0; + int cal_stored = 0; + + // Sequence to enable or disable a sensor + // 1. reset master enable (=0) + // 2. enable or disable a sensor + // 3. set master enable (=1) + + if (isLowPowerQuatEnabled() || + changed & ((1 << Gyro) | (1 << RawGyro) | (1 << Accelerometer) | + (mCompassSensor->isIntegrated() << MagneticField) | + (mCompassSensor->isIntegrated() << RawMagneticField) | + (mPressureSensor->isIntegrated() << Pressure))) { + + /* reset master enable */ + res = masterEnable(0); + if(res < 0) { + return res; + } + } + + LOGV_IF(ENG_VERBOSE, "HAL:enableSensors - sensors: 0x%0x", + (unsigned int)sensors); + + if (changed & ((1 << Gyro) | (1 << RawGyro))) { + LOGV_IF(ENG_VERBOSE, "HAL:enableSensors - gyro %s", + (sensors & INV_THREE_AXIS_GYRO? "enable": "disable")); + res = enableGyro(!!(sensors & INV_THREE_AXIS_GYRO)); + if(res < 0) { + return res; + } + + if (!cal_stored && (!en && (changed & (1 << Gyro)))) { + storeCalibration(); + cal_stored = 1; + } + } + + if (changed & (1 << Accelerometer)) { + LOGV_IF(ENG_VERBOSE, "HAL:enableSensors - accel %s", + (sensors & INV_THREE_AXIS_ACCEL? "enable": "disable")); + res = enableAccel(!!(sensors & INV_THREE_AXIS_ACCEL)); + if(res < 0) { + return res; + } + + if (!(sensors & INV_THREE_AXIS_ACCEL) && !cal_stored) { + storeCalibration(); + cal_stored = 1; + } + } + + if (changed & ((1 << MagneticField) | (1 << RawMagneticField))) { + LOGV_IF(ENG_VERBOSE, "HAL:enableSensors - compass %s", + (sensors & INV_THREE_AXIS_COMPASS? "enable": "disable")); + res = enableCompass(!!(sensors & INV_THREE_AXIS_COMPASS), changed & (1 << RawMagneticField)); + if(res < 0) { + return res; + } + + if (!cal_stored && (!en && (changed & (1 << MagneticField)))) { + storeCalibration(); + cal_stored = 1; + } + } + + if (changed & (1 << Pressure)) { + LOGV_IF(ENG_VERBOSE, "HAL:enableSensors - pressure %s", + (sensors & INV_ONE_AXIS_PRESSURE? "enable": "disable")); + res = enablePressure(!!(sensors & INV_ONE_AXIS_PRESSURE)); + if(res < 0) { + return res; + } + } + + if (isLowPowerQuatEnabled()) { + // Enable LP Quat + if ((mEnabled & VIRTUAL_SENSOR_9AXES_MASK) + || (mEnabled & VIRTUAL_SENSOR_GYRO_6AXES_MASK)) { + LOGV_IF(ENG_VERBOSE, "HAL: 9 axis or game rot enabled"); + if (!(changed & ((1 << Gyro) + | (1 << RawGyro) + | (1 << Accelerometer) + | (mCompassSensor->isIntegrated() << MagneticField) + | (mCompassSensor->isIntegrated() << RawMagneticField))) + ) { + /* reset master enable */ + res = masterEnable(0); + if(res < 0) { + return res; + } + } + if (!checkLPQuaternion()) { + enableLPQuaternion(1); + } else { + LOGV_IF(ENG_VERBOSE, "HAL:LP Quat already enabled"); + } + } else if (checkLPQuaternion()) { + enableLPQuaternion(0); + } + } + + /* apply accel/gyro bias to DMP bias */ + /* precondition: masterEnable(0), mGyroBiasAvailable=true */ + /* postcondition: bias is applied upon masterEnable(1) */ + if(!(sensors & INV_THREE_AXIS_GYRO)) { + setGyroBias(); + } + if(!(sensors & INV_THREE_AXIS_ACCEL)) { + setAccelBias(); + } + + /* to batch or not to batch */ + int batchMode = computeBatchSensorMask(mEnabled, mBatchEnabled); + /* skip setBatch if there is no need to */ + if(((int)mOldBatchEnabledMask != batchMode) || batchMode) { + setBatch(batchMode,0); + } + mOldBatchEnabledMask = batchMode; + + /* check for invn hardware sensors change */ + if (changed & ((1 << Gyro) | (1 << RawGyro) | (1 << Accelerometer) | + (mCompassSensor->isIntegrated() << MagneticField) | + (mCompassSensor->isIntegrated() << RawMagneticField) | + (mPressureSensor->isIntegrated() << Pressure))) { + LOGV_IF(ENG_VERBOSE, + "HAL DEBUG: Gyro, Accel, Compass, Pressure changes"); + if ((checkSmdSupport() == 1) || (checkPedometerSupport() == 1) || (sensors & + (INV_THREE_AXIS_GYRO + | INV_THREE_AXIS_ACCEL + | (INV_THREE_AXIS_COMPASS * mCompassSensor->isIntegrated()) + | (INV_ONE_AXIS_PRESSURE * mPressureSensor->isIntegrated())))) { + LOGV_IF(ENG_VERBOSE, "SMD or Hardware sensors enabled"); + LOGV_IF(ENG_VERBOSE, + "mFeatureActiveMask=0x%llx", mFeatureActiveMask); + LOGV_IF(ENG_VERBOSE, "HAL DEBUG: LPQ, SMD, SO enabled"); + // disable DMP event interrupt only (w/ data interrupt) + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, 0) < 0) { + res = -1; + LOGE("HAL:ERR can't disable DMP event interrupt"); + return res; + } + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=0x%llx", mFeatureActiveMask); + LOGV_IF(ENG_VERBOSE, "DMP_FEATURE_MASK=0x%x", DMP_FEATURE_MASK); + if ((mFeatureActiveMask & (long long)DMP_FEATURE_MASK) && + !((mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION) || + (mFeatureActiveMask & INV_DMP_PED_STANDALONE) || + (mFeatureActiveMask & INV_DMP_PED_QUATERNION) || + (mFeatureActiveMask & INV_DMP_BATCH_MODE))) { + // enable DMP + onDmp(1); + res = enableAccel(on); + if(res < 0) { + return res; + } + LOGV_IF(ENG_VERBOSE, "mLocalSensorMask=0x%lx", mLocalSensorMask); + if (((sensors | mLocalSensorMask) & INV_THREE_AXIS_ACCEL) == 0) { + res = turnOffAccelFifo(); + } + if(res < 0) { + return res; + } + } + } else { // all sensors idle + LOGV_IF(ENG_VERBOSE, "HAL DEBUG: not SMD or Hardware sensors"); + if (isDmpDisplayOrientationOn() + && (mDmpOrientationEnabled + || !isDmpScreenAutoRotationEnabled())) { + enableDmpOrientation(1); + } + + if (!cal_stored) { + storeCalibration(); + cal_stored = 1; + } + } + } else if ((changed & + ((!mCompassSensor->isIntegrated()) << MagneticField) || + ((!mCompassSensor->isIntegrated()) << RawMagneticField)) + && + !(sensors & (INV_THREE_AXIS_GYRO | INV_THREE_AXIS_ACCEL + | (INV_THREE_AXIS_COMPASS * (!mCompassSensor->isIntegrated())))) + ) { + LOGV_IF(ENG_VERBOSE, "HAL DEBUG: Gyro, Accel, Compass no change"); + if (!cal_stored) { + storeCalibration(); + cal_stored = 1; + } + } /*else { + LOGV_IF(ENG_VERBOSE, "HAL DEBUG: mEnabled"); + if (sensors & + (INV_THREE_AXIS_GYRO + | INV_THREE_AXIS_ACCEL + | (INV_THREE_AXIS_COMPASS * mCompassSensor->isIntegrated()))) { + res = masterEnable(1); + if(res < 0) + return res; + } + }*/ + + if (!batchMode && (resetDataRates() < 0)) { + LOGE("HAL:ERR can't reset output rate back to original setting"); + } + + if(mFeatureActiveMask || sensors) { + res = masterEnable(1); + if(res < 0) + return res; + } + return res; +} + +/* check if batch mode should be turned on or not */ +int MPLSensor::computeBatchSensorMask(int enableSensors, int tempBatchSensor) +{ + VFUNC_LOG; + int batchMode = 1; + mFeatureActiveMask &= ~INV_DMP_BATCH_MODE; + + LOGV_IF(ENG_VERBOSE, + "HAL:computeBatchSensorMask: enableSensors=%d tempBatchSensor=%d", + enableSensors, tempBatchSensor); + + // handle initialization case + if (enableSensors == 0 && tempBatchSensor == 0) + return 0; + + // check for possible continuous data mode + for(int i = 0; i <= Pressure; i++) { + // if any one of the hardware sensor is in continuous data mode + // turn off batch mode. + if ((enableSensors & (1 << i)) && !(tempBatchSensor & (1 << i))) { + LOGV_IF(ENG_VERBOSE, "HAL:computeBatchSensorMask: " + "hardware sensor on continuous mode:%d", i); + return 0; + } + if ((enableSensors & (1 << i)) && (tempBatchSensor & (1 << i))) { + LOGV_IF(ENG_VERBOSE, + "HAL:computeBatchSensorMask: hardware sensor is batch:%d", + i); + // if hardware sensor is batched, check if virtual sensor is also batched + if ((enableSensors & (1 << GameRotationVector)) + && !(tempBatchSensor & (1 << GameRotationVector))) { + LOGV_IF(ENG_VERBOSE, + "HAL:computeBatchSensorMask: but virtual sensor is not:%d", + i); + return 0; + } + } + } + + // if virtual sensors are on but not batched, turn off batch mode. + for(int i = Orientation; i <= GeomagneticRotationVector; i++) { + if ((enableSensors & (1 << i)) && !(tempBatchSensor & (1 << i))) { + LOGV_IF(ENG_VERBOSE, "HAL:computeBatchSensorMask: " + "composite sensor on continuous mode:%d", i); + return 0; + } + } + + if ((mFeatureActiveMask & INV_DMP_PEDOMETER) && !(tempBatchSensor & (1 << StepDetector))) { + LOGV("HAL:computeBatchSensorMask: step detector on continuous mode."); + return 0; + } + + mFeatureActiveMask |= INV_DMP_BATCH_MODE; + LOGV_IF(EXTRA_VERBOSE, + "HAL:computeBatchSensorMask: batchMode=%d, mBatchEnabled=%0x", + batchMode, tempBatchSensor); + return (batchMode && tempBatchSensor); +} + +/* This function is called by enable() */ +int MPLSensor::setBatch(int en, int toggleEnable) +{ + VFUNC_LOG; + + int res = 0; + int64_t wanted = 1000000000LL; + int64_t timeout = 0; + int timeoutInMs = 0; + int featureMask = computeBatchDataOutput(); + + // reset master enable + if (toggleEnable == 1) { + res = masterEnable(0); + if (res < 0) { + return res; + } + } + + if (en) { + /* take the minimum batchmode timeout */ + int64_t timeout = 100000000000LL; + int64_t ns; + for (int i = 0; i < NumSensors; i++) { + LOGV_IF(0, "mFeatureActiveMask=0x%016llx, mEnabled=0x%01x, mBatchEnabled=0x%x", + mFeatureActiveMask, mEnabled, mBatchEnabled); + if (((mEnabled & (1 << i)) && (mBatchEnabled & (1 << i))) || + (((featureMask & INV_DMP_PED_STANDALONE) && (mBatchEnabled & (1 << StepDetector))))) { + LOGV_IF(ENG_VERBOSE, "sensor=%d, timeout=%lld", i, mBatchTimeouts[i]); + ns = mBatchTimeouts[i]; + timeout = (ns < timeout) ? ns : timeout; + } + } + /* Convert ns to millisecond */ + timeoutInMs = timeout / 1000000; + } else { + timeoutInMs = 0; + } + + LOGV_IF(ENG_VERBOSE, "HAL: batch timeout set to %dms", timeoutInMs); + + /* step detector is enabled and */ + /* batch mode is standalone */ + if (en && (mFeatureActiveMask & INV_DMP_PEDOMETER) && + (featureMask & INV_DMP_PED_STANDALONE)) { + LOGV_IF(ENG_VERBOSE, "ID_P only = 0x%x", mBatchEnabled); + enablePedStandalone(1); + } else { + enablePedStandalone(0); + } + + /* step detector and GRV are enabled and */ + /* batch mode is ped q */ + if (en && (mFeatureActiveMask & INV_DMP_PEDOMETER) && + (mEnabled & (1 << GameRotationVector)) && + (featureMask & INV_DMP_PED_QUATERNION)) { + LOGV_IF(ENG_VERBOSE, "ID_P and GRV or ALL = 0x%x", mBatchEnabled); + LOGV_IF(ENG_VERBOSE, "ID_P is enabled for batching, " + "PED quat will be automatically enabled"); + enableLPQuaternion(0); + enablePedQuaternion(1); + } else if (!(featureMask & INV_DMP_PED_STANDALONE)){ + enablePedQuaternion(0); + } else { + enablePedQuaternion(0); + } + + /* step detector and hardware sensors enabled */ + if (en && (featureMask & INV_DMP_PED_INDICATOR) && + ((mEnabled) || + (mFeatureActiveMask & INV_DMP_PED_STANDALONE))) { + enablePedIndicator(1); + } else { + enablePedIndicator(0); + } + + /* GRV is enabled and */ + /* batch mode is 6axis q */ + if (en && (mEnabled & (1 << GameRotationVector)) && + (featureMask & INV_DMP_6AXIS_QUATERNION)) { + LOGV_IF(ENG_VERBOSE, "GRV = 0x%x", mBatchEnabled); + enableLPQuaternion(0); + enable6AxisQuaternion(1); + setInitial6QuatValue(); + } else if (!(featureMask & INV_DMP_PED_QUATERNION)){ + LOGV_IF(ENG_VERBOSE, "Toggle back to normal 6 axis"); + if (mEnabled & (1 << GameRotationVector)) { + enableLPQuaternion(checkLPQRateSupported()); + } + enable6AxisQuaternion(0); + } else { + enable6AxisQuaternion(0); + } + + /* write required timeout to sysfs */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + timeoutInMs, mpu.batchmode_timeout, getTimestamp()); + if (write_sysfs_int(mpu.batchmode_timeout, timeoutInMs) < 0) { + LOGE("HAL:ERR can't write batchmode_timeout"); + } + + if (en) { + // enable DMP + res = onDmp(1); + if (res < 0) { + return res; + } + + // set batch rates + if (setBatchDataRates() < 0) { + LOGE("HAL:ERR can't set batch data rates"); + } + + // default fifo rate to 200Hz + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 200, mpu.gyro_fifo_rate, getTimestamp()); + if (write_sysfs_int(mpu.gyro_fifo_rate, 200) < 0) { + res = -1; + LOGE("HAL:ERR can't set rate to 200Hz"); + return res; + } + } else { + if (mFeatureActiveMask == 0) { + // disable DMP + res = onDmp(0); + if (res < 0) { + return res; + } + /* reset sensor rate */ + if (resetDataRates() < 0) { + LOGE("HAL:ERR can't reset output rate back to original setting"); + } + } + } + + // set sensor data interrupt + uint32_t dataInterrupt = (mEnabled || (mFeatureActiveMask & INV_DMP_BATCH_MODE)); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + !dataInterrupt, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, !dataInterrupt) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + + if (toggleEnable == 1) { + if (mFeatureActiveMask || mEnabled) + masterEnable(1); + } + return res; +} + +/* Store calibration file */ +void MPLSensor::storeCalibration(void) +{ + VFUNC_LOG; + + if(mHaveGoodMpuCal == true + || mAccelAccuracy >= 2 + || mCompassAccuracy >= 3) { + int res = inv_store_calibration(); + if (res) { + LOGE("HAL:Cannot store calibration on file"); + } else { + LOGV_IF(PROCESS_VERBOSE, "HAL:Cal file updated"); + } + } +} + +/* these handlers transform mpl data into one of the Android sensor types */ +int MPLSensor::gyroHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_gyroscope(s->gyro.v, &s->gyro.status, + &s->timestamp); + LOGV_IF(HANDLER_DATA, "HAL:gyro data : %+f %+f %+f -- %lld - %d", + s->gyro.v[0], s->gyro.v[1], s->gyro.v[2], s->timestamp, update); + return update; +} + +int MPLSensor::rawGyroHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_gyroscope_raw(s->uncalibrated_gyro.uncalib, + &s->gyro.status, &s->timestamp); + if(update) { + memcpy(s->uncalibrated_gyro.bias, mGyroBias, sizeof(mGyroBias)); + LOGV_IF(HANDLER_DATA,"HAL:gyro bias data : %+f %+f %+f -- %lld - %d", + s->uncalibrated_gyro.bias[0], s->uncalibrated_gyro.bias[1], + s->uncalibrated_gyro.bias[2], s->timestamp, update); + } + s->gyro.status = SENSOR_STATUS_UNRELIABLE; + LOGV_IF(HANDLER_DATA, "HAL:raw gyro data : %+f %+f %+f -- %lld - %d", + s->uncalibrated_gyro.uncalib[0], s->uncalibrated_gyro.uncalib[1], + s->uncalibrated_gyro.uncalib[2], s->timestamp, update); + return update; +} + +int MPLSensor::accelHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_accelerometer( + s->acceleration.v, &s->acceleration.status, &s->timestamp); + LOGV_IF(HANDLER_DATA, "HAL:accel data : %+f %+f %+f -- %lld - %d", + s->acceleration.v[0], s->acceleration.v[1], s->acceleration.v[2], + s->timestamp, update); + mAccelAccuracy = s->acceleration.status; + return update; +} + +int MPLSensor::compassHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_magnetic_field( + s->magnetic.v, &s->magnetic.status, &s->timestamp); + LOGV_IF(HANDLER_DATA, "HAL:compass data: %+f %+f %+f -- %lld - %d", + s->magnetic.v[0], s->magnetic.v[1], s->magnetic.v[2], + s->timestamp, update); + mCompassAccuracy = s->magnetic.status; + return update; +} + +int MPLSensor::rawCompassHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + //TODO: need to handle uncalib data and bias for 3rd party compass + if(mCompassSensor->providesCalibration()) { + update = mCompassSensor->readRawSample(s->uncalibrated_magnetic.uncalib, &s->timestamp); + } + else { + update = inv_get_sensor_type_magnetic_field_raw(s->uncalibrated_magnetic.uncalib, + &s->magnetic.status, &s->timestamp); + } + if(update) { + memcpy(s->uncalibrated_magnetic.bias, mCompassBias, sizeof(mCompassBias)); + LOGV_IF(HANDLER_DATA, "HAL:compass bias data: %+f %+f %+f -- %lld - %d", + s->uncalibrated_magnetic.bias[0], s->uncalibrated_magnetic.bias[1], + s->uncalibrated_magnetic.bias[2], s->timestamp, update); + } + s->magnetic.status = SENSOR_STATUS_UNRELIABLE; + LOGV_IF(HANDLER_DATA, "HAL:compass raw data: %+f %+f %+f %d -- %lld - %d", + s->uncalibrated_magnetic.uncalib[0], s->uncalibrated_magnetic.uncalib[1], + s->uncalibrated_magnetic.uncalib[2], s->magnetic.status, s->timestamp, update); + return update; +} + +/* + Rotation Vector handler. + NOTE: rotation vector does not have an accuracy or status +*/ +int MPLSensor::rvHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int8_t status; + int update; + update = inv_get_sensor_type_rotation_vector(s->data, &status, + &s->timestamp); + update |= isCompassDisabled(); + LOGV_IF(HANDLER_DATA, "HAL:rv data: %+f %+f %+f %+f %+f- %+lld - %d", + s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->timestamp, + update); + + return update; +} + +/* + Game Rotation Vector handler. + NOTE: rotation vector does not have an accuracy or status +*/ +int MPLSensor::grvHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int8_t status; + int update; + update = inv_get_sensor_type_rotation_vector_6_axis(s->data, &status, + &s->timestamp); + + LOGV_IF(HANDLER_DATA, "HAL:grv data: %+f %+f %+f %+f %+f - %+lld - %d", + s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->timestamp, + update); + return update; +} + +int MPLSensor::laHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_linear_acceleration( + s->gyro.v, &s->gyro.status, &s->timestamp); + update |= isCompassDisabled(); + LOGV_IF(HANDLER_DATA, "HAL:la data: %+f %+f %+f - %lld - %d", + s->gyro.v[0], s->gyro.v[1], s->gyro.v[2], s->timestamp, update); + return update; +} + +int MPLSensor::gravHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_gravity(s->gyro.v, &s->gyro.status, + &s->timestamp); + update |= isCompassDisabled(); + LOGV_IF(HANDLER_DATA, "HAL:gr data: %+f %+f %+f - %lld - %d", + s->gyro.v[0], s->gyro.v[1], s->gyro.v[2], s->timestamp, update); + return update; +} + +int MPLSensor::orienHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update; + update = inv_get_sensor_type_orientation( + s->orientation.v, &s->orientation.status, &s->timestamp); + update |= isCompassDisabled(); + LOGV_IF(HANDLER_DATA, "HAL:or data: %f %f %f - %lld - %d", + s->orientation.v[0], s->orientation.v[1], s->orientation.v[2], + s->timestamp, update); + return update; +} + +int MPLSensor::smHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update = 1; + + /* When event is triggered, set data to 1 */ + s->data[0] = 1.f; + s->data[1] = 0.f; + s->data[2] = 0.f; + + /* Capture timestamp in HAL */ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + s->timestamp = (int64_t) ts.tv_sec * 1000000000 + ts.tv_nsec; + + LOGV_IF(HANDLER_DATA, "HAL:sm data: %f - %lld - %d", + s->data[0], s->timestamp, update); + return update; +} + +int MPLSensor::gmHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int8_t status; + int update = 0; + update = inv_get_sensor_type_geomagnetic_rotation_vector(s->data, &status, + &s->timestamp); + + LOGV_IF(HANDLER_DATA, "HAL:gm data: %+f %+f %+f %+f %+f- %+lld - %d", + s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->timestamp, update); + return update < 1 ? 0 :1; + +} + +int MPLSensor::psHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int8_t status; + int update = 0; + + s->pressure = mCachedPressureData / 100.f; //hpa (millibar) + s->data[1] = 0; + s->data[2] = 0; + s->timestamp = mPressureTimestamp; + s->magnetic.status = 0; + update = mPressureUpdate; + mPressureUpdate = 0; + + LOGV_IF(HANDLER_DATA, "HAL:ps data: %+f %+f %+f %+f- %+lld - %d", + s->data[0], s->data[1], s->data[2], s->data[3], s->timestamp, update); + return update < 1 ? 0 :1; + +} + +int MPLSensor::sdHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update = 1; + + /* When event is triggered, set data to 1 */ + s->data[0] = 1; + s->data[1] = 0.f; + s->data[2] = 0.f; + + /* get current timestamp */ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts) ; + s->timestamp = (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; + + LOGV_IF(HANDLER_DATA, "HAL:sd data: %f - %lld - %d", + s->data[0], s->timestamp, update); + return update; +} + +int MPLSensor::scHandler(sensors_event_t* s) +{ + VHANDLER_LOG; + int update = 1; + + /* Set step count */ +#if defined ANDROID_KITKAT + s->u64.step_counter = mLastStepCount; + LOGV_IF(HANDLER_DATA, "HAL:sc data: %lld - %lld - %d", + s->u64.step_counter, s->timestamp, update); +#else + s->step_counter = mLastStepCount; + LOGV_IF(HANDLER_DATA, "HAL:sc data: %lld - %lld - %d", + s->step_counter, s->timestamp, update); +#endif + return update; +} + +int MPLSensor::metaHandler(sensors_event_t* s, int flags) +{ + VHANDLER_LOG; + int update = 0; + +#if defined ANDROID_KITKAT + /* initalize SENSOR_TYPE_META_DATA */ + s->version = 0; + s->sensor = 0; + s->reserved0 = 0; + s->timestamp = 0LL; + + switch(flags) { + case META_DATA_FLUSH_COMPLETE: + update = mFlushBatchSet; + s->type = SENSOR_TYPE_META_DATA; + s->meta_data.what = flags; + s->meta_data.sensor = mFlushSensorEnabled; + mFlushBatchSet = 0; + mFlushSensorEnabled = -1; + LOGV_IF(HANDLER_DATA, + "HAL:flush complete data: type=%d what=%d, " + "sensor=%d - %lld - %d", + s->type, s->meta_data.what, s->meta_data.sensor, + s->timestamp, update); + break; + + default: + LOGW("HAL: Meta flags not supported"); + break; + } +#endif + return update; +} + +int MPLSensor::enable(int32_t handle, int en) +{ + VFUNC_LOG; + + android::String8 sname; + int what = -1, err = 0; + int batchMode = 0; + + if (uint32_t(handle) >= NumSensors) + return -EINVAL; + + if (!en) + mBatchEnabled &= ~(1 << handle); + + LOGV_IF(ENG_VERBOSE, "HAL:handle = %d", handle); + + switch (handle) { + case ID_SC: + what = StepCounter; + sname = "Step Counter"; + LOGV_IF(PROCESS_VERBOSE, "HAL:enable - sensor %s (handle %d) %s -> %s", + sname.string(), handle, + (mDmpStepCountEnabled? "en": "dis"), + (en? "en" : "dis")); + enableDmpPedometer(en, 0); + mDmpStepCountEnabled = !!en; + return 0; + case ID_P: + sname = "StepDetector"; + LOGV_IF(PROCESS_VERBOSE, "HAL:enable - sensor %s (handle %d) %s -> %s", + sname.string(), handle, + (mDmpPedometerEnabled? "en": "dis"), + (en? "en" : "dis")); + enableDmpPedometer(en, 1); + mDmpPedometerEnabled = !!en; + batchMode = computeBatchSensorMask(mEnabled, mBatchEnabled); + /* skip setBatch if there is no need to */ + if(((int)mOldBatchEnabledMask != batchMode) || batchMode) { + setBatch(batchMode,1); + } + mOldBatchEnabledMask = batchMode; + return 0; + case ID_SM: + sname = "Significant Motion"; + LOGV_IF(PROCESS_VERBOSE, "HAL:enable - sensor %s (handle %d) %s -> %s", + sname.string(), handle, + (mDmpSignificantMotionEnabled? "en": "dis"), + (en? "en" : "dis")); + enableDmpSignificantMotion(en); + mDmpSignificantMotionEnabled = !!en; + return 0; + case ID_SO: + sname = "Screen Orientation"; + LOGV_IF(PROCESS_VERBOSE, "HAL:enable - sensor %s (handle %d) %s -> %s", + sname.string(), handle, + (mDmpOrientationEnabled? "en": "dis"), + (en? "en" : "dis")); + enableDmpOrientation(en && isDmpDisplayOrientationOn()); + mDmpOrientationEnabled = !!en; + return 0; + case ID_A: + what = Accelerometer; + sname = "Accelerometer"; + break; + case ID_M: + what = MagneticField; + sname = "MagneticField"; + break; + case ID_RM: + what = RawMagneticField; + sname = "MagneticField Uncalibrated"; + break; + case ID_O: + what = Orientation; + sname = "Orientation"; + break; + case ID_GY: + what = Gyro; + sname = "Gyro"; + break; + case ID_RG: + what = RawGyro; + sname = "Gyro Uncalibrated"; + break; + case ID_GR: + what = Gravity; + sname = "Gravity"; + break; + case ID_RV: + what = RotationVector; + sname = "RotationVector"; + break; + case ID_GRV: + what = GameRotationVector; + sname = "GameRotationVector"; + break; + case ID_LA: + what = LinearAccel; + sname = "LinearAccel"; + break; + case ID_GMRV: + what = GeomagneticRotationVector; + sname = "GeomagneticRotationVector"; + break; + case ID_PS: + what = Pressure; + sname = "Pressure"; + break; + default: + what = handle; + sname = "Others"; + break; + } + + int newState = en ? 1 : 0; + unsigned long sen_mask; + + LOGV_IF(PROCESS_VERBOSE, "HAL:enable - sensor %s (handle %d) %s -> %s", + sname.string(), handle, + ((mEnabled & (1 << what)) ? "en" : "dis"), + ((uint32_t(newState) << what) ? "en" : "dis")); + LOGV_IF(ENG_VERBOSE, + "HAL:%s sensor state change what=%d", sname.string(), what); + + // pthread_mutex_lock(&mMplMutex); + // pthread_mutex_lock(&mHALMutex); + + if ((uint32_t(newState) << what) != (mEnabled & (1 << what))) { + uint32_t sensor_type; + short flags = newState; + uint32_t lastEnabled = mEnabled, changed = 0; + + mEnabled &= ~(1 << what); + mEnabled |= (uint32_t(flags) << what); + + LOGV_IF(ENG_VERBOSE, "HAL:flags = %d", flags); + computeLocalSensorMask(mEnabled); + LOGV_IF(ENG_VERBOSE, "HAL:enable : mEnabled = %d", mEnabled); + LOGV_IF(ENG_VERBOSE, "HAL:last enable : lastEnabled = %d", lastEnabled); + sen_mask = mLocalSensorMask & mMasterSensorMask; + mSensorMask = sen_mask; + LOGV_IF(ENG_VERBOSE, "HAL:sen_mask= 0x%0lx", sen_mask); + + switch (what) { + case Gyro: + case RawGyro: + case Accelerometer: + if ((!(mEnabled & VIRTUAL_SENSOR_GYRO_6AXES_MASK) && + !(mEnabled & VIRTUAL_SENSOR_9AXES_MASK)) && + ((lastEnabled & (1 << what)) != (mEnabled & (1 << what)))) { + changed |= (1 << what); + } + if (mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION) { + changed |= (1 << what); + } + break; + case MagneticField: + case RawMagneticField: + if (!(mEnabled & VIRTUAL_SENSOR_9AXES_MASK) && + ((lastEnabled & (1 << what)) != (mEnabled & (1 << what)))) { + changed |= (1 << what); + } + break; + case Pressure: + if ((lastEnabled & (1 << what)) != (mEnabled & (1 << what))) { + changed |= (1 << what); + } + break; + case GameRotationVector: + if (!en) + storeCalibration(); + if ((en && !(lastEnabled & VIRTUAL_SENSOR_ALL_MASK)) + || + (en && !(lastEnabled & VIRTUAL_SENSOR_9AXES_MASK)) + || + (!en && !(mEnabled & VIRTUAL_SENSOR_ALL_MASK)) + || + (!en && (mEnabled & VIRTUAL_SENSOR_MAG_6AXES_MASK))) { + for (int i = Gyro; i <= RawMagneticField; i++) { + if (!(mEnabled & (1 << i))) { + changed |= (1 << i); + } + } + } + break; + + case Orientation: + case RotationVector: + case LinearAccel: + case Gravity: + if (!en) + storeCalibration(); + if ((en && !(lastEnabled & VIRTUAL_SENSOR_9AXES_MASK)) + || + (!en && !(mEnabled & VIRTUAL_SENSOR_9AXES_MASK))) { + for (int i = Gyro; i <= RawMagneticField; i++) { + if (!(mEnabled & (1 << i))) { + changed |= (1 << i); + } + } + } + break; + case GeomagneticRotationVector: + if (!en) + storeCalibration(); + if ((en && !(lastEnabled & VIRTUAL_SENSOR_ALL_MASK)) + || + (en && !(lastEnabled & VIRTUAL_SENSOR_9AXES_MASK)) + || + (!en && !(mEnabled & VIRTUAL_SENSOR_ALL_MASK)) + || + (!en && (mEnabled & VIRTUAL_SENSOR_GYRO_6AXES_MASK))) { + for (int i = Accelerometer; i <= RawMagneticField; i++) { + if (!(mEnabled & (1<<i))) { + changed |= (1 << i); + } + } + } + break; + } + LOGV_IF(ENG_VERBOSE, "HAL:changed = %d", changed); + enableSensors(sen_mask, flags, changed); + } + + // pthread_mutex_unlock(&mMplMutex); + // pthread_mutex_unlock(&mHALMutex); + +#ifdef INV_PLAYBACK_DBG + /* apparently the logging needs to go through this sequence + to properly flush the log file */ + inv_turn_off_data_logging(); + if (fclose(logfile) < 0) { + LOGE("cannot close debug log file"); + } + logfile = fopen("/data/playback.bin", "ab"); + if (logfile) + inv_turn_on_data_logging(logfile); +#endif + + return err; +} + +void MPLSensor::getHandle(int32_t handle, int &what, android::String8 &sname) +{ + VFUNC_LOG; + + what = -1; + + switch (handle) { + case ID_P: + what = StepDetector; + sname = "StepDetector"; + break; + case ID_SC: + what = StepCounter; + sname = "StepCounter"; + break; + case ID_SM: + what = SignificantMotion; + sname = "SignificantMotion"; + break; + case ID_SO: + what = handle; + sname = "ScreenOrienation"; + break; + case ID_A: + what = Accelerometer; + sname = "Accelerometer"; + break; + case ID_M: + what = MagneticField; + sname = "MagneticField"; + break; + case ID_RM: + what = RawMagneticField; + sname = "MagneticField Uncalibrated"; + break; + case ID_O: + what = Orientation; + sname = "Orientation"; + break; + case ID_GY: + what = Gyro; + sname = "Gyro"; + break; + case ID_RG: + what = RawGyro; + sname = "Gyro Uncalibrated"; + break; + case ID_GR: + what = Gravity; + sname = "Gravity"; + break; + case ID_RV: + what = RotationVector; + sname = "RotationVector"; + break; + case ID_GRV: + what = GameRotationVector; + sname = "GameRotationVector"; + break; + case ID_LA: + what = LinearAccel; + sname = "LinearAccel"; + break; + case ID_PS: + what = Pressure; + sname = "Pressure"; + break; + default: // this takes care of all the gestures + what = handle; + sname = "Others"; + break; + } + + LOGI_IF(EXTRA_VERBOSE, "HAL:getHandle - what=%d, sname=%s", what, sname.string()); + return; +} + +int MPLSensor::setDelay(int32_t handle, int64_t ns) +{ + VFUNC_LOG; + + android::String8 sname; + int what = -1; + +#if 0 + // skip the 1st call for enalbing sensors called by ICS/JB sensor service + static int counter_delay = 0; + if (!(mEnabled & (1 << what))) { + counter_delay = 0; + } else { + if (++counter_delay == 1) { + return 0; + } + else { + counter_delay = 0; + } + } +#endif + + getHandle(handle, what, sname); + if (uint32_t(what) >= NumSensors) + return -EINVAL; + + if (ns < 0) + return -EINVAL; + + LOGV_IF(PROCESS_VERBOSE, + "setDelay : %llu ns, (%.2f Hz)", ns, 1000000000.f / ns); + + // limit all rates to reasonable ones */ + if (ns < 5000000LL) { + ns = 5000000LL; + } + + /* store request rate to mDelays arrary for each sensor */ + int64_t previousDelay = mDelays[what]; + mDelays[what] = ns; + LOGV_IF(ENG_VERBOSE, "storing mDelays[%d] = %lld, previousDelay = %lld", what, ns, previousDelay); + + switch (what) { + case StepCounter: + /* set limits of delivery rate of events */ + mStepCountPollTime = ns; + LOGV_IF(ENG_VERBOSE, "step count rate =%lld ns", ns); + break; + case StepDetector: + case SignificantMotion: +#ifdef ENABLE_DMP_SCREEN_AUTO_ROTATION + case ID_SO: +#endif + LOGV_IF(ENG_VERBOSE, "Step Detect, SMD, SO rate=%lld ns", ns); + break; + case Gyro: + case RawGyro: + case Accelerometer: + // need to update delay since they are different + // resetDataRates was called earlier + // LOGV("what=%d mEnabled=%d mDelays[%d]=%lld previousDelay=%lld", + // what, mEnabled, what, mDelays[what], previousDelay); + if ((mEnabled & (1 << what)) && (previousDelay != mDelays[what])) { + LOGV_IF(ENG_VERBOSE, + "HAL:need to update delay due to resetDataRates"); + break; + } + for (int i = Gyro; + i <= Accelerometer + mCompassSensor->isIntegrated(); + i++) { + if (i != what && (mEnabled & (1 << i)) && ns > mDelays[i]) { + LOGV_IF(ENG_VERBOSE, + "HAL:ignore delay set due to sensor %d", i); + return 0; + } + } + break; + + case MagneticField: + case RawMagneticField: + // need to update delay since they are different + // resetDataRates was called earlier + if ((mEnabled & (1 << what)) && (previousDelay != mDelays[what])) { + LOGV_IF(ENG_VERBOSE, + "HAL:need to update delay due to resetDataRates"); + break; + } + if (mCompassSensor->isIntegrated() && + (((mEnabled & (1 << Gyro)) && ns > mDelays[Gyro]) || + ((mEnabled & (1 << RawGyro)) && ns > mDelays[RawGyro]) || + ((mEnabled & (1 << Accelerometer)) && + ns > mDelays[Accelerometer])) && + !checkBatchEnabled()) { + /* if request is slower rate, ignore request */ + LOGV_IF(ENG_VERBOSE, + "HAL:ignore delay set due to gyro/accel"); + return 0; + } + break; + + case Orientation: + case RotationVector: + case GameRotationVector: + case GeomagneticRotationVector: + case LinearAccel: + case Gravity: + if (isLowPowerQuatEnabled()) { + LOGV_IF(ENG_VERBOSE, + "HAL:need to update delay due to LPQ"); + break; + } + + for (int i = 0; i < NumSensors; i++) { + if (i != what && (mEnabled & (1 << i)) && ns > mDelays[i]) { + LOGV_IF(ENG_VERBOSE, + "HAL:ignore delay set due to sensor %d", i); + return 0; + } + } + break; + } + + // pthread_mutex_lock(&mHALMutex); + int res = update_delay(); + // pthread_mutex_unlock(&mHALMutex); + return res; +} + +int MPLSensor::update_delay(void) +{ + VFUNC_LOG; + + int res = 0; + int64_t got; + + if (mEnabled) { + int64_t wanted = 1000000000LL; + int64_t wanted_3rd_party_sensor = 1000000000LL; + + // Sequence to change sensor's FIFO rate + // 1. reset master enable + // 2. Update delay + // 3. set master enable + + // reset master enable + masterEnable(0); + + int64_t gyroRate; + int64_t accelRate; + int64_t compassRate; + int64_t pressureRate; + + int rateInus; + int mplGyroRate; + int mplAccelRate; + int mplCompassRate; + int tempRate = wanted; + + /* search the minimum delay requested across all enabled sensors */ + for (int i = 0; i < NumSensors; i++) { + if (mEnabled & (1 << i)) { + int64_t ns = mDelays[i]; + wanted = wanted < ns ? wanted : ns; + } + } + + /* initialize rate for each sensor */ + gyroRate = wanted; + accelRate = wanted; + compassRate = wanted; + pressureRate = wanted; + // same delay for 3rd party Accel or Compass + wanted_3rd_party_sensor = wanted; + + int enabled_sensors = mEnabled; + int tempFd = -1; + + if(mFeatureActiveMask & INV_DMP_BATCH_MODE) { + // set batch rates + LOGV_IF(ENG_VERBOSE, "HAL: mFeatureActiveMask=%016llx", mFeatureActiveMask); + LOGV("HAL: batch mode is set, set batch data rates"); + if (setBatchDataRates() < 0) { + LOGE("HAL:ERR can't set batch data rates"); + } + } else { + /* set master sampling frequency */ + int64_t tempWanted = wanted; + getDmpRate(&tempWanted); + /* driver only looks at sampling frequency if DMP is off */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / tempWanted, mpu.gyro_fifo_rate, getTimestamp()); + tempFd = open(mpu.gyro_fifo_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / tempWanted); + LOGE_IF(res < 0, "HAL:sampling frequency update delay error"); + + if (LA_ENABLED || GR_ENABLED || RV_ENABLED + || GRV_ENABLED || O_ENABLED || GMRV_ENABLED) { + rateInus = (int)wanted / 1000LL; + + /* set rate in MPL */ + /* compass can only do 100Hz max */ + inv_set_gyro_sample_rate(rateInus); + inv_set_accel_sample_rate(rateInus); + inv_set_compass_sample_rate(rateInus); + inv_set_linear_acceleration_sample_rate(rateInus); + inv_set_orientation_sample_rate(rateInus); + inv_set_rotation_vector_sample_rate(rateInus); + inv_set_gravity_sample_rate(rateInus); + inv_set_orientation_geomagnetic_sample_rate(rateInus); + inv_set_rotation_vector_6_axis_sample_rate(rateInus); + inv_set_geomagnetic_rotation_vector_sample_rate(rateInus); + + LOGV_IF(ENG_VERBOSE, + "HAL:MPL virtual sensor sample rate: (mpl)=%d us (mpu)=%.2f Hz", + rateInus, 1000000000.f / wanted); + LOGV_IF(ENG_VERBOSE, + "HAL:MPL gyro sample rate: (mpl)=%d us (mpu)=%.2f Hz", + rateInus, 1000000000.f / gyroRate); + LOGV_IF(ENG_VERBOSE, + "HAL:MPL accel sample rate: (mpl)=%d us (mpu)=%.2f Hz", + rateInus, 1000000000.f / accelRate); + LOGV_IF(ENG_VERBOSE, + "HAL:MPL compass sample rate: (mpl)=%d us (mpu)=%.2f Hz", + rateInus, 1000000000.f / compassRate); + + LOGV_IF(ENG_VERBOSE, + "mFeatureActiveMask=%016llx", mFeatureActiveMask); + if(mFeatureActiveMask & DMP_FEATURE_MASK) { + bool setDMPrate= 0; + gyroRate = wanted; + accelRate = wanted; + compassRate = wanted; + // same delay for 3rd party Accel or Compass + wanted_3rd_party_sensor = wanted; + rateInus = (int)wanted / 1000LL; + // Set LP Quaternion sample rate if enabled + if (checkLPQuaternion()) { + if (wanted <= RATE_200HZ) { +#ifndef USE_LPQ_AT_FASTEST + enableLPQuaternion(0); +#endif + } else { + inv_set_quat_sample_rate(rateInus); + LOGV_IF(ENG_VERBOSE, "HAL:MPL quat sample rate: " + "(mpl)=%d us (mpu)=%.2f Hz", + rateInus, 1000000000.f / wanted); + setDMPrate= 1; + } + } + } + + LOGV_IF(EXTRA_VERBOSE, "HAL:setDelay - Fusion"); + //nsToHz + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / gyroRate, mpu.gyro_rate, + getTimestamp()); + tempFd = open(mpu.gyro_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / gyroRate); + if(res < 0) { + LOGE("HAL:GYRO update delay error"); + } + + if(USE_THIRD_PARTY_ACCEL == 1) { + // 3rd party accelerometer - if applicable + // nsToHz (BMA250) + LOGV_IF(SYSFS_VERBOSE, "echo %lld > %s (%lld)", + wanted_3rd_party_sensor / 1000000L, mpu.accel_rate, + getTimestamp()); + tempFd = open(mpu.accel_rate, O_RDWR); + res = write_attribute_sensor(tempFd, + wanted_3rd_party_sensor / 1000000L); + LOGE_IF(res < 0, "HAL:ACCEL update delay error"); + } else { + // mpu accel + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / accelRate, mpu.accel_rate, + getTimestamp()); + tempFd = open(mpu.accel_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / accelRate); + LOGE_IF(res < 0, "HAL:ACCEL update delay error"); + } + + if (!mCompassSensor->isIntegrated()) { + // stand-alone compass - if applicable + LOGV_IF(ENG_VERBOSE, + "HAL:Ext compass delay %lld", wanted_3rd_party_sensor); + LOGV_IF(ENG_VERBOSE, "HAL:Ext compass rate %.2f Hz", + 1000000000.f / wanted_3rd_party_sensor); + if (wanted_3rd_party_sensor < + mCompassSensor->getMinDelay() * 1000LL) { + wanted_3rd_party_sensor = + mCompassSensor->getMinDelay() * 1000LL; + } + LOGV_IF(ENG_VERBOSE, + "HAL:Ext compass delay %lld", wanted_3rd_party_sensor); + LOGV_IF(ENG_VERBOSE, "HAL:Ext compass rate %.2f Hz", + 1000000000.f / wanted_3rd_party_sensor); + mCompassSensor->setDelay(ID_M, wanted_3rd_party_sensor); + got = mCompassSensor->getDelay(ID_M); + inv_set_compass_sample_rate(got / 1000); + } else { + // compass on secondary bus + if (compassRate < mCompassSensor->getMinDelay() * 1000LL) { + compassRate = mCompassSensor->getMinDelay() * 1000LL; + } + mCompassSensor->setDelay(ID_M, compassRate); + } + } else { + + if (GY_ENABLED || RGY_ENABLED) { + wanted = (mDelays[Gyro] <= mDelays[RawGyro]? + (mEnabled & (1 << Gyro)? mDelays[Gyro]: mDelays[RawGyro]): + (mEnabled & (1 << RawGyro)? mDelays[RawGyro]: mDelays[Gyro])); + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + inv_set_gyro_sample_rate((int)wanted/1000LL); + LOGV_IF(ENG_VERBOSE, + "HAL:MPL gyro sample rate: (mpl)=%d us", int(wanted/1000LL)); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / wanted, mpu.gyro_rate, getTimestamp()); + tempFd = open(mpu.gyro_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / wanted); + LOGE_IF(res < 0, "HAL:GYRO update delay error"); + } + + if (A_ENABLED) { /* there is only 1 fifo rate for MPUxxxx */ + if (GY_ENABLED && mDelays[Gyro] < mDelays[Accelerometer]) { + wanted = mDelays[Gyro]; + } else if (RGY_ENABLED && mDelays[RawGyro] + < mDelays[Accelerometer]) { + wanted = mDelays[RawGyro]; + } else { + wanted = mDelays[Accelerometer]; + } + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + inv_set_accel_sample_rate((int)wanted/1000LL); + LOGV_IF(ENG_VERBOSE, "HAL:MPL accel sample rate: (mpl)=%d us", + int(wanted/1000LL)); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / wanted, mpu.accel_rate, + getTimestamp()); + tempFd = open(mpu.accel_rate, O_RDWR); + if(USE_THIRD_PARTY_ACCEL == 1) { + //BMA250 in ms + res = write_attribute_sensor(tempFd, wanted / 1000000L); + } + else { + //MPUxxxx in hz + res = write_attribute_sensor(tempFd, 1000000000.f/wanted); + } + LOGE_IF(res < 0, "HAL:ACCEL update delay error"); + } + + /* Invensense compass calibration */ + if (M_ENABLED || RM_ENABLED) { + int64_t compassWanted = (mDelays[MagneticField] <= mDelays[RawMagneticField]? + (mEnabled & (1 << MagneticField)? mDelays[MagneticField]: mDelays[RawMagneticField]): + (mEnabled & (1 << RawMagneticField)? mDelays[RawMagneticField]: mDelays[MagneticField])); + if (!mCompassSensor->isIntegrated()) { + wanted = compassWanted; + } else { + if (GY_ENABLED + && (mDelays[Gyro] < compassWanted)) { + wanted = mDelays[Gyro]; + } else if (RGY_ENABLED + && mDelays[RawGyro] < compassWanted) { + wanted = mDelays[RawGyro]; + } else if (A_ENABLED && mDelays[Accelerometer] + < compassWanted) { + wanted = mDelays[Accelerometer]; + } else { + wanted = compassWanted; + } + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + } + + mCompassSensor->setDelay(ID_M, wanted); + got = mCompassSensor->getDelay(ID_M); + inv_set_compass_sample_rate(got / 1000); + LOGV_IF(ENG_VERBOSE, "HAL:MPL compass sample rate: (mpl)=%d us", + int(got/1000LL)); + } + + if (PS_ENABLED) { + int64_t pressureRate = mDelays[Pressure]; + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + mPressureSensor->setDelay(ID_PS, pressureRate); + LOGE_IF(res < 0, "HAL:PRESSURE update delay error"); + } + } + + } //end of non batch mode + + unsigned long sensors = mLocalSensorMask & mMasterSensorMask; + if (sensors & + (INV_THREE_AXIS_GYRO + | INV_THREE_AXIS_ACCEL + | (INV_THREE_AXIS_COMPASS * mCompassSensor->isIntegrated() + | (INV_ONE_AXIS_PRESSURE * mPressureSensor->isIntegrated())))) { + LOGV_IF(ENG_VERBOSE, "sensors=%lu", sensors); + res = masterEnable(1); + if(res < 0) + return res; + } else { // all sensors idle -> reduce power, unless DMP is needed + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + if(mFeatureActiveMask & DMP_FEATURE_MASK) { + res = masterEnable(1); + if(res < 0) + return res; + } + } + } + + return res; +} + +/* For Third Party Accel Input Subsystem Drivers only */ +int MPLSensor::readAccelEvents(sensors_event_t* data, int count) +{ + VHANDLER_LOG; + + if (count < 1) + return -EINVAL; + + ssize_t n = mAccelInputReader.fill(accel_fd); + if (n < 0) { + LOGE("HAL:missed accel events, exit"); + return n; + } + + int numEventReceived = 0; + input_event const* event; + int nb, done = 0; + + while (done == 0 && count && mAccelInputReader.readEvent(&event)) { + int type = event->type; + if (type == EV_ABS) { + if (event->code == EVENT_TYPE_ACCEL_X) { + mPendingMask |= 1 << Accelerometer; + mCachedAccelData[0] = event->value; + } else if (event->code == EVENT_TYPE_ACCEL_Y) { + mPendingMask |= 1 << Accelerometer; + mCachedAccelData[1] = event->value; + } else if (event->code == EVENT_TYPE_ACCEL_Z) { + mPendingMask |= 1 << Accelerometer; + mCachedAccelData[2] =event-> value; + } + } else if (type == EV_SYN) { + done = 1; + if (mLocalSensorMask & INV_THREE_AXIS_ACCEL) { + inv_build_accel(mCachedAccelData, 0, getTimestamp()); + } + } else { + LOGE("HAL:AccelSensor: unknown event (type=%d, code=%d)", + type, event->code); + } + mAccelInputReader.next(); + } + + return numEventReceived; +} + +/** + * Should be called after reading at least one of gyro + * compass or accel data. (Also okay for handling all of them). + * @returns 0, if successful, error number if not. + */ +int MPLSensor::readEvents(sensors_event_t* data, int count) +{ + VHANDLER_LOG; + + inv_execute_on_data(); + + int numEventReceived = 0; + + long msg; + msg = inv_get_message_level_0(1); + if (msg) { + if (msg & INV_MSG_MOTION_EVENT) { + LOGV_IF(PROCESS_VERBOSE, "HAL:**** Motion ****\n"); + } + if (msg & INV_MSG_NO_MOTION_EVENT) { + LOGV_IF(PROCESS_VERBOSE, "HAL:***** No Motion *****\n"); + /* after the first no motion, the gyro should be + calibrated well */ + mGyroAccuracy = SENSOR_STATUS_ACCURACY_HIGH; + /* if gyros are on and we got a no motion, set a flag + indicating that the cal file can be written. */ + mHaveGoodMpuCal = true; + } + if(msg & INV_MSG_NEW_AB_EVENT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:***** New Accel Bias *****\n"); + getAccelBias(); + mAccelAccuracy = inv_get_accel_accuracy(); + } + if(msg & INV_MSG_NEW_GB_EVENT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:***** New Gyro Bias *****\n"); + getGyroBias(); + setGyroBias(); + } + if(msg & INV_MSG_NEW_FGB_EVENT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:***** New Factory Gyro Bias *****\n"); + getFactoryGyroBias(); + } + if(msg & INV_MSG_NEW_FAB_EVENT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:***** New Factory Accel Bias *****\n"); + getFactoryAccelBias(); + } + if(msg & INV_MSG_NEW_CB_EVENT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:***** New Compass Bias *****\n"); + getCompassBias(); + mCompassAccuracy = inv_get_mag_accuracy(); + } + } + + // handle partial packet read and end marker + // skip readEvents from hal_outputs + if (mSkipReadEvents) { + if(mDataMarkerDetected || mEmptyDataMarkerDetected) { + if (!mEmptyDataMarkerDetected) { + // turn off sensors in data_builder + resetMplStates(); + } + mEmptyDataMarkerDetected = 0; + mDataMarkerDetected = 0; + + // handle flush complete event + if(mFlushBatchSet && mFlushSensorEnabled != -1) { + sensors_event_t temp; +#if defined ANDROID_KITKAT + int sendEvent = metaHandler(&temp, META_DATA_FLUSH_COMPLETE); +#else + int sendEvent = metaHandler(&temp, 0); +#endif + + if(sendEvent == 1 && count > 0) { + *data++ = temp; + count--; + numEventReceived++; + } + } + } + return numEventReceived; + } + + for (int i = 0; i < NumSensors; i++) { + int update = 0; + + // handle step detector when ped_q is enabled + if(mPedUpdate) { + if (i == StepDetector) { + update = readDmpPedometerEvents(data, count, ID_P, 1); + mPedUpdate = 0; + if(update == 1 && count > 0) { + data->timestamp = mStepSensorTimestamp; + count--; + numEventReceived++; + continue; + } + } else { + if (mPedUpdate == DATA_FORMAT_STEP) { + continue; + } + } + } + + // load up virtual sensors + if (mEnabled & (1 << i)) { + update = CALL_MEMBER_FN(this, mHandlers[i])(mPendingEvents + i); + mPendingMask |= (1 << i); + + if (update && (count > 0)) { + *data++ = mPendingEvents[i]; + count--; + numEventReceived++; + } + } + } + + return numEventReceived; +} + +// collect data for MPL (but NOT sensor service currently), from driver layer +void MPLSensor::buildMpuEvent(void) +{ + VHANDLER_LOG; + + mSkipReadEvents = 0; + int64_t mGyroSensorTimestamp=0, mAccelSensorTimestamp=0, latestTimestamp=0; + int lp_quaternion_on = 0, sixAxis_quaternion_on = 0, + ped_quaternion_on = 0, ped_standalone_on = 0; + size_t nbyte; + unsigned short data_format = 0; + int i, nb, mask = 0, + sensors = ((mLocalSensorMask & INV_THREE_AXIS_GYRO)? 1 : 0) + + ((mLocalSensorMask & INV_THREE_AXIS_ACCEL)? 1 : 0) + + (((mLocalSensorMask & INV_THREE_AXIS_COMPASS) + && mCompassSensor->isIntegrated())? 1 : 0) + + ((mLocalSensorMask & INV_ONE_AXIS_PRESSURE)? 1 : 0); + //LOGV("mLocalSensorMask=0x%lx", mLocalSensorMask); + char *rdata = mIIOBuffer; + ssize_t rsize = 0; + ssize_t readCounter = 0; + char *rdataP = NULL; + bool doneFlag = 0; + + if (isLowPowerQuatEnabled()) { + lp_quaternion_on = checkLPQuaternion(); + } + sixAxis_quaternion_on = check6AxisQuatEnabled(); + ped_quaternion_on = checkPedQuatEnabled(); + ped_standalone_on = checkPedStandaloneEnabled(); + + nbyte = MAX_READ_SIZE - mLeftOverBufferSize; + + /* check previous copied buffer */ + /* append with just read data */ + if (mLeftOverBufferSize > 0) { + LOGV_IF(0, "append old buffer size=%d", mLeftOverBufferSize); + memset(rdata, 0, sizeof(rdata)); + memcpy(rdata, mLeftOverBuffer, mLeftOverBufferSize); + LOGV_IF(0, + "HAL:input retrieve old buffer data=:%d, %d, %d, %d,%d, %d, %d, %d,%d, %d, " + "%d, %d,%d, %d, %d, %d\n", + rdata[0], rdata[1], rdata[2], rdata[3], + rdata[4], rdata[5], rdata[6], rdata[7], + rdata[8], rdata[9], rdata[10], rdata[11], + rdata[12], rdata[13], rdata[14], rdata[15]); + } + rdataP = rdata + mLeftOverBufferSize; + + /* read expected number of bytes */ + rsize = read(iio_fd, rdataP, nbyte); + if(rsize < 0) { + /* IIO buffer might have old data. + Need to flush it if no sensor is on, to avoid infinite + read loop.*/ + LOGE("HAL:input data file descriptor not available - (%s)", + strerror(errno)); + if (sensors == 0) { + rsize = read(iio_fd, rdata, MAX_SUSPEND_BATCH_PACKET_SIZE); + if(rsize > 0) { + LOGV_IF(ENG_VERBOSE, "HAL:input data flush rsize=%d", (int)rsize); +#ifdef TESTING + LOGV_IF(INPUT_DATA, + "HAL:input rdata:r=%d, n=%d," + "%d, %d, %d, %d, %d, %d, %d, %d", + (int)rsize, nbyte, + rdataP[0], rdataP[1], rdataP[2], rdataP[3], + rdataP[4], rdataP[5], rdataP[6], rdataP[7]); +#endif + mLeftOverBufferSize = 0; + } + } + return; + } + +#ifdef TESTING +LOGV_IF(INPUT_DATA, + "HAL:input just read rdataP:r=%d, n=%d," + "%d, %d, %d, %d,%d, %d, %d, %d,%d, %d, %d, %d,%d, %d, %d, %d," + "%d, %d, %d, %d,%d, %d, %d, %d\n", + (int)rsize, nbyte, + rdataP[0], rdataP[1], rdataP[2], rdataP[3], + rdataP[4], rdataP[5], rdataP[6], rdataP[7], + rdataP[8], rdataP[9], rdataP[10], rdataP[11], + rdataP[12], rdataP[13], rdataP[14], rdataP[15], + rdataP[16], rdataP[17], rdataP[18], rdataP[19], + rdataP[20], rdataP[21], rdataP[22], rdataP[23]); + + LOGV_IF(INPUT_DATA, + "HAL:input rdata:r=%d, n=%d," + "%d, %d, %d, %d,%d, %d, %d, %d,%d, %d, %d, %d,%d, %d, %d, %d," + "%d, %d, %d, %d,%d, %d, %d, %d\n", + (int)rsize, nbyte, + rdata[0], rdata[1], rdata[2], rdata[3], + rdata[4], rdata[5], rdata[6], rdata[7], + rdata[8], rdata[9], rdata[10], rdata[11], + rdata[12], rdata[13], rdata[14], rdata[15], + rdata[16], rdata[17], rdata[18], rdata[19], + rdata[20], rdata[21], rdata[22], rdata[23]); +#endif + + if(rsize + mLeftOverBufferSize < MAX_READ_SIZE) { + /* store packet then return */ + mLeftOverBufferSize += rsize; + memcpy(mLeftOverBuffer, rdata, mLeftOverBufferSize); + +#ifdef TESTING + LOGV_IF(1, "HAL:input data has batched partial packet"); + LOGV_IF(1, "HAL:input data batched mLeftOverBufferSize=%d", mLeftOverBufferSize); + LOGV_IF(1, + "HAL:input catch up batched retrieve buffer=:%d, %d, %d, %d, %d, %d, %d, %d," + "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + mLeftOverBuffer[0], mLeftOverBuffer[1], mLeftOverBuffer[2], mLeftOverBuffer[3], + mLeftOverBuffer[4], mLeftOverBuffer[5], mLeftOverBuffer[6], mLeftOverBuffer[7], + mLeftOverBuffer[8], mLeftOverBuffer[9], mLeftOverBuffer[10], mLeftOverBuffer[11], + mLeftOverBuffer[12], mLeftOverBuffer[13], mLeftOverBuffer[14], mLeftOverBuffer[15]); +#endif + mSkipReadEvents = 1; + return; + } + + /* reset data and count pointer */ + rdataP = rdata; + readCounter = rsize + mLeftOverBufferSize; + LOGV_IF(0, "HAL:input readCounter set=%d", (int)readCounter); + + LOGV_IF(INPUT_DATA && ENG_VERBOSE, + "HAL:input b=%d rdata= %d nbyte= %d rsize= %d readCounter= %d", + checkBatchEnabled(), *((short *) rdata), nbyte, (int)rsize, (int)readCounter); + LOGV_IF(INPUT_DATA && ENG_VERBOSE, + "HAL:input sensors= %d, lp_q_on= %d, 6axis_q_on= %d, " + "ped_q_on= %d, ped_standalone_on= %d", + sensors, lp_quaternion_on, sixAxis_quaternion_on, ped_quaternion_on, + ped_standalone_on); + + while (readCounter > 0) { + // since copied buffer is already accounted for, reset left over size + mLeftOverBufferSize = 0; + // clear data format mask for parsing the next set of data + mask = 0; + data_format = *((short *)(rdata)); + LOGV_IF(INPUT_DATA && ENG_VERBOSE, + "HAL:input data_format=%x", data_format); + + if(checkValidHeader(data_format) == 0) { + LOGE("HAL:input invalid data_format 0x%02X", data_format); + return; + } + + if (data_format & DATA_FORMAT_STEP) { + if (data_format == DATA_FORMAT_STEP) { + rdata += BYTES_PER_SENSOR; + latestTimestamp = *((long long*) (rdata)); + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "STEP DETECTED:0x%x - ts: %lld", data_format, latestTimestamp); + // readCounter is decrement by 24 because DATA_FORMAT_STEP only applies in batch mode + readCounter -= BYTES_PER_SENSOR_PACKET; + } else { + LOGV_IF(0, "STEP DETECTED:0x%x", data_format); + } + mPedUpdate |= data_format; + mask |= DATA_FORMAT_STEP; + // cancels step bit + data_format &= (~DATA_FORMAT_STEP); + } + + if (data_format & DATA_FORMAT_MARKER) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "MARKER DETECTED:0x%x", data_format); + readCounter -= BYTES_PER_SENSOR; + if (mFlushSensorEnabled != -1) { + mFlushBatchSet = 1; + } + mDataMarkerDetected = 1; + mSkipReadEvents = 1; + } + else if (data_format & DATA_FORMAT_EMPTY_MARKER) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "EMPTY MARKER DETECTED:0x%x", data_format); + readCounter -= BYTES_PER_SENSOR; + if (mFlushSensorEnabled != -1) { + mFlushBatchSet = 1; + } + mEmptyDataMarkerDetected = 1; + mSkipReadEvents = 1; + } + else if (data_format == DATA_FORMAT_QUAT) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "QUAT DETECTED:0x%x", data_format); + if (readCounter >= BYTES_QUAT_DATA) { + mCachedQuaternionData[0] = *((int *) (rdata + 4)); + mCachedQuaternionData[1] = *((int *) (rdata + 8)); + mCachedQuaternionData[2] = *((int *) (rdata + 12)); + rdata += QUAT_ONLY_LAST_PACKET_OFFSET; + mQuatSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_QUAT; + readCounter -= BYTES_QUAT_DATA; + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_6_AXIS) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "6AXIS DETECTED:0x%x", data_format); + if (readCounter >= BYTES_QUAT_DATA) { + mCached6AxisQuaternionData[0] = *((int *) (rdata + 4)); + mCached6AxisQuaternionData[1] = *((int *) (rdata + 8)); + mCached6AxisQuaternionData[2] = *((int *) (rdata + 12)); + rdata += QUAT_ONLY_LAST_PACKET_OFFSET; + mQuatSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_6_AXIS; + readCounter -= BYTES_QUAT_DATA; + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_PED_QUAT) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "PED QUAT DETECTED:0x%x", data_format); + if (readCounter >= BYTES_PER_SENSOR_PACKET) { + mCachedPedQuaternionData[0] = *((short *) (rdata + 2)); + mCachedPedQuaternionData[1] = *((short *) (rdata + 4)); + mCachedPedQuaternionData[2] = *((short *) (rdata + 6)); + rdata += BYTES_PER_SENSOR; + mQuatSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_PED_QUAT; + readCounter -= BYTES_PER_SENSOR_PACKET; + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_PED_STANDALONE) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "STANDALONE STEP DETECTED:0x%x", data_format); + if (readCounter >= BYTES_PER_SENSOR_PACKET) { + rdata += BYTES_PER_SENSOR; + mStepSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_PED_STANDALONE; + readCounter -= BYTES_PER_SENSOR_PACKET; + mPedUpdate |= data_format; + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_GYRO) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "GYRO DETECTED:0x%x", data_format); + if (readCounter >= BYTES_PER_SENSOR_PACKET) { + mCachedGyroData[0] = *((short *) (rdata + 2)); + mCachedGyroData[1] = *((short *) (rdata + 4)); + mCachedGyroData[2] = *((short *) (rdata + 6)); + rdata += BYTES_PER_SENSOR; + mGyroSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_GYRO; + readCounter -= BYTES_PER_SENSOR_PACKET; + } else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_ACCEL) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "ACCEL DETECTED:0x%x", data_format); + if (readCounter >= BYTES_PER_SENSOR_PACKET) { + mCachedAccelData[0] = *((short *) (rdata + 2)); + mCachedAccelData[1] = *((short *) (rdata + 4)); + mCachedAccelData[2] = *((short *) (rdata + 6)); + rdata += BYTES_PER_SENSOR; + mAccelSensorTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_ACCEL; + readCounter -= BYTES_PER_SENSOR_PACKET; + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_COMPASS) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "COMPASS DETECTED:0x%x", data_format); + if (readCounter >= BYTES_PER_SENSOR_PACKET) { + if (mCompassSensor->isIntegrated()) { + mCachedCompassData[0] = *((short *) (rdata + 2)); + mCachedCompassData[1] = *((short *) (rdata + 4)); + mCachedCompassData[2] = *((short *) (rdata + 6)); + rdata += BYTES_PER_SENSOR; + mCompassTimestamp = *((long long*) (rdata)); + mask |= DATA_FORMAT_COMPASS; + readCounter -= BYTES_PER_SENSOR_PACKET; + } + } + else { + doneFlag = 1; + } + } + else if (data_format == DATA_FORMAT_PRESSURE) { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "PRESSURE DETECTED:0x%x", data_format); + if (readCounter >= BYTES_QUAT_DATA) { + if (mPressureSensor->isIntegrated()) { + mCachedPressureData = + ((*((short *)(rdata + 4))) << 16) + + (*((unsigned short *) (rdata + 6))); + rdata += BYTES_PER_SENSOR; + mPressureTimestamp = *((long long*) (rdata)); + if (mCachedPressureData != 0) { + mask |= DATA_FORMAT_PRESSURE; + } + readCounter -= BYTES_PER_SENSOR_PACKET; + } + } else{ + doneFlag = 1; + } + } + + if(doneFlag == 0) { + rdata += BYTES_PER_SENSOR; + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "HAL: input data doneFlag is zero, readCounter=%d", (int)readCounter); + } + else { + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "HAL: input data doneFlag is set, readCounter=%d", (int)readCounter); + } + + /* read ahead and store left over data if any */ + if (readCounter != 0) { + int currentBufferCounter = 0; + LOGV_IF(0, "Not enough data readCounter=%d, expected nbyte=%d, rsize=%d", (int)readCounter, nbyte, (int)rsize); + memset(mLeftOverBuffer, 0, sizeof(mLeftOverBuffer)); + memcpy(mLeftOverBuffer, rdata, readCounter); + LOGV_IF(0, + "HAL:input store rdata=:%d, %d, %d, %d,%d, %d, %d, %d,%d, " + "%d, %d, %d,%d, %d, %d, %d\n", + mLeftOverBuffer[0], mLeftOverBuffer[1], mLeftOverBuffer[2], mLeftOverBuffer[3], + mLeftOverBuffer[4], mLeftOverBuffer[5], mLeftOverBuffer[6], mLeftOverBuffer[7], + mLeftOverBuffer[8], mLeftOverBuffer[9], mLeftOverBuffer[10], mLeftOverBuffer[11], + mLeftOverBuffer[12],mLeftOverBuffer[13],mLeftOverBuffer[14], mLeftOverBuffer[15]); + + mLeftOverBufferSize = readCounter; + readCounter = 0; + LOGV_IF(0, "Stored number of bytes:%d", mLeftOverBufferSize); + } else { + /* reset count since this is the last packet for the data set */ + readCounter = 0; + mLeftOverBufferSize = 0; + } + + /* handle data read */ + if (mask & DATA_FORMAT_GYRO) { + /* batch mode does not batch temperature */ + /* disable temperature read */ + if (!(mFeatureActiveMask & INV_DMP_BATCH_MODE)) { + // send down temperature every 0.5 seconds + // with timestamp measured in "driver" layer + if(mGyroSensorTimestamp - mTempCurrentTime >= 500000000LL) { + mTempCurrentTime = mGyroSensorTimestamp; + long long temperature[2]; + if(inv_read_temperature(temperature) == 0) { + LOGV_IF(INPUT_DATA, + "HAL:input inv_read_temperature = %lld, timestamp= %lld", + temperature[0], temperature[1]); + inv_build_temp(temperature[0], temperature[1]); + } +#ifdef TESTING + long bias[3], temp, temp_slope[3]; + inv_get_mpl_gyro_bias(bias, &temp); + inv_get_gyro_ts(temp_slope); + LOGI("T: %.3f " + "GB: %+13f %+13f %+13f " + "TS: %+13f %+13f %+13f " + "\n", + (float)temperature[0] / 65536.f, + (float)bias[0] / 65536.f / 16.384f, + (float)bias[1] / 65536.f / 16.384f, + (float)bias[2] / 65536.f / 16.384f, + temp_slope[0] / 65536.f, + temp_slope[1] / 65536.f, + temp_slope[2] / 65536.f); +#endif + } + } + mPendingMask |= 1 << Gyro; + mPendingMask |= 1 << RawGyro; + + inv_build_gyro(mCachedGyroData, mGyroSensorTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_gyro: %+8d %+8d %+8d - %lld", + mCachedGyroData[0], mCachedGyroData[1], + mCachedGyroData[2], mGyroSensorTimestamp); + latestTimestamp = mGyroSensorTimestamp; + } + + if (mask & DATA_FORMAT_ACCEL) { + mPendingMask |= 1 << Accelerometer; + inv_build_accel(mCachedAccelData, 0, mAccelSensorTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_accel: %+8ld %+8ld %+8ld - %lld", + mCachedAccelData[0], mCachedAccelData[1], + mCachedAccelData[2], mAccelSensorTimestamp); + /* remember inital 6 axis quaternion */ + inv_time_t tempTimestamp; + inv_get_6axis_quaternion(mInitial6QuatValue, &tempTimestamp); + if (mInitial6QuatValue[0] != 0 && mInitial6QuatValue[1] != 0 && + mInitial6QuatValue[2] != 0 && mInitial6QuatValue[3] != 0) { + mInitial6QuatValueAvailable = 1; + LOGV_IF(INPUT_DATA && ENG_VERBOSE, + "HAL:input build 6q init: %+8ld %+8ld %+8ld %+8ld", + mInitial6QuatValue[0], mInitial6QuatValue[1], + mInitial6QuatValue[2], mInitial6QuatValue[3]); + } + latestTimestamp = mAccelSensorTimestamp; + } + + if ((mask & DATA_FORMAT_COMPASS) && mCompassSensor->isIntegrated()) { + int status = 0; + if (mCompassSensor->providesCalibration()) { + status = mCompassSensor->getAccuracy(); + status |= INV_CALIBRATED; + } + inv_build_compass(mCachedCompassData, status, + mCompassTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_compass: %+8ld %+8ld %+8ld - %lld", + mCachedCompassData[0], mCachedCompassData[1], + mCachedCompassData[2], mCompassTimestamp); + latestTimestamp = mCompassTimestamp; + } + + if (mask & DATA_FORMAT_QUAT) { + /* if bias was applied to DMP bias, + set status bits to disable gyro bias cal */ + int status = 0; + if (mGyroBiasApplied == true) { + LOGV_IF(INPUT_DATA && ENG_VERBOSE, "HAL:input dmp bias is used"); + status |= INV_BIAS_APPLIED; + } + status |= INV_CALIBRATED | INV_QUAT_3AXIS | INV_QUAT_3ELEMENT; /* default 32 (16/32bits) */ + inv_build_quat(mCachedQuaternionData, + status, + mQuatSensorTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_quat-3x: %+8ld %+8ld %+8ld - %lld", + mCachedQuaternionData[0], mCachedQuaternionData[1], + mCachedQuaternionData[2], + mQuatSensorTimestamp); + latestTimestamp = mQuatSensorTimestamp; + } + + if (mask & DATA_FORMAT_6_AXIS) { + /* if bias was applied to DMP bias, + set status bits to disable gyro bias cal */ + int status = 0; + if (mGyroBiasApplied == true) { + LOGV_IF(INPUT_DATA && ENG_VERBOSE, "HAL:input dmp bias is used"); + status |= INV_QUAT_6AXIS; + } + status |= INV_CALIBRATED | INV_QUAT_6AXIS | INV_QUAT_3ELEMENT; /* default 32 (16/32bits) */ + inv_build_quat(mCached6AxisQuaternionData, + status, + mQuatSensorTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_quat-6x: %+8ld %+8ld %+8ld - %lld", + mCached6AxisQuaternionData[0], mCached6AxisQuaternionData[1], + mCached6AxisQuaternionData[2], mQuatSensorTimestamp); + latestTimestamp = mQuatSensorTimestamp; + } + + if (mask & DATA_FORMAT_PED_QUAT) { + /* if bias was applied to DMP bias, + set status bits to disable gyro bias cal */ + int status = 0; + if (mGyroBiasApplied == true) { + LOGV_IF(INPUT_DATA && ENG_VERBOSE, + "HAL:input dmp bias is used"); + status |= INV_QUAT_6AXIS; + } + status |= INV_CALIBRATED | INV_QUAT_6AXIS | INV_QUAT_3ELEMENT; /* default 32 (16/32bits) */ + mCachedPedQuaternionData[0] = mCachedPedQuaternionData[0] << 16; + mCachedPedQuaternionData[1] = mCachedPedQuaternionData[1] << 16; + mCachedPedQuaternionData[2] = mCachedPedQuaternionData[2] << 16; + inv_build_quat(mCachedPedQuaternionData, + status, + mQuatSensorTimestamp); + + LOGV_IF(INPUT_DATA, + "HAL:HAL:input inv_build_quat-ped_6x: %+8ld %+8ld %+8ld - %lld", + mCachedPedQuaternionData[0], mCachedPedQuaternionData[1], + mCachedPedQuaternionData[2], mQuatSensorTimestamp); + latestTimestamp = mQuatSensorTimestamp; + } + + if ((mask & DATA_FORMAT_PRESSURE) && mPressureSensor->isIntegrated()) { + int status = 0; + if (mLocalSensorMask & INV_ONE_AXIS_PRESSURE) { + latestTimestamp = mPressureTimestamp; + mPressureUpdate = 1; + inv_build_pressure(mCachedPressureData, + status, + mPressureTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_pressure: %+8ld - %lld", + mCachedPressureData, mPressureTimestamp); + } + } + + /* take the latest timestamp */ + if (mask & DATA_FORMAT_STEP) { + /* work around driver output duplicate step detector bit */ + if (latestTimestamp > mStepSensorTimestamp) { + mStepSensorTimestamp = latestTimestamp; + LOGV_IF(INPUT_DATA, + "HAL:input build step: 1 - %lld", mStepSensorTimestamp); + } else { + mPedUpdate = 0; + } + } + } //while end +} + +int MPLSensor::checkValidHeader(unsigned short data_format) +{ + if(data_format & DATA_FORMAT_STEP) { + data_format &= (~DATA_FORMAT_STEP); + } + + LOGV_IF(ENG_VERBOSE && INPUT_DATA, "check data_format=%x", data_format); + + if ((data_format == DATA_FORMAT_PED_STANDALONE) || + (data_format == DATA_FORMAT_PED_QUAT) || + (data_format == DATA_FORMAT_6_AXIS) || + (data_format == DATA_FORMAT_QUAT) || + (data_format == DATA_FORMAT_COMPASS) || + (data_format == DATA_FORMAT_GYRO) || + (data_format == DATA_FORMAT_ACCEL) || + (data_format == DATA_FORMAT_PRESSURE) || + (data_format == DATA_FORMAT_EMPTY_MARKER) || + (data_format == DATA_FORMAT_MARKER)) + return 1; + else { + LOGV_IF(ENG_VERBOSE, "bad data_format = %x", data_format); + return 0; + } +} + +/* use for both MPUxxxx and third party compass */ +void MPLSensor::buildCompassEvent(void) +{ + VHANDLER_LOG; + + int done = 0; + + // pthread_mutex_lock(&mMplMutex); + // pthread_mutex_lock(&mHALMutex); + + done = mCompassSensor->readSample(mCachedCompassData, &mCompassTimestamp); + if(mCompassSensor->isYasCompass()) { + if (mCompassSensor->checkCoilsReset() == 1) { + //Reset relevant compass settings + resetCompass(); + } + } + if (done > 0) { + int status = 0; + if (mCompassSensor->providesCalibration()) { + status = mCompassSensor->getAccuracy(); + status |= INV_CALIBRATED; + } + if (mLocalSensorMask & INV_THREE_AXIS_COMPASS) { + inv_build_compass(mCachedCompassData, status, + mCompassTimestamp); + LOGV_IF(INPUT_DATA, + "HAL:input inv_build_compass: %+8ld %+8ld %+8ld - %lld", + mCachedCompassData[0], mCachedCompassData[1], + mCachedCompassData[2], mCompassTimestamp); + } + } + + // pthread_mutex_unlock(&mMplMutex); + // pthread_mutex_unlock(&mHALMutex); +} + +int MPLSensor::resetCompass(void) +{ + VFUNC_LOG; + + //Reset compass cal if enabled + if (mMplFeatureActiveMask & INV_COMPASS_CAL) { + LOGV_IF(EXTRA_VERBOSE, "HAL:Reset compass cal"); + inv_init_vector_compass_cal(); + } + + //Reset compass fit if enabled + if (mMplFeatureActiveMask & INV_COMPASS_FIT) { + LOGV_IF(EXTRA_VERBOSE, "HAL:Reset compass fit"); + inv_init_compass_fit(); + } + + return 0; +} + +int MPLSensor::getFd(void) const +{ + VFUNC_LOG; + LOGV_IF(EXTRA_VERBOSE, "getFd returning %d", iio_fd); + return iio_fd; +} + +int MPLSensor::getAccelFd(void) const +{ + VFUNC_LOG; + LOGV_IF(EXTRA_VERBOSE, "getAccelFd returning %d", accel_fd); + return accel_fd; +} + +int MPLSensor::getCompassFd(void) const +{ + VFUNC_LOG; + int fd = mCompassSensor->getFd(); + LOGV_IF(EXTRA_VERBOSE, "getCompassFd returning %d", fd); + return fd; +} + +int MPLSensor::turnOffAccelFifo(void) +{ + VFUNC_LOG; + int i, res = 0, tempFd; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.accel_fifo_enable, getTimestamp()); + res += write_sysfs_int(mpu.accel_fifo_enable, 0); + return res; +} + +int MPLSensor::turnOffGyroFifo(void) +{ + VFUNC_LOG; + int i, res = 0, tempFd; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.gyro_fifo_enable, getTimestamp()); + res += write_sysfs_int(mpu.gyro_fifo_enable, 0); + return res; +} + +int MPLSensor::enableDmpOrientation(int en) +{ + VFUNC_LOG; + int res = 0; + int enabled_sensors = mEnabled; + + if (isMpuNonDmp()) + return res; + + // reset master enable + res = masterEnable(0); + if (res < 0) + return res; + + if (en == 1) { + // Enable DMP orientation + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.display_orientation_on, getTimestamp()); + if (write_sysfs_int(mpu.display_orientation_on, en) < 0) { + LOGE("HAL:ERR can't enable Android orientation"); + res = -1; // indicate an err + return res; + } + + // enable accel engine + res = enableAccel(1); + if (res < 0) + return res; + + // disable accel FIFO + if (!(mLocalSensorMask & mMasterSensorMask & INV_THREE_AXIS_ACCEL)) { + res = turnOffAccelFifo(); + if (res < 0) + return res; + } + + if (!mEnabled){ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, en) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + } + + mFeatureActiveMask |= INV_DMP_DISPL_ORIENTATION; + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + } else { + mFeatureActiveMask &= ~INV_DMP_DISPL_ORIENTATION; + + if (mFeatureActiveMask == 0) { + // disable accel engine + if (!(mLocalSensorMask & mMasterSensorMask + & INV_THREE_AXIS_ACCEL)) { + res = enableAccel(0); + if (res < 0) + return res; + } + } + + if (mEnabled){ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + en, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, en) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + } + LOGV_IF(ENG_VERBOSE, "mFeatureActiveMask=%016llx", mFeatureActiveMask); + } + + if ((res = computeAndSetDmpState()) < 0) + return res; + + if (en || mEnabled || mFeatureActiveMask) { + res = masterEnable(1); + } + return res; +} + +int MPLSensor::openDmpOrientFd(void) +{ + VFUNC_LOG; + + if (!isDmpDisplayOrientationOn() || dmp_orient_fd >= 0) { + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP display orientation disabled or file desc opened"); + return 0; + } + + dmp_orient_fd = open(mpu.event_display_orientation, O_RDONLY| O_NONBLOCK); + if (dmp_orient_fd < 0) { + LOGE("HAL:ERR couldn't open dmpOrient node"); + return -1; + } else { + LOGV_IF(PROCESS_VERBOSE, + "HAL:dmp_orient_fd opened : %d", dmp_orient_fd); + return 0; + } +} + +int MPLSensor::closeDmpOrientFd(void) +{ + VFUNC_LOG; + if (dmp_orient_fd >= 0) + close(dmp_orient_fd); + return 0; +} + +int MPLSensor::dmpOrientHandler(int orient) +{ + VFUNC_LOG; + LOGV_IF(PROCESS_VERBOSE, "HAL:orient %x", orient); + return 0; +} + +int MPLSensor::readDmpOrientEvents(sensors_event_t* data, int count) +{ + VFUNC_LOG; + + char dummy[4]; + int screen_orientation = 0; + FILE *fp; + + fp = fopen(mpu.event_display_orientation, "r"); + if (fp == NULL) { + LOGE("HAL:cannot open event_display_orientation"); + return 0; + } else { + if (fscanf(fp, "%d\n", &screen_orientation) < 0 || fclose(fp) < 0) + { + LOGE("HAL:cannot write event_display_orientation"); + } + } + + int numEventReceived = 0; + + if (mDmpOrientationEnabled && count > 0) { + sensors_event_t temp; + + temp.acceleration.x = 0; + temp.acceleration.y = 0; + temp.acceleration.z = 0; + temp.version = sizeof(sensors_event_t); + temp.sensor = ID_SO; + temp.acceleration.status + = SENSOR_STATUS_UNRELIABLE; +#ifdef ENABLE_DMP_SCREEN_AUTO_ROTATION + temp.type = SENSOR_TYPE_SCREEN_ORIENTATION; + temp.screen_orientation = screen_orientation; +#endif + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + temp.timestamp = (int64_t) ts.tv_sec * 1000000000 + ts.tv_nsec; + + *data++ = temp; + count--; + numEventReceived++; + } + + // read dummy data per driver's request + dmpOrientHandler(screen_orientation); + read(dmp_orient_fd, dummy, 4); + + return numEventReceived; +} + +int MPLSensor::getDmpOrientFd(void) +{ + VFUNC_LOG; + + LOGV_IF(EXTRA_VERBOSE, "getDmpOrientFd returning %d", dmp_orient_fd); + return dmp_orient_fd; + +} + +int MPLSensor::checkDMPOrientation(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_DISPL_ORIENTATION) ? 1 : 0); +} + +int MPLSensor::getDmpRate(int64_t *wanted) +{ + VFUNC_LOG; + + // set DMP output rate to FIFO + if(mDmpOn == 1) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / *wanted), mpu.three_axis_q_rate, + getTimestamp()); + write_sysfs_int(mpu.three_axis_q_rate, 1000000000.f / *wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP three axis rate %.2f Hz", 1000000000.f / *wanted); + if (mFeatureActiveMask & INV_DMP_BATCH_MODE) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / *wanted), mpu.six_axis_q_rate, + getTimestamp()); + write_sysfs_int(mpu.six_axis_q_rate, 1000000000.f / *wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP six axis rate %.2f Hz", 1000000000.f / *wanted); + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / *wanted), mpu.ped_q_rate, + getTimestamp()); + write_sysfs_int(mpu.ped_q_rate, 1000000000.f / *wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP ped quaternion rate %.2f Hz", 1000000000.f / *wanted); + } + // DMP running rate must be @ 200Hz + *wanted= RATE_200HZ; + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP rate= %.2f Hz", 1000000000.f / *wanted); + } + return 0; +} + +int MPLSensor::getPollTime(void) +{ + VFUNC_LOG; + return mPollTime; +} + +int MPLSensor::getStepCountPollTime(void) +{ + VFUNC_LOG; + /* clamped to 1ms? as spec, still rather large */ + return 1000; +} + +bool MPLSensor::hasStepCountPendingEvents(void) +{ + VFUNC_LOG; + if (mDmpStepCountEnabled) { + struct timespec t_now; + int64_t interval = 0; + + clock_gettime(CLOCK_MONOTONIC, &t_now); + interval = ((int64_t(t_now.tv_sec) * 1000000000LL + t_now.tv_nsec) - + (int64_t(mt_pre.tv_sec) * 1000000000LL + mt_pre.tv_nsec)); + + if (interval < mStepCountPollTime) { + LOGV_IF(0, + "Step Count interval elapsed: %lld, triggered: %lld", + interval, mStepCountPollTime); + return false; + } else { + clock_gettime(CLOCK_MONOTONIC, &mt_pre); + LOGV_IF(0, "Step Count previous time: %ld ms", + mt_pre.tv_nsec / 1000); + return true; + } + } + return false; +} + +bool MPLSensor::hasPendingEvents(void) const +{ + VFUNC_LOG; + // if we are using the polling workaround, force the main + // loop to check for data every time + return (mPollTime != -1); +} + +int MPLSensor::inv_read_temperature(long long *data) +{ + VHANDLER_LOG; + + int count = 0; + char raw_buf[40]; + long raw = 0; + + long long timestamp = 0; + + memset(raw_buf, 0, sizeof(raw_buf)); + count = read_attribute_sensor(gyro_temperature_fd, raw_buf, + sizeof(raw_buf)); + if(count < 1) { + LOGE("HAL:error reading gyro temperature"); + return -1; + } + + count = sscanf(raw_buf, "%ld%lld", &raw, ×tamp); + + if(count < 0) { + return -1; + } + + LOGV_IF(ENG_VERBOSE && INPUT_DATA, + "HAL:temperature raw = %ld, timestamp = %lld, count = %d", + raw, timestamp, count); + data[0] = raw; + data[1] = timestamp; + + return 0; +} + +int MPLSensor::inv_read_dmp_state(int fd) +{ + VFUNC_LOG; + + if(fd < 0) + return -1; + + int count = 0; + char raw_buf[10]; + short raw = 0; + + memset(raw_buf, 0, sizeof(raw_buf)); + count = read_attribute_sensor(fd, raw_buf, sizeof(raw_buf)); + if(count < 1) { + LOGE("HAL:error reading dmp state"); + close(fd); + return -1; + } + count = sscanf(raw_buf, "%hd", &raw); + if(count < 0) { + LOGE("HAL:dmp state data is invalid"); + close(fd); + return -1; + } + LOGV_IF(EXTRA_VERBOSE, "HAL:dmp state = %d, count = %d", raw, count); + close(fd); + return (int)raw; +} + +int MPLSensor::inv_read_sensor_bias(int fd, long *data) +{ + VFUNC_LOG; + + if(fd == -1) { + return -1; + } + + char buf[50]; + char x[15], y[15], z[15]; + + memset(buf, 0, sizeof(buf)); + int count = read_attribute_sensor(fd, buf, sizeof(buf)); + if(count < 1) { + LOGE("HAL:Error reading gyro bias"); + return -1; + } + count = sscanf(buf, "%[^','],%[^','],%[^',']", x, y, z); + if(count) { + /* scale appropriately for MPL */ + LOGV_IF(ENG_VERBOSE, + "HAL:pre-scaled bias: X:Y:Z (%ld, %ld, %ld)", + atol(x), atol(y), atol(z)); + + data[0] = (long)(atol(x) / 10000 * (1L << 16)); + data[1] = (long)(atol(y) / 10000 * (1L << 16)); + data[2] = (long)(atol(z) / 10000 * (1L << 16)); + + LOGV_IF(ENG_VERBOSE, + "HAL:scaled bias: X:Y:Z (%ld, %ld, %ld)", + data[0], data[1], data[2]); + } + return 0; +} + +/** fill in the sensor list based on which sensors are configured. + * return the number of configured sensors. + * parameter list must point to a memory region of at least 7*sizeof(sensor_t) + * parameter len gives the length of the buffer pointed to by list + */ +int MPLSensor::populateSensorList(struct sensor_t *list, int len) +{ + VFUNC_LOG; + + int numsensors; + + if(len < + (int)((sizeof(sBaseSensorList) / sizeof(sensor_t)) * sizeof(sensor_t))) { + LOGE("HAL:sensor list too small, not populating."); + return -(sizeof(sBaseSensorList) / sizeof(sensor_t)); + } + + /* fill in the base values */ + memcpy(list, sBaseSensorList, + sizeof (struct sensor_t) * (sizeof(sBaseSensorList) / sizeof(sensor_t))); + + /* first add gyro, accel and compass to the list */ + + /* fill in gyro/accel values */ + if(chip_ID == NULL) { + LOGE("HAL:Can not get gyro/accel id"); + } + fillGyro(chip_ID, list); + fillAccel(chip_ID, list); + + // TODO: need fixes for unified HAL and 3rd-party solution + mCompassSensor->fillList(&list[MagneticField]); + mCompassSensor->fillList(&list[RawMagneticField]); + + if (mPressureSensor != NULL) { + mPressureSensor->fillList(&list[Pressure]); + } + + if(1) { + numsensors = (sizeof(sBaseSensorList) / sizeof(sensor_t)); + /* all sensors will be added to the list + fill in orientation values */ + fillOrientation(list); + /* fill in rotation vector values */ + fillRV(list); + /* fill in game rotation vector values */ + fillGRV(list); + /* fill in gravity values */ + fillGravity(list); + /* fill in Linear accel values */ + fillLinearAccel(list); + /* fill in Significant motion values */ + fillSignificantMotion(list); +#ifdef ENABLE_DMP_SCREEN_AUTO_ROTATION + /* fill in screen orientation values */ + fillScreenOrientation(list); +#endif + } else { + /* no 9-axis sensors, zero fill that part of the list */ + numsensors = 3; + memset(list + 3, 0, 4 * sizeof(struct sensor_t)); + } + + return numsensors; +} + +void MPLSensor::fillAccel(const char* accel, struct sensor_t *list) +{ + VFUNC_LOG; + + if (accel) { + if(accel != NULL && strcmp(accel, "BMA250") == 0) { + list[Accelerometer].maxRange = ACCEL_BMA250_RANGE; + list[Accelerometer].resolution = ACCEL_BMA250_RESOLUTION; + list[Accelerometer].power = ACCEL_BMA250_POWER; + list[Accelerometer].minDelay = ACCEL_BMA250_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU6050") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU6050_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6050_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6050_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6050_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU6500") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU6500_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6500_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6500_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6500_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU6515") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU6500_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6500_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6500_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6500_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU6500") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU6500_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6500_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6500_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6500_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU6500") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU6500_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6500_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6500_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6500_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU9150") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU9150_RANGE; + list[Accelerometer].resolution = ACCEL_MPU9150_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU9150_POWER; + list[Accelerometer].minDelay = ACCEL_MPU9150_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU9250") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU9250_RANGE; + list[Accelerometer].resolution = ACCEL_MPU9250_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU9250_POWER; + list[Accelerometer].minDelay = ACCEL_MPU9250_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU9350") == 0) { + list[Accelerometer].maxRange = ACCEL_MPU9350_RANGE; + list[Accelerometer].resolution = ACCEL_MPU9350_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU9350_POWER; + list[Accelerometer].minDelay = ACCEL_MPU9350_MINDELAY; + return; + } else if (accel != NULL && strcmp(accel, "MPU3050") == 0) { + list[Accelerometer].maxRange = ACCEL_BMA250_RANGE; + list[Accelerometer].resolution = ACCEL_BMA250_RESOLUTION; + list[Accelerometer].power = ACCEL_BMA250_POWER; + list[Accelerometer].minDelay = ACCEL_BMA250_MINDELAY; + return; + } + } + + LOGE("HAL:unknown accel id %s -- " + "params default to mpu6515 and might be wrong.", + accel); + list[Accelerometer].maxRange = ACCEL_MPU6500_RANGE; + list[Accelerometer].resolution = ACCEL_MPU6500_RESOLUTION; + list[Accelerometer].power = ACCEL_MPU6500_POWER; + list[Accelerometer].minDelay = ACCEL_MPU6500_MINDELAY; +} + +void MPLSensor::fillGyro(const char* gyro, struct sensor_t *list) +{ + VFUNC_LOG; + + if ( gyro != NULL && strcmp(gyro, "MPU3050") == 0) { + list[Gyro].maxRange = GYRO_MPU3050_RANGE; + list[Gyro].resolution = GYRO_MPU3050_RESOLUTION; + list[Gyro].power = GYRO_MPU3050_POWER; + list[Gyro].minDelay = GYRO_MPU3050_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU6050") == 0) { + list[Gyro].maxRange = GYRO_MPU6050_RANGE; + list[Gyro].resolution = GYRO_MPU6050_RESOLUTION; + list[Gyro].power = GYRO_MPU6050_POWER; + list[Gyro].minDelay = GYRO_MPU6050_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU6500") == 0) { + list[Gyro].maxRange = GYRO_MPU6500_RANGE; + list[Gyro].resolution = GYRO_MPU6500_RESOLUTION; + list[Gyro].power = GYRO_MPU6500_POWER; + list[Gyro].minDelay = GYRO_MPU6500_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU6515") == 0) { + list[Gyro].maxRange = GYRO_MPU6500_RANGE; + list[Gyro].resolution = GYRO_MPU6500_RESOLUTION; + list[Gyro].power = GYRO_MPU6500_POWER; + list[Gyro].minDelay = GYRO_MPU6500_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU9150") == 0) { + list[Gyro].maxRange = GYRO_MPU9150_RANGE; + list[Gyro].resolution = GYRO_MPU9150_RESOLUTION; + list[Gyro].power = GYRO_MPU9150_POWER; + list[Gyro].minDelay = GYRO_MPU9150_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU9250") == 0) { + list[Gyro].maxRange = GYRO_MPU9250_RANGE; + list[Gyro].resolution = GYRO_MPU9250_RESOLUTION; + list[Gyro].power = GYRO_MPU9250_POWER; + list[Gyro].minDelay = GYRO_MPU9250_MINDELAY; + } else if( gyro != NULL && strcmp(gyro, "MPU9350") == 0) { + list[Gyro].maxRange = GYRO_MPU9350_RANGE; + list[Gyro].resolution = GYRO_MPU9350_RESOLUTION; + list[Gyro].power = GYRO_MPU9350_POWER; + list[Gyro].minDelay = GYRO_MPU9350_MINDELAY; + } else { + LOGE("HAL:unknown gyro id -- gyro params will be wrong."); + LOGE("HAL:default to use mpu6515 params"); + list[Gyro].maxRange = GYRO_MPU6500_RANGE; + list[Gyro].resolution = GYRO_MPU6500_RESOLUTION; + list[Gyro].power = GYRO_MPU6500_POWER; + list[Gyro].minDelay = GYRO_MPU6500_MINDELAY; + } + + list[RawGyro].maxRange = list[Gyro].maxRange; + list[RawGyro].resolution = list[Gyro].resolution; + list[RawGyro].power = list[Gyro].power; + list[RawGyro].minDelay = list[Gyro].minDelay; + + return; +} + +/* fillRV depends on values of gyro, accel and compass in the list */ +void MPLSensor::fillRV(struct sensor_t *list) +{ + VFUNC_LOG; + + /* compute power on the fly */ + list[RotationVector].power = list[Gyro].power + + list[Accelerometer].power + + list[MagneticField].power; + list[RotationVector].resolution = .00001; + list[RotationVector].maxRange = 1.0; + list[RotationVector].minDelay = 5000; + + return; +} + +/* fillGMRV depends on values of accel and mag in the list */ +void MPLSensor::fillGMRV(struct sensor_t *list) +{ + VFUNC_LOG; + + /* compute power on the fly */ + list[GeomagneticRotationVector].power = list[Accelerometer].power + + list[MagneticField].power; + list[GeomagneticRotationVector].resolution = .00001; + list[GeomagneticRotationVector].maxRange = 1.0; + list[GeomagneticRotationVector].minDelay = 5000; + + return; +} + +/* fillGRV depends on values of gyro and accel in the list */ +void MPLSensor::fillGRV(struct sensor_t *list) +{ + VFUNC_LOG; + + /* compute power on the fly */ + list[GameRotationVector].power = list[Gyro].power + + list[Accelerometer].power; + list[GameRotationVector].resolution = .00001; + list[GameRotationVector].maxRange = 1.0; + list[GameRotationVector].minDelay = 5000; + + return; +} + +void MPLSensor::fillOrientation(struct sensor_t *list) +{ + VFUNC_LOG; + + list[Orientation].power = list[Gyro].power + + list[Accelerometer].power + + list[MagneticField].power; + list[Orientation].resolution = .00001; + list[Orientation].maxRange = 360.0; + list[Orientation].minDelay = 5000; + + return; +} + +void MPLSensor::fillGravity( struct sensor_t *list) +{ + VFUNC_LOG; + + list[Gravity].power = list[Gyro].power + + list[Accelerometer].power + + list[MagneticField].power; + list[Gravity].resolution = .00001; + list[Gravity].maxRange = 9.81; + list[Gravity].minDelay = 5000; + + return; +} + +void MPLSensor::fillLinearAccel(struct sensor_t *list) +{ + VFUNC_LOG; + + list[LinearAccel].power = list[Gyro].power + + list[Accelerometer].power + + list[MagneticField].power; + list[LinearAccel].resolution = list[Accelerometer].resolution; + list[LinearAccel].maxRange = list[Accelerometer].maxRange; + list[LinearAccel].minDelay = 5000; + + return; +} + +void MPLSensor::fillSignificantMotion(struct sensor_t *list) +{ + VFUNC_LOG; + + list[SignificantMotion].power = list[Accelerometer].power; + list[SignificantMotion].resolution = 1; + list[SignificantMotion].maxRange = 1; + list[SignificantMotion].minDelay = -1; +} + +#ifdef ENABLE_DMP_SCREEN_AUTO_ROTATION +void MPLSensor::fillScreenOrientation(struct sensor_t *list) +{ + VFUNC_LOG; + + list[NumSensors].power = list[Accelerometer].power; + list[NumSensors].resolution = 1; + list[NumSensors].maxRange = 3; + list[NumSensors].minDelay = 0; +} +#endif + +int MPLSensor::inv_init_sysfs_attributes(void) +{ + VFUNC_LOG; + + unsigned char i = 0; + char sysfs_path[MAX_SYSFS_NAME_LEN]; + char tbuf[2]; + char *sptr; + char **dptr; + int num; + + memset(sysfs_path, 0, sizeof(sysfs_path)); + + sysfs_names_ptr = + (char*)malloc(sizeof(char[MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN])); + sptr = sysfs_names_ptr; + if (sptr != NULL) { + dptr = (char**)&mpu; + do { + *dptr++ = sptr; + memset(sptr, 0, sizeof(sptr)); + sptr += sizeof(char[MAX_SYSFS_NAME_LEN]); + } while (++i < MAX_SYSFS_ATTRB); + } else { + LOGE("HAL:couldn't alloc mem for sysfs paths"); + return -1; + } + + // get proper (in absolute) IIO path & build MPU's sysfs paths + inv_get_sysfs_path(sysfs_path); + + memcpy(mSysfsPath, sysfs_path, sizeof(sysfs_path)); + sprintf(mpu.key, "%s%s", sysfs_path, "/key"); + sprintf(mpu.chip_enable, "%s%s", sysfs_path, "/buffer/enable"); + sprintf(mpu.buffer_length, "%s%s", sysfs_path, "/buffer/length"); + sprintf(mpu.master_enable, "%s%s", sysfs_path, "/master_enable"); + sprintf(mpu.power_state, "%s%s", sysfs_path, "/power_state"); + + sprintf(mpu.in_timestamp_en, "%s%s", sysfs_path, + "/scan_elements/in_timestamp_en"); + sprintf(mpu.in_timestamp_index, "%s%s", sysfs_path, + "/scan_elements/in_timestamp_index"); + sprintf(mpu.in_timestamp_type, "%s%s", sysfs_path, + "/scan_elements/in_timestamp_type"); + + sprintf(mpu.dmp_firmware, "%s%s", sysfs_path, "/dmp_firmware"); + sprintf(mpu.firmware_loaded, "%s%s", sysfs_path, "/firmware_loaded"); + sprintf(mpu.dmp_on, "%s%s", sysfs_path, "/dmp_on"); + sprintf(mpu.dmp_int_on, "%s%s", sysfs_path, "/dmp_int_on"); + sprintf(mpu.dmp_event_int_on, "%s%s", sysfs_path, "/dmp_event_int_on"); + sprintf(mpu.tap_on, "%s%s", sysfs_path, "/tap_on"); + + sprintf(mpu.self_test, "%s%s", sysfs_path, "/self_test"); + + sprintf(mpu.temperature, "%s%s", sysfs_path, "/temperature"); + sprintf(mpu.gyro_enable, "%s%s", sysfs_path, "/gyro_enable"); + sprintf(mpu.gyro_fifo_rate, "%s%s", sysfs_path, "/sampling_frequency"); + sprintf(mpu.gyro_orient, "%s%s", sysfs_path, "/gyro_matrix"); + sprintf(mpu.gyro_fifo_enable, "%s%s", sysfs_path, "/gyro_fifo_enable"); + sprintf(mpu.gyro_fsr, "%s%s", sysfs_path, "/in_anglvel_scale"); + sprintf(mpu.gyro_fifo_enable, "%s%s", sysfs_path, "/gyro_fifo_enable"); + sprintf(mpu.gyro_rate, "%s%s", sysfs_path, "/gyro_rate"); + + sprintf(mpu.accel_enable, "%s%s", sysfs_path, "/accel_enable"); + sprintf(mpu.accel_fifo_rate, "%s%s", sysfs_path, "/sampling_frequency"); + sprintf(mpu.accel_orient, "%s%s", sysfs_path, "/accel_matrix"); + sprintf(mpu.accel_fifo_enable, "%s%s", sysfs_path, "/accel_fifo_enable"); + sprintf(mpu.accel_rate, "%s%s", sysfs_path, "/accel_rate"); + +#ifndef THIRD_PARTY_ACCEL //MPU3050 + sprintf(mpu.accel_fsr, "%s%s", sysfs_path, "/in_accel_scale"); + + // DMP uses these values + sprintf(mpu.in_accel_x_dmp_bias, "%s%s", sysfs_path, "/in_accel_x_dmp_bias"); + sprintf(mpu.in_accel_y_dmp_bias, "%s%s", sysfs_path, "/in_accel_y_dmp_bias"); + sprintf(mpu.in_accel_z_dmp_bias, "%s%s", sysfs_path, "/in_accel_z_dmp_bias"); + + // MPU uses these values + sprintf(mpu.in_accel_x_offset, "%s%s", sysfs_path, "/in_accel_x_offset"); + sprintf(mpu.in_accel_y_offset, "%s%s", sysfs_path, "/in_accel_y_offset"); + sprintf(mpu.in_accel_z_offset, "%s%s", sysfs_path, "/in_accel_z_offset"); + sprintf(mpu.in_accel_self_test_scale, "%s%s", sysfs_path, "/in_accel_self_test_scale"); +#endif + + // DMP uses these bias values + sprintf(mpu.in_gyro_x_dmp_bias, "%s%s", sysfs_path, "/in_anglvel_x_dmp_bias"); + sprintf(mpu.in_gyro_y_dmp_bias, "%s%s", sysfs_path, "/in_anglvel_y_dmp_bias"); + sprintf(mpu.in_gyro_z_dmp_bias, "%s%s", sysfs_path, "/in_anglvel_z_dmp_bias"); + + // MPU uses these bias values + sprintf(mpu.in_gyro_x_offset, "%s%s", sysfs_path, "/in_anglvel_x_offset"); + sprintf(mpu.in_gyro_y_offset, "%s%s", sysfs_path, "/in_anglvel_y_offset"); + sprintf(mpu.in_gyro_z_offset, "%s%s", sysfs_path, "/in_anglvel_z_offset"); + sprintf(mpu.in_gyro_self_test_scale, "%s%s", sysfs_path, "/in_anglvel_self_test_scale"); + + sprintf(mpu.three_axis_q_on, "%s%s", sysfs_path, "/three_axes_q_on"); //formerly quaternion_on + sprintf(mpu.three_axis_q_rate, "%s%s", sysfs_path, "/three_axes_q_rate"); + + sprintf(mpu.ped_q_on, "%s%s", sysfs_path, "/ped_q_on"); + sprintf(mpu.ped_q_rate, "%s%s", sysfs_path, "/ped_q_rate"); + + sprintf(mpu.six_axis_q_on, "%s%s", sysfs_path, "/six_axes_q_on"); + sprintf(mpu.six_axis_q_rate, "%s%s", sysfs_path, "/six_axes_q_rate"); + + sprintf(mpu.six_axis_q_value, "%s%s", sysfs_path, "/six_axes_q_value"); + + sprintf(mpu.step_detector_on, "%s%s", sysfs_path, "/step_detector_on"); + sprintf(mpu.step_indicator_on, "%s%s", sysfs_path, "/step_indicator_on"); + + sprintf(mpu.display_orientation_on, "%s%s", sysfs_path, + "/display_orientation_on"); + sprintf(mpu.event_display_orientation, "%s%s", sysfs_path, + "/event_display_orientation"); + + sprintf(mpu.event_smd, "%s%s", sysfs_path, + "/event_smd"); + sprintf(mpu.smd_enable, "%s%s", sysfs_path, + "/smd_enable"); + sprintf(mpu.smd_delay_threshold, "%s%s", sysfs_path, + "/smd_delay_threshold"); + sprintf(mpu.smd_delay_threshold2, "%s%s", sysfs_path, + "/smd_delay_threshold2"); + sprintf(mpu.smd_threshold, "%s%s", sysfs_path, + "/smd_threshold"); + sprintf(mpu.batchmode_timeout, "%s%s", sysfs_path, + "/batchmode_timeout"); + sprintf(mpu.batchmode_wake_fifo_full_on, "%s%s", sysfs_path, + "/batchmode_wake_fifo_full_on"); + sprintf(mpu.flush_batch, "%s%s", sysfs_path, + "/flush_batch"); + sprintf(mpu.pedometer_on, "%s%s", sysfs_path, + "/pedometer_on"); + sprintf(mpu.pedometer_int_on, "%s%s", sysfs_path, + "/pedometer_int_on"); + sprintf(mpu.event_pedometer, "%s%s", sysfs_path, + "/event_pedometer"); + sprintf(mpu.pedometer_steps, "%s%s", sysfs_path, + "/pedometer_steps"); + sprintf(mpu.pedometer_counter, "%s%s", sysfs_path, + "/pedometer_counter"); + sprintf(mpu.motion_lpa_on, "%s%s", sysfs_path, + "/motion_lpa_on"); + return 0; +} + +//DMP support only for MPU6xxx/9xxx +bool MPLSensor::isMpuNonDmp(void) +{ + VFUNC_LOG; + if (!strcmp(chip_ID, "mpu3050") || !strcmp(chip_ID, "MPU3050")) + return true; + else + return false; +} + +int MPLSensor::isLowPowerQuatEnabled(void) +{ + VFUNC_LOG; +#ifdef ENABLE_LP_QUAT_FEAT + return !isMpuNonDmp(); +#else + return 0; +#endif +} + +int MPLSensor::isDmpDisplayOrientationOn(void) +{ + VFUNC_LOG; +#ifdef ENABLE_DMP_DISPL_ORIENT_FEAT + if (isMpuNonDmp()) + return 0; + return 1; +#else + return 0; +#endif +} + +/* these functions can be consolidated +with inv_convert_to_body_with_scale */ +void MPLSensor::getCompassBias() +{ + VFUNC_LOG; + + + long bias[3]; + long compassBias[3]; + unsigned short orient; + signed char orientMtx[9]; + mCompassSensor->getOrientationMatrix(orientMtx); + orient = inv_orientation_matrix_to_scalar(orientMtx); + + /* Get Values from MPL */ + inv_get_compass_bias(bias); + inv_convert_to_body(orient, bias, compassBias); + LOGV_IF(HANDLER_DATA, "Mpl Compass Bias (HW unit) %ld %ld %ld", bias[0], bias[1], bias[2]); + LOGV_IF(HANDLER_DATA, "Mpl Compass Bias (HW unit) (body) %ld %ld %ld", compassBias[0], compassBias[1], compassBias[2]); + long compassSensitivity = inv_get_compass_sensitivity(); + if (compassSensitivity == 0) { + compassSensitivity = mCompassScale; + } + for(int i=0; i<3; i++) { + /* convert to uT */ + float temp = (float) compassSensitivity / (1L << 30); + mCompassBias[i] =(float) (compassBias[i] * temp / 65536.f); + } + + return; +} + +void MPLSensor::getFactoryGyroBias() +{ + VFUNC_LOG; + + /* Get Values from MPL */ + inv_get_gyro_bias(mFactoryGyroBias); + LOGV_IF(ENG_VERBOSE, "Factory Gyro Bias %ld %ld %ld", mFactoryGyroBias[0], mFactoryGyroBias[1], mFactoryGyroBias[2]); + mFactoryGyroBiasAvailable = true; + + return; +} + +/* set bias from factory cal file to MPU offset (in chip frame) + x = values store in cal file --> (v/1000 * 2^16 / (2000/250)) + offset = x/2^16 * (Gyro scale / self test scale used) * (-1) / offset scale + i.e. self test default scale = 250 + gyro scale default to = 2000 + offset scale = 4 //as spec by hardware + offset = x/2^16 * (8) * (-1) / (4) +*/ +void MPLSensor::setFactoryGyroBias() +{ + VFUNC_LOG; + int scaleRatio = mGyroScale / mGyroSelfTestScale; + int offsetScale = 4; + LOGV_IF(ENG_VERBOSE, "HAL: scaleRatio used =%d", scaleRatio); + LOGV_IF(ENG_VERBOSE, "HAL: offsetScale used =%d", offsetScale); + + /* Write to Driver */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + (((int) (((float) mFactoryGyroBias[0]) / 65536.f * scaleRatio)) * -1 / offsetScale), + mpu.in_gyro_x_offset, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_x_offset_fd, + (((int) (((float) mFactoryGyroBias[0]) / 65536.f * scaleRatio)) * -1 / offsetScale)) < 0) + { + LOGE("HAL:Error writing to gyro_x_offset"); + return; + } + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + (((int) (((float) mFactoryGyroBias[1]) / 65536.f * scaleRatio)) * -1 / offsetScale), + mpu.in_gyro_y_offset, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_y_offset_fd, + (((int) (((float) mFactoryGyroBias[1]) / 65536.f * scaleRatio)) * -1 / offsetScale)) < 0) + { + LOGE("HAL:Error writing to gyro_y_offset"); + return; + } + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + (((int) (((float) mFactoryGyroBias[2]) / 65536.f * scaleRatio)) * -1 / offsetScale), + mpu.in_gyro_z_offset, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_z_offset_fd, + (((int) (((float) mFactoryGyroBias[2]) / 65536.f * scaleRatio)) * -1 / offsetScale)) < 0) + { + LOGE("HAL:Error writing to gyro_z_offset"); + return; + } + mFactoryGyroBiasAvailable = false; + LOGV_IF(EXTRA_VERBOSE, "HAL:Factory Gyro Calibrated Bias Applied"); + + return; +} + +/* these functions can be consolidated +with inv_convert_to_body_with_scale */ +void MPLSensor::getGyroBias() +{ + VFUNC_LOG; + + long *temp = NULL; + long chipBias[3]; + long bias[3]; + unsigned short orient; + + /* Get Values from MPL */ + inv_get_mpl_gyro_bias(mGyroChipBias, temp); + orient = inv_orientation_matrix_to_scalar(mGyroOrientation); + inv_convert_to_body(orient, mGyroChipBias, bias); + LOGV_IF(ENG_VERBOSE, "Mpl Gyro Bias (HW unit) %ld %ld %ld", mGyroChipBias[0], mGyroChipBias[1], mGyroChipBias[2]); + LOGV_IF(ENG_VERBOSE, "Mpl Gyro Bias (HW unit) (body) %ld %ld %ld", bias[0], bias[1], bias[2]); + long gyroSensitivity = inv_get_gyro_sensitivity(); + if(gyroSensitivity == 0) { + gyroSensitivity = mGyroScale; + } + + /* scale and convert to rad */ + for(int i=0; i<3; i++) { + float temp = (float) gyroSensitivity / (1L << 30); + mGyroBias[i] = (float) (bias[i] * temp / (1<<16) / 180 * M_PI); + if (mGyroBias[i] != 0) + mGyroBiasAvailable = true; + } + + return; +} + +void MPLSensor::setGyroZeroBias() +{ + VFUNC_LOG; + + /* Write to Driver */ + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.in_gyro_x_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_x_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_x_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.in_gyro_y_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_y_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_y_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.in_gyro_z_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_z_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_z_dmp_bias"); + return; + } + LOGV_IF(EXTRA_VERBOSE, "HAL:Zero Gyro DMP Calibrated Bias Applied"); + + return; +} + +void MPLSensor::setGyroBias() +{ + VFUNC_LOG; + + if(mGyroBiasAvailable == false) + return; + + long bias[3]; + long gyroSensitivity = inv_get_gyro_sensitivity(); + + if(gyroSensitivity == 0) { + gyroSensitivity = mGyroScale; + } + + inv_get_gyro_bias_dmp_units(bias); + + /* Write to Driver */ + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + bias[0], mpu.in_gyro_x_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_x_dmp_bias_fd, bias[0]) < 0) { + LOGE("HAL:Error writing to gyro_x_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + bias[1], mpu.in_gyro_y_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_y_dmp_bias_fd, bias[1]) < 0) { + LOGE("HAL:Error writing to gyro_y_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + bias[2], mpu.in_gyro_z_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous(gyro_z_dmp_bias_fd, bias[2]) < 0) { + LOGE("HAL:Error writing to gyro_z_dmp_bias"); + return; + } + mGyroBiasApplied = true; + mGyroBiasAvailable = false; + LOGV_IF(EXTRA_VERBOSE, "HAL:Gyro DMP Calibrated Bias Applied"); + + return; +} + +void MPLSensor::getFactoryAccelBias() +{ + VFUNC_LOG; + + long temp; + + /* Get Values from MPL */ + inv_get_accel_bias(mFactoryAccelBias); + LOGV_IF(ENG_VERBOSE, "Factory Accel Bias (mg) %ld %ld %ld", mFactoryAccelBias[0], mFactoryAccelBias[1], mFactoryAccelBias[2]); + mFactoryAccelBiasAvailable = true; + + return; +} + +void MPLSensor::setFactoryAccelBias() +{ + VFUNC_LOG; + + if(mFactoryAccelBiasAvailable == false) + return; + + /* add scaling here - depends on self test parameters */ + int scaleRatio = mAccelScale / mAccelSelfTestScale; + int offsetScale = 16; + long tempBias; + + LOGV_IF(ENG_VERBOSE, "HAL: scaleRatio used =%d", scaleRatio); + LOGV_IF(ENG_VERBOSE, "HAL: offsetScale used =%d", offsetScale); + + /* Write to Driver */ + tempBias = -mFactoryAccelBias[0] / 65536.f * scaleRatio / offsetScale; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %ld > %s (%lld)", + tempBias, mpu.in_accel_x_offset, getTimestamp()); + if(write_attribute_sensor_continuous(accel_x_offset_fd, tempBias) < 0) { + LOGE("HAL:Error writing to accel_x_offset"); + return; + } + tempBias = -mFactoryAccelBias[1] / 65536.f * scaleRatio / offsetScale; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %ld > %s (%lld)", + tempBias, mpu.in_accel_y_offset, getTimestamp()); + if(write_attribute_sensor_continuous(accel_y_offset_fd, tempBias) < 0) { + LOGE("HAL:Error writing to accel_y_offset"); + return; + } + tempBias = -mFactoryAccelBias[2] / 65536.f * scaleRatio / offsetScale; + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %ld > %s (%lld)", + tempBias, mpu.in_accel_z_offset, getTimestamp()); + if(write_attribute_sensor_continuous(accel_z_offset_fd, tempBias) < 0) { + LOGE("HAL:Error writing to accel_z_offset"); + return; + } + mFactoryAccelBiasAvailable = false; + LOGV_IF(EXTRA_VERBOSE, "HAL:Factory Accel Calibrated Bias Applied"); + + return; +} + +void MPLSensor::getAccelBias() +{ + VFUNC_LOG; + long temp; + + /* Get Values from MPL */ + inv_get_mpl_accel_bias(mAccelBias, &temp); + LOGV_IF(ENG_VERBOSE, "Accel Bias (mg) %ld %ld %ld", + mAccelBias[0], mAccelBias[1], mAccelBias[2]); + mAccelBiasAvailable = true; + + return; +} + +/* set accel bias obtained from MPL + bias is scaled by 65536 from MPL + DMP expects: bias * 536870912 / 2^30 = bias / 2 (in body frame) +*/ +void MPLSensor::setAccelBias() +{ + VFUNC_LOG; + + if(mAccelBiasAvailable == false) { + LOGV_IF(ENG_VERBOSE, "HAL: setAccelBias - accel bias not available"); + return; + } + + /* write to driver */ + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + (long) (mAccelBias[0] / 65536.f / 2), + mpu.in_accel_x_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous( + accel_x_dmp_bias_fd, (long)(mAccelBias[0] / 65536.f / 2)) < 0) { + LOGE("HAL:Error writing to accel_x_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + (long)(mAccelBias[1] / 65536.f / 2), + mpu.in_accel_y_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous( + accel_y_dmp_bias_fd, (long)(mAccelBias[1] / 65536.f / 2)) < 0) { + LOGE("HAL:Error writing to accel_y_dmp_bias"); + return; + } + LOGV_IF(SYSFS_VERBOSE && INPUT_DATA, "HAL:sysfs:echo %ld > %s (%lld)", + (long)(mAccelBias[2] / 65536 / 2), + mpu.in_accel_z_dmp_bias, getTimestamp()); + if(write_attribute_sensor_continuous( + accel_z_dmp_bias_fd, (long)(mAccelBias[2] / 65536 / 2)) < 0) { + LOGE("HAL:Error writing to accel_z_dmp_bias"); + return; + } + + mAccelBiasAvailable = false; + mAccelBiasApplied = true; + LOGV_IF(EXTRA_VERBOSE, "HAL:Accel DMP Calibrated Bias Applied"); + + return; +} + +int MPLSensor::isCompassDisabled(void) +{ + VFUNC_LOG; + if(mCompassSensor->getFd() < 0 && !mCompassSensor->isIntegrated()) { + LOGI_IF(EXTRA_VERBOSE, "HAL: Compass is disabled, Six-axis Sensor Fusion is used."); + return 1; + } + return 0; +} + +int MPLSensor::checkBatchEnabled(void) +{ + VFUNC_LOG; + return ((mFeatureActiveMask & INV_DMP_BATCH_MODE)? 1:0); +} + +/* precondition: framework disallows this case, ie enable continuous sensor, */ +/* and enable batch sensor */ +/* if one sensor is in continuous mode, HAL disallows enabling batch for this sensor */ +/* or any other sensors */ +int MPLSensor::batch(int handle, int flags, int64_t period_ns, int64_t timeout) +{ + VFUNC_LOG; + + int res = 0; + + if (isMpuNonDmp()) + return res; + + /* Enables batch mode and sets timeout for the given sensor */ + /* enum SENSORS_BATCH_DRY_RUN, SENSORS_BATCH_WAKE_UPON_FIFO_FULL */ + bool dryRun = false; + android::String8 sname; + int what = -1; + int enabled_sensors = mEnabled; + int batchMode = timeout > 0 ? 1 : 0; + + LOGI_IF(DEBUG_BATCHING || ENG_VERBOSE, + "HAL:batch called - handle=%d, flags=%d, period=%lld, timeout=%lld", + handle, flags, period_ns, timeout); + + if(flags & SENSORS_BATCH_DRY_RUN) { + dryRun = true; + LOGI_IF(PROCESS_VERBOSE, + "HAL:batch - dry run mode is set (%d)", SENSORS_BATCH_DRY_RUN); + } + + /* check if we can support issuing interrupt before FIFO fills-up */ + /* in a given timeout. */ + if (flags & SENSORS_BATCH_WAKE_UPON_FIFO_FULL) { + LOGE("HAL: batch SENSORS_BATCH_WAKE_UPON_FIFO_FULL is not supported"); + return -EINVAL; + } + + getHandle(handle, what, sname); + if(uint32_t(what) >= NumSensors) { + LOGE("HAL:batch sensors %d not found", what); + return -EINVAL; + } + + LOGV_IF(PROCESS_VERBOSE, + "HAL:batch : %llu ns, (%.2f Hz)", period_ns, 1000000000.f / period_ns); + + // limit all rates to reasonable ones */ + if (period_ns < 5000000LL) { + period_ns = 5000000LL; + } + + switch (what) { + case Gyro: + case RawGyro: + case Accelerometer: + case MagneticField: + case RawMagneticField: + case Pressure: + case GameRotationVector: + case StepDetector: + LOGV_IF(PROCESS_VERBOSE, "HAL: batch - select sensor (handle %d)", handle); + break; + default: + if (timeout > 0) { + LOGE("sensor (handle %d) is not supported in batch mode", handle); + return -EINVAL; + } + } + + if(dryRun == true) { + LOGI("HAL: batch Dry Run is complete"); + return 0; + } + + int tempBatch = 0; + if (timeout > 0) { + tempBatch = mBatchEnabled | (1 << what); + } else { + tempBatch = mBatchEnabled & ~(1 << what); + } + + if (!computeBatchSensorMask(mEnabled, tempBatch)) { + batchMode = 0; + } else { + batchMode = 1; + } + + /* get maximum possible bytes to batch per sample */ + /* get minimum delay for each requested sensor */ + ssize_t nBytes = 0; + int64_t wanted = 1000000000LL, ns = 0; + int64_t timeoutInMs = 0; + for (int i = 0; i < NumSensors; i++) { + if (batchMode == 1) { + ns = mBatchDelays[i]; + LOGV_IF(DEBUG_BATCHING && EXTRA_VERBOSE, + "HAL:batch - requested sensor=0x%01x, batch delay=%lld", mEnabled & (1 << i), ns); + // take the min delay ==> max rate + wanted = (ns < wanted) ? ns : wanted; + if (i <= RawMagneticField) { + nBytes += 8; + } + if (i == Pressure) { + nBytes += 6; + } + if ((i == StepDetector) || (i == GameRotationVector)) { + nBytes += 16; + } + } + } + + /* starting from code below, we will modify hardware */ + /* first edit global batch mode mask */ + + if (!timeout) { + mBatchEnabled &= ~(1 << what); + mBatchDelays[what] = 1000000000L; + mDelays[what] = period_ns; + mBatchTimeouts[what] = 100000000000LL; + } else { + mBatchEnabled |= (1 << what); + mBatchDelays[what] = period_ns; + mDelays[what] = period_ns; + mBatchTimeouts[what] = timeout; + } + + // reset master enable + res = masterEnable(0); + if (res < 0) { + return res; + } + + if(((int)mOldBatchEnabledMask != batchMode) || batchMode) { + + /* remember batch mode that is set */ + mOldBatchEnabledMask = batchMode; + + /* For these sensors, switch to different data output */ + int featureMask = computeBatchDataOutput(); + + LOGV_IF(ENG_VERBOSE, "batchMode =%d, featureMask=0x%x, mEnabled=%d", + batchMode, featureMask, mEnabled); + if (DEBUG_BATCHING && EXTRA_VERBOSE) { + LOGV("HAL:batch - sensor=0x%01x", mBatchEnabled); + for (int d = 0; d < NumSensors; d++) { + LOGV("HAL:batch - sensor status=0x%01x batch status=0x%01x timeout=%lld delay=%lld", + mEnabled & (1 << d), (mBatchEnabled & (1 << d)), mBatchTimeouts[d], + mBatchDelays[d]); + } + } + + /* take the minimum batchmode timeout */ + if (batchMode == 1) { + int64_t tempTimeout = 100000000000LL; + for (int i = 0; i < NumSensors; i++) { + if ((mEnabled & (1 << i) && mBatchEnabled & (1 << i)) || + (((featureMask & INV_DMP_PED_STANDALONE) && (mBatchEnabled & (1 << StepDetector))))) { + LOGV_IF(ENG_VERBOSE, "i=%d, timeout=%lld", i, mBatchTimeouts[i]); + ns = mBatchTimeouts[i]; + tempTimeout = (ns < tempTimeout) ? ns : tempTimeout; + } + } + timeout = tempTimeout; + /* Convert ns to millisecond */ + timeoutInMs = timeout / 1000000; + + /* remember last timeout value */ + mBatchTimeoutInMs = timeoutInMs; + } else { + timeoutInMs = 0; + } + + LOGV_IF(DEBUG_BATCHING || EXTRA_VERBOSE, + "HAL:batch - timeout - timeout=%lld ns, timeoutInMs=%lld, delay=%lld ns", + timeout, timeoutInMs, period_ns); + + /* case for Ped standalone */ + if ((batchMode == 1) && (featureMask & INV_DMP_PED_STANDALONE) && + (mFeatureActiveMask & INV_DMP_PEDOMETER)) { + LOGI("ID_P only = 0x%x", mBatchEnabled); + enablePedQuaternion(0); + enablePedStandalone(1); + } else { + enablePedStandalone(0); + if (featureMask & INV_DMP_PED_QUATERNION) { + enableLPQuaternion(0); + enablePedQuaternion(1); + } + } + + /* case for Ped Quaternion */ + if ((batchMode == 1) && (featureMask & INV_DMP_PED_QUATERNION) && + (mEnabled & (1 << GameRotationVector)) && + (mFeatureActiveMask & INV_DMP_PEDOMETER)) { + LOGI("ID_P and GRV or ALL = 0x%x", mBatchEnabled); + LOGI("ID_P is enabled for batching, PED quat will be automatically enabled"); + enableLPQuaternion(0); + enablePedQuaternion(1); + + wanted = mBatchDelays[GameRotationVector]; + /* set pedq rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / wanted), mpu.ped_q_rate, + getTimestamp()); + write_sysfs_int(mpu.ped_q_rate, 1000000000.f / wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP ped quaternion rate %.2f Hz", 1000000000.f / wanted); + } else if (!(featureMask & INV_DMP_PED_STANDALONE)){ + LOGV_IF(ENG_VERBOSE, "batch - PedQ Toggle back to normal 6 axis"); + if (mEnabled & (1 << GameRotationVector)) { + enableLPQuaternion(checkLPQRateSupported()); + } + enablePedQuaternion(0); + } else { + enablePedQuaternion(0); + } + + /* case for Ped indicator */ + if ((batchMode == 1) && ((featureMask & INV_DMP_PED_INDICATOR))) { + enablePedIndicator(1); + } else { + enablePedIndicator(0); + } + + /* case for Six Axis Quaternion */ + if ((batchMode == 1) && (featureMask & INV_DMP_6AXIS_QUATERNION) && + (mEnabled & (1 << GameRotationVector))) { + LOGI("GRV = 0x%x", mBatchEnabled); + enableLPQuaternion(0); + enable6AxisQuaternion(1); + if (what == GameRotationVector) { + setInitial6QuatValue(); + } + + wanted = mBatchDelays[GameRotationVector]; + /* set sixaxis rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / wanted), mpu.six_axis_q_rate, + getTimestamp()); + write_sysfs_int(mpu.six_axis_q_rate, 1000000000.f / wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP six axis rate %.2f Hz", 1000000000.f / wanted); + } else if (!(featureMask & INV_DMP_PED_QUATERNION)){ + LOGV_IF(ENG_VERBOSE, "batch - 6Axis Toggle back to normal 6 axis"); + if (mEnabled & (1 << GameRotationVector)) { + enableLPQuaternion(checkLPQRateSupported()); + } + enable6AxisQuaternion(0); + } else { + enable6AxisQuaternion(0); + } + + /* TODO: This may make a come back some day */ + /* Not to overflow hardware FIFO if flag is set */ + /*if (flags & (1 << SENSORS_BATCH_WAKE_UPON_FIFO_FULL)) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.batchmode_wake_fifo_full_on, getTimestamp()); + if (write_sysfs_int(mpu.batchmode_wake_fifo_full_on, 0) < 0) { + LOGE("HAL:ERR can't write batchmode_wake_fifo_full_on"); + } + }*/ + + /* write required timeout to sysfs */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %lld > %s (%lld)", + timeoutInMs, mpu.batchmode_timeout, getTimestamp()); + if (write_sysfs_int(mpu.batchmode_timeout, timeoutInMs) < 0) { + LOGE("HAL:ERR can't write batchmode_timeout"); + } + + if (computeAndSetDmpState() < 0) { + LOGE("HAL:ERR can't compute dmp state"); + } + +}//end of batch mode modify + + if (batchMode == 1) { + /* set batch rates */ + if (setBatchDataRates() < 0) { + LOGE("HAL:ERR can't set batch data rates"); + } + } else { + /* reset sensor rate */ + if (resetDataRates() < 0) { + LOGE("HAL:ERR can't reset output rate back to original setting"); + } + } + + // set sensor data interrupt + uint32_t dataInterrupt = (mEnabled || (mFeatureActiveMask & INV_DMP_BATCH_MODE)); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + !dataInterrupt, mpu.dmp_event_int_on, getTimestamp()); + if (write_sysfs_int(mpu.dmp_event_int_on, !dataInterrupt) < 0) { + res = -1; + LOGE("HAL:ERR can't enable DMP event interrupt"); + } + + if (enabled_sensors || mFeatureActiveMask) { + masterEnable(1); + } + return res; +} + +/* Send empty event when: */ +/* 1. batch mode is not enabled */ +/* 2. no data in HW FIFO */ +/* return status zero if (2) */ +int MPLSensor::flush(int handle) +{ + VFUNC_LOG; + + int res = 0; + int status = 0; + android::String8 sname; + int what = -1; + + getHandle(handle, what, sname); + if (uint32_t(what) >= NumSensors) { + LOGE("HAL:flush - what=%d is invalid", what); + return -EINVAL; + } + + switch (what) { + case Gyro: + case RawGyro: + case Accelerometer: + case MagneticField: + case RawMagneticField: + case Pressure: + case GameRotationVector: + case StepDetector: + LOGV_IF(PROCESS_VERBOSE, "HAL: flush - select sensor %s (handle %d)", sname.string(), handle); + break; + default: + LOGE("sensor (handle %d) is not supported in batch or flush mode", handle); + return -EINVAL; + } + + if (((what != StepDetector) && (!(mEnabled & (1 << what)))) || + ((what == StepDetector) && !(mFeatureActiveMask & INV_DMP_PEDOMETER))) { + LOGE("HAL: flush - sensor %s not enabled", sname.string()); + return -EINVAL; + } + + if(!(mBatchEnabled & (1 << what))) { + LOGV_IF(PROCESS_VERBOSE, "HAL:flush - batch mode not enabled for sensor %s (handle %d)", sname.string(), handle); + } + + /*write sysfs */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:cat %s (%lld)", + mpu.flush_batch, getTimestamp()); + + status = read_sysfs_int(mpu.flush_batch, &res); + + if (status < 0) + return status; + + /* driver returns 0 if FIFO is empty */ + /* ensure we return status zero */ + if (res == 0) { + LOGI("HAL: flush - no data in FIFO"); + status = 0; + } + + mFlushSensorEnabled = handle; + LOGV_IF(ENG_VERBOSE, "HAl:flush - mFlushSensorEnabled=%d", mFlushSensorEnabled); + + mFlushBatchSet = 0; + return status; +} + +int MPLSensor::selectAndSetQuaternion(int batchMode, int mEnabled, long long featureMask) +{ + VFUNC_LOG; + int res = 0; + + int64_t wanted; + + /* case for Ped Quaternion */ + if (batchMode == 1) { + if ((featureMask & INV_DMP_PED_QUATERNION) && + (mEnabled & (1 << GameRotationVector)) && + (mFeatureActiveMask & INV_DMP_PEDOMETER)) { + enableLPQuaternion(0); + enable6AxisQuaternion(0); + setInitial6QuatValue(); + enablePedQuaternion(1); + + wanted = mBatchDelays[GameRotationVector]; + /* set pedq rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / wanted), mpu.ped_q_rate, + getTimestamp()); + write_sysfs_int(mpu.ped_q_rate, 1000000000.f / wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP ped quaternion rate %.2f Hz", 1000000000.f / wanted); + } else if ((featureMask & INV_DMP_6AXIS_QUATERNION) && + (mEnabled & (1 << GameRotationVector))) { + enableLPQuaternion(0); + enablePedQuaternion(0); + setInitial6QuatValue(); + enable6AxisQuaternion(1); + + wanted = mBatchDelays[GameRotationVector]; + /* set sixaxis rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + int(1000000000.f / wanted), mpu.six_axis_q_rate, + getTimestamp()); + write_sysfs_int(mpu.six_axis_q_rate, 1000000000.f / wanted); + LOGV_IF(PROCESS_VERBOSE, + "HAL:DMP six axis rate %.2f Hz", 1000000000.f / wanted); + } else { + enablePedQuaternion(0); + enable6AxisQuaternion(0); + } + } else { + if(mEnabled & (1 << GameRotationVector)) { + enablePedQuaternion(0); + enable6AxisQuaternion(0); + enableLPQuaternion(checkLPQRateSupported()); + } + else { + enablePedQuaternion(0); + enable6AxisQuaternion(0); + } + } + + return res; +} + +/* +Select Quaternion and Options for Batching + + ID_P ID_GRV HW Batch Type +a 1 1 1 PedQ, Ped Indicator, HW +b 1 1 0 PedQ +c 1 0 1 Ped Indicator, HW +d 1 0 0 Ped Standalone, Ped Indicator +e 0 1 1 6Q, HW +f 0 1 0 6Q +g 0 0 1 HW +h 0 0 0 LPQ <defualt> +*/ +int MPLSensor::computeBatchDataOutput() +{ + VFUNC_LOG; + + int featureMask = 0; + if (mBatchEnabled == 0) + return 0;//h + + uint32_t hardwareSensorMask = (1 << Gyro) + | (1 << RawGyro) + | (1 << Accelerometer) + | (1 << MagneticField) + | (1 << RawMagneticField) + | (1 << Pressure); + LOGV_IF(ENG_VERBOSE, "hardwareSensorMask = 0x%0x, mBatchEnabled = 0x%0x", + hardwareSensorMask, mBatchEnabled); + + if (mBatchEnabled & (1 << StepDetector)) { + if (mBatchEnabled & (1 << GameRotationVector)) { + if ((mBatchEnabled & hardwareSensorMask)) { + featureMask |= INV_DMP_6AXIS_QUATERNION;//a + featureMask |= INV_DMP_PED_INDICATOR; +//LOGE("batch output: a"); + } else { + featureMask |= INV_DMP_PED_QUATERNION; //b + featureMask |= INV_DMP_PED_INDICATOR; //always piggy back a bit +//LOGE("batch output: b"); + } + } else { + if (mBatchEnabled & hardwareSensorMask) { + featureMask |= INV_DMP_PED_INDICATOR; //c +//LOGE("batch output: c"); + } else { + featureMask |= INV_DMP_PED_STANDALONE; //d + featureMask |= INV_DMP_PED_INDICATOR; //required for standalone +//LOGE("batch output: d"); + } + } + } else if (mBatchEnabled & (1 << GameRotationVector)) { + featureMask |= INV_DMP_6AXIS_QUATERNION; //e,f +//LOGE("batch output: e,f"); + } else { + LOGV_IF(ENG_VERBOSE, + "HAL:computeBatchDataOutput: featuerMask=0x%x", featureMask); +//LOGE("batch output: g"); + return 0; //g + } + + LOGV_IF(ENG_VERBOSE, + "HAL:computeBatchDataOutput: featuerMask=0x%x", featureMask); + return featureMask; +} + +int MPLSensor::getDmpPedometerFd() +{ + VFUNC_LOG; + LOGV_IF(EXTRA_VERBOSE, "getDmpPedometerFd returning %d", dmp_pedometer_fd); + return dmp_pedometer_fd; +} + +/* @param [in] : outputType = 1 --event is from PED_Q */ +/* outputType = 0 --event is from ID_SC, ID_P */ +int MPLSensor::readDmpPedometerEvents(sensors_event_t* data, int count, + int32_t id, int outputType) +{ + VFUNC_LOG; + + int res = 0; + char dummy[4]; + + int numEventReceived = 0; + int update = 0; + + LOGI_IF(0, "HAL: Read Pedometer Event ID=%d", id); + switch (id) { + case ID_P: + if (mDmpPedometerEnabled && count > 0) { + /* Handles return event */ + LOGI("HAL: Step detected"); + update = sdHandler(&mSdEvents); + } + + if (update && count > 0) { + *data++ = mSdEvents; + count--; + numEventReceived++; + } + break; + case ID_SC: + FILE *fp; + uint64_t stepCount; + uint64_t stepCountTs; + + if (mDmpStepCountEnabled && count > 0) { + fp = fopen(mpu.pedometer_steps, "r"); + if (fp == NULL) { + LOGE("HAL:cannot open pedometer_steps"); + } else { + if (fscanf(fp, "%lld\n", &stepCount) < 0 || fclose(fp) < 0) { + LOGE("HAL:cannot read pedometer_steps"); + return 0; + } + } + + /* return event onChange only */ + if (stepCount == mLastStepCount) { + return 0; + } + + mLastStepCount = stepCount; + + /* Read step count timestamp */ + fp = fopen(mpu.pedometer_counter, "r"); + if (fp == NULL) { + LOGE("HAL:cannot open pedometer_counter"); + } else{ + if (fscanf(fp, "%lld\n", &stepCountTs) < 0 || fclose(fp) < 0) { + LOGE("HAL:cannot read pedometer_counter"); + return 0; + } + } + mScEvents.timestamp = stepCountTs; + + /* Handles return event */ + update = scHandler(&mScEvents); + } + + if (update && count > 0) { + *data++ = mScEvents; + count--; + numEventReceived++; + } + break; + } + + if (!outputType) { + // read dummy data per driver's request + // only required if actual irq is issued + read(dmp_pedometer_fd, dummy, 4); + } else { + return 1; + } + + return numEventReceived; +} + +int MPLSensor::getDmpSignificantMotionFd() +{ + VFUNC_LOG; + + LOGV_IF(EXTRA_VERBOSE, "getDmpSignificantMotionFd returning %d", + dmp_sign_motion_fd); + return dmp_sign_motion_fd; +} + +int MPLSensor::readDmpSignificantMotionEvents(sensors_event_t* data, int count) +{ + VFUNC_LOG; + + int res = 0; + char dummy[4]; + int significantMotion; + FILE *fp; + int sensors = mEnabled; + int numEventReceived = 0; + int update = 0; + + /* Technically this step is not necessary for now */ + /* In the future, we may have meaningful values */ + fp = fopen(mpu.event_smd, "r"); + if (fp == NULL) { + LOGE("HAL:cannot open event_smd"); + return 0; + } else { + if (fscanf(fp, "%d\n", &significantMotion) < 0 || fclose(fp) < 0) { + LOGE("HAL:cannot read event_smd"); + } + } + + if(mDmpSignificantMotionEnabled && count > 0) { + /* By implementation, smd is disabled once an event is triggered */ + sensors_event_t temp; + + /* Handles return event */ + LOGI("HAL: SMD detected"); + int update = smHandler(&mSmEvents); + if (update && count > 0) { + *data++ = mSmEvents; + count--; + numEventReceived++; + + /* reset smd state */ + mDmpSignificantMotionEnabled = 0; + mFeatureActiveMask &= ~INV_DMP_SIGNIFICANT_MOTION; + } + } + + // read dummy data per driver's request + read(dmp_sign_motion_fd, dummy, 4); + + return numEventReceived; +} + +int MPLSensor::enableDmpSignificantMotion(int en) +{ + VFUNC_LOG; + + int res = 0; + int enabled_sensors = mEnabled; + + if (isMpuNonDmp()) + return res; + + // reset master enable + res = masterEnable(0); + if (res < 0) + return res; + + //Toggle significant montion detection + if(en) { + LOGV_IF(ENG_VERBOSE, "HAL:Enabling Significant Motion"); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 1, mpu.smd_enable, getTimestamp()); + if (write_sysfs_int(mpu.smd_enable, 1) < 0) { + LOGE("HAL:ERR can't write DMP smd_enable"); + res = -1; //Indicate an err + } + mFeatureActiveMask |= INV_DMP_SIGNIFICANT_MOTION; + } + else { + LOGV_IF(ENG_VERBOSE, "HAL:Disabling Significant Motion"); + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + 0, mpu.smd_enable, getTimestamp()); + if (write_sysfs_int(mpu.smd_enable, 0) < 0) { + LOGE("HAL:ERR write DMP smd_enable"); + } + mFeatureActiveMask &= ~INV_DMP_SIGNIFICANT_MOTION; + } + + if ((res = setDmpFeature(en)) < 0) + return res; + + if ((res = computeAndSetDmpState()) < 0) + return res; + + if(en || enabled_sensors || mFeatureActiveMask) { + res = masterEnable(1); + } + return res; +} + +void MPLSensor::setInitial6QuatValue() +{ + VFUNC_LOG; + + if (!mInitial6QuatValueAvailable) + return; + + /* convert to unsigned char array */ + size_t length = 16; + unsigned char quat[16]; + convert_long_to_hex_char(mInitial6QuatValue, quat, 4); + + /* write to sysfs */ + LOGV_IF(EXTRA_VERBOSE, "HAL:six axis q value: %s", mpu.six_axis_q_value); + FILE* fptr = fopen(mpu.six_axis_q_value, "w"); + if(fptr == NULL) { + LOGE("HAL:could not open six_axis_q_value"); + } else { + if (fwrite(quat, 1, length, fptr) != length || fclose(fptr) < 0) { + LOGE("HAL:write six axis q value failed"); + } else { + mInitial6QuatValueAvailable = 0; + } + } + + return; +} +int MPLSensor::writeSignificantMotionParams(bool toggleEnable, + uint32_t delayThreshold1, + uint32_t delayThreshold2, + uint32_t motionThreshold) +{ + VFUNC_LOG; + + int res = 0; + + // Turn off enable + if (toggleEnable) { + masterEnable(0); + } + + // Write supplied values + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + delayThreshold1, mpu.smd_delay_threshold, getTimestamp()); + res = write_sysfs_int(mpu.smd_delay_threshold, delayThreshold1); + if (res == 0) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + delayThreshold2, mpu.smd_delay_threshold2, getTimestamp()); + res = write_sysfs_int(mpu.smd_delay_threshold2, delayThreshold2); + } + if (res == 0) { + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", + motionThreshold, mpu.smd_threshold, getTimestamp()); + res = write_sysfs_int(mpu.smd_threshold, motionThreshold); + } + + // Turn on enable + if (toggleEnable) { + masterEnable(1); + } + return res; +} + +/* set batch data rate */ +/* this function should be optimized */ +int MPLSensor::setBatchDataRates() +{ + VFUNC_LOG; + + int res = 0; + int tempFd = -1; + + int64_t gyroRate; + int64_t accelRate; + int64_t compassRate; + int64_t pressureRate; + int64_t quatRate; + + int mplGyroRate; + int mplAccelRate; + int mplCompassRate; + int mplQuatRate; + +#ifdef ENABLE_MULTI_RATE + gyroRate = mBatchDelays[Gyro]; + /* take care of case where only one type of gyro sensors or + compass sensors is turned on */ + if (mBatchEnabled & (1 << Gyro) || mBatchEnabled & (1 << RawGyro)) { + gyroRate = (mBatchDelays[Gyro] <= mBatchDelays[RawGyro]) ? + (mBatchEnabled & (1 << Gyro) ? mBatchDelays[Gyro] : mBatchDelays[RawGyro]): + (mBatchEnabled & (1 << RawGyro) ? mBatchDelays[RawGyro] : mBatchDelays[Gyro]); + } + compassRate = mBatchDelays[MagneticField]; + if (mBatchEnabled & (1 << MagneticField) || mBatchEnabled & (1 << RawMagneticField)) { + compassRate = (mBatchDelays[MagneticField] <= mBatchDelays[RawMagneticField]) ? + (mBatchEnabled & (1 << MagneticField) ? mBatchDelays[MagneticField] : + mBatchDelays[RawMagneticField]) : + (mBatchEnabled & (1 << RawMagneticField) ? mBatchDelays[RawMagneticField] : + mBatchDelays[MagneticField]); + } + accelRate = mBatchDelays[Accelerometer]; + pressureRate = mBatchDelays[Pressure]; + + if ((mFeatureActiveMask & INV_DMP_PED_QUATERNION) || + (mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION)) { + quatRate = mBatchDelays[GameRotationVector]; + mplQuatRate = (int) quatRate / 1000LL; + inv_set_quat_sample_rate(mplQuatRate); + inv_set_rotation_vector_6_axis_sample_rate(mplQuatRate); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL rv 6 axis sample rate: (mpl)=%d us (mpu)=%.2f Hz", mplQuatRate, + 1000000000.f / quatRate ); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL quat sample rate: (mpl)=%d us (mpu)=%.2f Hz", mplQuatRate, + 1000000000.f / quatRate ); + getDmpRate(&quatRate); + } + + mplGyroRate = (int) gyroRate / 1000LL; + mplAccelRate = (int) accelRate / 1000LL; + mplCompassRate = (int) compassRate / 1000LL; + + /* set rate in MPL */ + /* compass can only do 100Hz max */ + inv_set_gyro_sample_rate(mplGyroRate); + inv_set_accel_sample_rate(mplAccelRate); + inv_set_compass_sample_rate(mplCompassRate); + + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL gyro sample rate: (mpl)=%d us (mpu)=%.2f Hz", mplGyroRate, 1000000000.f / gyroRate); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL accel sample rate: (mpl)=%d us (mpu)=%.2f Hz", mplAccelRate, 1000000000.f / accelRate); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL compass sample rate: (mpl)=%d us (mpu)=%.2f Hz", mplCompassRate, 1000000000.f / compassRate); + +#else + /* search the minimum delay requested across all enabled sensors */ + int64_t wanted = 1000000000LL; + for (int i = 0; i < NumSensors; i++) { + if (mBatchEnabled & (1 << i)) { + int64_t ns = mBatchDelays[i]; + wanted = wanted < ns ? wanted : ns; + } + } + gyroRate = wanted; + accelRate = wanted; + compassRate = wanted; + pressureRate = wanted; +#endif + + /* takes care of gyro rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / gyroRate, mpu.gyro_rate, + getTimestamp()); + tempFd = open(mpu.gyro_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / gyroRate); + if(res < 0) { + LOGE("HAL:GYRO update delay error"); + } + + /* takes care of accel rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / accelRate, mpu.accel_rate, + getTimestamp()); + tempFd = open(mpu.accel_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / accelRate); + LOGE_IF(res < 0, "HAL:ACCEL update delay error"); + + /* takes care of compass rate */ + if (compassRate < mCompassSensor->getMinDelay() * 1000LL) { + compassRate = mCompassSensor->getMinDelay() * 1000LL; + } + mCompassSensor->setDelay(ID_M, compassRate); + + /* takes care of pressure rate */ + mPressureSensor->setDelay(ID_PS, pressureRate); + + return res; +} + +/* Set sensor rate */ +/* this function should be optimized */ +int MPLSensor::resetDataRates() +{ + VFUNC_LOG; + + int res = 0; + int tempFd = -1; + int64_t wanted = 1000000000LL; + + int64_t resetRate; + int64_t gyroRate; + int64_t accelRate; + int64_t compassRate; + int64_t pressureRate; + + if (!mEnabled) { + LOGV_IF(ENG_VERBOSE, "skip resetDataRates"); + return 0; + } + LOGI("HAL:resetDataRates mEnabled=%d", mEnabled); + /* search the minimum delay requested across all enabled sensors */ + /* skip setting rates if it is not changed */ + for (int i = 0; i < NumSensors; i++) { + if (mEnabled & (1 << i)) { + int64_t ns = mDelays[i]; + if ((wanted == ns) && (i != Pressure)) { + LOGV_IF(ENG_VERBOSE, "skip resetDataRates : same delay mDelays[%d]=%lld", i,mDelays[i]); + //return 0; + } + LOGV_IF(ENG_VERBOSE, "resetDataRates - mDelays[%d]=%lld", i, mDelays[i]); + wanted = wanted < ns ? wanted : ns; + } + } + + resetRate = wanted; + gyroRate = wanted; + accelRate = wanted; + compassRate = wanted; + pressureRate = wanted; + + /* set mpl data rate */ + inv_set_gyro_sample_rate((int)gyroRate/1000LL); + inv_set_accel_sample_rate((int)accelRate/1000LL); + inv_set_compass_sample_rate((int)compassRate/1000LL); + inv_set_linear_acceleration_sample_rate((int)resetRate/1000LL); + inv_set_orientation_sample_rate((int)resetRate/1000LL); + inv_set_rotation_vector_sample_rate((int)resetRate/1000LL); + inv_set_gravity_sample_rate((int)resetRate/1000LL); + inv_set_orientation_geomagnetic_sample_rate((int)resetRate/1000LL); + inv_set_rotation_vector_6_axis_sample_rate((int)resetRate/1000LL); + inv_set_geomagnetic_rotation_vector_sample_rate((int)resetRate/1000LL); + + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL gyro sample rate: (mpl)=%lld us (mpu)=%.2f Hz", + gyroRate/1000LL, 1000000000.f / gyroRate); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL accel sample rate: (mpl)=%lld us (mpu)=%.2f Hz", + accelRate/1000LL, 1000000000.f / accelRate); + LOGV_IF(PROCESS_VERBOSE, + "HAL:MPL compass sample rate: (mpl)=%lld us (mpu)=%.2f Hz", + compassRate/1000LL, 1000000000.f / compassRate); + + /* reset dmp rate */ + getDmpRate (&wanted); + + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / wanted, mpu.gyro_fifo_rate, + getTimestamp()); + tempFd = open(mpu.gyro_fifo_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / wanted); + LOGE_IF(res < 0, "HAL:sampling frequency update delay error"); + + /* takes care of gyro rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / gyroRate, mpu.gyro_rate, + getTimestamp()); + tempFd = open(mpu.gyro_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / gyroRate); + if(res < 0) { + LOGE("HAL:GYRO update delay error"); + } + + /* takes care of accel rate */ + LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %.0f > %s (%lld)", + 1000000000.f / accelRate, mpu.accel_rate, + getTimestamp()); + tempFd = open(mpu.accel_rate, O_RDWR); + res = write_attribute_sensor(tempFd, 1000000000.f / accelRate); + LOGE_IF(res < 0, "HAL:ACCEL update delay error"); + + /* takes care of compass rate */ + if (compassRate < mCompassSensor->getMinDelay() * 1000LL) { + compassRate = mCompassSensor->getMinDelay() * 1000LL; + } + mCompassSensor->setDelay(ID_M, compassRate); + + /* takes care of pressure rate */ + mPressureSensor->setDelay(ID_PS, pressureRate); + + /* takes care of lpq case for data rate at 200Hz */ + if (checkLPQuaternion()) { + if (resetRate <= RATE_200HZ) { +#ifndef USE_LPQ_AT_FASTEST + enableLPQuaternion(0); +#endif + } + } + + return res; +} + +void MPLSensor::resetMplStates() +{ + VFUNC_LOG; + LOGV_IF(ENG_VERBOSE, "HAL:resetMplStates()"); + + inv_gyro_was_turned_off(); + inv_accel_was_turned_off(); + inv_compass_was_turned_off(); + inv_quaternion_sensor_was_turned_off(); + + return; +} + +void MPLSensor::initBias() +{ + VFUNC_LOG; + + LOGV_IF(ENG_VERBOSE, "HAL:inititalize dmp and device offsets to 0"); + if(write_attribute_sensor_continuous(accel_x_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_x_dmp_bias"); + } + if(write_attribute_sensor_continuous(accel_y_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_y_dmp_bias"); + } + if(write_attribute_sensor_continuous(accel_z_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_z_dmp_bias"); + } + + if(write_attribute_sensor_continuous(accel_x_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_x_offset"); + } + if(write_attribute_sensor_continuous(accel_y_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_y_offset"); + } + if(write_attribute_sensor_continuous(accel_z_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to accel_z_offset"); + } + + if(write_attribute_sensor_continuous(gyro_x_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_x_dmp_bias"); + } + if(write_attribute_sensor_continuous(gyro_y_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_y_dmp_bias"); + } + if(write_attribute_sensor_continuous(gyro_z_dmp_bias_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_z_dmp_bias"); + } + + if(write_attribute_sensor_continuous(gyro_x_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_x_offset"); + } + if(write_attribute_sensor_continuous(gyro_y_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_y_offset"); + } + if(write_attribute_sensor_continuous(gyro_z_offset_fd, 0) < 0) { + LOGE("HAL:Error writing to gyro_z_offset"); + } + return; +} + +/*TODO: reg_dump in a separate file*/ +void MPLSensor::sys_dump(bool fileMode) +{ + VFUNC_LOG; + + char sysfs_path[MAX_SYSFS_NAME_LEN]; + char scan_element_path[MAX_SYSFS_NAME_LEN]; + + memset(sysfs_path, 0, sizeof(sysfs_path)); + memset(scan_element_path, 0, sizeof(scan_element_path)); + inv_get_sysfs_path(sysfs_path); + sprintf(scan_element_path, "%s%s", sysfs_path, "/scan_elements"); + + read_sysfs_dir(fileMode, sysfs_path); + read_sysfs_dir(fileMode, scan_element_path); + + dump_dmp_img("/data/local/read_img.h"); + return; +} |