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