Home | History | Annotate | Download | only in mllite
      1 /*
      2  $License:
      3     Copyright (C) 2011-2012 InvenSense Corporation, All Rights Reserved.
      4     See included License.txt for License information.
      5  $
      6  */
      7 
      8 /**
      9  *   @defgroup  Data_Builder data_builder
     10  *   @brief     Motion Library - Data Builder
     11  *              Constructs and Creates the data for MPL
     12  *
     13  *   @{
     14  *       @file data_builder.c
     15  *       @brief Data Builder.
     16  */
     17 
     18 #undef MPL_LOG_NDEBUG
     19 #define MPL_LOG_NDEBUG 1 /* Use 0 to turn on MPL_LOGV output */
     20 
     21 #include <string.h>
     22 
     23 #include "ml_math_func.h"
     24 #include "data_builder.h"
     25 #include "mlmath.h"
     26 #include "storage_manager.h"
     27 #include "message_layer.h"
     28 #include "results_holder.h"
     29 
     30 #include "log.h"
     31 #undef MPL_LOG_TAG
     32 #define MPL_LOG_TAG "MLLITE"
     33 
     34 typedef inv_error_t (*inv_process_cb_func)(struct inv_sensor_cal_t *data);
     35 
     36 struct process_t {
     37     inv_process_cb_func func;
     38     int priority;
     39     int data_required;
     40 };
     41 
     42 struct inv_data_builder_t {
     43     int num_cb;
     44     struct process_t process[INV_MAX_DATA_CB];
     45     struct inv_db_save_t save;
     46     struct inv_db_save_mpl_t save_mpl;
     47     struct inv_db_save_accel_mpl_t save_accel_mpl;
     48     int compass_disturbance;
     49     int mode;
     50 #ifdef INV_PLAYBACK_DBG
     51     int debug_mode;
     52     int last_mode;
     53     FILE *file;
     54 #endif
     55 };
     56 
     57 void inv_apply_calibration(struct inv_single_sensor_t *sensor, const long *bias);
     58 static void inv_set_contiguous(void);
     59 
     60 static struct inv_data_builder_t inv_data_builder;
     61 static struct inv_sensor_cal_t sensors;
     62 
     63 #ifdef INV_PLAYBACK_DBG
     64 
     65 /** Turn on data logging to allow playback of same scenario at a later time.
     66 * @param[in] file File to write to, must be open.
     67 */
     68 void inv_turn_on_data_logging(FILE *file)
     69 {
     70     MPL_LOGV("input data logging started\n");
     71     inv_data_builder.file = file;
     72     inv_data_builder.debug_mode = RD_RECORD;
     73 }
     74 
     75 /** Turn off data logging to allow playback of same scenario at a later time.
     76 * File passed to inv_turn_on_data_logging() must be closed after calling this.
     77 */
     78 void inv_turn_off_data_logging()
     79 {
     80     MPL_LOGV("input data logging stopped\n");
     81     inv_data_builder.debug_mode = RD_NO_DEBUG;
     82     inv_data_builder.file = NULL;
     83 }
     84 #endif
     85 
     86 /** Gets last value of raw compass data.
     87 * @param[out] raw Raw compass data in mounting frame in hardware units. Length 3.
     88 */
     89 void inv_get_raw_compass(short *raw)
     90 {
     91     memcpy(raw, sensors.compass.raw, sizeof(sensors.compass.raw));
     92 }
     93 
     94 /** This function receives the data that was stored in non-volatile memory between power off */
     95 static inv_error_t inv_db_load_func(const unsigned char *data)
     96 {
     97     memcpy(&inv_data_builder.save, data, sizeof(inv_data_builder.save));
     98     // copy in the saved accuracy in the actual sensors accuracy
     99     sensors.gyro.accuracy = inv_data_builder.save.gyro_accuracy;
    100     sensors.accel.accuracy = inv_data_builder.save.accel_accuracy;
    101     sensors.compass.accuracy = inv_data_builder.save.compass_accuracy;
    102     // TODO
    103     if (sensors.accel.accuracy == 3) {
    104         inv_set_accel_bias_found(1);
    105     }
    106     if (sensors.compass.accuracy == 3) {
    107         inv_set_compass_bias_found(1);
    108     }
    109     return INV_SUCCESS;
    110 }
    111 
    112 /** This function returns the data to be stored in non-volatile memory between power off */
    113 static inv_error_t inv_db_save_func(unsigned char *data)
    114 {
    115     memcpy(data, &inv_data_builder.save, sizeof(inv_data_builder.save));
    116     return INV_SUCCESS;
    117 }
    118 
    119 /** This function receives the data for mpl that was stored in non-volatile memory between power off */
    120 static inv_error_t inv_db_load_mpl_func(const unsigned char *data)
    121 {
    122     memcpy(&inv_data_builder.save_mpl, data, sizeof(inv_data_builder.save_mpl));
    123 
    124     return INV_SUCCESS;
    125 }
    126 
    127 /** This function returns the data for mpl to be stored in non-volatile memory between power off */
    128 static inv_error_t inv_db_save_mpl_func(unsigned char *data)
    129 {
    130     memcpy(data, &inv_data_builder.save_mpl, sizeof(inv_data_builder.save_mpl));
    131     return INV_SUCCESS;
    132 }
    133 
    134 /** This function receives the data for mpl that was stored in non-volatile memory between power off */
    135 static inv_error_t inv_db_load_accel_mpl_func(const unsigned char *data)
    136 {
    137     memcpy(&inv_data_builder.save_accel_mpl, data, sizeof(inv_data_builder.save_accel_mpl));
    138 
    139     return INV_SUCCESS;
    140 }
    141 
    142 /** This function returns the data for mpl to be stored in non-volatile memory between power off */
    143 static inv_error_t inv_db_save_accel_mpl_func(unsigned char *data)
    144 {
    145     memcpy(data, &inv_data_builder.save_accel_mpl, sizeof(inv_data_builder.save_accel_mpl));
    146     return INV_SUCCESS;
    147 }
    148 
    149 /** Initialize the data builder
    150 */
    151 inv_error_t inv_init_data_builder(void)
    152 {
    153     /* TODO: Hardcode temperature scale/offset here. */
    154     memset(&inv_data_builder, 0, sizeof(inv_data_builder));
    155     memset(&sensors, 0, sizeof(sensors));
    156 
    157     // disable the soft iron transform process
    158     inv_reset_compass_soft_iron_matrix();
    159 
    160     return ((inv_register_load_store(inv_db_load_func, inv_db_save_func,
    161                                    sizeof(inv_data_builder.save),
    162                                    INV_DB_SAVE_KEY))
    163           | (inv_register_load_store(inv_db_load_mpl_func, inv_db_save_mpl_func,
    164                                    sizeof(inv_data_builder.save_mpl),
    165                                    INV_DB_SAVE_MPL_KEY))
    166           | (inv_register_load_store(inv_db_load_accel_mpl_func, inv_db_save_accel_mpl_func,
    167                                    sizeof(inv_data_builder.save_accel_mpl),
    168                                    INV_DB_SAVE_ACCEL_MPL_KEY)) );
    169 }
    170 
    171 /** Gyro sensitivity.
    172 * @return A scale factor to convert device units to degrees per second scaled by 2^16
    173 * such that degrees_per_second  = device_units * sensitivity / 2^30. Typically
    174 * it works out to be the maximum rate * 2^15.
    175 */
    176 long inv_get_gyro_sensitivity(void)
    177 {
    178     return sensors.gyro.sensitivity;
    179 }
    180 
    181 /** Accel sensitivity.
    182 * @return A scale factor to convert device units to g's scaled by 2^16
    183 * such that g_s  = device_units * sensitivity / 2^30. Typically
    184 * it works out to be the maximum accel value in g's * 2^15.
    185 */
    186 long inv_get_accel_sensitivity(void)
    187 {
    188     return sensors.accel.sensitivity;
    189 }
    190 
    191 /** Compass sensitivity.
    192 * @return A scale factor to convert device units to micro Tesla scaled by 2^16
    193 * such that uT  = device_units * sensitivity / 2^30. Typically
    194 * it works out to be the maximum uT * 2^15.
    195 */
    196 long inv_get_compass_sensitivity(void)
    197 {
    198     return sensors.compass.sensitivity;
    199 }
    200 
    201 /** Sets orientation and sensitivity field for a sensor.
    202 * @param[out] sensor Structure to apply settings to
    203 * @param[in] orientation Orientation description of how part is mounted.
    204 * @param[in] sensitivity A Scale factor to convert from hardware units to
    205 *            standard units (dps, uT, g).
    206 */
    207 void set_sensor_orientation_and_scale(struct inv_single_sensor_t *sensor,
    208                                  int orientation, long sensitivity)
    209 {
    210     int error = 0;
    211 
    212     if (!sensitivity) {
    213         // Sensitivity can't be zero
    214         sensitivity = 1L<<16;
    215         MPL_LOGE("\n\nCritical error! Sensitivity is zero.\n\n");
    216     }
    217 
    218     sensor->sensitivity = sensitivity;
    219     // Make sure we don't describe some impossible orientation
    220     if ((orientation & 3) == 3) {
    221         error = 1;
    222     }
    223     if ((orientation & 0x18) == 0x18) {
    224         error = 1;
    225     }
    226     if ((orientation & 0xc0) == 0xc0) {
    227         error = 1;
    228     }
    229     if (error) {
    230         orientation = 0x88; // Identity
    231         MPL_LOGE("\n\nCritical error! Impossible mounting orientation given. Using Identity instead\n\n");
    232     }
    233     sensor->orientation = orientation;
    234 }
    235 
    236 /** Sets the Orientation and Sensitivity of the gyro data.
    237 * @param[in] orientation A scalar defining the transformation from chip mounting
    238 *            to the body frame. The function inv_orientation_matrix_to_scalar()
    239 *            can convert the transformation matrix to this scalar and describes the
    240 *            scalar in further detail.
    241 * @param[in] sensitivity A scale factor to convert device units to degrees per second scaled by 2^16
    242 *            such that degrees_per_second  = device_units * sensitivity / 2^30. Typically
    243 *            it works out to be the maximum rate * 2^15.
    244 */
    245 void inv_set_gyro_orientation_and_scale(int orientation, long sensitivity)
    246 {
    247 #ifdef INV_PLAYBACK_DBG
    248     if (inv_data_builder.debug_mode == RD_RECORD) {
    249         int type = PLAYBACK_DBG_TYPE_G_ORIENT;
    250         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    251         fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file);
    252         fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file);
    253     }
    254 #endif
    255     set_sensor_orientation_and_scale(&sensors.gyro, orientation,
    256                                      sensitivity);
    257 }
    258 
    259 /** Set Gyro Sample rate in micro seconds.
    260 * @param[in] sample_rate_us Set Gyro Sample rate in us
    261 */
    262 void inv_set_gyro_sample_rate(long sample_rate_us)
    263 {
    264 #ifdef INV_PLAYBACK_DBG
    265     if (inv_data_builder.debug_mode == RD_RECORD) {
    266         int type = PLAYBACK_DBG_TYPE_G_SAMPLE_RATE;
    267         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    268         fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file);
    269     }
    270 #endif
    271     sensors.gyro.sample_rate_us = sample_rate_us;
    272     sensors.gyro.sample_rate_ms = sample_rate_us / 1000;
    273     if (sensors.gyro.bandwidth == 0) {
    274         sensors.gyro.bandwidth = (int)(1000000L / sample_rate_us);
    275     }
    276 }
    277 
    278 /** Set Accel Sample rate in micro seconds.
    279 * @param[in] sample_rate_us Set Accel Sample rate in us
    280 */
    281 void inv_set_accel_sample_rate(long sample_rate_us)
    282 {
    283 #ifdef INV_PLAYBACK_DBG
    284     if (inv_data_builder.debug_mode == RD_RECORD) {
    285         int type = PLAYBACK_DBG_TYPE_A_SAMPLE_RATE;
    286         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    287         fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file);
    288     }
    289 #endif
    290     sensors.accel.sample_rate_us = sample_rate_us;
    291     sensors.accel.sample_rate_ms = sample_rate_us / 1000;
    292     if (sensors.accel.bandwidth == 0) {
    293         sensors.accel.bandwidth = (int)(1000000L / sample_rate_us);
    294     }
    295 }
    296 
    297 /** Pick the smallest non-negative number. Priority to td1 on equal
    298 * If both are negative, return the largest.
    299 */
    300 static int inv_pick_best_time_difference(long td1, long td2)
    301 {
    302     if (td1 >= 0) {
    303         if (td2 >= 0) {
    304             if (td1 <= td2) {
    305                 // td1
    306                 return 0;
    307             } else {
    308                 // td2
    309                 return 1;
    310             }
    311         } else {
    312             // td1
    313             return 0;
    314         }
    315     } else if (td2 >= 0) {
    316         // td2
    317         return 1;
    318     } else {
    319         // Both are negative
    320         if (td1 >= td2) {
    321             // td1
    322             return 0;
    323         } else {
    324             // td2
    325             return 1;
    326         }
    327     }
    328 }
    329 
    330 /** Returns timestame based upon a raw sensor, and returns if that sample has a new piece of data.
    331 */
    332 static int inv_raw_sensor_timestamp(int sensor_number, inv_time_t *ts)
    333 {
    334     int status = 0;
    335     switch (sensor_number) {
    336     case 0: // Quat
    337         *ts = sensors.quat.timestamp;
    338         if (inv_data_builder.mode & INV_QUAT_NEW)
    339             if (sensors.quat.timestamp_prev != sensors.quat.timestamp)
    340                 status = 1;
    341         return status;
    342     case 1: // Gyro
    343         *ts = sensors.gyro.timestamp;
    344         if (inv_data_builder.mode & INV_GYRO_NEW)
    345             if (sensors.gyro.timestamp_prev != sensors.gyro.timestamp)
    346                 status = 1;
    347         return status;
    348     case 2: // Accel
    349         *ts = sensors.accel.timestamp;
    350         if (inv_data_builder.mode & INV_ACCEL_NEW)
    351             if (sensors.accel.timestamp_prev != sensors.accel.timestamp)
    352                 status = 1;
    353         return status;
    354    case 3: // Compass
    355         *ts = sensors.compass.timestamp;
    356         if (inv_data_builder.mode & INV_MAG_NEW)
    357             if (sensors.compass.timestamp_prev != sensors.compass.timestamp)
    358                 status = 1;
    359         return status;
    360     default:
    361         *ts = 0;
    362         return 0;
    363     }
    364     return 0;
    365 }
    366 
    367 /** Gets best timestamp and if there is a new piece of data for a 9-axis sensor combination.
    368 * It does this by finding a raw sensor that has the closest sample rate that is at least as
    369 * often desired. It also returns if that raw sensor has a new piece of data.
    370 * Priority is 9-axis quat, 6-axis quat, 3-axis quat, gyro, compass, accel on ties.
    371 * @return Returns 1, if the raw sensor being attached has new data, 0 otherwise.
    372 */
    373 int inv_get_9_axis_timestamp(long sample_rate_us, inv_time_t *ts)
    374 {
    375     int status = 0;
    376     long td[3];
    377     int idx,idx2;
    378 
    379     if ((sensors.quat.status & (INV_QUAT_9AXIS | INV_SENSOR_ON)) == (INV_QUAT_9AXIS | INV_SENSOR_ON)) {
    380         // 9-axis from DMP
    381         *ts = sensors.quat.timestamp;
    382         if (inv_data_builder.mode & INV_QUAT_NEW)
    383             if (sensors.quat.timestamp_prev != sensors.quat.timestamp)
    384                 status = 1;
    385         return status;
    386     }
    387 
    388     if ((sensors.compass.status & INV_SENSOR_ON) == 0) {
    389         return 0; // Compass must be on
    390     }
    391 
    392     // At this point, we know compass is on. Check if accel or 6-axis quat is on
    393     td[0] = sample_rate_us - sensors.quat.sample_rate_us;
    394     td[1] = sample_rate_us - sensors.compass.sample_rate_us;
    395     if ((sensors.quat.status & (INV_QUAT_6AXIS | INV_SENSOR_ON)) == (INV_QUAT_6AXIS | INV_SENSOR_ON)) {
    396         // Sensor tied to compass or 6-axis
    397         idx = inv_pick_best_time_difference(td[0], td[1]);
    398         idx *= 3; // Sensor number is 0 (Quat) or 3 (Compass)
    399         return inv_raw_sensor_timestamp(idx, ts);
    400     } else if ((sensors.accel.status & INV_SENSOR_ON) == 0) {
    401         return 0; // Accel must be on or 6-axis quat must be on
    402     }
    403 
    404     // At this point, we know accel is on. Check if 3-axis quat is on
    405     td[2] = sample_rate_us - sensors.accel.sample_rate_us;
    406     if ((sensors.quat.status & (INV_QUAT_3AXIS | INV_SENSOR_ON)) == (INV_QUAT_3AXIS | INV_SENSOR_ON)) {
    407         idx = inv_pick_best_time_difference(td[0], td[1]);
    408         idx2 = inv_pick_best_time_difference(td[idx], td[2]);
    409         if (idx2 == 1)
    410             idx = 2;
    411         if (idx > 0)
    412             idx++; // Skip gyro sensor in next function call
    413         // 0 = quat, 2 = compass, 3=accel
    414         return inv_raw_sensor_timestamp(idx, ts);
    415     }
    416 
    417     // No Quaternion data from outside, Gyro must be on
    418     if ((sensors.gyro.status & INV_SENSOR_ON) == 0) {
    419         return 0; // Gyro must be on
    420     }
    421 
    422     td[0] = sample_rate_us - sensors.gyro.sample_rate_us;
    423     idx = inv_pick_best_time_difference(td[0], td[1]);
    424     idx2 = inv_pick_best_time_difference(td[idx], td[2]);
    425     if (idx2 == 1)
    426         idx = 2;
    427     idx++;
    428     // 1 = gyro, 2 = compass, 3=accel
    429     return inv_raw_sensor_timestamp(idx, ts);
    430 }
    431 
    432 /** Gets best timestamp and if there is a new piece of data for a 9-axis sensor combination.
    433 * It does this by finding a raw sensor that has the closest sample rate that is at least as
    434 * often desired. It also returns if that raw sensor has a new piece of data.
    435 * Priority compass, accel on a tie
    436 * @return Returns 1, if the raw sensor being attached has new data, 0 otherwise.
    437 */
    438 int inv_get_6_axis_compass_accel_timestamp(long sample_rate_us, inv_time_t *ts)
    439 {
    440     long td[2];
    441     int idx;
    442 
    443     if ((sensors.compass.status & INV_SENSOR_ON) == 0) {
    444         return 0; // Compass must be on
    445     }
    446     if ((sensors.accel.status & INV_SENSOR_ON) == 0) {
    447         return 0; // Accel must be on
    448     }
    449 
    450     // At this point, we know compass & accel are both on.
    451     td[0] = sample_rate_us - sensors.accel.sample_rate_us;
    452     td[1] = sample_rate_us - sensors.compass.sample_rate_us;
    453     idx = inv_pick_best_time_difference(td[0], td[1]);
    454     idx += 2;
    455     return inv_raw_sensor_timestamp(idx, ts);
    456 }
    457 
    458 /** Gets best timestamp and if there is a new piece of data for a 9-axis sensor combination.
    459 * It does this by finding a raw sensor that has the closest sample rate that is at least as
    460 * often desired. It also returns if that raw sensor has a new piece of data.
    461 * Priority is Quaternion-6axis, Quaternion 3-axis, Gyro, Accel
    462 * @return Returns 1, if the raw sensor being attached has new data, 0 otherwise.
    463 */
    464 int inv_get_6_axis_gyro_accel_timestamp(long sample_rate_us, inv_time_t *ts)
    465 {
    466     long td[2];
    467     int idx;
    468 
    469     if ((sensors.quat.status & (INV_QUAT_6AXIS | INV_SENSOR_ON)) == (INV_QUAT_6AXIS | INV_SENSOR_ON)) {
    470         // Sensor number is 0 (Quat)
    471         return inv_raw_sensor_timestamp(0, ts);
    472     } else if ((sensors.accel.status & INV_SENSOR_ON) == 0) {
    473         return 0; // Accel must be on or 6-axis quat must be on
    474     }
    475 
    476     // At this point, we know accel is on. Check if 3-axis quat is on
    477     td[0] = sample_rate_us - sensors.quat.sample_rate_us;
    478     td[1] = sample_rate_us - sensors.accel.sample_rate_us;
    479     if ((sensors.quat.status & (INV_QUAT_3AXIS | INV_SENSOR_ON)) == (INV_QUAT_3AXIS | INV_SENSOR_ON)) {
    480         idx = inv_pick_best_time_difference(td[0], td[1]);
    481         idx *= 2;
    482         // 0 = quat, 3=accel
    483         return inv_raw_sensor_timestamp(idx, ts);
    484     }
    485 
    486     // No Quaternion data from outside, Gyro must be on
    487     if ((sensors.gyro.status & INV_SENSOR_ON) == 0) {
    488         return 0; // Gyro must be on
    489     }
    490 
    491     td[0] = sample_rate_us - sensors.gyro.sample_rate_us;
    492     idx = inv_pick_best_time_difference(td[0], td[1]);
    493     idx *= 2; // 0=gyro 2=accel
    494     idx++;
    495     // 1 = gyro, 3=accel
    496     return inv_raw_sensor_timestamp(idx, ts);
    497 }
    498 
    499 /** Set Compass Sample rate in micro seconds.
    500 * @param[in] sample_rate_us Set Gyro Sample rate in micro seconds.
    501 */
    502 void inv_set_compass_sample_rate(long sample_rate_us)
    503 {
    504 #ifdef INV_PLAYBACK_DBG
    505     if (inv_data_builder.debug_mode == RD_RECORD) {
    506         int type = PLAYBACK_DBG_TYPE_C_SAMPLE_RATE;
    507         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    508         fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file);
    509     }
    510 #endif
    511     sensors.compass.sample_rate_us = sample_rate_us;
    512     sensors.compass.sample_rate_ms = sample_rate_us / 1000;
    513     if (sensors.compass.bandwidth == 0) {
    514         sensors.compass.bandwidth = (int)(1000000L / sample_rate_us);
    515     }
    516 }
    517 
    518 void inv_get_gyro_sample_rate_ms(long *sample_rate_ms)
    519 {
    520 	*sample_rate_ms = sensors.gyro.sample_rate_ms;
    521 }
    522 
    523 void inv_get_accel_sample_rate_ms(long *sample_rate_ms)
    524 {
    525 	*sample_rate_ms = sensors.accel.sample_rate_ms;
    526 }
    527 
    528 void inv_get_compass_sample_rate_ms(long *sample_rate_ms)
    529 {
    530 	*sample_rate_ms = sensors.compass.sample_rate_ms;
    531 }
    532 
    533 /** Set Quat Sample rate in micro seconds.
    534 * @param[in] sample_rate_us Set Quat Sample rate in us
    535 */
    536 void inv_set_quat_sample_rate(long sample_rate_us)
    537 {
    538 #ifdef INV_PLAYBACK_DBG
    539     if (inv_data_builder.debug_mode == RD_RECORD) {
    540         int type = PLAYBACK_DBG_TYPE_Q_SAMPLE_RATE;
    541         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    542         fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file);
    543     }
    544 #endif
    545     sensors.quat.sample_rate_us = sample_rate_us;
    546     sensors.quat.sample_rate_ms = sample_rate_us / 1000;
    547 }
    548 
    549 /** Set Gyro Bandwidth in Hz
    550 * @param[in] bandwidth_hz Gyro bandwidth in Hz
    551 */
    552 void inv_set_gyro_bandwidth(int bandwidth_hz)
    553 {
    554     sensors.gyro.bandwidth = bandwidth_hz;
    555 }
    556 
    557 /** Set Accel Bandwidth in Hz
    558 * @param[in] bandwidth_hz Gyro bandwidth in Hz
    559 */
    560 void inv_set_accel_bandwidth(int bandwidth_hz)
    561 {
    562     sensors.accel.bandwidth = bandwidth_hz;
    563 }
    564 
    565 /** Set Compass Bandwidth in Hz
    566 * @param[in]  bandwidth_hz Gyro bandwidth in Hz
    567 */
    568 void inv_set_compass_bandwidth(int bandwidth_hz)
    569 {
    570     sensors.compass.bandwidth = bandwidth_hz;
    571 }
    572 
    573 /** Helper function stating whether the compass is on or off.
    574  * @return TRUE if compass if on, 0 if compass if off
    575 */
    576 int inv_get_compass_on()
    577 {
    578     return (sensors.compass.status & INV_SENSOR_ON) == INV_SENSOR_ON;
    579 }
    580 
    581 /** Helper function stating whether the gyro is on or off.
    582  * @return TRUE if gyro if on, 0 if gyro if off
    583 */
    584 int inv_get_gyro_on()
    585 {
    586     return (sensors.gyro.status & INV_SENSOR_ON) == INV_SENSOR_ON;
    587 }
    588 
    589 /** Helper function stating whether the acceleromter is on or off.
    590  * @return TRUE if accel if on, 0 if accel if off
    591 */
    592 int inv_get_accel_on()
    593 {
    594     return (sensors.accel.status & INV_SENSOR_ON) == INV_SENSOR_ON;
    595 }
    596 
    597 /** Get last timestamp across all 3 sensors that are on.
    598 * This find out which timestamp has the largest value for sensors that are on.
    599 * @return Returns INV_SUCCESS if successful or an error code if not.
    600 */
    601 inv_time_t inv_get_last_timestamp()
    602 {
    603     inv_time_t timestamp = 0;
    604     if (sensors.accel.status & INV_SENSOR_ON) {
    605         timestamp = sensors.accel.timestamp;
    606     }
    607     if (sensors.gyro.status & INV_SENSOR_ON) {
    608         if (timestamp < sensors.gyro.timestamp) {
    609             timestamp = sensors.gyro.timestamp;
    610         }
    611         MPL_LOGV("g ts: %lld", timestamp);
    612     }
    613     if (sensors.compass.status & INV_SENSOR_ON) {
    614         if (timestamp < sensors.compass.timestamp) {
    615             timestamp = sensors.compass.timestamp;
    616         }
    617     }
    618     if (sensors.temp.status & INV_SENSOR_ON) {
    619         if (timestamp < sensors.temp.timestamp) {
    620             timestamp = sensors.temp.timestamp;
    621         }
    622     }
    623     if (sensors.quat.status & INV_SENSOR_ON) {
    624         if (timestamp < sensors.quat.timestamp) {
    625             timestamp = sensors.quat.timestamp;
    626         }
    627         MPL_LOGV("q ts: %lld", timestamp);
    628     }
    629 
    630     return timestamp;
    631 }
    632 
    633 /** Sets the orientation and sensitivity of the gyro data.
    634 * @param[in] orientation A scalar defining the transformation from chip mounting
    635 *            to the body frame. The function inv_orientation_matrix_to_scalar()
    636 *            can convert the transformation matrix to this scalar and describes the
    637 *            scalar in further detail.
    638 * @param[in] sensitivity A scale factor to convert device units to g's
    639 *            such that g's = device_units * sensitivity / 2^30. Typically
    640 *            it works out to be the maximum g_value * 2^15.
    641 */
    642 void inv_set_accel_orientation_and_scale(int orientation, long sensitivity)
    643 {
    644 #ifdef INV_PLAYBACK_DBG
    645     if (inv_data_builder.debug_mode == RD_RECORD) {
    646         int type = PLAYBACK_DBG_TYPE_A_ORIENT;
    647         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    648         fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file);
    649         fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file);
    650     }
    651 #endif
    652     set_sensor_orientation_and_scale(&sensors.accel, orientation,
    653                                      sensitivity);
    654 }
    655 
    656 /** Sets the Orientation and Sensitivity of the gyro data.
    657 * @param[in] orientation A scalar defining the transformation from chip mounting
    658 *            to the body frame. The function inv_orientation_matrix_to_scalar()
    659 *            can convert the transformation matrix to this scalar and describes the
    660 *            scalar in further detail.
    661 * @param[in] sensitivity A scale factor to convert device units to uT
    662 *            such that uT = device_units * sensitivity / 2^30. Typically
    663 *            it works out to be the maximum uT_value * 2^15.
    664 */
    665 void inv_set_compass_orientation_and_scale(int orientation, long sensitivity)
    666 {
    667 #ifdef INV_PLAYBACK_DBG
    668     if (inv_data_builder.debug_mode == RD_RECORD) {
    669         int type = PLAYBACK_DBG_TYPE_C_ORIENT;
    670         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
    671         fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file);
    672         fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file);
    673     }
    674 #endif
    675     set_sensor_orientation_and_scale(&sensors.compass, orientation, sensitivity);
    676 }
    677 
    678 void inv_matrix_vector_mult(const long *A, const long *x, long *y)
    679 {
    680     y[0] = inv_q30_mult(A[0], x[0]) + inv_q30_mult(A[1], x[1]) + inv_q30_mult(A[2], x[2]);
    681     y[1] = inv_q30_mult(A[3], x[0]) + inv_q30_mult(A[4], x[1]) + inv_q30_mult(A[5], x[2]);
    682     y[2] = inv_q30_mult(A[6], x[0]) + inv_q30_mult(A[7], x[1]) + inv_q30_mult(A[8], x[2]);
    683 }
    684 
    685 /** Takes raw data stored in the sensor, removes bias, and converts it to
    686 * calibrated data in the body frame. Also store raw data for body frame.
    687 * @param[in,out] sensor structure to modify
    688 * @param[in] bias bias in the mounting frame, in hardware units scaled by
    689 *                 2^16. Length 3.
    690 */
    691 void inv_apply_calibration(struct inv_single_sensor_t *sensor, const long *bias)
    692 {
    693     long raw32[3];
    694 
    695     // Convert raw to calibrated
    696     raw32[0] = (long)sensor->raw[0] << 15;
    697     raw32[1] = (long)sensor->raw[1] << 15;
    698     raw32[2] = (long)sensor->raw[2] << 15;
    699 
    700     inv_convert_to_body_with_scale(sensor->orientation, sensor->sensitivity << 1, raw32, sensor->raw_scaled);
    701 
    702     raw32[0] -= bias[0] >> 1;
    703     raw32[1] -= bias[1] >> 1;
    704     raw32[2] -= bias[2] >> 1;
    705 
    706     inv_convert_to_body_with_scale(sensor->orientation, sensor->sensitivity << 1, raw32, sensor->calibrated);
    707 
    708     sensor->status |= INV_CALIBRATED;
    709 }
    710 
    711 /** Returns the current bias for the compass
    712 * @param[out] bias Compass bias in hardware units scaled by 2^16. In mounting frame.
    713 *             Length 3.
    714 */
    715 void inv_get_compass_bias(long *bias)
    716 {
    717     if (bias != NULL) {
    718         memcpy(bias, inv_data_builder.save.compass_bias, sizeof(inv_data_builder.save.compass_bias));
    719     }
    720 }
    721 
    722 /** Sets the compass bias
    723 * @param[in] bias Length 3, in body frame, in hardware units scaled by 2^16 to allow fractional bit correction.
    724 * @param[in] accuracy Accuracy of compass data, where 3=most accurate, and 0=least accurate.
    725 */
    726 void inv_set_compass_bias(const long *bias, int accuracy)
    727 {
    728     if (memcmp(inv_data_builder.save.compass_bias, bias, sizeof(inv_data_builder.save.compass_bias))) {
    729         memcpy(inv_data_builder.save.compass_bias, bias, sizeof(inv_data_builder.save.compass_bias));
    730         inv_apply_calibration(&sensors.compass, inv_data_builder.save.compass_bias);
    731     }
    732     sensors.compass.accuracy = accuracy;
    733     inv_data_builder.save.compass_accuracy = accuracy;
    734     inv_set_message(INV_MSG_NEW_CB_EVENT, INV_MSG_NEW_CB_EVENT, 0);
    735 }
    736 
    737 /** Set the state of a compass disturbance
    738 * @param[in] dist 1=disturbance, 0=no disturbance
    739 */
    740 void inv_set_compass_disturbance(int dist)
    741 {
    742     inv_data_builder.compass_disturbance = dist;
    743 }
    744 
    745 int inv_get_compass_disturbance(void) {
    746     return inv_data_builder.compass_disturbance;
    747 }
    748 
    749 /**
    750  *  Sets the factory accel bias
    751  *  @param[in] bias
    752  *               Accel bias in hardware units (+/- 2 gee full scale assumed)
    753  *               scaled by 2^16. In chip mounting frame. Length of 3.
    754  */
    755 void inv_set_accel_bias(const long *bias)
    756 {
    757     if (!bias)
    758         return;
    759 
    760     if (memcmp(inv_data_builder.save.factory_accel_bias, bias,
    761                sizeof(inv_data_builder.save.factory_accel_bias))) {
    762         memcpy(inv_data_builder.save.factory_accel_bias, bias,
    763                sizeof(inv_data_builder.save.factory_accel_bias));
    764         }
    765     inv_set_message(INV_MSG_NEW_FAB_EVENT, INV_MSG_NEW_FAB_EVENT, 0);
    766 }
    767 
    768 /** Sets the accel accuracy.
    769 * @param[in] accuracy Accuracy rating from 0 to 3, with 3 being most accurate.
    770 */
    771 void inv_set_accel_accuracy(int accuracy)
    772 {
    773     sensors.accel.accuracy = accuracy;
    774     inv_data_builder.save.accel_accuracy = accuracy;
    775 }
    776 
    777 /** Sets the accel bias with control over which axis.
    778 * @param[in] bias Accel bias, length 3. In HW units scaled by 2^16 in body frame
    779 * @param[in] accuracy Accuracy rating from 0 to 3, with 3 being most accurate.
    780 * @param[in] mask Mask to select axis to apply bias set.
    781 */
    782 void inv_set_accel_bias_mask(const long *bias, int accuracy, int mask)
    783 {
    784     if (bias) {
    785         if (mask & 1){
    786             inv_data_builder.save_accel_mpl.accel_bias[0] = bias[0];
    787         }
    788         if (mask & 2){
    789             inv_data_builder.save_accel_mpl.accel_bias[1] = bias[1];
    790         }
    791         if (mask & 4){
    792             inv_data_builder.save_accel_mpl.accel_bias[2] = bias[2];
    793         }
    794 
    795         inv_apply_calibration(&sensors.accel, inv_data_builder.save_accel_mpl.accel_bias);
    796     }
    797     inv_set_accel_accuracy(accuracy);
    798     inv_set_message(INV_MSG_NEW_AB_EVENT, INV_MSG_NEW_AB_EVENT, 0);
    799 }
    800 
    801 #ifdef WIN32
    802 /** Sends out a message to activate writing 9-axis quaternion to the DMP.
    803 */
    804 void inv_overwrite_dmp_9quat(void)
    805 {
    806     inv_set_message(INV_MSG_NEW_DMP_QUAT_WRITE_EVENT, INV_MSG_NEW_DMP_QUAT_WRITE_EVENT, 0);
    807 }
    808 #endif
    809 
    810 /**
    811  *  Sets the factory gyro bias
    812  *  @param[in] bias
    813  *               Gyro bias in hardware units (+/- 2000 dps full scale assumed)
    814  *               scaled by 2^16. In chip mounting frame. Length of 3.
    815  */
    816 void inv_set_gyro_bias(const long *bias)
    817 {
    818     if (!bias)
    819         return;
    820 
    821     if (memcmp(inv_data_builder.save.factory_gyro_bias, bias,
    822                sizeof(inv_data_builder.save.factory_gyro_bias))) {
    823         memcpy(inv_data_builder.save.factory_gyro_bias, bias,
    824                sizeof(inv_data_builder.save.factory_gyro_bias));
    825     }
    826     inv_set_message(INV_MSG_NEW_FGB_EVENT, INV_MSG_NEW_FGB_EVENT, 0);
    827 }
    828 
    829 /**
    830  *  Sets the mpl gyro bias
    831  *  @param[in] bias
    832  *              Gyro bias in hardware units scaled by 2^16  (+/- 2000 dps full
    833  *              scale assumed). In chip mounting frame. Length 3.
    834  *  @param[in] accuracy
    835  *              Accuracy of bias. 0 = least accurate, 3 = most accurate.
    836  */
    837 void inv_set_mpl_gyro_bias(const long *bias, int accuracy)
    838 {
    839     if (bias != NULL) {
    840         if (memcmp(inv_data_builder.save_mpl.gyro_bias, bias,
    841                    sizeof(inv_data_builder.save_mpl.gyro_bias))) {
    842             memcpy(inv_data_builder.save_mpl.gyro_bias, bias,
    843                    sizeof(inv_data_builder.save_mpl.gyro_bias));
    844             inv_apply_calibration(&sensors.gyro,
    845                                   inv_data_builder.save_mpl.gyro_bias);
    846         }
    847     }
    848     sensors.gyro.accuracy = accuracy;
    849     inv_data_builder.save.gyro_accuracy = accuracy;
    850 
    851     /* TODO: What should we do if there's no temperature data? */
    852     if (sensors.temp.calibrated[0])
    853         inv_data_builder.save.gyro_temp = sensors.temp.calibrated[0];
    854     else
    855         /* Set to 27 deg C for now until we've got a better solution. */
    856         inv_data_builder.save.gyro_temp = 27L << 16;
    857     inv_set_message(INV_MSG_NEW_GB_EVENT, INV_MSG_NEW_GB_EVENT, 0);
    858 
    859     /* TODO: this flag works around the synchronization problem seen with using
    860        the user-exposed message layer to signal the temperature compensation
    861        module that gyro biases were set.
    862        A better, cleaner method is certainly needed. */
    863     inv_data_builder.save.gyro_bias_tc_set = true;
    864 }
    865 
    866 /**
    867  *  @internal
    868  *  @brief  Return whether gyro biases were set to signal the temperature
    869  *          compensation algorithm that it can collect a data point to build
    870  *          the temperature slope while in no motion state.
    871  *          The flag clear automatically after is read.
    872  *  @return true if the flag was set, indicating gyro biases were set.
    873  *          false if the flag was not set.
    874  */
    875 int inv_get_gyro_bias_tc_set(void)
    876 {
    877     int flag = (inv_data_builder.save.gyro_bias_tc_set == true);
    878     inv_data_builder.save.gyro_bias_tc_set = false;
    879     return flag;
    880 }
    881 
    882 
    883 /**
    884  *  Get the mpl gyro biases
    885  *  @param[in] bias
    886  *              Gyro calibrated bias.
    887  *              Length 3.
    888  */
    889 void inv_get_mpl_gyro_bias(long *bias, long *temp)
    890 {
    891     if (bias != NULL)
    892         memcpy(bias, inv_data_builder.save_mpl.gyro_bias,
    893                sizeof(inv_data_builder.save_mpl.gyro_bias));
    894 
    895     if (temp != NULL)
    896         temp[0] = inv_data_builder.save.gyro_temp;
    897 }
    898 
    899 /** Gyro Bias in the form used by the DMP.
    900 * @param[out] bias Gyro Bias in the form used by the DMP. It is scaled appropriately
    901 *             and is in the body frame as needed. If this bias is applied in the DMP
    902 *             then any quaternion must have the flag INV_BIAS_APPLIED set if it is a
    903 *             3-axis quaternion, or INV_QUAT_6AXIS if it is a 6-axis quaternion
    904 */
    905 void inv_get_gyro_bias_dmp_units(long *bias)
    906 {
    907     if (bias == NULL)
    908         return;
    909     inv_convert_to_body_with_scale(sensors.gyro.orientation, 46850825L,
    910                                    inv_data_builder.save_mpl.gyro_bias, bias);
    911 }
    912 
    913 /* TODO: Add this information to inv_sensor_cal_t */
    914 /**
    915  *  Get the gyro biases and temperature record from MPL
    916  *  @param[in] bias
    917  *              Gyro bias in hardware units scaled by 2^16.
    918  *              In chip mounting frame.
    919  *              Length 3.
    920  */
    921 void inv_get_gyro_bias(long *bias)
    922 {
    923     if (bias != NULL)
    924         memcpy(bias, inv_data_builder.save.factory_gyro_bias,
    925                sizeof(inv_data_builder.save.factory_gyro_bias));
    926 }
    927 
    928 /**
    929  * Get factory accel bias mask
    930  * @param[in] bias
    931  *             Accel bias mask
    932  *             1 is set, 0 is not set, Length 3 = x,y,z.
    933  */
    934 int inv_get_factory_accel_bias_mask()
    935 {
    936     long bias[3];
    937 	int bias_mask = 0;
    938     inv_get_accel_bias(bias);
    939     if (bias != NULL) {
    940         int i;
    941         for(i = 0; i < 3; i++) {
    942             if(bias[i] != 0) {
    943                 bias_mask |= 1 << i;
    944 			} else {
    945                 bias_mask &= ~ (1 << i);
    946 			}
    947         }
    948     }
    949 	return bias_mask;
    950 }
    951 
    952 /**
    953  * Get accel bias from MPL
    954  * @param[in] bias
    955  *             Accel bias in hardware units scaled by 2^16.
    956  *             In chp mounting frame.
    957  *             Length 3.
    958  */
    959 void inv_get_accel_bias(long *bias)
    960 {
    961     if (bias != NULL)
    962         memcpy(bias, inv_data_builder.save.factory_accel_bias,
    963                sizeof(inv_data_builder.save.factory_accel_bias));
    964 }
    965 
    966 /** Get Accel Bias
    967 * @param[out] bias Accel bias
    968 * @param[out] temp Temperature where 1 C = 2^16
    969 */
    970 void inv_get_mpl_accel_bias(long *bias, long *temp)
    971 {
    972     if (bias != NULL)
    973         memcpy(bias, inv_data_builder.save_accel_mpl.accel_bias,
    974                sizeof(inv_data_builder.save_accel_mpl.accel_bias));
    975     if (temp != NULL)
    976         temp[0] = inv_data_builder.save.accel_temp;
    977 }
    978 
    979 /** Accel Bias in the form used by the DMP.
    980 * @param[out] bias Accel Bias in the form used by the DMP. It is scaled appropriately
    981 *             and is in the body frame as needed.
    982 */
    983 void inv_get_accel_bias_dmp_units(long *bias)
    984 {
    985     if (bias == NULL)
    986         return;
    987     inv_convert_to_body_with_scale(sensors.accel.orientation, 536870912L,
    988                                    inv_data_builder.save_accel_mpl.accel_bias, bias);
    989 }
    990 
    991 /**
    992  *  Record new accel data for use when inv_execute_on_data() is called
    993  *  @param[in]  accel
    994  *                accel data, length 3.
    995  *                Calibrated data is in m/s^2 scaled by 2^16 in body frame.
    996  *                Raw data is in device units in chip mounting frame.
    997  *  @param[in]  status
    998  *                Lower 2 bits are the accuracy, with 0 being inaccurate, and 3
    999  *                being most accurate.
   1000  *                The upper bit INV_CALIBRATED, is set if the data was calibrated
   1001  *                outside MPL and it is not set if the data being passed is raw.
   1002  *                Raw data should be in device units, typically in a 16-bit range.
   1003  *  @param[in]  timestamp
   1004  *                Monotonic time stamp, for Android it's in nanoseconds.
   1005  *  @return     Returns INV_SUCCESS if successful or an error code if not.
   1006  */
   1007 inv_error_t inv_build_accel(const long *accel, int status, inv_time_t timestamp)
   1008 {
   1009 #ifdef INV_PLAYBACK_DBG
   1010     if (inv_data_builder.debug_mode == RD_RECORD) {
   1011         int type = PLAYBACK_DBG_TYPE_ACCEL;
   1012         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1013         fwrite(accel, sizeof(accel[0]), 3, inv_data_builder.file);
   1014         fwrite(&timestamp, sizeof(timestamp), 1, inv_data_builder.file);
   1015     }
   1016 #endif
   1017 
   1018     if ((status & INV_CALIBRATED) == 0) {
   1019         sensors.accel.raw[0] = (short)accel[0];
   1020         sensors.accel.raw[1] = (short)accel[1];
   1021         sensors.accel.raw[2] = (short)accel[2];
   1022         sensors.accel.status |= INV_RAW_DATA;
   1023         inv_apply_calibration(&sensors.accel, inv_data_builder.save_accel_mpl.accel_bias);
   1024     } else {
   1025         sensors.accel.calibrated[0] = accel[0];
   1026         sensors.accel.calibrated[1] = accel[1];
   1027         sensors.accel.calibrated[2] = accel[2];
   1028         sensors.accel.status |= INV_CALIBRATED;
   1029         sensors.accel.accuracy = status & 3;
   1030         inv_data_builder.save.accel_accuracy = status & 3;
   1031     }
   1032     sensors.accel.status |= INV_NEW_DATA | INV_SENSOR_ON;
   1033     sensors.accel.timestamp_prev = sensors.accel.timestamp;
   1034     sensors.accel.timestamp = timestamp;
   1035 
   1036     return INV_SUCCESS;
   1037 }
   1038 
   1039 /** Record new gyro data and calls inv_execute_on_data() if previous
   1040 * sample has not been processed.
   1041 * @param[in] gyro Data is in device units. Length 3.
   1042 * @param[in] timestamp Monotonic time stamp, for Android it's in nanoseconds.
   1043 * @param[out] executed Set to 1 if data processing was done.
   1044 * @return Returns INV_SUCCESS if successful or an error code if not.
   1045 */
   1046 inv_error_t inv_build_gyro(const short *gyro, inv_time_t timestamp)
   1047 {
   1048 #ifdef INV_PLAYBACK_DBG
   1049     if (inv_data_builder.debug_mode == RD_RECORD) {
   1050         int type = PLAYBACK_DBG_TYPE_GYRO;
   1051         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1052         fwrite(gyro, sizeof(gyro[0]), 3, inv_data_builder.file);
   1053         fwrite(&timestamp, sizeof(timestamp), 1, inv_data_builder.file);
   1054     }
   1055 #endif
   1056 
   1057     memcpy(sensors.gyro.raw, gyro, 3 * sizeof(short));
   1058     sensors.gyro.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON;
   1059     sensors.gyro.timestamp_prev = sensors.gyro.timestamp;
   1060     sensors.gyro.timestamp = timestamp;
   1061     inv_apply_calibration(&sensors.gyro, inv_data_builder.save_mpl.gyro_bias);
   1062 
   1063     return INV_SUCCESS;
   1064 }
   1065 
   1066 /** Record new compass data for use when inv_execute_on_data() is called
   1067 * @param[in] compass Compass data, if it was calibrated outside MPL, the units are uT scaled by 2^16.
   1068 *            Length 3.
   1069 * @param[in] status Lower 2 bits are the accuracy, with 0 being inaccurate, and 3 being most accurate.
   1070 *            The upper bit INV_CALIBRATED, is set if the data was calibrated outside MPL and it is
   1071 *            not set if the data being passed is raw. Raw data should be in device units, typically
   1072 *            in a 16-bit range.
   1073 * @param[in] timestamp Monotonic time stamp, for Android it's in nanoseconds.
   1074 * @param[out] executed Set to 1 if data processing was done.
   1075 * @return Returns INV_SUCCESS if successful or an error code if not.
   1076 */
   1077 inv_error_t inv_build_compass(const long *compass, int status,
   1078                               inv_time_t timestamp)
   1079 {
   1080 #ifdef INV_PLAYBACK_DBG
   1081     if (inv_data_builder.debug_mode == RD_RECORD) {
   1082         int type = PLAYBACK_DBG_TYPE_COMPASS;
   1083         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1084         fwrite(compass, sizeof(compass[0]), 3, inv_data_builder.file);
   1085         fwrite(&timestamp, sizeof(timestamp), 1, inv_data_builder.file);
   1086     }
   1087 #endif
   1088 
   1089     if ((status & INV_CALIBRATED) == 0) {
   1090         long data[3];
   1091         inv_set_compass_soft_iron_input_data(compass);
   1092         inv_get_compass_soft_iron_output_data(data);
   1093         sensors.compass.raw[0] = (short)data[0];
   1094         sensors.compass.raw[1] = (short)data[1];
   1095         sensors.compass.raw[2] = (short)data[2];
   1096         inv_apply_calibration(&sensors.compass, inv_data_builder.save.compass_bias);
   1097         sensors.compass.status |= INV_RAW_DATA;
   1098     } else {
   1099         sensors.compass.calibrated[0] = compass[0];
   1100         sensors.compass.calibrated[1] = compass[1];
   1101         sensors.compass.calibrated[2] = compass[2];
   1102         sensors.compass.status |= INV_CALIBRATED;
   1103         sensors.compass.accuracy = status & 3;
   1104         inv_data_builder.save.compass_accuracy = status & 3;
   1105     }
   1106     sensors.compass.timestamp_prev = sensors.compass.timestamp;
   1107     sensors.compass.timestamp = timestamp;
   1108     sensors.compass.status |= INV_NEW_DATA | INV_SENSOR_ON;
   1109 
   1110     return INV_SUCCESS;
   1111 }
   1112 
   1113 /** Record new temperature data for use when inv_execute_on_data() is called.
   1114  *  @param[in]  temp Temperature data in q16 format.
   1115  *  @param[in]  timestamp   Monotonic time stamp; for Android it's in
   1116  *                          nanoseconds.
   1117 * @return Returns INV_SUCCESS if successful or an error code if not.
   1118  */
   1119 inv_error_t inv_build_temp(const long temp, inv_time_t timestamp)
   1120 {
   1121 #ifdef INV_PLAYBACK_DBG
   1122     if (inv_data_builder.debug_mode == RD_RECORD) {
   1123         int type = PLAYBACK_DBG_TYPE_TEMPERATURE;
   1124         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1125         fwrite(&temp, sizeof(temp), 1, inv_data_builder.file);
   1126         fwrite(&timestamp, sizeof(timestamp), 1, inv_data_builder.file);
   1127     }
   1128 #endif
   1129     sensors.temp.calibrated[0] = temp;
   1130     sensors.temp.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON;
   1131     sensors.temp.timestamp_prev = sensors.temp.timestamp;
   1132     sensors.temp.timestamp = timestamp;
   1133     /* TODO: Apply scale, remove offset. */
   1134 
   1135     return INV_SUCCESS;
   1136 }
   1137 /** quaternion data
   1138 * @param[in] quat Quaternion data. 2^30 = 1.0 or 2^14=1 for 16-bit data.
   1139 *                 Real part first. Length 4.
   1140 * @param[in] status number of axis, 16-bit or 32-bit
   1141 *            set INV_QUAT_3ELEMENT if input quaternion has only 3 elements (no scalar).
   1142 *            inv_compute_scalar_part() assumes 32-bit data.  If using 16-bit quaternion,
   1143 *            shift 16 bits first before calling this function.
   1144 * @param[in] timestamp
   1145 * @param[in]  timestamp   Monotonic time stamp; for Android it's in
   1146 *                         nanoseconds.
   1147 * @param[out] executed Set to 1 if data processing was done.
   1148 * @return Returns INV_SUCCESS if successful or an error code if not.
   1149 */
   1150 inv_error_t inv_build_quat(const long *quat, int status, inv_time_t timestamp)
   1151 {
   1152 #ifdef INV_PLAYBACK_DBG
   1153     if (inv_data_builder.debug_mode == RD_RECORD) {
   1154         int type = PLAYBACK_DBG_TYPE_QUAT;
   1155         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1156         fwrite(quat, sizeof(quat[0]), 4, inv_data_builder.file);
   1157         fwrite(&timestamp, sizeof(timestamp), 1, inv_data_builder.file);
   1158     }
   1159 #endif
   1160 
   1161     /* Android version DMP does not have scalar part */
   1162     if (status & INV_QUAT_3ELEMENT) {
   1163         long resultQuat[4];
   1164         MPL_LOGV("3q: %ld,%ld,%ld\n", quat[0], quat[1], quat[2]);
   1165         inv_compute_scalar_part(quat, resultQuat);
   1166         MPL_LOGV("4q: %ld,%ld,%ld,%ld\n", resultQuat[0], resultQuat[1], resultQuat[2], resultQuat[3]);
   1167         memcpy(sensors.quat.raw, resultQuat, sizeof(sensors.quat.raw));
   1168     } else {
   1169         memcpy(sensors.quat.raw, quat, sizeof(sensors.quat.raw));
   1170     }
   1171     sensors.quat.timestamp_prev = sensors.quat.timestamp;
   1172     sensors.quat.timestamp = timestamp;
   1173     sensors.quat.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON;
   1174     sensors.quat.status |= (INV_QUAT_3AXIS & status);
   1175     sensors.quat.status |= (INV_QUAT_6AXIS & status);
   1176     sensors.quat.status |= (INV_QUAT_9AXIS & status);
   1177     sensors.quat.status |= (INV_BIAS_APPLIED & status);
   1178     sensors.quat.status |= (INV_DMP_BIAS_APPLIED & status);
   1179     sensors.quat.status |= (INV_QUAT_3ELEMENT & status);
   1180     MPL_LOGV("quat.status: %d", sensors.quat.status);
   1181     if (sensors.quat.status & (INV_QUAT_9AXIS | INV_QUAT_6AXIS)) {
   1182         // Set quaternion
   1183         inv_store_gaming_quaternion(quat, timestamp);
   1184     }
   1185     if (sensors.quat.status & INV_QUAT_9AXIS) {
   1186         long identity[4] = {(1L<<30), 0, 0, 0};
   1187         inv_set_compass_correction(identity, timestamp);
   1188     }
   1189     return INV_SUCCESS;
   1190 }
   1191 
   1192 inv_error_t inv_build_pressure(const long pressure, int status, inv_time_t timestamp)
   1193 {
   1194     sensors.pressure.status |= INV_NEW_DATA;
   1195     return INV_SUCCESS;
   1196 }
   1197 
   1198 /** This should be called when the accel has been turned off. This is so
   1199 * that we will know if the data is contiguous.
   1200 */
   1201 void inv_accel_was_turned_off()
   1202 {
   1203 #ifdef INV_PLAYBACK_DBG
   1204     if (inv_data_builder.debug_mode == RD_RECORD) {
   1205         int type = PLAYBACK_DBG_TYPE_COMPASS_OFF;
   1206         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1207     }
   1208 #endif
   1209     sensors.accel.status = 0;
   1210 }
   1211 
   1212 /** This should be called when the compass has been turned off. This is so
   1213 * that we will know if the data is contiguous.
   1214 */
   1215 void inv_compass_was_turned_off()
   1216 {
   1217 #ifdef INV_PLAYBACK_DBG
   1218     if (inv_data_builder.debug_mode == RD_RECORD) {
   1219         int type = PLAYBACK_DBG_TYPE_COMPASS_OFF;
   1220         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1221     }
   1222 #endif
   1223     sensors.compass.status = 0;
   1224 }
   1225 
   1226 /** This should be called when the quaternion data from the DMP has been turned off. This is so
   1227 * that we will know if the data is contiguous.
   1228 */
   1229 void inv_quaternion_sensor_was_turned_off(void)
   1230 {
   1231 #ifdef INV_PLAYBACK_DBG
   1232     if (inv_data_builder.debug_mode == RD_RECORD) {
   1233         int type = PLAYBACK_DBG_TYPE_QUAT_OFF;
   1234         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1235     }
   1236 #endif
   1237     sensors.quat.status = 0;
   1238 }
   1239 
   1240 /** This should be called when the gyro has been turned off. This is so
   1241 * that we will know if the data is contiguous.
   1242 */
   1243 void inv_gyro_was_turned_off()
   1244 {
   1245 #ifdef INV_PLAYBACK_DBG
   1246     if (inv_data_builder.debug_mode == RD_RECORD) {
   1247         int type = PLAYBACK_DBG_TYPE_GYRO_OFF;
   1248         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1249     }
   1250 #endif
   1251     sensors.gyro.status = 0;
   1252 }
   1253 
   1254 /** This should be called when the temperature sensor has been turned off.
   1255  *  This is so that we will know if the data is contiguous.
   1256  */
   1257 void inv_temperature_was_turned_off()
   1258 {
   1259     sensors.temp.status = 0;
   1260 }
   1261 
   1262 /** Registers to receive a callback when there is new sensor data.
   1263 * @internal
   1264 * @param[in] func Function pointer to receive callback when there is new sensor data
   1265 * @param[in] priority Lower priority numbers receive a callback before larger numbers. All priority
   1266 *            numbers must be unique.
   1267 * @param[in] sensor_type Sets the type of data that triggers the callback. Must be non-zero. May be
   1268 *            a combination. INV_ACCEL_NEW = accel data, INV_GYRO_NEW =
   1269 *            gyro data, INV_MAG_NEW = compass data. So passing in
   1270 *            INV_ACCEL_NEW | INV_MAG_NEW, a
   1271 *            callback would be generated if there was new magnetomer data OR new accel data.
   1272 */
   1273 inv_error_t inv_register_data_cb(
   1274     inv_error_t (*func)(struct inv_sensor_cal_t *data),
   1275     int priority, int sensor_type)
   1276 {
   1277     inv_error_t result = INV_SUCCESS;
   1278     int kk, nn;
   1279 
   1280     // Make sure we haven't registered this function already
   1281     // Or used the same priority
   1282     for (kk = 0; kk < inv_data_builder.num_cb; ++kk) {
   1283         if ((inv_data_builder.process[kk].func == func) ||
   1284                 (inv_data_builder.process[kk].priority == priority)) {
   1285             return INV_ERROR_INVALID_PARAMETER;    //fixme give a warning
   1286         }
   1287     }
   1288 
   1289     // Make sure we have not filled up our number of allowable callbacks
   1290     if (inv_data_builder.num_cb <= INV_MAX_DATA_CB - 1) {
   1291         kk = 0;
   1292         if (inv_data_builder.num_cb != 0) {
   1293             // set kk to be where this new callback goes in the array
   1294             while ((kk < inv_data_builder.num_cb) &&
   1295                     (inv_data_builder.process[kk].priority < priority)) {
   1296                 kk++;
   1297             }
   1298             if (kk != inv_data_builder.num_cb) {
   1299                 // We need to move the others
   1300                 for (nn = inv_data_builder.num_cb; nn > kk; --nn) {
   1301                     inv_data_builder.process[nn] =
   1302                         inv_data_builder.process[nn - 1];
   1303                 }
   1304             }
   1305         }
   1306         // Add new callback
   1307         inv_data_builder.process[kk].func = func;
   1308         inv_data_builder.process[kk].priority = priority;
   1309         inv_data_builder.process[kk].data_required = sensor_type;
   1310         inv_data_builder.num_cb++;
   1311     } else {
   1312         MPL_LOGE("Unable to add feature callback as too many were already registered\n");
   1313         result = INV_ERROR_MEMORY_EXAUSTED;
   1314     }
   1315 
   1316     return result;
   1317 }
   1318 
   1319 /** Unregisters the callback that happens when new sensor data is received.
   1320 * @internal
   1321 * @param[in] func Function pointer to receive callback when there is new sensor data
   1322 * @param[in] priority Lower priority numbers receive a callback before larger numbers. All priority
   1323 *            numbers must be unique.
   1324 * @param[in] sensor_type Sets the type of data that triggers the callback. Must be non-zero. May be
   1325 *            a combination. INV_ACCEL_NEW = accel data, INV_GYRO_NEW =
   1326 *            gyro data, INV_MAG_NEW = compass data. So passing in
   1327 *            INV_ACCEL_NEW | INV_MAG_NEW, a
   1328 *            callback would be generated if there was new magnetomer data OR new accel data.
   1329 */
   1330 inv_error_t inv_unregister_data_cb(
   1331     inv_error_t (*func)(struct inv_sensor_cal_t *data))
   1332 {
   1333     int kk, nn;
   1334 
   1335     for (kk = 0; kk < inv_data_builder.num_cb; ++kk) {
   1336         if (inv_data_builder.process[kk].func == func) {
   1337             // Delete this callback
   1338             for (nn = kk + 1; nn < inv_data_builder.num_cb; ++nn) {
   1339                 inv_data_builder.process[nn - 1] =
   1340                     inv_data_builder.process[nn];
   1341             }
   1342             inv_data_builder.num_cb--;
   1343             return INV_SUCCESS;
   1344         }
   1345     }
   1346 
   1347     return INV_SUCCESS;    // We did not find the callback
   1348 }
   1349 
   1350 /** After at least one of inv_build_gyro(), inv_build_accel(), or
   1351 * inv_build_compass() has been called, this function should be called.
   1352 * It will process the data it has received and update all the internal states
   1353 * and features that have been turned on.
   1354 * @return Returns INV_SUCCESS if successful or an error code if not.
   1355 */
   1356 inv_error_t inv_execute_on_data(void)
   1357 {
   1358     inv_error_t result, first_error;
   1359     int kk;
   1360 
   1361 #ifdef INV_PLAYBACK_DBG
   1362     if (inv_data_builder.debug_mode == RD_RECORD) {
   1363         int type = PLAYBACK_DBG_TYPE_EXECUTE;
   1364         fwrite(&type, sizeof(type), 1, inv_data_builder.file);
   1365     }
   1366 #endif
   1367     // Determine what new data we have
   1368     inv_data_builder.mode = 0;
   1369     if (sensors.gyro.status & INV_NEW_DATA)
   1370         inv_data_builder.mode |= INV_GYRO_NEW;
   1371     if (sensors.accel.status & INV_NEW_DATA)
   1372         inv_data_builder.mode |= INV_ACCEL_NEW;
   1373     if (sensors.compass.status & INV_NEW_DATA)
   1374         inv_data_builder.mode |= INV_MAG_NEW;
   1375     if (sensors.temp.status & INV_NEW_DATA)
   1376         inv_data_builder.mode |= INV_TEMP_NEW;
   1377     if (sensors.quat.status & INV_NEW_DATA)
   1378         inv_data_builder.mode |= INV_QUAT_NEW;
   1379     if (sensors.pressure.status & INV_NEW_DATA)
   1380         inv_data_builder.mode |= INV_PRESSURE_NEW;
   1381 
   1382     first_error = INV_SUCCESS;
   1383 
   1384     for (kk = 0; kk < inv_data_builder.num_cb; ++kk) {
   1385         if (inv_data_builder.mode & inv_data_builder.process[kk].data_required) {
   1386             result = inv_data_builder.process[kk].func(&sensors);
   1387             if (result && !first_error) {
   1388                 first_error = result;
   1389             }
   1390         }
   1391     }
   1392 
   1393     inv_set_contiguous();
   1394 
   1395     return first_error;
   1396 }
   1397 
   1398 /** Cleans up status bits after running all the callbacks. It sets the contiguous flag.
   1399 *
   1400 */
   1401 static void inv_set_contiguous(void)
   1402 {
   1403     inv_time_t current_time = 0;
   1404     if (sensors.gyro.status & INV_NEW_DATA) {
   1405         sensors.gyro.status |= INV_CONTIGUOUS;
   1406         current_time = sensors.gyro.timestamp;
   1407     }
   1408     if (sensors.accel.status & INV_NEW_DATA) {
   1409         sensors.accel.status |= INV_CONTIGUOUS;
   1410         current_time = MAX(current_time, sensors.accel.timestamp);
   1411     }
   1412     if (sensors.compass.status & INV_NEW_DATA) {
   1413         sensors.compass.status |= INV_CONTIGUOUS;
   1414         current_time = MAX(current_time, sensors.compass.timestamp);
   1415     }
   1416     if (sensors.temp.status & INV_NEW_DATA) {
   1417         sensors.temp.status |= INV_CONTIGUOUS;
   1418         current_time = MAX(current_time, sensors.temp.timestamp);
   1419     }
   1420     if (sensors.quat.status & INV_NEW_DATA) {
   1421         sensors.quat.status |= INV_CONTIGUOUS;
   1422         current_time = MAX(current_time, sensors.quat.timestamp);
   1423     }
   1424 
   1425 #if 0
   1426     /* See if sensors are still on. These should be turned off by inv_*_was_turned_off()
   1427      * type functions. This is just in case that breaks down. We make sure
   1428      * all the data is within 2 seconds of the newest piece of data*/
   1429     if (inv_delta_time_ms(current_time, sensors.gyro.timestamp) >= 2000)
   1430         inv_gyro_was_turned_off();
   1431     if (inv_delta_time_ms(current_time, sensors.accel.timestamp) >= 2000)
   1432         inv_accel_was_turned_off();
   1433     if (inv_delta_time_ms(current_time, sensors.compass.timestamp) >= 2000)
   1434         inv_compass_was_turned_off();
   1435     /* TODO: Temperature might not need to be read this quickly. */
   1436     if (inv_delta_time_ms(current_time, sensors.temp.timestamp) >= 2000)
   1437         inv_temperature_was_turned_off();
   1438 #endif
   1439 
   1440     /* clear bits */
   1441     sensors.gyro.status &= ~INV_NEW_DATA;
   1442     sensors.accel.status &= ~INV_NEW_DATA;
   1443     sensors.compass.status &= ~INV_NEW_DATA;
   1444     sensors.temp.status &= ~INV_NEW_DATA;
   1445     sensors.quat.status &= ~INV_NEW_DATA;
   1446     sensors.pressure.status &= ~INV_NEW_DATA;
   1447 }
   1448 
   1449 /** Gets a whole set of accel data including data, accuracy and timestamp.
   1450  * @param[out] data Accel Data where 1g = 2^16
   1451  * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate.
   1452  * @param[out] timestamp The timestamp of the data sample.
   1453 */
   1454 void inv_get_accel_set(long *data, int8_t *accuracy, inv_time_t *timestamp)
   1455 {
   1456     if (data != NULL) {
   1457         memcpy(data, sensors.accel.calibrated, sizeof(sensors.accel.calibrated));
   1458     }
   1459     if (timestamp != NULL) {
   1460         *timestamp = sensors.accel.timestamp;
   1461     }
   1462     if (accuracy != NULL) {
   1463         *accuracy = sensors.accel.accuracy;
   1464     }
   1465 }
   1466 
   1467 /** Gets a whole set of gyro data including data, accuracy and timestamp.
   1468  * @param[out] data Gyro Data where 1 dps = 2^16
   1469  * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate.
   1470  * @param[out] timestamp The timestamp of the data sample.
   1471 */
   1472 void inv_get_gyro_set(long *data, int8_t *accuracy, inv_time_t *timestamp)
   1473 {
   1474     memcpy(data, sensors.gyro.calibrated, sizeof(sensors.gyro.calibrated));
   1475     if (timestamp != NULL) {
   1476         *timestamp = sensors.gyro.timestamp;
   1477     }
   1478     if (accuracy != NULL) {
   1479         *accuracy = sensors.gyro.accuracy;
   1480     }
   1481 }
   1482 
   1483 /** Gets a whole set of gyro raw data including data, accuracy and timestamp.
   1484  * @param[out] data Gyro Data where 1 dps = 2^16
   1485  * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate.
   1486  * @param[out] timestamp The timestamp of the data sample.
   1487 */
   1488 void inv_get_gyro_set_raw(long *data, int8_t *accuracy, inv_time_t *timestamp)
   1489 {
   1490     memcpy(data, sensors.gyro.raw_scaled, sizeof(sensors.gyro.raw_scaled));
   1491     if (timestamp != NULL) {
   1492         *timestamp = sensors.gyro.timestamp;
   1493     }
   1494     if (accuracy != NULL) {
   1495         *accuracy = 0;
   1496     }
   1497 }
   1498 
   1499 /** Get's latest gyro data.
   1500 * @param[out] gyro Gyro Data, Length 3. 1 dps = 2^16.
   1501 */
   1502 void inv_get_gyro(long *gyro)
   1503 {
   1504     memcpy(gyro, sensors.gyro.calibrated, sizeof(sensors.gyro.calibrated));
   1505 }
   1506 
   1507 /** Gets a whole set of compass data including data, accuracy and timestamp.
   1508  * @param[out] data Compass Data where 1 uT = 2^16
   1509  * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate.
   1510  * @param[out] timestamp The timestamp of the data sample.
   1511 */
   1512 void inv_get_compass_set(long *data, int8_t *accuracy, inv_time_t *timestamp)
   1513 {
   1514     memcpy(data, sensors.compass.calibrated, sizeof(sensors.compass.calibrated));
   1515     if (timestamp != NULL) {
   1516         *timestamp = sensors.compass.timestamp;
   1517     }
   1518     if (accuracy != NULL) {
   1519         if (inv_data_builder.compass_disturbance)
   1520             *accuracy = 0;
   1521         else
   1522             *accuracy = sensors.compass.accuracy;
   1523     }
   1524 }
   1525 
   1526 /** Gets a whole set of compass raw data including data, accuracy and timestamp.
   1527  * @param[out] data Compass Data where 1 uT = 2^16
   1528  * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate.
   1529  * @param[out] timestamp The timestamp of the data sample.
   1530 */
   1531 void inv_get_compass_set_raw(long *data, int8_t *accuracy, inv_time_t *timestamp)
   1532 {
   1533     memcpy(data, sensors.compass.raw_scaled, sizeof(sensors.compass.raw_scaled));
   1534     if (timestamp != NULL) {
   1535         *timestamp = sensors.compass.timestamp;
   1536     }
   1537     //per Michele, since data is raw, accuracy should = 0
   1538     *accuracy = 0;
   1539 }
   1540 
   1541 /** Gets a whole set of temperature data including data, accuracy and timestamp.
   1542  *  @param[out] data        Temperature data where 1 degree C = 2^16
   1543  *  @param[out] accuracy    0 to 3, where 3 is most accurate.
   1544  *  @param[out] timestamp   The timestamp of the data sample.
   1545  */
   1546 void inv_get_temp_set(long *data, int *accuracy, inv_time_t *timestamp)
   1547 {
   1548     data[0] = sensors.temp.calibrated[0];
   1549     if (timestamp)
   1550         *timestamp = sensors.temp.timestamp;
   1551     if (accuracy)
   1552         *accuracy = sensors.temp.accuracy;
   1553 }
   1554 
   1555 /** Returns accuracy of gyro.
   1556  * @return Accuracy of gyro with 0 being not accurate, and 3 being most accurate.
   1557 */
   1558 int inv_get_gyro_accuracy(void)
   1559 {
   1560     return sensors.gyro.accuracy;
   1561 }
   1562 
   1563 /** Returns accuracy of compass.
   1564  * @return Accuracy of compass with 0 being not accurate, and 3 being most accurate.
   1565 */
   1566 int inv_get_mag_accuracy(void)
   1567 {
   1568     if (inv_data_builder.compass_disturbance)
   1569         return 0;
   1570     return sensors.compass.accuracy;
   1571 }
   1572 
   1573 /** Returns accuracy of accel.
   1574  * @return Accuracy of accel with 0 being not accurate, and 3 being most accurate.
   1575 */
   1576 int inv_get_accel_accuracy(void)
   1577 {
   1578     return sensors.accel.accuracy;
   1579 }
   1580 
   1581 inv_error_t inv_get_gyro_orient(int *orient)
   1582 {
   1583     *orient = sensors.gyro.orientation;
   1584     return 0;
   1585 }
   1586 
   1587 inv_error_t inv_get_accel_orient(int *orient)
   1588 {
   1589     *orient = sensors.accel.orientation;
   1590     return 0;
   1591 }
   1592 
   1593 /*======================================================================*/
   1594 /*   compass soft iron module                                           */
   1595 /*======================================================================*/
   1596 
   1597 /** Gets the 3x3 compass transform matrix in 32 bit Q30 fixed point format.
   1598  * @param[out] the pointer of the 3x3 matrix in Q30 format
   1599 */
   1600 void inv_get_compass_soft_iron_matrix_d(long *matrix) {
   1601     int i;
   1602     for (i=0; i<9; i++)  {
   1603         matrix[i] = sensors.soft_iron.matrix_d[i];
   1604     }
   1605 }
   1606 
   1607 /** Sets the 3x3 compass transform matrix in 32 bit Q30 fixed point format.
   1608  * @param[in] the pointer of the 3x3 matrix in Q30 format
   1609 */
   1610 void inv_set_compass_soft_iron_matrix_d(long *matrix)  {
   1611     int i;
   1612     for (i=0; i<9; i++)  {
   1613         // set the floating point matrix
   1614         sensors.soft_iron.matrix_d[i] = matrix[i];
   1615         // convert to Q30 format
   1616         sensors.soft_iron.matrix_f[i] = inv_q30_to_float(matrix[i]);
   1617     }
   1618 }
   1619 /** Gets the 3x3 compass transform matrix in 32 bit floating point format.
   1620  * @param[out] the pointer of the 3x3 matrix in floating point format
   1621 */
   1622 void inv_get_compass_soft_iron_matrix_f(float *matrix)  {
   1623     int i;
   1624     for (i=0; i<9; i++)  {
   1625         matrix[i] = sensors.soft_iron.matrix_f[i];
   1626     }
   1627 }
   1628 /** Sets the 3x3 compass transform matrix in 32 bit floating point format.
   1629  * @param[in] the pointer of the 3x3 matrix in floating point format
   1630 */
   1631 void inv_set_compass_soft_iron_matrix_f(float *matrix)   {
   1632     int i;
   1633     for (i=0; i<9; i++)  {
   1634         // set the floating point matrix
   1635         sensors.soft_iron.matrix_f[i] = matrix[i];
   1636         // convert to Q30 format
   1637         sensors.soft_iron.matrix_d[i] = (long )(matrix[i]*ROT_MATRIX_SCALE_LONG);
   1638     }
   1639 }
   1640 
   1641 /** This subroutine gets the fixed point Q30 compass data after the soft iron transformation.
   1642  * @param[out] the pointer of the 3x1 vector compass data in MPL format
   1643 */
   1644 void inv_get_compass_soft_iron_output_data(long *data) {
   1645     int i;
   1646     for (i=0; i<3; i++)  {
   1647         data[i] = sensors.soft_iron.trans[i];
   1648     }
   1649 }
   1650 /** This subroutine gets the fixed point Q30 compass data before the soft iron transformation.
   1651  * @param[out] the pointer of the 3x1 vector compass data in MPL format
   1652 */
   1653 void inv_get_compass_soft_iron_input_data(long *data)  {
   1654     int i;
   1655     for (i=0; i<3; i++)  {
   1656         data[i] = sensors.soft_iron.raw[i];
   1657     }
   1658 }
   1659 /** This subroutine sets the compass raw data for the soft iron transformation.
   1660  * @param[int] the pointer of the 3x1 vector compass raw data in MPL format
   1661 */
   1662 void inv_set_compass_soft_iron_input_data(const long *data)  {
   1663     int i;
   1664     for (i=0; i<3; i++)  {
   1665         sensors.soft_iron.raw[i] = data[i];
   1666     }
   1667     if (sensors.soft_iron.enable == 1)  {
   1668         mlMatrixVectorMult(sensors.soft_iron.matrix_d, data, sensors.soft_iron.trans);
   1669     } else {
   1670         for (i=0; i<3; i++)  {
   1671             sensors.soft_iron.trans[i] = data[i];
   1672         }
   1673     }
   1674 }
   1675 
   1676 /** This subroutine resets the the soft iron transformation to unity matrix and
   1677  * disable the soft iron transformation process by default.
   1678 */
   1679 void inv_reset_compass_soft_iron_matrix(void)  {
   1680     int i;
   1681     for (i=0; i<9; i++) {
   1682         sensors.soft_iron.matrix_f[i] = 0.0f;
   1683     }
   1684 
   1685     memset(&sensors.soft_iron.matrix_d,0,sizeof(sensors.soft_iron.matrix_d));
   1686 
   1687     for (i=0; i<3; i++)  {
   1688         // set the floating point matrix
   1689         sensors.soft_iron.matrix_f[i*4] = 1.0;
   1690         // set the fixed point matrix
   1691         sensors.soft_iron.matrix_d[i*4] = ROT_MATRIX_SCALE_LONG;
   1692     }
   1693 
   1694     inv_disable_compass_soft_iron_matrix();
   1695 }
   1696 
   1697 /** This subroutine enables the the soft iron transformation process.
   1698 */
   1699 void inv_enable_compass_soft_iron_matrix(void)   {
   1700     sensors.soft_iron.enable = 1;
   1701 }
   1702 
   1703 /** This subroutine disables the the soft iron transformation process.
   1704 */
   1705 void inv_disable_compass_soft_iron_matrix(void)   {
   1706     sensors.soft_iron.enable = 0;
   1707 }
   1708 
   1709 /**
   1710  * @}
   1711  */
   1712