SG RFID nRF51822 fork

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 #include "pstorage.h "
00014 #include <stdlib.h>
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include "nordic_common.h"
00018 #include "nrf_error.h"
00019 #include "nrf_assert.h"
00020 // #include "nrf.h"
00021 #include "nrf_soc.h"
00022 #include "app_util.h "
00023 
00024 #define INVALID_OPCODE     0x00                            /**< Invalid op code identifier. */
00025 #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. */
00026 #define RAW_MODE_APP_ID    (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */
00027 
00028 /**
00029  * @defgroup api_param_check API Parameters check macros.
00030  *
00031  * @details Macros that verify parameters passed to the module in the APIs. These macros
00032  *          could be mapped to nothing in final versions of code to save execution and size.
00033  *
00034  * @{
00035  */
00036 
00037 /**
00038  * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
00039  */
00040 #define NULL_PARAM_CHECK(PARAM)                                                                   \
00041         if ((PARAM) == NULL)                                                                      \
00042         {                                                                                         \
00043             return NRF_ERROR_NULL;                                                                \
00044         }
00045 
00046 /**
00047  * @brief Verifies the module identifier supplied by the application is within permissible
00048  *        range.
00049  */
00050 #define MODULE_ID_RANGE_CHECK(ID)                                                                 \
00051         if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) ||                                   \
00052             (m_app_table[(ID)->module_id].cb == NULL))                                            \
00053         {                                                                                         \
00054             return NRF_ERROR_INVALID_PARAM;                                                       \
00055         }
00056 
00057 /**
00058  * @brief Verifies the block identifier supplied by the application is within the permissible
00059  *        range.
00060  */
00061 #define BLOCK_ID_RANGE_CHECK(ID)                                                                  \
00062         if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id +                           \
00063             (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID))))                  \
00064         {                                                                                         \
00065             return NRF_ERROR_INVALID_PARAM;                                                       \
00066         }
00067 
00068 /**
00069  * @brief Verifies the block size requested by the application can be supported by the module.
00070  */
00071 #define BLOCK_SIZE_CHECK(X)                                                                       \
00072         if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE))                   \
00073         {                                                                                         \
00074             return NRF_ERROR_INVALID_PARAM;                                                       \
00075         }
00076 
00077 /**
00078  * @brief Verifies block size requested by Application in registration API.
00079  */
00080 #define BLOCK_COUNT_CHECK(COUNT, SIZE)                                                            \
00081         if (((COUNT) == 0) ||                                                                     \
00082             ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)) ||                      \
00083             ((((COUNT) * (SIZE)) > PSTORAGE_FLASH_PAGE_SIZE) && (PSTORAGE_FLASH_PAGE_SIZE % (SIZE))))  \
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                 // In case of busy error code, it is possible to attempt to access flash.
00378                 retval = NRF_SUCCESS;
00379             }
00380         }
00381     }
00382     else
00383     {
00384         // No flash access request pending.
00385     }
00386 
00387     return retval;
00388 }
00389 
00390 
00391 /**
00392  * @brief Routine to notify application of any errors.
00393  *
00394  * @param[in] result Result of event being notified.
00395  */
00396 static void app_notify(uint32_t result)
00397 {
00398     pstorage_ntf_cb_t ntf_cb;
00399     uint8_t           op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
00400 
00401 #ifdef PSTORAGE_RAW_MODE_ENABLE
00402     if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID)
00403     {
00404         ntf_cb = m_raw_app_table.cb;
00405     }
00406     else
00407 #endif // PSTORAGE_RAW_MODE_ENABLE
00408     {
00409         ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb;
00410     }
00411 
00412     // Indicate result to client.
00413     // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally
00414     // for clients registering multiple pages.
00415     ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
00416            op_code,
00417            result,
00418            m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
00419            m_cmd_queue.cmd[m_cmd_queue.rp].size);
00420 }
00421 
00422 
00423 /**
00424  * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
00425  *
00426  * @param[in] sys_evt System event to be handled.
00427  */
00428 void pstorage_sys_event_handler(uint32_t sys_evt)
00429 {
00430     uint32_t retval = NRF_SUCCESS;
00431 
00432     // Its possible the flash access was not initiated by bond manager, hence
00433     // event is processed only if the event triggered was for an operation requested by the
00434     // bond manager.
00435     if (m_cmd_queue.flash_access == true)
00436     {
00437         cmd_queue_element_t * p_cmd;
00438 
00439         m_cmd_queue.flash_access = false;
00440 
00441         if (m_swap_state == STATE_SWAP_DIRTY)
00442         {
00443             if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
00444             {
00445                 m_swap_state = STATE_INIT;
00446             }
00447             else
00448             {
00449                 // If clearing the swap fails, set the application back to un-initialized, to give
00450                 // the application a chance for a retry.
00451                 m_module_initialized = false;
00452             }
00453 
00454             // Schedule any queued flash access operations.
00455             retval = cmd_queue_dequeue();
00456             if (retval != NRF_SUCCESS)
00457             {
00458                 app_notify(retval);
00459             }
00460             return;
00461         }
00462 
00463         switch (sys_evt)
00464         {
00465             case NRF_EVT_FLASH_OPERATION_SUCCESS:
00466             {
00467                 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00468                 m_round_val++;
00469 
00470                 const bool store_finished =
00471                     ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
00472                      ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));
00473 
00474                 const bool update_finished =
00475                     ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
00476                      (m_swap_state == STATE_COMPLETE));
00477 
00478                 const bool clear_block_finished =
00479                     ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
00480                      (m_swap_state == STATE_COMPLETE));
00481 
00482                 const bool clear_all_finished =
00483                     ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
00484                      ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
00485                      (m_swap_state == STATE_INIT));
00486 
00487                 if (update_finished ||
00488                     clear_block_finished ||
00489                     clear_all_finished ||
00490                     store_finished)
00491                 {
00492                     m_swap_state = STATE_INIT;
00493 
00494                     app_notify(retval);
00495 
00496                     // Initialize/free the element as it is now processed.
00497                     cmd_queue_element_init(m_cmd_queue.rp);
00498                     m_round_val = 0;
00499                     m_cmd_queue.count--;
00500                     m_cmd_queue.rp++;
00501 
00502                     if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
00503                     {
00504                         m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
00505                     }
00506                 }
00507                 // Schedule any queued flash access operations.
00508                 retval = cmd_queue_dequeue();
00509 
00510                 if (retval != NRF_SUCCESS)
00511                 {
00512                     app_notify(retval);
00513                 }
00514             }
00515             break;
00516 
00517             case NRF_EVT_FLASH_OPERATION_ERROR:
00518                 app_notify(NRF_ERROR_TIMEOUT);
00519                 break;
00520 
00521             default:
00522                 // No implementation needed.
00523                 break;
00524 
00525         }
00526     }
00527 }
00528 
00529 
00530 /** @brief Function for handling flash accesses when using swap.
00531  *
00532  * __________________________________________________________
00533  * |                       Page                             |
00534  * |________________________________________________________|
00535  * | head | affected body (to be updated or cleared) | tail |
00536  * |______|__________________________________________|______|
00537  *
00538  * @param[in] p_cmd          Queue element being processed.
00539  * @param[in] page_number    The affected page number.
00540  * @param[in] head_word_size Size of the head in number of words.
00541  * @param[in] tail_word_size Size of the tail in number of words.
00542  *
00543  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00544  */
00545 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd,
00546                                    uint32_t              page_number,
00547                                    uint32_t              head_word_size,
00548                                    uint32_t              tail_word_size)
00549 {
00550     uint32_t retval = NRF_ERROR_INTERNAL;
00551 
00552     // Adjust entry point to state machine if needed. When we update has no head or tail its
00553     // no need for using the swap.
00554     if (m_swap_state == STATE_INIT)
00555     {
00556         if ((head_word_size == 0) && (tail_word_size == 0))
00557         {
00558             // Only skip swap usage if the new data fills a whole flash page.
00559             m_swap_state = STATE_DATA_ERASE;
00560         }
00561         else
00562         {
00563             // Else start backing up application data to swap.
00564             m_swap_state = STATE_DATA_TO_SWAP_WRITE;
00565         }
00566     }
00567 
00568     switch (m_swap_state)
00569     {
00570         case STATE_DATA_TO_SWAP_WRITE:
00571             // Backup previous content into swap page.
00572             retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
00573                                     (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
00574                                     PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
00575             if (retval == NRF_SUCCESS)
00576             {
00577                 m_swap_state = STATE_DATA_ERASE;
00578             }
00579             break;
00580 
00581         case STATE_DATA_ERASE:
00582             // Clear the application data page.
00583             retval = sd_flash_page_erase(page_number);
00584             if (retval == NRF_SUCCESS)
00585             {
00586                 if (head_word_size == 0)
00587                 {
00588                     if (tail_word_size == 0)
00589                     {
00590                         if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00591                         {
00592                             m_swap_state = STATE_COMPLETE;
00593                         }
00594                         else
00595                         {
00596                             m_swap_state = STATE_NEW_BODY_WRITE;
00597                         }
00598                     }
00599                     else
00600                     {
00601                         m_swap_state = STATE_TAIL_RESTORE;
00602                     }
00603                 }
00604                 else
00605                 {
00606                     m_swap_state = STATE_HEAD_RESTORE;
00607                 }
00608             }
00609             break;
00610 
00611         case STATE_HEAD_RESTORE:
00612             // Restore head from swap to application data page.
00613             retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
00614                                     (uint32_t *)PSTORAGE_SWAP_ADDR,
00615                                     head_word_size);
00616             if (retval == NRF_SUCCESS)
00617             {
00618                 if (tail_word_size == 0)
00619                 {
00620                     if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00621                     {
00622                         m_swap_state = STATE_SWAP_ERASE;
00623                     }
00624                     else
00625                     {
00626                         m_swap_state = STATE_NEW_BODY_WRITE;
00627                     }
00628                 }
00629                 else
00630                 {
00631                     m_swap_state = STATE_TAIL_RESTORE;
00632                 }
00633             }
00634             break;
00635 
00636         case STATE_TAIL_RESTORE:
00637             // Restore tail from swap to application data page.
00638             retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
00639                                                  (head_word_size * sizeof(uint32_t)) +
00640                                                  p_cmd->size),
00641                                     (uint32_t *)(PSTORAGE_SWAP_ADDR +
00642                                                  (head_word_size * sizeof(uint32_t)) +
00643                                                  p_cmd->size),
00644                                     tail_word_size);
00645             if (retval == NRF_SUCCESS)
00646             {
00647                 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
00648                 {
00649                     m_swap_state = STATE_SWAP_ERASE;
00650                 }
00651                 else
00652                 {
00653                     m_swap_state = STATE_NEW_BODY_WRITE;
00654                 }
00655             }
00656             break;
00657 
00658         case STATE_NEW_BODY_WRITE:
00659             // Write new data (body) to application data page.
00660             retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
00661                                                  (head_word_size * sizeof(uint32_t))),
00662                                     (uint32_t *)p_cmd->p_data_addr,
00663                                     p_cmd->size / sizeof(uint32_t));
00664             if (retval == NRF_SUCCESS)
00665             {
00666                 if ((head_word_size == 0) && (tail_word_size == 0))
00667                 {
00668                     m_swap_state = STATE_COMPLETE;
00669                 }
00670                 else
00671                 {
00672                     m_swap_state = STATE_SWAP_ERASE;
00673                 }
00674             }
00675             break;
00676 
00677         case STATE_SWAP_ERASE:
00678             // Clear the swap page for subsequent use.
00679             retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
00680             if (retval == NRF_SUCCESS)
00681             {
00682                 m_swap_state = STATE_COMPLETE;
00683             }
00684             break;
00685 
00686         default:
00687             break;
00688     }
00689 
00690     return retval;
00691 }
00692 
00693 
00694 /**
00695  * @brief Routine called to actually issue the flash access request to the SoftDevice.
00696  *
00697  * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
00698  */
00699 static uint32_t cmd_process(void)
00700 {
00701     uint32_t              retval;
00702     uint32_t              storage_addr;
00703     cmd_queue_element_t * p_cmd;
00704 
00705     retval = NRF_ERROR_FORBIDDEN;
00706 
00707     p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
00708 
00709     storage_addr = p_cmd->storage_addr.block_id;
00710 
00711     switch (p_cmd->op_code)
00712     {
00713         case PSTORAGE_STORE_OP_CODE:
00714         {
00715             uint32_t  size;
00716             uint32_t  offset;
00717             uint8_t * p_data_addr = p_cmd->p_data_addr;
00718 
00719             offset        = (m_round_val * SOC_MAX_WRITE_SIZE);
00720             size          = p_cmd->size - offset;
00721             p_data_addr  += offset;
00722             storage_addr += (p_cmd->offset + offset);
00723 
00724             if (size < SOC_MAX_WRITE_SIZE)
00725             {
00726                 retval = sd_flash_write(((uint32_t *)storage_addr),
00727                                         (uint32_t *)p_data_addr,
00728                                         size / sizeof(uint32_t));
00729             }
00730             else
00731             {
00732                 retval = sd_flash_write(((uint32_t *)storage_addr),
00733                                         (uint32_t *)p_data_addr,
00734                                         SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
00735             }
00736         }
00737         break;
00738 
00739         case PSTORAGE_CLEAR_OP_CODE:
00740         {
00741             // Calculate page number before clearing.
00742             uint32_t page_number;
00743 
00744             pstorage_size_t block_size =
00745                 m_app_table[p_cmd->storage_addr.module_id].block_size;
00746 
00747             pstorage_size_t block_count =
00748                 m_app_table[p_cmd->storage_addr.module_id].block_count;
00749 
00750             pstorage_block_t base_address =
00751                 m_app_table[p_cmd->storage_addr.module_id].base_id;
00752 
00753             // If the whole module should be cleared.
00754             if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) ||
00755                 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
00756             {
00757                 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val);
00758 
00759                 retval = sd_flash_page_erase(page_number);
00760             }
00761             // If one block is to be erased.
00762             else
00763             {
00764                 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
00765 
00766                 uint32_t head_word_size = (
00767                     storage_addr -
00768                     (page_number * PSTORAGE_FLASH_PAGE_SIZE)
00769                     ) / sizeof(uint32_t);
00770 
00771                 uint32_t tail_word_size = (
00772                     ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
00773                     (storage_addr + p_cmd->size)
00774                     ) / sizeof(uint32_t);
00775 
00776                 retval = swap_state_process(p_cmd,
00777                                             page_number,
00778                                             head_word_size,
00779                                             tail_word_size);
00780             }
00781         }
00782         break;
00783 
00784         case PSTORAGE_UPDATE_OP_CODE:
00785         {
00786             uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
00787 
00788             uint32_t head_word_size = (
00789                 storage_addr + p_cmd->offset -
00790                 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
00791                 ) / sizeof(uint32_t);
00792 
00793             uint32_t tail_word_size = (
00794                 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
00795                 (storage_addr + p_cmd->offset + p_cmd->size)
00796                 ) / sizeof(uint32_t);
00797 
00798             retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size);
00799         }
00800         break;
00801 
00802         default:
00803             // Should never reach here.
00804             break;
00805     }
00806 
00807     if (retval == NRF_SUCCESS)
00808     {
00809         m_cmd_queue.flash_access = true;
00810     }
00811 
00812     return retval;
00813 }
00814 /** @} */
00815 
00816 
00817 uint32_t pstorage_init(void)
00818 {
00819     uint32_t retval;
00820 
00821     cmd_queue_init();
00822 
00823     m_next_app_instance = 0;
00824     m_next_page_addr    = PSTORAGE_DATA_START_ADDR;
00825     m_round_val         = 0;
00826 
00827     for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
00828     {
00829         m_app_table[index].cb           = NULL;
00830         m_app_table[index].block_size   = 0;
00831         m_app_table[index].num_of_pages = 0;
00832         m_app_table[index].block_count  = 0;
00833     }
00834 
00835 #ifdef PSTORAGE_RAW_MODE_ENABLE
00836     m_raw_app_table.cb           = NULL;
00837     m_raw_app_table.num_of_pages = 0;
00838     m_module_initialized         = true;
00839     m_swap_state                 = STATE_INIT;
00840 
00841     retval = NRF_SUCCESS;
00842 #else
00843     m_swap_state = STATE_SWAP_DIRTY;
00844 
00845     // Erase swap region in case it is dirty.
00846     retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
00847     if (retval == NRF_SUCCESS)
00848     {
00849         m_cmd_queue.flash_access = true;
00850         m_module_initialized     = true;
00851     }
00852 #endif //PSTORAGE_RAW_MODE_ENABLE
00853 
00854     return retval;
00855 }
00856 
00857 
00858 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
00859                            pstorage_handle_t       * p_block_id)
00860 {
00861     uint16_t page_count;
00862     uint32_t total_size;
00863 
00864     VERIFY_MODULE_INITIALIZED();
00865     NULL_PARAM_CHECK(p_module_param);
00866     NULL_PARAM_CHECK(p_block_id);
00867     NULL_PARAM_CHECK(p_module_param->cb);
00868     BLOCK_SIZE_CHECK(p_module_param->block_size);
00869     BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
00870 
00871     // Block size should be a multiple of word size.
00872     if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
00873     {
00874         return NRF_ERROR_INVALID_PARAM;
00875     }
00876 
00877     if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
00878     {
00879         return NRF_ERROR_NO_MEM;
00880     }
00881 
00882     p_block_id->module_id = m_next_app_instance;
00883     p_block_id->block_id  = m_next_page_addr;
00884 
00885     m_app_table[m_next_app_instance].base_id     = p_block_id->block_id;
00886     m_app_table[m_next_app_instance].cb          = p_module_param->cb;
00887     m_app_table[m_next_app_instance].block_size  = p_module_param->block_size;
00888     m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
00889 
00890     // Calculate number of flash pages allocated for the device.
00891     page_count = 0;
00892     total_size = p_module_param->block_size * p_module_param->block_count;
00893     do
00894     {
00895         page_count++;
00896         if (total_size > PSTORAGE_FLASH_PAGE_SIZE)
00897         {
00898             total_size -= PSTORAGE_FLASH_PAGE_SIZE;
00899         }
00900         else
00901         {
00902             total_size = 0;
00903         }
00904         m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
00905     }
00906     while (total_size >= PSTORAGE_FLASH_PAGE_SIZE);
00907 
00908     m_app_table[m_next_app_instance].num_of_pages = page_count;
00909     m_next_app_instance++;
00910 
00911     return NRF_SUCCESS;
00912 }
00913 
00914 
00915 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
00916                                        pstorage_size_t     block_num,
00917                                        pstorage_handle_t * p_block_id)
00918 {
00919     pstorage_handle_t temp_id;
00920 
00921     VERIFY_MODULE_INITIALIZED();
00922     NULL_PARAM_CHECK(p_base_id);
00923     NULL_PARAM_CHECK(p_block_id);
00924     MODULE_ID_RANGE_CHECK(p_base_id);
00925 
00926     temp_id           = (*p_base_id);
00927     temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
00928 
00929     BLOCK_ID_RANGE_CHECK(&temp_id);
00930 
00931     (*p_block_id) = temp_id;
00932 
00933     return NRF_SUCCESS;
00934 }
00935 
00936 
00937 uint32_t pstorage_store(pstorage_handle_t * p_dest,
00938                         uint8_t           * p_src,
00939                         pstorage_size_t     size,
00940                         pstorage_size_t     offset)
00941 {
00942     VERIFY_MODULE_INITIALIZED();
00943     NULL_PARAM_CHECK(p_src);
00944     NULL_PARAM_CHECK(p_dest);
00945     MODULE_ID_RANGE_CHECK(p_dest);
00946     BLOCK_ID_RANGE_CHECK(p_dest);
00947     SIZE_CHECK(p_dest, size);
00948     OFFSET_CHECK(p_dest, offset,size);
00949 
00950     // Verify word alignment.
00951     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
00952     {
00953         return NRF_ERROR_INVALID_ADDR;
00954     }
00955 
00956     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
00957     {
00958         return NRF_ERROR_INVALID_ADDR;
00959     }
00960 
00961     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
00962 }
00963 
00964 
00965 uint32_t pstorage_update(pstorage_handle_t * p_dest,
00966                          uint8_t           * p_src,
00967                          pstorage_size_t     size,
00968                          pstorage_size_t     offset)
00969 {
00970     VERIFY_MODULE_INITIALIZED();
00971     NULL_PARAM_CHECK(p_src);
00972     NULL_PARAM_CHECK(p_dest);
00973     MODULE_ID_RANGE_CHECK(p_dest);
00974     BLOCK_ID_RANGE_CHECK(p_dest);
00975     SIZE_CHECK(p_dest, size);
00976     OFFSET_CHECK(p_dest, offset, size);
00977 
00978     // Verify word alignment.
00979     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
00980     {
00981         return NRF_ERROR_INVALID_ADDR;
00982     }
00983 
00984     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
00985     {
00986         return NRF_ERROR_INVALID_ADDR;
00987     }
00988 
00989     return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
00990 }
00991 
00992 
00993 uint32_t pstorage_load(uint8_t           * p_dest,
00994                        pstorage_handle_t * p_src,
00995                        pstorage_size_t     size,
00996                        pstorage_size_t     offset)
00997 {
00998     VERIFY_MODULE_INITIALIZED();
00999     NULL_PARAM_CHECK(p_src);
01000     NULL_PARAM_CHECK(p_dest);
01001     MODULE_ID_RANGE_CHECK(p_src);
01002     BLOCK_ID_RANGE_CHECK(p_src);
01003     SIZE_CHECK(p_src, size);
01004     OFFSET_CHECK(p_src, offset, size);
01005 
01006     // Verify word alignment.
01007     if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
01008     {
01009         return NRF_ERROR_INVALID_ADDR;
01010     }
01011 
01012     if ((!is_word_aligned((uint32_t *)p_src->block_id)))
01013     {
01014         return NRF_ERROR_INVALID_ADDR;
01015     }
01016 
01017     memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
01018 
01019     m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
01020 
01021     return NRF_SUCCESS;
01022 }
01023 
01024 
01025 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01026 {
01027     uint32_t retval;
01028 
01029     VERIFY_MODULE_INITIALIZED();
01030     NULL_PARAM_CHECK(p_dest);
01031     MODULE_ID_RANGE_CHECK(p_dest);
01032     BLOCK_ID_RANGE_CHECK(p_dest);
01033 
01034     if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
01035     {
01036         return NRF_ERROR_INVALID_ADDR;
01037     }
01038 
01039     if (
01040         !(
01041             ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
01042              m_app_table[p_dest->module_id].block_size) == 0
01043             )
01044         )
01045     {
01046         return NRF_ERROR_INVALID_PARAM;
01047     }
01048 
01049     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01050 
01051     return retval;
01052 }
01053 
01054 
01055 uint32_t pstorage_access_status_get(uint32_t * p_count)
01056 {
01057     VERIFY_MODULE_INITIALIZED();
01058     NULL_PARAM_CHECK(p_count);
01059 
01060     (*p_count) = m_cmd_queue.count;
01061 
01062     return NRF_SUCCESS;
01063 }
01064 
01065 #ifdef PSTORAGE_RAW_MODE_ENABLE
01066 
01067 
01068 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
01069                                pstorage_handle_t       * p_block_id)
01070 {
01071     VERIFY_MODULE_INITIALIZED();
01072     NULL_PARAM_CHECK(p_module_param);
01073     NULL_PARAM_CHECK(p_block_id);
01074     NULL_PARAM_CHECK(p_module_param->cb);
01075 
01076     if (m_raw_app_table.cb != NULL)
01077     {
01078         return NRF_ERROR_NO_MEM;
01079     }
01080 
01081     p_block_id->module_id = RAW_MODE_APP_ID;
01082     m_raw_app_table.cb    = p_module_param->cb;
01083 
01084     return NRF_SUCCESS;
01085 }
01086 
01087 
01088 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
01089                             uint8_t           * p_src,
01090                             pstorage_size_t     size,
01091                             pstorage_size_t     offset)
01092 {
01093     VERIFY_MODULE_INITIALIZED();
01094     NULL_PARAM_CHECK(p_src);
01095     NULL_PARAM_CHECK(p_dest);
01096     MODULE_RAW_ID_RANGE_CHECK(p_dest);
01097 
01098     // Verify word alignment.
01099     if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
01100     {
01101         return NRF_ERROR_INVALID_ADDR;
01102     }
01103 
01104     return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
01105 }
01106 
01107 
01108 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
01109 {
01110     uint32_t retval;
01111 
01112     VERIFY_MODULE_INITIALIZED();
01113     NULL_PARAM_CHECK(p_dest);
01114     MODULE_RAW_ID_RANGE_CHECK(p_dest);
01115 
01116     retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
01117 
01118     return retval;
01119 }
01120 
01121 #endif // PSTORAGE_RAW_MODE_ENABLE