/** * @brief An MPL wrapper for the main MPU Self Test API inv_factory_calibrate(). * See inv_factory_calibrate() function for more details. * * @pre inv_dmp_open() <b>must</b> have been called to populate the mldl_cfg * data structure. * On Windows, SetupPlatform() is also a madatory pre condition to * ensure the accelerometer is properly configured before running the * test. * * @param mlsl_handle * serial interface handle to allow serial communication with the * device, both gyro and accelerometer. * @param provide_result * If 1: * perform and analyze the offset, drive frequency, and noise * calculation and compare it against set thresholds. Report * also the final result using a bit-mask like error code as * described in the inv_test_gyro_xxxx() functions. * When 0: * skip the noise and drive frequency calculation and pass/fail * assessment. It simply calculates the gyro and accel biases. * NOTE: for MPU6050 devices, this parameter is currently * ignored. * * @return INV_SUCCESS or first non-zero error code otherwise. */ inv_error_t inv_self_test_factory_calibrate(void *mlsl_handle, unsigned char provide_result) { INVENSENSE_FUNC_START; inv_error_t firstError = INV_SUCCESS; inv_error_t result; unsigned char initState = inv_get_state(); if (initState < INV_STATE_DMP_OPENED) { MPL_LOGE("Self Test cannot run before inv_dmp_open()\n"); return INV_ERROR_SM_IMPROPER_STATE; } /* obtain a pointer to the 'struct mldl_cfg' data structure. */ mputestCfgPtr = inv_get_dl_config(); if(initState == INV_STATE_DMP_STARTED) { result = inv_dmp_stop(); ERROR_CHECK_FIRST(firstError, result); } result = inv_factory_calibrate(mlsl_handle, provide_result); ERROR_CHECK_FIRST(firstError, result); if(initState == INV_STATE_DMP_STARTED) { result = inv_dmp_start(); ERROR_CHECK_FIRST(firstError, result); } return firstError; }
/** * @brief umplStop stops the uMPL state machine. This function * in turn calls the necessary MPL functions like inv_dmp_stop() * and inv_dmp_close() to stop the motion processing algorithms. * * * @pre umplInit() and umplStartMPU() must have been called. * * @return INV_SUCCESS if successful, a non-zero error code otherwise. */ inv_error_t umplStop(void) { inv_error_t result; if (umplState == UMPL_RUN) { #ifndef UMPL_DISABLE_STORE_CAL result = inv_ustore_calibration(); if (result != INV_SUCCESS) MPL_LOGE("inv_ustore_calibration failed with %d in umplStop\n",result); #endif } if (umplState == UMPL_RUN || umplState == UMPL_ACCEL_ONLY || umplState == UMPL_LPACCEL_ONLY) { result = inv_dmp_stop(); if (result != INV_SUCCESS) return result; result = inv_dmp_close(); if (result != INV_SUCCESS) return result; umplSetState(UMPL_STOP); return INV_SUCCESS; } return INV_ERROR_SM_IMPROPER_STATE; }
MPLSensor::~MPLSensor() { FUNC_LOG; pthread_mutex_lock(&mMplMutex); if (inv_dmp_stop() != INV_SUCCESS) { ALOGW("Error: could not stop the DMP correctly.\n"); } if (inv_dmp_close() != INV_SUCCESS) { ALOGW("Error: could not close the DMP"); } if (inv_serial_stop() != INV_SUCCESS) { ALOGW("Error : could not close the serial port"); } pthread_mutex_unlock(&mMplMutex); pthread_mutex_destroy(&mMplMutex); }
/* 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 }; //ALOGV(" 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) { ALOGV_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) { //ALOGV("setPowerStates: %lx", sen_mask); rv = inv_set_mpu_sensors(sen_mask); ALOGE_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)) { ALOGV_IF(EXTRA_VERBOSE, "Allowing TimerIRQ"); mUseTimerirq = true; } else { if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); clearIrqData(irq_set); } ALOGV_IF(EXTRA_VERBOSE, "Not allowing TimerIRQ"); mUseTimerirq = false; } if (!mDmpStarted) { if (mHaveGoodMpuCal || mHaveGoodCompassCal) { rv = inv_store_calibration(); ALOGE_IF(rv != INV_SUCCESS, "error: unable to store MPL calibration file"); mHaveGoodMpuCal = false; mHaveGoodCompassCal = false; } //ALOGV("Starting DMP"); rv = inv_dmp_start(); ALOGE_IF(rv != INV_SUCCESS, "unable to start dmp"); mDmpStarted = true; } } //check if we should stop the DMP if (mDmpStarted && (sen_mask == 0)) { //ALOGV("Stopping DMP"); rv = inv_dmp_stop(); ALOGE_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; } }
/** * @brief The main entry point of the MPU Self Test, triggering the run of * the single tests, for gyros and accelerometers. * Prepares the MPU for the test, taking the device out of low power * state if necessary, switching the MPU secondary I2C interface into * bypass mode and restoring the original power state at the end of * the test. * This function is also responsible for encoding the output of each * test in the correct format as it is stored on the file/medium of * choice (according to inv_serial_write_cal() function). * The format needs to stay perfectly consistent with the one expected * by the corresponding loader in ml_stored_data.c; currectly the * loaded in use is inv_load_cal_V1 (record type 1 - initial * calibration). * * @param mlsl_handle * serial interface handle to allow serial communication with the * device, both gyro and accelerometer. * @param perform_full_test * If 1: * Complete calibration test: * Calculate offset, drive frequency, and noise and compare it * against set thresholds. * When 0: * Skip the noise and drive frequency calculation, * simply calculate the gyro biases. * @param provide_result * If 1: * Report the final result using a bit-mask like error code as * described in the test_gyro() function. * * @return 0 on success. A non-zero error code on error. * Propagates the errors from the tests up to the caller. */ int inv_device_test(void *mlsl_handle, uint_fast8_t sensor_mask, uint_fast8_t perform_full_test, uint_fast8_t provide_result) { int result = 0, gyro_test_result = 0, accel_test_result = 0; short temp_avg = 0; short gyro_biases[3] = {0, 0, 0}; short accel_biases[3] = {0, 0, 0}; long accel_sens[3] = {0}; unsigned long saved_sensor_mask; unsigned char saved_state = inv_get_state(); mldl_cfg = inv_get_dl_config(); saved_sensor_mask = mldl_cfg->inv_mpu_cfg->requested_sensors; if (sensor_mask & (INV_THREE_AXIS_GYRO & ~INV_DMP_PROCESSOR)) { result = inv_set_mpu_sensors(INV_THREE_AXIS_GYRO & ~INV_DMP_PROCESSOR); if (result) { LOG_RESULT_LOCATION(result); return -1; } if (saved_state < INV_STATE_DMP_STARTED) { result = inv_dmp_start(); if (result) { LOG_RESULT_LOCATION(result); return -1; } } #ifdef TRACK_IDS result = get_mpu_unique_id(mlsl_handle); if (result != INV_SUCCESS) { MPL_LOGI("Could not read the device's unique ID\n"); MPL_LOGI("\n"); return -1; } #endif MPL_LOGI("Collecting one group of %d ms samples for each axis\n", (perform_full_test ? DEF_PERIOD_CAL : DEF_PERIOD_SELF)); MPL_LOGI("\n"); /* adjust the gyro sensitivity according to the gyro_sens_trim value */ adj_gyro_sens = test_setup.gyro_sens * mldl_cfg->mpu_chip_info->gyro_sens_trim / 131.072f; test_setup.gyro_fs = (int)(32768.f / adj_gyro_sens); /* collect gyro and temperature data, test gyro, report result */ gyro_test_result = test_gyro(mlsl_handle, gyro_biases, &temp_avg, perform_full_test); MPL_LOGI("\n"); if (gyro_test_result == 0) { MPL_LOGI_IF(provide_result, "Test : PASSED\n"); } else { MPL_LOGI_IF(provide_result, "Test : FAILED %d/%04X - Biases NOT stored\n", gyro_test_result, gyro_test_result); goto gyro_test_failed; } MPL_LOGI_IF(provide_result, "\n"); } if (sensor_mask & INV_THREE_AXIS_ACCEL) { if (!mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL]) { MPL_LOGI("\n"); MPL_LOGI("No accelerometer configured\n"); } else { result = inv_set_mpu_sensors(INV_THREE_AXIS_ACCEL); if (result) return -1; if (inv_get_state() < INV_STATE_DMP_STARTED) { result = inv_dmp_start(); if (result) return -1; } get_accel_sensitivity(accel_sens); /* collect accel data. if this step is skipped, ensure the array still contains zeros. */ accel_test_result = test_accel(mlsl_handle, sensor_mask >> 4, accel_biases, accel_sens[Z], perform_full_test); if (accel_test_result) goto accel_test_failed; /* if only Z accel is requested, clear out the biases from the other 2 axes */ if ((sensor_mask & INV_THREE_AXIS_ACCEL) == INV_Z_ACCEL) accel_biases[X] = accel_biases[Y] = 0; } } ALOGE("in %s: accel_bias is %d %d %d", __func__, accel_biases[0], accel_biases[1], accel_biases[2]); result = populate_data_store(sensor_mask, temp_avg, gyro_biases, accel_biases, accel_sens); if (result) return -1; result = inv_serial_write_cal(data_store, ML_INIT_CAL_LEN); if (result) { MPL_LOGI("Error : cannot write calibration on file - error %d\n", result); LOG_RESULT_LOCATION(result); return -1; } gyro_test_failed: accel_test_failed: /* restore the setting had at the beginning */ mldl_cfg->inv_mpu_state->status |= MPU_GYRO_NEEDS_CONFIG; result = inv_set_mpu_sensors(saved_sensor_mask); if (result) { LOG_RESULT_LOCATION(result); return -1; } /* turn off only if it was off when the function was called */ if (saved_state < INV_STATE_DMP_STARTED) { result = inv_dmp_stop(); if (result) { LOG_RESULT_LOCATION(result); return -1; } } if (gyro_test_result) return gyro_test_result; if (accel_test_result) return accel_test_result; return result; }