1/*
2 $License:
3   Copyright 2011 InvenSense, Inc.
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16  $
17 */
18
19/******************************************************************************
20 *
21 * $Id: ml_stored_data.c 5641 2011-06-14 02:10:02Z mcaramello $
22 *
23 *****************************************************************************/
24
25/**
26 * @defgroup ML_STORED_DATA
27 *
28 * @{
29 *      @file     ml_stored_data.c
30 *      @brief    functions for reading and writing stored data sets.
31 *                Typically, these functions process stored calibration data.
32 */
33
34#include "ml_stored_data.h"
35#include "ml.h"
36#include "mlFIFO.h"
37#include "mltypes.h"
38#include "mlinclude.h"
39#include "compass.h"
40#include "dmpKey.h"
41#include "dmpDefault.h"
42#include "mlstates.h"
43#include "checksum.h"
44#include "mlsupervisor.h"
45
46#include "mlsl.h"
47#include "mlos.h"
48
49#include "log.h"
50#undef MPL_LOG_TAG
51#define MPL_LOG_TAG "MPL-storeload"
52
53/*
54    Typedefs
55*/
56typedef inv_error_t(*tMLLoadFunc) (unsigned char *, unsigned short);
57
58/*
59    Globals
60*/
61extern struct inv_obj_t inv_obj;
62
63/*
64    Debugging Definitions
65    set LOADCAL_DEBUG and/or STORECAL_DEBUG to 1 print the fields
66    being read or stored in human-readable format.
67    When set to 0, the compiler will optimize and remove the printouts
68    from the code.
69*/
70#define LOADCAL_DEBUG    0
71#define STORECAL_DEBUG   0
72
73#define LOADCAL_LOG(...)                        \
74    if(LOADCAL_DEBUG)                           \
75        MPL_LOGI("LOADCAL: " __VA_ARGS__)
76#define STORECAL_LOG(...)                       \
77    if(STORECAL_DEBUG)                          \
78        MPL_LOGI("STORECAL: " __VA_ARGS__)
79
80/**
81 *  @brief  Duplicate of the inv_temp_comp_find_bin function in the libmpl
82 *          advanced algorithms library. To remove cross-dependency, for now,
83 *          we reimplement the same function here.
84 *  @param  temp
85 *              the temperature (1 count == 1 degree C).
86 */
87int FindTempBin(float temp)
88{
89    int bin = (int)((temp - MIN_TEMP) / TEMP_PER_BIN);
90    if (bin < 0)
91        bin = 0;
92    if (bin > BINS - 1)
93        bin = BINS - 1;
94    return bin;
95}
96
97/**
98 * @brief   Returns the length of the <b>MPL internal calibration data</b>.
99 *          Should be called before allocating the memory required to store
100 *          this data to a file.
101 *          This function returns the total size required to store the cal
102 *          data including the header (4 bytes) and the checksum (2 bytes).
103 *
104 *  @pre    Must be in INV_STATE_DMP_OPENED state.
105 *          inv_dmp_open() or inv_dmp_stop() must have been called.
106 *          inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
107 *          been called.
108 *
109 * @return  the length of the internal calibrated data format.
110 */
111unsigned int inv_get_cal_length(void)
112{
113    INVENSENSE_FUNC_START;
114    unsigned int length;
115    length = INV_CAL_HDR_LEN +  // header
116        BINS * PTS_PER_BIN * 4 * 4 + BINS * 4 * 2 + // gyro cal
117        INV_CAL_ACCEL_LEN +     // accel cal
118        INV_CAL_COMPASS_LEN +   // compass cal
119        INV_CAL_CHK_LEN;        // checksum
120    return length;
121}
122
123/**
124 *  @brief  Loads a type 0 set of calibration data.
125 *          It parses a binary data set containing calibration data.
126 *          The binary data set is intended to be loaded from a file.
127 *          This calibrations data format stores values for (in order of
128 *          appearance) :
129 *          - temperature,
130 *          - gyro biases for X, Y, Z axes.
131 *          This calibration data would normally be produced by the MPU Self
132 *          Test and its size is 18 bytes (header and checksum included).
133 *          Calibration format type 0 is currently <b>NOT</b> used and
134 *          is substituted by type 5 : inv_load_cal_V5().
135 *
136 *  @note   This calibration data format is obsoleted and no longer supported
137 *          by the rest of the MPL
138 *
139 *  @pre    inv_dmp_open()
140 *          @ifnot MPL_MF
141 *              or inv_open_low_power_pedometer()
142 *              or inv_eis_open_dmp()
143 *          @endif
144 *          must have been called.
145 *
146 *  @param  calData
147 *              A pointer to an array of bytes to be parsed.
148 *  @param  len
149 *              the length of the calibration
150 *
151 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
152 */
153inv_error_t inv_load_cal_V0(unsigned char *calData, unsigned short len)
154{
155    INVENSENSE_FUNC_START;
156    const short expLen = 18;
157    long newGyroData[3] = { 0, 0, 0 };
158    float newTemp;
159    int bin;
160
161    LOADCAL_LOG("Entering inv_load_cal_V0\n");
162
163    if (len != expLen) {
164        MPL_LOGE("Calibration data type 1 must be %d bytes long\n", expLen);
165        return INV_ERROR_FILE_READ;
166    }
167
168    newTemp = (float)inv_decode_temperature(
169                (unsigned short)calData[6] * 256 + calData[7]) / 65536.f;
170    LOADCAL_LOG("newTemp = %f\n", newTemp);
171
172    newGyroData[0] = ((long)calData[8]) * 256 + ((long)calData[9]);
173    if (newGyroData[0] > 32767L)
174        newGyroData[0] -= 65536L;
175    LOADCAL_LOG("newGyroData[0] = %ld\n", newGyroData[0]);
176    newGyroData[1] = ((long)calData[10]) * 256 + ((long)calData[11]);
177    if (newGyroData[1] > 32767L)
178        newGyroData[1] -= 65536L;
179    LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
180    newGyroData[2] = ((long)calData[12]) * 256 + ((long)calData[13]);
181    if (newGyroData[2] > 32767L)
182        newGyroData[2] -= 65536L;
183    LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
184
185    bin = FindTempBin(newTemp);
186    LOADCAL_LOG("bin = %d", bin);
187
188    inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
189    LOADCAL_LOG("temp_data[%d][%d] = %f",
190                bin, inv_obj.temp_ptrs[bin],
191                inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]]);
192    inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
193        ((float)newGyroData[0]) / 65536.f;
194    LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
195                bin, inv_obj.temp_ptrs[bin],
196                inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
197    inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
198        ((float)newGyroData[0]) / 65536.f;
199    LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
200                bin, inv_obj.temp_ptrs[bin],
201                inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
202    inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] =
203        ((float)newGyroData[0]) / 65536.f;
204    LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
205                bin, inv_obj.temp_ptrs[bin],
206                inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
207
208    inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
209    LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
210
211    if (inv_obj.temp_ptrs[bin] == 0)
212        inv_obj.temp_valid_data[bin] = TRUE;
213    LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
214                bin, inv_obj.temp_valid_data[bin]);
215
216    inv_obj.got_no_motion_bias = TRUE;
217    LOADCAL_LOG("got_no_motion_bias = 1\n");
218    inv_obj.cal_loaded_flag = TRUE;
219    LOADCAL_LOG("cal_loaded_flag = 1\n");
220
221    LOADCAL_LOG("Exiting inv_load_cal_V0\n");
222    return INV_SUCCESS;
223}
224
225/**
226 *  @brief  Loads a type 1 set of calibration data.
227 *          It parses a binary data set containing calibration data.
228 *          The binary data set is intended to be loaded from a file.
229 *          This calibrations data format stores values for (in order of
230 *          appearance) :
231 *          - temperature,
232 *          - gyro biases for X, Y, Z axes,
233 *          - accel biases for X, Y, Z axes.
234 *          This calibration data would normally be produced by the MPU Self
235 *          Test and its size is 24 bytes (header and checksum included).
236 *          Calibration format type 1 is currently <b>NOT</b> used and
237 *          is substituted by type 5 : inv_load_cal_V5().
238 *
239 *  @note   In order to successfully work, the gyro bias must be stored
240 *          expressed in 250 dps full scale (131.072 sensitivity). Other full
241 *          scale range will produce unpredictable results in the gyro biases.
242 *
243 *  @pre    inv_dmp_open()
244 *          @ifnot MPL_MF
245 *              or inv_open_low_power_pedometer()
246 *              or inv_eis_open_dmp()
247 *          @endif
248 *          must have been called.
249 *
250 *  @param  calData
251 *              A pointer to an array of bytes to be parsed.
252 *  @param  len
253 *              the length of the calibration
254 *
255 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
256 */
257inv_error_t inv_load_cal_V1(unsigned char *calData, unsigned short len)
258{
259    INVENSENSE_FUNC_START;
260    const short expLen = 24;
261    long newGyroData[3] = {0, 0, 0};
262    long accelBias[3] = {0, 0, 0};
263    float gyroBias[3] = {0, 0, 0};
264    float newTemp = 0;
265    int bin;
266
267    LOADCAL_LOG("Entering inv_load_cal_V1\n");
268
269    if (len != expLen) {
270        MPL_LOGE("Calibration data type 1 must be %d bytes long\n", expLen);
271        return INV_ERROR_FILE_READ;
272    }
273
274    newTemp = (float)inv_decode_temperature(
275                (unsigned short)calData[6] * 256 + calData[7]) / 65536.f;
276    LOADCAL_LOG("newTemp = %f\n", newTemp);
277
278    newGyroData[0] = ((long)calData[8]) * 256 + ((long)calData[9]);
279    if (newGyroData[0] > 32767L)
280        newGyroData[0] -= 65536L;
281    LOADCAL_LOG("newGyroData[0] = %ld\n", newGyroData[0]);
282    newGyroData[1] = ((long)calData[10]) * 256 + ((long)calData[11]);
283    if (newGyroData[1] > 32767L)
284        newGyroData[1] -= 65536L;
285    LOADCAL_LOG("newGyroData[1] = %ld\n", newGyroData[1]);
286    newGyroData[2] = ((long)calData[12]) * 256 + ((long)calData[13]);
287    if (newGyroData[2] > 32767L)
288        newGyroData[2] -= 65536L;
289    LOADCAL_LOG("newGyroData[2] = %ld\n", newGyroData[2]);
290
291    bin = FindTempBin(newTemp);
292    LOADCAL_LOG("bin = %d\n", bin);
293
294    gyroBias[0] = ((float)newGyroData[0]) / 131.072f;
295    gyroBias[1] = ((float)newGyroData[1]) / 131.072f;
296    gyroBias[2] = ((float)newGyroData[2]) / 131.072f;
297    LOADCAL_LOG("gyroBias[0] = %f\n", gyroBias[0]);
298    LOADCAL_LOG("gyroBias[1] = %f\n", gyroBias[1]);
299    LOADCAL_LOG("gyroBias[2] = %f\n", gyroBias[2]);
300
301    inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
302    LOADCAL_LOG("temp_data[%d][%d] = %f",
303                bin, inv_obj.temp_ptrs[bin],
304                inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]]);
305    inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[0];
306    LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
307                bin, inv_obj.temp_ptrs[bin],
308                inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
309    inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[1];
310    LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
311                bin, inv_obj.temp_ptrs[bin],
312                inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
313    inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[2];
314    LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
315                bin, inv_obj.temp_ptrs[bin],
316                inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]]);
317
318    inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
319    LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
320
321    if (inv_obj.temp_ptrs[bin] == 0)
322        inv_obj.temp_valid_data[bin] = TRUE;
323    LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
324                bin, inv_obj.temp_valid_data[bin]);
325
326    /* load accel biases and apply immediately */
327    accelBias[0] = ((long)calData[14]) * 256 + ((long)calData[15]);
328    if (accelBias[0] > 32767)
329        accelBias[0] -= 65536L;
330    accelBias[0] = (long)((long long)accelBias[0] * 65536L *
331                          inv_obj.accel_sens / 1073741824L);
332    LOADCAL_LOG("accelBias[0] = %ld\n", accelBias[0]);
333    accelBias[1] = ((long)calData[16]) * 256 + ((long)calData[17]);
334    if (accelBias[1] > 32767)
335        accelBias[1] -= 65536L;
336    accelBias[1] = (long)((long long)accelBias[1] * 65536L *
337                          inv_obj.accel_sens / 1073741824L);
338    LOADCAL_LOG("accelBias[1] = %ld\n", accelBias[1]);
339    accelBias[2] = ((long)calData[18]) * 256 + ((int)calData[19]);
340    if (accelBias[2] > 32767)
341        accelBias[2] -= 65536L;
342    accelBias[2] = (long)((long long)accelBias[2] * 65536L *
343                          inv_obj.accel_sens / 1073741824L);
344    LOADCAL_LOG("accelBias[2] = %ld\n", accelBias[2]);
345    if (inv_set_array(INV_ACCEL_BIAS, accelBias)) {
346        LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accelBias));
347        return inv_set_array(INV_ACCEL_BIAS, accelBias);
348    }
349
350    inv_obj.got_no_motion_bias = TRUE;
351    LOADCAL_LOG("got_no_motion_bias = 1\n");
352    inv_obj.cal_loaded_flag = TRUE;
353    LOADCAL_LOG("cal_loaded_flag = 1\n");
354
355    LOADCAL_LOG("Exiting inv_load_cal_V1\n");
356    return INV_SUCCESS;
357}
358
359/**
360 *  @brief  Loads a type 2 set of calibration data.
361 *          It parses a binary data set containing calibration data.
362 *          The binary data set is intended to be loaded from a file.
363 *          This calibrations data format stores values for (in order of
364 *          appearance) :
365 *          - temperature compensation : temperature data points,
366 *          - temperature compensation : gyro biases data points for X, Y,
367 *              and Z axes.
368 *          - accel biases for X, Y, Z axes.
369 *          This calibration data is produced internally by the MPL and its
370 *          size is 2222 bytes (header and checksum included).
371 *          Calibration format type 2 is currently <b>NOT</b> used and
372 *          is substituted by type 4 : inv_load_cal_V4().
373 *
374 *  @pre    inv_dmp_open()
375 *          @ifnot MPL_MF
376 *              or inv_open_low_power_pedometer()
377 *              or inv_eis_open_dmp()
378 *          @endif
379 *          must have been called.
380 *
381 *  @param  calData
382 *              A pointer to an array of bytes to be parsed.
383 *  @param  len
384 *              the length of the calibration
385 *
386 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
387 */
388inv_error_t inv_load_cal_V2(unsigned char *calData, unsigned short len)
389{
390    INVENSENSE_FUNC_START;
391    const short expLen = 2222;
392    long accel_bias[3];
393    int ptr = INV_CAL_HDR_LEN;
394
395    int i, j;
396    long long tmp;
397
398    LOADCAL_LOG("Entering inv_load_cal_V2\n");
399
400    if (len != expLen) {
401        MPL_LOGE("Calibration data type 2 must be %d bytes long (got %d)\n",
402                 expLen, len);
403        return INV_ERROR_FILE_READ;
404    }
405
406    for (i = 0; i < BINS; i++) {
407        inv_obj.temp_ptrs[i] = 0;
408        inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
409        inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
410        inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
411        inv_obj.temp_ptrs[i] += (int)calData[ptr++];
412        LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
413    }
414    for (i = 0; i < BINS; i++) {
415        inv_obj.temp_valid_data[i] = 0;
416        inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
417        inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
418        inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
419        inv_obj.temp_valid_data[i] += (int)calData[ptr++];
420        LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
421                    i, inv_obj.temp_valid_data[i]);
422    }
423
424    for (i = 0; i < BINS; i++) {
425        for (j = 0; j < PTS_PER_BIN; j++) {
426            tmp = 0;
427            tmp += 16777216LL * (long long)calData[ptr++];
428            tmp += 65536LL * (long long)calData[ptr++];
429            tmp += 256LL * (long long)calData[ptr++];
430            tmp += (long long)calData[ptr++];
431            if (tmp > 2147483648LL) {
432                tmp -= 4294967296LL;
433            }
434            inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
435            LOADCAL_LOG("temp_data[%d][%d] = %f\n",
436                        i, j, inv_obj.temp_data[i][j]);
437        }
438
439    }
440    for (i = 0; i < BINS; i++) {
441        for (j = 0; j < PTS_PER_BIN; j++) {
442            tmp = 0;
443            tmp += 16777216LL * (long long)calData[ptr++];
444            tmp += 65536LL * (long long)calData[ptr++];
445            tmp += 256LL * (long long)calData[ptr++];
446            tmp += (long long)calData[ptr++];
447            if (tmp > 2147483648LL) {
448                tmp -= 4294967296LL;
449            }
450            inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
451            LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
452                        i, j, inv_obj.x_gyro_temp_data[i][j]);
453        }
454    }
455    for (i = 0; i < BINS; i++) {
456        for (j = 0; j < PTS_PER_BIN; j++) {
457            tmp = 0;
458            tmp += 16777216LL * (long long)calData[ptr++];
459            tmp += 65536LL * (long long)calData[ptr++];
460            tmp += 256LL * (long long)calData[ptr++];
461            tmp += (long long)calData[ptr++];
462            if (tmp > 2147483648LL) {
463                tmp -= 4294967296LL;
464            }
465            inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
466            LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
467                        i, j, inv_obj.y_gyro_temp_data[i][j]);
468        }
469    }
470    for (i = 0; i < BINS; i++) {
471        for (j = 0; j < PTS_PER_BIN; j++) {
472            tmp = 0;
473            tmp += 16777216LL * (long long)calData[ptr++];
474            tmp += 65536LL * (long long)calData[ptr++];
475            tmp += 256LL * (long long)calData[ptr++];
476            tmp += (long long)calData[ptr++];
477            if (tmp > 2147483648LL) {
478                tmp -= 4294967296LL;
479            }
480            inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
481            LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
482                        i, j, inv_obj.z_gyro_temp_data[i][j]);
483        }
484    }
485
486    /* read the accel biases */
487    for (i = 0; i < 3; i++) {
488        uint32_t t = 0;
489        t += 16777216UL * ((uint32_t) calData[ptr++]);
490        t += 65536UL * ((uint32_t) calData[ptr++]);
491        t += 256u * ((uint32_t) calData[ptr++]);
492        t += (uint32_t) calData[ptr++];
493        accel_bias[i] = (int32_t) t;
494        LOADCAL_LOG("accel_bias[%d] = %ld\n", i, accel_bias[i]);
495    }
496
497    if (inv_set_array(INV_ACCEL_BIAS, accel_bias)) {
498        LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accel_bias));
499        return inv_set_array(INV_ACCEL_BIAS, accel_bias);
500    }
501
502    inv_obj.got_no_motion_bias = TRUE;
503    LOADCAL_LOG("got_no_motion_bias = 1\n");
504    inv_obj.cal_loaded_flag = TRUE;
505    LOADCAL_LOG("cal_loaded_flag = 1\n");
506
507    LOADCAL_LOG("Exiting inv_load_cal_V2\n");
508    return INV_SUCCESS;
509}
510
511/**
512 *  @brief  Loads a type 3 set of calibration data.
513 *          It parses a binary data set containing calibration data.
514 *          The binary data set is intended to be loaded from a file.
515 *          This calibrations data format stores values for (in order of
516 *          appearance) :
517 *          - temperature compensation : temperature data points,
518 *          - temperature compensation : gyro biases data points for X, Y,
519 *              and Z axes.
520 *          - accel biases for X, Y, Z axes.
521 *          - compass biases for X, Y, Z axes and bias tracking algorithm
522 *              mock-up.
523 *          This calibration data is produced internally by the MPL and its
524 *          size is 2429 bytes (header and checksum included).
525 *          Calibration format type 3 is currently <b>NOT</b> used and
526 *          is substituted by type 4 : inv_load_cal_V4().
527
528 *  @pre    inv_dmp_open()
529 *          @ifnot MPL_MF
530 *              or inv_open_low_power_pedometer()
531 *              or inv_eis_open_dmp()
532 *          @endif
533 *          must have been called.
534 *
535 *  @param  calData
536 *              A pointer to an array of bytes to be parsed.
537 *  @param  len
538 *              the length of the calibration
539 *
540 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
541 */
542inv_error_t inv_load_cal_V3(unsigned char *calData, unsigned short len)
543{
544    INVENSENSE_FUNC_START;
545    union doubleToLongLong {
546        double db;
547        unsigned long long ll;
548    } dToLL;
549
550    const short expLen = 2429;
551    long bias[3];
552    int i, j;
553    int ptr = INV_CAL_HDR_LEN;
554    long long tmp;
555
556    LOADCAL_LOG("Entering inv_load_cal_V3\n");
557
558    if (len != expLen) {
559        MPL_LOGE("Calibration data type 3 must be %d bytes long (got %d)\n",
560                 expLen, len);
561        return INV_ERROR_FILE_READ;
562    }
563
564    for (i = 0; i < BINS; i++) {
565        inv_obj.temp_ptrs[i] = 0;
566        inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
567        inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
568        inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
569        inv_obj.temp_ptrs[i] += (int)calData[ptr++];
570        LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
571    }
572    for (i = 0; i < BINS; i++) {
573        inv_obj.temp_valid_data[i] = 0;
574        inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
575        inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
576        inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
577        inv_obj.temp_valid_data[i] += (int)calData[ptr++];
578        LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
579                    i, inv_obj.temp_valid_data[i]);
580    }
581
582    for (i = 0; i < BINS; i++) {
583        for (j = 0; j < PTS_PER_BIN; j++) {
584            tmp = 0;
585            tmp += 16777216LL * (long long)calData[ptr++];
586            tmp += 65536LL * (long long)calData[ptr++];
587            tmp += 256LL * (long long)calData[ptr++];
588            tmp += (long long)calData[ptr++];
589            if (tmp > 2147483648LL) {
590                tmp -= 4294967296LL;
591            }
592            inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
593            LOADCAL_LOG("temp_data[%d][%d] = %f\n",
594                        i, j, inv_obj.temp_data[i][j]);
595        }
596    }
597
598    for (i = 0; i < BINS; i++) {
599        for (j = 0; j < PTS_PER_BIN; j++) {
600            tmp = 0;
601            tmp += 16777216LL * (long long)calData[ptr++];
602            tmp += 65536LL * (long long)calData[ptr++];
603            tmp += 256LL * (long long)calData[ptr++];
604            tmp += (long long)calData[ptr++];
605            if (tmp > 2147483648LL) {
606                tmp -= 4294967296LL;
607            }
608            inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
609            LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
610                        i, j, inv_obj.x_gyro_temp_data[i][j]);
611        }
612    }
613    for (i = 0; i < BINS; i++) {
614        for (j = 0; j < PTS_PER_BIN; j++) {
615            tmp = 0;
616            tmp += 16777216LL * (long long)calData[ptr++];
617            tmp += 65536LL * (long long)calData[ptr++];
618            tmp += 256LL * (long long)calData[ptr++];
619            tmp += (long long)calData[ptr++];
620            if (tmp > 2147483648LL) {
621                tmp -= 4294967296LL;
622            }
623            inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
624            LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
625                        i, j, inv_obj.y_gyro_temp_data[i][j]);
626        }
627    }
628    for (i = 0; i < BINS; i++) {
629        for (j = 0; j < PTS_PER_BIN; j++) {
630            tmp = 0;
631            tmp += 16777216LL * (long long)calData[ptr++];
632            tmp += 65536LL * (long long)calData[ptr++];
633            tmp += 256LL * (long long)calData[ptr++];
634            tmp += (long long)calData[ptr++];
635            if (tmp > 2147483648LL) {
636                tmp -= 4294967296LL;
637            }
638            inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
639            LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
640                        i, j, inv_obj.z_gyro_temp_data[i][j]);
641        }
642    }
643
644    /* read the accel biases */
645    for (i = 0; i < 3; i++) {
646        uint32_t t = 0;
647        t += 16777216UL * ((uint32_t) calData[ptr++]);
648        t += 65536UL * ((uint32_t) calData[ptr++]);
649        t += 256u * ((uint32_t) calData[ptr++]);
650        t += (uint32_t) calData[ptr++];
651        bias[i] = (int32_t) t;
652        LOADCAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
653    }
654    if (inv_set_array(INV_ACCEL_BIAS, bias)) {
655        LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, bias));
656        return inv_set_array(INV_ACCEL_BIAS, bias);
657    }
658
659    /* read the compass biases */
660    inv_obj.got_compass_bias = (int)calData[ptr++];
661    inv_obj.got_init_compass_bias = (int)calData[ptr++];
662    inv_obj.compass_state = (int)calData[ptr++];
663
664    for (i = 0; i < 3; i++) {
665        uint32_t t = 0;
666        t += 16777216UL * ((uint32_t) calData[ptr++]);
667        t += 65536UL * ((uint32_t) calData[ptr++]);
668        t += 256u * ((uint32_t) calData[ptr++]);
669        t += (uint32_t) calData[ptr++];
670        inv_obj.compass_bias_error[i] = (int32_t) t;
671        LOADCAL_LOG("compass_bias_error[%d] = %ld\n", i,
672                    inv_obj.compass_bias_error[i]);
673    }
674    for (i = 0; i < 3; i++) {
675        uint32_t t = 0;
676        t += 16777216UL * ((uint32_t) calData[ptr++]);
677        t += 65536UL * ((uint32_t) calData[ptr++]);
678        t += 256u * ((uint32_t) calData[ptr++]);
679        t += (uint32_t) calData[ptr++];
680        inv_obj.init_compass_bias[i] = (int32_t) t;
681        LOADCAL_LOG("init_compass_bias[%d] = %ld\n", i,
682                    inv_obj.init_compass_bias[i]);
683    }
684    for (i = 0; i < 3; i++) {
685        uint32_t t = 0;
686        t += 16777216UL * ((uint32_t) calData[ptr++]);
687        t += 65536UL * ((uint32_t) calData[ptr++]);
688        t += 256u * ((uint32_t) calData[ptr++]);
689        t += (uint32_t) calData[ptr++];
690        inv_obj.compass_bias[i] = (int32_t) t;
691        LOADCAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
692    }
693    for (i = 0; i < 18; i++) {
694        uint32_t t = 0;
695        t += 16777216UL * ((uint32_t) calData[ptr++]);
696        t += 65536UL * ((uint32_t) calData[ptr++]);
697        t += 256u * ((uint32_t) calData[ptr++]);
698        t += (uint32_t) calData[ptr++];
699        inv_obj.compass_peaks[i] = (int32_t) t;
700        LOADCAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
701    }
702    for (i = 0; i < 3; i++) {
703        dToLL.ll = 0;
704        dToLL.ll += 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
705        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
706        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
707        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
708        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
709        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
710        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
711        dToLL.ll += (unsigned long long)calData[ptr++];
712
713        inv_obj.compass_bias_v[i] = dToLL.db;
714        LOADCAL_LOG("compass_bias_v[%d] = %lf\n", i, inv_obj.compass_bias_v[i]);
715    }
716    for (i = 0; i < 9; i++) {
717        dToLL.ll = 0;
718        dToLL.ll += 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
719        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
720        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
721        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
722        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
723        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
724        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
725        dToLL.ll += (unsigned long long)calData[ptr++];
726
727        inv_obj.compass_bias_ptr[i] = dToLL.db;
728        LOADCAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
729                    inv_obj.compass_bias_ptr[i]);
730    }
731
732    inv_obj.got_no_motion_bias = TRUE;
733    LOADCAL_LOG("got_no_motion_bias = 1\n");
734    inv_obj.cal_loaded_flag = TRUE;
735    LOADCAL_LOG("cal_loaded_flag = 1\n");
736
737    LOADCAL_LOG("Exiting inv_load_cal_V3\n");
738    return INV_SUCCESS;
739}
740
741/**
742 *  @brief  Loads a type 4 set of calibration data.
743 *          It parses a binary data set containing calibration data.
744 *          The binary data set is intended to be loaded from a file.
745 *          This calibrations data format stores values for (in order of
746 *          appearance) :
747 *          - temperature compensation : temperature data points,
748 *          - temperature compensation : gyro biases data points for X, Y,
749 *              and Z axes.
750 *          - accel biases for X, Y, Z axes.
751 *          - compass biases for X, Y, Z axes, compass scale, and bias
752 *              tracking algorithm  mock-up.
753 *          This calibration data is produced internally by the MPL and its
754 *          size is 2777 bytes (header and checksum included).
755 *          Calibration format type 4 is currently used and
756 *          substitutes type 2 (inv_load_cal_V2()) and 3 (inv_load_cal_V3()).
757 *
758 *  @pre    inv_dmp_open()
759 *          @ifnot MPL_MF
760 *              or inv_open_low_power_pedometer()
761 *              or inv_eis_open_dmp()
762 *          @endif
763 *          must have been called.
764 *
765 *  @param  calData
766 *              A pointer to an array of bytes to be parsed.
767 *  @param  len
768 *              the length of the calibration
769 *
770 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
771 */
772inv_error_t inv_load_cal_V4(unsigned char *calData, unsigned short len)
773{
774    INVENSENSE_FUNC_START;
775    union doubleToLongLong {
776        double db;
777        unsigned long long ll;
778    } dToLL;
779
780    const unsigned int expLen = 2782;
781    long bias[3];
782    int ptr = INV_CAL_HDR_LEN;
783    int i, j;
784    long long tmp;
785    inv_error_t result;
786
787    LOADCAL_LOG("Entering inv_load_cal_V4\n");
788
789    if (len != expLen) {
790        MPL_LOGE("Calibration data type 4 must be %d bytes long (got %d)\n",
791                 expLen, len);
792        return INV_ERROR_FILE_READ;
793    }
794
795    for (i = 0; i < BINS; i++) {
796        inv_obj.temp_ptrs[i] = 0;
797        inv_obj.temp_ptrs[i] += 16777216L * ((long)calData[ptr++]);
798        inv_obj.temp_ptrs[i] += 65536L * ((long)calData[ptr++]);
799        inv_obj.temp_ptrs[i] += 256 * ((int)calData[ptr++]);
800        inv_obj.temp_ptrs[i] += (int)calData[ptr++];
801        LOADCAL_LOG("temp_ptrs[%d] = %d\n", i, inv_obj.temp_ptrs[i]);
802    }
803    for (i = 0; i < BINS; i++) {
804        inv_obj.temp_valid_data[i] = 0;
805        inv_obj.temp_valid_data[i] += 16777216L * ((long)calData[ptr++]);
806        inv_obj.temp_valid_data[i] += 65536L * ((long)calData[ptr++]);
807        inv_obj.temp_valid_data[i] += 256 * ((int)calData[ptr++]);
808        inv_obj.temp_valid_data[i] += (int)calData[ptr++];
809        LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
810                    i, inv_obj.temp_valid_data[i]);
811    }
812
813    for (i = 0; i < BINS; i++) {
814        for (j = 0; j < PTS_PER_BIN; j++) {
815            tmp = 0;
816            tmp += 16777216LL * (long long)calData[ptr++];
817            tmp += 65536LL * (long long)calData[ptr++];
818            tmp += 256LL * (long long)calData[ptr++];
819            tmp += (long long)calData[ptr++];
820            if (tmp > 2147483648LL) {
821                tmp -= 4294967296LL;
822            }
823            inv_obj.temp_data[i][j] = ((float)tmp) / 65536.0f;
824            LOADCAL_LOG("temp_data[%d][%d] = %f\n",
825                        i, j, inv_obj.temp_data[i][j]);
826        }
827    }
828
829    for (i = 0; i < BINS; i++) {
830        for (j = 0; j < PTS_PER_BIN; j++) {
831            tmp = 0;
832            tmp += 16777216LL * (long long)calData[ptr++];
833            tmp += 65536LL * (long long)calData[ptr++];
834            tmp += 256LL * (long long)calData[ptr++];
835            tmp += (long long)calData[ptr++];
836            if (tmp > 2147483648LL) {
837                tmp -= 4294967296LL;
838            }
839            inv_obj.x_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
840            LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
841                        i, j, inv_obj.x_gyro_temp_data[i][j]);
842        }
843    }
844    for (i = 0; i < BINS; i++) {
845        for (j = 0; j < PTS_PER_BIN; j++) {
846            tmp = 0;
847            tmp += 16777216LL * (long long)calData[ptr++];
848            tmp += 65536LL * (long long)calData[ptr++];
849            tmp += 256LL * (long long)calData[ptr++];
850            tmp += (long long)calData[ptr++];
851            if (tmp > 2147483648LL) {
852                tmp -= 4294967296LL;
853            }
854            inv_obj.y_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
855            LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
856                        i, j, inv_obj.y_gyro_temp_data[i][j]);
857        }
858    }
859    for (i = 0; i < BINS; i++) {
860        for (j = 0; j < PTS_PER_BIN; j++) {
861            tmp = 0;
862            tmp += 16777216LL * (long long)calData[ptr++];
863            tmp += 65536LL * (long long)calData[ptr++];
864            tmp += 256LL * (long long)calData[ptr++];
865            tmp += (long long)calData[ptr++];
866            if (tmp > 2147483648LL) {
867                tmp -= 4294967296LL;
868            }
869            inv_obj.z_gyro_temp_data[i][j] = ((float)tmp) / 65536.0f;
870            LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
871                        i, j, inv_obj.z_gyro_temp_data[i][j]);
872        }
873    }
874
875    /* read the accel biases */
876    for (i = 0; i < 3; i++) {
877        uint32_t t = 0;
878        t += 16777216UL * ((uint32_t) calData[ptr++]);
879        t += 65536UL * ((uint32_t) calData[ptr++]);
880        t += 256u * ((uint32_t) calData[ptr++]);
881        t += (uint32_t) calData[ptr++];
882        bias[i] = (int32_t) t;
883        LOADCAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
884    }
885    if (inv_set_array(INV_ACCEL_BIAS, bias)) {
886        LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, bias));
887        return inv_set_array(INV_ACCEL_BIAS, bias);
888    }
889
890    /* read the compass biases */
891    inv_reset_compass_calibration();
892
893    inv_obj.got_compass_bias = (int)calData[ptr++];
894    LOADCAL_LOG("got_compass_bias = %ld\n", inv_obj.got_compass_bias);
895    inv_obj.got_init_compass_bias = (int)calData[ptr++];
896    LOADCAL_LOG("got_init_compass_bias = %d\n", inv_obj.got_init_compass_bias);
897    inv_obj.compass_state = (int)calData[ptr++];
898    LOADCAL_LOG("compass_state = %ld\n", inv_obj.compass_state);
899
900    for (i = 0; i < 3; i++) {
901        uint32_t t = 0;
902        t += 16777216UL * ((uint32_t) calData[ptr++]);
903        t += 65536UL * ((uint32_t) calData[ptr++]);
904        t += 256u * ((uint32_t) calData[ptr++]);
905        t += (uint32_t) calData[ptr++];
906        inv_obj.compass_bias_error[i] = (int32_t) t;
907        LOADCAL_LOG("compass_bias_error[%d] = %ld\n", i,
908                    inv_obj.compass_bias_error[i]);
909    }
910    for (i = 0; i < 3; i++) {
911        uint32_t t = 0;
912        t += 16777216UL * ((uint32_t) calData[ptr++]);
913        t += 65536UL * ((uint32_t) calData[ptr++]);
914        t += 256u * ((uint32_t) calData[ptr++]);
915        t += (uint32_t) calData[ptr++];
916        inv_obj.init_compass_bias[i] = (int32_t) t;
917        LOADCAL_LOG("init_compass_bias[%d] = %ld\n", i,
918                    inv_obj.init_compass_bias[i]);
919    }
920    for (i = 0; i < 3; i++) {
921        uint32_t t = 0;
922        t += 16777216UL * ((uint32_t) calData[ptr++]);
923        t += 65536UL * ((uint32_t) calData[ptr++]);
924        t += 256u * ((uint32_t) calData[ptr++]);
925        t += (uint32_t) calData[ptr++];
926        inv_obj.compass_bias[i] = (int32_t) t;
927        LOADCAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
928    }
929    for (i = 0; i < 18; i++) {
930        uint32_t t = 0;
931        t += 16777216UL * ((uint32_t) calData[ptr++]);
932        t += 65536UL * ((uint32_t) calData[ptr++]);
933        t += 256u * ((uint32_t) calData[ptr++]);
934        t += (uint32_t) calData[ptr++];
935        inv_obj.compass_peaks[i] = (int32_t) t;
936        LOADCAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
937    }
938    for (i = 0; i < 3; i++) {
939        dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
940        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
941        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
942        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
943        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
944        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
945        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
946        dToLL.ll += (unsigned long long)calData[ptr++];
947
948        inv_obj.compass_bias_v[i] = dToLL.db;
949        LOADCAL_LOG("compass_bias_v[%d] = %lf\n", i, inv_obj.compass_bias_v[i]);
950    }
951    for (i = 0; i < 9; i++) {
952        dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
953        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
954        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
955        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
956        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
957        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
958        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
959        dToLL.ll += (unsigned long long)calData[ptr++];
960
961        inv_obj.compass_bias_ptr[i] = dToLL.db;
962        LOADCAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
963                    inv_obj.compass_bias_ptr[i]);
964    }
965    for (i = 0; i < 3; i++) {
966        uint32_t t = 0;
967        t += 16777216UL * ((uint32_t) calData[ptr++]);
968        t += 65536UL * ((uint32_t) calData[ptr++]);
969        t += 256u * ((uint32_t) calData[ptr++]);
970        t += (uint32_t) calData[ptr++];
971        inv_obj.compass_scale[i] = (int32_t) t;
972        LOADCAL_LOG("compass_scale[%d] = %d\n", i, (int32_t) t);
973    }
974    for (i = 0; i < 6; i++) {
975        dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
976        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
977        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
978        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
979        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
980        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
981        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
982        dToLL.ll += (unsigned long long)calData[ptr++];
983
984        inv_obj.compass_prev_xty[i] = dToLL.db;
985        LOADCAL_LOG("compass_prev_xty[%d] = %f\n", i, dToLL.db);
986    }
987    for (i = 0; i < 36; i++) {
988        dToLL.ll = 72057594037927936ULL * ((unsigned long long)calData[ptr++]);
989        dToLL.ll += 281474976710656ULL * ((unsigned long long)calData[ptr++]);
990        dToLL.ll += 1099511627776ULL * ((unsigned long long)calData[ptr++]);
991        dToLL.ll += 4294967296LL * ((unsigned long long)calData[ptr++]);
992        dToLL.ll += 16777216ULL * ((unsigned long long)calData[ptr++]);
993        dToLL.ll += 65536ULL * ((unsigned long long)calData[ptr++]);
994        dToLL.ll += 256LL * ((unsigned long long)calData[ptr++]);
995        dToLL.ll += (unsigned long long)calData[ptr++];
996
997        inv_obj.compass_prev_m[i] = dToLL.db;
998        LOADCAL_LOG("compass_prev_m[%d] = %f\n", i, dToLL.db);
999    }
1000
1001    /* Load the compass offset flag and values */
1002    inv_obj.flags[INV_COMPASS_OFFSET_VALID] = calData[ptr++];
1003    inv_obj.compass_offsets[0] = calData[ptr++];
1004    inv_obj.compass_offsets[1] = calData[ptr++];
1005    inv_obj.compass_offsets[2] = calData[ptr++];
1006
1007    inv_obj.compass_accuracy = calData[ptr++];
1008    /* push the compass offset values to the device */
1009    result = inv_set_compass_offset();
1010
1011    if (result == INV_SUCCESS) {
1012        if (inv_compass_check_range() != INV_SUCCESS) {
1013            MPL_LOGI("range check fail");
1014            inv_reset_compass_calibration();
1015            inv_obj.flags[INV_COMPASS_OFFSET_VALID] = 0;
1016            inv_set_compass_offset();
1017        }
1018    }
1019
1020    inv_obj.got_no_motion_bias = TRUE;
1021    LOADCAL_LOG("got_no_motion_bias = 1\n");
1022    inv_obj.cal_loaded_flag = TRUE;
1023    LOADCAL_LOG("cal_loaded_flag = 1\n");
1024
1025    LOADCAL_LOG("Exiting inv_load_cal_V4\n");
1026    return INV_SUCCESS;
1027}
1028
1029/**
1030 *  @brief  Loads a type 5 set of calibration data.
1031 *          It parses a binary data set containing calibration data.
1032 *          The binary data set is intended to be loaded from a file.
1033 *          This calibrations data format stores values for (in order of
1034 *          appearance) :
1035 *          - temperature,
1036 *          - gyro biases for X, Y, Z axes,
1037 *          - accel biases for X, Y, Z axes.
1038 *          This calibration data would normally be produced by the MPU Self
1039 *          Test and its size is 36 bytes (header and checksum included).
1040 *          Calibration format type 5 is produced by the MPU Self Test and
1041 *          substitutes the type 1 : inv_load_cal_V1().
1042 *
1043 *  @pre    inv_dmp_open()
1044 *          @ifnot MPL_MF
1045 *              or inv_open_low_power_pedometer()
1046 *              or inv_eis_open_dmp()
1047 *          @endif
1048 *          must have been called.
1049 *
1050 *  @param  calData
1051 *              A pointer to an array of bytes to be parsed.
1052 *  @param  len
1053 *              the length of the calibration
1054 *
1055 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
1056 */
1057inv_error_t inv_load_cal_V5(unsigned char *calData, unsigned short len)
1058{
1059    INVENSENSE_FUNC_START;
1060    const short expLen = 36;
1061    long accelBias[3] = { 0, 0, 0 };
1062    float gyroBias[3] = { 0, 0, 0 };
1063
1064    int ptr = INV_CAL_HDR_LEN;
1065    unsigned short temp;
1066    float newTemp;
1067    int bin;
1068    int i;
1069
1070    LOADCAL_LOG("Entering inv_load_cal_V5\n");
1071
1072    if (len != expLen) {
1073        MPL_LOGE("Calibration data type 5 must be %d bytes long (got %d)\n",
1074                 expLen, len);
1075        return INV_ERROR_FILE_READ;
1076    }
1077
1078    /* load the temperature */
1079    temp = (unsigned short)calData[ptr++] * (1L << 8);
1080    temp += calData[ptr++];
1081    newTemp = (float)inv_decode_temperature(temp) / 65536.f;
1082    LOADCAL_LOG("newTemp = %f\n", newTemp);
1083
1084    /* load the gyro biases (represented in 2 ^ 16 == 1 dps) */
1085    for (i = 0; i < 3; i++) {
1086        int32_t tmp = 0;
1087        tmp += (int32_t) calData[ptr++] * (1L << 24);
1088        tmp += (int32_t) calData[ptr++] * (1L << 16);
1089        tmp += (int32_t) calData[ptr++] * (1L << 8);
1090        tmp += (int32_t) calData[ptr++];
1091        gyroBias[i] = (float)tmp / 65536.0f;
1092        LOADCAL_LOG("gyroBias[%d] = %f\n", i, gyroBias[i]);
1093    }
1094    /* find the temperature bin */
1095    bin = FindTempBin(newTemp);
1096
1097    /* populate the temp comp data structure */
1098    inv_obj.temp_data[bin][inv_obj.temp_ptrs[bin]] = newTemp;
1099    LOADCAL_LOG("temp_data[%d][%d] = %f\n",
1100                bin, inv_obj.temp_ptrs[bin], newTemp);
1101
1102    inv_obj.x_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[0];
1103    LOADCAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
1104                bin, inv_obj.temp_ptrs[bin], gyroBias[0]);
1105    inv_obj.y_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[1];
1106    LOADCAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
1107                bin, inv_obj.temp_ptrs[bin], gyroBias[1]);
1108    inv_obj.z_gyro_temp_data[bin][inv_obj.temp_ptrs[bin]] = gyroBias[2];
1109    LOADCAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
1110                bin, inv_obj.temp_ptrs[bin], gyroBias[2]);
1111    inv_obj.temp_ptrs[bin] = (inv_obj.temp_ptrs[bin] + 1) % PTS_PER_BIN;
1112    LOADCAL_LOG("temp_ptrs[%d] = %d\n", bin, inv_obj.temp_ptrs[bin]);
1113
1114    if (inv_obj.temp_ptrs[bin] == 0)
1115        inv_obj.temp_valid_data[bin] = TRUE;
1116    LOADCAL_LOG("temp_valid_data[%d] = %ld\n",
1117                bin, inv_obj.temp_valid_data[bin]);
1118
1119    /* load accel biases (represented in 2 ^ 16 == 1 gee)
1120       and apply immediately */
1121    for (i = 0; i < 3; i++) {
1122        int32_t tmp = 0;
1123        tmp += (int32_t) calData[ptr++] * (1L << 24);
1124        tmp += (int32_t) calData[ptr++] * (1L << 16);
1125        tmp += (int32_t) calData[ptr++] * (1L << 8);
1126        tmp += (int32_t) calData[ptr++];
1127        accelBias[i] = (long)tmp;
1128        LOADCAL_LOG("accelBias[%d] = %ld\n", i, accelBias[i]);
1129    }
1130    if (inv_set_array(INV_ACCEL_BIAS, accelBias)) {
1131        LOG_RESULT_LOCATION(inv_set_array(INV_ACCEL_BIAS, accelBias));
1132        return inv_set_array(INV_ACCEL_BIAS, accelBias);
1133    }
1134
1135    inv_obj.got_no_motion_bias = TRUE;
1136    LOADCAL_LOG("got_no_motion_bias = 1\n");
1137    inv_obj.cal_loaded_flag = TRUE;
1138    LOADCAL_LOG("cal_loaded_flag = 1\n");
1139
1140    LOADCAL_LOG("Exiting inv_load_cal_V5\n");
1141    return INV_SUCCESS;
1142}
1143
1144/**
1145 * @brief   Loads a set of calibration data.
1146 *          It parses a binary data set containing calibration data.
1147 *          The binary data set is intended to be loaded from a file.
1148 *
1149 * @pre     inv_dmp_open()
1150 *          @ifnot MPL_MF
1151 *              or inv_open_low_power_pedometer()
1152 *              or inv_eis_open_dmp()
1153 *          @endif
1154 *          must have been called.
1155 *
1156 * @param   calData
1157 *              A pointer to an array of bytes to be parsed.
1158 *
1159 * @return  INV_SUCCESS if successful, a non-zero error code otherwise.
1160 */
1161inv_error_t inv_load_cal(unsigned char *calData)
1162{
1163    INVENSENSE_FUNC_START;
1164    int calType = 0;
1165    int len = 0;
1166    int ptr;
1167    uint32_t chk = 0;
1168    uint32_t cmp_chk = 0;
1169
1170    tMLLoadFunc loaders[] = {
1171        inv_load_cal_V0,
1172        inv_load_cal_V1,
1173        inv_load_cal_V2,
1174        inv_load_cal_V3,
1175        inv_load_cal_V4,
1176        inv_load_cal_V5
1177    };
1178
1179    if (inv_get_state() < INV_STATE_DMP_OPENED)
1180        return INV_ERROR_SM_IMPROPER_STATE;
1181
1182    /* read the header (type and len)
1183       len is the total record length including header and checksum */
1184    len = 0;
1185    len += 16777216L * ((int)calData[0]);
1186    len += 65536L * ((int)calData[1]);
1187    len += 256 * ((int)calData[2]);
1188    len += (int)calData[3];
1189
1190    calType = ((int)calData[4]) * 256 + ((int)calData[5]);
1191    if (calType > 5) {
1192        MPL_LOGE("Unsupported calibration file format %d. "
1193                 "Valid types 0..5\n", calType);
1194        return INV_ERROR_INVALID_PARAMETER;
1195    }
1196
1197    /* check the checksum */
1198    chk = 0;
1199    ptr = len - INV_CAL_CHK_LEN;
1200
1201    chk += 16777216L * ((uint32_t) calData[ptr++]);
1202    chk += 65536L * ((uint32_t) calData[ptr++]);
1203    chk += 256 * ((uint32_t) calData[ptr++]);
1204    chk += (uint32_t) calData[ptr++];
1205
1206    cmp_chk = inv_checksum(calData + INV_CAL_HDR_LEN,
1207                           len - (INV_CAL_HDR_LEN + INV_CAL_CHK_LEN));
1208
1209    if (chk != cmp_chk) {
1210        return INV_ERROR_CALIBRATION_CHECKSUM;
1211    }
1212
1213    /* call the proper method to read in the data */
1214    return loaders[calType] (calData, len);
1215}
1216
1217/**
1218 *  @brief  Stores a set of calibration data.
1219 *          It generates a binary data set containing calibration data.
1220 *          The binary data set is intended to be stored into a file.
1221 *
1222 *  @pre    inv_dmp_open()
1223 *
1224 *  @param  calData
1225 *              A pointer to an array of bytes to be stored.
1226 *  @param  length
1227 *              The amount of bytes available in the array.
1228 *
1229 *  @return INV_SUCCESS if successful, a non-zero error code otherwise.
1230 */
1231inv_error_t inv_store_cal(unsigned char *calData, int length)
1232{
1233    INVENSENSE_FUNC_START;
1234    int ptr = 0;
1235    int i = 0;
1236    int j = 0;
1237    long long tmp;
1238    uint32_t chk;
1239    long bias[3];
1240    //unsigned char state;
1241    union doubleToLongLong {
1242        double db;
1243        unsigned long long ll;
1244    } dToLL;
1245
1246    if (inv_get_state() < INV_STATE_DMP_OPENED)
1247        return INV_ERROR_SM_IMPROPER_STATE;
1248
1249    STORECAL_LOG("Entering inv_store_cal\n");
1250
1251    // length
1252    calData[0] = (unsigned char)((length >> 24) & 0xff);
1253    calData[1] = (unsigned char)((length >> 16) & 0xff);
1254    calData[2] = (unsigned char)((length >> 8) & 0xff);
1255    calData[3] = (unsigned char)(length & 0xff);
1256    STORECAL_LOG("calLen = %d\n", length);
1257
1258    // calibration data format type
1259    calData[4] = 0;
1260    calData[5] = 4;
1261    STORECAL_LOG("calType = %d\n", (int)calData[4] * 256 + calData[5]);
1262
1263    // data
1264    ptr = 6;
1265    for (i = 0; i < BINS; i++) {
1266        tmp = (int)inv_obj.temp_ptrs[i];
1267        calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1268        calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1269        calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1270        calData[ptr++] = (unsigned char)(tmp & 0xff);
1271        STORECAL_LOG("temp_ptrs[%d] = %lld\n", i, tmp);
1272    }
1273
1274    for (i = 0; i < BINS; i++) {
1275        tmp = (int)inv_obj.temp_valid_data[i];
1276        calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1277        calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1278        calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1279        calData[ptr++] = (unsigned char)(tmp & 0xff);
1280        STORECAL_LOG("temp_valid_data[%d] = %lld\n", i, tmp);
1281    }
1282    for (i = 0; i < BINS; i++) {
1283        for (j = 0; j < PTS_PER_BIN; j++) {
1284            tmp = (long long)(inv_obj.temp_data[i][j] * 65536.0f);
1285            if (tmp < 0) {
1286                tmp += 4294967296LL;
1287            }
1288            calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1289            calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1290            calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1291            calData[ptr++] = (unsigned char)(tmp & 0xff);
1292            STORECAL_LOG("temp_data[%d][%d] = %f\n",
1293                         i, j, inv_obj.temp_data[i][j]);
1294        }
1295    }
1296
1297    for (i = 0; i < BINS; i++) {
1298        for (j = 0; j < PTS_PER_BIN; j++) {
1299            tmp = (long long)(inv_obj.x_gyro_temp_data[i][j] * 65536.0f);
1300            if (tmp < 0) {
1301                tmp += 4294967296LL;
1302            }
1303            calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1304            calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1305            calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1306            calData[ptr++] = (unsigned char)(tmp & 0xff);
1307            STORECAL_LOG("x_gyro_temp_data[%d][%d] = %f\n",
1308                         i, j, inv_obj.x_gyro_temp_data[i][j]);
1309        }
1310    }
1311    for (i = 0; i < BINS; i++) {
1312        for (j = 0; j < PTS_PER_BIN; j++) {
1313            tmp = (long long)(inv_obj.y_gyro_temp_data[i][j] * 65536.0f);
1314            if (tmp < 0) {
1315                tmp += 4294967296LL;
1316            }
1317            calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1318            calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1319            calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1320            calData[ptr++] = (unsigned char)(tmp & 0xff);
1321            STORECAL_LOG("y_gyro_temp_data[%d][%d] = %f\n",
1322                         i, j, inv_obj.y_gyro_temp_data[i][j]);
1323        }
1324    }
1325    for (i = 0; i < BINS; i++) {
1326        for (j = 0; j < PTS_PER_BIN; j++) {
1327            tmp = (long long)(inv_obj.z_gyro_temp_data[i][j] * 65536.0f);
1328            if (tmp < 0) {
1329                tmp += 4294967296LL;
1330            }
1331            calData[ptr++] = (unsigned char)((tmp >> 24) & 0xff);
1332            calData[ptr++] = (unsigned char)((tmp >> 16) & 0xff);
1333            calData[ptr++] = (unsigned char)((tmp >> 8) & 0xff);
1334            calData[ptr++] = (unsigned char)(tmp & 0xff);
1335            STORECAL_LOG("z_gyro_temp_data[%d][%d] = %f\n",
1336                         i, j, inv_obj.z_gyro_temp_data[i][j]);
1337        }
1338    }
1339
1340    inv_get_array(INV_ACCEL_BIAS, bias);
1341
1342    /* write the accel biases */
1343    for (i = 0; i < 3; i++) {
1344        uint32_t t = (uint32_t) bias[i];
1345        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1346        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1347        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1348        calData[ptr++] = (unsigned char)(t & 0xff);
1349        STORECAL_LOG("accel_bias[%d] = %ld\n", i, bias[i]);
1350    }
1351
1352    /* write the compass calibration state */
1353    calData[ptr++] = (unsigned char)(inv_obj.got_compass_bias);
1354    STORECAL_LOG("got_compass_bias = %ld\n", inv_obj.got_compass_bias);
1355    calData[ptr++] = (unsigned char)(inv_obj.got_init_compass_bias);
1356    STORECAL_LOG("got_init_compass_bias = %d\n", inv_obj.got_init_compass_bias);
1357    if (inv_obj.compass_state == SF_UNCALIBRATED) {
1358        calData[ptr++] = SF_UNCALIBRATED;
1359    } else {
1360        calData[ptr++] = SF_STARTUP_SETTLE;
1361    }
1362    STORECAL_LOG("compass_state = %ld\n", inv_obj.compass_state);
1363
1364    for (i = 0; i < 3; i++) {
1365        uint32_t t = (uint32_t) inv_obj.compass_bias_error[i];
1366        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1367        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1368        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1369        calData[ptr++] = (unsigned char)(t & 0xff);
1370        STORECAL_LOG("compass_bias_error[%d] = %ld\n",
1371                     i, inv_obj.compass_bias_error[i]);
1372    }
1373    for (i = 0; i < 3; i++) {
1374        uint32_t t = (uint32_t) inv_obj.init_compass_bias[i];
1375        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1376        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1377        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1378        calData[ptr++] = (unsigned char)(t & 0xff);
1379        STORECAL_LOG("init_compass_bias[%d] = %ld\n", i,
1380                     inv_obj.init_compass_bias[i]);
1381    }
1382    for (i = 0; i < 3; i++) {
1383        uint32_t t = (uint32_t) inv_obj.compass_bias[i];
1384        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1385        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1386        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1387        calData[ptr++] = (unsigned char)(t & 0xff);
1388        STORECAL_LOG("compass_bias[%d] = %ld\n", i, inv_obj.compass_bias[i]);
1389    }
1390    for (i = 0; i < 18; i++) {
1391        uint32_t t = (uint32_t) inv_obj.compass_peaks[i];
1392        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1393        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1394        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1395        calData[ptr++] = (unsigned char)(t & 0xff);
1396        STORECAL_LOG("compass_peaks[%d] = %d\n", i, inv_obj.compass_peaks[i]);
1397    }
1398    for (i = 0; i < 3; i++) {
1399        dToLL.db = inv_obj.compass_bias_v[i];
1400        calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
1401        calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
1402        calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
1403        calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
1404        calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
1405        calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
1406        calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
1407        calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
1408        STORECAL_LOG("compass_bias_v[%d] = %lf\n", i,
1409                     inv_obj.compass_bias_v[i]);
1410    }
1411    for (i = 0; i < 9; i++) {
1412        dToLL.db = inv_obj.compass_bias_ptr[i];
1413        calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
1414        calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
1415        calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
1416        calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
1417        calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
1418        calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
1419        calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
1420        calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
1421        STORECAL_LOG("compass_bias_ptr[%d] = %lf\n", i,
1422                     inv_obj.compass_bias_ptr[i]);
1423    }
1424    for (i = 0; i < 3; i++) {
1425        uint32_t t = (uint32_t) inv_obj.compass_scale[i];
1426        calData[ptr++] = (unsigned char)((t >> 24) & 0xff);
1427        calData[ptr++] = (unsigned char)((t >> 16) & 0xff);
1428        calData[ptr++] = (unsigned char)((t >> 8) & 0xff);
1429        calData[ptr++] = (unsigned char)(t & 0xff);
1430        STORECAL_LOG("compass_scale[%d] = %ld\n", i, inv_obj.compass_scale[i]);
1431    }
1432    for (i = 0; i < 6; i++) {
1433        dToLL.db = inv_obj.compass_prev_xty[i];
1434        calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
1435        calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
1436        calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
1437        calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
1438        calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
1439        calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
1440        calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
1441        calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
1442        STORECAL_LOG("compass_prev_xty[%d] = %lf\n", i,
1443                     inv_obj.compass_prev_xty[i]);
1444    }
1445    for (i = 0; i < 36; i++) {
1446        dToLL.db = inv_obj.compass_prev_m[i];
1447        calData[ptr++] = (unsigned char)((dToLL.ll >> 56) & 0xff);
1448        calData[ptr++] = (unsigned char)((dToLL.ll >> 48) & 0xff);
1449        calData[ptr++] = (unsigned char)((dToLL.ll >> 40) & 0xff);
1450        calData[ptr++] = (unsigned char)((dToLL.ll >> 32) & 0xff);
1451        calData[ptr++] = (unsigned char)((dToLL.ll >> 24) & 0xff);
1452        calData[ptr++] = (unsigned char)((dToLL.ll >> 16) & 0xff);
1453        calData[ptr++] = (unsigned char)((dToLL.ll >> 8) & 0xff);
1454        calData[ptr++] = (unsigned char)(dToLL.ll & 0xff);
1455        STORECAL_LOG("compass_prev_m[%d] = %lf\n", i,
1456                     inv_obj.compass_prev_m[i]);
1457    }
1458
1459    /* store the compass offsets and validity flag */
1460    calData[ptr++] = (unsigned char)inv_obj.flags[INV_COMPASS_OFFSET_VALID];
1461    calData[ptr++] = (unsigned char)inv_obj.compass_offsets[0];
1462    calData[ptr++] = (unsigned char)inv_obj.compass_offsets[1];
1463    calData[ptr++] = (unsigned char)inv_obj.compass_offsets[2];
1464
1465    /* store the compass accuracy */
1466    calData[ptr++] = (unsigned char)(inv_obj.compass_accuracy);
1467
1468    /* add a checksum */
1469    chk = inv_checksum(calData + INV_CAL_HDR_LEN,
1470                       length - (INV_CAL_HDR_LEN + INV_CAL_CHK_LEN));
1471    calData[ptr++] = (unsigned char)((chk >> 24) & 0xff);
1472    calData[ptr++] = (unsigned char)((chk >> 16) & 0xff);
1473    calData[ptr++] = (unsigned char)((chk >> 8) & 0xff);
1474    calData[ptr++] = (unsigned char)(chk & 0xff);
1475
1476    STORECAL_LOG("Exiting inv_store_cal\n");
1477    return INV_SUCCESS;
1478}
1479
1480/**
1481 *  @brief  Load a calibration file.
1482 *
1483 *  @pre    Must be in INV_STATE_DMP_OPENED state.
1484 *          inv_dmp_open() or inv_dmp_stop() must have been called.
1485 *          inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
1486 *          been called.
1487 *
1488 *  @return 0 or error code.
1489 */
1490inv_error_t inv_load_calibration(void)
1491{
1492    unsigned char *calData;
1493    inv_error_t result;
1494    unsigned int length;
1495
1496    if (inv_get_state() < INV_STATE_DMP_OPENED)
1497        return INV_ERROR_SM_IMPROPER_STATE;
1498
1499    result = inv_serial_get_cal_length(&length);
1500    if (result == INV_ERROR_FILE_OPEN) {
1501        MPL_LOGI("Calibration data not loaded\n");
1502        return INV_SUCCESS;
1503    }
1504    if (result || length <= 0) {
1505        MPL_LOGE("Could not get file calibration length - "
1506                 "error %d - aborting\n", result);
1507        return result;
1508    }
1509    calData = (unsigned char *)inv_malloc(length);
1510    if (!calData) {
1511        MPL_LOGE("Could not allocate buffer of %d bytes - "
1512                 "aborting\n", length);
1513        return INV_ERROR_MEMORY_EXAUSTED;
1514    }
1515    result = inv_serial_read_cal(calData, length);
1516    if (result) {
1517        MPL_LOGE("Could not read the calibration data from file - "
1518                 "error %d - aborting\n", result);
1519        goto free_mem_n_exit;
1520
1521    }
1522    result = inv_load_cal(calData);
1523    if (result) {
1524        MPL_LOGE("Could not load the calibration data - "
1525                 "error %d - aborting\n", result);
1526        goto free_mem_n_exit;
1527
1528    }
1529
1530
1531
1532free_mem_n_exit:
1533    inv_free(calData);
1534    return INV_SUCCESS;
1535}
1536
1537/**
1538 *  @brief  Store runtime calibration data to a file
1539 *
1540 *  @pre    Must be in INV_STATE_DMP_OPENED state.
1541 *          inv_dmp_open() or inv_dmp_stop() must have been called.
1542 *          inv_dmp_start() and inv_dmp_close() must have <b>NOT</b>
1543 *          been called.
1544 *
1545 *  @return 0 or error code.
1546 */
1547inv_error_t inv_store_calibration(void)
1548{
1549    unsigned char *calData;
1550    inv_error_t result;
1551    unsigned int length;
1552
1553    if (inv_get_state() < INV_STATE_DMP_OPENED)
1554        return INV_ERROR_SM_IMPROPER_STATE;
1555
1556    length = inv_get_cal_length();
1557    calData = (unsigned char *)inv_malloc(length);
1558    if (!calData) {
1559        MPL_LOGE("Could not allocate buffer of %d bytes - "
1560                 "aborting\n", length);
1561        return INV_ERROR_MEMORY_EXAUSTED;
1562    }
1563    result = inv_store_cal(calData, length);
1564    if (result) {
1565        MPL_LOGE("Could not store calibrated data on file - "
1566                 "error %d - aborting\n", result);
1567        goto free_mem_n_exit;
1568
1569    }
1570    result = inv_serial_write_cal(calData, length);
1571    if (result) {
1572        MPL_LOGE("Could not write calibration data - " "error %d\n", result);
1573        goto free_mem_n_exit;
1574
1575    }
1576
1577
1578
1579free_mem_n_exit:
1580    inv_free(calData);
1581    return INV_SUCCESS;
1582}
1583
1584/**
1585 *  @}
1586 */
1587