Home | History | Annotate | Download | only in mllite
      1 /*
      2  $License:
      3    Copyright 2011 InvenSense, Inc.
      4 
      5  Licensed under the Apache License, Version 2.0 (the "License");
      6  you may not use this file except in compliance with the License.
      7  You may obtain a copy of the License at
      8 
      9  http://www.apache.org/licenses/LICENSE-2.0
     10 
     11  Unless required by applicable law or agreed to in writing, software
     12  distributed under the License is distributed on an "AS IS" BASIS,
     13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  See the License for the specific language governing permissions and
     15  limitations under the License.
     16   $
     17  */
     18 /******************************************************************************
     19  *
     20  * $Id: ml.c 5642 2011-06-14 02:26:20Z mcaramello $
     21  *
     22  *****************************************************************************/
     23 
     24 /**
     25  *  @defgroup ML
     26  *  @brief  Motion Library APIs.
     27  *          The Motion Library processes gyroscopes, accelerometers, and
     28  *          compasses to provide a physical model of the movement for the
     29  *          sensors.
     30  *          The results of this processing may be used to control objects
     31  *          within a user interface environment, detect gestures, track 3D
     32  *          movement for gaming applications, and analyze the blur created
     33  *          due to hand movement while taking a picture.
     34  *
     35  *  @{
     36  *      @file   ml.c
     37  *      @brief  The Motion Library APIs.
     38  */
     39 
     40 /* ------------------ */
     41 /* - Include Files. - */
     42 /* ------------------ */
     43 
     44 #include <string.h>
     45 
     46 #include "ml.h"
     47 #include "mldl.h"
     48 #include "mltypes.h"
     49 #include "mlinclude.h"
     50 #include "compass.h"
     51 #include "dmpKey.h"
     52 #include "dmpDefault.h"
     53 #include "mlstates.h"
     54 #include "mlFIFO.h"
     55 #include "mlFIFOHW.h"
     56 #include "mlMathFunc.h"
     57 #include "mlsupervisor.h"
     58 #include "mlmath.h"
     59 #include "mlcontrol.h"
     60 #include "mldl_cfg.h"
     61 #include "mpu.h"
     62 #include "accel.h"
     63 #include "mlos.h"
     64 #include "mlsl.h"
     65 #include "mlos.h"
     66 #include "mlBiasNoMotion.h"
     67 #include "log.h"
     68 #undef MPL_LOG_TAG
     69 #define MPL_LOG_TAG "MPL-ml"
     70 
     71 #define ML_MOT_TYPE_NONE 0
     72 #define ML_MOT_TYPE_NO_MOTION 1
     73 #define ML_MOT_TYPE_MOTION_DETECTED 2
     74 
     75 #define ML_MOT_STATE_MOVING 0
     76 #define ML_MOT_STATE_NO_MOTION 1
     77 #define ML_MOT_STATE_BIAS_IN_PROG 2
     78 
     79 #define _mlDebug(x)             //{x}
     80 
     81 /* Global Variables */
     82 const unsigned char mlVer[] = { INV_VERSION };
     83 
     84 struct inv_params_obj inv_params_obj = {
     85     INV_BIAS_UPDATE_FUNC_DEFAULT,   // bias_mode
     86     INV_ORIENTATION_MASK_DEFAULT,   // orientation_mask
     87     INV_PROCESSED_DATA_CALLBACK_DEFAULT,    // fifo_processed_func
     88     INV_ORIENTATION_CALLBACK_DEFAULT,   // orientation_cb_func
     89     INV_MOTION_CALLBACK_DEFAULT,    // motion_cb_func
     90     INV_STATE_SERIAL_CLOSED     // starting state
     91 };
     92 
     93 struct inv_obj_t inv_obj;
     94 void *g_mlsl_handle;
     95 
     96 typedef struct {
     97     // These describe callbacks happening everythime a DMP interrupt is processed
     98     int_fast8_t numInterruptProcesses;
     99     // Array of function pointers, function being void function taking void
    100     inv_obj_func processInterruptCb[MAX_INTERRUPT_PROCESSES];
    101 
    102 } tMLXCallbackInterrupt;        // MLX_callback_t
    103 
    104 tMLXCallbackInterrupt mlxCallbackInterrupt;
    105 
    106 /* --------------- */
    107 /* -  Functions. - */
    108 /* --------------- */
    109 
    110 inv_error_t inv_freescale_sensor_fusion_16bit(unsigned short orient);
    111 inv_error_t inv_freescale_sensor_fusion_8bit(unsigned short orient);
    112 unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx);
    113 
    114 /**
    115  *  @brief  Open serial connection with the MPU device.
    116  *          This is the entry point of the MPL and must be
    117  *          called prior to any other function call.
    118  *
    119  *  @param  port     System handle for 'port' MPU device is found on.
    120  *                   The significance of this parameter varies by
    121  *                   platform. It is passed as 'port' to MLSLSerialOpen.
    122  *
    123  *  @return INV_SUCCESS or error code.
    124  */
    125 inv_error_t inv_serial_start(char const *port)
    126 {
    127     INVENSENSE_FUNC_START;
    128     inv_error_t result;
    129 
    130     if (inv_get_state() >= INV_STATE_SERIAL_OPENED)
    131         return INV_SUCCESS;
    132 
    133     result = inv_state_transition(INV_STATE_SERIAL_OPENED);
    134     if (result) {
    135         LOG_RESULT_LOCATION(result);
    136         return result;
    137     }
    138 
    139     result = inv_serial_open(port, &g_mlsl_handle);
    140     if (INV_SUCCESS != result) {
    141         (void)inv_state_transition(INV_STATE_SERIAL_CLOSED);
    142     }
    143 
    144     return result;
    145 }
    146 
    147 /**
    148  *  @brief  Close the serial communication.
    149  *          This function needs to be called explicitly to shut down
    150  *          the communication with the device.  Calling inv_dmp_close()
    151  *          won't affect the established serial communication.
    152  *  @return INV_SUCCESS; non-zero error code otherwise.
    153  */
    154 inv_error_t inv_serial_stop(void)
    155 {
    156     INVENSENSE_FUNC_START;
    157     inv_error_t result = INV_SUCCESS;
    158 
    159     if (inv_get_state() == INV_STATE_SERIAL_CLOSED)
    160         return INV_SUCCESS;
    161 
    162     result = inv_state_transition(INV_STATE_SERIAL_CLOSED);
    163     if (INV_SUCCESS != result) {
    164         MPL_LOGE("State Transition Failure in %s: %d\n", __func__, result);
    165     }
    166     result = inv_serial_close(g_mlsl_handle);
    167     if (INV_SUCCESS != result) {
    168         MPL_LOGE("Unable to close Serial Handle %s: %d\n", __func__, result);
    169     }
    170     return result;
    171 }
    172 
    173 /**
    174  *  @brief  Get the serial file handle to the device.
    175  *  @return The serial file handle.
    176  */
    177 void *inv_get_serial_handle(void)
    178 {
    179     INVENSENSE_FUNC_START;
    180     return g_mlsl_handle;
    181 }
    182 
    183 /**
    184  *  @brief  apply the choosen orientation and full scale range
    185  *          for gyroscopes, accelerometer, and compass.
    186  *  @return INV_SUCCESS if successful, a non-zero code otherwise.
    187  */
    188 inv_error_t inv_apply_calibration(void)
    189 {
    190     INVENSENSE_FUNC_START;
    191     signed char gyroCal[9] = { 0 };
    192     signed char accelCal[9] = { 0 };
    193     signed char magCal[9] = { 0 };
    194     float gyroScale = 2000.f;
    195     float accelScale = 0.f;
    196     float magScale = 0.f;
    197 
    198     inv_error_t result;
    199     int ii;
    200     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    201 
    202     for (ii = 0; ii < 9; ii++) {
    203         gyroCal[ii] = mldl_cfg->pdata->orientation[ii];
    204         if (NULL != mldl_cfg->accel){
    205             accelCal[ii] = mldl_cfg->pdata->accel.orientation[ii];
    206         }
    207         if (NULL != mldl_cfg->compass){
    208             magCal[ii] = mldl_cfg->pdata->compass.orientation[ii];
    209         }
    210     }
    211 
    212     switch (mldl_cfg->full_scale) {
    213     case MPU_FS_250DPS:
    214         gyroScale = 250.f;
    215         break;
    216     case MPU_FS_500DPS:
    217         gyroScale = 500.f;
    218         break;
    219     case MPU_FS_1000DPS:
    220         gyroScale = 1000.f;
    221         break;
    222     case MPU_FS_2000DPS:
    223         gyroScale = 2000.f;
    224         break;
    225     default:
    226         MPL_LOGE("Unrecognized full scale setting for gyros : %02X\n",
    227                  mldl_cfg->full_scale);
    228         return INV_ERROR_INVALID_PARAMETER;
    229         break;
    230     }
    231 
    232     if (NULL != mldl_cfg->accel){
    233         RANGE_FIXEDPOINT_TO_FLOAT(mldl_cfg->accel->range, accelScale);
    234         inv_obj.accel_sens = (long)(accelScale * 65536L);
    235     /* sensitivity adjustment, typically = 2 (for +/- 2 gee) */
    236 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
    237     defined CONFIG_MPU_SENSORS_MPU6050B1
    238     inv_obj.accel_sens /= 32768 / mldl_cfg->accel_sens_trim;
    239 #else
    240     inv_obj.accel_sens /= 2;
    241 #endif
    242     }
    243     if (NULL != mldl_cfg->compass){
    244         RANGE_FIXEDPOINT_TO_FLOAT(mldl_cfg->compass->range, magScale);
    245         inv_obj.compass_sens = (long)(magScale * 32768);
    246     }
    247 
    248     if (inv_get_state() == INV_STATE_DMP_OPENED) {
    249         result = inv_set_gyro_calibration(gyroScale, gyroCal);
    250         if (INV_SUCCESS != result) {
    251             MPL_LOGE("Unable to set Gyro Calibration\n");
    252             return result;
    253         }
    254         if (NULL != mldl_cfg->accel){
    255             result = inv_set_accel_calibration(accelScale, accelCal);
    256             if (INV_SUCCESS != result) {
    257                 MPL_LOGE("Unable to set Accel Calibration\n");
    258                 return result;
    259             }
    260         }
    261         if (NULL != mldl_cfg->compass){
    262             result = inv_set_compass_calibration(magScale, magCal);
    263             if (INV_SUCCESS != result) {
    264                 MPL_LOGE("Unable to set Mag Calibration\n");
    265                 return result;
    266             }
    267         }
    268     }
    269     return INV_SUCCESS;
    270 }
    271 
    272 /**
    273  *  @brief  Setup the DMP to handle the accelerometer endianess.
    274  *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
    275  */
    276 inv_error_t inv_apply_endian_accel(void)
    277 {
    278     INVENSENSE_FUNC_START;
    279     unsigned char regs[4] = { 0 };
    280     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    281     int endian = mldl_cfg->accel->endian;
    282 
    283     if (mldl_cfg->pdata->accel.bus != EXT_SLAVE_BUS_SECONDARY) {
    284         endian = EXT_SLAVE_BIG_ENDIAN;
    285     }
    286     switch (endian) {
    287     case EXT_SLAVE_FS8_BIG_ENDIAN:
    288     case EXT_SLAVE_FS16_BIG_ENDIAN:
    289     case EXT_SLAVE_LITTLE_ENDIAN:
    290         regs[0] = 0;
    291         regs[1] = 64;
    292         regs[2] = 0;
    293         regs[3] = 0;
    294         break;
    295     case EXT_SLAVE_BIG_ENDIAN:
    296     default:
    297         regs[0] = 0;
    298         regs[1] = 0;
    299         regs[2] = 64;
    300         regs[3] = 0;
    301     }
    302 
    303     return inv_set_mpu_memory(KEY_D_1_236, 4, regs);
    304 }
    305 
    306 /**
    307  * @internal
    308  * @brief   Initialize MLX data.  This should be called to setup the mlx
    309  *          output buffers before any motion processing is done.
    310  */
    311 void inv_init_ml(void)
    312 {
    313     INVENSENSE_FUNC_START;
    314     int ii;
    315     long tmp[COMPASS_NUM_AXES];
    316     // Set all values to zero by default
    317     memset(&inv_obj, 0, sizeof(struct inv_obj_t));
    318     memset(&mlxCallbackInterrupt, 0, sizeof(tMLXCallbackInterrupt));
    319 
    320     inv_obj.compass_correction[0] = 1073741824L;
    321     inv_obj.compass_correction_relative[0] = 1073741824L;
    322     inv_obj.compass_disturb_correction[0] = 1073741824L;
    323     inv_obj.compass_correction_offset[0] = 1073741824L;
    324     inv_obj.relative_quat[0] = 1073741824L;
    325 
    326     //Not used with the ST accelerometer
    327     inv_obj.no_motion_threshold = 20;   // noMotionThreshold
    328     //Not used with the ST accelerometer
    329     inv_obj.motion_duration = 1536; // motionDuration
    330 
    331     inv_obj.motion_state = INV_MOTION;  // Motion state
    332 
    333     inv_obj.bias_update_time = 8000;
    334     inv_obj.bias_calc_time = 2000;
    335 
    336     inv_obj.internal_motion_state = ML_MOT_STATE_MOVING;
    337 
    338     inv_obj.start_time = inv_get_tick_count();
    339 
    340     inv_obj.compass_cal[0] = 322122560L;
    341     inv_obj.compass_cal[4] = 322122560L;
    342     inv_obj.compass_cal[8] = 322122560L;
    343     inv_obj.compass_sens = 322122560L;  // Should only change when the sensor full-scale range (FSR) is changed.
    344 
    345     for (ii = 0; ii < COMPASS_NUM_AXES; ii++) {
    346         inv_obj.compass_scale[ii] = 65536L;
    347         inv_obj.compass_test_scale[ii] = 65536L;
    348         inv_obj.compass_bias_error[ii] = P_INIT;
    349         inv_obj.init_compass_bias[ii] = 0;
    350         inv_obj.compass_asa[ii] = (1L << 30);
    351     }
    352     if (inv_compass_read_scale(tmp) == INV_SUCCESS) {
    353         for (ii = 0; ii < COMPASS_NUM_AXES; ii++)
    354             inv_obj.compass_asa[ii] = tmp[ii];
    355     }
    356     inv_obj.got_no_motion_bias = 0;
    357     inv_obj.got_compass_bias = 0;
    358     inv_obj.compass_state = SF_UNCALIBRATED;
    359     inv_obj.acc_state = SF_STARTUP_SETTLE;
    360 
    361     inv_obj.got_init_compass_bias = 0;
    362     inv_obj.resetting_compass = 0;
    363 
    364     inv_obj.external_slave_callback = NULL;
    365     inv_obj.compass_accuracy = 0;
    366 
    367     inv_obj.factory_temp_comp = 0;
    368     inv_obj.got_coarse_heading = 0;
    369 
    370     inv_obj.compass_bias_ptr[0] = P_INIT;
    371     inv_obj.compass_bias_ptr[4] = P_INIT;
    372     inv_obj.compass_bias_ptr[8] = P_INIT;
    373 
    374     inv_obj.gyro_bias_err = 1310720;
    375 
    376     inv_obj.accel_lpf_gain = 1073744L;
    377     inv_obj.no_motion_accel_threshold = 7000000L;
    378 }
    379 
    380 /**
    381  * @internal
    382  * @brief   This registers a function to be called for each time the DMP
    383  *          generates an an interrupt.
    384  *          It will be called after inv_register_fifo_rate_process() which gets called
    385  *          every time the FIFO data is processed.
    386  *          The FIFO does not have to be on for this callback.
    387  * @param func Function to be called when a DMP interrupt occurs.
    388  * @return INV_SUCCESS or non-zero error code.
    389  */
    390 inv_error_t inv_register_dmp_interupt_cb(inv_obj_func func)
    391 {
    392     INVENSENSE_FUNC_START;
    393     // Make sure we have not filled up our number of allowable callbacks
    394     if (mlxCallbackInterrupt.numInterruptProcesses <=
    395         MAX_INTERRUPT_PROCESSES - 1) {
    396         int kk;
    397         // Make sure we haven't registered this function already
    398         for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) {
    399             if (mlxCallbackInterrupt.processInterruptCb[kk] == func) {
    400                 return INV_ERROR_INVALID_PARAMETER;
    401             }
    402         }
    403         // Add new callback
    404         mlxCallbackInterrupt.processInterruptCb[mlxCallbackInterrupt.
    405                                                 numInterruptProcesses] = func;
    406         mlxCallbackInterrupt.numInterruptProcesses++;
    407         return INV_SUCCESS;
    408     }
    409     return INV_ERROR_MEMORY_EXAUSTED;
    410 }
    411 
    412 /**
    413  * @internal
    414  * @brief This unregisters a function to be called for each DMP interrupt.
    415  * @return INV_SUCCESS or non-zero error code.
    416  */
    417 inv_error_t inv_unregister_dmp_interupt_cb(inv_obj_func func)
    418 {
    419     INVENSENSE_FUNC_START;
    420     int kk, jj;
    421     // Make sure we haven't registered this function already
    422     for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) {
    423         if (mlxCallbackInterrupt.processInterruptCb[kk] == func) {
    424             // FIXME, we may need a thread block here
    425             for (jj = kk + 1; jj < mlxCallbackInterrupt.numInterruptProcesses;
    426                  ++jj) {
    427                 mlxCallbackInterrupt.processInterruptCb[jj - 1] =
    428                     mlxCallbackInterrupt.processInterruptCb[jj];
    429             }
    430             mlxCallbackInterrupt.numInterruptProcesses--;
    431             return INV_SUCCESS;
    432         }
    433     }
    434     return INV_ERROR_INVALID_PARAMETER;
    435 }
    436 
    437 /**
    438  *  @internal
    439  *  @brief  Run the recorded interrupt process callbacks in the event
    440  *          of an interrupt.
    441  */
    442 void inv_run_dmp_interupt_cb(void)
    443 {
    444     int kk;
    445     for (kk = 0; kk < mlxCallbackInterrupt.numInterruptProcesses; ++kk) {
    446         if (mlxCallbackInterrupt.processInterruptCb[kk])
    447             mlxCallbackInterrupt.processInterruptCb[kk] (&inv_obj);
    448     }
    449 }
    450 
    451 /** @internal
    452 * Resets the Motion/No Motion state which should be called at startup and resume.
    453 */
    454 inv_error_t inv_reset_motion(void)
    455 {
    456     unsigned char regs[8];
    457     inv_error_t result;
    458 
    459     inv_obj.motion_state = INV_MOTION;
    460     inv_obj.flags[INV_MOTION_STATE_CHANGE] = INV_MOTION;
    461     inv_obj.no_motion_accel_time = inv_get_tick_count();
    462 #if defined CONFIG_MPU_SENSORS_MPU3050
    463     regs[0] = DINAD8 + 2;
    464     regs[1] = DINA0C;
    465     regs[2] = DINAD8 + 1;
    466     result = inv_set_mpu_memory(KEY_CFG_18, 3, regs);
    467     if (result) {
    468         LOG_RESULT_LOCATION(result);
    469         return result;
    470     }
    471 #else
    472 #endif
    473     regs[0] = (unsigned char)((inv_obj.motion_duration >> 8) & 0xff);
    474     regs[1] = (unsigned char)(inv_obj.motion_duration & 0xff);
    475     result = inv_set_mpu_memory(KEY_D_1_106, 2, regs);
    476     if (result) {
    477         LOG_RESULT_LOCATION(result);
    478         return result;
    479     }
    480     memset(regs, 0, 8);
    481     result = inv_set_mpu_memory(KEY_D_1_96, 8, regs);
    482     if (result) {
    483         LOG_RESULT_LOCATION(result);
    484         return result;
    485     }
    486 
    487     result =
    488         inv_set_mpu_memory(KEY_D_0_96, 4, inv_int32_to_big8(0x40000000, regs));
    489     if (result) {
    490         LOG_RESULT_LOCATION(result);
    491         return result;
    492     }
    493 
    494     inv_set_motion_state(INV_MOTION);
    495     return result;
    496 }
    497 
    498 /**
    499  * @internal
    500  * @brief   inv_start_bias_calc starts the bias calculation on the MPU.
    501  */
    502 void inv_start_bias_calc(void)
    503 {
    504     INVENSENSE_FUNC_START;
    505 
    506     inv_obj.suspend = 1;
    507 }
    508 
    509 /**
    510  * @internal
    511  * @brief   inv_stop_bias_calc stops the bias calculation on the MPU.
    512  */
    513 void inv_stop_bias_calc(void)
    514 {
    515     INVENSENSE_FUNC_START;
    516 
    517     inv_obj.suspend = 0;
    518 }
    519 
    520 /**
    521  *  @brief  inv_update_data fetches data from the fifo and updates the
    522  *          motion algorithms.
    523  *
    524  *  @pre    inv_dmp_open()
    525  *          @ifnot MPL_MF
    526  *              or inv_open_low_power_pedometer()
    527  *              or inv_eis_open_dmp()
    528  *          @endif
    529  *          and inv_dmp_start() must have been called.
    530  *
    531  *  @note   Motion algorithm data is constant between calls to inv_update_data
    532  *
    533  * @return
    534  * - INV_SUCCESS
    535  * - Non-zero error code
    536  */
    537 inv_error_t inv_update_data(void)
    538 {
    539     INVENSENSE_FUNC_START;
    540     inv_error_t result = INV_SUCCESS;
    541     int_fast8_t got, ftry;
    542     uint_fast8_t mpu_interrupt;
    543     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    544 
    545     if (inv_get_state() != INV_STATE_DMP_STARTED)
    546         return INV_ERROR_SM_IMPROPER_STATE;
    547 
    548     // Set the maximum number of FIFO packets we want to process
    549     if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) {
    550         ftry = 100;             // Large enough to process all packets
    551     } else {
    552         ftry = 1;
    553     }
    554 
    555     // Go and process at most ftry number of packets, probably less than ftry
    556     result = inv_read_and_process_fifo(ftry, &got);
    557     if (result) {
    558         LOG_RESULT_LOCATION(result);
    559         return result;
    560     }
    561 
    562     // Process all interrupts
    563     mpu_interrupt = inv_get_interrupt_trigger(INTSRC_AUX1);
    564     if (mpu_interrupt) {
    565         inv_clear_interrupt_trigger(INTSRC_AUX1);
    566     }
    567     // Check if interrupt was from MPU
    568     mpu_interrupt = inv_get_interrupt_trigger(INTSRC_MPU);
    569     if (mpu_interrupt) {
    570         inv_clear_interrupt_trigger(INTSRC_MPU);
    571     }
    572     // Take care of the callbacks that want to be notified when there was an MPU interrupt
    573     if (mpu_interrupt) {
    574         inv_run_dmp_interupt_cb();
    575     }
    576 
    577     result = inv_get_fifo_status();
    578     return result;
    579 }
    580 
    581 /**
    582  *  @brief  inv_check_flag returns the value of a flag.
    583  *          inv_check_flag can be used to check a number of flags,
    584  *          allowing users to poll flags rather than register callback
    585  *          functions. If a flag is set to True when inv_check_flag is called,
    586  *          the flag is automatically reset.
    587  *          The flags are:
    588  *          - INV_RAW_DATA_READY
    589  *          Indicates that new raw data is available.
    590  *          - INV_PROCESSED_DATA_READY
    591  *          Indicates that new processed data is available.
    592  *          - INV_GOT_GESTURE
    593  *          Indicates that a gesture has been detected by the gesture engine.
    594  *          - INV_MOTION_STATE_CHANGE
    595  *          Indicates that a change has been made from motion to no motion,
    596  *          or vice versa.
    597  *
    598  *  @pre    inv_dmp_open()
    599  *          @ifnot MPL_MF
    600  *              or inv_open_low_power_pedometer()
    601  *              or inv_eis_open_dmp()
    602  *          @endif
    603  *          and inv_dmp_start() must have been called.
    604  *
    605  *  @param flag The flag to check.
    606  *
    607  * @return TRUE or FALSE state of the flag
    608  */
    609 int inv_check_flag(int flag)
    610 {
    611     INVENSENSE_FUNC_START;
    612     int flagReturn = inv_obj.flags[flag];
    613 
    614     inv_obj.flags[flag] = 0;
    615     return flagReturn;
    616 }
    617 
    618 /**
    619  *  @brief  Enable generation of the DMP interrupt when Motion or no-motion
    620  *          is detected
    621  *  @param on
    622  *          Boolean to turn the interrupt on or off.
    623  *  @return INV_SUCCESS or non-zero error code.
    624  */
    625 inv_error_t inv_set_motion_interrupt(unsigned char on)
    626 {
    627     INVENSENSE_FUNC_START;
    628     inv_error_t result;
    629     unsigned char regs[2] = { 0 };
    630 
    631     if (inv_get_state() < INV_STATE_DMP_OPENED)
    632         return INV_ERROR_SM_IMPROPER_STATE;
    633 
    634     if (on) {
    635         result = inv_get_dl_cfg_int(BIT_DMP_INT_EN);
    636         if (result) {
    637             LOG_RESULT_LOCATION(result);
    638             return result;
    639         }
    640         inv_obj.interrupt_sources |= INV_INT_MOTION;
    641     } else {
    642         inv_obj.interrupt_sources &= ~INV_INT_MOTION;
    643         if (!inv_obj.interrupt_sources) {
    644             result = inv_get_dl_cfg_int(0);
    645             if (result) {
    646                 LOG_RESULT_LOCATION(result);
    647                 return result;
    648             }
    649         }
    650     }
    651 
    652     if (on) {
    653         regs[0] = DINAFE;
    654     } else {
    655         regs[0] = DINAD8;
    656     }
    657     result = inv_set_mpu_memory(KEY_CFG_7, 1, regs);
    658     if (result) {
    659         LOG_RESULT_LOCATION(result);
    660         return result;
    661     }
    662     return result;
    663 }
    664 
    665 /**
    666  * Enable generation of the DMP interrupt when a FIFO packet is ready
    667  *
    668  * @param on Boolean to turn the interrupt on or off
    669  *
    670  * @return INV_SUCCESS or non-zero error code
    671  */
    672 inv_error_t inv_set_fifo_interrupt(unsigned char on)
    673 {
    674     INVENSENSE_FUNC_START;
    675     inv_error_t result;
    676     unsigned char regs[2] = { 0 };
    677 
    678     if (inv_get_state() < INV_STATE_DMP_OPENED)
    679         return INV_ERROR_SM_IMPROPER_STATE;
    680 
    681     if (on) {
    682         result = inv_get_dl_cfg_int(BIT_DMP_INT_EN);
    683         if (result) {
    684             LOG_RESULT_LOCATION(result);
    685             return result;
    686         }
    687         inv_obj.interrupt_sources |= INV_INT_FIFO;
    688     } else {
    689         inv_obj.interrupt_sources &= ~INV_INT_FIFO;
    690         if (!inv_obj.interrupt_sources) {
    691             result = inv_get_dl_cfg_int(0);
    692             if (result) {
    693                 LOG_RESULT_LOCATION(result);
    694                 return result;
    695             }
    696         }
    697     }
    698 
    699     if (on) {
    700         regs[0] = DINAFE;
    701     } else {
    702         regs[0] = DINAD8;
    703     }
    704     result = inv_set_mpu_memory(KEY_CFG_6, 1, regs);
    705     if (result) {
    706         LOG_RESULT_LOCATION(result);
    707         return result;
    708     }
    709     return result;
    710 }
    711 
    712 /**
    713  * @brief   Get the current set of DMP interrupt sources.
    714  *          These interrupts are generated by the DMP and can be
    715  *          routed to the MPU interrupt line via internal
    716  *          settings.
    717  *
    718  *  @pre    inv_dmp_open()
    719  *          @ifnot MPL_MF
    720  *              or inv_open_low_power_pedometer()
    721  *              or inv_eis_open_dmp()
    722  *          @endif
    723  *          must have been called.
    724  *
    725  * @return  Currently enabled interrupt sources.  The possible interrupts are:
    726  *          - INV_INT_FIFO,
    727  *          - INV_INT_MOTION,
    728  *          - INV_INT_TAP
    729  */
    730 int inv_get_interrupts(void)
    731 {
    732     INVENSENSE_FUNC_START;
    733 
    734     if (inv_get_state() < INV_STATE_DMP_OPENED)
    735         return 0;               // error
    736 
    737     return inv_obj.interrupt_sources;
    738 }
    739 
    740 /**
    741  *  @brief  Sets up the Accelerometer calibration and scale factor.
    742  *
    743  *          Please refer to the provided "9-Axis Sensor Fusion Application
    744  *          Note" document provided.  Section 5, "Sensor Mounting Orientation"
    745  *          offers a good coverage on the mounting matrices and explains how
    746  *          to use them.
    747  *
    748  *  @pre    inv_dmp_open()
    749  *          @ifnot MPL_MF
    750  *              or inv_open_low_power_pedometer()
    751  *              or inv_eis_open_dmp()
    752  *          @endif
    753  *          must have been called.
    754  *  @pre    inv_dmp_start() must <b>NOT</b> have been called.
    755  *
    756  *  @see    inv_set_gyro_calibration().
    757  *  @see    inv_set_compass_calibration().
    758  *
    759  *  @param[in]  range
    760  *                  The range of the accelerometers in g's. An accelerometer
    761  *                  that has a range of +2g's to -2g's should pass in 2.
    762  *  @param[in]  orientation
    763  *                  A 9 element matrix that represents how the accelerometers
    764  *                  are oriented with respect to the device they are mounted
    765  *                  in and the reference axis system.
    766  *                  A typical set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}.
    767  *                  This example corresponds to a 3 x 3 identity matrix.
    768  *
    769  *  @return INV_SUCCESS if successful; a non-zero error code otherwise.
    770  */
    771 inv_error_t inv_set_accel_calibration(float range, signed char *orientation)
    772 {
    773     INVENSENSE_FUNC_START;
    774     float cal[9];
    775     float scale = range / 32768.f;
    776     int kk;
    777     unsigned long sf;
    778     inv_error_t result;
    779     unsigned char regs[4] = { 0, 0, 0, 0 };
    780     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    781 
    782     if (inv_get_state() != INV_STATE_DMP_OPENED)
    783         return INV_ERROR_SM_IMPROPER_STATE;
    784 
    785     /* Apply zero g-offset values */
    786     if (ACCEL_ID_KXSD9 == mldl_cfg->accel->id) {
    787         regs[0] = 0x80;
    788         regs[1] = 0x0;
    789         regs[2] = 0x80;
    790         regs[3] = 0x0;
    791     }
    792 
    793     if (inv_dmpkey_supported(KEY_D_1_152)) {
    794         result = inv_set_mpu_memory(KEY_D_1_152, 4, &regs[0]);
    795         if (result) {
    796             LOG_RESULT_LOCATION(result);
    797             return result;
    798         }
    799     }
    800 
    801     if (scale == 0) {
    802         inv_obj.accel_sens = 0;
    803     }
    804 
    805     if (mldl_cfg->accel->id) {
    806 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
    807     defined CONFIG_MPU_SENSORS_MPU6050B1
    808         unsigned char tmp[3] = { DINA0C, DINAC9, DINA2C };
    809 #else
    810         unsigned char tmp[3] = { DINA4C, DINACD, DINA6C };
    811 #endif
    812         struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    813         unsigned char regs[3];
    814         unsigned short orient;
    815 
    816         for (kk = 0; kk < 9; ++kk) {
    817             cal[kk] = scale * orientation[kk];
    818             inv_obj.accel_cal[kk] = (long)(cal[kk] * (float)(1L << 30));
    819         }
    820 
    821         orient = inv_orientation_matrix_to_scalar(orientation);
    822         regs[0] = tmp[orient & 3];
    823         regs[1] = tmp[(orient >> 3) & 3];
    824         regs[2] = tmp[(orient >> 6) & 3];
    825         result = inv_set_mpu_memory(KEY_FCFG_2, 3, regs);
    826         if (result) {
    827             LOG_RESULT_LOCATION(result);
    828             return result;
    829         }
    830 
    831         regs[0] = DINA26;
    832         regs[1] = DINA46;
    833 #if defined CONFIG_MPU_SENSORS_MPU3050 || defined CONFIG_MPU_SENSORS_MPU6050A2
    834         regs[2] = DINA66;
    835 #else
    836         if (MPL_PROD_KEY(mldl_cfg->product_id, mldl_cfg->product_revision)
    837                 == MPU_PRODUCT_KEY_B1_E1_5)
    838             regs[2] = DINA76;
    839         else
    840             regs[2] = DINA66;
    841 #endif
    842         if (orient & 4)
    843             regs[0] |= 1;
    844         if (orient & 0x20)
    845             regs[1] |= 1;
    846         if (orient & 0x100)
    847             regs[2] |= 1;
    848 
    849         result = inv_set_mpu_memory(KEY_FCFG_7, 3, regs);
    850         if (result) {
    851             LOG_RESULT_LOCATION(result);
    852             return result;
    853         }
    854 
    855         if (mldl_cfg->accel->id == ACCEL_ID_MMA845X) {
    856             result = inv_freescale_sensor_fusion_16bit(orient);
    857             if (result) {
    858                 LOG_RESULT_LOCATION(result);
    859                 return result;
    860             }
    861         } else if (mldl_cfg->accel->id == ACCEL_ID_MMA8450) {
    862             result = inv_freescale_sensor_fusion_8bit(orient);
    863             if (result) {
    864                 LOG_RESULT_LOCATION(result);
    865                 return result;
    866             }
    867         }
    868     }
    869 
    870     if (inv_obj.accel_sens != 0) {
    871         sf = (1073741824L / inv_obj.accel_sens);
    872     } else {
    873         sf = 0;
    874     }
    875     regs[0] = (unsigned char)((sf >> 8) & 0xff);
    876     regs[1] = (unsigned char)(sf & 0xff);
    877     result = inv_set_mpu_memory(KEY_D_0_108, 2, regs);
    878     if (result) {
    879         LOG_RESULT_LOCATION(result);
    880         return result;
    881     }
    882 
    883     return result;
    884 }
    885 
    886 /**
    887  *  @brief  Sets up the Gyro calibration and scale factor.
    888  *
    889  *          Please refer to the provided "9-Axis Sensor Fusion Application
    890  *          Note" document provided.  Section 5, "Sensor Mounting Orientation"
    891  *          offers a good coverage on the mounting matrices and explains
    892  *          how to use them.
    893  *
    894  *  @pre    inv_dmp_open()
    895  *          @ifnot MPL_MF
    896  *              or inv_open_low_power_pedometer()
    897  *              or inv_eis_open_dmp()
    898  *          @endif
    899  *          must have been called.
    900  *  @pre    inv_dmp_start() must have <b>NOT</b> been called.
    901  *
    902  *  @see    inv_set_accel_calibration().
    903  *  @see    inv_set_compass_calibration().
    904  *
    905  *  @param[in]  range
    906  *                  The range of the gyros in degrees per second. A gyro
    907  *                  that has a range of +2000 dps to -2000 dps should pass in
    908  *                  2000.
    909  *  @param[in] orientation
    910  *                  A 9 element matrix that represents how the gyro are oriented
    911  *                  with respect to the device they are mounted in. A typical
    912  *                  set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}. This
    913  *                  example corresponds to a 3 x 3 identity matrix.
    914  *
    915  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
    916  */
    917 inv_error_t inv_set_gyro_calibration(float range, signed char *orientation)
    918 {
    919     INVENSENSE_FUNC_START;
    920 
    921     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
    922     int kk;
    923     float scale;
    924     inv_error_t result;
    925 
    926     unsigned char regs[12] = { 0 };
    927     unsigned char maxVal = 0;
    928     unsigned char tmpPtr = 0;
    929     unsigned char tmpSign = 0;
    930     unsigned char i = 0;
    931     int sf = 0;
    932 
    933     if (inv_get_state() != INV_STATE_DMP_OPENED)
    934         return INV_ERROR_SM_IMPROPER_STATE;
    935 
    936     if (mldl_cfg->gyro_sens_trim != 0) {
    937         /* adjust the declared range to consider the gyro_sens_trim
    938            of this part when different from the default (first dividend) */
    939         range *= (32768.f / 250) / mldl_cfg->gyro_sens_trim;
    940     }
    941 
    942     scale = range / 32768.f;    // inverse of sensitivity for the given full scale range
    943     inv_obj.gyro_sens = (long)(range * 32768L);
    944 
    945     for (kk = 0; kk < 9; ++kk) {
    946         inv_obj.gyro_cal[kk] = (long)(scale * orientation[kk] * (1L << 30));
    947         inv_obj.gyro_orient[kk] = (long)((double)orientation[kk] * (1L << 30));
    948     }
    949 
    950     {
    951 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
    952     defined CONFIG_MPU_SENSORS_MPU6050B1
    953         unsigned char tmpD = DINA4C;
    954         unsigned char tmpE = DINACD;
    955         unsigned char tmpF = DINA6C;
    956 #else
    957         unsigned char tmpD = DINAC9;
    958         unsigned char tmpE = DINA2C;
    959         unsigned char tmpF = DINACB;
    960 #endif
    961         regs[3] = DINA36;
    962         regs[4] = DINA56;
    963         regs[5] = DINA76;
    964 
    965         for (i = 0; i < 3; i++) {
    966             maxVal = 0;
    967             tmpSign = 0;
    968             if (inv_obj.gyro_orient[0 + 3 * i] < 0)
    969                 tmpSign = 1;
    970             if (ABS(inv_obj.gyro_orient[1 + 3 * i]) >
    971                 ABS(inv_obj.gyro_orient[0 + 3 * i])) {
    972                 maxVal = 1;
    973                 if (inv_obj.gyro_orient[1 + 3 * i] < 0)
    974                     tmpSign = 1;
    975             }
    976             if (ABS(inv_obj.gyro_orient[2 + 3 * i]) >
    977                 ABS(inv_obj.gyro_orient[1 + 3 * i])) {
    978                 tmpSign = 0;
    979                 maxVal = 2;
    980                 if (inv_obj.gyro_orient[2 + 3 * i] < 0)
    981                     tmpSign = 1;
    982             }
    983             if (maxVal == 0) {
    984                 regs[tmpPtr++] = tmpD;
    985                 if (tmpSign)
    986                     regs[tmpPtr + 2] |= 0x01;
    987             } else if (maxVal == 1) {
    988                 regs[tmpPtr++] = tmpE;
    989                 if (tmpSign)
    990                     regs[tmpPtr + 2] |= 0x01;
    991             } else {
    992                 regs[tmpPtr++] = tmpF;
    993                 if (tmpSign)
    994                     regs[tmpPtr + 2] |= 0x01;
    995             }
    996         }
    997         result = inv_set_mpu_memory(KEY_FCFG_1, 3, regs);
    998         if (result) {
    999             LOG_RESULT_LOCATION(result);
   1000             return result;
   1001         }
   1002         result = inv_set_mpu_memory(KEY_FCFG_3, 3, &regs[3]);
   1003         if (result) {
   1004             LOG_RESULT_LOCATION(result);
   1005             return result;
   1006         }
   1007 
   1008         //sf = (gyroSens) * (0.5 * (pi/180) / 200.0) * 16384
   1009         inv_obj.gyro_sf =
   1010             (long)(((long long)inv_obj.gyro_sens * 767603923LL) / 1073741824LL);
   1011         result =
   1012             inv_set_mpu_memory(KEY_D_0_104, 4,
   1013                                inv_int32_to_big8(inv_obj.gyro_sf, regs));
   1014         if (result) {
   1015             LOG_RESULT_LOCATION(result);
   1016             return result;
   1017         }
   1018 
   1019         if (inv_obj.gyro_sens != 0) {
   1020             sf = (long)((long long)23832619764371LL / inv_obj.gyro_sens);
   1021         } else {
   1022             sf = 0;
   1023         }
   1024 
   1025         result = inv_set_mpu_memory(KEY_D_0_24, 4, inv_int32_to_big8(sf, regs));
   1026         if (result) {
   1027             LOG_RESULT_LOCATION(result);
   1028             return result;
   1029         }
   1030     }
   1031     return INV_SUCCESS;
   1032 }
   1033 
   1034 /**
   1035  *  @brief  Sets up the Compass calibration and scale factor.
   1036  *
   1037  *          Please refer to the provided "9-Axis Sensor Fusion Application
   1038  *          Note" document provided.  Section 5, "Sensor Mounting Orientation"
   1039  *          offers a good coverage on the mounting matrices and explains
   1040  *          how to use them.
   1041  *
   1042  *  @pre    inv_dmp_open()
   1043  *          @ifnot MPL_MF
   1044  *              or inv_open_low_power_pedometer()
   1045  *              or inv_eis_open_dmp()
   1046  *          @endif
   1047  *          must have been called.
   1048  *  @pre    inv_dmp_start() must have <b>NOT</b> been called.
   1049  *
   1050  *  @see    inv_set_gyro_calibration().
   1051  *  @see    inv_set_accel_calibration().
   1052  *
   1053  *  @param[in] range
   1054  *                  The range of the compass.
   1055  *  @param[in] orientation
   1056  *                  A 9 element matrix that represents how the compass is
   1057  *                  oriented with respect to the device they are mounted in.
   1058  *                  A typical set of values are {1, 0, 0, 0, 1, 0, 0, 0, 1}.
   1059  *                  This example corresponds to a 3 x 3 identity matrix.
   1060  *                  The matrix describes how to go from the chip mounting to
   1061  *                  the body of the device.
   1062  *
   1063  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1064  */
   1065 inv_error_t inv_set_compass_calibration(float range, signed char *orientation)
   1066 {
   1067     INVENSENSE_FUNC_START;
   1068     float cal[9];
   1069     float scale = range / 32768.f;
   1070     int kk;
   1071     unsigned short compassId = 0;
   1072 
   1073     compassId = inv_get_compass_id();
   1074 
   1075     if ((compassId == COMPASS_ID_YAS529) || (compassId == COMPASS_ID_HMC5883)
   1076         || (compassId == COMPASS_ID_LSM303M)) {
   1077         scale /= 32.0f;
   1078     }
   1079 
   1080     for (kk = 0; kk < 9; ++kk) {
   1081         cal[kk] = scale * orientation[kk];
   1082         inv_obj.compass_cal[kk] = (long)(cal[kk] * (float)(1L << 30));
   1083     }
   1084 
   1085     inv_obj.compass_sens = (long)(scale * 1073741824L);
   1086 
   1087     if (inv_dmpkey_supported(KEY_CPASS_MTX_00)) {
   1088         unsigned char reg0[4] = { 0, 0, 0, 0 };
   1089         unsigned char regp[4] = { 64, 0, 0, 0 };
   1090         unsigned char regn[4] = { 64 + 128, 0, 0, 0 };
   1091         unsigned char *reg;
   1092         int_fast8_t kk;
   1093         unsigned short keyList[9] =
   1094             { KEY_CPASS_MTX_00, KEY_CPASS_MTX_01, KEY_CPASS_MTX_02,
   1095             KEY_CPASS_MTX_10, KEY_CPASS_MTX_11, KEY_CPASS_MTX_12,
   1096             KEY_CPASS_MTX_20, KEY_CPASS_MTX_21, KEY_CPASS_MTX_22
   1097         };
   1098 
   1099         for (kk = 0; kk < 9; ++kk) {
   1100 
   1101             if (orientation[kk] == 1)
   1102                 reg = regp;
   1103             else if (orientation[kk] == -1)
   1104                 reg = regn;
   1105             else
   1106                 reg = reg0;
   1107             inv_set_mpu_memory(keyList[kk], 4, reg);
   1108         }
   1109     }
   1110 
   1111     return INV_SUCCESS;
   1112 }
   1113 
   1114 /**
   1115 * @internal
   1116 * @brief Sets the Gyro Dead Zone based upon LPF filter settings and Control setup.
   1117 */
   1118 inv_error_t inv_set_dead_zone(void)
   1119 {
   1120     unsigned char reg;
   1121     inv_error_t result;
   1122     extern struct control_params cntrl_params;
   1123 
   1124     if (cntrl_params.functions & INV_DEAD_ZONE) {
   1125         reg = 0x08;
   1126     } else {
   1127 #if defined CONFIG_MPU_SENSORS_MPU6050A2 || \
   1128     defined CONFIG_MPU_SENSORS_MPU6050B1
   1129         reg = 0;
   1130 #else
   1131         if (inv_params_obj.bias_mode & INV_BIAS_FROM_LPF) {
   1132             reg = 0x2;
   1133         } else {
   1134             reg = 0;
   1135         }
   1136 #endif
   1137     }
   1138 
   1139     result = inv_set_mpu_memory(KEY_D_0_163, 1, &reg);
   1140     if (result) {
   1141         LOG_RESULT_LOCATION(result);
   1142         return result;
   1143     }
   1144     return result;
   1145 }
   1146 
   1147 /**
   1148  *  @brief  inv_set_bias_update is used to register which algorithms will be
   1149  *          used to automatically reset the gyroscope bias.
   1150  *          The engine INV_BIAS_UPDATE must be enabled for these algorithms to
   1151  *          run.
   1152  *
   1153  *  @pre    inv_dmp_open()
   1154  *          @ifnot MPL_MF
   1155  *              or inv_open_low_power_pedometer()
   1156  *              or inv_eis_open_dmp()
   1157  *          @endif
   1158  *          and inv_dmp_start()
   1159  *          must <b>NOT</b> have been called.
   1160  *
   1161  *  @param  function    A function or bitwise OR of functions that determine
   1162  *                      how the gyroscope bias will be automatically updated.
   1163  *                      Functions include:
   1164  *                      - INV_NONE or 0,
   1165  *                      - INV_BIAS_FROM_NO_MOTION,
   1166  *                      - INV_BIAS_FROM_GRAVITY,
   1167  *                      - INV_BIAS_FROM_TEMPERATURE,
   1168                     \ifnot UMPL
   1169  *                      - INV_BIAS_FROM_LPF,
   1170  *                      - INV_MAG_BIAS_FROM_MOTION,
   1171  *                      - INV_MAG_BIAS_FROM_GYRO,
   1172  *                      - INV_ALL.
   1173  *                   \endif
   1174  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1175  */
   1176 inv_error_t inv_set_bias_update(unsigned short function)
   1177 {
   1178     INVENSENSE_FUNC_START;
   1179     unsigned char regs[4];
   1180     long tmp[3] = { 0, 0, 0 };
   1181     inv_error_t result = INV_SUCCESS;
   1182     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
   1183 
   1184     if (inv_get_state() != INV_STATE_DMP_OPENED)
   1185         return INV_ERROR_SM_IMPROPER_STATE;
   1186 
   1187     /* do not allow progressive no motion bias tracker to run -
   1188        it's not fully debugged */
   1189     function &= ~INV_PROGRESSIVE_NO_MOTION; // FIXME, workaround
   1190     MPL_LOGV("forcing disable of PROGRESSIVE_NO_MOTION bias tracker\n");
   1191 
   1192     // You must use EnableFastNoMotion() to get this feature
   1193     function &= ~INV_BIAS_FROM_FAST_NO_MOTION;
   1194 
   1195     // You must use DisableFastNoMotion() to turn this feature off
   1196     if (inv_params_obj.bias_mode & INV_BIAS_FROM_FAST_NO_MOTION)
   1197         function |= INV_BIAS_FROM_FAST_NO_MOTION;
   1198 
   1199     /*--- remove magnetic components from bias tracking
   1200           if there is no compass ---*/
   1201     if (!inv_compass_present()) {
   1202         function &= ~(INV_MAG_BIAS_FROM_GYRO | INV_MAG_BIAS_FROM_MOTION);
   1203     } else {
   1204         function &= ~(INV_BIAS_FROM_LPF);
   1205     }
   1206 
   1207     // Enable function sets bias from no motion
   1208     inv_params_obj.bias_mode = function & (~INV_BIAS_FROM_NO_MOTION);
   1209 
   1210     if (function & INV_BIAS_FROM_NO_MOTION) {
   1211         inv_enable_bias_no_motion();
   1212     } else {
   1213         inv_disable_bias_no_motion();
   1214     }
   1215 
   1216     if (inv_params_obj.bias_mode & INV_BIAS_FROM_LPF) {
   1217         regs[0] = DINA80 + 2;
   1218         regs[1] = DINA2D;
   1219         regs[2] = DINA55;
   1220         regs[3] = DINA7D;
   1221     } else {
   1222         regs[0] = DINA80 + 7;
   1223         regs[1] = DINA2D;
   1224         regs[2] = DINA35;
   1225         regs[3] = DINA3D;
   1226     }
   1227     result = inv_set_mpu_memory(KEY_FCFG_5, 4, regs);
   1228     if (result) {
   1229         LOG_RESULT_LOCATION(result);
   1230         return result;
   1231     }
   1232     result = inv_set_dead_zone();
   1233     if (result) {
   1234         LOG_RESULT_LOCATION(result);
   1235         return result;
   1236     }
   1237 
   1238     if ((inv_params_obj.bias_mode & INV_BIAS_FROM_GRAVITY) &&
   1239         !inv_compass_present()) {
   1240         result = inv_set_gyro_data_source(INV_GYRO_FROM_QUATERNION);
   1241         if (result) {
   1242             LOG_RESULT_LOCATION(result);
   1243             return result;
   1244         }
   1245     } else {
   1246         result = inv_set_gyro_data_source(INV_GYRO_FROM_RAW);
   1247         if (result) {
   1248             LOG_RESULT_LOCATION(result);
   1249             return result;
   1250         }
   1251     }
   1252 
   1253     inv_obj.factory_temp_comp = 0;  // FIXME, workaround
   1254     if ((mldl_cfg->offset_tc[0] != 0) ||
   1255         (mldl_cfg->offset_tc[1] != 0) || (mldl_cfg->offset_tc[2] != 0)) {
   1256         inv_obj.factory_temp_comp = 1;
   1257     }
   1258 
   1259     if (inv_obj.factory_temp_comp == 0) {
   1260         if (inv_params_obj.bias_mode & INV_BIAS_FROM_TEMPERATURE) {
   1261             result = inv_set_gyro_temp_slope(inv_obj.temp_slope);
   1262             if (result) {
   1263                 LOG_RESULT_LOCATION(result);
   1264                 return result;
   1265             }
   1266         } else {
   1267             result = inv_set_gyro_temp_slope(tmp);
   1268             if (result) {
   1269                 LOG_RESULT_LOCATION(result);
   1270                 return result;
   1271             }
   1272         }
   1273     } else {
   1274         inv_params_obj.bias_mode &= ~INV_LEARN_BIAS_FROM_TEMPERATURE;
   1275         MPL_LOGV("factory temperature compensation coefficients available - "
   1276                  "disabling INV_LEARN_BIAS_FROM_TEMPERATURE\n");
   1277     }
   1278 
   1279     /*---- hard requirement for using bias tracking BIAS_FROM_GRAVITY, relying on
   1280            compass and accel data, is to have accelerometer data delivered in the
   1281            FIFO ----*/
   1282     if (((inv_params_obj.bias_mode & INV_BIAS_FROM_GRAVITY)
   1283          && inv_compass_present())
   1284         || (inv_params_obj.bias_mode & INV_MAG_BIAS_FROM_GYRO)
   1285         || (inv_params_obj.bias_mode & INV_MAG_BIAS_FROM_MOTION)) {
   1286         inv_send_accel(INV_ALL, INV_32_BIT);
   1287         inv_send_gyro(INV_ALL, INV_32_BIT);
   1288     }
   1289 
   1290     return result;
   1291 }
   1292 
   1293 /**
   1294  *  @brief  inv_get_motion_state is used to determine if the device is in
   1295  *          a 'motion' or 'no motion' state.
   1296  *          inv_get_motion_state returns INV_MOTION of the device is moving,
   1297  *          or INV_NO_MOTION if the device is not moving.
   1298  *
   1299  *  @pre    inv_dmp_open()
   1300  *          @ifnot MPL_MF
   1301  *              or inv_open_low_power_pedometer()
   1302  *              or inv_eis_open_dmp()
   1303  *          @endif
   1304  *          and inv_dmp_start()
   1305  *          must have been called.
   1306  *
   1307  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1308  */
   1309 int inv_get_motion_state(void)
   1310 {
   1311     INVENSENSE_FUNC_START;
   1312     return inv_obj.motion_state;
   1313 }
   1314 
   1315 /**
   1316  *  @brief  inv_set_no_motion_thresh is used to set the threshold for
   1317  *          detecting INV_NO_MOTION
   1318  *
   1319  *  @pre    inv_dmp_open()
   1320  *          @ifnot MPL_MF
   1321  *              or inv_open_low_power_pedometer()
   1322  *              or inv_eis_open_dmp()
   1323  *          @endif
   1324  *          must have been called.
   1325  *
   1326  *  @param  thresh  A threshold scaled in degrees per second.
   1327  *
   1328  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1329  */
   1330 inv_error_t inv_set_no_motion_thresh(float thresh)
   1331 {
   1332     inv_error_t result = INV_SUCCESS;
   1333     unsigned char regs[4] = { 0 };
   1334     long tmp;
   1335     INVENSENSE_FUNC_START;
   1336 
   1337     tmp = (long)(thresh * thresh * 2.045f);
   1338     if (tmp < 0) {
   1339         return INV_ERROR;
   1340     } else if (tmp > 8180000L) {
   1341         return INV_ERROR;
   1342     }
   1343     inv_obj.no_motion_threshold = tmp;
   1344 
   1345     regs[0] = (unsigned char)(tmp >> 24);
   1346     regs[1] = (unsigned char)((tmp >> 16) & 0xff);
   1347     regs[2] = (unsigned char)((tmp >> 8) & 0xff);
   1348     regs[3] = (unsigned char)(tmp & 0xff);
   1349 
   1350     result = inv_set_mpu_memory(KEY_D_1_108, 4, regs);
   1351     if (result) {
   1352         LOG_RESULT_LOCATION(result);
   1353         return result;
   1354     }
   1355     result = inv_reset_motion();
   1356     return result;
   1357 }
   1358 
   1359 /**
   1360  *  @brief  inv_set_no_motion_threshAccel is used to set the threshold for
   1361  *          detecting INV_NO_MOTION with accelerometers when Gyros have
   1362  *          been turned off
   1363  *
   1364  *  @pre    inv_dmp_open()
   1365  *          @ifnot MPL_MF
   1366  *              or inv_open_low_power_pedometer()
   1367  *              or inv_eis_open_dmp()
   1368  *          @endif
   1369  *          must have been called.
   1370  *
   1371  *  @param  thresh  A threshold in g's scaled by 2^32
   1372  *
   1373  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1374  */
   1375 inv_error_t inv_set_no_motion_threshAccel(long thresh)
   1376 {
   1377     INVENSENSE_FUNC_START;
   1378 
   1379     inv_obj.no_motion_accel_threshold = thresh;
   1380 
   1381     return INV_SUCCESS;
   1382 }
   1383 
   1384 /**
   1385  *  @brief  inv_set_no_motion_time is used to set the time required for
   1386  *          detecting INV_NO_MOTION
   1387  *
   1388  *  @pre    inv_dmp_open()
   1389  *          @ifnot MPL_MF
   1390  *              or inv_open_low_power_pedometer()
   1391  *              or inv_eis_open_dmp()
   1392  *          @endif
   1393  *          must have been called.
   1394  *
   1395  *  @param  time    A time in seconds.
   1396  *
   1397  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1398  */
   1399 inv_error_t inv_set_no_motion_time(float time)
   1400 {
   1401     inv_error_t result = INV_SUCCESS;
   1402     unsigned char regs[2] = { 0 };
   1403     long tmp;
   1404 
   1405     INVENSENSE_FUNC_START;
   1406 
   1407     tmp = (long)(time * 200);
   1408     if (tmp < 0) {
   1409         return INV_ERROR;
   1410     } else if (tmp > 65535L) {
   1411         return INV_ERROR;
   1412     }
   1413     inv_obj.motion_duration = (unsigned short)tmp;
   1414 
   1415     regs[0] = (unsigned char)((inv_obj.motion_duration >> 8) & 0xff);
   1416     regs[1] = (unsigned char)(inv_obj.motion_duration & 0xff);
   1417     result = inv_set_mpu_memory(KEY_D_1_106, 2, regs);
   1418     if (result) {
   1419         LOG_RESULT_LOCATION(result);
   1420         return result;
   1421     }
   1422     result = inv_reset_motion();
   1423     return result;
   1424 }
   1425 
   1426 /**
   1427  *  @brief  inv_get_version is used to get the ML version.
   1428  *
   1429  *  @pre    inv_get_version can be called at any time.
   1430  *
   1431  *  @param  version     inv_get_version writes the ML version
   1432  *                      string pointer to version.
   1433  *
   1434  *  @return INV_SUCCESS if successful or Non-zero error code otherwise.
   1435  */
   1436 inv_error_t inv_get_version(unsigned char **version)
   1437 {
   1438     INVENSENSE_FUNC_START;
   1439 
   1440     *version = (unsigned char *)mlVer;  //fixme we are wiping const
   1441 
   1442     return INV_SUCCESS;
   1443 }
   1444 
   1445 /**
   1446  * @brief Check for the presence of the gyro sensor.
   1447  *
   1448  * This is not a physical check but a logical check and the value can change
   1449  * dynamically based on calls to inv_set_mpu_sensors().
   1450  *
   1451  * @return  TRUE if the gyro is enabled FALSE otherwise.
   1452  */
   1453 int inv_get_gyro_present(void)
   1454 {
   1455     return inv_get_dl_config()->requested_sensors & (INV_X_GYRO | INV_Y_GYRO |
   1456                                                      INV_Z_GYRO);
   1457 }
   1458 
   1459 static unsigned short inv_row_2_scale(const signed char *row)
   1460 {
   1461     unsigned short b;
   1462 
   1463     if (row[0] > 0)
   1464         b = 0;
   1465     else if (row[0] < 0)
   1466         b = 4;
   1467     else if (row[1] > 0)
   1468         b = 1;
   1469     else if (row[1] < 0)
   1470         b = 5;
   1471     else if (row[2] > 0)
   1472         b = 2;
   1473     else if (row[2] < 0)
   1474         b = 6;
   1475     else
   1476         b = 7;                  // error
   1477     return b;
   1478 }
   1479 
   1480 unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx)
   1481 {
   1482     unsigned short scalar;
   1483     /*
   1484        XYZ  010_001_000 Identity Matrix
   1485        XZY  001_010_000
   1486        YXZ  010_000_001
   1487        YZX  000_010_001
   1488        ZXY  001_000_010
   1489        ZYX  000_001_010
   1490      */
   1491 
   1492     scalar = inv_row_2_scale(mtx);
   1493     scalar |= inv_row_2_scale(mtx + 3) << 3;
   1494     scalar |= inv_row_2_scale(mtx + 6) << 6;
   1495 
   1496     return scalar;
   1497 }
   1498 
   1499 /* Setups up the Freescale 16-bit accel for Sensor Fusion
   1500 * @param[in] orient A scalar representation of the orientation
   1501 *  that describes how to go from the Chip Orientation
   1502 *  to the Board Orientation often times called the Body Orientation in Invensense Documentation.
   1503 *  inv_orientation_matrix_to_scalar() will turn the transformation matrix into this scalar.
   1504 */
   1505 inv_error_t inv_freescale_sensor_fusion_16bit(unsigned short orient)
   1506 {
   1507     unsigned char rr[3];
   1508     inv_error_t result;
   1509 
   1510     orient = orient & 0xdb;
   1511     switch (orient) {
   1512     default:
   1513         // Typically 0x88
   1514         rr[0] = DINACC;
   1515         rr[1] = DINACF;
   1516         rr[2] = DINA0E;
   1517         break;
   1518     case 0x50:
   1519         rr[0] = DINACE;
   1520         rr[1] = DINA0E;
   1521         rr[2] = DINACD;
   1522         break;
   1523     case 0x81:
   1524         rr[0] = DINACE;
   1525         rr[1] = DINACB;
   1526         rr[2] = DINA0E;
   1527         break;
   1528     case 0x11:
   1529         rr[0] = DINACC;
   1530         rr[1] = DINA0E;
   1531         rr[2] = DINACB;
   1532         break;
   1533     case 0x42:
   1534         rr[0] = DINA0A;
   1535         rr[1] = DINACF;
   1536         rr[2] = DINACB;
   1537         break;
   1538     case 0x0a:
   1539         rr[0] = DINA0A;
   1540         rr[1] = DINACB;
   1541         rr[2] = DINACD;
   1542         break;
   1543     }
   1544     result = inv_set_mpu_memory(KEY_FCFG_AZ, 3, rr);
   1545     return result;
   1546 }
   1547 
   1548 /* Setups up the Freescale 8-bit accel for Sensor Fusion
   1549 * @param[in] orient A scalar representation of the orientation
   1550 *  that describes how to go from the Chip Orientation
   1551 *  to the Board Orientation often times called the Body Orientation in Invensense Documentation.
   1552 *  inv_orientation_matrix_to_scalar() will turn the transformation matrix into this scalar.
   1553 */
   1554 inv_error_t inv_freescale_sensor_fusion_8bit(unsigned short orient)
   1555 {
   1556     unsigned char regs[27];
   1557     inv_error_t result;
   1558     uint_fast8_t kk;
   1559 
   1560     orient = orient & 0xdb;
   1561     kk = 0;
   1562 
   1563     regs[kk++] = DINAC3;
   1564     regs[kk++] = DINA90 + 14;
   1565     regs[kk++] = DINAA0 + 9;
   1566     regs[kk++] = DINA3E;
   1567     regs[kk++] = DINA5E;
   1568     regs[kk++] = DINA7E;
   1569 
   1570     regs[kk++] = DINAC2;
   1571     regs[kk++] = DINAA0 + 9;
   1572     regs[kk++] = DINA90 + 9;
   1573     regs[kk++] = DINAF8 + 2;
   1574 
   1575     switch (orient) {
   1576     default:
   1577         // Typically 0x88
   1578         regs[kk++] = DINACB;
   1579 
   1580         regs[kk++] = DINA54;
   1581         regs[kk++] = DINA50;
   1582         regs[kk++] = DINA50;
   1583         regs[kk++] = DINA50;
   1584         regs[kk++] = DINA50;
   1585         regs[kk++] = DINA50;
   1586         regs[kk++] = DINA50;
   1587         regs[kk++] = DINA50;
   1588 
   1589         regs[kk++] = DINACD;
   1590         break;
   1591     case 0x50:
   1592         regs[kk++] = DINACB;
   1593 
   1594         regs[kk++] = DINACF;
   1595 
   1596         regs[kk++] = DINA7C;
   1597         regs[kk++] = DINA78;
   1598         regs[kk++] = DINA78;
   1599         regs[kk++] = DINA78;
   1600         regs[kk++] = DINA78;
   1601         regs[kk++] = DINA78;
   1602         regs[kk++] = DINA78;
   1603         regs[kk++] = DINA78;
   1604         break;
   1605     case 0x81:
   1606         regs[kk++] = DINA2C;
   1607         regs[kk++] = DINA28;
   1608         regs[kk++] = DINA28;
   1609         regs[kk++] = DINA28;
   1610         regs[kk++] = DINA28;
   1611         regs[kk++] = DINA28;
   1612         regs[kk++] = DINA28;
   1613         regs[kk++] = DINA28;
   1614 
   1615         regs[kk++] = DINACD;
   1616 
   1617         regs[kk++] = DINACB;
   1618         break;
   1619     case 0x11:
   1620         regs[kk++] = DINA2C;
   1621         regs[kk++] = DINA28;
   1622         regs[kk++] = DINA28;
   1623         regs[kk++] = DINA28;
   1624         regs[kk++] = DINA28;
   1625         regs[kk++] = DINA28;
   1626         regs[kk++] = DINA28;
   1627         regs[kk++] = DINA28;
   1628         regs[kk++] = DINACB;
   1629         regs[kk++] = DINACF;
   1630         break;
   1631     case 0x42:
   1632         regs[kk++] = DINACF;
   1633         regs[kk++] = DINACD;
   1634 
   1635         regs[kk++] = DINA7C;
   1636         regs[kk++] = DINA78;
   1637         regs[kk++] = DINA78;
   1638         regs[kk++] = DINA78;
   1639         regs[kk++] = DINA78;
   1640         regs[kk++] = DINA78;
   1641         regs[kk++] = DINA78;
   1642         regs[kk++] = DINA78;
   1643         break;
   1644     case 0x0a:
   1645         regs[kk++] = DINACD;
   1646 
   1647         regs[kk++] = DINA54;
   1648         regs[kk++] = DINA50;
   1649         regs[kk++] = DINA50;
   1650         regs[kk++] = DINA50;
   1651         regs[kk++] = DINA50;
   1652         regs[kk++] = DINA50;
   1653         regs[kk++] = DINA50;
   1654         regs[kk++] = DINA50;
   1655 
   1656         regs[kk++] = DINACF;
   1657         break;
   1658     }
   1659 
   1660     regs[kk++] = DINA90 + 7;
   1661     regs[kk++] = DINAF8 + 3;
   1662     regs[kk++] = DINAA0 + 9;
   1663     regs[kk++] = DINA0E;
   1664     regs[kk++] = DINA0E;
   1665     regs[kk++] = DINA0E;
   1666 
   1667     regs[kk++] = DINAF8 + 1;    // filler
   1668 
   1669     result = inv_set_mpu_memory(KEY_FCFG_FSCALE, kk, regs);
   1670     if (result) {
   1671         LOG_RESULT_LOCATION(result);
   1672         return result;
   1673     }
   1674 
   1675     return result;
   1676 }
   1677 
   1678 /**
   1679  * Controlls each sensor and each axis when the motion processing unit is
   1680  * running.  When it is not running, simply records the state for later.
   1681  *
   1682  * NOTE: In this version only full sensors controll is allowed.  Independent
   1683  * axis control will return an error.
   1684  *
   1685  * @param sensors Bit field of each axis desired to be turned on or off
   1686  *
   1687  * @return INV_SUCCESS or non-zero error code
   1688  */
   1689 inv_error_t inv_set_mpu_sensors(unsigned long sensors)
   1690 {
   1691     INVENSENSE_FUNC_START;
   1692     unsigned char state = inv_get_state();
   1693     struct mldl_cfg *mldl_cfg = inv_get_dl_config();
   1694     inv_error_t result = INV_SUCCESS;
   1695     unsigned short fifoRate;
   1696 
   1697     if (state < INV_STATE_DMP_OPENED)
   1698         return INV_ERROR_SM_IMPROPER_STATE;
   1699 
   1700     if (((sensors & INV_THREE_AXIS_ACCEL) != INV_THREE_AXIS_ACCEL) &&
   1701         ((sensors & INV_THREE_AXIS_ACCEL) != 0)) {
   1702         return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
   1703     }
   1704     if (((sensors & INV_THREE_AXIS_ACCEL) != 0) &&
   1705         (mldl_cfg->pdata->accel.get_slave_descr == 0)) {
   1706         return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED;
   1707     }
   1708 
   1709     if (((sensors & INV_THREE_AXIS_COMPASS) != INV_THREE_AXIS_COMPASS) &&
   1710         ((sensors & INV_THREE_AXIS_COMPASS) != 0)) {
   1711         return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
   1712     }
   1713     if (((sensors & INV_THREE_AXIS_COMPASS) != 0) &&
   1714         (mldl_cfg->pdata->compass.get_slave_descr == 0)) {
   1715         return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED;
   1716     }
   1717 
   1718     if (((sensors & INV_THREE_AXIS_PRESSURE) != INV_THREE_AXIS_PRESSURE) &&
   1719         ((sensors & INV_THREE_AXIS_PRESSURE) != 0)) {
   1720         return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
   1721     }
   1722     if (((sensors & INV_THREE_AXIS_PRESSURE) != 0) &&
   1723         (mldl_cfg->pdata->pressure.get_slave_descr == 0)) {
   1724         return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED;
   1725     }
   1726 
   1727     /* DMP was off, and is turning on */
   1728     if (sensors & INV_DMP_PROCESSOR &&
   1729         !(mldl_cfg->requested_sensors & INV_DMP_PROCESSOR)) {
   1730         struct ext_slave_config config;
   1731         long odr;
   1732         config.key = MPU_SLAVE_CONFIG_ODR_RESUME;
   1733         config.len = sizeof(long);
   1734         config.apply = (state == INV_STATE_DMP_STARTED);
   1735         config.data = &odr;
   1736 
   1737         odr = (inv_mpu_get_sampling_rate_hz(mldl_cfg) * 1000);
   1738         result = inv_mpu_config_accel(mldl_cfg,
   1739                                       inv_get_serial_handle(),
   1740                                       inv_get_serial_handle(), &config);
   1741         if (result) {
   1742             LOG_RESULT_LOCATION(result);
   1743             return result;
   1744         }
   1745 
   1746         config.key = MPU_SLAVE_CONFIG_IRQ_RESUME;
   1747         odr = MPU_SLAVE_IRQ_TYPE_NONE;
   1748         result = inv_mpu_config_accel(mldl_cfg,
   1749                                       inv_get_serial_handle(),
   1750                                       inv_get_serial_handle(), &config);
   1751         if (result) {
   1752             LOG_RESULT_LOCATION(result);
   1753             return result;
   1754         }
   1755         inv_init_fifo_hardare();
   1756     }
   1757 
   1758     if (inv_obj.mode_change_func) {
   1759         result = inv_obj.mode_change_func(mldl_cfg->requested_sensors, sensors);
   1760         if (result) {
   1761             LOG_RESULT_LOCATION(result);
   1762             return result;
   1763         }
   1764     }
   1765 
   1766     /* Get the fifo rate before changing sensors so if we need to match it */
   1767     fifoRate = inv_get_fifo_rate();
   1768     mldl_cfg->requested_sensors = sensors;
   1769 
   1770     /* inv_dmp_start will turn the sensors on */
   1771     if (state == INV_STATE_DMP_STARTED) {
   1772         result = inv_dl_start(sensors);
   1773         if (result) {
   1774             LOG_RESULT_LOCATION(result);
   1775             return result;
   1776         }
   1777         result = inv_reset_motion();
   1778         if (result) {
   1779             LOG_RESULT_LOCATION(result);
   1780             return result;
   1781         }
   1782         result = inv_dl_stop(~sensors);
   1783         if (result) {
   1784             LOG_RESULT_LOCATION(result);
   1785             return result;
   1786         }
   1787     }
   1788 
   1789     inv_set_fifo_rate(fifoRate);
   1790 
   1791     if (!(sensors & INV_DMP_PROCESSOR) && (sensors & INV_THREE_AXIS_ACCEL)) {
   1792         struct ext_slave_config config;
   1793         long data;
   1794 
   1795         config.len = sizeof(long);
   1796         config.key = MPU_SLAVE_CONFIG_IRQ_RESUME;
   1797         config.apply = (state == INV_STATE_DMP_STARTED);
   1798         config.data = &data;
   1799         data = MPU_SLAVE_IRQ_TYPE_DATA_READY;
   1800         result = inv_mpu_config_accel(mldl_cfg,
   1801                                       inv_get_serial_handle(),
   1802                                       inv_get_serial_handle(), &config);
   1803         if (result) {
   1804             LOG_RESULT_LOCATION(result);
   1805             return result;
   1806         }
   1807     }
   1808 
   1809     return result;
   1810 }
   1811 
   1812 void inv_set_mode_change(inv_error_t(*mode_change_func)
   1813                          (unsigned long, unsigned long))
   1814 {
   1815     inv_obj.mode_change_func = mode_change_func;
   1816 }
   1817 
   1818 /**
   1819 * Mantis setup
   1820 */
   1821 #ifdef CONFIG_MPU_SENSORS_MPU6050B1
   1822 inv_error_t inv_set_mpu_6050_config()
   1823 {
   1824     long temp;
   1825     inv_error_t result;
   1826     unsigned char big8[4];
   1827     unsigned char atc[4];
   1828     long s[3], s2[3];
   1829     int kk;
   1830     struct mldl_cfg *mldlCfg = inv_get_dl_config();
   1831 
   1832     result = inv_serial_read(inv_get_serial_handle(), inv_get_mpu_slave_addr(),
   1833                              0x0d, 4, atc);
   1834     if (result) {
   1835         LOG_RESULT_LOCATION(result);
   1836         return result;
   1837     }
   1838 
   1839     temp = atc[3] & 0x3f;
   1840     if (temp >= 32)
   1841         temp = temp - 64;
   1842     temp = (temp << 21) | 0x100000;
   1843     temp += (1L << 29);
   1844     temp = -temp;
   1845     result = inv_set_mpu_memory(KEY_D_ACT0, 4, inv_int32_to_big8(temp, big8));
   1846     if (result) {
   1847         LOG_RESULT_LOCATION(result);
   1848         return result;
   1849     }
   1850 
   1851     for (kk = 0; kk < 3; ++kk) {
   1852         s[kk] = atc[kk] & 0x3f;
   1853         if (s[kk] > 32)
   1854             s[kk] = s[kk] - 64;
   1855         s[kk] *= 2516582L;
   1856     }
   1857 
   1858     for (kk = 0; kk < 3; ++kk) {
   1859         s2[kk] = mldlCfg->pdata->orientation[kk * 3] * s[0] +
   1860             mldlCfg->pdata->orientation[kk * 3 + 1] * s[1] +
   1861             mldlCfg->pdata->orientation[kk * 3 + 2] * s[2];
   1862     }
   1863     result = inv_set_mpu_memory(KEY_D_ACSX, 4, inv_int32_to_big8(s2[0], big8));
   1864     if (result) {
   1865         LOG_RESULT_LOCATION(result);
   1866         return result;
   1867     }
   1868     result = inv_set_mpu_memory(KEY_D_ACSY, 4, inv_int32_to_big8(s2[1], big8));
   1869     if (result) {
   1870         LOG_RESULT_LOCATION(result);
   1871         return result;
   1872     }
   1873     result = inv_set_mpu_memory(KEY_D_ACSZ, 4, inv_int32_to_big8(s2[2], big8));
   1874     if (result) {
   1875         LOG_RESULT_LOCATION(result);
   1876         return result;
   1877     }
   1878 
   1879     return result;
   1880 }
   1881 #endif
   1882 
   1883 /**
   1884  * @}
   1885  */
   1886