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