Nordic stack and drivers for the mbed BLE API. Version to work around build bug.

Dependents:   microbit_rubber_ducky microbit_mouse_BLE microbit_mouse_BLE_daybreak_version microbit_presenter

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pstorage.c Source File

pstorage.c

00001 /*
00002  * Copyright (c) Nordic Semiconductor ASA
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  *   1. Redistributions of source code must retain the above copyright notice, this
00009  *   list of conditions and the following disclaimer.
00010  *
00011  *   2. Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  *   3. Neither the name of Nordic Semiconductor ASA nor the names of other
00016  *   contributors to this software may be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 #include "pstorage.h "
00034 #include <stdlib.h>
00035 #include <stdint.h>
00036 #include <string.h>
00037 #include "nordic_common.h"
00038 #include "nrf_error.h"
00039 #include "nrf_assert.h"
00040 #include "nrf.h"
00041 #include "nrf_soc.h"
00042 #include "app_util.h "
00043 #include "app_error.h "
00044 
00045 #define INVALID_OPCODE             0x00                                /**< Invalid op code identifier. */
00046 #define SOC_MAX_WRITE_SIZE         PSTORAGE_FLASH_PAGE_SIZE            /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
00047 #define RAW_MODE_APP_ID            (PSTORAGE_NUM_OF_PAGES + 1)         /**< Application id for raw mode. */
00048 
00049 #if defined(NRF52)
00050 #define SD_CMD_MAX_TRIES           1000                                /**< Number of times to try a softdevice flash operatoion, specific for nRF52 to account for longest time of flash page erase*/
00051 #else
00052 #define SD_CMD_MAX_TRIES           3                                   /**< Number of times to try a softdevice flash operation when the @ref NRF_EVT_FLASH_OPERATION_ERROR sys_evt is received. */
00053 #endif /* defined(NRF52) */
00054 
00055 #define MASK_TAIL_SWAP_DONE        (1 << 0)                            /**< Flag for checking if the tail restore area has been written to swap page. */     
00056 #define MASK_SINGLE_PAGE_OPERATION (1 << 1)                            /**< Flag for checking if command is a single flash page operation. */
00057 #define MASK_MODULE_INITIALIZED    (1 << 2)                            /**< Flag for checking if the module has been initialized. */
00058 #define MASK_FLASH_API_ERR_BUSY    (1 << 3)                            /**< Flag for checking if flash API returned NRF_ERROR_BUSY. */
00059 
00060 /**
00061  * @defgroup api_param_check API Parameters check macros.
00062  *
00063  * @details Macros that verify parameters passed to the module in the APIs. These macros
00064  *          could be mapped to nothing in final code versions to save execution and size.
00065  *
00066  * @{
00067  */
00068 
00069 /**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL.
00070  */
00071 #define NULL_PARAM_CHECK(PARAM)                                                                   \
00072         if ((PARAM) == NULL)                                                                      \
00073         {                                                                                         \
00074             return NRF_ERROR_NULL;                                                                \
00075         }
00076 
00077 /**@brief Verifies that the module identifier supplied by the application is within permissible
00078  *        range.
00079  */
00080 #define MODULE_ID_RANGE_CHECK(ID)                                                                 \
00081         if ((((ID)->module_id) >= PSTORAGE_NUM_OF_PAGES) ||                                       \
00082             (m_app_table[(ID)->module_id].cb == NULL))                                            \
00083         {                                                                                         \
00084             return NRF_ERROR_INVALID_PARAM;                                                       \
00085         }
00086 
00087 /**@brief Verifies that the block identifier supplied by the application is within the permissible
00088  *        range.
00089  */
00090 #define BLOCK_ID_RANGE_CHECK(ID)                                                                  \
00091         if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id +                           \
00092             (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID))))                  \
00093         {                                                                                         \
00094             return NRF_ERROR_INVALID_PARAM;                                                       \
00095         }
00096 
00097 /**@brief Verifies that the block size requested by the application can be supported by the module.
00098  */
00099 #define BLOCK_SIZE_CHECK(X)                                                                       \
00100         if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE))                   \
00101         {                                                                                         \
00102             return NRF_ERROR_INVALID_PARAM;                                                       \
00103         }
00104 
00105 /**@brief Verifies the block size requested by the application in registration API.
00106  */
00107 #define BLOCK_COUNT_CHECK(COUNT, SIZE)                                                            \
00108         if (((COUNT) == 0) ||                                                                     \
00109             ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)))                        \
00110         {                                                                                         \
00111             return NRF_ERROR_INVALID_PARAM;                                                       \
00112         }        
00113 
00114 /**@brief Verifies the size parameter provided by the application in API.
00115  */
00116 #define SIZE_CHECK(ID, SIZE)                                                                      \
00117         if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID)))                                     \
00118         {                                                                                         \
00119             return NRF_ERROR_INVALID_PARAM;                                                       \
00120         }
00121 
00122 /**@brief Verifies the offset parameter provided by the application in API.
00123  */
00124 #define OFFSET_CHECK(ID, OFFSET, SIZE)                                                            \
00125         if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID))                                           \
00126         {                                                                                         \
00127             return NRF_ERROR_INVALID_PARAM;                                                       \
00128         }
00129 
00130 #ifdef PSTORAGE_RAW_MODE_ENABLE
00131 
00132 /**@brief Verifies the module identifier supplied by the application.
00133  */
00134 #define MODULE_RAW_HANDLE_CHECK(ID)                                                               \
00135         if ((((ID)->module_id) != RAW_MODE_APP_ID))                                               \
00136         {                                                                                         \
00137             return NRF_ERROR_INVALID_PARAM;                                                       \
00138         }
00139 
00140 #endif // PSTORAGE_RAW_MODE_ENABLE
00141 
00142 /**@} */
00143 
00144 
00145 /**@brief Verify module's initialization status.
00146  *
00147  * @details  Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE when a
00148  *           module API is called without initializing the module.
00149  */
00150 #define VERIFY_MODULE_INITIALIZED()                                                               \
00151         do                                                                                        \
00152         {                                                                                         \
00153             if (!(m_flags & MASK_MODULE_INITIALIZED))                                             \
00154             {                                                                                     \
00155                  return NRF_ERROR_INVALID_STATE;                                                  \
00156             }                                                                                     \
00157         } while(0)
00158 
00159 /**@brief Macro to fetch the block size registered for the module. */
00160 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
00161 
00162 /**@brief Main state machine of the component. */
00163 typedef enum
00164 {
00165     STATE_IDLE,                                                        /**< State for being idle (no command execution in progress). */
00166     STATE_STORE,                                                       /**< State for storing data when using store/update API. */
00167     STATE_DATA_ERASE_WITH_SWAP,                                        /**< State for erasing the data page when using update/clear API when use of swap page is required. */
00168     STATE_DATA_ERASE,                                                  /**< State for erasing the data page when using update/clear API without the need to use the swap page. */
00169     STATE_ERROR                                                        /**< State entered when command processing is terminated abnormally. */
00170 } pstorage_state_t;  
00171 
00172 /**@brief Sub state machine contained by @ref STATE_DATA_ERASE_WITH_SWAP super state machine. */
00173 typedef enum
00174 {
00175     STATE_ERASE_SWAP,                                                  /**< State for erasing the swap page when using the update/clear API. */   
00176     STATE_WRITE_DATA_TO_SWAP,                                          /**< State for writing the data page into the swap page when using update/clear API. */
00177     STATE_ERASE_DATA_PAGE,                                             /**< State for erasing data page when using update/clear API. */
00178     STATE_RESTORE_TAIL,                                                /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
00179     STATE_RESTORE_HEAD,                                                /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
00180     SWAP_SUB_STATE_MAX                                                 /**< Enumeration upper bound. */   
00181 } flash_swap_sub_state_t;
00182 
00183 /**@brief Application registration information.
00184  *
00185  * @details Defines application specific information that the application needs to maintain to be able 
00186  *          to process requests from each one of them.
00187  */
00188 typedef struct
00189 {
00190     pstorage_ntf_cb_t cb;                                              /**< Callback registered with the module to be notified of result of flash access.  */
00191     pstorage_block_t  base_id;                                         /**< Base block ID assigned to the module. */
00192     pstorage_size_t   block_size;                                      /**< Size of block for the module. */
00193     pstorage_size_t   block_count;                                     /**< Number of blocks requested by the application. */
00194 } pstorage_module_table_t;
00195 
00196 
00197 #ifdef PSTORAGE_RAW_MODE_ENABLE
00198 /**@brief Application registration information.
00199  *
00200  * @details Defines application specific information that the application registered for raw mode.
00201  */
00202 typedef struct
00203 {
00204     pstorage_ntf_cb_t cb;                                              /**< Callback registered with the module to be notified of the result of flash access.  */
00205 } pstorage_raw_module_table_t;
00206 #endif // PSTORAGE_RAW_MODE_ENABLE
00207 
00208 
00209 /**@brief Defines command queue element.
00210  *
00211  * @details Defines command queue element. Each element encapsulates needed information to process
00212  *          a flash access command.
00213  */
00214 typedef struct
00215 {
00216     uint8_t           op_code;                                         /**< Identifies the flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
00217     pstorage_size_t   size;                                            /**< Identifies the size in bytes requested for the operation. */
00218     pstorage_size_t   offset;                                          /**< Offset requested by the application for the access operation. */
00219     pstorage_handle_t storage_addr;                                    /**< Address/Identifier for persistent memory. */
00220     uint8_t *         p_data_addr;                                     /**< Address/Identifier for data memory. This is assumed to be resident memory. */
00221 } cmd_queue_element_t;
00222 
00223 
00224 /**@brief   Defines command queue, an element is free if the op_code field is not invalid.
00225  *
00226  * @details Defines commands enqueued for flash access. At any point in time, this queue has one or
00227  *          more flash access operations pending if the count field is not zero. When the queue is
00228  *          not empty, the rp (read pointer) field points to the flash access command in progress 
00229  *          or, if none is in progress, the command to be requested next. The queue implements a 
00230  *          simple first in first out algorithm. Data addresses are assumed to be resident.
00231  */
00232 typedef struct
00233 {
00234     uint8_t             rp;                                            /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
00235     uint8_t             count;                                         /**< Number of elements in the queue.  */
00236     cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE];                  /**< Array to maintain flash access operation details. */
00237 } cmd_queue_t;
00238 
00239 static cmd_queue_t             m_cmd_queue;                            /**< Flash operation request queue. */
00240 static pstorage_size_t         m_next_app_instance;                    /**< Points to the application module instance that can be allocated next. */
00241 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 that can span across flash pages. */
00242 static pstorage_state_t        m_state;                                /**< Main state tracking variable. */
00243 static flash_swap_sub_state_t  m_swap_sub_state;                       /**< Flash swap erase when swap used state tracking variable. */
00244 static uint32_t                m_head_word_size;                       /**< Head restore area size in words. */
00245 static uint32_t                m_tail_word_size;                       /**< Tail restore area size in words. */
00246 static uint32_t                m_current_page_id;                      /**< Variable for tracking the flash page being processed. */
00247 static uint32_t                m_num_of_command_retries;               /**< Variable for tracking flash operation retries upon flash operation failures. */
00248 static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES];     /**< Registered application information table. */
00249 static uint32_t                m_num_of_bytes_written;                 /**< Variable for tracking the number of bytes written by the store operation. */
00250 static uint32_t                m_app_data_size;                        /**< Variable for storing the application command size parameter internally. */
00251 static uint32_t                m_flags = 0;                            /**< Storage for boolean flags for state tracking. */
00252 
00253 #ifdef PSTORAGE_RAW_MODE_ENABLE
00254 static pstorage_raw_module_table_t m_raw_app_table;                    /**< Registered application information table for raw mode. */
00255 #endif // PSTORAGE_RAW_MODE_ENABLE
00256 
00257 // Required forward declarations.
00258 static void cmd_process(void);
00259 static void store_operation_execute(void);
00260 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem);
00261 static void cmd_queue_element_init(uint32_t index);
00262 static void cmd_queue_dequeue(void);
00263 static void sm_state_change(pstorage_state_t new_state);
00264 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state); 
00265 
00266 /**@brief Function for consuming a command queue element.
00267  *
00268  * @details Function for consuming a command queue element, which has been fully processed.
00269  */
00270 static void command_queue_element_consume(void)
00271 {
00272     // Initialize/free the element as it is now processed.    
00273     cmd_queue_element_init(m_cmd_queue.rp);
00274 
00275     // Adjust command queue state tracking variables.
00276     --(m_cmd_queue.count);   
00277     if (++(m_cmd_queue.rp) == PSTORAGE_CMD_QUEUE_SIZE)
00278     {
00279         m_cmd_queue.rp = 0;
00280     }    
00281 }
00282 
00283 
00284 /**@brief Function for executing the finalization procedure for the command executed.
00285  *
00286  * @details Function for executing the finalization procedure for command executed, which includes 
00287  *          notifying the application of command completion, consuming the command queue element, 
00288  *          and changing the internal state.
00289  */
00290 static void command_end_procedure_run(void)
00291 {    
00292     app_notify(NRF_SUCCESS, &m_cmd_queue.cmd[m_cmd_queue.rp]);
00293     
00294     command_queue_element_consume();
00295     
00296     sm_state_change(STATE_IDLE);
00297 }
00298 
00299 
00300 /**@brief Function for idle state entry actions.
00301  *
00302  * @details Function for idle state entry actions, which include resetting relevant state data and 
00303  *          scheduling any possible queued flash access operation.
00304  */
00305 static void state_idle_entry_run(void)
00306 {
00307     m_num_of_command_retries = 0;
00308     m_num_of_bytes_written   = 0;
00309     
00310     // Schedule any possible queued flash access operation.
00311     cmd_queue_dequeue();
00312 }
00313 
00314 
00315 /**@brief Function for notifying an application of command completion and transitioning to an error 
00316  *        state.
00317  *
00318  * @param[in] result Result code of the operation for the application.
00319  */
00320 static void app_notify_error_state_transit(uint32_t result)
00321 {
00322     app_notify(result, &m_cmd_queue.cmd[m_cmd_queue.rp]);
00323     sm_state_change(STATE_ERROR);                
00324 }
00325 
00326 
00327 /**@brief Function for processing flash API error code.
00328  *
00329  * @param[in] err_code Error code from the flash API.
00330  */
00331 static void flash_api_err_code_process(uint32_t err_code)
00332 {
00333     switch (err_code)
00334     {
00335         case NRF_SUCCESS:
00336             break;
00337             
00338         case NRF_ERROR_BUSY:
00339             // Flash access operation was not accepted and must be reissued upon flash operation 
00340             // complete event.
00341             m_flags |= MASK_FLASH_API_ERR_BUSY;        
00342             break;
00343             
00344         default:
00345             // Complete the operation with appropriate result code and transit to an error state. 
00346             app_notify_error_state_transit(err_code);
00347             break;
00348     }
00349 }
00350 
00351 /**@brief Function for writing data to flash.
00352  *
00353  * @param[in] p_dst         Pointer to start of flash location to be written.
00354  * @param[in] p_src         Pointer to buffer with data to be written.
00355  * @param[in] size_in_words Number of 32-bit words to write. 
00356  */
00357 static void flash_write(uint32_t * const       p_dst, 
00358                         uint32_t const * const p_src, 
00359                         uint32_t               size_in_words)
00360 {
00361     flash_api_err_code_process(sd_flash_write(p_dst, p_src, size_in_words));    
00362 }
00363 
00364 
00365 /**@brief Function for writing data to flash upon store command.
00366  *
00367  * @details Function for writing data to flash upon executing store command. Data is written to 
00368  *          flash in reverse order, meaning starting at the end. If the data that is to be written 
00369  *          is greater than the flash page size, it will be fragmented to fit the flash page size.
00370  */
00371 static void store_cmd_flash_write_execute(void)
00372 {
00373     const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00374     
00375     if (p_cmd->size > SOC_MAX_WRITE_SIZE)    
00376     {
00377         const uint32_t offset = p_cmd->size - PSTORAGE_FLASH_PAGE_SIZE;
00378         flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset + offset),
00379                     (uint32_t *)(p_cmd->p_data_addr + offset), 
00380                     PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));   
00381 
00382         m_num_of_bytes_written = PSTORAGE_FLASH_PAGE_SIZE;    
00383     }
00384     else
00385     {
00386         flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset),
00387                     (uint32_t *)(p_cmd->p_data_addr), 
00388                     p_cmd->size / sizeof(uint32_t));   
00389 
00390         m_num_of_bytes_written = p_cmd->size;        
00391     }    
00392 }
00393 
00394 
00395 /**@brief Function for store state entry action.
00396  *
00397  * @details Function for store state entry action, which includes writing data to a flash page.
00398  */
00399 static void state_store_entry_run(void)
00400 {
00401     store_cmd_flash_write_execute();    
00402 }
00403 
00404 
00405 /**@brief Function for data erase with swap state entry actions.
00406  *
00407  * @details Function for data erase with swap state entry actions. This includes adjusting relevant 
00408  *          state and data variables and transitioning to the correct sub state.
00409  */
00410 static void state_data_erase_swap_entry_run(void)
00411 {
00412     m_flags &= ~MASK_TAIL_SWAP_DONE;
00413     
00414     const cmd_queue_element_t * p_cmd        = &m_cmd_queue.cmd[m_cmd_queue.rp];
00415     const pstorage_block_t      cmd_block_id = p_cmd->storage_addr.block_id;
00416     
00417     const uint32_t clear_start_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
00418     m_current_page_id                  = clear_start_page_id;      
00419         
00420     // @note: No need to include p_cmd->offset when calculating clear_end_page_id as:
00421     // - clear API does not include offset parameter
00422     // - update and store APIs are limited to operate on single block boundary thus the boolean 
00423     // clause ((m_head_word_size == 0) && is_more_than_one_page) below in this function  will never 
00424     // evaluate as true as if is_more_than_one_page == true m_head_word_size is always != 0        
00425     const uint32_t clear_end_page_id  = (cmd_block_id + p_cmd->size - 1u) / 
00426                                         PSTORAGE_FLASH_PAGE_SIZE;
00427 
00428     if (clear_start_page_id == clear_end_page_id)
00429     {
00430         m_flags |= MASK_SINGLE_PAGE_OPERATION;
00431     }
00432     else
00433     {
00434         m_flags &= ~MASK_SINGLE_PAGE_OPERATION;
00435     }
00436                             
00437     if ((m_head_word_size == 0) && !(m_flags & MASK_SINGLE_PAGE_OPERATION))
00438     {        
00439         // No head restore required and clear/update area is shared by multiple flash pages, which 
00440         // means the current flash page does not have any tail area to restore. You can proceed with 
00441         // data page erase directly as no swap is needed for the current flash page.
00442         swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);        
00443     }
00444     else
00445     {     
00446         swap_sub_state_state_change(STATE_ERASE_SWAP);
00447     }               
00448 }
00449 
00450 
00451 /**@brief Function for erasing flash page.
00452  *
00453  * @param[in] page_number Page number of the page to be erased.
00454  */
00455 static void flash_page_erase(uint32_t page_number)
00456 {
00457     flash_api_err_code_process(sd_flash_page_erase(page_number));
00458 }
00459 
00460 
00461 /**@brief Function for data erase state entry action.
00462  *
00463  * @details Function for data erase state entry action, which includes erasing the data flash page.
00464  */
00465 static void state_data_erase_entry_run(void)
00466 {
00467     flash_page_erase(m_current_page_id);                          
00468 }
00469 
00470 
00471 /**@brief Function for dispatching the correct application main state entry action.
00472  */
00473 static void state_entry_action_run(void)
00474 {
00475     switch (m_state)
00476     {
00477         case STATE_IDLE:
00478             state_idle_entry_run();
00479             break;
00480 
00481         case STATE_STORE:
00482             state_store_entry_run();
00483             break;
00484             
00485         case STATE_DATA_ERASE_WITH_SWAP:
00486             state_data_erase_swap_entry_run();
00487             break;
00488             
00489         case STATE_DATA_ERASE:
00490             state_data_erase_entry_run();        
00491             break;
00492                         
00493         default:
00494             // No action needed.
00495             break;
00496     }
00497 }
00498 
00499 
00500 /**@brief Function for changing application main state and dispatching state entry action.
00501  *
00502  * @param[in] new_state New application main state to transit to.
00503  */
00504 static void sm_state_change(pstorage_state_t new_state)
00505 {
00506     m_state = new_state;
00507     state_entry_action_run();
00508 }
00509 
00510 
00511 /**@brief Function for swap erase state entry action.
00512  *
00513  * @details Function for swap erase state entry action, which includes erasing swap flash 
00514  *          page.
00515  */
00516 static void state_swap_erase_entry_run(void)
00517 {
00518     flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);                
00519 }
00520 
00521 
00522 /**@brief Function for write data to the swap state entry action.
00523  *
00524  * @details Function for write data to the swap state entry action, which includes writing the 
00525  *          current data page to the swap flash page.
00526  */
00527 static void state_write_data_swap_entry_run(void)
00528 {
00529     // @note: There is room for further optimization here as there is only need to write the
00530     // whole flash page to swap area if there is both head and tail area to be restored. In any 
00531     // other case we can omit some data from the head or end of the page as that is the clear area.
00532     flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR), 
00533                 (uint32_t *)(m_current_page_id * PSTORAGE_FLASH_PAGE_SIZE), 
00534                 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));    
00535 }
00536 
00537 
00538 /**@brief Function for erase data page state entry action.
00539  *
00540  * @details Function for erase data page state entry action, which includes erasing the data flash 
00541  *          page.
00542  */
00543 static void state_erase_data_page_entry_run(void)
00544 {
00545     flash_page_erase(m_current_page_id);
00546 }
00547 
00548 
00549 /**@brief Function for restore tail state entry action.
00550  *
00551  * @details Function for restore tail state entry action, which includes writing the tail section 
00552  *          back from swap to the data page.
00553  */
00554 static void state_restore_tail_entry_run(void)
00555 {
00556     const cmd_queue_element_t * p_cmd        = &m_cmd_queue.cmd[m_cmd_queue.rp];    
00557     const pstorage_block_t      cmd_block_id = p_cmd->storage_addr.block_id;                            
00558     
00559     const uint32_t tail_offset = (cmd_block_id + p_cmd->size + p_cmd->offset) % 
00560                                  PSTORAGE_FLASH_PAGE_SIZE; 
00561                                  
00562     flash_write((uint32_t *)(cmd_block_id + p_cmd->size + p_cmd->offset),
00563                 (uint32_t *)(PSTORAGE_SWAP_ADDR + tail_offset),
00564                 m_tail_word_size);
00565 }
00566 
00567 
00568 /**@brief Function for restore head state entry action.
00569  *
00570  * @details Function for restore head state entry action, which includes writing the head section 
00571  *          back from swap to the data page.
00572  */
00573 static void state_restore_head_entry_run(void)
00574 {
00575     flash_write((uint32_t *)((m_current_page_id - 1u) * PSTORAGE_FLASH_PAGE_SIZE),
00576                 (uint32_t *)PSTORAGE_SWAP_ADDR,
00577                 m_head_word_size);
00578 }
00579 
00580 
00581 /**@brief Function for dispatching the correct swap sub state entry action.
00582  */
00583 static void swap_sub_state_entry_action_run(void)
00584 {
00585     static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) = 
00586     {
00587         state_swap_erase_entry_run,
00588         state_write_data_swap_entry_run,
00589         state_erase_data_page_entry_run,
00590         state_restore_tail_entry_run,
00591         state_restore_head_entry_run
00592     };
00593     
00594     swap_sub_state_sm_lut[m_swap_sub_state]();
00595 }
00596 
00597 
00598 /**@brief Function for changing the swap sub state and dispatching state entry action.
00599  *
00600  * @param[in] new_state New swap sub state to transit to.
00601  */   
00602 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state)
00603 {
00604     m_swap_sub_state = new_state;
00605     swap_sub_state_entry_action_run();    
00606 }
00607 
00608 
00609 /**@brief Function for initializing the command queue element.
00610  *
00611  * @param[in] index Index of the element to be initialized.
00612  */
00613 static void cmd_queue_element_init(uint32_t index)
00614 {
00615     // Internal function and checks on range of index can be avoided.
00616     m_cmd_queue.cmd[index].op_code                = INVALID_OPCODE;
00617     m_cmd_queue.cmd[index].size                   = 0;
00618     m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_NUM_OF_PAGES;
00619     m_cmd_queue.cmd[index].storage_addr.block_id  = 0;
00620     m_cmd_queue.cmd[index].p_data_addr            = NULL;
00621     m_cmd_queue.cmd[index].offset                 = 0;
00622 }
00623 
00624 
00625 /**@brief Function for initializing the command queue.
00626  */
00627 static void cmd_queue_init(void)
00628 {
00629     m_cmd_queue.rp    = 0;
00630     m_cmd_queue.count = 0;
00631 
00632     for (uint32_t cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; ++cmd_index)
00633     {
00634         cmd_queue_element_init(cmd_index);
00635     }
00636 }
00637 
00638 
00639 /**@brief Function for enqueuing, and possibly dispatching, a flash access operation.
00640  *
00641  * @param[in] opcode         Identifies the operation requested to be enqueued.
00642  * @param[in] p_storage_addr Identifies the module and flash address on which the operation is 
00643  *                           requested.
00644  * @param[in] p_data_addr    Identifies the data address for flash access.
00645  * @param[in] size           Size in bytes of data requested for the access operation.
00646  * @param[in] offset         Offset within the flash memory block at which operation is requested.
00647  *
00648  * @retval    NRF_SUCCESS      Upon success.
00649  * @retval    NRF_ERROR_NO_MEM Upon failure, when no space is available in the command queue. 
00650  */
00651 static uint32_t cmd_queue_enqueue(uint8_t             opcode,
00652                                   pstorage_handle_t * p_storage_addr,
00653                                   uint8_t           * p_data_addr,
00654                                   pstorage_size_t     size,
00655                                   pstorage_size_t     offset)
00656 {
00657     uint32_t err_code;
00658 
00659     if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
00660     {
00661         // Enqueue the command if it the queue is not full.
00662         uint32_t write_index = m_cmd_queue.rp + m_cmd_queue.count;
00663 
00664         if (write_index >= PSTORAGE_CMD_QUEUE_SIZE) 
00665         {
00666             write_index -= PSTORAGE_CMD_QUEUE_SIZE;
00667         }
00668 
00669         m_cmd_queue.cmd[write_index].op_code      = opcode;
00670         m_cmd_queue.cmd[write_index].p_data_addr  = p_data_addr;
00671         m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
00672         m_cmd_queue.cmd[write_index].size         = size;
00673         m_cmd_queue.cmd[write_index].offset       = offset;
00674                
00675         m_cmd_queue.count++;
00676                                 
00677         if (m_state == STATE_IDLE)
00678         {
00679             cmd_process(); 
00680         }            
00681         
00682         err_code = NRF_SUCCESS;        
00683     }
00684     else
00685     {
00686         err_code = NRF_ERROR_NO_MEM;
00687     }
00688 
00689     return err_code;
00690 }
00691 
00692 
00693 /**@brief Function for dequeing a possible pending flash access operation.
00694  */
00695 static void cmd_queue_dequeue(void)
00696 {
00697     if ((m_cmd_queue.count != 0)) 
00698     {
00699         cmd_process();
00700     }
00701 }
00702 
00703 
00704 /**@brief Function for notifying an application of command completion.
00705  *
00706  * @param[in] result Result code of the operation for the application.
00707  * @param[in] p_elem Pointer to the command queue element for which this result was received. 
00708  */
00709 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem)
00710 {
00711     pstorage_ntf_cb_t ntf_cb;
00712     const uint8_t     op_code = p_elem->op_code;
00713 
00714 #ifdef PSTORAGE_RAW_MODE_ENABLE
00715     if (p_elem->storage_addr.module_id == RAW_MODE_APP_ID)
00716     {
00717         ntf_cb = m_raw_app_table.cb;
00718     }
00719     else
00720 #endif // PSTORAGE_RAW_MODE_ENABLE
00721     {
00722         ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb;
00723     }
00724 
00725     ntf_cb(&p_elem->storage_addr, op_code, result, p_elem->p_data_addr, m_app_data_size);
00726 }
00727 
00728 
00729 /**@brief Function for evaluating if a data page swap is required for the tail section on the 
00730  *        current page.
00731  *
00732  * @retval true  If data page swap is required.
00733  * @retval false If data page swap is not required.
00734  */
00735 static bool is_tail_data_page_swap_required(void)
00736 {
00737     bool ret_value;
00738 
00739     // Extract id of the last page command is executed upon.
00740     const cmd_queue_element_t * p_cmd        = &m_cmd_queue.cmd[m_cmd_queue.rp];
00741     const pstorage_block_t      cmd_block_id = p_cmd->storage_addr.block_id;        
00742     const uint32_t              last_page_id = (cmd_block_id + p_cmd->size + p_cmd->offset - 1u) / 
00743                                                PSTORAGE_FLASH_PAGE_SIZE;    
00744         
00745     // If tail section area exists and the current page is the last page then tail data page swap is 
00746     // required.    
00747     if ((m_tail_word_size != 0) && (m_current_page_id == last_page_id))
00748     {
00749         ret_value = true;
00750     }
00751     else
00752     {
00753         ret_value = false;    
00754     }
00755     
00756     return ret_value;
00757 }
00758 
00759 
00760 /**@brief Function for performing post processing for the update and clear commands.
00761  *
00762  * @details Function for performing post processing for the update and clear commands, which implies 
00763  *          executing the correct execution path depending on the command. 
00764  */
00765 static void clear_post_processing_run(void)
00766 {
00767     const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 
00768     
00769     if (p_cmd->op_code != PSTORAGE_UPDATE_OP_CODE)
00770     {
00771         command_end_procedure_run();    
00772     }
00773     else
00774     {
00775         store_operation_execute();                    
00776     }
00777 }
00778 
00779 
00780 /**@brief Function for doing swap sub state exit action.
00781  */
00782 static void swap_sub_sm_exit_action_run(void)
00783 {
00784     clear_post_processing_run();
00785 }
00786 
00787 
00788 /**@brief Function for evaluating if the page erase operation is required for the current page.
00789  *
00790  * @retval true  If page erase is required.
00791  * @retval false If page erase is not required. 
00792  */
00793 static bool is_page_erase_required(void)
00794 {
00795     bool ret;
00796     
00797     const cmd_queue_element_t * p_cmd                      = &m_cmd_queue.cmd[m_cmd_queue.rp];
00798     const pstorage_block_t      cmd_block_id               = p_cmd->storage_addr.block_id;        
00799     const uint32_t              id_last_page_to_be_cleared = (cmd_block_id + p_cmd->size + 
00800                                                              p_cmd->offset - 1u) / 
00801                                                              PSTORAGE_FLASH_PAGE_SIZE;
00802 
00803     // True if:
00804     // - current page is not the last page OR
00805     // - current page is the last page AND no tail exists
00806     if ((m_current_page_id < id_last_page_to_be_cleared) ||
00807         ((m_current_page_id == id_last_page_to_be_cleared) && (m_tail_word_size == 0)))         
00808     {
00809         ret = true;
00810     }
00811     else
00812     {
00813         ret = false;
00814     }
00815     
00816     return ret;
00817 }
00818 
00819 
00820 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash 
00821  *        API, in swap sub sate.
00822  */
00823 static void swap_sub_state_err_busy_process(void)
00824 {
00825     // Reissue the request by doing a self transition to the current state.    
00826     m_flags &= ~MASK_FLASH_API_ERR_BUSY;
00827     swap_sub_state_state_change(m_swap_sub_state);        
00828 }
00829 
00830 
00831 /**@brief Function for doing restore head state action upon flash operation success event.
00832  *
00833  * @details Function for doing restore head state action upon flash operation success event, which 
00834  *          includes making a state transition depending on the current state.
00835  */
00836 static void head_restore_state_run(void)
00837 {
00838     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
00839     {            
00840         if (is_tail_data_page_swap_required())
00841         {
00842             // Additional data page needs to be swapped for tail section as we are clearing a block, 
00843             // which is shared between 2 flash pages.
00844                     
00845             // Adjust variables to ensure correct state transition path is taken after the tail 
00846             // section swap has completed.
00847             m_head_word_size = 0;   
00848             m_flags         |= MASK_TAIL_SWAP_DONE;        
00849                   
00850             swap_sub_state_state_change(STATE_ERASE_SWAP);        
00851         }
00852         else if (is_page_erase_required())
00853         {
00854             // Additional page erase operation is required.
00855                     
00856             // Adjust variable to ensure correct state transition path is taken after the additional 
00857             // page erase operation has completed.
00858             m_head_word_size = 0;
00859             swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);        
00860         }            
00861         else if (m_tail_word_size != 0)
00862         {
00863             // Proceed with restoring tail from swap to data page. 
00864             swap_sub_state_state_change(STATE_RESTORE_TAIL);
00865         }
00866         else
00867         {            
00868             // Swap statemachine execution end reached.
00869             swap_sub_sm_exit_action_run();        
00870         }
00871     }
00872     else
00873     {
00874         // As operation request was rejected by the flash API reissue the request.
00875         swap_sub_state_err_busy_process();        
00876     }
00877 }
00878 
00879 
00880 /**@brief Function for doing restore tail state action upon flash operation success event.
00881  */
00882 static void tail_restore_state_run(void)
00883 {
00884     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
00885     {
00886         swap_sub_sm_exit_action_run();        
00887     }
00888     else
00889     {
00890         // As operation request was rejected by the flash API reissue the request.
00891         swap_sub_state_err_busy_process();        
00892     }    
00893 }
00894 
00895 
00896 /**@brief Function for doing data page erase state action upon a flash operation success event.
00897  *
00898  * @details Function for doing data page erase state action upon a flash operation success event, 
00899  *          which includes making a state transit to a new state depending on the current state.
00900  */
00901 static void data_page_erase_state_run(void)
00902 {            
00903     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
00904     {
00905         ++m_current_page_id;   
00906                     
00907         if (m_head_word_size != 0)
00908         {            
00909             swap_sub_state_state_change(STATE_RESTORE_HEAD);
00910         }
00911         else if (is_page_erase_required())
00912         {
00913             // Additional page erase operation is required.    
00914             swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);                
00915         }                
00916         else if (m_tail_word_size != 0)
00917         {                    
00918             if (!(m_flags & MASK_TAIL_SWAP_DONE)) 
00919             {
00920                 // Tail area restore is required and we have not yet written the relevant data page 
00921                 // to swap area. Start the process of writing the data page to swap.
00922                 m_flags |= MASK_TAIL_SWAP_DONE;            
00923 
00924                 swap_sub_state_state_change(STATE_ERASE_SWAP);            
00925             }
00926             else
00927             {
00928                 // Tail area restore is required and we have already written the relevant data page 
00929                 // to swap area. Proceed by restoring the tail area.
00930                 swap_sub_state_state_change(STATE_RESTORE_TAIL);            
00931             }
00932         }            
00933         else
00934         {
00935             swap_sub_sm_exit_action_run();        
00936         }        
00937     }
00938     else
00939     {
00940         // As operation request was rejected by the flash API reissue the request.
00941         swap_sub_state_err_busy_process();        
00942     }
00943 }
00944 
00945 
00946 /**@brief Function for doing data to swap write state action upon flash operation success event.
00947  */
00948 static void data_to_swap_write_state_run(void)
00949 {        
00950     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
00951     {
00952         // If the operation is executed only on 1 single flash page it automatically means that tail 
00953         // area is written to the swap, which we store to flags.     
00954         if (m_flags & MASK_SINGLE_PAGE_OPERATION)
00955         {
00956             m_flags |= MASK_TAIL_SWAP_DONE;        
00957         }
00958 
00959         swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);    
00960     }
00961     else
00962     {
00963         // As operation request was rejected by the flash API reissue the request.
00964         swap_sub_state_err_busy_process();        
00965     }        
00966 }
00967 
00968 
00969 /**@brief Function for doing swap erase state action upon flash operation success event.
00970  */
00971 static void swap_erase_state_run(void)
00972 {
00973     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
00974     {        
00975         swap_sub_state_state_change(STATE_WRITE_DATA_TO_SWAP);
00976     }
00977     else
00978     {
00979         // As operation request was rejected by the flash API reissue the request.
00980         swap_sub_state_err_busy_process();        
00981     }
00982 }
00983 
00984 
00985 /**@brief Function for dispatching the correct state action for data erase with a swap composite 
00986 *         state upon a flash operation success event.
00987  */
00988 static void swap_sub_state_sm_run(void)
00989 {  
00990     static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) = 
00991     {
00992         swap_erase_state_run,
00993         data_to_swap_write_state_run,
00994         data_page_erase_state_run,
00995         tail_restore_state_run,
00996         head_restore_state_run
00997     };
00998     
00999     swap_sub_state_sm_lut[m_swap_sub_state]();    
01000 }
01001 
01002 
01003 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash 
01004  *        API, in main sate.
01005  */
01006 static void main_state_err_busy_process(void)
01007 {
01008     // Reissue the request by doing a self transition to the current state.    
01009     m_flags &= ~MASK_FLASH_API_ERR_BUSY;
01010     sm_state_change(m_state);                    
01011 }
01012 
01013 
01014 /**@brief Function for doing erase state action upon flash operation success event.
01015  *
01016  * @details Function for doing erase state action upon flash operation success event, which includes 
01017  *          making a state transition depending on the current state.
01018  */
01019 static void erase_sub_state_sm_run(void)
01020 {
01021     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
01022     {        
01023         // Clear operation request has succeeded.
01024         ++m_current_page_id;                        
01025                 
01026         if (!is_page_erase_required())
01027         {
01028             clear_post_processing_run();
01029         }
01030         else
01031         {   
01032             // All required flash pages have not yet been erased, issue erase by doing a self 
01033             // transit. 
01034             sm_state_change(m_state);        
01035         }                              
01036     }
01037     else
01038     {
01039         // As operation request was rejected by the flash API reissue the request.
01040         main_state_err_busy_process();
01041     }
01042 }
01043 
01044 
01045 /**@brief Function for doing store state action upon flash operation success event.
01046  */
01047 static void store_sub_state_sm_run(void)
01048 {
01049     if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
01050     {        
01051         // As write operation request has succeeded, adjust the size tracking state information 
01052         // accordingly.
01053         cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];    
01054         p_cmd->size                -= m_num_of_bytes_written;
01055 
01056         if (p_cmd->size == 0)
01057         {
01058             command_end_procedure_run();
01059         }
01060         else
01061         {
01062             store_cmd_flash_write_execute();
01063         }
01064     }
01065     else
01066     {
01067         // As operation request was rejected by the flash API reissue the request.
01068         main_state_err_busy_process();
01069     }
01070 }
01071 
01072 
01073 /**@brief Function for doing action upon flash operation success event.
01074  */
01075 static void flash_operation_success_run(void)
01076 {    
01077     switch (m_state)
01078     {                   
01079         case STATE_STORE:
01080             store_sub_state_sm_run();
01081             break;
01082                         
01083         case STATE_DATA_ERASE:
01084             erase_sub_state_sm_run();
01085             break;
01086                         
01087         case STATE_DATA_ERASE_WITH_SWAP:
01088             swap_sub_state_sm_run();                        
01089             break;                        
01090             
01091         default:
01092             // No implementation needed.
01093             break;
01094     }                    
01095 }
01096 
01097 
01098 /**@brief Function for doing action upon flash operation failure event.
01099  *
01100  * @details Function for doing action upon flash operation failure event, which includes retrying 
01101  *          the last operation or if retry count has been reached completing the operation with 
01102  *          appropriate result code and transitioning to an error state.
01103  *
01104  * @note    The command is not removed from the command queue, which will result to stalling of the 
01105  *          command pipeline and the appropriate application recovery procedure for this is to reset 
01106  *          the system by issuing @ref pstorage_init which will also result to flushing of the 
01107  *          command queue.
01108  */
01109 static void flash_operation_failure_run(void)
01110 {   
01111     if (++m_num_of_command_retries != SD_CMD_MAX_TRIES)
01112     {
01113         // Retry the last operation by doing a self transition to the current state.
01114             
01115         if (m_state != STATE_DATA_ERASE_WITH_SWAP)
01116         {
01117             sm_state_change(m_state);        
01118         }
01119         else
01120         {
01121             swap_sub_state_state_change(m_swap_sub_state);
01122         }
01123     }
01124     else
01125     {
01126         // Complete the operation with appropriate result code and transit to an error state.     
01127         app_notify_error_state_transit(NRF_ERROR_TIMEOUT);        
01128     }   
01129 }
01130 
01131 
01132 /**@brief Function for handling flash access result events.
01133  *
01134  * @param[in] sys_evt System event to be handled.
01135  */
01136 void pstorage_sys_event_handler(uint32_t sys_evt)
01137 {  
01138     if (m_state != STATE_IDLE && m_state != STATE_ERROR)
01139     {        
01140         switch (sys_evt)
01141         {
01142             case NRF_EVT_FLASH_OPERATION_SUCCESS:
01143                 flash_operation_success_run();
01144                 break;
01145             
01146             case NRF_EVT_FLASH_OPERATION_ERROR:            
01147                 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
01148                 {
01149                     flash_operation_failure_run();
01150                 }
01151                 else
01152                 {
01153                     // As our last flash operation request was rejected by the flash API reissue the 
01154                     // request by doing same code execution path as for flash operation sucess 
01155                     // event. This will promote code reuse in the implementation.                    
01156                     flash_operation_success_run();
01157                 }                
01158                 break;
01159                 
01160             default:
01161                 // No implementation needed.
01162                 break;
01163         }
01164 
01165     }
01166 }
01167 
01168 
01169 /**@brief Function for calculating the tail area size in number of 32-bit words.
01170  *
01171  * @param[in] cmd_end_of_storage_address End of storage area within the scope of the command.
01172  * @param[in] end_of_storage_address     End of allocated storage area for the application.
01173  */
01174 static void tail_word_size_calculate(pstorage_size_t cmd_end_of_storage_address, 
01175                                      pstorage_size_t end_of_storage_address)
01176 { 
01177     // Two different cases to resolve when calculating correct size for restore tail section:
01178     // 1) End of storage area and command end area are in the same page.
01179     // 2) End of storage area and command end area are not in the same page.
01180     
01181     const uint32_t end_of_storage_area_page         = end_of_storage_address     / 
01182                                                       PSTORAGE_FLASH_PAGE_SIZE;
01183     const uint32_t command_end_of_storage_area_page = cmd_end_of_storage_address / 
01184                                                       PSTORAGE_FLASH_PAGE_SIZE;
01185 
01186     if (end_of_storage_area_page == command_end_of_storage_area_page)
01187     {
01188         //lint -e{573} suppress "Signed-unsigned mix with divide".
01189         m_tail_word_size = (end_of_storage_address - cmd_end_of_storage_address) / sizeof(uint32_t);                                           
01190     }
01191     else
01192     {
01193         //lint -e{573} suppress "Signed-unsigned mix with divide".    
01194         m_tail_word_size = (PSTORAGE_FLASH_PAGE_SIZE - 
01195                            (cmd_end_of_storage_address % PSTORAGE_FLASH_PAGE_SIZE)) / 
01196                            sizeof(uint32_t);               
01197     }            
01198 }
01199 
01200 
01201 /**@brief Function for executing the clear operation.
01202  */
01203 static void clear_operation_execute(void)
01204 {    
01205     const cmd_queue_element_t * p_cmd        = &m_cmd_queue.cmd[m_cmd_queue.rp];
01206     const pstorage_block_t      cmd_block_id = p_cmd->storage_addr.block_id;
01207 
01208     const pstorage_size_t  block_size    = m_app_table[p_cmd->storage_addr.module_id].block_size;
01209     const pstorage_size_t  block_count   = m_app_table[p_cmd->storage_addr.module_id].block_count;
01210     const pstorage_block_t block_base_id = m_app_table[p_cmd->storage_addr.module_id].base_id;  
01211       
01212     const bool is_start_address_page_aligned = (cmd_block_id % PSTORAGE_FLASH_PAGE_SIZE) == 0;
01213     
01214     // Calculate the end (1 beyond allocated area) for complete storage area and to the area only 
01215     // within scope of this command.
01216     const pstorage_block_t end_of_storage_address     = block_base_id + (block_size * block_count); 
01217     const pstorage_block_t cmd_end_of_storage_address = cmd_block_id + p_cmd->size + p_cmd->offset;
01218 
01219     // Zero tail to make sure no extra erase is done erroneously.
01220     m_tail_word_size = 0;        
01221         
01222     // If the following is true no swap access is needed:
01223     // - 1st logical test covers the case of: clear/update 1 complete single page.
01224     // - 2nd logical test covers the case of: 
01225     //   1) Clear/update last allocated page and page is not full (page can't be shared between 
01226     //      multiple clients so the end of the page is unused area).
01227     //   2) Clear/update all allocated storage.
01228     if ((is_start_address_page_aligned && (p_cmd->size == PSTORAGE_FLASH_PAGE_SIZE)) ||
01229         (is_start_address_page_aligned && (cmd_end_of_storage_address == end_of_storage_address) && 
01230         (p_cmd->offset == 0)) || (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID)) 
01231     {
01232         // Nothing to put to the swap and we can just erase the pages(s).         
01233         
01234         m_current_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
01235         
01236         sm_state_change(STATE_DATA_ERASE);                        
01237     }
01238     else
01239     {
01240         // Not all the blocks for the module can be cleared, we need to use swap page for storing 
01241         // data temporarily.                        
01242         
01243         m_head_word_size = ((cmd_block_id + p_cmd->offset) % PSTORAGE_FLASH_PAGE_SIZE) / 
01244                            sizeof(uint32_t);
01245         
01246         const bool is_cmd_end_address_page_aligned = ((cmd_end_of_storage_address % 
01247                                                       PSTORAGE_FLASH_PAGE_SIZE) == 0);
01248         if ((cmd_end_of_storage_address != end_of_storage_address) && 
01249             !is_cmd_end_address_page_aligned)
01250         {
01251             // When command area is not equal to end of the storage allocation area and not ending 
01252             // to page boundary there is a need to restore the tail area.
01253             tail_word_size_calculate(cmd_end_of_storage_address, end_of_storage_address);
01254         }
01255 
01256         sm_state_change(STATE_DATA_ERASE_WITH_SWAP);         
01257     }        
01258 }
01259 
01260 
01261 /**@brief Function for executing the store operation.
01262  */
01263 static void store_operation_execute(void)
01264 {    
01265     sm_state_change(STATE_STORE);
01266 }
01267  
01268 
01269 /**@brief Function for executing the update operation.
01270  */ 
01271 static void update_operation_execute(void)
01272 {
01273     clear_operation_execute();
01274 }
01275 
01276 
01277 /**@brief Function for dispatching the flash access operation.
01278  */  
01279 static void cmd_process(void)
01280 {
01281     const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
01282     m_app_data_size                   = p_cmd->size;
01283 
01284     switch (p_cmd->op_code)
01285     {
01286         case PSTORAGE_STORE_OP_CODE:                   
01287             store_operation_execute();       
01288             break;
01289 
01290         case PSTORAGE_CLEAR_OP_CODE:
01291             clear_operation_execute();
01292             break;
01293 
01294         case PSTORAGE_UPDATE_OP_CODE:
01295             update_operation_execute();
01296             break;
01297 
01298         default:
01299             // No action required.
01300             break;
01301     }
01302 }
01303 
01304 
01305 uint32_t pstorage_init(void)
01306 {
01307     cmd_queue_init();
01308 
01309     m_next_app_instance = 0;
01310     m_next_page_addr    = PSTORAGE_DATA_START_ADDR;
01311     m_current_page_id   = 0;
01312     
01313     for (uint32_t index = 0; index < PSTORAGE_NUM_OF_PAGES; index++)
01314     {
01315         m_app_table[index].cb           = NULL;
01316         m_app_table[index].block_size   = 0;
01317         m_app_table[index].block_count  = 0;
01318     }
01319 
01320 #ifdef PSTORAGE_RAW_MODE_ENABLE
01321     m_raw_app_table.cb           = NULL;
01322 #endif //PSTORAGE_RAW_MODE_ENABLE
01323 
01324     m_state                     = STATE_IDLE;
01325     m_num_of_command_retries    = 0;
01326     m_flags                     = 0;
01327     m_num_of_bytes_written      = 0;
01328     m_flags                    |= MASK_MODULE_INITIALIZED;
01329        
01330     return NRF_SUCCESS;
01331 }
01332 
01333 
01334 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
01335                            pstorage_handle_t       * p_block_id)
01336 {
01337     VERIFY_MODULE_INITIALIZED();
01338     NULL_PARAM_CHECK(p_module_param);
01339     NULL_PARAM_CHECK(p_block_id);
01340     NULL_PARAM_CHECK(p_module_param->cb);
01341     BLOCK_SIZE_CHECK(p_module_param->block_size);    
01342     BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
01343 
01344     if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
01345     {
01346         return NRF_ERROR_INVALID_PARAM;
01347     }
01348     
01349     if (m_next_app_instance == PSTORAGE_NUM_OF_PAGES)
01350     {
01351         return NRF_ERROR_NO_MEM;
01352     }
01353 
01354     p_block_id->module_id = m_next_app_instance;
01355     p_block_id->block_id  = m_next_page_addr;
01356 
01357     m_app_table[m_next_app_instance].base_id     = p_block_id->block_id;
01358     m_app_table[m_next_app_instance].cb          = p_module_param->cb;
01359     m_app_table[m_next_app_instance].block_size  = p_module_param->block_size;
01360     m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
01361 
01362     // Calculate number of flash pages allocated for the device and adjust next free page address.
01363     /*lint -save -e666 */
01364     const uint32_t page_count = CEIL_DIV((p_module_param->block_size * p_module_param->block_count), 
01365                                          PSTORAGE_FLASH_PAGE_SIZE);
01366     /*lint -restore */
01367     m_next_page_addr         += page_count * PSTORAGE_FLASH_PAGE_SIZE;
01368     
01369     ++m_next_app_instance;
01370 
01371     return NRF_SUCCESS;
01372 }
01373 
01374 
01375 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
01376                                        pstorage_size_t     block_num,
01377                                        pstorage_handle_t * p_block_id)
01378 {
01379     pstorage_handle_t temp_id;
01380 
01381     VERIFY_MODULE_INITIALIZED();
01382     NULL_PARAM_CHECK(p_base_id);
01383     NULL_PARAM_CHECK(p_block_id);
01384     MODULE_ID_RANGE_CHECK(p_base_id);
01385 
01386     temp_id           = (*p_base_id);
01387     temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
01388 
01389     BLOCK_ID_RANGE_CHECK(&temp_id);
01390 
01391     (*p_block_id) = temp_id;
01392 
01393     return NRF_SUCCESS;
01394 }
01395 
01396 
01397 uint32_t pstorage_store(pstorage_handle_t * p_dest,
01398                         uint8_t           * p_src,
01399                         pstorage_size_t     size,
01400                         pstorage_size_t     offset)
01401 {
01402     VERIFY_MODULE_INITIALIZED();
01403     NULL_PARAM_CHECK(p_src);
01404     NULL_PARAM_CHECK(p_dest);
01405     MODULE_ID_RANGE_CHECK(p_dest);
01406     BLOCK_ID_RANGE_CHECK(p_dest);
01407     SIZE_CHECK(p_dest, size);    
01408     OFFSET_CHECK(p_dest, offset, size);
01409     
01410     if ((!is_word_aligned(p_src))                    || 
01411         (!is_word_aligned((void *)(uint32_t)offset)) || 
01412         (!is_word_aligned((uint32_t *)p_dest->block_id)))
01413     {
01414         return NRF_ERROR_INVALID_ADDR;
01415     }
01416 
01417     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
01418 }
01419 
01420 
01421 uint32_t pstorage_update(pstorage_handle_t * p_dest,
01422                          uint8_t           * p_src,
01423                          pstorage_size_t     size,
01424                          pstorage_size_t     offset)
01425 {
01426     VERIFY_MODULE_INITIALIZED();
01427     NULL_PARAM_CHECK(p_src);
01428     NULL_PARAM_CHECK(p_dest);
01429     MODULE_ID_RANGE_CHECK(p_dest);
01430     BLOCK_ID_RANGE_CHECK(p_dest);
01431     SIZE_CHECK(p_dest, size);
01432     OFFSET_CHECK(p_dest, offset, size);
01433 
01434     if ((!is_word_aligned(p_src))                    || 
01435         (!is_word_aligned((void *)(uint32_t)offset)) || 
01436         (!is_word_aligned((uint32_t *)p_dest->block_id)))
01437     {
01438         return NRF_ERROR_INVALID_ADDR;
01439     }
01440 
01441     return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
01442 }
01443 
01444 
01445 uint32_t pstorage_load(uint8_t           * p_dest,
01446                        pstorage_handle_t * p_src,
01447                        pstorage_size_t     size,
01448                        pstorage_size_t     offset)
01449 {
01450     VERIFY_MODULE_INITIALIZED();
01451     NULL_PARAM_CHECK(p_src);
01452     NULL_PARAM_CHECK(p_dest);
01453     MODULE_ID_RANGE_CHECK(p_src);
01454     BLOCK_ID_RANGE_CHECK(p_src);
01455     SIZE_CHECK(p_src, size);
01456     OFFSET_CHECK(p_src, offset, size);
01457 
01458     if ((!is_word_aligned(p_dest))                   || 
01459         (!is_word_aligned((void *)(uint32_t)offset)) || 
01460         (!is_word_aligned((uint32_t *)p_src->block_id)))
01461     {
01462         return NRF_ERROR_INVALID_ADDR;
01463     }
01464 
01465     memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
01466 
01467     m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
01468 
01469     return NRF_SUCCESS;
01470 }
01471 
01472 
01473 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01474 {
01475     VERIFY_MODULE_INITIALIZED();
01476     NULL_PARAM_CHECK(p_dest);
01477     MODULE_ID_RANGE_CHECK(p_dest);
01478     BLOCK_ID_RANGE_CHECK(p_dest);
01479 
01480     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
01481     {
01482         return NRF_ERROR_INVALID_ADDR;
01483     }
01484 
01485     // Check is the area starting from block_id multiple of block_size.
01486     if (
01487         !(
01488             ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
01489              m_app_table[p_dest->module_id].block_size) == 0
01490             )
01491         )
01492     {
01493         return NRF_ERROR_INVALID_PARAM;
01494     }
01495 
01496     // Check is requested size multiple of registered block size or 0.
01497     if (((size % m_app_table[p_dest->module_id].block_size) != 0) || (size == 0))    
01498     {        
01499         return NRF_ERROR_INVALID_PARAM;        
01500     }
01501 
01502     const uint32_t registered_allocation_size = m_app_table[p_dest->module_id].block_size * 
01503                                                 m_app_table[p_dest->module_id].block_count;
01504     
01505     const pstorage_block_t clear_request_end_address = p_dest->block_id + size;
01506     const pstorage_block_t allocation_end_address    = m_app_table[p_dest->module_id].base_id + 
01507                                                        registered_allocation_size;
01508     // Check if request would lead to a buffer overrun.                                                       
01509     if (clear_request_end_address > allocation_end_address)
01510     {        
01511         return NRF_ERROR_INVALID_PARAM;            
01512     }
01513     
01514     return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01515 }
01516 
01517 
01518 uint32_t pstorage_access_status_get(uint32_t * p_count)
01519 {
01520     VERIFY_MODULE_INITIALIZED();
01521     NULL_PARAM_CHECK(p_count);
01522 
01523     (*p_count) = m_cmd_queue.count;
01524 
01525     return NRF_SUCCESS;
01526 }
01527 
01528 #ifdef PSTORAGE_RAW_MODE_ENABLE
01529 
01530 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
01531                                pstorage_handle_t       * p_block_id)
01532 {
01533     VERIFY_MODULE_INITIALIZED();
01534     NULL_PARAM_CHECK(p_module_param);
01535     NULL_PARAM_CHECK(p_block_id);
01536     NULL_PARAM_CHECK(p_module_param->cb);
01537 
01538     if (m_raw_app_table.cb != NULL)
01539     {
01540         return NRF_ERROR_NO_MEM;
01541     }
01542 
01543     p_block_id->module_id = RAW_MODE_APP_ID;
01544     m_raw_app_table.cb    = p_module_param->cb;
01545 
01546     return NRF_SUCCESS;
01547 }
01548 
01549 
01550 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
01551                             uint8_t           * p_src,
01552                             pstorage_size_t     size,
01553                             pstorage_size_t     offset)
01554 {
01555     VERIFY_MODULE_INITIALIZED();
01556     NULL_PARAM_CHECK(p_src);
01557     NULL_PARAM_CHECK(p_dest);
01558     MODULE_RAW_HANDLE_CHECK(p_dest);
01559     
01560     if (size == 0)
01561     {
01562         return NRF_ERROR_INVALID_PARAM;        
01563     }
01564     
01565     // Verify word alignment.
01566     if ((!is_word_aligned(p_src))                    || 
01567         (!is_word_aligned((void *)(uint32_t)size))   ||     
01568         (!is_word_aligned((void *)(uint32_t)offset)) || 
01569         (!is_word_aligned((void *)(p_dest->block_id))))
01570     {
01571         return NRF_ERROR_INVALID_ADDR;
01572     }
01573        
01574     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
01575 }
01576 
01577 
01578 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01579 {
01580     VERIFY_MODULE_INITIALIZED();
01581     NULL_PARAM_CHECK(p_dest);
01582     MODULE_RAW_HANDLE_CHECK(p_dest);
01583     
01584     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
01585     {
01586         return NRF_ERROR_INVALID_ADDR;
01587     }    
01588 
01589     return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01590 }
01591 
01592 #endif // PSTORAGE_RAW_MODE_ENABLE