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 0 /* 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 "MPL" 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_db_save_t { 43 /** Compass Bias in Chip Frame in Hardware units scaled by 2^16 */ 44 long compass_bias[3]; 45 /** Gyro Bias in Chip Frame in Hardware units scaled by 2^16 */ 46 long gyro_bias[3]; 47 /** Temperature when *gyro_bias was stored. */ 48 long gyro_temp; 49 /** Accel Bias in Chip Frame in Hardware units scaled by 2^16 */ 50 long accel_bias[3]; 51 /** Temperature when accel bias was stored. */ 52 long accel_temp; 53 long gyro_temp_slope[3]; 54 /** Sensor Accuracy */ 55 int gyro_accuracy; 56 int accel_accuracy; 57 int compass_accuracy; 58 }; 59 60 struct inv_data_builder_t { 61 int num_cb; 62 struct process_t process[INV_MAX_DATA_CB]; 63 struct inv_db_save_t save; 64 int compass_disturbance; 65 #ifdef INV_PLAYBACK_DBG 66 int debug_mode; 67 int last_mode; 68 FILE *file; 69 #endif 70 }; 71 72 void inv_apply_calibration(struct inv_single_sensor_t *sensor, const long *bias); 73 static void inv_set_contiguous(void); 74 75 static struct inv_data_builder_t inv_data_builder; 76 static struct inv_sensor_cal_t sensors; 77 78 /** Change this key if the data being stored by this file changes */ 79 #define INV_DB_SAVE_KEY 53395 80 81 #ifdef INV_PLAYBACK_DBG 82 83 /** Turn on data logging to allow playback of same scenario at a later time. 84 * @param[in] file File to write to, must be open. 85 */ 86 void inv_turn_on_data_logging(FILE *file) 87 { 88 MPL_LOGV("input data logging started\n"); 89 inv_data_builder.file = file; 90 inv_data_builder.debug_mode = RD_RECORD; 91 } 92 93 /** Turn off data logging to allow playback of same scenario at a later time. 94 * File passed to inv_turn_on_data_logging() must be closed after calling this. 95 */ 96 void inv_turn_off_data_logging() 97 { 98 MPL_LOGV("input data logging stopped\n"); 99 inv_data_builder.debug_mode = RD_NO_DEBUG; 100 inv_data_builder.file = NULL; 101 } 102 #endif 103 104 /** This function receives the data that was stored in non-volatile memory between power off */ 105 static inv_error_t inv_db_load_func(const unsigned char *data) 106 { 107 memcpy(&inv_data_builder.save, data, sizeof(inv_data_builder.save)); 108 // copy in the saved accuracy in the actual sensors accuracy 109 sensors.gyro.accuracy = inv_data_builder.save.gyro_accuracy; 110 sensors.accel.accuracy = inv_data_builder.save.accel_accuracy; 111 sensors.compass.accuracy = inv_data_builder.save.compass_accuracy; 112 // TODO 113 if (sensors.compass.accuracy == 3) { 114 inv_set_compass_bias_found(1); 115 } 116 return INV_SUCCESS; 117 } 118 119 /** This function returns the data to be stored in non-volatile memory between power off */ 120 static inv_error_t inv_db_save_func(unsigned char *data) 121 { 122 memcpy(data, &inv_data_builder.save, sizeof(inv_data_builder.save)); 123 return INV_SUCCESS; 124 } 125 126 /** Initialize the data builder 127 */ 128 inv_error_t inv_init_data_builder(void) 129 { 130 /* TODO: Hardcode temperature scale/offset here. */ 131 memset(&inv_data_builder, 0, sizeof(inv_data_builder)); 132 memset(&sensors, 0, sizeof(sensors)); 133 return inv_register_load_store(inv_db_load_func, inv_db_save_func, 134 sizeof(inv_data_builder.save), 135 INV_DB_SAVE_KEY); 136 } 137 138 /** Gyro sensitivity. 139 * @return A scale factor to convert device units to degrees per second scaled by 2^16 140 * such that degrees_per_second = device_units * sensitivity / 2^30. Typically 141 * it works out to be the maximum rate * 2^15. 142 */ 143 long inv_get_gyro_sensitivity() 144 { 145 return sensors.gyro.sensitivity; 146 } 147 148 /** Accel sensitivity. 149 * @return A scale factor to convert device units to g's scaled by 2^16 150 * such that g_s = device_units * sensitivity / 2^30. Typically 151 * it works out to be the maximum accel value in g's * 2^15. 152 */ 153 long inv_get_accel_sensitivity(void) 154 { 155 return sensors.accel.sensitivity; 156 } 157 158 /** Compass sensitivity. 159 * @return A scale factor to convert device units to micro Tesla scaled by 2^16 160 * such that uT = device_units * sensitivity / 2^30. Typically 161 * it works out to be the maximum uT * 2^15. 162 */ 163 long inv_get_compass_sensitivity(void) 164 { 165 return sensors.compass.sensitivity; 166 } 167 168 /** Sets orientation and sensitivity field for a sensor. 169 * @param[out] sensor Structure to apply settings to 170 * @param[in] orientation Orientation description of how part is mounted. 171 * @param[in] sensitivity A Scale factor to convert from hardware units to 172 * standard units (dps, uT, g). 173 */ 174 void set_sensor_orientation_and_scale(struct inv_single_sensor_t *sensor, 175 int orientation, long sensitivity) 176 { 177 sensor->sensitivity = sensitivity; 178 sensor->orientation = orientation; 179 } 180 181 /** Sets the Orientation and Sensitivity of the gyro data. 182 * @param[in] orientation A scalar defining the transformation from chip mounting 183 * to the body frame. The function inv_orientation_matrix_to_scalar() 184 * can convert the transformation matrix to this scalar and describes the 185 * scalar in further detail. 186 * @param[in] sensitivity A scale factor to convert device units to degrees per second scaled by 2^16 187 * such that degrees_per_second = device_units * sensitivity / 2^30. Typically 188 * it works out to be the maximum rate * 2^15. 189 */ 190 void inv_set_gyro_orientation_and_scale(int orientation, long sensitivity) 191 { 192 #ifdef INV_PLAYBACK_DBG 193 if (inv_data_builder.debug_mode == RD_RECORD) { 194 int type = PLAYBACK_DBG_TYPE_G_ORIENT; 195 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 196 fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file); 197 fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file); 198 } 199 #endif 200 set_sensor_orientation_and_scale(&sensors.gyro, orientation, 201 sensitivity); 202 } 203 204 /** Set Gyro Sample rate in micro seconds. 205 * @param[in] sample_rate_us Set Gyro Sample rate in us 206 */ 207 void inv_set_gyro_sample_rate(long sample_rate_us) 208 { 209 #ifdef INV_PLAYBACK_DBG 210 if (inv_data_builder.debug_mode == RD_RECORD) { 211 int type = PLAYBACK_DBG_TYPE_G_SAMPLE_RATE; 212 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 213 fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file); 214 } 215 #endif 216 sensors.gyro.sample_rate_us = sample_rate_us; 217 sensors.gyro.sample_rate_ms = sample_rate_us / 1000; 218 if (sensors.gyro.bandwidth == 0) { 219 sensors.gyro.bandwidth = (int)(1000000L / sample_rate_us); 220 } 221 } 222 223 /** Set Accel Sample rate in micro seconds. 224 * @param[in] sample_rate_us Set Accel Sample rate in us 225 */ 226 void inv_set_accel_sample_rate(long sample_rate_us) 227 { 228 #ifdef INV_PLAYBACK_DBG 229 if (inv_data_builder.debug_mode == RD_RECORD) { 230 int type = PLAYBACK_DBG_TYPE_A_SAMPLE_RATE; 231 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 232 fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file); 233 } 234 #endif 235 sensors.accel.sample_rate_us = sample_rate_us; 236 sensors.accel.sample_rate_ms = sample_rate_us / 1000; 237 if (sensors.accel.bandwidth == 0) { 238 sensors.accel.bandwidth = (int)(1000000L / sample_rate_us); 239 } 240 } 241 242 /** Set Compass Sample rate in micro seconds. 243 * @param[in] sample_rate_us Set Gyro Sample rate in micro seconds. 244 */ 245 void inv_set_compass_sample_rate(long sample_rate_us) 246 { 247 #ifdef INV_PLAYBACK_DBG 248 if (inv_data_builder.debug_mode == RD_RECORD) { 249 int type = PLAYBACK_DBG_TYPE_C_SAMPLE_RATE; 250 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 251 fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file); 252 } 253 #endif 254 sensors.compass.sample_rate_us = sample_rate_us; 255 sensors.compass.sample_rate_ms = sample_rate_us / 1000; 256 if (sensors.compass.bandwidth == 0) { 257 sensors.compass.bandwidth = (int)(1000000L / sample_rate_us); 258 } 259 } 260 261 void inv_get_gyro_sample_rate_ms(long *sample_rate_ms) 262 { 263 *sample_rate_ms = sensors.gyro.sample_rate_ms; 264 } 265 266 void inv_get_accel_sample_rate_ms(long *sample_rate_ms) 267 { 268 *sample_rate_ms = sensors.accel.sample_rate_ms; 269 } 270 271 void inv_get_compass_sample_rate_ms(long *sample_rate_ms) 272 { 273 *sample_rate_ms = sensors.compass.sample_rate_ms; 274 } 275 276 /** Set Quat Sample rate in micro seconds. 277 * @param[in] sample_rate_us Set Quat Sample rate in us 278 */ 279 void inv_set_quat_sample_rate(long sample_rate_us) 280 { 281 #ifdef INV_PLAYBACK_DBG 282 if (inv_data_builder.debug_mode == RD_RECORD) { 283 int type = PLAYBACK_DBG_TYPE_Q_SAMPLE_RATE; 284 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 285 fwrite(&sample_rate_us, sizeof(sample_rate_us), 1, inv_data_builder.file); 286 } 287 #endif 288 sensors.quat.sample_rate_us = sample_rate_us; 289 sensors.quat.sample_rate_ms = sample_rate_us / 1000; 290 } 291 292 /** Set Gyro Bandwidth in Hz 293 * @param[in] bandwidth_hz Gyro bandwidth in Hz 294 */ 295 void inv_set_gyro_bandwidth(int bandwidth_hz) 296 { 297 sensors.gyro.bandwidth = bandwidth_hz; 298 } 299 300 /** Set Accel Bandwidth in Hz 301 * @param[in] bandwidth_hz Gyro bandwidth in Hz 302 */ 303 void inv_set_accel_bandwidth(int bandwidth_hz) 304 { 305 sensors.accel.bandwidth = bandwidth_hz; 306 } 307 308 /** Set Compass Bandwidth in Hz 309 * @param[in] bandwidth_hz Gyro bandwidth in Hz 310 */ 311 void inv_set_compass_bandwidth(int bandwidth_hz) 312 { 313 sensors.compass.bandwidth = bandwidth_hz; 314 } 315 316 /** Helper function stating whether the compass is on or off. 317 * @return TRUE if compass if on, 0 if compass if off 318 */ 319 int inv_get_compass_on() 320 { 321 return (sensors.compass.status & INV_SENSOR_ON) == INV_SENSOR_ON; 322 } 323 324 /** Helper function stating whether the gyro is on or off. 325 * @return TRUE if gyro if on, 0 if gyro if off 326 */ 327 int inv_get_gyro_on() 328 { 329 return (sensors.gyro.status & INV_SENSOR_ON) == INV_SENSOR_ON; 330 } 331 332 /** Helper function stating whether the acceleromter is on or off. 333 * @return TRUE if accel if on, 0 if accel if off 334 */ 335 int inv_get_accel_on() 336 { 337 return (sensors.accel.status & INV_SENSOR_ON) == INV_SENSOR_ON; 338 } 339 340 /** Get last timestamp across all 3 sensors that are on. 341 * This find out which timestamp has the largest value for sensors that are on. 342 * @return Returns INV_SUCCESS if successful or an error code if not. 343 */ 344 inv_time_t inv_get_last_timestamp() 345 { 346 inv_time_t timestamp = 0; 347 if (sensors.accel.status & INV_SENSOR_ON) { 348 timestamp = sensors.accel.timestamp; 349 } 350 if (sensors.gyro.status & INV_SENSOR_ON) { 351 if (timestamp < sensors.gyro.timestamp) { 352 timestamp = sensors.gyro.timestamp; 353 } 354 } 355 if (sensors.compass.status & INV_SENSOR_ON) { 356 if (timestamp < sensors.compass.timestamp) { 357 timestamp = sensors.compass.timestamp; 358 } 359 } 360 if (sensors.temp.status & INV_SENSOR_ON) { 361 if (timestamp < sensors.temp.timestamp) 362 timestamp = sensors.temp.timestamp; 363 } 364 return timestamp; 365 } 366 367 /** Sets the orientation and sensitivity of the gyro data. 368 * @param[in] orientation A scalar defining the transformation from chip mounting 369 * to the body frame. The function inv_orientation_matrix_to_scalar() 370 * can convert the transformation matrix to this scalar and describes the 371 * scalar in further detail. 372 * @param[in] sensitivity A scale factor to convert device units to g's 373 * such that g's = device_units * sensitivity / 2^30. Typically 374 * it works out to be the maximum g_value * 2^15. 375 */ 376 void inv_set_accel_orientation_and_scale(int orientation, long sensitivity) 377 { 378 #ifdef INV_PLAYBACK_DBG 379 if (inv_data_builder.debug_mode == RD_RECORD) { 380 int type = PLAYBACK_DBG_TYPE_A_ORIENT; 381 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 382 fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file); 383 fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file); 384 } 385 #endif 386 set_sensor_orientation_and_scale(&sensors.accel, orientation, 387 sensitivity); 388 } 389 390 /** Sets the Orientation and Sensitivity of the gyro data. 391 * @param[in] orientation A scalar defining the transformation from chip mounting 392 * to the body frame. The function inv_orientation_matrix_to_scalar() 393 * can convert the transformation matrix to this scalar and describes the 394 * scalar in further detail. 395 * @param[in] sensitivity A scale factor to convert device units to uT 396 * such that uT = device_units * sensitivity / 2^30. Typically 397 * it works out to be the maximum uT_value * 2^15. 398 */ 399 void inv_set_compass_orientation_and_scale(int orientation, long sensitivity) 400 { 401 #ifdef INV_PLAYBACK_DBG 402 if (inv_data_builder.debug_mode == RD_RECORD) { 403 int type = PLAYBACK_DBG_TYPE_C_ORIENT; 404 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 405 fwrite(&orientation, sizeof(orientation), 1, inv_data_builder.file); 406 fwrite(&sensitivity, sizeof(sensitivity), 1, inv_data_builder.file); 407 } 408 #endif 409 set_sensor_orientation_and_scale(&sensors.compass, orientation, sensitivity); 410 } 411 412 void inv_matrix_vector_mult(const long *A, const long *x, long *y) 413 { 414 y[0] = inv_q30_mult(A[0], x[0]) + inv_q30_mult(A[1], x[1]) + inv_q30_mult(A[2], x[2]); 415 y[1] = inv_q30_mult(A[3], x[0]) + inv_q30_mult(A[4], x[1]) + inv_q30_mult(A[5], x[2]); 416 y[2] = inv_q30_mult(A[6], x[0]) + inv_q30_mult(A[7], x[1]) + inv_q30_mult(A[8], x[2]); 417 } 418 419 /** Takes raw data stored in the sensor, removes bias, and converts it to 420 * calibrated data in the body frame. Also store raw data for body frame. 421 * @param[in,out] sensor structure to modify 422 * @param[in] bias bias in the mounting frame, in hardware units scaled by 423 * 2^16. Length 3. 424 */ 425 void inv_apply_calibration(struct inv_single_sensor_t *sensor, const long *bias) 426 { 427 long raw32[3]; 428 429 // Convert raw to calibrated 430 raw32[0] = (long)sensor->raw[0] << 15; 431 raw32[1] = (long)sensor->raw[1] << 15; 432 raw32[2] = (long)sensor->raw[2] << 15; 433 434 inv_convert_to_body_with_scale(sensor->orientation, sensor->sensitivity << 1, raw32, sensor->raw_scaled); 435 436 raw32[0] -= bias[0] >> 1; 437 raw32[1] -= bias[1] >> 1; 438 raw32[2] -= bias[2] >> 1; 439 440 inv_convert_to_body_with_scale(sensor->orientation, sensor->sensitivity << 1, raw32, sensor->calibrated); 441 442 sensor->status |= INV_CALIBRATED; 443 } 444 445 /** Returns the current bias for the compass 446 * @param[out] bias Compass bias in hardware units scaled by 2^16. In mounting frame. 447 * Length 3. 448 */ 449 void inv_get_compass_bias(long *bias) 450 { 451 if (bias != NULL) { 452 memcpy(bias, inv_data_builder.save.compass_bias, sizeof(inv_data_builder.save.compass_bias)); 453 } 454 } 455 456 void inv_set_compass_bias(const long *bias, int accuracy) 457 { 458 if (memcmp(inv_data_builder.save.compass_bias, bias, sizeof(inv_data_builder.save.compass_bias))) { 459 memcpy(inv_data_builder.save.compass_bias, bias, sizeof(inv_data_builder.save.compass_bias)); 460 inv_apply_calibration(&sensors.compass, inv_data_builder.save.compass_bias); 461 } 462 sensors.compass.accuracy = accuracy; 463 inv_data_builder.save.compass_accuracy = accuracy; 464 inv_set_message(INV_MSG_NEW_CB_EVENT, INV_MSG_NEW_CB_EVENT, 0); 465 } 466 467 /** Set the state of a compass disturbance 468 * @param[in] dist 1=disturbance, 0=no disturbance 469 */ 470 void inv_set_compass_disturbance(int dist) 471 { 472 inv_data_builder.compass_disturbance = dist; 473 } 474 475 int inv_get_compass_disturbance(void) { 476 return inv_data_builder.compass_disturbance; 477 } 478 /** Sets the accel bias. 479 * @param[in] bias Accel bias, length 3. In HW units scaled by 2^16 in body frame 480 * @param[in] accuracy Accuracy rating from 0 to 3, with 3 being most accurate. 481 */ 482 void inv_set_accel_bias(const long *bias, int accuracy) 483 { 484 if (bias) { 485 if (memcmp(inv_data_builder.save.accel_bias, bias, sizeof(inv_data_builder.save.accel_bias))) { 486 memcpy(inv_data_builder.save.accel_bias, bias, sizeof(inv_data_builder.save.accel_bias)); 487 inv_apply_calibration(&sensors.accel, inv_data_builder.save.accel_bias); 488 } 489 } 490 sensors.accel.accuracy = accuracy; 491 inv_data_builder.save.accel_accuracy = accuracy; 492 inv_set_message(INV_MSG_NEW_AB_EVENT, INV_MSG_NEW_AB_EVENT, 0); 493 } 494 495 /** Sets the accel accuracy. 496 * @param[in] accuracy Accuracy rating from 0 to 3, with 3 being most accurate. 497 */ 498 void inv_set_accel_accuracy(int accuracy) 499 { 500 sensors.accel.accuracy = accuracy; 501 inv_data_builder.save.accel_accuracy = accuracy; 502 inv_set_message(INV_MSG_NEW_AB_EVENT, INV_MSG_NEW_AB_EVENT, 0); 503 } 504 505 /** Sets the accel bias with control over which axis. 506 * @param[in] bias Accel bias, length 3. In HW units scaled by 2^16 in body frame 507 * @param[in] accuracy Accuracy rating from 0 to 3, with 3 being most accurate. 508 * @param[in] mask Mask to select axis to apply bias set. 509 */ 510 void inv_set_accel_bias_mask(const long *bias, int accuracy, int mask) 511 { 512 if (bias) { 513 if (mask & 1){ 514 inv_data_builder.save.accel_bias[0] = bias[0]; 515 } 516 if (mask & 2){ 517 inv_data_builder.save.accel_bias[1] = bias[1]; 518 } 519 if (mask & 4){ 520 inv_data_builder.save.accel_bias[2] = bias[2]; 521 } 522 523 inv_apply_calibration(&sensors.accel, inv_data_builder.save.accel_bias); 524 } 525 sensors.accel.accuracy = accuracy; 526 inv_data_builder.save.accel_accuracy = accuracy; 527 inv_set_message(INV_MSG_NEW_AB_EVENT, INV_MSG_NEW_AB_EVENT, 0); 528 } 529 530 531 /** Sets the gyro bias 532 * @param[in] bias Gyro bias in hardware units scaled by 2^16. In chip mounting frame. 533 * Length 3. 534 * @param[in] accuracy Accuracy of bias. 0 = least accurate, 3 = most accurate. 535 */ 536 void inv_set_gyro_bias(const long *bias, int accuracy) 537 { 538 if (bias != NULL) { 539 if (memcmp(inv_data_builder.save.gyro_bias, bias, sizeof(inv_data_builder.save.gyro_bias))) { 540 memcpy(inv_data_builder.save.gyro_bias, bias, sizeof(inv_data_builder.save.gyro_bias)); 541 inv_apply_calibration(&sensors.gyro, inv_data_builder.save.gyro_bias); 542 } 543 } 544 sensors.gyro.accuracy = accuracy; 545 inv_data_builder.save.gyro_accuracy = accuracy; 546 547 /* TODO: What should we do if there's no temperature data? */ 548 if (sensors.temp.calibrated[0]) 549 inv_data_builder.save.gyro_temp = sensors.temp.calibrated[0]; 550 else 551 /* Set to 27 deg C for now until we've got a better solution. */ 552 inv_data_builder.save.gyro_temp = 1769472L; 553 inv_set_message(INV_MSG_NEW_GB_EVENT, INV_MSG_NEW_GB_EVENT, 0); 554 } 555 556 /* TODO: Add this information to inv_sensor_cal_t */ 557 /** 558 * Get the gyro biases and temperature record from MPL 559 * @param[in] bias 560 * Gyro bias in hardware units scaled by 2^16. 561 * In chip mounting frame. 562 * Length 3. 563 * @param[in] temp 564 * Tempearature in degrees C. 565 */ 566 void inv_get_gyro_bias(long *bias, long *temp) 567 { 568 if (bias != NULL) 569 memcpy(bias, inv_data_builder.save.gyro_bias, 570 sizeof(inv_data_builder.save.gyro_bias)); 571 if (temp != NULL) 572 temp[0] = inv_data_builder.save.gyro_temp; 573 } 574 575 /** Get Accel Bias 576 * @param[out] bias Accel bias where 577 * @param[out] temp Temperature where 1 C = 2^16 578 */ 579 void inv_get_accel_bias(long *bias, long *temp) 580 { 581 if (bias != NULL) 582 memcpy(bias, inv_data_builder.save.accel_bias, 583 sizeof(inv_data_builder.save.accel_bias)); 584 if (temp != NULL) 585 temp[0] = inv_data_builder.save.accel_temp; 586 } 587 588 /** 589 * Record new accel data for use when inv_execute_on_data() is called 590 * @param[in] accel accel data. 591 * Length 3. 592 * Calibrated data is in m/s^2 scaled by 2^16 in body frame. 593 * Raw data is in device units in chip mounting frame. 594 * @param[in] status 595 * Lower 2 bits are the accuracy, with 0 being inaccurate, and 3 596 * being most accurate. 597 * The upper bit INV_CALIBRATED, is set if the data was calibrated 598 * outside MPL and it is not set if the data being passed is raw. 599 * Raw data should be in device units, typically in a 16-bit range. 600 * @param[in] timestamp 601 * Monotonic time stamp, for Android it's in nanoseconds. 602 * @return Returns INV_SUCCESS if successful or an error code if not. 603 */ 604 inv_error_t inv_build_accel(const long *accel, int status, inv_time_t timestamp) 605 { 606 #ifdef INV_PLAYBACK_DBG 607 if (inv_data_builder.debug_mode == RD_RECORD) { 608 int type = PLAYBACK_DBG_TYPE_ACCEL; 609 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 610 fwrite(accel, sizeof(accel[0]), 3, inv_data_builder.file); 611 fwrite(×tamp, sizeof(timestamp), 1, inv_data_builder.file); 612 } 613 #endif 614 615 if ((status & INV_CALIBRATED) == 0) { 616 sensors.accel.raw[0] = (short)accel[0]; 617 sensors.accel.raw[1] = (short)accel[1]; 618 sensors.accel.raw[2] = (short)accel[2]; 619 sensors.accel.status |= INV_RAW_DATA; 620 inv_apply_calibration(&sensors.accel, inv_data_builder.save.accel_bias); 621 } else { 622 sensors.accel.calibrated[0] = accel[0]; 623 sensors.accel.calibrated[1] = accel[1]; 624 sensors.accel.calibrated[2] = accel[2]; 625 sensors.accel.status |= INV_CALIBRATED; 626 sensors.accel.accuracy = status & 3; 627 inv_data_builder.save.accel_accuracy = status & 3; 628 } 629 sensors.accel.status |= INV_NEW_DATA | INV_SENSOR_ON; 630 sensors.accel.timestamp_prev = sensors.accel.timestamp; 631 sensors.accel.timestamp = timestamp; 632 633 return INV_SUCCESS; 634 } 635 636 /** Record new gyro data and calls inv_execute_on_data() if previous 637 * sample has not been processed. 638 * @param[in] gyro Data is in device units. Length 3. 639 * @param[in] timestamp Monotonic time stamp, for Android it's in nanoseconds. 640 * @param[out] executed Set to 1 if data processing was done. 641 * @return Returns INV_SUCCESS if successful or an error code if not. 642 */ 643 inv_error_t inv_build_gyro(const short *gyro, inv_time_t timestamp) 644 { 645 #ifdef INV_PLAYBACK_DBG 646 if (inv_data_builder.debug_mode == RD_RECORD) { 647 int type = PLAYBACK_DBG_TYPE_GYRO; 648 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 649 fwrite(gyro, sizeof(gyro[0]), 3, inv_data_builder.file); 650 fwrite(×tamp, sizeof(timestamp), 1, inv_data_builder.file); 651 } 652 #endif 653 654 memcpy(sensors.gyro.raw, gyro, 3 * sizeof(short)); 655 sensors.gyro.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON; 656 sensors.gyro.timestamp_prev = sensors.gyro.timestamp; 657 sensors.gyro.timestamp = timestamp; 658 inv_apply_calibration(&sensors.gyro, inv_data_builder.save.gyro_bias); 659 660 return INV_SUCCESS; 661 } 662 663 /** Record new compass data for use when inv_execute_on_data() is called 664 * @param[in] compass Compass data, if it was calibrated outside MPL, the units are uT scaled by 2^16. 665 * Length 3. 666 * @param[in] status Lower 2 bits are the accuracy, with 0 being inaccurate, and 3 being most accurate. 667 * The upper bit INV_CALIBRATED, is set if the data was calibrated outside MPL and it is 668 * not set if the data being passed is raw. Raw data should be in device units, typically 669 * in a 16-bit range. 670 * @param[in] timestamp Monotonic time stamp, for Android it's in nanoseconds. 671 * @param[out] executed Set to 1 if data processing was done. 672 * @return Returns INV_SUCCESS if successful or an error code if not. 673 */ 674 inv_error_t inv_build_compass(const long *compass, int status, 675 inv_time_t timestamp) 676 { 677 #ifdef INV_PLAYBACK_DBG 678 if (inv_data_builder.debug_mode == RD_RECORD) { 679 int type = PLAYBACK_DBG_TYPE_COMPASS; 680 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 681 fwrite(compass, sizeof(compass[0]), 3, inv_data_builder.file); 682 fwrite(×tamp, sizeof(timestamp), 1, inv_data_builder.file); 683 } 684 #endif 685 686 if ((status & INV_CALIBRATED) == 0) { 687 sensors.compass.raw[0] = (short)compass[0]; 688 sensors.compass.raw[1] = (short)compass[1]; 689 sensors.compass.raw[2] = (short)compass[2]; 690 inv_apply_calibration(&sensors.compass, inv_data_builder.save.compass_bias); 691 sensors.compass.status |= INV_RAW_DATA; 692 } else { 693 sensors.compass.calibrated[0] = compass[0]; 694 sensors.compass.calibrated[1] = compass[1]; 695 sensors.compass.calibrated[2] = compass[2]; 696 sensors.compass.status |= INV_CALIBRATED; 697 sensors.compass.accuracy = status & 3; 698 inv_data_builder.save.compass_accuracy = status & 3; 699 } 700 sensors.compass.timestamp_prev = sensors.compass.timestamp; 701 sensors.compass.timestamp = timestamp; 702 sensors.compass.status |= INV_NEW_DATA | INV_SENSOR_ON; 703 704 return INV_SUCCESS; 705 } 706 707 /** Record new temperature data for use when inv_execute_on_data() is called. 708 * @param[in] temp Temperature data in q16 format. 709 * @param[in] timestamp Monotonic time stamp; for Android it's in 710 * nanoseconds. 711 * @return Returns INV_SUCCESS if successful or an error code if not. 712 */ 713 inv_error_t inv_build_temp(const long temp, inv_time_t timestamp) 714 { 715 #ifdef INV_PLAYBACK_DBG 716 if (inv_data_builder.debug_mode == RD_RECORD) { 717 int type = PLAYBACK_DBG_TYPE_TEMPERATURE; 718 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 719 fwrite(&temp, sizeof(temp), 1, inv_data_builder.file); 720 fwrite(×tamp, sizeof(timestamp), 1, inv_data_builder.file); 721 } 722 #endif 723 sensors.temp.calibrated[0] = temp; 724 sensors.temp.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON; 725 sensors.temp.timestamp_prev = sensors.temp.timestamp; 726 sensors.temp.timestamp = timestamp; 727 /* TODO: Apply scale, remove offset. */ 728 729 return INV_SUCCESS; 730 } 731 /** quaternion data 732 * @param[in] quat Quaternion data. 2^30 = 1.0 or 2^14=1 for 16-bit data. 733 * Real part first. Length 4. 734 * @param[in] status number of axis, 16-bit or 32-bit 735 * @param[in] timestamp 736 * @param[in] timestamp Monotonic time stamp; for Android it's in 737 * nanoseconds. 738 * @param[out] executed Set to 1 if data processing was done. 739 * @return Returns INV_SUCCESS if successful or an error code if not. 740 */ 741 inv_error_t inv_build_quat(const long *quat, int status, inv_time_t timestamp) 742 { 743 #ifdef INV_PLAYBACK_DBG 744 if (inv_data_builder.debug_mode == RD_RECORD) { 745 int type = PLAYBACK_DBG_TYPE_QUAT; 746 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 747 fwrite(quat, sizeof(quat[0]), 4, inv_data_builder.file); 748 fwrite(×tamp, sizeof(timestamp), 1, inv_data_builder.file); 749 } 750 #endif 751 752 memcpy(sensors.quat.raw, quat, sizeof(sensors.quat.raw)); 753 sensors.quat.timestamp = timestamp; 754 sensors.quat.status |= INV_NEW_DATA | INV_RAW_DATA | INV_SENSOR_ON; 755 sensors.quat.status |= (INV_BIAS_APPLIED & status); 756 757 return INV_SUCCESS; 758 } 759 760 /** This should be called when the accel has been turned off. This is so 761 * that we will know if the data is contiguous. 762 */ 763 void inv_accel_was_turned_off() 764 { 765 sensors.accel.status = 0; 766 } 767 768 /** This should be called when the compass has been turned off. This is so 769 * that we will know if the data is contiguous. 770 */ 771 void inv_compass_was_turned_off() 772 { 773 sensors.compass.status = 0; 774 } 775 776 /** This should be called when the quaternion data from the DMP has been turned off. This is so 777 * that we will know if the data is contiguous. 778 */ 779 void inv_quaternion_sensor_was_turned_off(void) 780 { 781 sensors.quat.status = 0; 782 } 783 784 /** This should be called when the gyro has been turned off. This is so 785 * that we will know if the data is contiguous. 786 */ 787 void inv_gyro_was_turned_off() 788 { 789 sensors.gyro.status = 0; 790 } 791 792 /** This should be called when the temperature sensor has been turned off. 793 * This is so that we will know if the data is contiguous. 794 */ 795 void inv_temperature_was_turned_off() 796 { 797 sensors.temp.status = 0; 798 } 799 800 /** Registers to receive a callback when there is new sensor data. 801 * @internal 802 * @param[in] func Function pointer to receive callback when there is new sensor data 803 * @param[in] priority Lower priority numbers receive a callback before larger numbers. All priority 804 * numbers must be unique. 805 * @param[in] sensor_type Sets the type of data that triggers the callback. Must be non-zero. May be 806 * a combination. INV_ACCEL_NEW = accel data, INV_GYRO_NEW = 807 * gyro data, INV_MAG_NEW = compass data. So passing in 808 * INV_ACCEL_NEW | INV_MAG_NEW, a 809 * callback would be generated if there was new magnetomer data OR new accel data. 810 */ 811 inv_error_t inv_register_data_cb( 812 inv_error_t (*func)(struct inv_sensor_cal_t *data), 813 int priority, int sensor_type) 814 { 815 inv_error_t result = INV_SUCCESS; 816 int kk, nn; 817 818 // Make sure we haven't registered this function already 819 // Or used the same priority 820 for (kk = 0; kk < inv_data_builder.num_cb; ++kk) { 821 if ((inv_data_builder.process[kk].func == func) || 822 (inv_data_builder.process[kk].priority == priority)) { 823 return INV_ERROR_INVALID_PARAMETER; //fixme give a warning 824 } 825 } 826 827 // Make sure we have not filled up our number of allowable callbacks 828 if (inv_data_builder.num_cb <= INV_MAX_DATA_CB - 1) { 829 kk = 0; 830 if (inv_data_builder.num_cb != 0) { 831 // set kk to be where this new callback goes in the array 832 while ((kk < inv_data_builder.num_cb) && 833 (inv_data_builder.process[kk].priority < priority)) { 834 kk++; 835 } 836 if (kk != inv_data_builder.num_cb) { 837 // We need to move the others 838 for (nn = inv_data_builder.num_cb; nn > kk; --nn) { 839 inv_data_builder.process[nn] = 840 inv_data_builder.process[nn - 1]; 841 } 842 } 843 } 844 // Add new callback 845 inv_data_builder.process[kk].func = func; 846 inv_data_builder.process[kk].priority = priority; 847 inv_data_builder.process[kk].data_required = sensor_type; 848 inv_data_builder.num_cb++; 849 } else { 850 MPL_LOGE("Unable to add feature callback as too many were already registered\n"); 851 result = INV_ERROR_MEMORY_EXAUSTED; 852 } 853 854 return result; 855 } 856 857 /** Unregisters the callback that happens when new sensor data is received. 858 * @internal 859 * @param[in] func Function pointer to receive callback when there is new sensor data 860 * @param[in] priority Lower priority numbers receive a callback before larger numbers. All priority 861 * numbers must be unique. 862 * @param[in] sensor_type Sets the type of data that triggers the callback. Must be non-zero. May be 863 * a combination. INV_ACCEL_NEW = accel data, INV_GYRO_NEW = 864 * gyro data, INV_MAG_NEW = compass data. So passing in 865 * INV_ACCEL_NEW | INV_MAG_NEW, a 866 * callback would be generated if there was new magnetomer data OR new accel data. 867 */ 868 inv_error_t inv_unregister_data_cb( 869 inv_error_t (*func)(struct inv_sensor_cal_t *data)) 870 { 871 int kk, nn; 872 873 for (kk = 0; kk < inv_data_builder.num_cb; ++kk) { 874 if (inv_data_builder.process[kk].func == func) { 875 // Delete this callback 876 for (nn = kk + 1; nn < inv_data_builder.num_cb; ++nn) { 877 inv_data_builder.process[nn - 1] = 878 inv_data_builder.process[nn]; 879 } 880 inv_data_builder.num_cb--; 881 return INV_SUCCESS; 882 } 883 } 884 885 return INV_SUCCESS; // We did not find the callback 886 } 887 888 /** After at least one of inv_build_gyro(), inv_build_accel(), or 889 * inv_build_compass() has been called, this function should be called. 890 * It will process the data it has received and update all the internal states 891 * and features that have been turned on. 892 * @return Returns INV_SUCCESS if successful or an error code if not. 893 */ 894 inv_error_t inv_execute_on_data(void) 895 { 896 inv_error_t result, first_error; 897 int kk; 898 int mode; 899 900 #ifdef INV_PLAYBACK_DBG 901 if (inv_data_builder.debug_mode == RD_RECORD) { 902 int type = PLAYBACK_DBG_TYPE_EXECUTE; 903 fwrite(&type, sizeof(type), 1, inv_data_builder.file); 904 } 905 #endif 906 // Determine what new data we have 907 mode = 0; 908 if (sensors.gyro.status & INV_NEW_DATA) 909 mode |= INV_GYRO_NEW; 910 if (sensors.accel.status & INV_NEW_DATA) 911 mode |= INV_ACCEL_NEW; 912 if (sensors.compass.status & INV_NEW_DATA) 913 mode |= INV_MAG_NEW; 914 if (sensors.temp.status & INV_NEW_DATA) 915 mode |= INV_TEMP_NEW; 916 if (sensors.quat.status & INV_QUAT_NEW) 917 mode |= INV_QUAT_NEW; 918 919 first_error = INV_SUCCESS; 920 921 for (kk = 0; kk < inv_data_builder.num_cb; ++kk) { 922 if (mode & inv_data_builder.process[kk].data_required) { 923 result = inv_data_builder.process[kk].func(&sensors); 924 if (result && !first_error) { 925 first_error = result; 926 } 927 } 928 } 929 930 inv_set_contiguous(); 931 932 return first_error; 933 } 934 935 /** Cleans up status bits after running all the callbacks. It sets the contiguous flag. 936 * 937 */ 938 static void inv_set_contiguous(void) 939 { 940 inv_time_t current_time = 0; 941 if (sensors.gyro.status & INV_NEW_DATA) { 942 sensors.gyro.status |= INV_CONTIGUOUS; 943 current_time = sensors.gyro.timestamp; 944 } 945 if (sensors.accel.status & INV_NEW_DATA) { 946 sensors.accel.status |= INV_CONTIGUOUS; 947 current_time = MAX(current_time, sensors.accel.timestamp); 948 } 949 if (sensors.compass.status & INV_NEW_DATA) { 950 sensors.compass.status |= INV_CONTIGUOUS; 951 current_time = MAX(current_time, sensors.compass.timestamp); 952 } 953 if (sensors.temp.status & INV_NEW_DATA) { 954 sensors.temp.status |= INV_CONTIGUOUS; 955 current_time = MAX(current_time, sensors.temp.timestamp); 956 } 957 if (sensors.quat.status & INV_NEW_DATA) { 958 sensors.quat.status |= INV_CONTIGUOUS; 959 current_time = MAX(current_time, sensors.quat.timestamp); 960 } 961 962 #if 0 963 /* See if sensors are still on. These should be turned off by inv_*_was_turned_off() 964 * type functions. This is just in case that breaks down. We make sure 965 * all the data is within 2 seconds of the newest piece of data*/ 966 if (inv_delta_time_ms(current_time, sensors.gyro.timestamp) >= 2000) 967 inv_gyro_was_turned_off(); 968 if (inv_delta_time_ms(current_time, sensors.accel.timestamp) >= 2000) 969 inv_accel_was_turned_off(); 970 if (inv_delta_time_ms(current_time, sensors.compass.timestamp) >= 2000) 971 inv_compass_was_turned_off(); 972 /* TODO: Temperature might not need to be read this quickly. */ 973 if (inv_delta_time_ms(current_time, sensors.temp.timestamp) >= 2000) 974 inv_temperature_was_turned_off(); 975 #endif 976 977 /* clear bits */ 978 sensors.gyro.status &= ~INV_NEW_DATA; 979 sensors.accel.status &= ~INV_NEW_DATA; 980 sensors.compass.status &= ~INV_NEW_DATA; 981 sensors.temp.status &= ~INV_NEW_DATA; 982 sensors.quat.status &= ~INV_NEW_DATA; 983 } 984 985 /** Gets a whole set of accel data including data, accuracy and timestamp. 986 * @param[out] data Accel Data where 1g = 2^16 987 * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate. 988 * @param[out] timestamp The timestamp of the data sample. 989 */ 990 void inv_get_accel_set(long *data, int8_t *accuracy, inv_time_t *timestamp) 991 { 992 if (data != NULL) { 993 memcpy(data, sensors.accel.calibrated, sizeof(sensors.accel.calibrated)); 994 } 995 if (timestamp != NULL) { 996 *timestamp = sensors.accel.timestamp; 997 } 998 if (accuracy != NULL) { 999 *accuracy = sensors.accel.accuracy; 1000 } 1001 } 1002 1003 /** Gets a whole set of gyro data including data, accuracy and timestamp. 1004 * @param[out] data Gyro Data where 1 dps = 2^16 1005 * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate. 1006 * @param[out] timestamp The timestamp of the data sample. 1007 */ 1008 void inv_get_gyro_set(long *data, int8_t *accuracy, inv_time_t *timestamp) 1009 { 1010 memcpy(data, sensors.gyro.calibrated, sizeof(sensors.gyro.calibrated)); 1011 if (timestamp != NULL) { 1012 *timestamp = sensors.gyro.timestamp; 1013 } 1014 if (accuracy != NULL) { 1015 *accuracy = sensors.gyro.accuracy; 1016 } 1017 } 1018 1019 /** Gets a whole set of gyro raw data including data, accuracy and timestamp. 1020 * @param[out] data Gyro Data where 1 dps = 2^16 1021 * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate. 1022 * @param[out] timestamp The timestamp of the data sample. 1023 */ 1024 void inv_get_gyro_set_raw(long *data, int8_t *accuracy, inv_time_t *timestamp) 1025 { 1026 memcpy(data, sensors.gyro.raw_scaled, sizeof(sensors.gyro.raw_scaled)); 1027 if (timestamp != NULL) { 1028 *timestamp = sensors.gyro.timestamp; 1029 } 1030 if (accuracy != NULL) { 1031 *accuracy = sensors.gyro.accuracy; 1032 } 1033 } 1034 1035 /** Get's latest gyro data. 1036 * @param[out] gyro Gyro Data, Length 3. 1 dps = 2^16. 1037 */ 1038 void inv_get_gyro(long *gyro) 1039 { 1040 memcpy(gyro, sensors.gyro.calibrated, sizeof(sensors.gyro.calibrated)); 1041 } 1042 1043 /** Gets a whole set of compass data including data, accuracy and timestamp. 1044 * @param[out] data Compass Data where 1 uT = 2^16 1045 * @param[out] accuracy Accuracy 0 being not accurate, and 3 being most accurate. 1046 * @param[out] timestamp The timestamp of the data sample. 1047 */ 1048 void inv_get_compass_set(long *data, int8_t *accuracy, inv_time_t *timestamp) 1049 { 1050 memcpy(data, sensors.compass.calibrated, sizeof(sensors.compass.calibrated)); 1051 if (timestamp != NULL) { 1052 *timestamp = sensors.compass.timestamp; 1053 } 1054 if (accuracy != NULL) { 1055 if (inv_data_builder.compass_disturbance) 1056 *accuracy = 0; 1057 else 1058 *accuracy = sensors.compass.accuracy; 1059 } 1060 } 1061 1062 /** Gets a whole set of temperature data including data, accuracy and timestamp. 1063 * @param[out] data Temperature data where 1 degree C = 2^16 1064 * @param[out] accuracy 0 to 3, where 3 is most accurate. 1065 * @param[out] timestamp The timestamp of the data sample. 1066 */ 1067 void inv_get_temp_set(long *data, int *accuracy, inv_time_t *timestamp) 1068 { 1069 data[0] = sensors.temp.calibrated[0]; 1070 if (timestamp) 1071 *timestamp = sensors.temp.timestamp; 1072 if (accuracy) 1073 *accuracy = sensors.temp.accuracy; 1074 } 1075 1076 /** Returns accuracy of gyro. 1077 * @return Accuracy of gyro with 0 being not accurate, and 3 being most accurate. 1078 */ 1079 int inv_get_gyro_accuracy(void) 1080 { 1081 return sensors.gyro.accuracy; 1082 } 1083 1084 /** Returns accuracy of compass. 1085 * @return Accuracy of compass with 0 being not accurate, and 3 being most accurate. 1086 */ 1087 int inv_get_mag_accuracy(void) 1088 { 1089 if (inv_data_builder.compass_disturbance) 1090 return 0; 1091 return sensors.compass.accuracy; 1092 } 1093 1094 /** Returns accuracy of accel. 1095 * @return Accuracy of accel with 0 being not accurate, and 3 being most accurate. 1096 */ 1097 int inv_get_accel_accuracy(void) 1098 { 1099 return sensors.accel.accuracy; 1100 } 1101 1102 inv_error_t inv_get_gyro_orient(int *orient) 1103 { 1104 *orient = sensors.gyro.orientation; 1105 return 0; 1106 } 1107 1108 inv_error_t inv_get_accel_orient(int *orient) 1109 { 1110 *orient = sensors.accel.orientation; 1111 return 0; 1112 } 1113 1114 1115 /** 1116 * @} 1117 */ 1118