/*
$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: ml_stored_data.c 5641 2011-06-14 02:10:02Z mcaramello $
*
*****************************************************************************/
/**
* @defgroup ML_STORED_DATA
*
* @{
* @file ml_stored_data.c
* @brief functions for reading and writing stored data sets.
* Typically, these functions process stored calibration data.
*/
#include "ml_stored_data.h"
#include "ml.h"
#include "mlFIFO.h"
#include "mltypes.h"
#include "mlinclude.h"
#include "compass.h"
#include "dmpKey.h"
#include "dmpDefault.h"
#include "mlstates.h"
#include "checksum.h"
#include "mlsupervisor.h"
#include "mlsl.h"
#include "mlos.h"
#include "log.h"
#undef MPL_LOG_TAG
#define MPL_LOG_TAG "MPL-storeload"
/*
Typedefs
*/
typedef inv_error_t(*tMLLoadFunc) (unsigned char *, unsigned short);
/*
Globals
*/
extern struct inv_obj_t inv_obj;
/*
Debugging Definitions
set LOADCAL_DEBUG and/or STORECAL_DEBUG to 1 print the fields
being read or stored in human-readable format.
When set to 0, the compiler will optimize and remove the printouts
from the code.
*/
#define LOADCAL_DEBUG 0
#define STORECAL_DEBUG 0
#define LOADCAL_LOG(...) \
if(LOADCAL_DEBUG) \
MPL_LOGI("LOADCAL: " __VA_ARGS__)
#define STORECAL_LOG(...) \
if(STORECAL_DEBUG) \
MPL_LOGI("STORECAL: " __VA_ARGS__)
/**
* @brief Duplicate of the inv_temp_comp_find_bin function in the libmpl
* advanced algorithms library. To remove cross-dependency, for now,
* we reimplement the same function here.
* @param temp
* the temperature (1 count == 1 degree C).
*/
int FindTempBin(float temp)
{
int bin = (int)((temp - MIN_TEMP) / TEMP_PER_BIN);
if (bin < 0)
bin = 0;
if (bin > BINS - 1)
bin = BINS - 1;
return bin;
}
/**
* @brief Returns the length of the <b>MPL internal calibration data</b>.
* Should be called before allocating the memory required to store
* this data to a file.
* This function returns the total size required to store the cal
* data including the header (4 bytes) and the checksum (2 bytes).
*
* @pre Must be in INV_STATE_DMP_OPENED state.
* inv_dmp_open() or inv_dmp_stop() must have been called.
* inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
* been called.
*
* @return the length of the internal calibrated data format.
*/
unsigned int inv_get_cal_length(void)
{
INVENSENSE_FUNC_START;
unsigned int length;
length = INV_CAL_HDR_LEN + // header
BINS * PTS_PER_BIN * 4 * 4 + BINS * 4 * 2 + // gyro cal
INV_CAL_ACCEL_LEN + // accel cal
INV_CAL_COMPASS_LEN + // compass cal
INV_CAL_CHK_LEN; // checksum
return length;
}
/**
* @brief Loads a type 0 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature,
* - gyro biases for X, Y, Z axes.
* This calibration data would normally be produced by the MPU Self
* Test and its size is 18 bytes (header and checksum included).
* Calibration format type 0 is currently <b>NOT</b> used and
* is substituted by type 5 : inv_load_cal_V5().
*
* @note This calibration data format is obsoleted and no longer supported
* by the rest of the MPL
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V0(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
const short expLen = 18;
long newGyroData[3] = { 0, 0, 0 };
float newTemp;
int bin;
LOADCAL_LOG("Entering inv_load_cal_V0\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 1 must be %d bytes long\n", expLen);
return INV_ERROR_FILE_READ;
}
newTemp = (float)inv_decode_temperature(
(unsigned short)calData[6] * 256 + calData[7]) / 65536.f;
LOADCAL_LOG("newTemp = %f\n", newTemp);
newGyroData[0] = ((long)calData[8]) * 256 + ((long)calData[9]);
if (newGyroData[0] > 32767L)
newGyroData[0] -= 65536L;
LOADCAL_LOG("newGyroData[0] = %ld\n", newGyroData[0]);
newGyroData[1] = ((long)calData[10]) * 256 + ((long)calData[11]);
if (newGyroData[1] > 32767L)
newGyroData[1] -= 65536L;
LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
newGyroData[2] = ((long)calData[12]) * 256 + ((long)calData[13]);
if (newGyroData[2] > 32767L)
newGyroData[2] -= 65536L;
LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
bin = FindTempBin(newTemp);
LOADCAL_LOG("bin = %d", bin);
inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
LOADCAL_LOG("temp_data[%d][%d] = %f",
bin, inv_obj.temp_ptrs[bin],
inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
((float)newGyroData[0]) / 65536.f;
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
((float)newGyroData[0]) / 65536.f;
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
((float)newGyroData[0]) / 65536.f;
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
if (inv_obj.temp_ptrs[bin] == 0)
inv_obj.temp_valid_data[bin] = TRUE;
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
bin, inv_obj.temp_valid_data[bin]);
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V0\n");
return INV_SUCCESS;
}
/**
* @brief Loads a type 1 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature,
* - gyro biases for X, Y, Z axes,
* - accel biases for X, Y, Z axes.
* This calibration data would normally be produced by the MPU Self
* Test and its size is 24 bytes (header and checksum included).
* Calibration format type 1 is currently <b>NOT</b> used and
* is substituted by type 5 : inv_load_cal_V5().
*
* @note In order to successfully work, the gyro bias must be stored
* expressed in 250 dps full scale (131.072 sensitivity). Other full
* scale range will produce unpredictable results in the gyro biases.
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V1(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
const short expLen = 24;
long newGyroData[3] = {0, 0, 0};
long accelBias[3] = {0, 0, 0};
float gyroBias[3] = {0, 0, 0};
float newTemp = 0;
int bin;
LOADCAL_LOG("Entering inv_load_cal_V1\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 1 must be %d bytes long\n", expLen);
return INV_ERROR_FILE_READ;
}
newTemp = (float)inv_decode_temperature(
(unsigned short)calData[6] * 256 + calData[7]) / 65536.f;
LOADCAL_LOG("newTemp = %f\n", newTemp);
newGyroData[0] = ((long)calData[8]) * 256 + ((long)calData[9]);
if (newGyroData[0] > 32767L)
newGyroData[0] -= 65536L;
LOADCAL_LOG("newGyroData[0] = %ld\n", newGyroData[0]);
newGyroData[1] = ((long)calData[10]) * 256 + ((long)calData[11]);
if (newGyroData[1] > 32767L)
newGyroData[1] -= 65536L;
LOADCAL_LOG("newGyroData[1] = %ld\n", newGyroData[1]);
newGyroData[2] = ((long)calData[12]) * 256 + ((long)calData[13]);
if (newGyroData[2] > 32767L)
newGyroData[2] -= 65536L;
LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
bin = FindTempBin(newTemp);
LOADCAL_LOG("bin = %d\n", bin);
gyroBias[0] = ((float)newGyroData[0]) / 131.072f;
gyroBias[1] = ((float)newGyroData[1]) / 131.072f;
gyroBias[2] = ((float)newGyroData[2]) / 131.072f;
LOADCAL_LOG("gyroBias[0] = %f\n", gyroBias[0]);
LOADCAL_LOG("gyroBias[1] = %f\n", gyroBias[1]);
LOADCAL_LOG("gyroBias[2] = %f\n", gyroBias[2]);
inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
LOADCAL_LOG("temp_data[%d][%d] = %f",
bin, inv_obj.temp_ptrs[bin],
inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[0];
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[1];
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[2];
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin],
inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
if (inv_obj.temp_ptrs[bin] == 0)
inv_obj.temp_valid_data[bin] = TRUE;
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
bin, inv_obj.temp_valid_data[bin]);
/* load accel biases and apply immediately */
accelBias[0] = ((long)calData[14]) * 256 + ((long)calData[15]);
if (accelBias[0] > 32767)
accelBias[0] -= 65536L;
accelBias[0] = (long)((long long)accelBias[0] * 65536L *
inv_obj.accel_sens / 1073741824L);
LOADCAL_LOG("accelBias[0] = %ld\n", accelBias[0]);
accelBias[1] = ((long)calData[16]) * 256 + ((long)calData[17]);
if (accelBias[1] > 32767)
accelBias[1] -= 65536L;
accelBias[1] = (long)((long long)accelBias[1] * 65536L *
inv_obj.accel_sens / 1073741824L);
LOADCAL_LOG("accelBias[1] = %ld\n", accelBias[1]);
accelBias[2] = ((long)calData[18]) * 256 + ((int)calData[19]);
if (accelBias[2] > 32767)
accelBias[2] -= 65536L;
accelBias[2] = (long)((long long)accelBias[2] * 65536L *
inv_obj.accel_sens / 1073741824L);
LOADCAL_LOG("accelBias[2] = %ld\n", accelBias[2]);
if (inv_set_array(INV_ACCEL_BIAS, accelBias)) {
LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accelBias));
return inv_set_array(INV_ACCEL_BIAS, accelBias);
}
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V1\n");
return INV_SUCCESS;
}
/**
* @brief Loads a type 2 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature compensation : temperature data points,
* - temperature compensation : gyro biases data points for X, Y,
* and Z axes.
* - accel biases for X, Y, Z axes.
* This calibration data is produced internally by the MPL and its
* size is 2222 bytes (header and checksum included).
* Calibration format type 2 is currently <b>NOT</b> used and
* is substituted by type 4 : inv_load_cal_V4().
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V2(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
const short expLen = 2222;
long accel_bias[3];
int ptr = INV_CAL_HDR_LEN;
int i, j;
long long tmp;
LOADCAL_LOG("Entering inv_load_cal_V2\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 2 must be %d bytes long (got %d)\n",
expLen, len);
return INV_ERROR_FILE_READ;
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_ptrs[i] = 0;
inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_ptrs[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_valid_data[i] = 0;
inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_valid_data[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
i, inv_obj.temp_valid_data[i]);
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("temp_data[%d][%d] = %f\n",
i, j, inv_obj.temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.x_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.y_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.z_gyro_temp_data[i][j]);
}
}
/* read the accel biases */
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
accel_bias[i] = (int32_t) t;
LOADCAL_LOG("accel_bias[%d] = %ld\n", i, accel_bias[i]);
}
if (inv_set_array(INV_ACCEL_BIAS, accel_bias)) {
LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accel_bias));
return inv_set_array(INV_ACCEL_BIAS, accel_bias);
}
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V2\n");
return INV_SUCCESS;
}
/**
* @brief Loads a type 3 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature compensation : temperature data points,
* - temperature compensation : gyro biases data points for X, Y,
* and Z axes.
* - accel biases for X, Y, Z axes.
* - compass biases for X, Y, Z axes and bias tracking algorithm
* mock-up.
* This calibration data is produced internally by the MPL and its
* size is 2429 bytes (header and checksum included).
* Calibration format type 3 is currently <b>NOT</b> used and
* is substituted by type 4 : inv_load_cal_V4().
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V3(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
union doubleToLongLong {
double db;
unsigned long long ll;
} dToLL;
const short expLen = 2429;
long bias[3];
int i, j;
int ptr = INV_CAL_HDR_LEN;
long long tmp;
LOADCAL_LOG("Entering inv_load_cal_V3\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 3 must be %d bytes long (got %d)\n",
expLen, len);
return INV_ERROR_FILE_READ;
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_ptrs[i] = 0;
inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_ptrs[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_valid_data[i] = 0;
inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_valid_data[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
i, inv_obj.temp_valid_data[i]);
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("temp_data[%d][%d] = %f\n",
i, j, inv_obj.temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.x_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.y_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.z_gyro_temp_data[i][j]);
}
}
/* read the accel biases */
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
bias[i] = (int32_t) t;
LOADCAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
}
if (inv_set_array(INV_ACCEL_BIAS, bias)) {
LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, bias));
return inv_set_array(INV_ACCEL_BIAS, bias);
}
/* read the compass biases */
inv_obj.got_compass_bias = (int)calData[ptr++];
inv_obj.got_init_compass_bias = (int)calData[ptr++];
inv_obj.compass_state = (int)calData[ptr++];
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_bias_error[i] = (int32_t) t;
LOADCAL_LOG("compass_bias_error[%d] = %ld\n", i,
inv_obj.compass_bias_error[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.init_compass_bias[i] = (int32_t) t;
LOADCAL_LOG("init_compass_bias[%d] = %ld\n", i,
inv_obj.init_compass_bias[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_bias[i] = (int32_t) t;
LOADCAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
}
for (i = 0; i < 18; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_peaks[i] = (int32_t) t;
LOADCAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
}
for (i = 0; i < 3; i++) {
dToLL.ll = 0;
dToLL.ll += 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_bias_v[i] = dToLL.db;
LOADCAL_LOG("compass_bias_v[%d] = %lf\n", i, inv_obj.compass_bias_v[i]);
}
for (i = 0; i < 9; i++) {
dToLL.ll = 0;
dToLL.ll += 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_bias_ptr[i] = dToLL.db;
LOADCAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
inv_obj.compass_bias_ptr[i]);
}
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V3\n");
return INV_SUCCESS;
}
/**
* @brief Loads a type 4 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature compensation : temperature data points,
* - temperature compensation : gyro biases data points for X, Y,
* and Z axes.
* - accel biases for X, Y, Z axes.
* - compass biases for X, Y, Z axes, compass scale, and bias
* tracking algorithm mock-up.
* This calibration data is produced internally by the MPL and its
* size is 2777 bytes (header and checksum included).
* Calibration format type 4 is currently used and
* substitutes type 2 (inv_load_cal_V2()) and 3 (inv_load_cal_V3()).
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V4(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
union doubleToLongLong {
double db;
unsigned long long ll;
} dToLL;
const unsigned int expLen = 2782;
long bias[3];
int ptr = INV_CAL_HDR_LEN;
int i, j;
long long tmp;
inv_error_t result;
LOADCAL_LOG("Entering inv_load_cal_V4\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 4 must be %d bytes long (got %d)\n",
expLen, len);
return INV_ERROR_FILE_READ;
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_ptrs[i] = 0;
inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_ptrs[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
}
for (i = 0; i < BINS; i++) {
inv_obj.temp_valid_data[i] = 0;
inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
inv_obj.temp_valid_data[i] += (int)calData[ptr++];
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
i, inv_obj.temp_valid_data[i]);
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("temp_data[%d][%d] = %f\n",
i, j, inv_obj.temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.x_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.y_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = 0;
tmp += 16777216LL * (long long)calData[ptr++];
tmp += 65536LL * (long long)calData[ptr++];
tmp += 256LL * (long long)calData[ptr++];
tmp += (long long)calData[ptr++];
if (tmp > 2147483648LL) {
tmp -= 4294967296LL;
}
inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.z_gyro_temp_data[i][j]);
}
}
/* read the accel biases */
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
bias[i] = (int32_t) t;
LOADCAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
}
if (inv_set_array(INV_ACCEL_BIAS, bias)) {
LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, bias));
return inv_set_array(INV_ACCEL_BIAS, bias);
}
/* read the compass biases */
inv_reset_compass_calibration();
inv_obj.got_compass_bias = (int)calData[ptr++];
LOADCAL_LOG("got_compass_bias = %ld\n", inv_obj.got_compass_bias);
inv_obj.got_init_compass_bias = (int)calData[ptr++];
LOADCAL_LOG("got_init_compass_bias = %d\n", inv_obj.got_init_compass_bias);
inv_obj.compass_state = (int)calData[ptr++];
LOADCAL_LOG("compass_state = %ld\n", inv_obj.compass_state);
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_bias_error[i] = (int32_t) t;
LOADCAL_LOG("compass_bias_error[%d] = %ld\n", i,
inv_obj.compass_bias_error[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.init_compass_bias[i] = (int32_t) t;
LOADCAL_LOG("init_compass_bias[%d] = %ld\n", i,
inv_obj.init_compass_bias[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_bias[i] = (int32_t) t;
LOADCAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
}
for (i = 0; i < 18; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_peaks[i] = (int32_t) t;
LOADCAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
}
for (i = 0; i < 3; i++) {
dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_bias_v[i] = dToLL.db;
LOADCAL_LOG("compass_bias_v[%d] = %lf\n", i, inv_obj.compass_bias_v[i]);
}
for (i = 0; i < 9; i++) {
dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_bias_ptr[i] = dToLL.db;
LOADCAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
inv_obj.compass_bias_ptr[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = 0;
t += 16777216UL * ((uint32_t) calData[ptr++]);
t += 65536UL * ((uint32_t) calData[ptr++]);
t += 256u * ((uint32_t) calData[ptr++]);
t += (uint32_t) calData[ptr++];
inv_obj.compass_scale[i] = (int32_t) t;
LOADCAL_LOG("compass_scale[%d] = %d\n", i, (int32_t) t);
}
for (i = 0; i < 6; i++) {
dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_prev_xty[i] = dToLL.db;
LOADCAL_LOG("compass_prev_xty[%d] = %f\n", i, dToLL.db);
}
for (i = 0; i < 36; i++) {
dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
dToLL.ll += (unsigned long long)calData[ptr++];
inv_obj.compass_prev_m[i] = dToLL.db;
LOADCAL_LOG("compass_prev_m[%d] = %f\n", i, dToLL.db);
}
/* Load the compass offset flag and values */
inv_obj.flags[INV_COMPASS_OFFSET_VALID] = calData[ptr++];
inv_obj.compass_offsets[0] = calData[ptr++];
inv_obj.compass_offsets[1] = calData[ptr++];
inv_obj.compass_offsets[2] = calData[ptr++];
inv_obj.compass_accuracy = calData[ptr++];
/* push the compass offset values to the device */
result = inv_set_compass_offset();
if (result == INV_SUCCESS) {
if (inv_compass_check_range() != INV_SUCCESS) {
MPL_LOGI("range check fail");
inv_reset_compass_calibration();
inv_obj.flags[INV_COMPASS_OFFSET_VALID] = 0;
inv_set_compass_offset();
}
}
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V4\n");
return INV_SUCCESS;
}
/**
* @brief Loads a type 5 set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
* This calibrations data format stores values for (in order of
* appearance) :
* - temperature,
* - gyro biases for X, Y, Z axes,
* - accel biases for X, Y, Z axes.
* This calibration data would normally be produced by the MPU Self
* Test and its size is 36 bytes (header and checksum included).
* Calibration format type 5 is produced by the MPU Self Test and
* substitutes the type 1 : inv_load_cal_V1().
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
* @param len
* the length of the calibration
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal_V5(unsigned char *calData, unsigned short len)
{
INVENSENSE_FUNC_START;
const short expLen = 36;
long accelBias[3] = { 0, 0, 0 };
float gyroBias[3] = { 0, 0, 0 };
int ptr = INV_CAL_HDR_LEN;
unsigned short temp;
float newTemp;
int bin;
int i;
LOADCAL_LOG("Entering inv_load_cal_V5\n");
if (len != expLen) {
MPL_LOGE("Calibration data type 5 must be %d bytes long (got %d)\n",
expLen, len);
return INV_ERROR_FILE_READ;
}
/* load the temperature */
temp = (unsigned short)calData[ptr++] * (1L << 8);
temp += calData[ptr++];
newTemp = (float)inv_decode_temperature(temp) / 65536.f;
LOADCAL_LOG("newTemp = %f\n", newTemp);
/* load the gyro biases (represented in 2 ^ 16 == 1 dps) */
for (i = 0; i < 3; i++) {
int32_t tmp = 0;
tmp += (int32_t) calData[ptr++] * (1L << 24);
tmp += (int32_t) calData[ptr++] * (1L << 16);
tmp += (int32_t) calData[ptr++] * (1L << 8);
tmp += (int32_t) calData[ptr++];
gyroBias[i] = (float)tmp / 65536.0f;
LOADCAL_LOG("gyroBias[%d] = %f\n", i, gyroBias[i]);
}
/* find the temperature bin */
bin = FindTempBin(newTemp);
/* populate the temp comp data structure */
inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
LOADCAL_LOG("temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin], newTemp);
inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[0];
LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin], gyroBias[0]);
inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[1];
LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin], gyroBias[1]);
inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[2];
LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
bin, inv_obj.temp_ptrs[bin], gyroBias[2]);
inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
if (inv_obj.temp_ptrs[bin] == 0)
inv_obj.temp_valid_data[bin] = TRUE;
LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
bin, inv_obj.temp_valid_data[bin]);
/* load accel biases (represented in 2 ^ 16 == 1 gee)
and apply immediately */
for (i = 0; i < 3; i++) {
int32_t tmp = 0;
tmp += (int32_t) calData[ptr++] * (1L << 24);
tmp += (int32_t) calData[ptr++] * (1L << 16);
tmp += (int32_t) calData[ptr++] * (1L << 8);
tmp += (int32_t) calData[ptr++];
accelBias[i] = (long)tmp;
LOADCAL_LOG("accelBias[%d] = %ld\n", i, accelBias[i]);
}
if (inv_set_array(INV_ACCEL_BIAS, accelBias)) {
LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accelBias));
return inv_set_array(INV_ACCEL_BIAS, accelBias);
}
inv_obj.got_no_motion_bias = TRUE;
LOADCAL_LOG("got_no_motion_bias = 1\n");
inv_obj.cal_loaded_flag = TRUE;
LOADCAL_LOG("cal_loaded_flag = 1\n");
LOADCAL_LOG("Exiting inv_load_cal_V5\n");
return INV_SUCCESS;
}
/**
* @brief Loads a set of calibration data.
* It parses a binary data set containing calibration data.
* The binary data set is intended to be loaded from a file.
*
* @pre inv_dmp_open()
* @ifnot MPL_MF
* or inv_open_low_power_pedometer()
* or inv_eis_open_dmp()
* @endif
* must have been called.
*
* @param calData
* A pointer to an array of bytes to be parsed.
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_load_cal(unsigned char *calData)
{
INVENSENSE_FUNC_START;
int calType = 0;
int len = 0;
int ptr;
uint32_t chk = 0;
uint32_t cmp_chk = 0;
tMLLoadFunc loaders[] = {
inv_load_cal_V0,
inv_load_cal_V1,
inv_load_cal_V2,
inv_load_cal_V3,
inv_load_cal_V4,
inv_load_cal_V5
};
if (inv_get_state() < INV_STATE_DMP_OPENED)
return INV_ERROR_SM_IMPROPER_STATE;
/* read the header (type and len)
len is the total record length including header and checksum */
len = 0;
len += 16777216L * ((int)calData[0]);
len += 65536L * ((int)calData[1]);
len += 256 * ((int)calData[2]);
len += (int)calData[3];
calType = ((int)calData[4]) * 256 + ((int)calData[5]);
if (calType > 5) {
MPL_LOGE("Unsupported calibration file format %d. "
"Valid types 0..5\n", calType);
return INV_ERROR_INVALID_PARAMETER;
}
/* check the checksum */
chk = 0;
ptr = len - INV_CAL_CHK_LEN;
chk += 16777216L * ((uint32_t) calData[ptr++]);
chk += 65536L * ((uint32_t) calData[ptr++]);
chk += 256 * ((uint32_t) calData[ptr++]);
chk += (uint32_t) calData[ptr++];
cmp_chk = inv_checksum(calData + INV_CAL_HDR_LEN,
len - (INV_CAL_HDR_LEN + INV_CAL_CHK_LEN));
if (chk != cmp_chk) {
return INV_ERROR_CALIBRATION_CHECKSUM;
}
/* call the proper method to read in the data */
return loaders[calType] (calData, len);
}
/**
* @brief Stores a set of calibration data.
* It generates a binary data set containing calibration data.
* The binary data set is intended to be stored into a file.
*
* @pre inv_dmp_open()
*
* @param calData
* A pointer to an array of bytes to be stored.
* @param length
* The amount of bytes available in the array.
*
* @return INV_SUCCESS if successful, a non-zero error code otherwise.
*/
inv_error_t inv_store_cal(unsigned char *calData, int length)
{
INVENSENSE_FUNC_START;
int ptr = 0;
int i = 0;
int j = 0;
long long tmp;
uint32_t chk;
long bias[3];
//unsigned char state;
union doubleToLongLong {
double db;
unsigned long long ll;
} dToLL;
if (inv_get_state() < INV_STATE_DMP_OPENED)
return INV_ERROR_SM_IMPROPER_STATE;
STORECAL_LOG("Entering inv_store_cal\n");
// length
calData[0] = (unsigned char)((length >> 24) & 0xff);
calData[1] = (unsigned char)((length >> 16) & 0xff);
calData[2] = (unsigned char)((length >> 8) & 0xff);
calData[3] = (unsigned char)(length & 0xff);
STORECAL_LOG("calLen = %d\n", length);
// calibration data format type
calData[4] = 0;
calData[5] = 4;
STORECAL_LOG("calType = %d\n", (int)calData[4] * 256 + calData[5]);
// data
ptr = 6;
for (i = 0; i < BINS; i++) {
tmp = (int)inv_obj.temp_ptrs[i];
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("temp_ptrs[%d] = %lld\n", i, tmp);
}
for (i = 0; i < BINS; i++) {
tmp = (int)inv_obj.temp_valid_data[i];
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("temp_valid_data[%d] = %lld\n", i, tmp);
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = (long long)(inv_obj.temp_data[i][j] * 65536.0f);
if (tmp < 0) {
tmp += 4294967296LL;
}
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("temp_data[%d][%d] = %f\n",
i, j, inv_obj.temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = (long long)(inv_obj.x_gyro_temp_data[i][j] * 65536.0f);
if (tmp < 0) {
tmp += 4294967296LL;
}
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.x_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = (long long)(inv_obj.y_gyro_temp_data[i][j] * 65536.0f);
if (tmp < 0) {
tmp += 4294967296LL;
}
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.y_gyro_temp_data[i][j]);
}
}
for (i = 0; i < BINS; i++) {
for (j = 0; j < PTS_PER_BIN; j++) {
tmp = (long long)(inv_obj.z_gyro_temp_data[i][j] * 65536.0f);
if (tmp < 0) {
tmp += 4294967296LL;
}
calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
calData[ptr++] = (unsigned char)(tmp & 0xff);
STORECAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
i, j, inv_obj.z_gyro_temp_data[i][j]);
}
}
inv_get_array(INV_ACCEL_BIAS, bias);
/* write the accel biases */
for (i = 0; i < 3; i++) {
uint32_t t = (uint32_t) bias[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
}
/* write the compass calibration state */
calData[ptr++] = (unsigned char)(inv_obj.got_compass_bias);
STORECAL_LOG("got_compass_bias = %ld\n", inv_obj.got_compass_bias);
calData[ptr++] = (unsigned char)(inv_obj.got_init_compass_bias);
STORECAL_LOG("got_init_compass_bias = %d\n", inv_obj.got_init_compass_bias);
if (inv_obj.compass_state == SF_UNCALIBRATED) {
calData[ptr++] = SF_UNCALIBRATED;
} else {
calData[ptr++] = SF_STARTUP_SETTLE;
}
STORECAL_LOG("compass_state = %ld\n", inv_obj.compass_state);
for (i = 0; i < 3; i++) {
uint32_t t = (uint32_t) inv_obj.compass_bias_error[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("compass_bias_error[%d] = %ld\n",
i, inv_obj.compass_bias_error[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = (uint32_t) inv_obj.init_compass_bias[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("init_compass_bias[%d] = %ld\n", i,
inv_obj.init_compass_bias[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = (uint32_t) inv_obj.compass_bias[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
}
for (i = 0; i < 18; i++) {
uint32_t t = (uint32_t) inv_obj.compass_peaks[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
}
for (i = 0; i < 3; i++) {
dToLL.db = inv_obj.compass_bias_v[i];
calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
STORECAL_LOG("compass_bias_v[%d] = %lf\n", i,
inv_obj.compass_bias_v[i]);
}
for (i = 0; i < 9; i++) {
dToLL.db = inv_obj.compass_bias_ptr[i];
calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
STORECAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
inv_obj.compass_bias_ptr[i]);
}
for (i = 0; i < 3; i++) {
uint32_t t = (uint32_t) inv_obj.compass_scale[i];
calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
calData[ptr++] = (unsigned char)(t & 0xff);
STORECAL_LOG("compass_scale[%d] = %ld\n", i, inv_obj.compass_scale[i]);
}
for (i = 0; i < 6; i++) {
dToLL.db = inv_obj.compass_prev_xty[i];
calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
STORECAL_LOG("compass_prev_xty[%d] = %lf\n", i,
inv_obj.compass_prev_xty[i]);
}
for (i = 0; i < 36; i++) {
dToLL.db = inv_obj.compass_prev_m[i];
calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
STORECAL_LOG("compass_prev_m[%d] = %lf\n", i,
inv_obj.compass_prev_m[i]);
}
/* store the compass offsets and validity flag */
calData[ptr++] = (unsigned char)inv_obj.flags[INV_COMPASS_OFFSET_VALID];
calData[ptr++] = (unsigned char)inv_obj.compass_offsets[0];
calData[ptr++] = (unsigned char)inv_obj.compass_offsets[1];
calData[ptr++] = (unsigned char)inv_obj.compass_offsets[2];
/* store the compass accuracy */
calData[ptr++] = (unsigned char)(inv_obj.compass_accuracy);
/* add a checksum */
chk = inv_checksum(calData + INV_CAL_HDR_LEN,
length - (INV_CAL_HDR_LEN + INV_CAL_CHK_LEN));
calData[ptr++] = (unsigned char)((chk >> 24) & 0xff);
calData[ptr++] = (unsigned char)((chk >> 16) & 0xff);
calData[ptr++] = (unsigned char)((chk >> 8) & 0xff);
calData[ptr++] = (unsigned char)(chk & 0xff);
STORECAL_LOG("Exiting inv_store_cal\n");
return INV_SUCCESS;
}
/**
* @brief Load a calibration file.
*
* @pre Must be in INV_STATE_DMP_OPENED state.
* inv_dmp_open() or inv_dmp_stop() must have been called.
* inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
* been called.
*
* @return 0 or error code.
*/
inv_error_t inv_load_calibration(void)
{
unsigned char *calData;
inv_error_t result;
unsigned int length;
if (inv_get_state() < INV_STATE_DMP_OPENED)
return INV_ERROR_SM_IMPROPER_STATE;
result = inv_serial_get_cal_length(&length);
if (result == INV_ERROR_FILE_OPEN) {
MPL_LOGI("Calibration data not loaded\n");
return INV_SUCCESS;
}
if (result || length <= 0) {
MPL_LOGE("Could not get file calibration length - "
"error %d - aborting\n", result);
return result;
}
calData = (unsigned char *)inv_malloc(length);
if (!calData) {
MPL_LOGE("Could not allocate buffer of %d bytes - "
"aborting\n", length);
return INV_ERROR_MEMORY_EXAUSTED;
}
result = inv_serial_read_cal(calData, length);
if (result) {
MPL_LOGE("Could not read the calibration data from file - "
"error %d - aborting\n", result);
goto free_mem_n_exit;
}
result = inv_load_cal(calData);
if (result) {
MPL_LOGE("Could not load the calibration data - "
"error %d - aborting\n", result);
goto free_mem_n_exit;
}
free_mem_n_exit:
inv_free(calData);
return INV_SUCCESS;
}
/**
* @brief Store runtime calibration data to a file
*
* @pre Must be in INV_STATE_DMP_OPENED state.
* inv_dmp_open() or inv_dmp_stop() must have been called.
* inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
* been called.
*
* @return 0 or error code.
*/
inv_error_t inv_store_calibration(void)
{
unsigned char *calData;
inv_error_t result;
unsigned int length;
if (inv_get_state() < INV_STATE_DMP_OPENED)
return INV_ERROR_SM_IMPROPER_STATE;
length = inv_get_cal_length();
calData = (unsigned char *)inv_malloc(length);
if (!calData) {
MPL_LOGE("Could not allocate buffer of %d bytes - "
"aborting\n", length);
return INV_ERROR_MEMORY_EXAUSTED;
}
result = inv_store_cal(calData, length);
if (result) {
MPL_LOGE("Could not store calibrated data on file - "
"error %d - aborting\n", result);
goto free_mem_n_exit;
}
result = inv_serial_write_cal(calData, length);
if (result) {
MPL_LOGE("Could not write calibration data - " "error %d\n", result);
goto free_mem_n_exit;
}
free_mem_n_exit:
inv_free(calData);
return INV_SUCCESS;
}
/**
* @}
*/