/* * Copyright (C) 2014 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/Vector.h> #include <utils/String8.h> #include <string.h> #include <linux/input.h> #include <utils/Atomic.h> #include <utils/SystemClock.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*)) // query path to determine if vibrator is currently vibrating #define VIBRATOR_ENABLE_FILE "/sys/class/timed_output/vibrator/enable" // Minimum time after vibrator triggers SMD before SMD can be declared valid // This allows 100mS for events to propogate #define MIN_TRIGGER_TIME_AFTER_VIBRATOR_NS 100000000 /******************************************************************************/ /* MPL Interface */ /******************************************************************************/ //#define INV_PLAYBACK_DBG #ifdef INV_PLAYBACK_DBG static FILE *logfile = NULL; #endif /******************************************************************************* * MPLSensor class implementation ******************************************************************************/ static int64_t mt_pre_ns; // 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), mEnabledCached(0), mBatchEnabled(0), 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), mGyroBatchRate(0), mAccelBatchRate(0), mCompassBatchRate(0), mPressureBatchRate(0), mQuatBatchRate(0), mGyroRate(0), mAccelRate(0), mCompassRate(0), mPressureRate(0), mQuatRate(0), mResetRate(0), mDataInterrupt(0), mFirstBatchCall(1), mEnableCalled(1), mMplFeatureActiveMask(0), mFeatureActiveMask(0), mDmpOn(0), mPedUpdate(0), mPressureUpdate(0), mQuatSensorTimestamp(0), mStepSensorTimestamp(0), mLastStepCount(-1), mLeftOverBufferSize(0), mInitial6QuatValueAvailable(0), mSkipReadEvents(0), mSkipExecuteOnData(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); mFlushBatchSet = 0; memset(mGyroOrientation, 0, sizeof(mGyroOrientation)); memset(mAccelOrientation, 0, sizeof(mAccelOrientation)); memset(mInitial6QuatValue, 0, sizeof(mInitial6QuatValue)); mFlushSensorEnabledVector.setCapacity(NumSensors); memset(mEnabledTime, 0, sizeof(mEnabledTime)); memset(mLastTimestamp, 0, sizeof(mLastTimestamp)); /* 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(); #ifdef ENABLE_PRESSURE /* instantiate pressure sensor on secondary bus */ mPressureSensor = new PressureSensor((const char*)mSysfsPath); #endif /* 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(gyroScale, 0, sizeof(gyroScale)); 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(accelScale, 0, sizeof(accelScale)); 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); } /* 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); #if 0 int StepCounterThreshold = 5; LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", StepCounterThreshold, mpu.pedometer_step_thresh, getTimestamp()); res = write_sysfs_int(mpu.pedometer_step_thresh, StepCounterThreshold); #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)); memset(mPendingFlushEvents, 0, sizeof(mPendingFlushEvents)); 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; #ifdef ENABLE_PRESSURE 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; #endif 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; #ifdef ENABLE_PRESSURE mHandlers[Pressure] = &MPLSensor::psHandler; #endif /* 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); #ifdef ENABLE_PRESSURE enablePressure(0); #endif 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) { LOGE("HAL:could not enable timestamp"); } if(fclose(tempFp) < 0) { LOGE("HAL:could not close 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) { LOGE("HAL:could not write buffer length"); } if (fclose(tempFp) < 0) { LOGE("HAL:could not close 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) { LOGE("HAL:could not write chip enable"); } if (fclose(tempFp) < 0) { LOGE("HAL:could not close 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) { LOGE("HAL:load DMP failed"); } else { LOGV_IF(PROCESS_VERBOSE, "HAL:DMP loaded"); } if (fclose(fptr) < 0) { LOGE("HAL:could not close dmp firmware"); } } } 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) { 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]; } if (fclose(fptr) < 0) { LOGE("HAL:Could not close gyro mounting matrix"); } } // 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) { 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]; } if (fclose(fptr) < 0) { LOGE("HAL:could not close accel mounting matrix"); } } } 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_offset_fd); } if (gyro_y_offset_fd > 0) { close(gyro_y_offset_fd); } if (gyro_z_offset_fd > 0) { close(gyro_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 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) #ifdef ENABLE_PRESSURE #define PS_ENABLED ((1 << ID_PS) & enabled_sensors) #endif /* 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 & ~INV_DMP_BATCH_MODE) & 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::computeDmpState(bool* dmp_state) { 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"); } }*/ *dmp_state = dmpState; return res; } int MPLSensor::SetDmpState(bool dmpState) { int res = 0; // 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")); mDmpState = dmpState; return dmpState; } int MPLSensor::computeAndSetDmpState() { int res = 0; bool dmpState = 0; computeDmpState(&dmpState); res = SetDmpState(dmpState); if (res < 0) return res; 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: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; } } } else { //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; } } 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::checkPedStandaloneBatched(void) { VFUNC_LOG; int res = 0; if ((mFeatureActiveMask & INV_DMP_PEDOMETER) && (mBatchEnabled & (1 << StepDetector))) { res = 1; } else res = 0; LOGV_IF(ENG_VERBOSE, "HAL:checkPedStandaloneBatched=%d", res); 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::setPedQuaternionRate(int64_t wanted) { VFUNC_LOG; int res = 0; LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", int(1000000000.f / wanted), mpu.ped_q_rate, getTimestamp()); res = write_sysfs_int(mpu.ped_q_rate, 1000000000.f / wanted); LOGV_IF(PROCESS_VERBOSE, "HAL:DMP ped quaternion rate %.2f Hz", 1000000000.f / wanted); 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; } int MPLSensor::set6AxisQuaternionRate(int64_t wanted) { VFUNC_LOG; int res = 0; LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", int(1000000000.f / wanted), mpu.six_axis_q_rate, getTimestamp()); res = 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); 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::setQuaternionRate(int64_t wanted) { VFUNC_LOG; int res = 0; LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)", int(1000000000.f / wanted), mpu.three_axis_q_rate, getTimestamp()); res = 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); 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) { if(!checkPedStandaloneBatched()) { //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; } mt_pre_ns = android::elapsedRealtimeNano(); } 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 (!mBatchEnabled && (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; } #ifdef ENABLE_PRESSURE int MPLSensor::enablePressure(int en) { VFUNC_LOG; int res = 0; if (mPressureSensor) res = mPressureSensor->enable(ID_PS, en); return res; } #endif /* 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 { #ifdef ENABLE_PRESSURE /* 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; } #else LOGV_IF(ENG_VERBOSE, "PS DISABLED"); mLocalSensorMask &= ~INV_ONE_AXIS_PRESSURE; #endif 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; } #ifdef ENABLE_PRESSURE if(!A_ENABLED && !M_ENABLED && !RM_ENABLED && !GRV_ENABLED && !GMRV_ENABLED && !GY_ENABLED && !RGY_ENABLED && !PS_ENABLED) { #else if(!A_ENABLED && !M_ENABLED && !RM_ENABLED && !GRV_ENABLED && !GMRV_ENABLED && !GY_ENABLED && !RGY_ENABLED) { #endif /* 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) | #ifdef ENABLE_PRESSURE (mPressureSensor->isIntegrated() << Pressure) | #endif (mCompassSensor->isIntegrated() << RawMagneticField))) { /* 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; } } #ifdef ENABLE_PRESSURE 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; } } #endif 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) | #ifdef ENABLE_PRESSURE (mPressureSensor->isIntegrated() << Pressure) | #endif (mCompassSensor->isIntegrated() << RawMagneticField))) { 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 #ifdef ENABLE_PRESSURE | (INV_ONE_AXIS_PRESSURE * mPressureSensor->isIntegrated()) #endif | (INV_THREE_AXIS_COMPASS * mCompassSensor->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 <= LAST_HW_SENSOR; 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 < NumSensors; 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_IF(ENG_VERBOSE, "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; } } /* step detector is enabled and */ /* batch mode is standalone */ if (en && (mFeatureActiveMask & INV_DMP_PEDOMETER) && (featureMask & INV_DMP_PED_STANDALONE)) { LOGV_IF(ENG_VERBOSE, "setBatch: 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, "setBatch: ID_P and GRV or ALL = 0x%x", mBatchEnabled); LOGV_IF(ENG_VERBOSE, "setBatch: 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, "setBatch: GRV = 0x%x", mBatchEnabled); enableLPQuaternion(0); enable6AxisQuaternion(1); setInitial6QuatValue(); } else if (!(featureMask & INV_DMP_PED_QUATERNION)){ LOGV_IF(ENG_VERBOSE, "setBatch: Toggle back to normal 6 axis"); if (mEnabled & (1 << GameRotationVector)) { enableLPQuaternion(checkLPQRateSupported()); } enable6AxisQuaternion(0); } else { enable6AxisQuaternion(0); } writeBatchTimeout(en); 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; } int MPLSensor::calcBatchTimeout(int en, int64_t *out) { VFUNC_LOG; int64_t timeoutInMs = 0; if (en) { /* take the minimum batchmode timeout */ int64_t timeout = 100000000000LL; int64_t ns = 0; 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))) || (checkPedStandaloneBatched() && (i == 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; } *out = timeoutInMs; return 0; } int MPLSensor::writeBatchTimeout(int en, int64_t timeoutInMs) { VFUNC_LOG; if(mBatchTimeoutInMs != timeoutInMs) { /* 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"); } } /* remember last timeout value */ mBatchTimeoutInMs = timeoutInMs; return 0; } int MPLSensor::writeBatchTimeout(int en) { VFUNC_LOG; int64_t timeoutInMs = 0; calcBatchTimeout(en, &timeoutInMs); LOGV_IF(PROCESS_VERBOSE, "HAL: batch timeout set to %lld ms", timeoutInMs); writeBatchTimeout(en, timeoutInMs); return 0; } /* 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_gyroscope(s->gyro.v, &s->gyro.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_gyroscope(s->gyro.v, &s->gyro.status, &s->timestamp); #endif if (!mEnabledTime[Gyro] || !(s->timestamp > mEnabledTime[Gyro])) { LOGV_IF(ENG_VERBOSE, "HAL:gyro incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[Gyro], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_gyroscope_raw(s->uncalibrated_gyro.uncalib, &s->gyro.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_gyroscope_raw(s->uncalibrated_gyro.uncalib, &s->gyro.status, &s->timestamp); #endif if (!mEnabledTime[RawGyro] || !(s->timestamp > mEnabledTime[RawGyro])) { LOGV_IF(ENG_VERBOSE, "HAL:raw gyro incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[RawGyro], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_accelerometer( s->acceleration.v, &s->acceleration.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_accelerometer( s->acceleration.v, &s->acceleration.status, &s->timestamp); #endif if (!mEnabledTime[Accelerometer] || !(s->timestamp > mEnabledTime[Accelerometer])) { LOGV_IF(ENG_VERBOSE, "HAL:accel incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[Accelerometer], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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; int overflow = mCompassOverFlow; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_magnetic_field( s->magnetic.v, &s->magnetic.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_magnetic_field( s->magnetic.v, &s->magnetic.status, &s->timestamp); #endif if (!mEnabledTime[MagneticField] || !(s->timestamp > mEnabledTime[MagneticField])) { LOGV_IF(ENG_VERBOSE, "HAL:compass incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[MagneticField], s->timestamp, android::elapsedRealtimeNano()); overflow = 0; update = 0; } 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 | overflow; } int MPLSensor::rawCompassHandler(sensors_event_t* s) { VHANDLER_LOG; int update; int overflow = mCompassOverFlow; //TODO: need to handle uncalib data and bias for 3rd party compass #if defined ANDROID_LOLLIPOP if(mCompassSensor->providesCalibration()) { update = mCompassSensor->readRawSample(s->uncalibrated_magnetic.uncalib, (int64_t *)(&s->timestamp)); } else { update = inv_get_sensor_type_magnetic_field_raw(s->uncalibrated_magnetic.uncalib, &s->magnetic.status, (inv_time_t *)(&s->timestamp)); } #else 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); } #endif if (!mEnabledTime[RawMagneticField] || !(s->timestamp > mEnabledTime[RawMagneticField])) { LOGV_IF(ENG_VERBOSE, "HAL:raw compass incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[RawMagneticField], s->timestamp, android::elapsedRealtimeNano()); overflow = 0; update = 0; } 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 | overflow; } /* 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_rotation_vector(s->data, &status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_rotation_vector(s->data, &status, &s->timestamp); #endif s->orientation.status = status; update |= isCompassDisabled(); if (!mEnabledTime[RotationVector] || !(s->timestamp > mEnabledTime[RotationVector])) { LOGV_IF(ENG_VERBOSE, "HAL:rv incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[RotationVector], s->timestamp, android::elapsedRealtimeNano()); update = 0; } LOGV_IF(HANDLER_DATA, "HAL:rv data: %+f %+f %+f %+f %+f %d- %+lld - %d", s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->orientation.status, 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_rotation_vector_6_axis(s->data, &status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_rotation_vector_6_axis(s->data, &status, &s->timestamp); #endif s->orientation.status = status; if (!mEnabledTime[GameRotationVector] || !(s->timestamp > mEnabledTime[GameRotationVector])) { LOGV_IF(ENG_VERBOSE, "HAL:grv incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[GameRotationVector], s->timestamp, android::elapsedRealtimeNano()); update = 0; } LOGV_IF(HANDLER_DATA, "HAL:grv data: %+f %+f %+f %+f %+f %d- %+lld - %d", s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->orientation.status, s->timestamp, update); return update; } int MPLSensor::laHandler(sensors_event_t* s) { VHANDLER_LOG; int update; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_linear_acceleration( s->gyro.v, &s->gyro.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_linear_acceleration( s->gyro.v, &s->gyro.status, &s->timestamp); #endif update |= isCompassDisabled(); if (!mEnabledTime[LinearAccel] || !(s->timestamp > mEnabledTime[LinearAccel])) { LOGV_IF(ENG_VERBOSE, "HAL:la incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[LinearAccel], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_gravity(s->gyro.v, &s->gyro.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_gravity(s->gyro.v, &s->gyro.status, &s->timestamp); #endif update |= isCompassDisabled(); if (!mEnabledTime[Gravity] || !(s->timestamp > mEnabledTime[Gravity])) { LOGV_IF(ENG_VERBOSE, "HAL:gr incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[Gravity], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_orientation( s->orientation.v, &s->orientation.status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_orientation( s->orientation.v, &s->orientation.status, &s->timestamp); #endif update |= isCompassDisabled(); if (!mEnabledTime[Orientation] || !(s->timestamp > mEnabledTime[Orientation])) { LOGV_IF(ENG_VERBOSE, "HAL:or incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[Orientation], s->timestamp, android::elapsedRealtimeNano()); update = 0; } 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 */ s->timestamp = android::elapsedRealtimeNano(); if (!mEnabledTime[SignificantMotion] || !(s->timestamp > mEnabledTime[SignificantMotion])) { LOGV_IF(ENG_VERBOSE, "HAL:sm incorrect timestamp Enabled=%lld, Timestamp=%lld", mEnabledTime[SignificantMotion], s->timestamp); update = 0; } 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; #if defined ANDROID_LOLLIPOP update = inv_get_sensor_type_geomagnetic_rotation_vector(s->data, &status, (inv_time_t *)(&s->timestamp)); #else update = inv_get_sensor_type_geomagnetic_rotation_vector(s->data, &status, &s->timestamp); #endif s->orientation.status = status; if (!mEnabledTime[GeomagneticRotationVector] || !(s->timestamp > mEnabledTime[GeomagneticRotationVector])) { LOGV_IF(ENG_VERBOSE, "HAL:gm incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[GeomagneticRotationVector], s->timestamp, android::elapsedRealtimeNano()); update = 0; } LOGV_IF(HANDLER_DATA, "HAL:gm data: %+f %+f %+f %+f %+f %d- %+lld - %d", s->data[0], s->data[1], s->data[2], s->data[3], s->data[4], s->orientation.status, 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; #ifdef ENABLE_PRESSURE if (!mEnabledTime[Pressure] || !(s->timestamp > mEnabledTime[Pressure])) { LOGV_IF(ENG_VERBOSE, "HAL:ps incorrect timestamp Enabled=%lld, Timestamp=%lld, Now=%lld", mEnabledTime[Pressure], s->timestamp, android::elapsedRealtimeNano()); update = 0; } #endif 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 */ s->timestamp = android::elapsedRealtimeNano(); 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 || defined ANDROID_LOLLIPOP 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 if (s->timestamp == 0 && update) { s->timestamp = android::elapsedRealtimeNano(); } return update; } int MPLSensor::metaHandler(sensors_event_t* s, int flags) { VHANDLER_LOG; int update = 1; #if defined ANDROID_KITKAT || defined ANDROID_LOLLIPOP /* initalize SENSOR_TYPE_META_DATA */ s->version = 0; s->sensor = 0; s->reserved0 = 0; s->timestamp = 0LL; switch(flags) { case META_DATA_FLUSH_COMPLETE: s->type = SENSOR_TYPE_META_DATA; s->version = META_DATA_VERSION; s->meta_data.what = flags; s->meta_data.sensor = mFlushSensorEnabledVector[0]; mFlushSensorEnabledVector.removeAt(0); 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 1; } 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; /* set called flag */ mEnableCalled = 1; if (!en) mBatchEnabled &= ~(1 << handle); LOGV_IF(ENG_VERBOSE, "HAL: MPLSensor::enable(handle = %d, en = %d)", handle, en); 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; if (en) mEnabledTime[StepCounter] = android::elapsedRealtimeNano(); else mEnabledTime[StepCounter] = 0; if (!en) mBatchDelays[what] = 1000000000LL; return 0; case ID_P: what = StepDetector; 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; if (en) mEnabledTime[StepDetector] = android::elapsedRealtimeNano(); else mEnabledTime[StepDetector] = 0; if (!en) mBatchDelays[what] = 1000000000LL; 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; if (en) mEnabledTime[SignificantMotion] = android::elapsedRealtimeNano(); else mEnabledTime[SignificantMotion] = 0; 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; #ifdef ENABLE_PRESSURE case ID_PS: what = Pressure; sname = "Pressure"; break; #endif 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); if (lastEnabled > mEnabled) { mEnabledCached = mEnabled; } else { mEnabledCached = lastEnabled; } 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; #ifdef ENABLE_PRESSURE case Pressure: if ((lastEnabled & (1 << what)) != (mEnabled & (1 << what))) { changed |= (1 << what); } break; #endif 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); // update mEnabledCached afer all configurations done mEnabledCached = mEnabled; if (en) mEnabledTime[what] = android::elapsedRealtimeNano(); else mEnabledTime[what] = 0; if (!en) mBatchDelays[what] = 1000000000LL; } // 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; #ifdef ENABLE_PRESSURE case ID_PS: what = Pressure; sname = "Pressure"; break; #endif 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; #ifdef ENABLE_PRESSURE int64_t pressureRate; #endif 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; #ifdef ENABLE_PRESSURE pressureRate = wanted; #endif // 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)); } #ifdef ENABLE_PRESSURE 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"); } #endif } } //end of non batch mode unsigned long sensors = mLocalSensorMask & mMasterSensorMask; if (sensors & (INV_THREE_AXIS_GYRO | INV_THREE_AXIS_ACCEL #ifdef ENABLE_PRESSURE | (INV_ONE_AXIS_PRESSURE * mPressureSensor->isIntegrated()) #endif | (INV_THREE_AXIS_COMPASS * mCompassSensor->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; } /** * 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; if (!mSkipExecuteOnData) inv_execute_on_data(); int numEventReceived = 0; long msg; if (count <= 0) return 0; 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(); } } if (!mSkipReadEvents) { 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) { if (mLastTimestamp[i] != mStepSensorTimestamp) { count--; numEventReceived++; data->timestamp = mStepSensorTimestamp; data++; mLastTimestamp[i] = mStepSensorTimestamp; } else { ALOGE("Event from type=%d with duplicate timestamp %lld discarded", mPendingEvents[i].type, mStepSensorTimestamp); } continue; } } else { if (mPedUpdate == DATA_FORMAT_STEP) { continue; } } } // load up virtual sensors if (mEnabledCached & (1 << i)) { update = CALL_MEMBER_FN(this, mHandlers[i])(mPendingEvents + i); mPendingMask |= (1 << i); if (update && (count > 0)) { // Discard any events with duplicate timestamps if (mLastTimestamp[i] != mPendingEvents[i].timestamp) { mLastTimestamp[i] = mPendingEvents[i].timestamp; *data++ = mPendingEvents[i]; count--; numEventReceived++; } else { ALOGE("Event from type=%d with duplicate timestamp %lld (%+f, %+f, %+f) discarded", mPendingEvents[i].type, mLastTimestamp[i], mPendingEvents[i].data[0], mPendingEvents[i].data[1], mPendingEvents[i].data[2]); } } } mCompassOverFlow = 0; // handle partial packet read and end marker // skip readEvents from hal_outputs if (mFlushBatchSet && count>0 && !mFlushSensorEnabledVector.isEmpty()) { while (mFlushBatchSet && count>0 && !mFlushSensorEnabledVector.isEmpty()) { int sendEvent = metaHandler(&mPendingFlushEvents[0], META_DATA_FLUSH_COMPLETE); if (sendEvent) { LOGV_IF(ENG_VERBOSE, "Queueing flush complete for handle=%d", mPendingFlushEvents[0].meta_data.sensor); *data++ = mPendingFlushEvents[0]; count--; numEventReceived++; } else { LOGV_IF(ENG_VERBOSE, "sendEvent false, NOT queueing flush complete for handle=%d", mPendingFlushEvents[0].meta_data.sensor); } mFlushBatchSet--; } // Double check flush status if (mFlushSensorEnabledVector.isEmpty()) { mEmptyDataMarkerDetected = 0; mDataMarkerDetected = 0; mFlushBatchSet = 0; LOGV_IF(ENG_VERBOSE, "Flush completed"); } else { LOGV_IF(ENG_VERBOSE, "Flush is still active"); } } else if (mFlushBatchSet && mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet = 0; } } } 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); char *rdata = mIIOBuffer; ssize_t rsize = 0; ssize_t readCounter = 0; char *rdataP = NULL; bool doneFlag = 0; /* flush buffer when no sensors are enabled */ if (mEnabledCached == 0 && mBatchEnabled == 0 && mDmpPedometerEnabled == 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); } mLeftOverBufferSize = 0; mDataMarkerDetected = 0; mEmptyDataMarkerDetected = 0; return; } lp_quaternion_on = isLowPowerQuatEnabled() && 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(mIIOBuffer)); 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 /* reset data and count pointer */ rdataP = rdata; readCounter = rsize + mLeftOverBufferSize; LOGV_IF(0, "HAL:input readCounter set=%d", (int)readCounter); if(readCounter < MAX_READ_SIZE) { // Handle standalone MARKER packet if (readCounter >= BYTES_PER_SENSOR) { data_format = *((short *)(rdata)); if (data_format == DATA_FORMAT_MARKER) { LOGV_IF(ENG_VERBOSE && INPUT_DATA, "MARKER DETECTED:0x%x", data_format); readCounter -= BYTES_PER_SENSOR; rdata += BYTES_PER_SENSOR; if (!mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet++; } mDataMarkerDetected = 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; rdata += BYTES_PER_SENSOR; if (!mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet++; } mEmptyDataMarkerDetected = 1; mDataMarkerDetected = 1; } } /* store packet then return */ mLeftOverBufferSize = readCounter; 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; } 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); mSkipExecuteOnData = 1; 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; // 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 (!mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet++; } mDataMarkerDetected = 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 (!mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet++; } mEmptyDataMarkerDetected = 1; mDataMarkerDetected = 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_COMPASS_OF) { LOGV_IF(ENG_VERBOSE && INPUT_DATA, "COMPASS OF DETECTED:0x%x", data_format); mask |= DATA_FORMAT_COMPASS_OF; mCompassOverFlow = 1; #ifdef INV_PLAYBACK_DBG 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)); readCounter -= BYTES_PER_SENSOR_PACKET; } } #else readCounter -= BYTES_PER_SENSOR; #endif } #ifdef ENABLE_PRESSURE 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; } } #endif 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)); /* check for end markers, don't save */ data_format = *((short *) (rdata)); if ((data_format == DATA_FORMAT_MARKER) || (data_format == DATA_FORMAT_EMPTY_MARKER)) { LOGV_IF(ENG_VERBOSE && INPUT_DATA, "s MARKER DETECTED:0x%x", data_format); rdata += BYTES_PER_SENSOR; readCounter -= BYTES_PER_SENSOR; if (!mFlushSensorEnabledVector.isEmpty()) { mFlushBatchSet++; } mDataMarkerDetected = 1; if (readCounter == 0) { mLeftOverBufferSize = 0; if(doneFlag != 0) { return; } } } 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]); mSkipExecuteOnData = 0; } #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); mSkipExecuteOnData = 0; 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); mSkipExecuteOnData = 0; /* 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_OF) { /* compass overflow detected */ /* reset compass algorithm */ int status = 0; inv_build_compass(mCachedCompassData, status, mCompassTimestamp); LOGV_IF(INPUT_DATA, "HAL:input inv_build_compass_of: %+8ld %+8ld %+8ld - %lld", mCachedCompassData[0], mCachedCompassData[1], mCachedCompassData[2], mCompassTimestamp); mSkipExecuteOnData = 0; resetCompass(); } 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); mSkipExecuteOnData = 0; 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); mSkipExecuteOnData = 0; 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); mSkipExecuteOnData = 0; 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); mSkipExecuteOnData = 0; latestTimestamp = mQuatSensorTimestamp; } #ifdef ENABLE_PRESSURE if ((mask ==DATA_FORMAT_PRESSURE) && mPressureSensor->isIntegrated()) { int status = 0; latestTimestamp = mPressureTimestamp; mPressureUpdate = 1; inv_build_pressure(mCachedPressureData, status, mPressureTimestamp); LOGV_IF(INPUT_DATA, "HAL:input inv_build_pressure: %+8ld - %lld", mCachedPressureData, mPressureTimestamp); mSkipExecuteOnData = 0; } #endif /* take the latest timestamp */ if (mPedUpdate & 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 { LOGV_IF(ENG_VERBOSE, "Step data OUT OF ORDER, " "mPedUpdate = 0x%x last = %lld, ts = %lld", mPedUpdate, mStepSensorTimestamp, latestTimestamp); mPedUpdate = 0; } } } //while end } int MPLSensor::checkValidHeader(unsigned short data_format) { LOGV_IF(ENG_VERBOSE && INPUT_DATA, "check data_format=%x", data_format); if(data_format == DATA_FORMAT_STEP) return 1; if(data_format & DATA_FORMAT_STEP) { data_format &= (~DATA_FORMAT_STEP); } 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) || (data_format == DATA_FORMAT_COMPASS_OF)) 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; } 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); mSkipReadEvents = 0; mSkipExecuteOnData = 0; } // 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(); inv_init_magnetic_disturbance(); inv_vector_compass_cal_sensitivity(3); } //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 temp.timestamp = android::elapsedRealtimeNano(); *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) { setQuaternionRate(*wanted); if (mFeatureActiveMask & INV_DMP_BATCH_MODE) { set6AxisQuaternionRate(*wanted); setPedQuaternionRate(*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; if (mDmpStepCountEnabled) { // convert poll time from nS to mS return (mStepCountPollTime / 1000000LL); } return 1000; } bool MPLSensor::hasStepCountPendingEvents(void) { VFUNC_LOG; if (mDmpStepCountEnabled) { int64_t t_now_ns; int64_t interval = 0; t_now_ns = android::elapsedRealtimeNano(); interval = t_now_ns - mt_pre_ns; if (interval < mStepCountPollTime) { LOGV_IF(0, "Step Count interval elapsed: %lld, triggered: %lld", interval, mStepCountPollTime); return false; } else { mt_pre_ns = android::elapsedRealtimeNano(); LOGV_IF(0, "Step Count previous time: %lld ms", mt_pre_ns / 1000000); 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]); #ifdef ENABLE_PRESSURE if (mPressureSensor != NULL) { mPressureSensor->fillList(&list[Pressure]); } #endif 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, "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, "MPU9255") == 0) { list[Accelerometer].maxRange = ACCEL_MPU9255_RANGE; list[Accelerometer].resolution = ACCEL_MPU9255_RESOLUTION; list[Accelerometer].power = ACCEL_MPU9255_POWER; list[Accelerometer].minDelay = ACCEL_MPU9255_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, "MPU9255") == 0) { list[Gyro].maxRange = GYRO_MPU9255_RANGE; list[Gyro].resolution = GYRO_MPU9255_RESOLUTION; list[Gyro].power = GYRO_MPU9255_POWER; list[Gyro].minDelay = GYRO_MPU9255_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; char sysfs_path[MAX_SYSFS_NAME_LEN]; memset(sysfs_path, 0, sizeof(sysfs_path)); sysfs_names_ptr = (char*)calloc(MAX_SYSFS_ATTRB, sizeof(char[MAX_SYSFS_NAME_LEN])); if (sysfs_names_ptr == NULL) { LOGE("HAL:couldn't alloc mem for sysfs paths"); return -1; } char *sptr = sysfs_names_ptr; char **dptr = reinterpret_cast<char **>(&mpu); for (size_t i = 0; i < MAX_SYSFS_ATTRB; i++) { *dptr++ = sptr; sptr += sizeof(char[MAX_SYSFS_NAME_LEN]); } // 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_step_thresh, "%s%s", sysfs_path, "/pedometer_step_thresh"); 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 && INPUT_DATA, "Mpl Gyro Bias (HW unit) %ld %ld %ld", mGyroChipBias[0], mGyroChipBias[1], mGyroChipBias[2]); LOGV_IF(ENG_VERBOSE && INPUT_DATA, "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; } else if (period_ns > 200000000LL) { period_ns = 200000000LL; } LOGV_IF(PROCESS_VERBOSE, "HAL:batch after applying upper and lower limit: %llu ns, (%.2f Hz)", period_ns, 1000000000.f / period_ns); LOGV_IF(PROCESS_VERBOSE, "HAL:batch after applying upper and lower limit: %llu ns, (%.2f Hz)", period_ns, 1000000000.f / period_ns); switch (what) { case Gyro: case RawGyro: case Accelerometer: #ifdef ENABLE_PRESSURE case Pressure: #endif case GameRotationVector: case StepDetector: LOGV_IF(PROCESS_VERBOSE, "HAL: batch - select sensor (handle %d)", handle); break; case MagneticField: case RawMagneticField: if(timeout > 0 && !mCompassSensor->isIntegrated()) return -EINVAL; else 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; } if (what == StepCounter) { mStepCountPollTime = period_ns; LOGI("HAL: set step count poll time = %lld nS (%.2f Hz)", mStepCountPollTime, 1000000000.f / mStepCountPollTime); } 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; } #ifdef ENABLE_PRESSURE if (i == Pressure) { nBytes += 6; } #endif 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] = 1000000000LL; mDelays[what] = period_ns; mBatchTimeouts[what] = 100000000000LL; } else { mBatchEnabled |= (1 << what); mBatchDelays[what] = period_ns; mDelays[what] = period_ns; mBatchTimeouts[what] = timeout; } // Check if need to change configurations int master_enable_call = 0; int64_t tmp_batch_timeout = 0; bool tmp_dmp_state = 0; int64_t tmp_gyro_rate; int64_t tmp_accel_rate; int64_t tmp_compass_rate; int64_t tmp_pressure_rate; int64_t tmp_quat_rate; int64_t tmp_reset_rate; bool skip_reset_data_rate = false; if (mFirstBatchCall) { LOGI_IF(0, "HAL: mFirstBatchCall = %d", mFirstBatchCall); master_enable_call++; mFirstBatchCall = 0; } if (mEnableCalled) { LOGI_IF(0, "HAL: mEnableCalled = %d", mEnableCalled); master_enable_call++; mEnableCalled = 0; } if(((int)mOldBatchEnabledMask != batchMode) || batchMode) { calcBatchTimeout(batchMode, &tmp_batch_timeout); if (tmp_batch_timeout != mBatchTimeoutInMs) master_enable_call++; if (computeDmpState(&tmp_dmp_state) < 0) { LOGE("HAL:ERR can't compute dmp state"); } if (tmp_dmp_state != mDmpState) master_enable_call++; } if (batchMode == 1) { if (calcBatchDataRates(&tmp_gyro_rate, &tmp_accel_rate, &tmp_compass_rate, &tmp_pressure_rate, &tmp_quat_rate) < 0) { LOGE("HAL:ERR can't get batch data rates"); } if (tmp_gyro_rate != mGyroBatchRate) master_enable_call++; if (tmp_accel_rate != mAccelBatchRate) master_enable_call++; if (tmp_compass_rate != mCompassBatchRate) master_enable_call++; if (tmp_pressure_rate != mPressureBatchRate) master_enable_call++; if (tmp_quat_rate != mQuatBatchRate) master_enable_call++; } else { if (calctDataRates(&tmp_reset_rate, &tmp_gyro_rate, &tmp_accel_rate, &tmp_compass_rate, &tmp_pressure_rate) < 0) { skip_reset_data_rate = true; LOGV_IF(ENG_VERBOSE, "HAL:ERR can't get output rate back to original setting"); } if (tmp_reset_rate != mResetRate) master_enable_call++; if (tmp_gyro_rate != mGyroRate) master_enable_call++; if (tmp_accel_rate != mAccelRate) master_enable_call++; if (tmp_compass_rate != mCompassRate) master_enable_call++; if (tmp_pressure_rate != mPressureRate) master_enable_call++; } uint32_t dataInterrupt = (mEnabled || (mFeatureActiveMask & INV_DMP_BATCH_MODE)); if (dataInterrupt != mDataInterrupt) master_enable_call++; if (master_enable_call == 0) { LOGI_IF(0, "HAL: Skip batch configurations"); goto batch_end; } else { LOGI_IF(0, "HAL: Do batch configurations"); } // 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]); } } /* case for Ped standalone */ if ((batchMode == 1) && (featureMask & INV_DMP_PED_STANDALONE) && (mFeatureActiveMask & INV_DMP_PEDOMETER)) { LOGI_IF(ENG_VERBOSE, "batch - 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_IF(ENG_VERBOSE, "batch - ID_P and GRV or ALL = 0x%x", mBatchEnabled); LOGI_IF(ENG_VERBOSE, "batch - ID_P is enabled for batching, PED quat will be automatically enabled"); enableLPQuaternion(0); enablePedQuaternion(1); /* set pedq rate */ wanted = mBatchDelays[GameRotationVector]; setPedQuaternionRate(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_IF(ENG_VERBOSE, "batch - GRV = 0x%x", mBatchEnabled); enableLPQuaternion(0); enable6AxisQuaternion(1); if (what == GameRotationVector) { setInitial6QuatValue(); } /* set sixaxis rate */ wanted = mBatchDelays[GameRotationVector]; set6AxisQuaternionRate(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"); } }*/ writeBatchTimeout(batchMode, tmp_batch_timeout); if (SetDmpState(tmp_dmp_state) < 0) { LOGE("HAL:ERR can't set dmp state"); } }//end of batch mode modify if (batchMode == 1) { /* set batch rates */ if (setBatchDataRates(tmp_gyro_rate, tmp_accel_rate, tmp_compass_rate, tmp_pressure_rate, tmp_quat_rate) < 0) { LOGE("HAL:ERR can't set batch data rates"); } } else { /* reset sensor rate */ if (!skip_reset_data_rate) { if (resetDataRates(tmp_reset_rate, tmp_gyro_rate, tmp_accel_rate, tmp_compass_rate, tmp_pressure_rate) < 0) { LOGE("HAL:ERR can't reset output rate back to original setting"); } } } // set sensor data interrupt 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"); } mDataInterrupt = dataInterrupt; if (enabled_sensors || mFeatureActiveMask) { masterEnable(1); } batch_end: 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; } LOGV_IF(PROCESS_VERBOSE, "HAL: flush - select sensor %s (handle %d)", sname.string(), handle); if (((what != StepDetector) && (!(mEnabled & (1 << what)))) || ((what == StepDetector) && !(mFeatureActiveMask & INV_DMP_PEDOMETER))) { LOGV_IF(ENG_VERBOSE, "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); } mFlushSensorEnabledVector.push_back(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) LOGE("HAL: flush - error invoking flush_batch"); /* driver returns 0 if FIFO is empty */ if (res == 0) { LOGV_IF(ENG_VERBOSE, "HAL: flush - no data in FIFO"); } LOGV_IF(ENG_VERBOSE, "HAl:flush - mFlushSensorEnabledVector=%d res=%d status=%d", handle, res, status); return 0; } 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); /* set pedq rate */ wanted = mBatchDelays[GameRotationVector]; setPedQuaternionRate(wanted); } else if ((featureMask & INV_DMP_6AXIS_QUATERNION) && (mEnabled & (1 << GameRotationVector))) { enableLPQuaternion(0); enablePedQuaternion(0); setInitial6QuatValue(); enable6AxisQuaternion(1); /* set sixaxis rate */ wanted = mBatchDelays[GameRotationVector]; set6AxisQuaternionRate(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) #ifdef ENABLE_PRESSURE | (1 << Pressure) #endif | (1 << RawMagneticField); 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) { LOGV_IF(PROCESS_VERBOSE, "HAL:cannot read pedometer_steps"); if (fclose(fp) < 0) { LOGW("HAL:cannot close pedometer_steps"); } return 0; } if (fclose(fp) < 0) { LOGW("HAL:cannot close pedometer_steps"); } } /* 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) { LOGE("HAL:cannot read pedometer_counter"); if (fclose(fp) < 0) { LOGE("HAL:cannot close pedometer_counter"); } return 0; } if (fclose(fp) < 0) { LOGE("HAL:cannot close 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 vibrator = 0; FILE *fp; int sensors = mEnabled; int numEventReceived = 0; int update = 0; static int64_t lastVibTrigger = 0; if (mDmpSignificantMotionEnabled && count > 0) { // If vibrator is going off, ignore this event fp = fopen(VIBRATOR_ENABLE_FILE, "r"); if (fp != NULL) { if (fscanf(fp, "%d\n", &vibrator) < 0) { LOGE("HAL:cannot read %s", VIBRATOR_ENABLE_FILE); } if (fclose(fp) < 0) { LOGE("HAL:cannot close %s", VIBRATOR_ENABLE_FILE); } if (vibrator != 0) { lastVibTrigger = android::elapsedRealtimeNano(); LOGV_IF(ENG_VERBOSE, "SMD triggered by vibrator, ignoring SMD event"); return 0; } else if (lastVibTrigger) { // vibrator recently triggered SMD, discard related events int64_t now = android::elapsedRealtimeNano(); if ((now - lastVibTrigger) < MIN_TRIGGER_TIME_AFTER_VIBRATOR_NS) { LOGV_IF(ENG_VERBOSE, "HAL: SMD triggered too close to vibrator (delta %lldnS), ignoring", (now-lastVibTrigger)); return 0; } else { LOGV_IF(ENG_VERBOSE, "HAL: SMD triggered %lld after vibrator (last %lld now %lld)", now-lastVibTrigger, lastVibTrigger, now); lastVibTrigger = 0; } } } else { LOGE("HAL:cannot open %s", VIBRATOR_ENABLE_FILE); } /* 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; /* auto disable this sensor */ enableDmpSignificantMotion(0); } } // 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 (!mBatchEnabled && (resetDataRates() < 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:sysfs:echo quat value > %s", mpu.six_axis_q_value); LOGV_IF(EXTRA_VERBOSE && ENG_VERBOSE, "quat=%ld,%ld,%ld,%ld", mInitial6QuatValue[0], mInitial6QuatValue[1], mInitial6QuatValue[2], mInitial6QuatValue[3]); 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) { LOGE("HAL:write six axis q value failed"); } else { mInitial6QuatValueAvailable = 0; } if (fclose(fptr) < 0) { LOGE("HAL:could not close six_axis_q_value"); } } 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; } int MPLSensor::calcBatchDataRates(int64_t *gyro_rate, int64_t *accel_rate, int64_t *compass_rate, int64_t *pressure_rate, int64_t *quat_rate) { VFUNC_LOG; int res = 0; int tempFd = -1; int64_t gyroRate; int64_t accelRate; int64_t compassRate; #ifdef ENABLE_PRESSURE int64_t pressureRate; #endif int64_t quatRate = 0; 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]; #ifdef ENABLE_PRESSURE pressureRate = mBatchDelays[Pressure]; #endif //ENABLE_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; #ifdef ENABLE_PRESSURE pressureRate = wanted; #endif #endif *gyro_rate = gyroRate; *accel_rate = accelRate; *compass_rate = compassRate; #ifdef ENABLE_PRESSURE *pressure_rate = pressureRate; #endif *quat_rate = quatRate; return 0; } int MPLSensor::MPLSensor::setBatchDataRates(int64_t gyroRate, int64_t accelRate, int64_t compassRate, int64_t pressureRate, int64_t quatRate) { VFUNC_LOG; int res = 0; int tempFd = -1; if ((mFeatureActiveMask & INV_DMP_PED_QUATERNION) || (mFeatureActiveMask & INV_DMP_6AXIS_QUATERNION)) { getDmpRate(&quatRate); } /* 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); #ifdef ENABLE_PRESSURE /* takes care of pressure rate */ mPressureSensor->setDelay(ID_PS, pressureRate); #endif mGyroBatchRate = gyroRate; mAccelBatchRate = accelRate; mCompassBatchRate = compassRate; mPressureBatchRate = pressureRate; mQuatBatchRate = quatRate; return res; } /* set batch data rate */ /* this function should be optimized */ int MPLSensor::setBatchDataRates() { VFUNC_LOG; int res = 0; int64_t gyroRate; int64_t accelRate; int64_t compassRate; int64_t pressureRate; int64_t quatRate; calcBatchDataRates(&gyroRate, &accelRate, &compassRate, &pressureRate, &quatRate); setBatchDataRates(gyroRate, accelRate, compassRate, pressureRate, quatRate); return res; } int MPLSensor::calctDataRates(int64_t *resetRate, int64_t *gyroRate, int64_t *accelRate, int64_t *compassRate, int64_t *pressureRate) { VFUNC_LOG; int res = 0; int tempFd = -1; int64_t wanted = 1000000000LL; if (!mEnabled) { LOGV_IF(ENG_VERBOSE, "skip resetDataRates"); return -1; } /* 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]; #ifdef ENABLE_PRESSURE if ((wanted == ns) && (i != Pressure)) { LOGV_IF(ENG_VERBOSE, "skip resetDataRates : same delay mDelays[%d]=%lld", i,mDelays[i]); //return 0; } #endif 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; return 0; } int MPLSensor::resetDataRates(int64_t resetRate, int64_t gyroRate, int64_t accelRate, int64_t compassRate, int64_t pressureRate) { VFUNC_LOG; int res = 0; int tempFd = -1; int64_t wanted; wanted = resetRate; /* 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); #ifdef ENABLE_PRESSURE /* takes care of pressure rate */ mPressureSensor->setDelay(ID_PS, pressureRate); #endif /* takes care of lpq case for data rate at 200Hz */ if (checkLPQuaternion()) { if (resetRate <= RATE_200HZ) { #ifndef USE_LPQ_AT_FASTEST enableLPQuaternion(0); #endif } } mResetRate = resetRate; mGyroRate = gyroRate; mAccelRate = accelRate; mCompassRate = compassRate; mPressureRate = pressureRate; return res; } /* Set sensor rate */ /* this function should be optimized */ int MPLSensor::resetDataRates() { VFUNC_LOG; int res = 0; int64_t resetRate; int64_t gyroRate; int64_t accelRate; int64_t compassRate; int64_t pressureRate; res = calctDataRates(&resetRate, &gyroRate, &accelRate, &compassRate, &pressureRate); if (res) return 0; resetDataRates(resetRate, gyroRate, accelRate, compassRate, pressureRate); 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; }