Nordic stack and drivers for the mbed BLE API Modified for HRM1017 for library 0.1.0

Fork of nRF51822 by Nordic Semiconductor

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 "pstorage.h "
00016 #include <stdlib.h>
00017 #include <stdint.h>
00018 #include <string.h>
00019 #include "nordic_common.h"
00020 #include "nrf_error.h"
00021 #include "nrf_assert.h"
00022 #include "nrf.h"
00023 #include "nrf_soc.h"
00024 #include "app_util.h "
00025 
00026 #define INVALID_OPCODE     0x00                            /**< Invalid op code identifier. */
00027 #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. */
00028 #define RAW_MODE_APP_ID    (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */
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 /**
00040  * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
00041  */
00042 #define NULL_PARAM_CHECK(PARAM)                                                                   \
00043         if ((PARAM) == NULL)                                                                      \
00044         {                                                                                         \
00045             return NRF_ERROR_NULL;                                                                \
00046         }
00047 
00048 /**
00049  * @brief Verifies the module identifier supplied by the application is within permissible
00050  *        range.
00051  */
00052 #define MODULE_ID_RANGE_CHECK(ID)                                                                 \
00053         if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) ||                                   \
00054             (m_app_table[(ID)->module_id].cb == NULL))                                            \
00055         {                                                                                         \
00056             return NRF_ERROR_INVALID_PARAM;                                                       \
00057         }
00058 
00059 /**
00060  * @brief Verifies the block identifier supplied by the application is within the permissible
00061  *        range.
00062  */
00063 #define BLOCK_ID_RANGE_CHECK(ID)                                                                  \
00064         if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id +                           \
00065             (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID))))                  \
00066         {                                                                                         \
00067             return NRF_ERROR_INVALID_PARAM;                                                       \
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_SWAP_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 
00123 /**@brief    Verify module's initialization status.
00124  *
00125  * @details   Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a
00126  *            module API is called without initializing the module.
00127  */
00128 #define VERIFY_MODULE_INITIALIZED()                                                               \
00129         do                                                                                        \
00130         {                                                                                         \
00131             if (!m_module_initialized)                                                            \
00132             {                                                                                     \
00133                  return NRF_ERROR_INVALID_STATE;                                                  \
00134             }                                                                                     \
00135         } while(0)
00136 
00137 /**@brief Macro to fetch the block size registered for the module. */
00138 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
00139 
00140 
00141 /** @brief States for the Update/Clear swap backup state machine. */
00142 typedef enum
00143 {
00144     STATE_INIT,                /**< State for indicating that swap can be used when using update/clear API. */
00145     STATE_DATA_TO_SWAP_WRITE,  /**< State for doing backup of data page into the swap page when using update/clear API. */
00146     STATE_DATA_ERASE,          /**< State for erasing data page when using update/clear API. */
00147     STATE_HEAD_RESTORE,        /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
00148     STATE_TAIL_RESTORE,        /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
00149     STATE_NEW_BODY_WRITE,      /**< State for writing body (middle) data to the data page when using update/clear API. */
00150     STATE_SWAP_ERASE,          /**< State for erasing the swap page when using the update/clear API. */
00151     STATE_COMPLETE,            /**< State for indicating that update/clear sequence is completed internal in the module when using the update/clear API. */
00152     STATE_SWAP_DIRTY           /**< State for initializing the swap region on module initialization. */
00153 } swap_backup_state_t;
00154 
00155 
00156 /**
00157  * @brief Application registration information.
00158  *
00159  * @details Define application specific information that application needs to maintain to be able
00160  *          to process requests from each one of them.
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     pstorage_block_t     base_id;        /**< Base block id assigned to the module. */
00166     pstorage_size_t      block_size;     /**< Size of block for the module. */
00167     pstorage_size_t      block_count;    /**< Number of block requested by application. */
00168     pstorage_size_t      num_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. */
00169 } pstorage_module_table_t;
00170 
00171 
00172 #ifdef PSTORAGE_RAW_MODE_ENABLE
00173 /**
00174  * @brief Application registration information.
00175  *
00176  * @details Define application specific information that application registered for raw mode.
00177  */
00178 typedef struct
00179 {
00180     pstorage_ntf_cb_t      cb;             /**< Callback registered with the module to be notified of result of flash access.  */
00181     uint16_t               num_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. */
00182 } pstorage_raw_module_table_t;
00183 #endif // PSTORAGE_RAW_MODE_ENABLE
00184 
00185 
00186 /**
00187  * @brief Defines command queue element.
00188  *
00189  * @details Defines command queue element. Each element encapsulates needed information to process
00190  *          a flash access command.
00191  */
00192 typedef struct
00193 {
00194     uint8_t              op_code;       /**< Identifies flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
00195     pstorage_size_t      size;          /**< Identifies size in bytes requested for the operation. */
00196     pstorage_size_t      offset;        /**< Offset requested by the application for access operation. */
00197     pstorage_handle_t    storage_addr;  /**< Address/Identifier for persistent memory. */
00198     uint8_t *            p_data_addr;   /**< Address/Identifier for data memory. This is assumed to be resident memory. */
00199 } cmd_queue_element_t;
00200 
00201 
00202 /**
00203  * @brief Defines command queue, an element is free if op_code field is not invalid.
00204  *
00205  * @details Defines commands enqueued for flash access. At any point of time, this queue has one or
00206  *          more flash access operation pending if the count field is not zero. When the queue is
00207  *          not empty, the rp (read pointer) field points to the flash access command in progress
00208  *          or to requested next. The queue implements a simple first in first out algorithm.
00209  *          Data addresses are assumed to be resident.
00210  */
00211 typedef struct
00212 {
00213     uint8_t              rp;                           /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
00214     uint8_t              count;                        /**< Number of elements in the queue.  */
00215     bool                 flash_access;                 /**< Flag to ensure an flash event received is for an request issued by the module. */
00216     cmd_queue_element_t  cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
00217 } cmd_queue_t;
00218 
00219 
00220 static cmd_queue_t         m_cmd_queue;                  /**< Flash operation request queue. */
00221 static pstorage_size_t     m_next_app_instance;          /**< Points to the application module instance that can be allocated next. */
00222 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. */
00223 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. */
00224 static bool                m_module_initialized = false; /**< Flag for checking if module has been initialized. */
00225 static swap_backup_state_t m_swap_state;                 /**< Swap page state. */
00226 
00227 
00228 static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS]; /**< Registered application information table. */
00229 
00230 #ifdef PSTORAGE_RAW_MODE_ENABLE
00231 static pstorage_raw_module_table_t m_raw_app_table;                    /**< Registered application information table for raw mode. */
00232 #endif // PSTORAGE_RAW_MODE_ENABLE
00233 
00234 
00235 /**
00236  * @brief Routine called to actually issue the flash access request to the SoftDevice.
00237  *
00238  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00239  */
00240 static uint32_t cmd_process(void);
00241 
00242 
00243 /**
00244  * @brief Routine to notify application of any errors.
00245  *
00246  * @param[in] result Result of event being notified.
00247  */
00248 static void app_notify(uint32_t result);
00249 
00250 
00251 /**
00252  * @defgroup utility_functions Utility internal functions.
00253  * @{
00254  * @details Utility functions needed for interfacing with flash through SoC APIs.
00255  * SoC APIs are non blocking and provide the result of flash access through an event.
00256  *
00257  * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is
00258  * maintained by this module.
00259  */
00260 
00261 
00262 /**
00263  * @brief Initializes command queue element.
00264  *
00265  * @param[in] index Element index being initialized.
00266  */
00267 static void cmd_queue_element_init(uint32_t index)
00268 {
00269     // Internal function and checks on range of index can be avoided.
00270     m_cmd_queue.cmd[index].op_code                = INVALID_OPCODE;
00271     m_cmd_queue.cmd[index].size                   = 0;
00272     m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS;
00273     m_cmd_queue.cmd[index].storage_addr.block_id  = 0;
00274     m_cmd_queue.cmd[index].p_data_addr            = NULL;
00275     m_cmd_queue.cmd[index].offset                 = 0;
00276 }
00277 
00278 
00279 /**
00280  * @brief Initializes command queue.
00281  */
00282 static void cmd_queue_init(void)
00283 {
00284     uint32_t cmd_index;
00285 
00286     m_round_val              = 0;
00287     m_swap_state             = STATE_INIT;
00288     m_cmd_queue.rp           = 0;
00289     m_cmd_queue.count        = 0;
00290     m_cmd_queue.flash_access = false;
00291 
00292     for (cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
00293     {
00294         cmd_queue_element_init(cmd_index);
00295     }
00296 }
00297 
00298 
00299 /**
00300  * @brief Routine to enqueue a flash access operation.
00301  *
00302  * @param[in] opcode         Identifies operation requested to be enqueued.
00303  * @param[in] p_storage_addr Identiifes module and flash address on which operation is requested.
00304  * @param[in] p_data_addr    Identifies data address for flash access.
00305  * @param[in] size           Size in bytes of data requested for the access operation.
00306  * @param[in] offset         Offset within the flash memory block at which operation is requested.
00307  *
00308  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00309  *
00310  * @note All paramater check should be performed before requesting in an enqueue.
00311  */
00312 static uint32_t cmd_queue_enqueue(uint8_t             opcode,
00313                                   pstorage_handle_t * p_storage_addr,
00314                                   uint8_t           * p_data_addr,
00315                                   pstorage_size_t     size,
00316                                   pstorage_size_t     offset)
00317 {
00318     uint32_t retval;
00319     uint8_t  write_index = 0;
00320 
00321     if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
00322     {
00323         // Enqueue the command if it is queue is not full.
00324         write_index = m_cmd_queue.rp + m_cmd_queue.count;
00325 
00326         if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
00327         {
00328             write_index -= PSTORAGE_CMD_QUEUE_SIZE;
00329         }
00330 
00331         m_cmd_queue.cmd[write_index].op_code      = opcode;
00332         m_cmd_queue.cmd[write_index].p_data_addr  = p_data_addr;
00333         m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
00334         m_cmd_queue.cmd[write_index].size         = size;
00335         m_cmd_queue.cmd[write_index].offset       = offset;
00336         retval                                    = NRF_SUCCESS;
00337         if (m_cmd_queue.flash_access == false)
00338         {
00339             retval = cmd_process();
00340             if (retval == NRF_ERROR_BUSY)
00341             {
00342                 // In case of busy error code, it is possible to attempt to access flash.
00343                 retval = NRF_SUCCESS;
00344             }
00345         }
00346         m_cmd_queue.count++;
00347     }
00348     else
00349     {
00350         retval = NRF_ERROR_NO_MEM;
00351     }
00352 
00353     return retval;
00354 }
00355 
00356 
00357 /**
00358  * @brief Dequeues a command element.
00359  *
00360  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00361  */
00362 static uint32_t cmd_queue_dequeue(void)
00363 {
00364     uint32_t retval;
00365     retval = NRF_SUCCESS;
00366 
00367     // If any flash operation is enqueued, schedule.
00368     if (m_cmd_queue.count > 0)
00369     {
00370         retval = cmd_process();
00371         if (retval != NRF_SUCCESS)
00372         {
00373             // Flash could be accessed by modules other than Bond Manager, hence a busy error is
00374             // acceptable, but any other error needs to be indicated to the bond manager.
00375             if (retval != NRF_ERROR_BUSY)
00376             {
00377                 app_notify(retval);
00378             }
00379             else
00380             {
00381                 // In case of busy next trigger will be a success or a failure event.
00382             }
00383         }
00384     }
00385     else
00386     {
00387         // No flash access request pending.
00388     }
00389 
00390     return retval;
00391 }
00392 
00393 
00394 /**
00395  * @brief Routine to notify application of any errors.
00396  *
00397  * @param[in] result Result of event being notified.
00398  */
00399 static void app_notify(uint32_t result)
00400 {
00401     pstorage_ntf_cb_t ntf_cb;
00402     uint8_t           op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
00403 
00404 #ifdef PSTORAGE_RAW_MODE_ENABLE
00405     if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID)
00406     {
00407         ntf_cb = m_raw_app_table.cb;
00408     }
00409     else
00410 #endif // PSTORAGE_RAW_MODE_ENABLE
00411     {
00412         ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb;
00413     }
00414 
00415     // Indicate result to client.
00416     // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally
00417     // for clients registering multiple pages.
00418     ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
00419            op_code,
00420            result,
00421            m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
00422            m_cmd_queue.cmd[m_cmd_queue.rp].size);
00423 }
00424 
00425 
00426 /**
00427  * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
00428  *
00429  * @param[in] sys_evt System event to be handled.
00430  */
00431 void pstorage_sys_event_handler(uint32_t sys_evt)
00432 {
00433     uint32_t retval = NRF_SUCCESS;
00434 
00435     // Its possible the flash access was not initiated by bond manager, hence
00436     // event is processed only if the event triggered was for an operation requested by the
00437     // bond manager.
00438     if (m_cmd_queue.flash_access == true)
00439     {
00440         cmd_queue_element_t * p_cmd;
00441 
00442         m_cmd_queue.flash_access = false;
00443 
00444         if (m_swap_state == STATE_SWAP_DIRTY)
00445         {
00446             if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
00447             {
00448                 m_swap_state = STATE_INIT;
00449             }
00450             else
00451             {
00452                 // If clearing the swap fails, set the application back to un-initialized, to give
00453                 // the application a chance for a retry.
00454                 m_module_initialized = false;
00455             }
00456 
00457             // Schedule any queued flash access operations.
00458             retval = cmd_queue_dequeue();
00459             if (retval != NRF_SUCCESS)
00460             {
00461                 app_notify(retval);
00462             }
00463             return;
00464         }
00465 
00466         switch (sys_evt)
00467         {
00468             case NRF_EVT_FLASH_OPERATION_SUCCESS:
00469             {
00470                 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00471                 m_round_val++;
00472 
00473                 const bool store_finished =
00474                     ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
00475                      ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));
00476 
00477                 const bool update_finished =
00478                     ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
00479                      (m_swap_state == STATE_COMPLETE));
00480 
00481                 const bool clear_block_finished =
00482                     ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
00483                      (m_swap_state == STATE_COMPLETE));
00484 
00485                 const bool clear_all_finished =
00486                     ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
00487                      ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
00488                      (m_swap_state == STATE_INIT));
00489 
00490                 if (update_finished ||
00491                     clear_block_finished ||
00492                     clear_all_finished ||
00493                     store_finished)
00494                 {
00495                     m_swap_state = STATE_INIT;
00496 
00497                     app_notify(retval);
00498 
00499                     // Initialize/free the element as it is now processed.
00500                     cmd_queue_element_init(m_cmd_queue.rp);
00501                     m_round_val = 0;
00502                     m_cmd_queue.count--;
00503                     m_cmd_queue.rp++;
00504 
00505                     if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
00506                     {
00507                         m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
00508                     }
00509                 }
00510                 // Schedule any queued flash access operations.
00511                 retval = cmd_queue_dequeue();
00512 
00513                 if (retval != NRF_SUCCESS)
00514                 {
00515                     app_notify(retval);
00516                 }
00517             }
00518             break;
00519 
00520             case NRF_EVT_FLASH_OPERATION_ERROR:
00521                 app_notify(NRF_ERROR_TIMEOUT);
00522                 break;
00523 
00524             default:
00525                 // No implementation needed.
00526                 break;
00527 
00528         }
00529     }
00530 }
00531 
00532 
00533 /** @brief Function for handling flash accesses when using swap.
00534  *
00535  * __________________________________________________________
00536  * |                       Page                             |
00537  * |________________________________________________________|
00538  * | head | affected body (to be updated or cleared) | tail |
00539  * |______|__________________________________________|______|
00540  *
00541  * @param[in] p_cmd          Queue element being processed.
00542  * @param[in] page_number    The affected page number.
00543  * @param[in] head_word_size Size of the head in number of words.
00544  * @param[in] tail_word_size Size of the tail in number of words.
00545  *
00546  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00547  */
00548 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd,
00549                                    uint32_t              page_number,
00550                                    uint32_t              head_word_size,
00551                                    uint32_t              tail_word_size)
00552 {
00553     uint32_t retval = NRF_ERROR_INTERNAL;
00554 
00555     // Adjust entry point to state machine if needed. When we update has no head or tail its
00556     // no need for using the swap.
00557     if (m_swap_state == STATE_INIT)
00558     {
00559         if ((head_word_size == 0) && (tail_word_size == 0))
00560         {
00561             // Only skip swap usage if the new data fills a whole flash page.
00562             m_swap_state = STATE_DATA_ERASE;
00563         }
00564         else
00565         {
00566             // Else start backing up application data to swap.
00567             m_swap_state = STATE_DATA_TO_SWAP_WRITE;
00568         }
00569     }
00570 
00571     switch (m_swap_state)
00572     {
00573         case STATE_DATA_TO_SWAP_WRITE:
00574             // Backup previous content into swap page.
00575             retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
00576                                     (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
00577                                     PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
00578             if (retval == NRF_SUCCESS)
00579             {
00580                 m_swap_state = STATE_DATA_ERASE;
00581             }
00582             break;
00583 
00584         case STATE_DATA_ERASE:
00585             // Clear the application data page.
00586             retval = sd_flash_page_erase(page_number);
00587             if (retval == NRF_SUCCESS)
00588             {
00589                 if (head_word_size == 0)
00590                 {
00591                     if (tail_word_size == 0)
00592                     {
00593                         if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00594                         {
00595                             m_swap_state = STATE_COMPLETE;
00596                         }
00597                         else
00598                         {
00599                             m_swap_state = STATE_NEW_BODY_WRITE;
00600                         }
00601                     }
00602                     else
00603                     {
00604                         m_swap_state = STATE_TAIL_RESTORE;
00605                     }
00606                 }
00607                 else
00608                 {
00609                     m_swap_state = STATE_HEAD_RESTORE;
00610                 }
00611             }
00612             break;
00613 
00614         case STATE_HEAD_RESTORE:
00615             // Restore head from swap to application data page.
00616             retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
00617                                     (uint32_t *)PSTORAGE_SWAP_ADDR,
00618                                     head_word_size);
00619             if (retval == NRF_SUCCESS)
00620             {
00621                 if (tail_word_size == 0)
00622                 {
00623                     if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00624                     {
00625                         m_swap_state = STATE_SWAP_ERASE;
00626                     }
00627                     else
00628                     {
00629                         m_swap_state = STATE_NEW_BODY_WRITE;
00630                     }
00631                 }
00632                 else
00633                 {
00634                     m_swap_state = STATE_TAIL_RESTORE;
00635                 }
00636             }
00637             break;
00638 
00639         case STATE_TAIL_RESTORE:
00640             // Restore tail from swap to application data page.
00641             retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
00642                                                  (head_word_size * sizeof(uint32_t)) +
00643                                                  p_cmd->size),
00644                                     (uint32_t *)(PSTORAGE_SWAP_ADDR +
00645                                                  (head_word_size * sizeof(uint32_t)) +
00646                                                  p_cmd->size),
00647                                     tail_word_size);
00648             if (retval == NRF_SUCCESS)
00649             {
00650                 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00651                 {
00652                     m_swap_state = STATE_SWAP_ERASE;
00653                 }
00654                 else
00655                 {
00656                     m_swap_state = STATE_NEW_BODY_WRITE;
00657                 }
00658             }
00659             break;
00660 
00661         case STATE_NEW_BODY_WRITE:
00662             // Write new data (body) to application data page.
00663             retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
00664                                                  (head_word_size * sizeof(uint32_t))),
00665                                     (uint32_t *)p_cmd->p_data_addr,
00666                                     p_cmd->size / sizeof(uint32_t));
00667             if (retval == NRF_SUCCESS)
00668             {
00669                 if ((head_word_size == 0) && (tail_word_size == 0))
00670                 {
00671                     m_swap_state = STATE_COMPLETE;
00672                 }
00673                 else
00674                 {
00675                     m_swap_state = STATE_SWAP_ERASE;
00676                 }
00677             }
00678             break;
00679 
00680         case STATE_SWAP_ERASE:
00681             // Clear the swap page for subsequent use.
00682             retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
00683             if (retval == NRF_SUCCESS)
00684             {
00685                 m_swap_state = STATE_COMPLETE;
00686             }
00687             break;
00688 
00689         default:
00690             break;
00691     }
00692 
00693     return retval;
00694 }
00695 
00696 
00697 /**
00698  * @brief Routine called to actually issue the flash access request to the SoftDevice.
00699  *
00700  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00701  */
00702 static uint32_t cmd_process(void)
00703 {
00704     uint32_t              retval;
00705     uint32_t              storage_addr;
00706     cmd_queue_element_t * p_cmd;
00707 
00708     retval = NRF_ERROR_FORBIDDEN;
00709 
00710     p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00711 
00712     storage_addr = p_cmd->storage_addr.block_id;
00713 
00714     switch (p_cmd->op_code)
00715     {
00716         case PSTORAGE_STORE_OP_CODE:
00717         {
00718             uint32_t  size;
00719             uint32_t  offset;
00720             uint8_t * p_data_addr = p_cmd->p_data_addr;
00721 
00722             offset        = (m_round_val * SOC_MAX_WRITE_SIZE);
00723             size          = p_cmd->size - offset;
00724             p_data_addr  += offset;
00725             storage_addr += (p_cmd->offset + offset);
00726 
00727             if (size < SOC_MAX_WRITE_SIZE)
00728             {
00729                 retval = sd_flash_write(((uint32_t *)storage_addr),
00730                                         (uint32_t *)p_data_addr,
00731                                         size / sizeof(uint32_t));
00732             }
00733             else
00734             {
00735                 retval = sd_flash_write(((uint32_t *)storage_addr),
00736                                         (uint32_t *)p_data_addr,
00737                                         SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
00738             }
00739         }
00740         break;
00741 
00742         case PSTORAGE_CLEAR_OP_CODE:
00743         {
00744             // Calculate page number before clearing.
00745             uint32_t page_number;
00746 
00747             pstorage_size_t block_size =
00748                 m_app_table[p_cmd->storage_addr.module_id].block_size;
00749 
00750             pstorage_size_t block_count =
00751                 m_app_table[p_cmd->storage_addr.module_id].block_count;
00752 
00753             pstorage_block_t base_address =
00754                 m_app_table[p_cmd->storage_addr.module_id].base_id;
00755 
00756             // If the whole module should be cleared.
00757             if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) ||
00758                 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
00759             {
00760                 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val);
00761 
00762                 retval = sd_flash_page_erase(page_number);
00763             }
00764             // If one block is to be erased.
00765             else
00766             {
00767                 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
00768 
00769                 uint32_t head_word_size = (
00770                     storage_addr -
00771                     (page_number * PSTORAGE_FLASH_PAGE_SIZE)
00772                     ) / sizeof(uint32_t);
00773 
00774                 uint32_t tail_word_size = (
00775                     ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
00776                     (storage_addr + p_cmd->size)
00777                     ) / sizeof(uint32_t);
00778 
00779                 retval = swap_state_process(p_cmd,
00780                                             page_number,
00781                                             head_word_size,
00782                                             tail_word_size);
00783             }
00784         }
00785         break;
00786 
00787         case PSTORAGE_UPDATE_OP_CODE:
00788         {
00789             uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
00790 
00791             uint32_t head_word_size = (
00792                 storage_addr + p_cmd->offset -
00793                 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
00794                 ) / sizeof(uint32_t);
00795 
00796             uint32_t tail_word_size = (
00797                 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
00798                 (storage_addr + p_cmd->offset + p_cmd->size)
00799                 ) / sizeof(uint32_t);
00800 
00801             retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size);
00802         }
00803         break;
00804 
00805         default:
00806             // Should never reach here.
00807             break;
00808     }
00809 
00810     if (retval == NRF_SUCCESS)
00811     {
00812         m_cmd_queue.flash_access = true;
00813     }
00814 
00815     return retval;
00816 }
00817 /** @} */
00818 
00819 
00820 uint32_t pstorage_init(void)
00821 {
00822     uint32_t retval;
00823 
00824     cmd_queue_init();
00825 
00826     m_next_app_instance = 0;
00827     m_next_page_addr    = PSTORAGE_DATA_START_ADDR;
00828     m_round_val         = 0;
00829 
00830     for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
00831     {
00832         m_app_table[index].cb           = NULL;
00833         m_app_table[index].block_size   = 0;
00834         m_app_table[index].num_of_pages = 0;
00835         m_app_table[index].block_count  = 0;
00836     }
00837 
00838 #ifdef PSTORAGE_RAW_MODE_ENABLE
00839     m_raw_app_table.cb           = NULL;
00840     m_raw_app_table.num_of_pages = 0;
00841     m_module_initialized         = true;
00842     m_swap_state                 = STATE_INIT;
00843 
00844     retval = NRF_SUCCESS;
00845 #else
00846     m_swap_state = STATE_SWAP_DIRTY;
00847 
00848     // Erase swap region in case it is dirty.
00849     retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
00850     if (retval == NRF_SUCCESS)
00851     {
00852         m_cmd_queue.flash_access = true;
00853         m_module_initialized     = true;
00854     }
00855 #endif //PSTORAGE_RAW_MODE_ENABLE
00856 
00857     return retval;
00858 }
00859 
00860 
00861 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
00862                            pstorage_handle_t       * p_block_id)
00863 {
00864     uint16_t page_count;
00865     uint32_t total_size;
00866 
00867     VERIFY_MODULE_INITIALIZED();
00868     NULL_PARAM_CHECK(p_module_param);
00869     NULL_PARAM_CHECK(p_block_id);
00870     NULL_PARAM_CHECK(p_module_param->cb);
00871     BLOCK_SIZE_CHECK(p_module_param->block_size);
00872     BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
00873 
00874     // Block size should be a multiple of word size.
00875     if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
00876     {
00877         return NRF_ERROR_INVALID_PARAM;
00878     }
00879 
00880     if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
00881     {
00882         return NRF_ERROR_NO_MEM;
00883     }
00884 
00885     p_block_id->module_id = m_next_app_instance;
00886     p_block_id->block_id  = m_next_page_addr;
00887 
00888     m_app_table[m_next_app_instance].base_id     = p_block_id->block_id;
00889     m_app_table[m_next_app_instance].cb          = p_module_param->cb;
00890     m_app_table[m_next_app_instance].block_size  = p_module_param->block_size;
00891     m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
00892 
00893     // Calculate number of flash pages allocated for the device.
00894     page_count = 0;
00895     total_size = p_module_param->block_size * p_module_param->block_count;
00896     do
00897     {
00898         page_count++;
00899         if (total_size > PSTORAGE_FLASH_PAGE_SIZE)
00900         {
00901             total_size -= PSTORAGE_FLASH_PAGE_SIZE;
00902         }
00903         else
00904         {
00905             total_size = 0;
00906         }
00907         m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
00908     }
00909     while (total_size >= PSTORAGE_FLASH_PAGE_SIZE);
00910 
00911     m_app_table[m_next_app_instance].num_of_pages = page_count;
00912     m_next_app_instance++;
00913 
00914     return NRF_SUCCESS;
00915 }
00916 
00917 
00918 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
00919                                        pstorage_size_t     block_num,
00920                                        pstorage_handle_t * p_block_id)
00921 {
00922     pstorage_handle_t temp_id;
00923 
00924     VERIFY_MODULE_INITIALIZED();
00925     NULL_PARAM_CHECK(p_base_id);
00926     NULL_PARAM_CHECK(p_block_id);
00927     MODULE_ID_RANGE_CHECK(p_base_id);
00928 
00929     temp_id           = (*p_base_id);
00930     temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
00931 
00932     BLOCK_ID_RANGE_CHECK(&temp_id);
00933 
00934     (*p_block_id) = temp_id;
00935 
00936     return NRF_SUCCESS;
00937 }
00938 
00939 
00940 uint32_t pstorage_store(pstorage_handle_t * p_dest,
00941                         uint8_t           * p_src,
00942                         pstorage_size_t     size,
00943                         pstorage_size_t     offset)
00944 {
00945     VERIFY_MODULE_INITIALIZED();
00946     NULL_PARAM_CHECK(p_src);
00947     NULL_PARAM_CHECK(p_dest);
00948     MODULE_ID_RANGE_CHECK(p_dest);
00949     BLOCK_ID_RANGE_CHECK(p_dest);
00950     SIZE_CHECK(p_dest, size);
00951     OFFSET_CHECK(p_dest, offset,size);
00952 
00953     // Verify word alignment.
00954     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
00955     {
00956         return NRF_ERROR_INVALID_ADDR;
00957     }
00958 
00959     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
00960     {
00961         return NRF_ERROR_INVALID_ADDR;
00962     }
00963 
00964     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
00965 }
00966 
00967 
00968 uint32_t pstorage_update(pstorage_handle_t * p_dest,
00969                          uint8_t           * p_src,
00970                          pstorage_size_t     size,
00971                          pstorage_size_t     offset)
00972 {
00973     VERIFY_MODULE_INITIALIZED();
00974     NULL_PARAM_CHECK(p_src);
00975     NULL_PARAM_CHECK(p_dest);
00976     MODULE_ID_RANGE_CHECK(p_dest);
00977     BLOCK_ID_RANGE_CHECK(p_dest);
00978     SIZE_CHECK(p_dest, size);
00979     OFFSET_CHECK(p_dest, offset, size);
00980 
00981     // Verify word alignment.
00982     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
00983     {
00984         return NRF_ERROR_INVALID_ADDR;
00985     }
00986 
00987     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
00988     {
00989         return NRF_ERROR_INVALID_ADDR;
00990     }
00991 
00992     return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
00993 }
00994 
00995 
00996 uint32_t pstorage_load(uint8_t           * p_dest,
00997                        pstorage_handle_t * p_src,
00998                        pstorage_size_t     size,
00999                        pstorage_size_t     offset)
01000 {
01001     VERIFY_MODULE_INITIALIZED();
01002     NULL_PARAM_CHECK(p_src);
01003     NULL_PARAM_CHECK(p_dest);
01004     MODULE_ID_RANGE_CHECK(p_src);
01005     BLOCK_ID_RANGE_CHECK(p_src);
01006     SIZE_CHECK(p_src, size);
01007     OFFSET_CHECK(p_src, offset, size);
01008 
01009     // Verify word alignment.
01010     if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
01011     {
01012         return NRF_ERROR_INVALID_ADDR;
01013     }
01014 
01015     if ((!is_word_aligned((uint32_t *)p_src->block_id)))
01016     {
01017         return NRF_ERROR_INVALID_ADDR;
01018     }
01019 
01020     memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
01021 
01022     m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
01023 
01024     return NRF_SUCCESS;
01025 }
01026 
01027 
01028 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01029 {
01030     uint32_t retval;
01031 
01032     VERIFY_MODULE_INITIALIZED();
01033     NULL_PARAM_CHECK(p_dest);
01034     MODULE_ID_RANGE_CHECK(p_dest);
01035     BLOCK_ID_RANGE_CHECK(p_dest);
01036 
01037     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
01038     {
01039         return NRF_ERROR_INVALID_ADDR;
01040     }
01041 
01042     if (
01043         !(
01044             ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
01045              m_app_table[p_dest->module_id].block_size) == 0
01046             )
01047         )
01048     {
01049         return NRF_ERROR_INVALID_PARAM;
01050     }
01051 
01052     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01053 
01054     return retval;
01055 }
01056 
01057 
01058 uint32_t pstorage_access_status_get(uint32_t * p_count)
01059 {
01060     VERIFY_MODULE_INITIALIZED();
01061     NULL_PARAM_CHECK(p_count);
01062 
01063     (*p_count) = m_cmd_queue.count;
01064 
01065     return NRF_SUCCESS;
01066 }
01067 
01068 #ifdef PSTORAGE_RAW_MODE_ENABLE
01069 
01070 
01071 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
01072                                pstorage_handle_t       * p_block_id)
01073 {
01074     VERIFY_MODULE_INITIALIZED();
01075     NULL_PARAM_CHECK(p_module_param);
01076     NULL_PARAM_CHECK(p_block_id);
01077     NULL_PARAM_CHECK(p_module_param->cb);
01078 
01079     if (m_raw_app_table.cb != NULL)
01080     {
01081         return NRF_ERROR_NO_MEM;
01082     }
01083 
01084     p_block_id->module_id = RAW_MODE_APP_ID;
01085     m_raw_app_table.cb    = p_module_param->cb;
01086 
01087     return NRF_SUCCESS;
01088 }
01089 
01090 
01091 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
01092                             uint8_t           * p_src,
01093                             pstorage_size_t     size,
01094                             pstorage_size_t     offset)
01095 {
01096     VERIFY_MODULE_INITIALIZED();
01097     NULL_PARAM_CHECK(p_src);
01098     NULL_PARAM_CHECK(p_dest);
01099     MODULE_RAW_ID_RANGE_CHECK(p_dest);
01100 
01101     // Verify word alignment.
01102     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
01103     {
01104         return NRF_ERROR_INVALID_ADDR;
01105     }
01106 
01107     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
01108 }
01109 
01110 
01111 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01112 {
01113     uint32_t retval;
01114 
01115     VERIFY_MODULE_INITIALIZED();
01116     NULL_PARAM_CHECK(p_dest);
01117     MODULE_RAW_ID_RANGE_CHECK(p_dest);
01118 
01119     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01120 
01121     return retval;
01122 }
01123 
01124 #endif // PSTORAGE_RAW_MODE_ENABLE
01125 
01126 #endif /* #if NEED_PSTORAGE */