data_builder.c 44 KB

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