/* * Copyright (C) 2011 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, below #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 <dlfcn.h> #include <pthread.h> #include <cutils/log.h> #include <utils/KeyedVector.h> #include "MPLSensor.h" #include "math.h" #include "ml.h" #include "mlFIFO.h" #include "mlsl.h" #include "mlos.h" #include "ml_mputest.h" #include "ml_stored_data.h" #include "mldl_cfg.h" #include "mldl.h" #include "mpu.h" #include "accel.h" #include "compass.h" #include "kernel/timerirq.h" #include "kernel/mpuirq.h" #include "kernel/slaveirq.h" extern "C" { #include "mlsupervisor.h" } #include "mlcontrol.h" #include "sensor_params.h" #define EXTRA_VERBOSE (0) //#define FUNC_LOG LOGV("%s", __PRETTY_FUNCTION__) #define FUNC_LOG #define VFUNC_LOG LOGV_IF(EXTRA_VERBOSE, "%s", __PRETTY_FUNCTION__) /* this mask must turn on only the sensors that are present and managed by the MPL */ #define ALL_MPL_SENSORS_NP (INV_THREE_AXIS_ACCEL | INV_THREE_AXIS_COMPASS | INV_THREE_AXIS_GYRO) #define CALL_MEMBER_FN(pobject,ptrToMember) ((pobject)->*(ptrToMember)) /******************************************/ /* Base values for the sensor list, these need to be in the order defined in MPLSensor.h */ static struct sensor_t sSensorList[] = { { "MPL Gyroscope", "Invensense", 1, SENSORS_GYROSCOPE_HANDLE, SENSOR_TYPE_GYROSCOPE, 2000.0f, 1.0f, 0.5f, 10000, { } }, { "MPL Accelerometer", "Invensense", 1, SENSORS_ACCELERATION_HANDLE, SENSOR_TYPE_ACCELEROMETER, 10240.0f, 1.0f, 0.5f, 10000, { } }, { "MPL Magnetic Field", "Invensense", 1, SENSORS_MAGNETIC_FIELD_HANDLE, SENSOR_TYPE_MAGNETIC_FIELD, 10240.0f, 1.0f, 0.5f, 10000, { } }, { "MPL Orientation", "Invensense", 1, SENSORS_ORIENTATION_HANDLE, SENSOR_TYPE_ORIENTATION, 360.0f, 1.0f, 9.7f, 10000, { } }, { "MPL Rotation Vector", "Invensense", 1, SENSORS_ROTATION_VECTOR_HANDLE, SENSOR_TYPE_ROTATION_VECTOR, 10240.0f, 1.0f, 0.5f, 10000, { } }, { "MPL Linear Acceleration", "Invensense", 1, SENSORS_LINEAR_ACCEL_HANDLE, SENSOR_TYPE_LINEAR_ACCELERATION, 10240.0f, 1.0f, 0.5f, 10000, { } }, { "MPL Gravity", "Invensense", 1, SENSORS_GRAVITY_HANDLE, SENSOR_TYPE_GRAVITY, 10240.0f, 1.0f, 0.5f, 10000, { } }, }; static unsigned long long irq_timestamp = 0; /* *************************************************************************** * MPL interface misc. */ //static pointer to the object that will handle callbacks static MPLSensor* gMPLSensor = NULL; /* we need to pass some callbacks to the MPL. The mpl is a C library, so * wrappers for the C++ callback implementations are required. */ extern "C" { //callback wrappers go here void mot_cb_wrapper(uint16_t val) { if (gMPLSensor) { gMPLSensor->cbOnMotion(val); } } void procData_cb_wrapper() { if(gMPLSensor) { gMPLSensor->cbProcData(); } } } //end of extern C void setCallbackObject(MPLSensor* gbpt) { gMPLSensor = gbpt; } /***************************************************************************** * sensor class implementation */ #define GY_ENABLED ((1<<ID_GY) & enabled_sensors) #define A_ENABLED ((1<<ID_A) & enabled_sensors) #define O_ENABLED ((1<<ID_O) & enabled_sensors) #define M_ENABLED ((1<<ID_M) & 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) MPLSensor::MPLSensor() : SensorBase(NULL, NULL), mMpuAccuracy(0), mNewData(0), mDmpStarted(false), mMasterSensorMask(INV_ALL_SENSORS), mLocalSensorMask(ALL_MPL_SENSORS_NP), mPollTime(-1), mCurFifoRate(-1), mHaveGoodMpuCal(false), mHaveGoodCompassCal(false), mUseTimerIrqAccel(false), mUsetimerIrqCompass(true), mUseTimerirq(false), mSampleCount(0), mEnabled(0), mPendingMask(0) { FUNC_LOG; inv_error_t rv; int mpu_int_fd, i; char *port = NULL; LOGV_IF(EXTRA_VERBOSE, "MPLSensor constructor: numSensors = %d", numSensors); pthread_mutex_init(&mMplMutex, NULL); mForceSleep = false; /* used for identifying whether 9axis is enabled or not */ /* this variable will be changed in initMPL() when libmpl is loaded */ /* sensor list will be changed based on this variable */ mNineAxisEnabled = false; for (i = 0; i < ARRAY_SIZE(mPollFds); i++) { mPollFds[i].fd = -1; mPollFds[i].events = 0; } pthread_mutex_lock(&mMplMutex); mpu_int_fd = open("/dev/mpuirq", O_RDWR); if (mpu_int_fd == -1) { LOGE("could not open the mpu irq device node"); } else { fcntl(mpu_int_fd, F_SETFL, O_NONBLOCK); //ioctl(mpu_int_fd, MPUIRQ_SET_TIMEOUT, 0); mIrqFds.add(MPUIRQ_FD, mpu_int_fd); mPollFds[MPUIRQ_FD].fd = mpu_int_fd; mPollFds[MPUIRQ_FD].events = POLLIN; } accel_fd = open("/dev/accelirq", O_RDWR); if (accel_fd == -1) { LOGE("could not open the accel irq device node"); } else { fcntl(accel_fd, F_SETFL, O_NONBLOCK); //ioctl(accel_fd, SLAVEIRQ_SET_TIMEOUT, 0); mIrqFds.add(ACCELIRQ_FD, accel_fd); mPollFds[ACCELIRQ_FD].fd = accel_fd; mPollFds[ACCELIRQ_FD].events = POLLIN; } timer_fd = open("/dev/timerirq", O_RDWR); if (timer_fd == -1) { LOGE("could not open the timer irq device node"); } else { fcntl(timer_fd, F_SETFL, O_NONBLOCK); //ioctl(timer_fd, TIMERIRQ_SET_TIMEOUT, 0); mIrqFds.add(TIMERIRQ_FD, timer_fd); mPollFds[TIMERIRQ_FD].fd = timer_fd; mPollFds[TIMERIRQ_FD].events = POLLIN; } data_fd = mpu_int_fd; if ((accel_fd == -1) && (timer_fd != -1)) { //no accel irq and timer available mUseTimerIrqAccel = true; //LOGD("MPLSensor falling back to timerirq for accel data"); } memset(mPendingEvents, 0, sizeof(mPendingEvents)); mPendingEvents[RotationVector].version = sizeof(sensors_event_t); mPendingEvents[RotationVector].sensor = ID_RV; mPendingEvents[RotationVector].type = SENSOR_TYPE_ROTATION_VECTOR; mPendingEvents[RotationVector].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[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[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; 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[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; mHandlers[RotationVector] = &MPLSensor::rvHandler; mHandlers[LinearAccel] = &MPLSensor::laHandler; mHandlers[Gravity] = &MPLSensor::gravHandler; mHandlers[Gyro] = &MPLSensor::gyroHandler; mHandlers[Accelerometer] = &MPLSensor::accelHandler; mHandlers[MagneticField] = &MPLSensor::compassHandler; mHandlers[Orientation] = &MPLSensor::orienHandler; for (int i = 0; i < numSensors; i++) mDelays[i] = 30000000LLU; // 30 ms by default if (inv_serial_start(port) != INV_SUCCESS) { LOGE("Fatal Error : could not open MPL serial interface"); } //initialize library parameters initMPL(); //setup the FIFO contents setupFIFO(); //we start the motion processing only when a sensor is enabled... //rv = inv_dmp_start(); //LOGE_IF(rv != INV_SUCCESS, "Fatal error: could not start the DMP correctly. (code = %d)\n", rv); //dmp_started = true; pthread_mutex_unlock(&mMplMutex); } MPLSensor::~MPLSensor() { FUNC_LOG; pthread_mutex_lock(&mMplMutex); if (inv_dmp_stop() != INV_SUCCESS) { LOGW("Error: could not stop the DMP correctly.\n"); } if (inv_dmp_close() != INV_SUCCESS) { LOGW("Error: could not close the DMP"); } if (inv_serial_stop() != INV_SUCCESS) { LOGW("Error : could not close the serial port"); } pthread_mutex_unlock(&mMplMutex); pthread_mutex_destroy(&mMplMutex); } /* clear any data from our various filehandles */ void MPLSensor::clearIrqData(bool* irq_set) { unsigned int i; int nread; struct mpuirq_data irqdata; poll(mPollFds, ARRAY_SIZE(mPollFds), 0); //check which ones need to be cleared for (i = 0; i < ARRAY_SIZE(mPollFds); i++) { int cur_fd = mPollFds[i].fd; int j = 0; if (mPollFds[i].revents & POLLIN) { nread = read(cur_fd, &irqdata, sizeof(irqdata)); if (nread > 0) { irq_set[i] = true; irq_timestamp = irqdata.irqtime; //LOGV_IF(EXTRA_VERBOSE, "irq: %d %d (%d)", i, irqdata.interruptcount, j++); } } mPollFds[i].revents = 0; } } /* set the power states of the various sensors based on the bits set in the * enabled_sensors parameter. * this function modifies globalish state variables. It must be called with the mMplMutex held. */ void MPLSensor::setPowerStates(int enabled_sensors) { FUNC_LOG; bool irq_set[5] = { false, false, false, false, false }; //LOGV(" setPowerStates: %d dmp_started: %d", enabled_sensors, mDmpStarted); do { if (LA_ENABLED || GR_ENABLED || RV_ENABLED || O_ENABLED) { mLocalSensorMask = ALL_MPL_SENSORS_NP; break; } if (!A_ENABLED && !M_ENABLED && !GY_ENABLED) { mLocalSensorMask = 0; break; } if (GY_ENABLED) { mLocalSensorMask |= INV_THREE_AXIS_GYRO; } else { mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; } if (A_ENABLED) { mLocalSensorMask |= (INV_THREE_AXIS_ACCEL); } else { mLocalSensorMask &= ~(INV_THREE_AXIS_ACCEL); } if (M_ENABLED) { mLocalSensorMask |= INV_THREE_AXIS_COMPASS; } else { mLocalSensorMask &= ~(INV_THREE_AXIS_COMPASS); } } while (0); //record the new sensor state inv_error_t rv; long sen_mask = mLocalSensorMask & mMasterSensorMask; bool changing_sensors = ((inv_get_dl_config()->requested_sensors != sen_mask) && (sen_mask != 0)); bool restart = (!mDmpStarted) && (sen_mask != 0); if (changing_sensors || restart) { LOGV_IF(EXTRA_VERBOSE, "cs:%d rs:%d ", changing_sensors, restart); if (mDmpStarted) { inv_dmp_stop(); clearIrqData(irq_set); mDmpStarted = false; } if (sen_mask != inv_get_dl_config()->requested_sensors) { //LOGV("setPowerStates: %lx", sen_mask); rv = inv_set_mpu_sensors(sen_mask); LOGE_IF(rv != INV_SUCCESS, "error: unable to set MPL sensor power states (sens=%ld retcode = %d)", sen_mask, rv); } if (((mUsetimerIrqCompass && (sen_mask == INV_THREE_AXIS_COMPASS)) || (mUseTimerIrqAccel && (sen_mask & INV_THREE_AXIS_ACCEL))) && ((sen_mask & INV_DMP_PROCESSOR) == 0)) { LOGV_IF(EXTRA_VERBOSE, "Allowing TimerIRQ"); mUseTimerirq = true; } else { if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); clearIrqData(irq_set); } LOGV_IF(EXTRA_VERBOSE, "Not allowing TimerIRQ"); mUseTimerirq = false; } if (!mDmpStarted) { if (mHaveGoodMpuCal || mHaveGoodCompassCal) { rv = inv_store_calibration(); LOGE_IF(rv != INV_SUCCESS, "error: unable to store MPL calibration file"); mHaveGoodMpuCal = false; mHaveGoodCompassCal = false; } //LOGV("Starting DMP"); rv = inv_dmp_start(); LOGE_IF(rv != INV_SUCCESS, "unable to start dmp"); mDmpStarted = true; } } //check if we should stop the DMP if (mDmpStarted && (sen_mask == 0)) { //LOGV("Stopping DMP"); rv = inv_dmp_stop(); LOGE_IF(rv != INV_SUCCESS, "error: unable to stop DMP (retcode = %d)", rv); if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); } clearIrqData(irq_set); mDmpStarted = false; mPollTime = -1; mCurFifoRate = -1; } } /** * container function for all the calls we make once to set up the MPL. */ void MPLSensor::initMPL() { FUNC_LOG; inv_error_t result; unsigned short bias_update_mask = 0xFFFF; struct mldl_cfg *mldl_cfg; if (inv_dmp_open() != INV_SUCCESS) { LOGE("Fatal Error : could not open DMP correctly.\n"); } result = inv_set_mpu_sensors(ALL_MPL_SENSORS_NP); //default to all sensors, also makes 9axis enable work LOGE_IF(result != INV_SUCCESS, "Fatal Error : could not set enabled sensors."); if (inv_load_calibration() != INV_SUCCESS) { LOGE("could not open MPL calibration file"); } //check for the 9axis fusion library: if available load it and start 9x void* h_dmp_lib=dlopen("libinvensense_mpl.so", RTLD_NOW); if(h_dmp_lib) { const char* error; error = dlerror(); inv_error_t (*fp_inv_enable_9x_fusion)() = (inv_error_t(*)()) dlsym(h_dmp_lib, "inv_enable_9x_fusion"); if((error = dlerror()) != NULL) { LOGE("%s %s", error, "inv_enable_9x_fusion"); } else if ((*fp_inv_enable_9x_fusion)() != INV_SUCCESS) { LOGE( "Warning : 9 axis sensor fusion not available " "- No compass detected.\n"); } else { /* 9axis is loaded and enabled */ /* this variable is used for coming up with sensor list */ mNineAxisEnabled = true; } } else { const char* error = dlerror(); LOGE("libinvensense_mpl.so not found, 9x sensor fusion disabled (%s)",error); } mldl_cfg = inv_get_dl_config(); if (inv_set_bias_update(bias_update_mask) != INV_SUCCESS) { LOGE("Error : Bias update function could not be set.\n"); } if (inv_set_motion_interrupt(1) != INV_SUCCESS) { LOGE("Error : could not set motion interrupt"); } if (inv_set_fifo_interrupt(1) != INV_SUCCESS) { LOGE("Error : could not set fifo interrupt"); } result = inv_set_fifo_rate(6); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_set_fifo_rate returned %d\n", result); } mMpuAccuracy = SENSOR_STATUS_ACCURACY_MEDIUM; setupCallbacks(); } /** setup the fifo contents. */ void MPLSensor::setupFIFO() { FUNC_LOG; inv_error_t result; result = inv_send_accel(INV_ALL, INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_accel returned %d\n", result); } result = inv_send_quaternion(INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_quaternion returned %d\n", result); } result = inv_send_linear_accel(INV_ALL, INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_linear_accel returned %d\n", result); } result = inv_send_linear_accel_in_world(INV_ALL, INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_linear_accel_in_world returned %d\n", result); } result = inv_send_gravity(INV_ALL, INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_gravity returned %d\n", result); } result = inv_send_gyro(INV_ALL, INV_32_BIT); if (result != INV_SUCCESS) { LOGE("Fatal error: inv_send_gyro returned %d\n", result); } } /** * set up the callbacks that we use in all cases (outside of gestures, etc) */ void MPLSensor::setupCallbacks() { FUNC_LOG; if (inv_set_motion_callback(mot_cb_wrapper) != INV_SUCCESS) { LOGE("Error : Motion callback could not be set.\n"); } if (inv_set_fifo_processed_callback(procData_cb_wrapper) != INV_SUCCESS) { LOGE("Error : Processed data callback could not be set."); } } /** * handle the motion/no motion output from the MPL. */ void MPLSensor::cbOnMotion(uint16_t val) { FUNC_LOG; //after the first no motion, the gyro should be calibrated well if (val == 2) { mMpuAccuracy = SENSOR_STATUS_ACCURACY_HIGH; if ((inv_get_dl_config()->requested_sensors) & INV_THREE_AXIS_GYRO) { //if gyros are on and we got a no motion, set a flag // indicating that the cal file can be written. mHaveGoodMpuCal = true; } } return; } void MPLSensor::cbProcData() { mNewData = 1; mSampleCount++; //LOGV_IF(EXTRA_VERBOSE, "new data (%d)", sampleCount); } //these handlers transform mpl data into one of the Android sensor types // scaling and coordinate transforms should be done in the handlers void MPLSensor::gyroHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { VFUNC_LOG; inv_error_t res; res = inv_get_float_array(INV_GYROS, s->gyro.v); s->gyro.v[0] = s->gyro.v[0] * M_PI / 180.0; s->gyro.v[1] = s->gyro.v[1] * M_PI / 180.0; s->gyro.v[2] = s->gyro.v[2] * M_PI / 180.0; s->gyro.status = mMpuAccuracy; if (res == INV_SUCCESS) *pending_mask |= (1 << index); } void MPLSensor::accelHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { //VFUNC_LOG; inv_error_t res; res = inv_get_float_array(INV_ACCELS, s->acceleration.v); //res = inv_get_accel_float(s->acceleration.v); s->acceleration.v[0] = s->acceleration.v[0] * 9.81; s->acceleration.v[1] = s->acceleration.v[1] * 9.81; s->acceleration.v[2] = s->acceleration.v[2] * 9.81; //LOGV_IF(EXTRA_VERBOSE, "accel data: %f %f %f", s->acceleration.v[0], s->acceleration.v[1], s->acceleration.v[2]); s->acceleration.status = SENSOR_STATUS_ACCURACY_HIGH; if (res == INV_SUCCESS) *pending_mask |= (1 << index); } int MPLSensor::estimateCompassAccuracy() { inv_error_t res; int rv; res = inv_get_compass_accuracy(&rv); if(rv >= SENSOR_STATUS_ACCURACY_MEDIUM) { mHaveGoodCompassCal = true; } LOGE_IF(res != INV_SUCCESS, "error returned from inv_get_compass_accuracy"); return rv; } void MPLSensor::compassHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { VFUNC_LOG; inv_error_t res, res2; float bias_error[3]; float total_be; static int bias_error_settled = 0; res = inv_get_float_array(INV_MAGNETOMETER, s->magnetic.v); if (res != INV_SUCCESS) { LOGW( "compass_handler inv_get_float_array(INV_MAGNETOMETER) returned %d", res); } s->magnetic.status = estimateCompassAccuracy(); if (res == INV_SUCCESS) *pending_mask |= (1 << index); } void MPLSensor::rvHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { VFUNC_LOG; float quat[4]; float norm = 0; float ang = 0; inv_error_t r; r = inv_get_float_array(INV_QUATERNION, quat); if (r != INV_SUCCESS) { *pending_mask &= ~(1 << index); return; } else { *pending_mask |= (1 << index); } norm = quat[1] * quat[1] + quat[2] * quat[2] + quat[3] * quat[3] + FLT_EPSILON; if (norm > 1.0f) { //renormalize norm = sqrtf(norm); float inv_norm = 1.0f / norm; quat[1] = quat[1] * inv_norm; quat[2] = quat[2] * inv_norm; quat[3] = quat[3] * inv_norm; } if (quat[0] < 0.0) { quat[1] = -quat[1]; quat[2] = -quat[2]; quat[3] = -quat[3]; } s->gyro.v[0] = quat[1]; s->gyro.v[1] = quat[2]; s->gyro.v[2] = quat[3]; s->gyro.status = ((mMpuAccuracy < estimateCompassAccuracy()) ? mMpuAccuracy : estimateCompassAccuracy()); } void MPLSensor::laHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { VFUNC_LOG; inv_error_t res; res = inv_get_float_array(INV_LINEAR_ACCELERATION, s->gyro.v); s->gyro.v[0] *= 9.81; s->gyro.v[1] *= 9.81; s->gyro.v[2] *= 9.81; s->gyro.status = mMpuAccuracy; if (res == INV_SUCCESS) *pending_mask |= (1 << index); } void MPLSensor::gravHandler(sensors_event_t* s, uint32_t* pending_mask, int index) { VFUNC_LOG; inv_error_t res; res = inv_get_float_array(INV_GRAVITY, s->gyro.v); s->gyro.v[0] *= 9.81; s->gyro.v[1] *= 9.81; s->gyro.v[2] *= 9.81; s->gyro.status = mMpuAccuracy; if (res == INV_SUCCESS) *pending_mask |= (1 << index); } void MPLSensor::calcOrientationSensor(float *R, float *values) { float tmp; //Azimuth if ((R[7] > 0.7071067f) || ((R[8] < 0) && (fabs(R[7]) > fabs(R[6])))) { values[0] = (float) atan2f(-R[3], R[0]); } else { values[0] = (float) atan2f(R[1], R[4]); } values[0] *= 57.295779513082320876798154814105f; if (values[0] < 0) { values[0] += 360.0f; } //Pitch tmp = R[7]; if (tmp > 1.0f) tmp = 1.0f; if (tmp < -1.0f) tmp = -1.0f; values[1] = -asinf(tmp) * 57.295779513082320876798154814105f; if (R[8] < 0) { values[1] = 180.0f - values[1]; } if (values[1] > 180.0f) { values[1] -= 360.0f; } //Roll if ((R[7] > 0.7071067f)) { values[2] = (float) atan2f(R[6], R[7]); } else { values[2] = (float) atan2f(R[6], R[8]); } values[2] *= 57.295779513082320876798154814105f; if (values[2] > 90.0f) { values[2] = 180.0f - values[2]; } if (values[2] < -90.0f) { values[2] = -180.0f - values[2]; } } void MPLSensor::orienHandler(sensors_event_t* s, uint32_t* pending_mask, int index) //note that this is the handler for the android 'orientation' sensor, not the mpl orientation output { VFUNC_LOG; inv_error_t res; float euler[3]; float heading[1]; float rot_mat[9]; res = inv_get_float_array(INV_ROTATION_MATRIX, rot_mat); //ComputeAndOrientation(heading[0], euler, s->orientation.v); calcOrientationSensor(rot_mat, s->orientation.v); s->orientation.status = estimateCompassAccuracy(); if (res == INV_SUCCESS) *pending_mask |= (1 << index); else LOGW("orienHandler: data not valid (%d)", (int) res); } int MPLSensor::enable(int32_t handle, int en) { FUNC_LOG; //LOGV("handle : %d en: %d", handle, en); int what = -1; switch (handle) { case ID_A: what = Accelerometer; break; case ID_M: what = MagneticField; break; case ID_O: what = Orientation; break; case ID_GY: what = Gyro; break; case ID_GR: what = Gravity; break; case ID_RV: what = RotationVector; break; case ID_LA: what = LinearAccel; break; default: //this takes care of all the gestures what = handle; break; } if (uint32_t(what) >= numSensors) return -EINVAL; int newState = en ? 1 : 0; int err = 0; //LOGV_IF((uint32_t(newState) << what) != (mEnabled & (1 << what)), // "sensor state change what=%d", what); pthread_mutex_lock(&mMplMutex); if ((uint32_t(newState) << what) != (mEnabled & (1 << what))) { uint32_t sensor_type; short flags = newState; mEnabled &= ~(1 << what); mEnabled |= (uint32_t(flags) << what); LOGV_IF(EXTRA_VERBOSE, "mEnabled = %x", mEnabled); setPowerStates(mEnabled); pthread_mutex_unlock(&mMplMutex); if (!newState) update_delay(); return err; } pthread_mutex_unlock(&mMplMutex); return err; } int MPLSensor::setDelay(int32_t handle, int64_t ns) { FUNC_LOG; LOGV_IF(EXTRA_VERBOSE, " setDelay handle: %d rate %d", handle, (int) (ns / 1000000LL)); int what = -1; switch (handle) { case ID_A: what = Accelerometer; break; case ID_M: what = MagneticField; break; case ID_O: what = Orientation; break; case ID_GY: what = Gyro; break; case ID_GR: what = Gravity; break; case ID_RV: what = RotationVector; break; case ID_LA: what = LinearAccel; break; default: what = handle; break; } if (uint32_t(what) >= numSensors) return -EINVAL; if (ns < 0) return -EINVAL; pthread_mutex_lock(&mMplMutex); mDelays[what] = ns; pthread_mutex_unlock(&mMplMutex); return update_delay(); } int MPLSensor::update_delay() { FUNC_LOG; int rv = 0; bool irq_set[5]; pthread_mutex_lock(&mMplMutex); if (mEnabled) { uint64_t wanted = -1LLU; for (int i = 0; i < numSensors; i++) { if (mEnabled & (1 << i)) { uint64_t ns = mDelays[i]; wanted = wanted < ns ? wanted : ns; } } //Limit all rates to 100Hz max. 100Hz = 10ms = 10000000ns if (wanted < 10000000LLU) { wanted = 10000000LLU; } int rate = ((wanted) / 5000000LLU) - ((wanted % 5000000LLU == 0) ? 1 : 0); //mpu fifo rate is in increments of 5ms if (rate == 0) //KLP disallow fifo rate 0 rate = 1; if (rate != mCurFifoRate) { //LOGD("set fifo rate: %d %llu", rate, wanted); inv_error_t res; // = inv_dmp_stop(); res = inv_set_fifo_rate(rate); LOGE_IF(res != INV_SUCCESS, "error setting FIFO rate"); //res = inv_dmp_start(); //LOGE_IF(res != INV_SUCCESS, "error re-starting DMP"); mCurFifoRate = rate; rv = (res == INV_SUCCESS); } if (((inv_get_dl_config()->requested_sensors & INV_DMP_PROCESSOR) == 0)) { if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); clearIrqData(irq_set); if (inv_get_dl_config()->requested_sensors == INV_THREE_AXIS_COMPASS) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_START, (unsigned long) (wanted / 1000000LLU)); LOGV_IF(EXTRA_VERBOSE, "updated timerirq period to %d", (int) (wanted / 1000000LLU)); } else { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_START, (unsigned long) inv_get_sample_step_size_ms()); LOGV_IF(EXTRA_VERBOSE, "updated timerirq period to %d", (int) inv_get_sample_step_size_ms()); } } } } pthread_mutex_unlock(&mMplMutex); return rv; } /* return the current time in nanoseconds */ int64_t MPLSensor::now_ns(void) { //FUNC_LOG; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); //LOGV("Time %lld", (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec); return (int64_t) ts.tv_sec * 1000000000 + ts.tv_nsec; } int MPLSensor::readEvents(sensors_event_t* data, int count) { //VFUNC_LOG; int i; bool irq_set[5] = { false, false, false, false, false }; inv_error_t rv; if (count < 1) return -EINVAL; int numEventReceived = 0; clearIrqData(irq_set); pthread_mutex_lock(&mMplMutex); if (mDmpStarted) { //LOGV_IF(EXTRA_VERBOSE, "Update Data"); rv = inv_update_data(); LOGE_IF(rv != INV_SUCCESS, "inv_update_data error (code %d)", (int) rv); } else { //probably just one extra read after shutting down LOGV_IF(EXTRA_VERBOSE, "MPLSensor::readEvents called, but there's nothing to do."); } pthread_mutex_unlock(&mMplMutex); if (!mNewData) { LOGV_IF(EXTRA_VERBOSE, "no new data"); return 0; } mNewData = 0; /* google timestamp */ pthread_mutex_lock(&mMplMutex); for (int i = 0; i < numSensors; i++) { if (mEnabled & (1 << i)) { CALL_MEMBER_FN(this,mHandlers[i])(mPendingEvents + i, &mPendingMask, i); mPendingEvents[i].timestamp = irq_timestamp; } } for (int j = 0; count && mPendingMask && j < numSensors; j++) { if (mPendingMask & (1 << j)) { mPendingMask &= ~(1 << j); if (mEnabled & (1 << j)) { *data++ = mPendingEvents[j]; count--; numEventReceived++; } } } pthread_mutex_unlock(&mMplMutex); return numEventReceived; } int MPLSensor::getFd() const { //LOGV("MPLSensor::getFd returning %d", data_fd); return data_fd; } int MPLSensor::getAccelFd() const { //LOGV("MPLSensor::getAccelFd returning %d", accel_fd); return accel_fd; } int MPLSensor::getTimerFd() const { //LOGV("MPLSensor::getTimerFd returning %d", timer_fd); return timer_fd; } int MPLSensor::getPowerFd() const { int hdl = (int) inv_get_serial_handle(); //LOGV("MPLSensor::getPowerFd returning %d", hdl); return hdl; } int MPLSensor::getPollTime() { return mPollTime; } bool MPLSensor::hasPendingEvents() const { //if we are using the polling workaround, force the main loop to check for data every time return (mPollTime != -1); } void MPLSensor::handlePowerEvent() { VFUNC_LOG; mpuirq_data irqd; int fd = (int) inv_get_serial_handle(); read(fd, &irqd, sizeof(irqd)); if (irqd.data == MPU_PM_EVENT_SUSPEND_PREPARE) { //going to sleep sleepEvent(); } else if (irqd.data == MPU_PM_EVENT_POST_SUSPEND) { //waking up wakeEvent(); } ioctl(fd, MPU_PM_EVENT_HANDLED, 0); } void MPLSensor::sleepEvent() { VFUNC_LOG; pthread_mutex_lock(&mMplMutex); if (mEnabled != 0) { mForceSleep = true; mOldEnabledMask = mEnabled; setPowerStates(0); } pthread_mutex_unlock(&mMplMutex); } void MPLSensor::wakeEvent() { VFUNC_LOG; pthread_mutex_lock(&mMplMutex); if (mForceSleep) { setPowerStates((mOldEnabledMask | mEnabled)); } mForceSleep = false; pthread_mutex_unlock(&mMplMutex); } /** 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) { int numsensors; if(len < 7*sizeof(sensor_t)) { LOGE("sensor list too small, not populating."); return 0; } /* fill in the base values */ memcpy(list, sSensorList, sizeof (struct sensor_t) * 7); /* first add gyro, accel and compass to the list */ /* fill in accel values */ unsigned short accelId = inv_get_accel_id(); if(accelId == 0) { LOGE("Can not get accel id"); } fillAccel(accelId, list); /* fill in compass values */ unsigned short compassId = inv_get_compass_id(); if(compassId == 0) { LOGE("Can not get compass id"); } fillCompass(compassId, list); /* fill in gyro values */ fillGyro(MPU_NAME, list); if(mNineAxisEnabled) { numsensors = 7; /* all sensors will be added to the list */ /* fill in orientation values */ fillOrientation(list); /* fill in rotation vector values */ fillRV(list); /* fill in gravity values */ fillGravity(list); /* fill in Linear accel values */ fillLinearAccel(list); } 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(unsigned char accel, struct sensor_t *list) { switch (accel) { case ACCEL_ID_LIS331: list[Accelerometer].maxRange = ACCEL_LIS331_RANGE; list[Accelerometer].resolution = ACCEL_LIS331_RESOLUTION; list[Accelerometer].power = ACCEL_LIS331_POWER; break; case ACCEL_ID_LIS3DH: list[Accelerometer].maxRange = ACCEL_LIS3DH_RANGE; list[Accelerometer].resolution = ACCEL_LIS3DH_RESOLUTION; list[Accelerometer].power = ACCEL_LIS3DH_POWER; break; case ACCEL_ID_KXSD9: list[Accelerometer].maxRange = ACCEL_KXSD9_RANGE; list[Accelerometer].resolution = ACCEL_KXSD9_RESOLUTION; list[Accelerometer].power = ACCEL_KXSD9_POWER; break; case ACCEL_ID_KXTF9: list[Accelerometer].maxRange = ACCEL_KXTF9_RANGE; list[Accelerometer].resolution = ACCEL_KXTF9_RESOLUTION; list[Accelerometer].power = ACCEL_KXTF9_POWER; break; case ACCEL_ID_BMA150: list[Accelerometer].maxRange = ACCEL_BMA150_RANGE; list[Accelerometer].resolution = ACCEL_BMA150_RESOLUTION; list[Accelerometer].power = ACCEL_BMA150_POWER; break; case ACCEL_ID_BMA222: list[Accelerometer].maxRange = ACCEL_BMA222_RANGE; list[Accelerometer].resolution = ACCEL_BMA222_RESOLUTION; list[Accelerometer].power = ACCEL_BMA222_POWER; break; case ACCEL_ID_BMA250: list[Accelerometer].maxRange = ACCEL_BMA250_RANGE; list[Accelerometer].resolution = ACCEL_BMA250_RESOLUTION; list[Accelerometer].power = ACCEL_BMA250_POWER; break; case ACCEL_ID_ADXL34X: list[Accelerometer].maxRange = ACCEL_ADXL34X_RANGE; list[Accelerometer].resolution = ACCEL_ADXL34X_RESOLUTION; list[Accelerometer].power = ACCEL_ADXL34X_POWER; break; case ACCEL_ID_MMA8450: list[Accelerometer].maxRange = ACCEL_MMA8450_RANGE; list[Accelerometer].maxRange = ACCEL_MMA8450_RANGE; list[Accelerometer].maxRange = ACCEL_MMA8450_RANGE; break; case ACCEL_ID_MMA845X: list[Accelerometer].maxRange = ACCEL_MMA845X_RANGE; list[Accelerometer].resolution = ACCEL_MMA845X_RESOLUTION; list[Accelerometer].power = ACCEL_MMA845X_POWER; break; case ACCEL_ID_MPU6050: list[Accelerometer].maxRange = ACCEL_MPU6050_RANGE; list[Accelerometer].resolution = ACCEL_MPU6050_RESOLUTION; list[Accelerometer].power = ACCEL_MPU6050_POWER; break; default: LOGE("unknown accel id -- accel params will be wrong."); break; } } void MPLSensor::fillCompass(unsigned char compass, struct sensor_t *list) { switch (compass) { case COMPASS_ID_AK8975: list[MagneticField].maxRange = COMPASS_AKM8975_RANGE; list[MagneticField].resolution = COMPASS_AKM8975_RESOLUTION; list[MagneticField].power = COMPASS_AKM8975_POWER; break; case COMPASS_ID_AMI30X: list[MagneticField].maxRange = COMPASS_AMI30X_RANGE; list[MagneticField].resolution = COMPASS_AMI30X_RESOLUTION; list[MagneticField].power = COMPASS_AMI30X_POWER; break; case COMPASS_ID_AMI306: list[MagneticField].maxRange = COMPASS_AMI306_RANGE; list[MagneticField].resolution = COMPASS_AMI306_RESOLUTION; list[MagneticField].power = COMPASS_AMI306_POWER; break; case COMPASS_ID_YAS529: list[MagneticField].maxRange = COMPASS_YAS529_RANGE; list[MagneticField].resolution = COMPASS_AMI306_RESOLUTION; list[MagneticField].power = COMPASS_AMI306_POWER; break; case COMPASS_ID_YAS530: list[MagneticField].maxRange = COMPASS_YAS530_RANGE; list[MagneticField].resolution = COMPASS_YAS530_RESOLUTION; list[MagneticField].power = COMPASS_YAS530_POWER; break; case COMPASS_ID_HMC5883: list[MagneticField].maxRange = COMPASS_HMC5883_RANGE; list[MagneticField].resolution = COMPASS_HMC5883_RESOLUTION; list[MagneticField].power = COMPASS_HMC5883_POWER; break; case COMPASS_ID_MMC314X: list[MagneticField].maxRange = COMPASS_MMC314X_RANGE; list[MagneticField].resolution = COMPASS_MMC314X_RESOLUTION; list[MagneticField].power = COMPASS_MMC314X_POWER; break; case COMPASS_ID_HSCDTD002B: list[MagneticField].maxRange = COMPASS_HSCDTD002B_RANGE; list[MagneticField].resolution = COMPASS_HSCDTD002B_RESOLUTION; list[MagneticField].power = COMPASS_HSCDTD002B_POWER; break; case COMPASS_ID_HSCDTD004A: list[MagneticField].maxRange = COMPASS_HSCDTD004A_RANGE; list[MagneticField].resolution = COMPASS_HSCDTD004A_RESOLUTION; list[MagneticField].power = COMPASS_HSCDTD004A_POWER; break; default: LOGE("unknown compass id -- compass parameters will be wrong"); } } void MPLSensor::fillGyro(const char* gyro, struct sensor_t *list) { 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; } else { list[Gyro].maxRange = GYRO_MPU6050_RANGE; list[Gyro].resolution = GYRO_MPU6050_RESOLUTION; list[Gyro].power = GYRO_MPU6050_POWER; } return; } /* fillRV depends on values of accel and compass in the list */ void MPLSensor::fillRV(struct sensor_t *list) { /* 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; return; } void MPLSensor::fillOrientation(struct sensor_t *list) { list[Orientation].power = list[Gyro].power + list[Accelerometer].power + list[MagneticField].power; list[Orientation].resolution = .00001; list[Orientation].maxRange = 360.0; return; } void MPLSensor::fillGravity( struct sensor_t *list) { list[Gravity].power = list[Gyro].power + list[Accelerometer].power + list[MagneticField].power; list[Gravity].resolution = .00001; list[Gravity].maxRange = 9.81; return; } void MPLSensor::fillLinearAccel(struct sensor_t *list) { list[Gravity].power = list[Gyro].power + list[Accelerometer].power + list[MagneticField].power; list[Gravity].resolution = list[Accelerometer].resolution; list[Gravity].maxRange = list[Accelerometer].maxRange; return; }