summaryrefslogtreecommitdiffstats
path: root/libsensors/mlsdk/mllite/mlFIFO.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsensors/mlsdk/mllite/mlFIFO.c')
-rw-r--r--libsensors/mlsdk/mllite/mlFIFO.c2126
1 files changed, 2126 insertions, 0 deletions
diff --git a/libsensors/mlsdk/mllite/mlFIFO.c b/libsensors/mlsdk/mllite/mlFIFO.c
new file mode 100644
index 0000000..3279b35
--- /dev/null
+++ b/libsensors/mlsdk/mllite/mlFIFO.c
@@ -0,0 +1,2126 @@
+/*
+ $License:
+ Copyright 2011 InvenSense, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ $
+ */
+/*******************************************************************************
+ *
+ * $Id: mlFIFO.c 5653 2011-06-16 21:06:55Z nroyer $
+ *
+ *******************************************************************************/
+
+/**
+ * @defgroup MLFIFO
+ * @brief Motion Library - FIFO Driver.
+ * The FIFO API Interface.
+ *
+ * @{
+ * @file mlFIFO.c
+ * @brief FIFO Interface.
+**/
+
+#include <string.h>
+#include "mpu.h"
+#include "mpu3050.h"
+#include "mlFIFO.h"
+#include "mlFIFOHW.h"
+#include "dmpKey.h"
+#include "mlMathFunc.h"
+#include "ml.h"
+#include "mldl.h"
+#include "mldl_cfg.h"
+#include "mlstates.h"
+#include "mlsupervisor.h"
+#include "mlos.h"
+#include "mlmath.h"
+#include "accel.h"
+
+#include "log.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-fifo"
+
+#define FIFO_DEBUG 0
+
+#define REF_QUATERNION (0)
+#define REF_GYROS (REF_QUATERNION + 4)
+#define REF_CONTROL (REF_GYROS + 3)
+#define REF_RAW (REF_CONTROL + 4)
+#define REF_RAW_EXTERNAL (REF_RAW + 8)
+#define REF_ACCEL (REF_RAW_EXTERNAL + 6)
+#define REF_QUANT_ACCEL (REF_ACCEL + 3)
+#define REF_QUATERNION_6AXIS (REF_QUANT_ACCEL + INV_MAX_NUM_ACCEL_SAMPLES)
+#define REF_EIS (REF_QUATERNION_6AXIS + 4)
+#define REF_DMP_PACKET (REF_EIS + 3)
+#define REF_GARBAGE (REF_DMP_PACKET + 1)
+#define REF_LAST (REF_GARBAGE + 1)
+
+long fifo_scale[REF_LAST] = {
+ (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quaternion
+ // 2^(16+30)/((2^30)*((3.14159265358/180)/200)/2)
+ 1501974482L, 1501974482L, 1501974482L, // Gyro
+ (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Control
+ (1L << 14), // Temperature
+ (1L << 14), (1L << 14), (1L << 14), // Raw Gyro
+ (1L << 14), (1L << 14), (1L << 14), (0), // Raw Accel, plus padding
+ (1L << 14), (1L << 14), (1L << 14), // Raw External
+ (1L << 14), (1L << 14), (1L << 14), // Raw External
+ (1L << 16), (1L << 16), (1L << 16), // Accel
+ (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quant Accel
+ (1L << 30), (1L << 30), (1L << 30), (1L << 30), //Quant Accel
+ (1L << 30), (1L << 30), (1L << 30), (1L << 30), // Quaternion 6 Axis
+ (1L << 30), (1L << 30), (1L << 30), // EIS
+ (1L << 30), // Packet
+ (1L << 30), // Garbage
+};
+
+// The scale factors for tap need to match the number in fifo_scale above.
+// fifo_base_offset below may also need to be changed if this is not 8
+#if INV_MAX_NUM_ACCEL_SAMPLES != 8
+#error INV_MAX_NUM_ACCEL_SAMPLES must be defined to 8
+#endif
+
+#define CONFIG_QUAT (0)
+#define CONFIG_GYROS (CONFIG_QUAT + 1)
+#define CONFIG_CONTROL_DATA (CONFIG_GYROS + 1)
+#define CONFIG_TEMPERATURE (CONFIG_CONTROL_DATA + 1)
+#define CONFIG_RAW_DATA (CONFIG_TEMPERATURE + 1)
+#define CONFIG_RAW_EXTERNAL (CONFIG_RAW_DATA + 1)
+#define CONFIG_ACCEL (CONFIG_RAW_EXTERNAL + 1)
+#define CONFIG_DMP_QUANT_ACCEL (CONFIG_ACCEL + 1)
+#define CONFIG_EIS (CONFIG_DMP_QUANT_ACCEL + 1)
+#define CONFIG_DMP_PACKET_NUMBER (CONFIG_EIS + 1)
+#define CONFIG_FOOTER (CONFIG_DMP_PACKET_NUMBER + 1)
+#define NUMFIFOELEMENTS (CONFIG_FOOTER + 1)
+
+const int fifo_base_offset[NUMFIFOELEMENTS] = {
+ REF_QUATERNION * 4,
+ REF_GYROS * 4,
+ REF_CONTROL * 4,
+ REF_RAW * 4,
+ REF_RAW * 4 + 4,
+ REF_RAW_EXTERNAL * 4,
+ REF_ACCEL * 4,
+ REF_QUANT_ACCEL * 4,
+ REF_EIS * 4,
+ REF_DMP_PACKET * 4,
+ REF_GARBAGE * 4
+};
+
+struct fifo_obj {
+ void (*fifo_process_cb) (void);
+ long decoded[REF_LAST];
+ long decoded_accel[INV_MAX_NUM_ACCEL_SAMPLES][ACCEL_NUM_AXES];
+ int offsets[REF_LAST * 4];
+ int cache;
+ uint_fast8_t gyro_source;
+ unsigned short fifo_rate;
+ unsigned short sample_step_size_ms;
+ uint_fast16_t fifo_packet_size;
+ uint_fast16_t data_config[NUMFIFOELEMENTS];
+ unsigned char reference_count[REF_LAST];
+ long acc_bias_filt[3];
+ float acc_filter_coef;
+ long gravity_cache[3];
+};
+
+static struct fifo_obj fifo_obj;
+
+#define FIFO_CACHE_TEMPERATURE 1
+#define FIFO_CACHE_GYRO 2
+#define FIFO_CACHE_GRAVITY_BODY 4
+#define FIFO_CACHE_ACC_BIAS 8
+
+struct fifo_rate_obj {
+ // These describe callbacks happening everytime a FIFO block is processed
+ int_fast8_t num_cb;
+ HANDLE mutex;
+ inv_obj_func fifo_process_cb[MAX_HIGH_RATE_PROCESSES];
+ int priority[MAX_HIGH_RATE_PROCESSES];
+};
+
+struct fifo_rate_obj fifo_rate_obj;
+
+/** Sets accuracy to be one of 0, INV_32_BIT, or INV_16_BIT. Looks up old
+ * accuracy if needed.
+ */
+static uint_fast16_t inv_set_fifo_accuracy(uint_fast16_t elements,
+ uint_fast16_t accuracy,
+ uint_fast8_t configOffset)
+{
+ if (elements) {
+ if (!accuracy)
+ accuracy = fifo_obj.data_config[configOffset];
+ else if (accuracy & INV_16_BIT)
+ if ((fifo_obj.data_config[configOffset] & INV_32_BIT))
+ accuracy = INV_32_BIT; // 32-bits takes priority
+ else
+ accuracy = INV_16_BIT;
+ else
+ accuracy = INV_32_BIT;
+ } else {
+ accuracy = 0;
+ }
+
+ return accuracy;
+}
+
+/** Adjusts (len) Reference Counts, at offset (refOffset). If increment is 0,
+ * the reference counts are subtracted, otherwise they are incremented for each
+ * bit set in element. The value returned are the elements that should be sent
+ * out as data through the FIFO.
+*/
+static uint_fast16_t inv_set_fifo_reference(uint_fast16_t elements,
+ uint_fast16_t increment,
+ uint_fast8_t refOffset,
+ uint_fast8_t len)
+{
+ uint_fast8_t kk;
+
+ if (increment == 0) {
+ for (kk = 0; kk < len; ++kk) {
+ if ((elements & 1)
+ && (fifo_obj.reference_count[kk + refOffset] > 0)) {
+ fifo_obj.reference_count[kk + refOffset]--;
+ }
+ elements >>= 1;
+ }
+ } else {
+ for (kk = 0; kk < len; ++kk) {
+ if (elements & 1)
+ fifo_obj.reference_count[kk + refOffset]++;
+ elements >>= 1;
+ }
+ }
+ elements = 0;
+ for (kk = 0; kk < len; ++kk) {
+ if (fifo_obj.reference_count[kk + refOffset] > 0)
+ elements |= (1 << kk);
+ }
+ return elements;
+}
+
+/**
+ * @param[in] accuracy INV_16_BIT or INV_32_BIT when constructing data to send
+ * out the FIFO, 0 when removing from the FIFO.
+ */
+static inv_error_t inv_construct3_fifo(unsigned char *regs,
+ uint_fast16_t elements,
+ uint_fast16_t accuracy,
+ uint_fast8_t refOffset,
+ unsigned short key,
+ uint_fast8_t configOffset)
+{
+ int_fast8_t kk;
+ inv_error_t result;
+
+ elements = inv_set_fifo_reference(elements, accuracy, refOffset, 3);
+ accuracy = inv_set_fifo_accuracy(elements, accuracy, configOffset);
+
+ if (accuracy & INV_16_BIT) {
+ regs[0] = DINAF8 + 2;
+ }
+
+ fifo_obj.data_config[configOffset] = elements | accuracy;
+
+ for (kk = 0; kk < 3; ++kk) {
+ if ((elements & 1) == 0)
+ regs[kk + 1] = DINAA0 + 3;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(key, 4, regs);
+
+ return result;
+}
+
+/**
+ * @internal
+ * Puts footer on FIFO data.
+ */
+static inv_error_t inv_set_footer(void)
+{
+ unsigned char regs = DINA30;
+ uint_fast8_t tmp_count;
+ int_fast8_t i, j;
+ int offset;
+ int result;
+ int *fifo_offsets_ptr = fifo_obj.offsets;
+
+ fifo_obj.fifo_packet_size = 0;
+ for (i = 0; i < NUMFIFOELEMENTS; i++) {
+ tmp_count = 0;
+ offset = fifo_base_offset[i];
+ for (j = 0; j < 8; j++) {
+ if ((fifo_obj.data_config[i] >> j) & 0x0001) {
+#ifndef BIG_ENDIAN
+ // Special Case for Byte Ordering on Accel Data
+ if ((i == CONFIG_RAW_DATA) && (j > 2)) {
+ tmp_count += 2;
+ switch (inv_get_dl_config()->accel->endian) {
+ case EXT_SLAVE_BIG_ENDIAN:
+ *fifo_offsets_ptr++ = offset + 3;
+ *fifo_offsets_ptr++ = offset + 2;
+ break;
+ case EXT_SLAVE_LITTLE_ENDIAN:
+ *fifo_offsets_ptr++ = offset + 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ break;
+ case EXT_SLAVE_FS8_BIG_ENDIAN:
+ if (j == 3) {
+ // Throw this byte away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ = offset + 3;
+ } else if (j == 4) {
+ *fifo_offsets_ptr++ = offset + 3;
+ *fifo_offsets_ptr++ = offset + 7;
+ } else {
+ // Throw these byte away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ }
+ break;
+ case EXT_SLAVE_FS16_BIG_ENDIAN:
+ if (j == 3) {
+ // Throw this byte away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ = offset + 3;
+ } else if (j == 4) {
+ *fifo_offsets_ptr++ = offset - 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ } else {
+ *fifo_offsets_ptr++ = offset - 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ }
+ break;
+ default:
+ return INV_ERROR; // Bad value on ordering
+ }
+ } else {
+ tmp_count += 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ *fifo_offsets_ptr++ = offset + 2;
+ if (fifo_obj.data_config[i] & INV_32_BIT) {
+ *fifo_offsets_ptr++ = offset + 1;
+ *fifo_offsets_ptr++ = offset;
+ tmp_count += 2;
+ }
+ }
+#else
+ // Big Endian Platform
+ // Special Case for Byte Ordering on Accel Data
+ if ((i == CONFIG_RAW_DATA) && (j > 2)) {
+ tmp_count += 2;
+ switch (inv_get_dl_config()->accel->endian) {
+ case EXT_SLAVE_BIG_ENDIAN:
+ *fifo_offsets_ptr++ = offset + 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ break;
+ case EXT_SLAVE_LITTLE_ENDIAN:
+ *fifo_offsets_ptr++ = offset + 3;
+ *fifo_offsets_ptr++ = offset + 2;
+ break;
+ case EXT_SLAVE_FS8_BIG_ENDIAN:
+ if (j == 3) {
+ // Throw this byte away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ = offset;
+ } else if (j == 4) {
+ *fifo_offsets_ptr++ = offset;
+ *fifo_offsets_ptr++ = offset + 4;
+ } else {
+ // Throw these bytes away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ }
+ break;
+ case EXT_SLAVE_FS16_BIG_ENDIAN:
+ if (j == 3) {
+ // Throw this byte away
+ *fifo_offsets_ptr++ =
+ fifo_base_offset[CONFIG_FOOTER];
+ *fifo_offsets_ptr++ = offset;
+ } else if (j == 4) {
+ *fifo_offsets_ptr++ = offset - 3;
+ *fifo_offsets_ptr++ = offset;
+ } else {
+ *fifo_offsets_ptr++ = offset - 3;
+ *fifo_offsets_ptr++ = offset;
+ }
+ break;
+ default:
+ return INV_ERROR; // Bad value on ordering
+ }
+ } else {
+ tmp_count += 2;
+ *fifo_offsets_ptr++ = offset;
+ *fifo_offsets_ptr++ = offset + 1;
+ if (fifo_obj.data_config[i] & INV_32_BIT) {
+ *fifo_offsets_ptr++ = offset + 2;
+ *fifo_offsets_ptr++ = offset + 3;
+ tmp_count += 2;
+ }
+ }
+
+#endif
+ }
+ offset += 4;
+ }
+ fifo_obj.fifo_packet_size += tmp_count;
+ }
+ if (fifo_obj.data_config[CONFIG_FOOTER] == 0 &&
+ fifo_obj.fifo_packet_size > 0) {
+ // Add footer
+ result = inv_set_mpu_memory(KEY_CFG_16, 1, &regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ fifo_obj.data_config[CONFIG_FOOTER] = 0x0001 | INV_16_BIT;
+ fifo_obj.fifo_packet_size += 2;
+ } else if (fifo_obj.data_config[CONFIG_FOOTER] &&
+ (fifo_obj.fifo_packet_size == 2)) {
+ // Remove Footer
+ regs = DINAA0 + 3;
+ result = inv_set_mpu_memory(KEY_CFG_16, 1, &regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ fifo_obj.data_config[CONFIG_FOOTER] = 0;
+ fifo_obj.fifo_packet_size = 0;
+ }
+
+ return INV_SUCCESS;
+}
+
+inv_error_t inv_decode_quantized_accel(void)
+{
+ int kk;
+ int fifoRate = inv_get_fifo_rate();
+
+ if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = (INV_MAX_NUM_ACCEL_SAMPLES - (fifoRate + 1));
+ kk < INV_MAX_NUM_ACCEL_SAMPLES; kk++) {
+ union {
+ unsigned int u10:10;
+ signed int s10:10;
+ } temp;
+
+ union {
+ uint32_t u32;
+ int32_t s32;
+ } value;
+
+ value.u32 = fifo_obj.decoded[REF_QUANT_ACCEL + kk];
+ // unquantize this samples.
+ // They are stored as x * 2^20 + y * 2^10 + z
+ // Z
+ temp.u10 = value.u32 & 0x3ff;
+ value.s32 -= temp.s10;
+ fifo_obj.decoded_accel[kk][2] = temp.s10 * 64;
+ // Y
+ value.s32 = value.s32 / 1024;
+ temp.u10 = value.u32 & 0x3ff;
+ value.s32 -= temp.s10;
+ fifo_obj.decoded_accel[kk][1] = temp.s10 * 64;
+ // X
+ value.s32 = value.s32 / 1024;
+ temp.u10 = value.u32 & 0x3ff;
+ fifo_obj.decoded_accel[kk][0] = temp.s10 * 64;
+ }
+ return INV_SUCCESS;
+}
+
+static inv_error_t inv_state_change_fifo(unsigned char newState)
+{
+ inv_error_t result = INV_SUCCESS;
+ unsigned char regs[4];
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+
+ /* Don't reset the fifo on a fifo rate change */
+ if ((mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) &&
+ (newState != inv_get_state()) && (inv_dmpkey_supported(KEY_D_1_178))) {
+ /* Delay output on restart by 50ms due to warm up time of gyros */
+
+ short delay = (short)-((50 / inv_get_sample_step_size_ms()) + 1);
+ inv_init_fifo_hardare();
+ inv_int16_to_big8(delay, regs);
+ result = inv_set_mpu_memory(KEY_D_1_178, 2, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ if (INV_STATE_DMP_STARTED == newState) {
+ if (inv_dmpkey_supported(KEY_D_1_128)) {
+ double tmp;
+ tmp = (0x20000000L * M_PI) / (fifo_obj.fifo_rate + 1);
+ if (tmp > 0x40000000L)
+ tmp = 0x40000000L;
+ (void)inv_int32_to_big8((long)tmp, regs);
+ result = inv_set_mpu_memory(KEY_D_1_128, sizeof(long), regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_reset_fifo();
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * @internal
+ * @brief get the FIFO packet size
+ * @return the FIFO packet size
+ */
+uint_fast16_t inv_get_fifo_packet_size(void)
+{
+ return fifo_obj.fifo_packet_size;
+}
+
+/**
+ * @brief Initializes all the internal static variables for
+ * the FIFO module.
+ * @note Should be called by the initialization routine such
+ * as inv_dmp_open().
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_init_fifo_param(void)
+{
+ inv_error_t result;
+ memset(&fifo_obj, 0, sizeof(struct fifo_obj));
+ fifo_obj.decoded[REF_QUATERNION] = 1073741824L; // Set to Identity
+ inv_set_linear_accel_filter_coef(0.f);
+ fifo_obj.fifo_rate = 20;
+ fifo_obj.sample_step_size_ms = 100;
+ memset(&fifo_rate_obj, 0, sizeof(struct fifo_rate_obj));
+ result = inv_create_mutex(&fifo_rate_obj.mutex);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_register_state_callback(inv_state_change_fifo);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ return result;
+}
+
+/**
+ * @brief Close the FIFO usage.
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_close_fifo(void)
+{
+ inv_error_t result;
+ inv_error_t first = INV_SUCCESS;
+ result = inv_unregister_state_callback(inv_state_change_fifo);
+ ERROR_CHECK_FIRST(first, result);
+ result = inv_destroy_mutex(fifo_rate_obj.mutex);
+ ERROR_CHECK_FIRST(first, result);
+ memset(&fifo_rate_obj, 0, sizeof(struct fifo_rate_obj));
+ return first;
+}
+
+/**
+ * Set the gyro source to output to the fifo
+ *
+ * @param source The source. One of
+ * - INV_GYRO_FROM_RAW
+ * - INV_GYRO_FROM_QUATERNION
+ *
+ * @return INV_SUCCESS or non-zero error code;
+ */
+inv_error_t inv_set_gyro_data_source(uint_fast8_t source)
+{
+ if (source != INV_GYRO_FROM_QUATERNION && source != INV_GYRO_FROM_RAW) {
+ return INV_ERROR_INVALID_PARAMETER;
+ }
+
+ fifo_obj.gyro_source = source;
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Reads and processes FIFO data. Also handles callbacks when data is
+ * ready.
+ * @param numPackets
+ * Number of FIFO packets to try to read. You should
+ * use a large number here, such as 100, if you want to read all
+ * the full packets in the FIFO, which is typical operation.
+ * @param processed
+ * The number of FIFO packets processed. This may be incremented
+ * even if high rate processes later fail.
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_read_and_process_fifo(int_fast8_t numPackets,
+ int_fast8_t * processed)
+{
+ int_fast8_t packet;
+ inv_error_t result = INV_SUCCESS;
+ uint_fast16_t read;
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+ int kk;
+
+ if (NULL == processed)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ *processed = 0;
+ if (fifo_obj.fifo_packet_size == 0)
+ return result; // Nothing to read
+
+ for (packet = 0; packet < numPackets; ++packet) {
+ if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) {
+ unsigned char footer_n_data[MAX_FIFO_LENGTH + FIFO_FOOTER_SIZE];
+ unsigned char *buf = &footer_n_data[FIFO_FOOTER_SIZE];
+ read = inv_get_fifo((uint_fast16_t) fifo_obj.fifo_packet_size,
+ footer_n_data);
+ if (0 == read ||
+ read != fifo_obj.fifo_packet_size - FIFO_FOOTER_SIZE) {
+ result = inv_get_fifo_status();
+ if (INV_SUCCESS != result) {
+ memset(fifo_obj.decoded, 0, sizeof(fifo_obj.decoded));
+ }
+ return result;
+ }
+
+ result = inv_process_fifo_packet(buf);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ } else if (inv_accel_present()) {
+ long data[ACCEL_NUM_AXES];
+ result = inv_get_accel_data(data);
+ if (result == INV_ERROR_ACCEL_DATA_NOT_READY) {
+ return INV_SUCCESS;
+ }
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ memset(fifo_obj.decoded, 0, sizeof(fifo_obj.decoded));
+ fifo_obj.cache = 0;
+ for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
+ fifo_obj.decoded[REF_RAW + 4 + kk] =
+ inv_q30_mult((data[kk] << 16),
+ fifo_scale[REF_RAW + 4 + kk]);
+ fifo_obj.decoded[REF_ACCEL + kk] =
+ inv_q30_mult((data[kk] << 15), fifo_scale[REF_ACCEL + kk]);
+ fifo_obj.decoded[REF_ACCEL + kk] -=
+ inv_obj.scaled_accel_bias[kk];
+ }
+ }
+ // The buffer was processed correctly, so increment even if
+ // other processes fail later, which will return an error
+ *processed = *processed + 1;
+
+ if ((fifo_obj.fifo_rate < INV_MAX_NUM_ACCEL_SAMPLES) &&
+ fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL]) {
+ result = inv_decode_quantized_accel();
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ if (fifo_obj.data_config[CONFIG_QUAT]) {
+ result = inv_accel_compass_supervisor();
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
+
+ result = inv_pressure_supervisor();
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ // Callbacks now that we have a buffer of data ready
+ result = inv_run_fifo_rate_processes();
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ }
+ return result;
+}
+
+/**
+ * @brief inv_set_fifo_processed_callback is used to set a processed data callback
+ * function. inv_set_fifo_processed_callback sets a user defined callback
+ * function that triggers when all the decoding has been finished by
+ * the motion processing engines. It is called before other bigger
+ * processing engines to allow lower latency for the user.
+ *
+ * @pre inv_dmp_open()
+ * @ifnot MPL_MF
+ * or inv_open_low_power_pedometer()
+ * or inv_eis_open_dmp()
+ * @endif
+ * and inv_dmp_start()
+ * must <b>NOT</b> have been called.
+ *
+ * @param func A user defined callback function.
+ *
+ * @return INV_SUCCESS if successful, or non-zero error code otherwise.
+ */
+inv_error_t inv_set_fifo_processed_callback(void (*func) (void))
+{
+ INVENSENSE_FUNC_START;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ fifo_obj.fifo_process_cb = func;
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @internal
+ * @brief Process data from the dmp read via the fifo. Takes a buffer
+ * filled with bytes read from the DMP FIFO.
+ * Currently expects only the 16 bytes of quaternion data.
+ * Calculates the motion parameters from that data and stores the
+ * results in an internal data structure.
+ * @param[in,out] dmpData Pointer to the buffer containing the fifo data.
+ * @return INV_SUCCESS or error code.
+**/
+inv_error_t inv_process_fifo_packet(const unsigned char *dmpData)
+{
+ INVENSENSE_FUNC_START;
+ unsigned int N, kk;
+ unsigned char *p;
+
+ p = (unsigned char *)(&fifo_obj.decoded);
+ N = fifo_obj.fifo_packet_size;
+ if (N > sizeof(fifo_obj.decoded))
+ return INV_ERROR_ASSERTION_FAILURE;
+
+ memset(&fifo_obj.decoded, 0, sizeof(fifo_obj.decoded));
+
+ for (kk = 0; kk < N; ++kk) {
+ p[fifo_obj.offsets[kk]] = *dmpData++;
+ }
+
+ // If multiplies are much greater cost than if checks, you could check
+ // to see if fifo_scale is non-zero first, or equal to (1L<<30)
+ for (kk = 0; kk < REF_LAST; ++kk) {
+ fifo_obj.decoded[kk] =
+ inv_q30_mult(fifo_obj.decoded[kk], fifo_scale[kk]);
+ }
+
+ memcpy(&fifo_obj.decoded[REF_QUATERNION_6AXIS],
+ &fifo_obj.decoded[REF_QUATERNION], 4 * sizeof(long));
+
+ inv_obj.flags[INV_PROCESSED_DATA_READY] = 1;
+ fifo_obj.cache = 0;
+
+ return INV_SUCCESS;
+}
+
+/** Converts 16-bit temperature data as read from temperature register
+* into Celcius scaled by 2^16.
+*/
+long inv_decode_temperature(short tempReg)
+{
+ // Celcius = 35 + (T + 13200)/280
+ return 5383314L + inv_q30_mult((long)tempReg << 16, 3834792L);
+}
+
+/** @internal
+* Returns the temperature in hardware units. The scaling may change from part to part.
+*/
+inv_error_t inv_get_temperature_raw(short *data)
+{
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_TEMPERATURE]) {
+ inv_error_t result;
+ unsigned char regs[2];
+ if ((fifo_obj.cache & FIFO_CACHE_TEMPERATURE) == 0) {
+ if (FIFO_DEBUG)
+ MPL_LOGI("Fetching the temperature from the registers\n");
+ fifo_obj.cache |= FIFO_CACHE_TEMPERATURE;
+ result = inv_serial_read(inv_get_serial_handle(),
+ inv_get_mpu_slave_addr(), MPUREG_TEMP_OUT_H, 2,
+ regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ fifo_obj.decoded[REF_RAW] = ((short)regs[0] << 8) | (regs[1]);
+ }
+ }
+ *data = (short)fifo_obj.decoded[REF_RAW];
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 1-element vector of temperature. It is read from the hardware if it
+ * doesn't exist in the FIFO.
+ * @param[out] data 1-element vector of temperature
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_temperature(long *data)
+{
+ short tr;
+ inv_error_t result;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+ result = inv_get_temperature_raw(&tr);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ data[0] = inv_decode_temperature(tr);
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Get the Decoded Accel Data.
+ * @param data
+ * a buffer to store the quantized data.
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_get_unquantized_accel(long *data)
+{
+ int ii, kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (ii = 0; ii < INV_MAX_NUM_ACCEL_SAMPLES; ii++) {
+ for (kk = 0; kk < ACCEL_NUM_AXES; kk++) {
+ data[ii * ACCEL_NUM_AXES + kk] = fifo_obj.decoded_accel[ii][kk];
+ }
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Get the Quantized Accel data algorithm output from the FIFO.
+ * @param data
+ * a buffer to store the quantized data.
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_get_quantized_accel(long *data)
+{
+ int ii;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (ii = 0; ii < INV_MAX_NUM_ACCEL_SAMPLES; ii++) {
+ data[ii] = fifo_obj.decoded[REF_QUANT_ACCEL + ii];
+ }
+
+ return INV_SUCCESS;
+}
+
+/** This gets raw gyro data. The data is taken from the FIFO if it was put in the FIFO
+* and it is read from the registers if it was not put into the FIFO. The data is
+* cached till the next FIFO processing block time.
+* @param[out] data Length 3, Gyro data
+*/
+inv_error_t inv_get_gyro_sensor(long *data)
+{
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+ if ((fifo_obj.data_config[CONFIG_RAW_DATA] & 7) != 7) {
+ inv_error_t result;
+ unsigned char regs[6];
+ if ((fifo_obj.cache & FIFO_CACHE_GYRO) == 0) {
+ fifo_obj.cache |= FIFO_CACHE_GYRO;
+ result =
+ inv_serial_read(inv_get_serial_handle(),
+ inv_get_mpu_slave_addr(), MPUREG_GYRO_XOUT_H, 6,
+ regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ fifo_obj.decoded[REF_RAW + 1] =
+ (((long)regs[0]) << 24) | (((long)regs[1]) << 16);
+ fifo_obj.decoded[REF_RAW + 2] =
+ (((long)regs[2]) << 24) | (((long)regs[3]) << 16);
+ fifo_obj.decoded[REF_RAW + 3] =
+ (((long)regs[4]) << 24) | (((long)regs[5]) << 16);
+
+ // Temperature starts at location 0, Gyro at location 1.
+ fifo_obj.decoded[REF_RAW + 1] =
+ inv_q30_mult(fifo_obj.decoded[REF_RAW + 1],
+ fifo_scale[REF_RAW + 1]);
+ fifo_obj.decoded[REF_RAW + 2] =
+ inv_q30_mult(fifo_obj.decoded[REF_RAW + 2],
+ fifo_scale[REF_RAW + 2]);
+ fifo_obj.decoded[REF_RAW + 3] =
+ inv_q30_mult(fifo_obj.decoded[REF_RAW + 3],
+ fifo_scale[REF_RAW + 3]);
+ }
+ data[0] = fifo_obj.decoded[REF_RAW + 1];
+ data[1] = fifo_obj.decoded[REF_RAW + 2];
+ data[2] = fifo_obj.decoded[REF_RAW + 3];
+ } else {
+ long data2[6];
+ inv_get_gyro_and_accel_sensor(data2);
+ data[0] = data2[0];
+ data[1] = data2[1];
+ data[2] = data2[2];
+ }
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 6-element vector of gyro and accel data
+ * @param[out] data 6-element vector of gyro and accel data
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_gyro_and_accel_sensor(long *data)
+{
+ int ii;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_RAW_DATA])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (ii = 0; ii < (GYRO_NUM_AXES + ACCEL_NUM_AXES); ii++) {
+ data[ii] = fifo_obj.decoded[REF_RAW + 1 + ii];
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 3-element vector of external sensor
+ * @param[out] data 3-element vector of external sensor
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_external_sensor_data(long *data, int size __unused)
+{
+ memset(data, 0, COMPASS_NUM_AXES * sizeof(long));
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+/**
+ * Sends accelerometer data to the FIFO.
+ *
+ * @param[in] elements Which of the 3 elements to send. Use INV_ALL for 3 axis
+ * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together
+ * for a subset.
+ *
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data. Set to zero to remove it from the FIFO.
+ */
+inv_error_t inv_send_accel(uint_fast16_t elements, uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ unsigned char regs[4] = { DINAF8 + 1, DINA28, DINA30, DINA38 };
+ inv_error_t result;
+ int kk;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ result = inv_construct3_fifo(regs, elements, accuracy, REF_ACCEL,
+ KEY_CFG_12, CONFIG_ACCEL);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ for (kk = 0; kk < ACCEL_NUM_AXES; kk++) {
+ fifo_scale[REF_ACCEL + kk] = 2 * inv_obj.accel_sens;
+ }
+
+ return inv_set_footer();
+}
+
+/**
+ * Sends control data to the FIFO. Control data is a 4 length vector of 32-bits.
+ *
+ * @param[in] elements Which of the 4 elements to send. Use INV_ALL for all
+ * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3, INV_ELEMENT_4 or'd
+ * together for a subset.
+ *
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data. Set to zero to remove it from the FIFO.
+ */
+inv_error_t inv_send_cntrl_data(uint_fast16_t elements, uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ int_fast8_t kk;
+ inv_error_t result;
+ unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28, DINA30, DINA38 };
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ elements = inv_set_fifo_reference(elements, accuracy, REF_CONTROL, 4);
+ accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_CONTROL_DATA);
+
+ if (accuracy & INV_16_BIT) {
+ regs[0] = DINAF8 + 2;
+ }
+
+ fifo_obj.data_config[CONFIG_CONTROL_DATA] = elements | accuracy;
+
+ for (kk = 0; kk < 4; ++kk) {
+ if ((elements & 1) == 0)
+ regs[kk + 1] = DINAA0 + 3;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(KEY_CFG_1, 5, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+/**
+ * Adds a rolling counter to the fifo packet. When used with the footer
+ * the data comes out the first time:
+ *
+ * @code
+ * <data0><data1>...<dataN><PacketNum0><PacketNum1>
+ * @endcode
+ * for every other packet it is
+ *
+ * @code
+ * <FifoFooter0><FifoFooter1><data0><data1>...<dataN><PacketNum0><PacketNum1>
+ * @endcode
+ *
+ * This allows for scanning of the fifo for packets
+ *
+ * @return INV_SUCCESS or error code
+ */
+inv_error_t inv_send_packet_number(uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ inv_error_t result;
+ unsigned char regs;
+ uint_fast16_t elements;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ elements = inv_set_fifo_reference(1, accuracy, REF_DMP_PACKET, 1);
+ if (elements & 1) {
+ regs = DINA28;
+ fifo_obj.data_config[CONFIG_DMP_PACKET_NUMBER] =
+ INV_ELEMENT_1 | INV_16_BIT;
+ } else {
+ regs = DINAF8 + 3;
+ fifo_obj.data_config[CONFIG_DMP_PACKET_NUMBER] = 0;
+ }
+ result = inv_set_mpu_memory(KEY_CFG_23, 1, &regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+/**
+ * @brief Send the computed gravity vectors into the FIFO.
+ * The gravity vectors can be retrieved from the FIFO via
+ * inv_get_gravity(), to have the gravitation vector expressed
+ * in coordinates relative to the body.
+ *
+ * Gravity is a derived vector derived from the quaternion.
+ * @param elements
+ * the gravitation vectors components bitmask.
+ * To send all compoents use INV_ALL.
+ * @param accuracy
+ * The number of bits the gravitation vector is expressed
+ * into.
+ * Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data.
+ * Set to zero to remove it from the FIFO.
+ *
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_send_gravity(uint_fast16_t elements __unused, uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ inv_error_t result;
+
+ result = inv_send_quaternion(accuracy);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+/** Sends gyro data to the FIFO. Gyro data is a 3 length vector
+ * of 32-bits. Should be called once after inv_dmp_open() and before inv_dmp_start().
+ * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of them
+ * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together
+ * for a subset.
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data. Set to zero to remove it from the FIFO.
+ */
+inv_error_t inv_send_gyro(uint_fast16_t elements, uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ unsigned char regs[4] = { DINAF8 + 1, DINA20, DINA28, DINA30 };
+ inv_error_t result;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ if (fifo_obj.gyro_source == INV_GYRO_FROM_QUATERNION) {
+ regs[0] = DINA90 + 5;
+ result = inv_set_mpu_memory(KEY_CFG_GYRO_SOURCE, 1, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ regs[0] = DINAF8 + 1;
+ regs[1] = DINA20;
+ regs[2] = DINA28;
+ regs[3] = DINA30;
+ } else {
+ regs[0] = DINA90 + 10;
+ result = inv_set_mpu_memory(KEY_CFG_GYRO_SOURCE, 1, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ regs[0] = DINAF8 + 1;
+ regs[1] = DINA28;
+ regs[2] = DINA30;
+ regs[3] = DINA38;
+ }
+ result = inv_construct3_fifo(regs, elements, accuracy, REF_GYROS,
+ KEY_CFG_9, CONFIG_GYROS);
+
+ return inv_set_footer();
+}
+
+/** Sends linear accelerometer data to the FIFO.
+ *
+ * Linear accelerometer data is a 3 length vector of 32-bits. It is the
+ * acceleration in the body frame with gravity removed.
+ *
+ *
+ * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of
+ * them or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together
+ * for a subset.
+ *
+ * NOTE: Elements is ignored if the fifo rate is < INV_MAX_NUM_ACCEL_SAMPLES
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data. Set to zero to remove it from the FIFO.
+ */
+inv_error_t inv_send_linear_accel(uint_fast16_t elements,
+ uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ inv_error_t result;
+ unsigned char state = inv_get_state();
+
+ if (state < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ result = inv_send_gravity(elements, accuracy);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_send_accel(elements, accuracy);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+/** Sends linear world accelerometer data to the FIFO. Linear world
+ * accelerometer data is a 3 length vector of 32-bits. It is the acceleration
+ * in the world frame with gravity removed. Should be called once after
+ * inv_dmp_open() and before inv_dmp_start().
+ *
+ * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of
+ * them or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together
+ * for a subset.
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data.
+ */
+inv_error_t inv_send_linear_accel_in_world(uint_fast16_t elements __unused,
+ uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ inv_error_t result;
+
+ result = inv_send_linear_accel(INV_ALL, accuracy);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_send_quaternion(accuracy);
+
+ return inv_set_footer();
+}
+
+/** Sends quaternion data to the FIFO. Quaternion data is a 4 length vector
+ * of 32-bits. Should be called once after inv_dmp_open() and before inv_dmp_start().
+ * @param[in] accuracy Set to INV_32_BIT for 32-bit data, or INV_16_BIT for 16
+ * bit data.
+ */
+inv_error_t inv_send_quaternion(uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28,
+ DINA30, DINA38
+ };
+ uint_fast16_t elements, kk;
+ inv_error_t result;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ elements = inv_set_fifo_reference(0xf, accuracy, REF_QUATERNION, 4);
+ accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_QUAT);
+
+ if (accuracy & INV_16_BIT) {
+ regs[0] = DINAF8 + 2;
+ }
+
+ fifo_obj.data_config[CONFIG_QUAT] = elements | accuracy;
+
+ for (kk = 0; kk < 4; ++kk) {
+ if ((elements & 1) == 0)
+ regs[kk + 1] = DINAA0 + 3;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(KEY_CFG_8, 5, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+/** Sends raw data to the FIFO.
+ * Should be called once after inv_dmp_open() and before inv_dmp_start().
+ * @param[in] elements Which of the 7 elements to send. Use INV_ALL for all of them
+ * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 ... INV_ELEMENT_7 or'd together
+ * for a subset. The first element is temperature, the next 3 are gyro data,
+ * and the last 3 accel data.
+ * @param accuracy
+ * The element's accuracy, can be INV_16_BIT, INV_32_BIT, or 0 to turn off.
+ * @return 0 if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_send_sensor_data(uint_fast16_t elements, uint_fast16_t accuracy)
+{
+ int result;
+ INVENSENSE_FUNC_START;
+ unsigned char regs[4] = { DINAA0 + 3,
+ DINAA0 + 3,
+ DINAA0 + 3,
+ DINAA0 + 3
+ };
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ if (accuracy)
+ accuracy = INV_16_BIT;
+
+ elements = inv_set_fifo_reference(elements, accuracy, REF_RAW, 7);
+
+ if (elements & 0x03) {
+ elements |= 0x03;
+ regs[0] = DINA20;
+ }
+ if (elements & 0x0C) {
+ elements |= 0x0C;
+ regs[1] = DINA28;
+ }
+ if (elements & 0x30) {
+ elements |= 0x30;
+ regs[2] = DINA30;
+ }
+ if (elements & 0x40) {
+ elements |= 0xC0;
+ regs[3] = DINA38;
+ }
+
+ result = inv_set_mpu_memory(KEY_CFG_15, 4, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ if (elements & 0x01)
+ fifo_obj.data_config[CONFIG_TEMPERATURE] = 1 | INV_16_BIT;
+ else
+ fifo_obj.data_config[CONFIG_TEMPERATURE] = 0;
+ if (elements & 0xfe)
+ fifo_obj.data_config[CONFIG_RAW_DATA] =
+ (0x7f & (elements >> 1)) | INV_16_BIT;
+ else
+ fifo_obj.data_config[CONFIG_RAW_DATA] = 0;
+
+ return inv_set_footer();
+}
+
+/** Sends raw external data to the FIFO.
+ * Should be called once after inv_dmp_open() and before inv_dmp_start().
+ * @param[in] elements Which of the 3 elements to send. Use INV_ALL for all of them
+ * or INV_ELEMENT_1, INV_ELEMENT_2, INV_ELEMENT_3 or'd together
+ * for a subset.
+ * @param[in] accuracy INV_16_BIT to send data, 0 to stop sending this data.
+ * Sending and Stop sending are reference counted, so data actually
+ * stops when the reference reaches zero.
+ */
+inv_error_t inv_send_external_sensor_data(uint_fast16_t elements __unused,
+ uint_fast16_t accuracy __unused)
+{
+ return INV_ERROR_FEATURE_NOT_IMPLEMENTED; // Feature not supported
+}
+
+/**
+ * @brief Send the Quantized Acceleromter data into the FIFO. The data can be
+ * retrieved using inv_get_quantized_accel() or inv_get_unquantized_accel().
+ *
+ * To be useful this should be set to fifo_rate + 1 if less than
+ * INV_MAX_NUM_ACCEL_SAMPLES, otherwise it doesn't work.
+ *
+ * @param elements
+ * the components bitmask.
+ * To send all compoents use INV_ALL.
+ *
+ * @param accuracy
+ * Use INV_32_BIT for 32-bit data or INV_16_BIT for
+ * 16-bit data.
+ * Set to zero to remove it from the FIFO.
+ *
+ * @return INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+inv_error_t inv_send_quantized_accel(uint_fast16_t elements,
+ uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ unsigned char regs[5] = { DINAF8 + 1, DINA20, DINA28,
+ DINA30, DINA38
+ };
+ unsigned char regs2[4] = { DINA20, DINA28,
+ DINA30, DINA38
+ };
+ inv_error_t result;
+ int_fast8_t kk;
+ int_fast8_t ii;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ elements = inv_set_fifo_reference(elements, accuracy, REF_QUANT_ACCEL, 8);
+
+ if (elements) {
+ fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL] = (elements) | INV_32_BIT;
+ } else {
+ fifo_obj.data_config[CONFIG_DMP_QUANT_ACCEL] = 0;
+ }
+
+ for (kk = 0; kk < INV_MAX_NUM_ACCEL_SAMPLES; ++kk) {
+ fifo_obj.decoded[REF_QUANT_ACCEL + kk] = 0;
+ for (ii = 0; ii < ACCEL_NUM_AXES; ii++) {
+ fifo_obj.decoded_accel[kk][ii] = 0;
+ }
+ }
+
+ for (kk = 0; kk < 4; ++kk) {
+ if ((elements & 1) == 0)
+ regs[kk + 1] = DINAA0 + 3;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(KEY_CFG_TAP0, 5, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ for (kk = 0; kk < 4; ++kk) {
+ if ((elements & 1) == 0)
+ regs2[kk] = DINAA0 + 3;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(KEY_CFG_TAP4, 4, regs2);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ return inv_set_footer();
+}
+
+inv_error_t inv_send_eis(uint_fast16_t elements, uint_fast16_t accuracy)
+{
+ INVENSENSE_FUNC_START;
+ int_fast8_t kk;
+ unsigned char regs[3] = { DINA28, DINA30, DINA38 };
+ inv_error_t result;
+
+ if (inv_get_state() < INV_STATE_DMP_OPENED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ if (accuracy) {
+ accuracy = INV_32_BIT;
+ }
+
+ elements = inv_set_fifo_reference(elements, accuracy, REF_EIS, 3);
+ accuracy = inv_set_fifo_accuracy(elements, accuracy, CONFIG_EIS);
+
+ fifo_obj.data_config[CONFIG_EIS] = elements | accuracy;
+
+ for (kk = 0; kk < 3; ++kk) {
+ if ((elements & 1) == 0)
+ regs[kk] = DINAA0 + 7;
+ elements >>= 1;
+ }
+
+ result = inv_set_mpu_memory(KEY_P_EIS_FIFO_XSHIFT, 3, regs);
+
+ return inv_set_footer();
+}
+
+/**
+ * @brief Returns 3-element vector of accelerometer data in body frame.
+ *
+ * @param[out] data 3-element vector of accelerometer data in body frame.
+ * One gee = 2^16.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_accel(long *data)
+{
+ int kk;
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if ((!fifo_obj.data_config[CONFIG_ACCEL] &&
+ (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR))
+ ||
+ (!(mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) &&
+ !inv_accel_present()))
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_ACCEL + kk];
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 4-element quaternion vector derived from 6-axis or
+ * 9-axis if 9-axis was implemented. 6-axis is gyros and accels. 9-axis is
+ * gyros, accel and compass.
+ *
+ * @param[out] data 4-element quaternion vector. One is scaled to 2^30.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_quaternion(long *data)
+{
+ int kk;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_QUAT])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < 4; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_QUATERNION + kk];
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 4-element quaternion vector derived from 6
+ * axis sensors (gyros and accels).
+ * @param[out] data
+ * 4-element quaternion vector. One is scaled to 2^30.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_6axis_quaternion(long *data)
+{
+ int kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_QUAT])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < 4; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_QUATERNION_6AXIS + kk];
+ }
+
+ return INV_SUCCESS;
+}
+
+inv_error_t inv_get_relative_quaternion(long *data)
+{
+ if (data == NULL)
+ return INV_ERROR;
+ data[0] = inv_obj.relative_quat[0];
+ data[1] = inv_obj.relative_quat[1];
+ data[2] = inv_obj.relative_quat[2];
+ data[3] = inv_obj.relative_quat[3];
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 3-element vector of gyro data in body frame.
+ * @param[out] data
+ * 3-element vector of gyro data in body frame
+ * with gravity removed. One degree per second = 2^16.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_gyro(long *data)
+{
+ int kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (fifo_obj.data_config[CONFIG_GYROS]) {
+ for (kk = 0; kk < 3; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_GYROS + kk];
+ }
+ return INV_SUCCESS;
+ } else {
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+ }
+}
+
+/**
+ * @brief Get the 3-element gravity vector from the FIFO expressed
+ * in coordinates relative to the body frame.
+ * @param data
+ * 3-element vector of gravity in body frame.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_gravity(long *data)
+{
+ long quat[4];
+ int ii;
+ inv_error_t result;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_QUAT])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ if ((fifo_obj.cache & FIFO_CACHE_GRAVITY_BODY) == 0) {
+ fifo_obj.cache |= FIFO_CACHE_GRAVITY_BODY;
+
+ // Compute it from Quaternion
+ result = inv_get_quaternion(quat);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ data[0] =
+ inv_q29_mult(quat[1], quat[3]) - inv_q29_mult(quat[2], quat[0]);
+ data[1] =
+ inv_q29_mult(quat[2], quat[3]) + inv_q29_mult(quat[1], quat[0]);
+ data[2] =
+ (inv_q29_mult(quat[3], quat[3]) + inv_q29_mult(quat[0], quat[0])) -
+ 1073741824L;
+
+ for (ii = 0; ii < ACCEL_NUM_AXES; ii++) {
+ data[ii] >>= 14;
+ fifo_obj.gravity_cache[ii] = data[ii];
+ }
+ } else {
+ data[0] = fifo_obj.gravity_cache[0];
+ data[1] = fifo_obj.gravity_cache[1];
+ data[2] = fifo_obj.gravity_cache[2];
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+* @brief Sets the filter coefficent used for computing the acceleration
+* bias which is used to compute linear acceleration.
+* @param[in] coef Fitler coefficient. 0. means no filter, a small number means
+* a small cutoff frequency with an increasing number meaning
+* an increasing cutoff frequency.
+*/
+inv_error_t inv_set_linear_accel_filter_coef(float coef)
+{
+ fifo_obj.acc_filter_coef = coef;
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 3-element vector of accelerometer data in body frame
+ * with gravity removed.
+ * @param[out] data 3-element vector of accelerometer data in body frame
+ * with gravity removed. One g = 2^16.
+ * @return 0 on success or an error code. data unchanged on error.
+ */
+inv_error_t inv_get_linear_accel(long *data)
+{
+ int kk;
+ long grav[3];
+ long la[3];
+ inv_error_t result;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ result = inv_get_gravity(grav);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_get_accel(la);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ if ((fifo_obj.cache & FIFO_CACHE_ACC_BIAS) == 0) {
+ fifo_obj.cache |= FIFO_CACHE_ACC_BIAS;
+
+ for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
+ long x;
+ x = la[kk] - grav[kk];
+ fifo_obj.acc_bias_filt[kk] = (long)(x * fifo_obj.acc_filter_coef +
+ fifo_obj.acc_bias_filt[kk] *
+ (1.f -
+ fifo_obj.acc_filter_coef));
+ data[kk] = x - fifo_obj.acc_bias_filt[kk];
+ }
+ } else {
+ for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
+ data[kk] = la[kk] - grav[kk] - fifo_obj.acc_bias_filt[kk];
+ }
+ }
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 3-element vector of accelerometer data in world frame
+ * with gravity removed.
+ * @param[out] data 3-element vector of accelerometer data in world frame
+ * with gravity removed. One g = 2^16.
+ * @return 0 on success or an error code.
+ */
+inv_error_t inv_get_linear_accel_in_world(long *data)
+{
+ int kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+ if (fifo_obj.data_config[CONFIG_ACCEL] && fifo_obj.data_config[CONFIG_QUAT]) {
+ long wtemp[4], qi[4], wtemp2[4];
+ wtemp[0] = 0;
+ inv_get_linear_accel(&wtemp[1]);
+ inv_q_mult(&fifo_obj.decoded[REF_QUATERNION], wtemp, wtemp2);
+ inv_q_invert(&fifo_obj.decoded[REF_QUATERNION], qi);
+ inv_q_mult(wtemp2, qi, wtemp);
+ for (kk = 0; kk < 3; ++kk) {
+ data[kk] = wtemp[kk + 1];
+ }
+ return INV_SUCCESS;
+ } else {
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+ }
+}
+
+/**
+ * @brief Returns 4-element vector of control data.
+ * @param[out] data 4-element vector of control data.
+ * @return 0 for succes or an error code.
+ */
+inv_error_t inv_get_cntrl_data(long *data)
+{
+ int kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_CONTROL_DATA])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < 4; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_CONTROL + kk];
+ }
+
+ return INV_SUCCESS;
+
+}
+
+/**
+ * @brief Returns 3-element vector of EIS shfit data
+ * @param[out] data 3-element vector of EIS shift data.
+ * @return 0 for succes or an error code.
+ */
+inv_error_t inv_get_eis(long *data)
+{
+ int kk;
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_EIS])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < 3; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_EIS + kk];
+ }
+
+ return INV_SUCCESS;
+
+}
+
+/**
+ * @brief Returns 3-element vector of accelerometer data in body frame.
+ * @param[out] data 3-element vector of accelerometer data in body frame in g's.
+ * @return 0 for success or an error code.
+ */
+inv_error_t inv_get_accel_float(float *data)
+{
+ long lData[3];
+ int kk;
+ int result;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ result = inv_get_accel(lData);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+
+ for (kk = 0; kk < ACCEL_NUM_AXES; ++kk) {
+ data[kk] = lData[kk] / 65536.0f;
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Returns 4-element quaternion vector.
+ * @param[out] data 4-element quaternion vector.
+ * @return 0 on success, an error code otherwise.
+ */
+inv_error_t inv_get_quaternion_float(float *data)
+{
+ int kk;
+
+ if (data == NULL)
+ return INV_ERROR_INVALID_PARAMETER;
+
+ if (!fifo_obj.data_config[CONFIG_QUAT])
+ return INV_ERROR_FEATURE_NOT_ENABLED;
+
+ for (kk = 0; kk < 4; ++kk) {
+ data[kk] = fifo_obj.decoded[REF_QUATERNION + kk] / 1073741824.0f;
+ }
+
+ return INV_SUCCESS;
+}
+
+/**
+ * @brief Command the MPU to put data in the FIFO at a particular rate.
+ *
+ * The DMP will add fifo entries every fifoRate + 1 MPU cycles. For
+ * example if the MPU is running at 200Hz the following values apply:
+ *
+ * <TABLE>
+ * <TR><TD>fifoRate</TD><TD>DMP Sample Rate</TD><TD>FIFO update frequency</TD></TR>
+ * <TR><TD>0</TD><TD>200Hz</TD><TD>200Hz</TD></TR>
+ * <TR><TD>1</TD><TD>200Hz</TD><TD>100Hz</TD></TR>
+ * <TR><TD>2</TD><TD>200Hz</TD><TD>50Hz</TD></TR>
+ * <TR><TD>4</TD><TD>200Hz</TD><TD>40Hz</TD></TR>
+ * <TR><TD>9</TD><TD>200Hz</TD><TD>20Hz</TD></TR>
+ * <TR><TD>19</TD><TD>200Hz</TD><TD>10Hz</TD></TR>
+ * </TABLE>
+ *
+ * Note: if the DMP is running, (state == INV_STATE_DMP_STARTED)
+ * then inv_run_state_callbacks() will be called to allow features
+ * that depend upon fundamental constants to be updated.
+ *
+ * @pre inv_dmp_open()
+ * @ifnot MPL_MF
+ * or inv_open_low_power_pedometer()
+ * or inv_eis_open_dmp()
+ * @endif
+ * and inv_dmp_start()
+ * must <b>NOT</b> have been called.
+ *
+ * @param fifoRate Divider value - 1. Output rate is
+ * (DMP Sample Rate) / (fifoRate + 1).
+ *
+ * @return INV_SUCCESS if successful, ML error code on any failure.
+ */
+inv_error_t inv_set_fifo_rate(unsigned short fifoRate)
+{
+ INVENSENSE_FUNC_START;
+ unsigned char regs[2];
+ unsigned char state;
+ inv_error_t result = INV_SUCCESS;
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+
+ state = inv_get_state();
+ if (state != INV_STATE_DMP_OPENED && state != INV_STATE_DMP_STARTED)
+ return INV_ERROR_SM_IMPROPER_STATE;
+
+ fifo_obj.fifo_rate = fifoRate;
+
+ if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR) {
+
+ regs[0] = (unsigned char)((fifoRate >> 8) & 0xff);
+ regs[1] = (unsigned char)(fifoRate & 0xff);
+
+ result = inv_set_mpu_memory(KEY_D_0_22, 2, regs);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ fifo_obj.sample_step_size_ms =
+ (unsigned short)(((long)fifoRate + 1) *
+ (inv_mpu_get_sampling_period_us
+ (mldl_cfg)) / 1000L);
+
+ if (state == INV_STATE_DMP_STARTED)
+ result = inv_run_state_callbacks(state);
+ } else if (mldl_cfg->requested_sensors & INV_THREE_AXIS_ACCEL) {
+ struct ext_slave_config config;
+ long data;
+ config.key = MPU_SLAVE_CONFIG_ODR_RESUME;
+ config.len = sizeof(long);
+ config.apply = (state == INV_STATE_DMP_STARTED);
+ config.data = &data;
+ data = (1000 * inv_mpu_get_sampling_rate_hz(mldl_cfg)) / (fifoRate + 1);
+
+ /* Ask for the same frequency */
+ result = inv_mpu_config_accel(mldl_cfg,
+ inv_get_serial_handle(),
+ inv_get_serial_handle(), &config);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ result = inv_mpu_get_accel_config(mldl_cfg,
+ inv_get_serial_handle(),
+ inv_get_serial_handle(), &config);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ if(FIFO_DEBUG)
+ MPL_LOGI("Actual ODR: %ld Hz\n", data / 1000);
+ /* Record the actual frequency granted odr is in mHz */
+ fifo_obj.sample_step_size_ms = (unsigned short)((1000L * 1000L) / data);
+ }
+ return result;
+}
+
+/**
+ * @brief Retrieve the current FIFO update divider - 1.
+ * See inv_set_fifo_rate() for how this value is used.
+ *
+ * The fifo rate when there is no fifo is the equivilent divider when
+ * derived from the value set by SetSampleSteSizeMs()
+ *
+ * @return The value of the fifo rate divider or INV_INVALID_FIFO_RATE on error.
+ */
+unsigned short inv_get_fifo_rate(void)
+{
+ return fifo_obj.fifo_rate;
+}
+
+/**
+ * @brief Returns the step size for quaternion type data.
+ *
+ * Typically the data rate for each FIFO packet. When the gryos are sleeping
+ * this value will return the last value set by SetSampleStepSizeMs()
+ *
+ * @return step size for quaternion type data
+ */
+int_fast16_t inv_get_sample_step_size_ms(void)
+{
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+
+ if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR)
+ return (fifo_obj.fifo_rate + 1) *
+ (inv_mpu_get_sampling_period_us(mldl_cfg) / 1000);
+ else
+ return fifo_obj.sample_step_size_ms;
+}
+
+/**
+ * @brief Returns the step size for quaternion type data.
+ *
+ * Typically the data rate for each FIFO packet. When the gryos are sleeping
+ * this value will return the last value set by SetSampleStepSizeMs()
+ *
+ * @return step size for quaternion type data
+ */
+int_fast16_t inv_get_sample_frequency(void)
+{
+ struct mldl_cfg *mldl_cfg = inv_get_dl_config();
+
+ if (mldl_cfg->requested_sensors & INV_DMP_PROCESSOR)
+ return (inv_mpu_get_sampling_rate_hz(mldl_cfg) /
+ (fifo_obj.fifo_rate + 1));
+ else
+ return (1000 / fifo_obj.sample_step_size_ms);
+}
+
+/**
+ * @brief The gyro data magnitude squared :
+ * (1 degree per second)^2 = 2^6 = 2^GYRO_MAG_SQR_SHIFT.
+ * @return the computed magnitude squared output of the gyroscope.
+ */
+unsigned long inv_get_gyro_sum_of_sqr(void)
+{
+ unsigned long gmag = 0;
+ long temp;
+ int kk;
+
+ for (kk = 0; kk < 3; ++kk) {
+ temp = fifo_obj.decoded[REF_GYROS + kk] >>
+ (16 - (GYRO_MAG_SQR_SHIFT / 2));
+ gmag += temp * temp;
+ }
+
+ return gmag;
+}
+
+/**
+ * @brief The gyro data magnitude squared:
+ * (1 g)^2 = 2^16 = 2^ACC_MAG_SQR_SHIFT.
+ * @return the computed magnitude squared output of the accelerometer.
+ */
+unsigned long inv_accel_sum_of_sqr(void)
+{
+ unsigned long amag = 0;
+ long temp;
+ int kk;
+ long accel[3];
+ inv_error_t result;
+
+ result = inv_get_accel(accel);
+ if (INV_SUCCESS != result) {
+ return 0;
+ }
+
+ for (kk = 0; kk < 3; ++kk) {
+ temp = accel[kk] >> (16 - (ACC_MAG_SQR_SHIFT / 2));
+ amag += temp * temp;
+ }
+ return amag;
+}
+
+/**
+ * @internal
+ */
+void inv_override_quaternion(float *q)
+{
+ int kk;
+ for (kk = 0; kk < 4; ++kk) {
+ fifo_obj.decoded[REF_QUATERNION + kk] = (long)(q[kk] * (1L << 30));
+ }
+}
+
+/**
+ * @internal
+ * @brief This registers a function to be called for each set of
+ * gyro/quaternion/rotation matrix/etc output.
+ * @param[in] func The callback function to register
+ * @param[in] priority The unique priority number of the callback. Lower numbers
+ * are called first.
+ * @return error code.
+ */
+inv_error_t inv_register_fifo_rate_process(inv_obj_func func, int priority)
+{
+ INVENSENSE_FUNC_START;
+ inv_error_t result;
+ int kk, nn;
+
+ result = inv_lock_mutex(fifo_rate_obj.mutex);
+ if (INV_SUCCESS != result) {
+ return result;
+ }
+ // Make sure we haven't registered this function already
+ // Or used the same priority
+ for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) {
+ if ((fifo_rate_obj.fifo_process_cb[kk] == func) ||
+ (fifo_rate_obj.priority[kk] == priority)) {
+ inv_unlock_mutex(fifo_rate_obj.mutex);
+ return INV_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ // Make sure we have not filled up our number of allowable callbacks
+ if (fifo_rate_obj.num_cb <= MAX_HIGH_RATE_PROCESSES - 1) {
+ kk = 0;
+ if (fifo_rate_obj.num_cb != 0) {
+ // set kk to be where this new callback goes in the array
+ while ((kk < fifo_rate_obj.num_cb) &&
+ (fifo_rate_obj.priority[kk] < priority)) {
+ kk++;
+ }
+ if (kk != fifo_rate_obj.num_cb) {
+ // We need to move the others
+ for (nn = fifo_rate_obj.num_cb; nn > kk; --nn) {
+ fifo_rate_obj.fifo_process_cb[nn] =
+ fifo_rate_obj.fifo_process_cb[nn - 1];
+ fifo_rate_obj.priority[nn] = fifo_rate_obj.priority[nn - 1];
+ }
+ }
+ }
+ // Add new callback
+ fifo_rate_obj.fifo_process_cb[kk] = func;
+ fifo_rate_obj.priority[kk] = priority;
+ fifo_rate_obj.num_cb++;
+ } else {
+ result = INV_ERROR_MEMORY_EXAUSTED;
+ }
+
+ inv_unlock_mutex(fifo_rate_obj.mutex);
+ return result;
+}
+
+/**
+ * @internal
+ * @brief This unregisters a function to be called for each set of
+ * gyro/quaternion/rotation matrix/etc output.
+ * @return error code.
+ */
+inv_error_t inv_unregister_fifo_rate_process(inv_obj_func func)
+{
+ INVENSENSE_FUNC_START;
+ int kk, jj;
+ inv_error_t result;
+
+ result = inv_lock_mutex(fifo_rate_obj.mutex);
+ if (INV_SUCCESS != result) {
+ return result;
+ }
+ // Make sure we haven't registered this function already
+ result = INV_ERROR_INVALID_PARAMETER;
+ for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) {
+ if (fifo_rate_obj.fifo_process_cb[kk] == func) {
+ for (jj = kk + 1; jj < fifo_rate_obj.num_cb; ++jj) {
+ fifo_rate_obj.fifo_process_cb[jj - 1] =
+ fifo_rate_obj.fifo_process_cb[jj];
+ fifo_rate_obj.priority[jj - 1] =
+ fifo_rate_obj.priority[jj];
+ }
+ fifo_rate_obj.fifo_process_cb[fifo_rate_obj.num_cb - 1] = NULL;
+ fifo_rate_obj.priority[fifo_rate_obj.num_cb - 1] = 0;
+ fifo_rate_obj.num_cb--;
+ result = INV_SUCCESS;
+ break;
+ }
+ }
+
+ inv_unlock_mutex(fifo_rate_obj.mutex);
+ return result;
+
+}
+#ifdef UMPL
+bool bFIFIDataAvailable = FALSE;
+bool isUmplDataInFIFO(void)
+{
+ return bFIFIDataAvailable;
+}
+void setUmplDataInFIFOFlag(bool flag)
+{
+ bFIFIDataAvailable = flag;
+}
+#endif
+inv_error_t inv_run_fifo_rate_processes(void)
+{
+ int kk;
+ inv_error_t result, result2;
+
+ result = inv_lock_mutex(fifo_rate_obj.mutex);
+ if (INV_SUCCESS != result) {
+ MPL_LOGE("MLOsLockMutex returned %d\n", result);
+ return result;
+ }
+ // User callbacks take priority over the fifo_process_cb callback
+ if (fifo_obj.fifo_process_cb)
+ fifo_obj.fifo_process_cb();
+
+ for (kk = 0; kk < fifo_rate_obj.num_cb; ++kk) {
+ if (fifo_rate_obj.fifo_process_cb[kk]) {
+ result2 = fifo_rate_obj.fifo_process_cb[kk] (&inv_obj);
+ if (result == INV_SUCCESS)
+#ifdef UMPL
+ setUmplDataInFIFOFlag(TRUE);
+#endif
+ result = result2;
+ }
+ }
+
+ inv_unlock_mutex(fifo_rate_obj.mutex);
+ return result;
+}
+
+/*********************/
+ /** \}*//* defgroup */
+/*********************/