konashi/SBBLEのテスト

Dependencies:   BLE_API mbed

Fork of BLE_LoopbackUART by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pstorage.cpp Source File

pstorage.cpp

00001 /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is property of Nordic Semiconductor ASA.
00004  * Terms and conditions of usage are described in detail in NORDIC
00005  * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  */
00012 
00013 #if NEED_PSTORAGE /* disabled by default */
00014 
00015 #include <stdlib.h>
00016 #include <stdint.h>
00017 #include <string.h>
00018 #include "nordic_common.h"
00019 #include "nrf_error.h"
00020 #include "nrf_assert.h"
00021 //#include "nrf.h"
00022 #include "nrf_soc.h"
00023 #include "app_util.h "
00024 #include "pstorage.h "
00025 
00026 
00027 #define INVALID_OPCODE              0x00                       /**< Invalid op code identifier. */
00028 #define SOC_MAX_WRITE_SIZE          1024                       /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
00029 
00030 /**
00031  * @defgroup api_param_check API Parameters check macros.
00032  *
00033  * @details Macros that verify parameters passed to the module in the APIs. These macros
00034  *          could be mapped to nothing in final versions of code to save execution and size.
00035  *
00036  * @{
00037  */
00038 /**
00039  * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
00040  */
00041 #define NULL_PARAM_CHECK(PARAM)                                                                   \
00042         if ((PARAM) == NULL)                                                                      \
00043         {                                                                                         \
00044             return NRF_ERROR_NULL;                                                                \
00045         }
00046 
00047 /**
00048  * @brief Verifies the module identifier supplied by the application is within permissible
00049  *        range.
00050  */
00051 #define MODULE_ID_RANGE_CHECK(ID)                                                                 \
00052         if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) ||                                   \
00053             (m_app_table[(ID)->module_id].cb == NULL))                                            \
00054         {                                                                                         \
00055             return NRF_ERROR_INVALID_PARAM;                                                       \
00056         }
00057 
00058 /**
00059  * @brief Verifies the block identifier supplied by the application is within the permissible
00060  *        range.
00061  */
00062 #define BLOCK_ID_RANGE_CHECK(ID)                                                                  \
00063         if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id +                           \
00064             (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID))))                  \
00065         {                                                                                         \
00066             return NRF_ERROR_INVALID_PARAM;                                                       \
00067         }
00068 
00069 
00070 /**
00071  * @brief Verifies the block size requested by the application can be supported by the module. 
00072  */
00073 #define BLOCK_SIZE_CHECK(X)                                                                       \
00074         if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE))                   \
00075         {                                                                                         \
00076             return NRF_ERROR_INVALID_PARAM;                                                       \
00077         }
00078 
00079 /**
00080  * @brief Verifies block size requested by Application in registration API.
00081  */
00082 #define BLOCK_COUNT_CHECK(COUNT, SIZE)                                                            \
00083         if (((COUNT) == 0) || ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_DATA_END_ADDR)))  \
00084         {                                                                                         \
00085             return NRF_ERROR_INVALID_PARAM;                                                       \
00086         }
00087 
00088 /**
00089  * @brief Verifies size parameter provided by application in API.
00090  */
00091 #define SIZE_CHECK(ID, SIZE)                                                                      \
00092         if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID)))                                     \
00093         {                                                                                         \
00094             return NRF_ERROR_INVALID_PARAM;                                                       \
00095         }
00096 
00097 /**
00098  * @brief Verifies offset parameter provided by application in API.
00099  */
00100 #define OFFSET_CHECK(ID, OFFSET, SIZE)                                                            \
00101         if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID))                                           \
00102         {                                                                                         \
00103             return NRF_ERROR_INVALID_PARAM;                                                       \
00104         }
00105 
00106 #ifdef PSTORAGE_RAW_MODE_ENABLE
00107 
00108 /**
00109  * @brief Verifies the module identifier supplied by the application is registered for raw mode.
00110  */
00111 #define MODULE_RAW_ID_RANGE_CHECK(ID)                                                             \
00112         if ((PSTORAGE_MAX_APPLICATIONS+1 != ((ID)->module_id)) ||                                 \
00113             (m_raw_app_table.cb == NULL))                                                         \
00114         {                                                                                         \
00115             return NRF_ERROR_INVALID_PARAM;                                                       \
00116         }
00117 
00118 #endif // PSTORAGE_RAW_MODE_ENABLE
00119 
00120 /**@} */
00121 
00122 /**@brief    Verify module's initialization status.
00123  *
00124  * @details   Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a
00125  *            module API is called without initializing the module.
00126  */
00127 #define VERIFY_MODULE_INITIALIZED()                                                               \
00128         do                                                                                        \
00129         {                                                                                         \
00130             if (!m_module_initialized)                                                            \
00131             {                                                                                     \
00132                  return NRF_ERROR_INVALID_STATE;                                                  \
00133             }                                                                                     \
00134         } while(0)
00135 
00136 /**@brief Macro to fetch the block size registered for the module. */
00137 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
00138 
00139 /**@} */
00140 
00141 /**
00142  * @brief Application registration information.
00143  *
00144  * @details Define application specific information that application needs to maintain to be able
00145  *          to process requests from each one of them.
00146  */
00147 typedef struct
00148 {
00149     pstorage_ntf_cb_t      cb;             /**< Callback registered with the module to be notified of result of flash access.  */
00150     pstorage_block_t       base_id;        /**< Base block id assigned to the module */
00151     pstorage_size_t        block_size;     /**< Size of block for the module */
00152     pstorage_size_t        block_count;    /**< Number of block requested by application */
00153     pstorage_size_t        no_of_pages;    /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */    
00154 } pstorage_module_table_t;
00155 
00156 #ifdef PSTORAGE_RAW_MODE_ENABLE
00157 /**
00158  * @brief Application registration information.
00159  *
00160  * @details Define application specific information that application registered for raw mode.
00161  */
00162 typedef struct
00163 {
00164     pstorage_ntf_cb_t      cb;             /**< Callback registered with the module to be notified of result of flash access.  */
00165     uint16_t               no_of_pages;    /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
00166 } pstorage_raw_module_table_t;
00167 #endif // PSTORAGE_RAW_MODE_ENABLE
00168 
00169 
00170 
00171 
00172 /**
00173  * @brief Defines command queue element.
00174  *
00175  * @details Defines command queue element. Each element encapsulates needed information to process
00176  *          a flash access command.
00177  */
00178 typedef struct
00179 {
00180     uint8_t              op_code;          /**< Identifies flash access operation being queued. Element is free is op-code is INVALID_OPCODE */
00181     pstorage_size_t      size;             /**< Identifies size in bytes requested for the operation. */
00182     pstorage_size_t      offset;           /**< Offset requested by the application for access operation. */    
00183     pstorage_handle_t    storage_addr;     /**< Address/Identifier for persistent memory. */
00184     uint8_t              * p_data_addr;    /**< Address/Identifier for data memory. This is assumed to be resident memory. */    
00185 } cmd_queue_element_t;
00186 
00187 
00188 /**
00189  * @brief Defines command queue, an element is free is op_code field is not invalid.
00190  *
00191  * @details Defines commands enqueued for flash access. At any point of time, this queue has one or
00192  *          more flash access operation pending if the count field is not zero. When the queue is
00193  *          not empty, the rp (read pointer) field points to the flash access command in progress
00194  *          or to requested next. The queue implements a simple first in first out algorithm.
00195  *          Data addresses are assumed to be resident.
00196  */
00197 typedef struct
00198 {
00199     uint8_t              rp;                              /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
00200     uint8_t              count;                           /**< Number of elements in the queue.  */
00201     bool                 flash_access;                    /**< Flag to ensure an flash event received is for an request issued by the module. */
00202     cmd_queue_element_t  cmd[PSTORAGE_CMD_QUEUE_SIZE];    /**< Array to maintain flash access operation details */
00203 }cmd_queue_t;
00204 
00205 static cmd_queue_t             m_cmd_queue;                               /**< Flash operation request queue. */
00206 static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS];    /**< Registered application information table. */
00207 
00208 #ifdef PSTORAGE_RAW_MODE_ENABLE
00209 static pstorage_raw_module_table_t m_raw_app_table;      /**< Registered application information table for raw mode. */
00210 #endif // PSTORAGE_RAW_MODE_ENABLE
00211 
00212 static pstorage_size_t  m_next_app_instance;             /**< Points to the application module instance that can be allocated next */
00213 static uint32_t         m_next_page_addr;                /**< Points to the flash address that can be allocated to a module next, this is needed as blocks of a module can span across flash pages. */
00214 static bool             m_module_initialized = false;    /**< Flag for checking if module has been initialized. */
00215 static pstorage_size_t  m_round_val;                     /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */
00216 
00217 static uint32_t process_cmd(void);
00218 static void app_notify (uint32_t reason);
00219 
00220 /**
00221  * @defgroup utility_functions Utility internal functions.
00222  * @{
00223  * @details Utility functions needed for interfacing with flash through SoC APIs.
00224  * SoC APIs are non blocking and provide the result of flash access through an event.
00225  *
00226  * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is
00227  * maintained by this module.
00228  */
00229  
00230 /**
00231  * @brief Initializes command queue element.
00232  */
00233 static void cmd_queue_init_element(uint32_t index)
00234 {
00235     // Internal function and checks on range of index can be avoided
00236     m_cmd_queue.cmd[index].op_code                = INVALID_OPCODE;
00237     m_cmd_queue.cmd[index].size                   = 0;
00238     m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS;
00239     m_cmd_queue.cmd[index].storage_addr.block_id  = 0;
00240     m_cmd_queue.cmd[index].p_data_addr            = NULL;
00241     m_cmd_queue.cmd[index].offset                 = 0;
00242 }
00243 
00244 
00245 /**
00246  * @brief Initializes command queue.
00247  */
00248 static void cmd_queue_init (void)
00249 {
00250     uint32_t cmd_index;
00251 
00252     m_round_val              = 0;
00253     m_cmd_queue.rp           = 0;
00254     m_cmd_queue.count        = 0;
00255     m_cmd_queue.flash_access = false;
00256 
00257     for(cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
00258     {
00259         cmd_queue_init_element(cmd_index);
00260     }
00261 }
00262 
00263 
00264 /**
00265  * @brief Routine to enqueue a flash access operation.
00266  */
00267 static uint32_t cmd_queue_enqueue(uint8_t opcode, pstorage_handle_t * p_storage_addr,uint8_t * p_data_addr, pstorage_size_t size, pstorage_size_t offset)
00268 {
00269     uint32_t retval;
00270     uint8_t  write_index = 0;
00271     retval = NRF_ERROR_NO_MEM;
00272 
00273     // Check if flash access is ongoing.
00274     if ((m_cmd_queue.flash_access == false) && (m_cmd_queue.count == 0))
00275     {
00276         m_cmd_queue.rp = 0;
00277         m_cmd_queue.cmd[m_cmd_queue.rp].op_code      = opcode;
00278         m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr  = p_data_addr;
00279         m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr = (*p_storage_addr);
00280         m_cmd_queue.cmd[m_cmd_queue.rp].size         = size;
00281         m_cmd_queue.cmd[m_cmd_queue.rp].offset       = offset;
00282         m_cmd_queue.count++;
00283         retval = process_cmd();
00284         if ((retval == NRF_SUCCESS) || (retval == NRF_ERROR_BUSY))
00285         {
00286             // In case of busy error code, it is possible to attempt to access flash
00287             retval = NRF_SUCCESS;
00288         }
00289     }
00290     else if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
00291     {
00292         // Enqueue the command if it is queue is not full
00293         write_index = m_cmd_queue.rp + m_cmd_queue.count;
00294 
00295         if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
00296         {
00297             write_index -= PSTORAGE_CMD_QUEUE_SIZE;
00298         }
00299 
00300         m_cmd_queue.cmd[write_index].op_code      = opcode;
00301         m_cmd_queue.cmd[write_index].p_data_addr  = p_data_addr;
00302         m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
00303         m_cmd_queue.cmd[write_index].size         = size;
00304         m_cmd_queue.cmd[write_index].offset       = offset;
00305         m_cmd_queue.count++;
00306 
00307         retval = NRF_SUCCESS;
00308 
00309     }
00310 
00311     return retval;
00312 }
00313 
00314 
00315 /**
00316  * @brief Dequeues a command element.
00317  */
00318 static uint32_t cmd_queue_dequeue(void)
00319 {
00320     uint32_t retval;    
00321 
00322     cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00323     // Update count and read pointer to process any queued requests
00324     if(m_round_val >= p_cmd->size)
00325     {
00326         // Initialize/free the element as it is now processed.
00327         cmd_queue_init_element(m_cmd_queue.rp);
00328         m_round_val = 0;
00329         m_cmd_queue.count--;
00330         m_cmd_queue.rp++;
00331     }
00332 
00333     retval = NRF_SUCCESS;
00334 
00335     // If any flash operation is enqueued, schedule
00336     if (m_cmd_queue.count)
00337     {
00338         retval = process_cmd();
00339 
00340         if (retval != NRF_SUCCESS)
00341         {
00342             // Flash could be accessed by modules other than Bond Manager, hence a busy error is
00343             // acceptable, but any other error needs to be indicated to the bond manager
00344             if (retval != NRF_ERROR_BUSY)
00345             {
00346                 app_notify (retval);
00347             }
00348             else
00349             {
00350                 // In case of busy next trigger will be a success or a failure event
00351             }
00352         }
00353     }
00354     else
00355     {
00356         // No flash access request pending
00357     }
00358 
00359     return retval;
00360 }
00361 
00362 
00363 /**
00364  * @brief Routine to notify application of any errors.
00365  */
00366 static void app_notify (uint32_t result)
00367 {
00368     pstorage_ntf_cb_t  ntf_cb;
00369     uint8_t            op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
00370     
00371 #ifdef PSTORAGE_RAW_MODE_ENABLE
00372     if(m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == (PSTORAGE_MAX_APPLICATIONS + 1))
00373     {
00374         ntf_cb = m_raw_app_table.cb;
00375     }
00376     else
00377 #endif // PSTORAGE_RAW_MODE_ENABLE
00378     {
00379         ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb;
00380     }
00381 
00382     // Indicate result to client.
00383     // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally 
00384     // for clients registering multiple pages.
00385     ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
00386            op_code,
00387            result,
00388            m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
00389            op_code == PSTORAGE_CLEAR_OP_CODE ? 0 : m_cmd_queue.cmd[m_cmd_queue.rp].size);
00390 }
00391 
00392 
00393 /**
00394  * @brief Handles Flash Access Result Events.
00395  */
00396 void pstorage_sys_event_handler (uint32_t sys_evt)
00397 {
00398     uint32_t retval;
00399 
00400     retval = NRF_SUCCESS;
00401 
00402     // Its possible the flash access was not initiated by bond manager, hence
00403     // event is processed only if the event triggered was for an operation requested by the
00404     // bond manager.
00405     if (m_cmd_queue.flash_access == true)
00406     {
00407         cmd_queue_element_t * p_cmd;
00408         m_cmd_queue.flash_access = false;
00409         switch (sys_evt)
00410         {
00411             case NRF_EVT_FLASH_OPERATION_SUCCESS:
00412                 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00413                 if ((p_cmd->op_code != PSTORAGE_CLEAR_OP_CODE) || (m_round_val >= p_cmd->size))
00414                 {
00415                     app_notify(retval);
00416                 }
00417                 // Schedule any queued flash access operations
00418                 retval = cmd_queue_dequeue ();
00419                 if (retval != NRF_SUCCESS)
00420                 {
00421                     app_notify(retval);
00422                 }
00423 
00424                 break;
00425             case NRF_EVT_FLASH_OPERATION_ERROR:
00426                 app_notify(NRF_ERROR_TIMEOUT);
00427                 break;
00428             default:
00429                 // No implementation needed.
00430                 break;
00431         }
00432     }
00433 }
00434 
00435 
00436 /**
00437  * @brief Routine called to actually issue the flash access request to the SoftDevice.
00438  */
00439 static uint32_t process_cmd(void)
00440 {
00441     uint32_t             retval;
00442     uint32_t             storage_addr;
00443     cmd_queue_element_t * p_cmd;
00444 
00445     retval = NRF_ERROR_FORBIDDEN;
00446 
00447     p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00448 
00449     storage_addr = p_cmd->storage_addr.block_id;
00450 
00451     if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00452     {
00453         // Calculate page number before copy.
00454         uint32_t page_number;
00455 
00456         page_number =  ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) +
00457                         m_round_val);
00458 
00459         retval = sd_flash_page_erase(page_number);
00460 
00461         if (NRF_SUCCESS == retval)
00462         {
00463             m_round_val++;
00464         }
00465     }
00466     else if (p_cmd->op_code == PSTORAGE_STORE_OP_CODE)
00467     {
00468         uint32_t size;
00469         uint8_t * p_data_addr = p_cmd->p_data_addr;
00470     
00471         p_data_addr += m_round_val;
00472         
00473         storage_addr += (p_cmd->offset + m_round_val);
00474         
00475         size = p_cmd->size - m_round_val;
00476         
00477         if (size < SOC_MAX_WRITE_SIZE)
00478         {
00479             retval = sd_flash_write(((uint32_t *)storage_addr),
00480                                      (uint32_t *)p_data_addr,
00481                                      size / sizeof(uint32_t));
00482         }
00483         else
00484         {
00485             retval = sd_flash_write(((uint32_t *)storage_addr),
00486                                      (uint32_t *)p_data_addr,
00487                                      SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
00488         }
00489         
00490 
00491         if (retval == NRF_SUCCESS)
00492         {
00493             m_round_val += SOC_MAX_WRITE_SIZE;
00494         }
00495     }
00496     else
00497     {
00498         // Should never reach here.
00499     }
00500     
00501     if (retval == NRF_SUCCESS)
00502     {
00503        m_cmd_queue.flash_access = true;
00504     }
00505 
00506     return retval;
00507 }
00508 /** @} */
00509 
00510 
00511 /**
00512  * @brief Module initialization routine to be called once by the application.
00513  */
00514 uint32_t pstorage_init(void)
00515 {
00516     unsigned int index;
00517     cmd_queue_init();
00518     
00519     m_next_app_instance = 0;
00520     m_next_page_addr    = PSTORAGE_DATA_START_ADDR;    
00521     m_round_val         = 0;
00522 
00523     for(index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
00524     {
00525         m_app_table[index].cb          = NULL;
00526         m_app_table[index].block_size  = 0;
00527         m_app_table[index].no_of_pages = 0;
00528         m_app_table[index].block_count = 0;
00529     }
00530 
00531 #ifdef PSTORAGE_RAW_MODE_ENABLE
00532     m_raw_app_table.cb          = NULL;
00533     m_raw_app_table.no_of_pages = 0;
00534 #endif //PSTORAGE_RAW_MODE_ENABLE
00535     
00536     m_module_initialized = true;
00537     return NRF_SUCCESS;
00538 }
00539 
00540 /**
00541  * @brief Registration routine to request persistent memory of certain sizes based on
00542  *        application module requirements.
00543  */
00544 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
00545                            pstorage_handle_t       * p_block_id)
00546 {
00547     uint16_t page_count;
00548     uint32_t total_size;
00549 
00550     VERIFY_MODULE_INITIALIZED();
00551     NULL_PARAM_CHECK(p_module_param);
00552     NULL_PARAM_CHECK(p_block_id);
00553     NULL_PARAM_CHECK(p_module_param->cb);
00554     BLOCK_SIZE_CHECK(p_module_param->block_size);
00555     BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
00556 
00557     if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
00558     {
00559         return NRF_ERROR_NO_MEM;
00560     }
00561 
00562     p_block_id->module_id = m_next_app_instance;
00563     p_block_id->block_id = m_next_page_addr;
00564     m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
00565     m_app_table[m_next_app_instance].cb = p_module_param->cb;
00566     m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
00567     m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
00568 
00569     // Calculate number of flash pages allocated for the device.
00570     page_count = 0;
00571     total_size = p_module_param->block_size * p_module_param->block_count;
00572     do
00573     {
00574         page_count++;
00575         if (total_size > PSTORAGE_FLASH_PAGE_SIZE)
00576         {
00577             total_size -= PSTORAGE_FLASH_PAGE_SIZE;
00578         }
00579         else
00580         {
00581             total_size = 0;
00582         }
00583         m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
00584     }while(total_size >= PSTORAGE_FLASH_PAGE_SIZE);
00585 
00586     m_app_table[m_next_app_instance].no_of_pages = page_count;
00587     m_next_app_instance++;
00588 
00589     return NRF_SUCCESS;
00590 }
00591 
00592 
00593 /**
00594  * @brief API to get the next block identifier.
00595  */
00596 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
00597                                        pstorage_size_t   block_num,
00598                                        pstorage_handle_t * p_block_id)
00599 {
00600     pstorage_handle_t temp_id;
00601 
00602     VERIFY_MODULE_INITIALIZED();
00603     NULL_PARAM_CHECK(p_base_id);
00604     NULL_PARAM_CHECK(p_block_id);
00605     MODULE_ID_RANGE_CHECK(p_base_id);
00606 
00607     temp_id = (*p_base_id);
00608     temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
00609     BLOCK_ID_RANGE_CHECK(&temp_id);
00610     (*p_block_id) = temp_id;
00611 
00612     return NRF_SUCCESS;
00613 }
00614 
00615 
00616 /**
00617  * @brief API to store data persistently.
00618  */
00619 uint32_t pstorage_store(pstorage_handle_t * p_dest,
00620                         uint8_t           * p_src,
00621                         pstorage_size_t     size,
00622                         pstorage_size_t     offset)
00623 {
00624     VERIFY_MODULE_INITIALIZED();
00625     NULL_PARAM_CHECK(p_src);
00626     NULL_PARAM_CHECK(p_dest);
00627     MODULE_ID_RANGE_CHECK (p_dest);
00628     BLOCK_ID_RANGE_CHECK(p_dest);
00629     SIZE_CHECK(p_dest,size);
00630     OFFSET_CHECK(p_dest,offset,size);
00631 
00632     // Verify word alignment.
00633     if ((!is_word_aligned(p_src)) || (!is_word_aligned(p_src+offset)))
00634     {
00635         return NRF_ERROR_INVALID_ADDR;
00636     }
00637 
00638     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
00639 }
00640 
00641 
00642 /**
00643  * @brief API to load data from persistent memory.
00644  */
00645 uint32_t pstorage_load(uint8_t           * p_dest,
00646                        pstorage_handle_t * p_src,
00647                        pstorage_size_t     size,
00648                        pstorage_size_t     offset)
00649 {
00650     VERIFY_MODULE_INITIALIZED();
00651     NULL_PARAM_CHECK(p_src);
00652     NULL_PARAM_CHECK(p_dest);
00653     MODULE_ID_RANGE_CHECK (p_src);
00654     BLOCK_ID_RANGE_CHECK(p_src);
00655     SIZE_CHECK(p_src,size);
00656     OFFSET_CHECK(p_src,offset,size);
00657 
00658     // Verify word alignment.
00659     if ((!is_word_aligned (p_dest)) || (!is_word_aligned (p_dest + offset)))
00660     {
00661         return NRF_ERROR_INVALID_ADDR;
00662     }
00663 
00664     memcpy (p_dest, (((uint8_t *)p_src->block_id) + offset), size);
00665 
00666     return NRF_SUCCESS;
00667 }
00668 
00669 
00670 /**
00671  * @brief API to clear data in blocks of persistent memory.
00672  */
00673 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
00674 {
00675     uint32_t retval;
00676     uint32_t pages;
00677 
00678     VERIFY_MODULE_INITIALIZED();
00679     NULL_PARAM_CHECK(p_dest);
00680     MODULE_ID_RANGE_CHECK(p_dest);
00681     BLOCK_ID_RANGE_CHECK(p_dest);
00682 
00683     pages = m_app_table[p_dest->module_id].no_of_pages;
00684 
00685     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL , pages , 0);
00686 
00687     return retval;
00688 }
00689 
00690 
00691 #ifdef PSTORAGE_RAW_MODE_ENABLE
00692 
00693 /**
00694  * @brief Registration routine to request persistent memory of certain sizes based on 
00695  *        application module requirements.
00696  */
00697 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
00698                                pstorage_handle_t       * p_block_id)
00699 {
00700     VERIFY_MODULE_INITIALIZED();
00701     NULL_PARAM_CHECK(p_module_param);
00702     NULL_PARAM_CHECK(p_block_id);
00703     NULL_PARAM_CHECK(p_module_param->cb);
00704 
00705     if (m_raw_app_table.cb != NULL)
00706     {
00707         return NRF_ERROR_NO_MEM;
00708     }
00709 
00710     p_block_id->module_id = PSTORAGE_MAX_APPLICATIONS + 1;
00711     m_raw_app_table.cb    = p_module_param->cb;
00712 
00713     return NRF_SUCCESS;
00714 }
00715 
00716 
00717 /**
00718  * @brief API to store data persistently.
00719  */
00720 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
00721                             uint8_t           * p_src,
00722                             uint32_t            size,
00723                             uint32_t            offset)
00724 {
00725     VERIFY_MODULE_INITIALIZED();
00726     NULL_PARAM_CHECK(p_src);
00727     NULL_PARAM_CHECK(p_dest);
00728     MODULE_RAW_ID_RANGE_CHECK(p_dest);
00729 
00730     // Verify word alignment.
00731     if ((!is_word_aligned(p_src)) || (!is_word_aligned(p_src+offset)))
00732     {
00733         return NRF_ERROR_INVALID_ADDR;
00734     }
00735 
00736     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
00737 }
00738 
00739 
00740 /**
00741  * @brief API to clear data in blocks of persistent memory.
00742  */
00743 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, uint32_t size)
00744 {
00745     uint32_t retval;
00746     uint32_t pages;
00747 
00748     VERIFY_MODULE_INITIALIZED();
00749     NULL_PARAM_CHECK(p_dest);
00750     MODULE_RAW_ID_RANGE_CHECK(p_dest);
00751 
00752     retval = NRF_SUCCESS;
00753 
00754     pages = CEIL_DIV(size, PSTORAGE_FLASH_PAGE_SIZE);
00755     
00756     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL , pages, 0);
00757 
00758     return retval;
00759 }
00760 
00761 #endif // PSTORAGE_RAW_MODE_ENABLE
00762 #endif /* #if NEED_PSTORAGE */