Home | History | Annotate | Download | only in mllite
      1 /*
      2  $License:
      3     Copyright (C) 2011-2012 InvenSense Corporation, All Rights Reserved.
      4     See included License.txt for License information.
      5  $
      6  */
      7 
      8 /**
      9  *   @defgroup  Storage_Manager storage_manager
     10  *   @brief     Motion Library - Stores Data for functions.
     11  *
     12  *
     13  *   @{
     14  *       @file storage_manager.c
     15  *       @brief Load and Store Manager.
     16  */
     17 
     18 #include <string.h>
     19 
     20 #include "storage_manager.h"
     21 #include "log.h"
     22 #include "ml_math_func.h"
     23 #include "mlmath.h"
     24 
     25 /* Must be changed if the format of storage changes */
     26 #define DEFAULT_KEY 29681
     27 
     28 typedef inv_error_t (*load_func_t)(const unsigned char *data);
     29 typedef inv_error_t (*save_func_t)(unsigned char *data);
     30 /** Max number of entites that can be stored */
     31 #define NUM_STORAGE_BOXES 20
     32 
     33 struct data_header_t {
     34     long size;
     35     uint32_t checksum;
     36     unsigned int key;
     37 };
     38 
     39 struct data_storage_t {
     40     int num; /**< Number of differnt save entities */
     41     size_t total_size; /**< Size in bytes to store non volatile data */
     42     load_func_t load[NUM_STORAGE_BOXES]; /**< Callback to load data */
     43     save_func_t save[NUM_STORAGE_BOXES]; /**< Callback to save data */
     44     struct data_header_t hd[NUM_STORAGE_BOXES]; /**< Header info for each entity */
     45 };
     46 static struct data_storage_t ds;
     47 
     48 /** Should be called once before using any of the storage methods. Typically
     49 * called first by inv_init_mpl().*/
     50 void inv_init_storage_manager()
     51 {
     52     memset(&ds, 0, sizeof(ds));
     53     ds.total_size = sizeof(struct data_header_t);
     54 }
     55 
     56 /** Used to register your mechanism to load and store non-volative data. This should typical be
     57 * called during the enable function for your feature.
     58 * @param[in] load_func function pointer you will use to receive data that was stored for you.
     59 * @param[in] save_func function pointer you will use to save any data you want saved to
     60 *            non-volatile memory between runs.
     61 * @param[in] size The size in bytes of the amount of data you want loaded and saved.
     62 * @param[in] key The key associated with your data type should be unique across MPL.
     63 *                    The key should change when your type of data for storage changes.
     64 * @return Returns INV_SUCCESS if successful or an error code if not.
     65 */
     66 inv_error_t inv_register_load_store(inv_error_t (*load_func)(const unsigned char *data),
     67                                     inv_error_t (*save_func)(unsigned char *data), size_t size, unsigned int key)
     68 {
     69     int kk;
     70     // Check if this has been registered already
     71     for (kk=0; kk<ds.num; ++kk) {
     72         if (key == ds.hd[kk].key) {
     73             return INV_ERROR_INVALID_PARAMETER;
     74         }
     75     }
     76     // Make sure there is room
     77     if (ds.num >= NUM_STORAGE_BOXES) {
     78         return INV_ERROR_INVALID_PARAMETER;
     79     }
     80     // Add to list
     81     ds.hd[ds.num].key = key;
     82     ds.hd[ds.num].size = size;
     83     ds.load[ds.num] = load_func;
     84     ds.save[ds.num] = save_func;
     85     ds.total_size += size + sizeof(struct data_header_t);
     86     ds.num++;
     87 
     88     return INV_SUCCESS;
     89 }
     90 
     91 /** Returns the memory size needed to perform a store
     92 * @param[out] size Size in bytes of memory needed to store.
     93 * @return Returns INV_SUCCESS if successful or an error code if not.
     94 */
     95 inv_error_t inv_get_mpl_state_size(size_t *size)
     96 {
     97     *size = ds.total_size;
     98     return INV_SUCCESS;
     99 }
    100 
    101 /** @internal
    102  * Finds key in ds.hd[] array and returns location
    103  * @return location where key exists in array, -1 if not found.
    104  */
    105 static int inv_find_entry(unsigned int key)
    106 {
    107     int kk;
    108     for (kk=0; kk<ds.num; ++kk) {
    109         if (key == ds.hd[kk].key) {
    110             return kk;
    111         }
    112     }
    113     return -1;
    114 }
    115 
    116 /** This function takes a block of data that has been saved in non-volatile memory and pushes
    117 * to the proper locations. Multiple error checks are performed on the data.
    118 * @param[in] data Data that was saved to be loaded up by MPL
    119 * @param[in] length Length of data vector in bytes
    120 * @return Returns INV_SUCCESS if successful or an error code if not.
    121 */
    122 inv_error_t inv_load_mpl_states(const unsigned char *data, size_t length)
    123 {
    124     struct data_header_t *hd;
    125     int entry;
    126     uint32_t checksum;
    127     long len;
    128 
    129     len = length; // Important so we get negative numbers
    130     if (len < sizeof(struct data_header_t))
    131         return INV_ERROR_CALIBRATION_LOAD;	// No data
    132     hd = (struct data_header_t *)data;
    133     if (hd->key != DEFAULT_KEY)
    134         return INV_ERROR_CALIBRATION_LOAD;	// Key changed or data corruption
    135     len = MIN(hd->size, len);
    136     len = hd->size;
    137     len -= sizeof(struct data_header_t);
    138     data += sizeof(struct data_header_t);
    139     checksum = inv_checksum(data, len);
    140     if (checksum != hd->checksum)
    141         return INV_ERROR_CALIBRATION_LOAD;	// Data corruption
    142 
    143     while (len > (long)sizeof(struct data_header_t)) {
    144         hd = (struct data_header_t *)data;
    145         entry = inv_find_entry(hd->key);
    146         data += sizeof(struct data_header_t);
    147         len -= sizeof(struct data_header_t);
    148         if (entry >= 0 && len >= hd->size) {
    149             if (hd->size == ds.hd[entry].size) {
    150                 checksum = inv_checksum(data, hd->size);
    151                 if (checksum == hd->checksum) {
    152                     ds.load[entry](data);
    153                 } else {
    154                     return INV_ERROR_CALIBRATION_LOAD;
    155                 }
    156             }
    157         }
    158         len -= hd->size;
    159         if (len >= 0)
    160             data = data + hd->size;
    161     }
    162 
    163     return INV_SUCCESS;
    164 }
    165 
    166 /** This function fills up a block of memory to be stored in non-volatile memory.
    167 * @param[out] data Place to store data, size of sz, must be at least size
    168 *                  returned by inv_get_mpl_state_size()
    169 * @param[in] sz Size of data.
    170 * @return Returns INV_SUCCESS if successful or an error code if not.
    171 */
    172 inv_error_t inv_save_mpl_states(unsigned char *data, size_t sz)
    173 {
    174     unsigned char *cur;
    175     int kk;
    176     struct data_header_t *hd;
    177 
    178     if (sz >= ds.total_size) {
    179         cur = data + sizeof(struct data_header_t);
    180         for (kk = 0; kk < ds.num; ++kk) {
    181             hd = (struct data_header_t *)cur;
    182             cur += sizeof(struct data_header_t);
    183             ds.save[kk](cur);
    184             hd->checksum = inv_checksum(cur, ds.hd[kk].size);
    185             hd->size = ds.hd[kk].size;
    186             hd->key = ds.hd[kk].key;
    187             cur += ds.hd[kk].size;
    188         }
    189     } else {
    190         return INV_ERROR_CALIBRATION_LOAD;
    191     }
    192 
    193     hd = (struct data_header_t *)data;
    194     hd->checksum = inv_checksum(data + sizeof(struct data_header_t),
    195                                 ds.total_size - sizeof(struct data_header_t));
    196     hd->key = DEFAULT_KEY;
    197     hd->size = ds.total_size;
    198 
    199     return INV_SUCCESS;
    200 }
    201 
    202 /**
    203  * @}
    204  */
    205