Qi Yao / LinkNode---test123

Dependencies:   mbed

Fork of LinkNode-Test by Qi Yao

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