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(×tamp, 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(×tamp, 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(×tamp, 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(×tamp, 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(×tamp, 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