BLE FOTA APP

Dependencies:   BLE_API mbed

It doesn't work with the default FOTA bootloader. It use NVIC_SystemReset() to enter a bootloader.

Committer:
yihui
Date:
Fri Oct 10 03:36:28 2014 +0000
Revision:
1:a607cd9655d7
use NVIC_SystemReset() to run bootloader

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 1:a607cd9655d7 1 /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
yihui 1:a607cd9655d7 2 *
yihui 1:a607cd9655d7 3 * The information contained herein is property of Nordic Semiconductor ASA.
yihui 1:a607cd9655d7 4 * Terms and conditions of usage are described in detail in NORDIC
yihui 1:a607cd9655d7 5 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
yihui 1:a607cd9655d7 6 *
yihui 1:a607cd9655d7 7 * Licensees are granted free, non-transferable use of the information. NO
yihui 1:a607cd9655d7 8 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
yihui 1:a607cd9655d7 9 * the file.
yihui 1:a607cd9655d7 10 *
yihui 1:a607cd9655d7 11 */
yihui 1:a607cd9655d7 12
yihui 1:a607cd9655d7 13 #if NEED_PSTORAGE /* disabled by default */
yihui 1:a607cd9655d7 14
yihui 1:a607cd9655d7 15 #include "pstorage.h"
yihui 1:a607cd9655d7 16 #include <stdlib.h>
yihui 1:a607cd9655d7 17 #include <stdint.h>
yihui 1:a607cd9655d7 18 #include <string.h>
yihui 1:a607cd9655d7 19 #include "nordic_common.h"
yihui 1:a607cd9655d7 20 #include "nrf_error.h"
yihui 1:a607cd9655d7 21 #include "nrf_assert.h"
yihui 1:a607cd9655d7 22 #include "nrf.h"
yihui 1:a607cd9655d7 23 #include "nrf_soc.h"
yihui 1:a607cd9655d7 24 #include "app_util.h"
yihui 1:a607cd9655d7 25
yihui 1:a607cd9655d7 26 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */
yihui 1:a607cd9655d7 27 #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. */
yihui 1:a607cd9655d7 28 #define RAW_MODE_APP_ID (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */
yihui 1:a607cd9655d7 29
yihui 1:a607cd9655d7 30 /**
yihui 1:a607cd9655d7 31 * @defgroup api_param_check API Parameters check macros.
yihui 1:a607cd9655d7 32 *
yihui 1:a607cd9655d7 33 * @details Macros that verify parameters passed to the module in the APIs. These macros
yihui 1:a607cd9655d7 34 * could be mapped to nothing in final versions of code to save execution and size.
yihui 1:a607cd9655d7 35 *
yihui 1:a607cd9655d7 36 * @{
yihui 1:a607cd9655d7 37 */
yihui 1:a607cd9655d7 38
yihui 1:a607cd9655d7 39 /**
yihui 1:a607cd9655d7 40 * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
yihui 1:a607cd9655d7 41 */
yihui 1:a607cd9655d7 42 #define NULL_PARAM_CHECK(PARAM) \
yihui 1:a607cd9655d7 43 if ((PARAM) == NULL) \
yihui 1:a607cd9655d7 44 { \
yihui 1:a607cd9655d7 45 return NRF_ERROR_NULL; \
yihui 1:a607cd9655d7 46 }
yihui 1:a607cd9655d7 47
yihui 1:a607cd9655d7 48 /**
yihui 1:a607cd9655d7 49 * @brief Verifies the module identifier supplied by the application is within permissible
yihui 1:a607cd9655d7 50 * range.
yihui 1:a607cd9655d7 51 */
yihui 1:a607cd9655d7 52 #define MODULE_ID_RANGE_CHECK(ID) \
yihui 1:a607cd9655d7 53 if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) || \
yihui 1:a607cd9655d7 54 (m_app_table[(ID)->module_id].cb == NULL)) \
yihui 1:a607cd9655d7 55 { \
yihui 1:a607cd9655d7 56 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 57 }
yihui 1:a607cd9655d7 58
yihui 1:a607cd9655d7 59 /**
yihui 1:a607cd9655d7 60 * @brief Verifies the block identifier supplied by the application is within the permissible
yihui 1:a607cd9655d7 61 * range.
yihui 1:a607cd9655d7 62 */
yihui 1:a607cd9655d7 63 #define BLOCK_ID_RANGE_CHECK(ID) \
yihui 1:a607cd9655d7 64 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \
yihui 1:a607cd9655d7 65 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \
yihui 1:a607cd9655d7 66 { \
yihui 1:a607cd9655d7 67 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 68 }
yihui 1:a607cd9655d7 69
yihui 1:a607cd9655d7 70 /**
yihui 1:a607cd9655d7 71 * @brief Verifies the block size requested by the application can be supported by the module.
yihui 1:a607cd9655d7 72 */
yihui 1:a607cd9655d7 73 #define BLOCK_SIZE_CHECK(X) \
yihui 1:a607cd9655d7 74 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \
yihui 1:a607cd9655d7 75 { \
yihui 1:a607cd9655d7 76 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 77 }
yihui 1:a607cd9655d7 78
yihui 1:a607cd9655d7 79 /**
yihui 1:a607cd9655d7 80 * @brief Verifies block size requested by Application in registration API.
yihui 1:a607cd9655d7 81 */
yihui 1:a607cd9655d7 82 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \
yihui 1:a607cd9655d7 83 if (((COUNT) == 0) || \
yihui 1:a607cd9655d7 84 ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)) || \
yihui 1:a607cd9655d7 85 ((((COUNT) * (SIZE)) > PSTORAGE_FLASH_PAGE_SIZE) && (PSTORAGE_FLASH_PAGE_SIZE % (SIZE)))) \
yihui 1:a607cd9655d7 86 { \
yihui 1:a607cd9655d7 87 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 88 }
yihui 1:a607cd9655d7 89
yihui 1:a607cd9655d7 90 /**
yihui 1:a607cd9655d7 91 * @brief Verifies size parameter provided by application in API.
yihui 1:a607cd9655d7 92 */
yihui 1:a607cd9655d7 93 #define SIZE_CHECK(ID, SIZE) \
yihui 1:a607cd9655d7 94 if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \
yihui 1:a607cd9655d7 95 { \
yihui 1:a607cd9655d7 96 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 97 }
yihui 1:a607cd9655d7 98
yihui 1:a607cd9655d7 99 /**
yihui 1:a607cd9655d7 100 * @brief Verifies offset parameter provided by application in API.
yihui 1:a607cd9655d7 101 */
yihui 1:a607cd9655d7 102 #define OFFSET_CHECK(ID, OFFSET, SIZE) \
yihui 1:a607cd9655d7 103 if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \
yihui 1:a607cd9655d7 104 { \
yihui 1:a607cd9655d7 105 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 106 }
yihui 1:a607cd9655d7 107
yihui 1:a607cd9655d7 108 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 109
yihui 1:a607cd9655d7 110 /**
yihui 1:a607cd9655d7 111 * @brief Verifies the module identifier supplied by the application is registered for raw mode.
yihui 1:a607cd9655d7 112 */
yihui 1:a607cd9655d7 113 #define MODULE_RAW_ID_RANGE_CHECK(ID) \
yihui 1:a607cd9655d7 114 if ((PSTORAGE_MAX_APPLICATIONS+1 != ((ID)->module_id)) || \
yihui 1:a607cd9655d7 115 (m_raw_app_table.cb == NULL)) \
yihui 1:a607cd9655d7 116 { \
yihui 1:a607cd9655d7 117 return NRF_ERROR_INVALID_PARAM; \
yihui 1:a607cd9655d7 118 }
yihui 1:a607cd9655d7 119
yihui 1:a607cd9655d7 120 #endif // PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 121
yihui 1:a607cd9655d7 122 /**@} */
yihui 1:a607cd9655d7 123
yihui 1:a607cd9655d7 124
yihui 1:a607cd9655d7 125 /**@brief Verify module's initialization status.
yihui 1:a607cd9655d7 126 *
yihui 1:a607cd9655d7 127 * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a
yihui 1:a607cd9655d7 128 * module API is called without initializing the module.
yihui 1:a607cd9655d7 129 */
yihui 1:a607cd9655d7 130 #define VERIFY_MODULE_INITIALIZED() \
yihui 1:a607cd9655d7 131 do \
yihui 1:a607cd9655d7 132 { \
yihui 1:a607cd9655d7 133 if (!m_module_initialized) \
yihui 1:a607cd9655d7 134 { \
yihui 1:a607cd9655d7 135 return NRF_ERROR_INVALID_STATE; \
yihui 1:a607cd9655d7 136 } \
yihui 1:a607cd9655d7 137 } while(0)
yihui 1:a607cd9655d7 138
yihui 1:a607cd9655d7 139 /**@brief Macro to fetch the block size registered for the module. */
yihui 1:a607cd9655d7 140 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
yihui 1:a607cd9655d7 141
yihui 1:a607cd9655d7 142
yihui 1:a607cd9655d7 143 /** @brief States for the Update/Clear swap backup state machine. */
yihui 1:a607cd9655d7 144 typedef enum
yihui 1:a607cd9655d7 145 {
yihui 1:a607cd9655d7 146 STATE_INIT, /**< State for indicating that swap can be used when using update/clear API. */
yihui 1:a607cd9655d7 147 STATE_DATA_TO_SWAP_WRITE, /**< State for doing backup of data page into the swap page when using update/clear API. */
yihui 1:a607cd9655d7 148 STATE_DATA_ERASE, /**< State for erasing data page when using update/clear API. */
yihui 1:a607cd9655d7 149 STATE_HEAD_RESTORE, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
yihui 1:a607cd9655d7 150 STATE_TAIL_RESTORE, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
yihui 1:a607cd9655d7 151 STATE_NEW_BODY_WRITE, /**< State for writing body (middle) data to the data page when using update/clear API. */
yihui 1:a607cd9655d7 152 STATE_SWAP_ERASE, /**< State for erasing the swap page when using the update/clear API. */
yihui 1:a607cd9655d7 153 STATE_COMPLETE, /**< State for indicating that update/clear sequence is completed internal in the module when using the update/clear API. */
yihui 1:a607cd9655d7 154 STATE_SWAP_DIRTY /**< State for initializing the swap region on module initialization. */
yihui 1:a607cd9655d7 155 } swap_backup_state_t;
yihui 1:a607cd9655d7 156
yihui 1:a607cd9655d7 157
yihui 1:a607cd9655d7 158 /**
yihui 1:a607cd9655d7 159 * @brief Application registration information.
yihui 1:a607cd9655d7 160 *
yihui 1:a607cd9655d7 161 * @details Define application specific information that application needs to maintain to be able
yihui 1:a607cd9655d7 162 * to process requests from each one of them.
yihui 1:a607cd9655d7 163 */
yihui 1:a607cd9655d7 164 typedef struct
yihui 1:a607cd9655d7 165 {
yihui 1:a607cd9655d7 166 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
yihui 1:a607cd9655d7 167 pstorage_block_t base_id; /**< Base block id assigned to the module. */
yihui 1:a607cd9655d7 168 pstorage_size_t block_size; /**< Size of block for the module. */
yihui 1:a607cd9655d7 169 pstorage_size_t block_count; /**< Number of block requested by application. */
yihui 1:a607cd9655d7 170 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. */
yihui 1:a607cd9655d7 171 } pstorage_module_table_t;
yihui 1:a607cd9655d7 172
yihui 1:a607cd9655d7 173
yihui 1:a607cd9655d7 174 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 175 /**
yihui 1:a607cd9655d7 176 * @brief Application registration information.
yihui 1:a607cd9655d7 177 *
yihui 1:a607cd9655d7 178 * @details Define application specific information that application registered for raw mode.
yihui 1:a607cd9655d7 179 */
yihui 1:a607cd9655d7 180 typedef struct
yihui 1:a607cd9655d7 181 {
yihui 1:a607cd9655d7 182 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
yihui 1:a607cd9655d7 183 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. */
yihui 1:a607cd9655d7 184 } pstorage_raw_module_table_t;
yihui 1:a607cd9655d7 185 #endif // PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 186
yihui 1:a607cd9655d7 187
yihui 1:a607cd9655d7 188 /**
yihui 1:a607cd9655d7 189 * @brief Defines command queue element.
yihui 1:a607cd9655d7 190 *
yihui 1:a607cd9655d7 191 * @details Defines command queue element. Each element encapsulates needed information to process
yihui 1:a607cd9655d7 192 * a flash access command.
yihui 1:a607cd9655d7 193 */
yihui 1:a607cd9655d7 194 typedef struct
yihui 1:a607cd9655d7 195 {
yihui 1:a607cd9655d7 196 uint8_t op_code; /**< Identifies flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
yihui 1:a607cd9655d7 197 pstorage_size_t size; /**< Identifies size in bytes requested for the operation. */
yihui 1:a607cd9655d7 198 pstorage_size_t offset; /**< Offset requested by the application for access operation. */
yihui 1:a607cd9655d7 199 pstorage_handle_t storage_addr; /**< Address/Identifier for persistent memory. */
yihui 1:a607cd9655d7 200 uint8_t * p_data_addr; /**< Address/Identifier for data memory. This is assumed to be resident memory. */
yihui 1:a607cd9655d7 201 } cmd_queue_element_t;
yihui 1:a607cd9655d7 202
yihui 1:a607cd9655d7 203
yihui 1:a607cd9655d7 204 /**
yihui 1:a607cd9655d7 205 * @brief Defines command queue, an element is free if op_code field is not invalid.
yihui 1:a607cd9655d7 206 *
yihui 1:a607cd9655d7 207 * @details Defines commands enqueued for flash access. At any point of time, this queue has one or
yihui 1:a607cd9655d7 208 * more flash access operation pending if the count field is not zero. When the queue is
yihui 1:a607cd9655d7 209 * not empty, the rp (read pointer) field points to the flash access command in progress
yihui 1:a607cd9655d7 210 * or to requested next. The queue implements a simple first in first out algorithm.
yihui 1:a607cd9655d7 211 * Data addresses are assumed to be resident.
yihui 1:a607cd9655d7 212 */
yihui 1:a607cd9655d7 213 typedef struct
yihui 1:a607cd9655d7 214 {
yihui 1:a607cd9655d7 215 uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
yihui 1:a607cd9655d7 216 uint8_t count; /**< Number of elements in the queue. */
yihui 1:a607cd9655d7 217 bool flash_access; /**< Flag to ensure an flash event received is for an request issued by the module. */
yihui 1:a607cd9655d7 218 cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
yihui 1:a607cd9655d7 219 } cmd_queue_t;
yihui 1:a607cd9655d7 220
yihui 1:a607cd9655d7 221
yihui 1:a607cd9655d7 222 static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
yihui 1:a607cd9655d7 223 static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */
yihui 1:a607cd9655d7 224 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. */
yihui 1:a607cd9655d7 225 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. */
yihui 1:a607cd9655d7 226 static bool m_module_initialized = false; /**< Flag for checking if module has been initialized. */
yihui 1:a607cd9655d7 227 static swap_backup_state_t m_swap_state; /**< Swap page state. */
yihui 1:a607cd9655d7 228
yihui 1:a607cd9655d7 229
yihui 1:a607cd9655d7 230 static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS]; /**< Registered application information table. */
yihui 1:a607cd9655d7 231
yihui 1:a607cd9655d7 232 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 233 static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */
yihui 1:a607cd9655d7 234 #endif // PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 235
yihui 1:a607cd9655d7 236
yihui 1:a607cd9655d7 237 /**
yihui 1:a607cd9655d7 238 * @brief Routine called to actually issue the flash access request to the SoftDevice.
yihui 1:a607cd9655d7 239 *
yihui 1:a607cd9655d7 240 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
yihui 1:a607cd9655d7 241 */
yihui 1:a607cd9655d7 242 static uint32_t cmd_process(void);
yihui 1:a607cd9655d7 243
yihui 1:a607cd9655d7 244
yihui 1:a607cd9655d7 245 /**
yihui 1:a607cd9655d7 246 * @brief Routine to notify application of any errors.
yihui 1:a607cd9655d7 247 *
yihui 1:a607cd9655d7 248 * @param[in] result Result of event being notified.
yihui 1:a607cd9655d7 249 */
yihui 1:a607cd9655d7 250 static void app_notify(uint32_t result);
yihui 1:a607cd9655d7 251
yihui 1:a607cd9655d7 252
yihui 1:a607cd9655d7 253 /**
yihui 1:a607cd9655d7 254 * @defgroup utility_functions Utility internal functions.
yihui 1:a607cd9655d7 255 * @{
yihui 1:a607cd9655d7 256 * @details Utility functions needed for interfacing with flash through SoC APIs.
yihui 1:a607cd9655d7 257 * SoC APIs are non blocking and provide the result of flash access through an event.
yihui 1:a607cd9655d7 258 *
yihui 1:a607cd9655d7 259 * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is
yihui 1:a607cd9655d7 260 * maintained by this module.
yihui 1:a607cd9655d7 261 */
yihui 1:a607cd9655d7 262
yihui 1:a607cd9655d7 263
yihui 1:a607cd9655d7 264 /**
yihui 1:a607cd9655d7 265 * @brief Initializes command queue element.
yihui 1:a607cd9655d7 266 *
yihui 1:a607cd9655d7 267 * @param[in] index Element index being initialized.
yihui 1:a607cd9655d7 268 */
yihui 1:a607cd9655d7 269 static void cmd_queue_element_init(uint32_t index)
yihui 1:a607cd9655d7 270 {
yihui 1:a607cd9655d7 271 // Internal function and checks on range of index can be avoided.
yihui 1:a607cd9655d7 272 m_cmd_queue.cmd[index].op_code = INVALID_OPCODE;
yihui 1:a607cd9655d7 273 m_cmd_queue.cmd[index].size = 0;
yihui 1:a607cd9655d7 274 m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS;
yihui 1:a607cd9655d7 275 m_cmd_queue.cmd[index].storage_addr.block_id = 0;
yihui 1:a607cd9655d7 276 m_cmd_queue.cmd[index].p_data_addr = NULL;
yihui 1:a607cd9655d7 277 m_cmd_queue.cmd[index].offset = 0;
yihui 1:a607cd9655d7 278 }
yihui 1:a607cd9655d7 279
yihui 1:a607cd9655d7 280
yihui 1:a607cd9655d7 281 /**
yihui 1:a607cd9655d7 282 * @brief Initializes command queue.
yihui 1:a607cd9655d7 283 */
yihui 1:a607cd9655d7 284 static void cmd_queue_init(void)
yihui 1:a607cd9655d7 285 {
yihui 1:a607cd9655d7 286 uint32_t cmd_index;
yihui 1:a607cd9655d7 287
yihui 1:a607cd9655d7 288 m_round_val = 0;
yihui 1:a607cd9655d7 289 m_swap_state = STATE_INIT;
yihui 1:a607cd9655d7 290 m_cmd_queue.rp = 0;
yihui 1:a607cd9655d7 291 m_cmd_queue.count = 0;
yihui 1:a607cd9655d7 292 m_cmd_queue.flash_access = false;
yihui 1:a607cd9655d7 293
yihui 1:a607cd9655d7 294 for (cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
yihui 1:a607cd9655d7 295 {
yihui 1:a607cd9655d7 296 cmd_queue_element_init(cmd_index);
yihui 1:a607cd9655d7 297 }
yihui 1:a607cd9655d7 298 }
yihui 1:a607cd9655d7 299
yihui 1:a607cd9655d7 300
yihui 1:a607cd9655d7 301 /**
yihui 1:a607cd9655d7 302 * @brief Routine to enqueue a flash access operation.
yihui 1:a607cd9655d7 303 *
yihui 1:a607cd9655d7 304 * @param[in] opcode Identifies operation requested to be enqueued.
yihui 1:a607cd9655d7 305 * @param[in] p_storage_addr Identiifes module and flash address on which operation is requested.
yihui 1:a607cd9655d7 306 * @param[in] p_data_addr Identifies data address for flash access.
yihui 1:a607cd9655d7 307 * @param[in] size Size in bytes of data requested for the access operation.
yihui 1:a607cd9655d7 308 * @param[in] offset Offset within the flash memory block at which operation is requested.
yihui 1:a607cd9655d7 309 *
yihui 1:a607cd9655d7 310 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
yihui 1:a607cd9655d7 311 *
yihui 1:a607cd9655d7 312 * @note All paramater check should be performed before requesting in an enqueue.
yihui 1:a607cd9655d7 313 */
yihui 1:a607cd9655d7 314 static uint32_t cmd_queue_enqueue(uint8_t opcode,
yihui 1:a607cd9655d7 315 pstorage_handle_t * p_storage_addr,
yihui 1:a607cd9655d7 316 uint8_t * p_data_addr,
yihui 1:a607cd9655d7 317 pstorage_size_t size,
yihui 1:a607cd9655d7 318 pstorage_size_t offset)
yihui 1:a607cd9655d7 319 {
yihui 1:a607cd9655d7 320 uint32_t retval;
yihui 1:a607cd9655d7 321 uint8_t write_index = 0;
yihui 1:a607cd9655d7 322
yihui 1:a607cd9655d7 323 if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
yihui 1:a607cd9655d7 324 {
yihui 1:a607cd9655d7 325 // Enqueue the command if it is queue is not full.
yihui 1:a607cd9655d7 326 write_index = m_cmd_queue.rp + m_cmd_queue.count;
yihui 1:a607cd9655d7 327
yihui 1:a607cd9655d7 328 if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
yihui 1:a607cd9655d7 329 {
yihui 1:a607cd9655d7 330 write_index -= PSTORAGE_CMD_QUEUE_SIZE;
yihui 1:a607cd9655d7 331 }
yihui 1:a607cd9655d7 332
yihui 1:a607cd9655d7 333 m_cmd_queue.cmd[write_index].op_code = opcode;
yihui 1:a607cd9655d7 334 m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr;
yihui 1:a607cd9655d7 335 m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
yihui 1:a607cd9655d7 336 m_cmd_queue.cmd[write_index].size = size;
yihui 1:a607cd9655d7 337 m_cmd_queue.cmd[write_index].offset = offset;
yihui 1:a607cd9655d7 338 retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 339 if (m_cmd_queue.flash_access == false)
yihui 1:a607cd9655d7 340 {
yihui 1:a607cd9655d7 341 retval = cmd_process();
yihui 1:a607cd9655d7 342 if (retval == NRF_ERROR_BUSY)
yihui 1:a607cd9655d7 343 {
yihui 1:a607cd9655d7 344 // In case of busy error code, it is possible to attempt to access flash.
yihui 1:a607cd9655d7 345 retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 346 }
yihui 1:a607cd9655d7 347 }
yihui 1:a607cd9655d7 348 m_cmd_queue.count++;
yihui 1:a607cd9655d7 349 }
yihui 1:a607cd9655d7 350 else
yihui 1:a607cd9655d7 351 {
yihui 1:a607cd9655d7 352 retval = NRF_ERROR_NO_MEM;
yihui 1:a607cd9655d7 353 }
yihui 1:a607cd9655d7 354
yihui 1:a607cd9655d7 355 return retval;
yihui 1:a607cd9655d7 356 }
yihui 1:a607cd9655d7 357
yihui 1:a607cd9655d7 358
yihui 1:a607cd9655d7 359 /**
yihui 1:a607cd9655d7 360 * @brief Dequeues a command element.
yihui 1:a607cd9655d7 361 *
yihui 1:a607cd9655d7 362 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
yihui 1:a607cd9655d7 363 */
yihui 1:a607cd9655d7 364 static uint32_t cmd_queue_dequeue(void)
yihui 1:a607cd9655d7 365 {
yihui 1:a607cd9655d7 366 uint32_t retval;
yihui 1:a607cd9655d7 367 retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 368
yihui 1:a607cd9655d7 369 // If any flash operation is enqueued, schedule.
yihui 1:a607cd9655d7 370 if (m_cmd_queue.count > 0)
yihui 1:a607cd9655d7 371 {
yihui 1:a607cd9655d7 372 retval = cmd_process();
yihui 1:a607cd9655d7 373 if (retval != NRF_SUCCESS)
yihui 1:a607cd9655d7 374 {
yihui 1:a607cd9655d7 375 // Flash could be accessed by modules other than Bond Manager, hence a busy error is
yihui 1:a607cd9655d7 376 // acceptable, but any other error needs to be indicated to the bond manager.
yihui 1:a607cd9655d7 377 if (retval == NRF_ERROR_BUSY)
yihui 1:a607cd9655d7 378 {
yihui 1:a607cd9655d7 379 // In case of busy error code, it is possible to attempt to access flash.
yihui 1:a607cd9655d7 380 retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 381 }
yihui 1:a607cd9655d7 382 }
yihui 1:a607cd9655d7 383 }
yihui 1:a607cd9655d7 384 else
yihui 1:a607cd9655d7 385 {
yihui 1:a607cd9655d7 386 // No flash access request pending.
yihui 1:a607cd9655d7 387 }
yihui 1:a607cd9655d7 388
yihui 1:a607cd9655d7 389 return retval;
yihui 1:a607cd9655d7 390 }
yihui 1:a607cd9655d7 391
yihui 1:a607cd9655d7 392
yihui 1:a607cd9655d7 393 /**
yihui 1:a607cd9655d7 394 * @brief Routine to notify application of any errors.
yihui 1:a607cd9655d7 395 *
yihui 1:a607cd9655d7 396 * @param[in] result Result of event being notified.
yihui 1:a607cd9655d7 397 */
yihui 1:a607cd9655d7 398 static void app_notify(uint32_t result)
yihui 1:a607cd9655d7 399 {
yihui 1:a607cd9655d7 400 pstorage_ntf_cb_t ntf_cb;
yihui 1:a607cd9655d7 401 uint8_t op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
yihui 1:a607cd9655d7 402
yihui 1:a607cd9655d7 403 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 404 if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID)
yihui 1:a607cd9655d7 405 {
yihui 1:a607cd9655d7 406 ntf_cb = m_raw_app_table.cb;
yihui 1:a607cd9655d7 407 }
yihui 1:a607cd9655d7 408 else
yihui 1:a607cd9655d7 409 #endif // PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 410 {
yihui 1:a607cd9655d7 411 ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb;
yihui 1:a607cd9655d7 412 }
yihui 1:a607cd9655d7 413
yihui 1:a607cd9655d7 414 // Indicate result to client.
yihui 1:a607cd9655d7 415 // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally
yihui 1:a607cd9655d7 416 // for clients registering multiple pages.
yihui 1:a607cd9655d7 417 ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
yihui 1:a607cd9655d7 418 op_code,
yihui 1:a607cd9655d7 419 result,
yihui 1:a607cd9655d7 420 m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
yihui 1:a607cd9655d7 421 m_cmd_queue.cmd[m_cmd_queue.rp].size);
yihui 1:a607cd9655d7 422 }
yihui 1:a607cd9655d7 423
yihui 1:a607cd9655d7 424
yihui 1:a607cd9655d7 425 /**
yihui 1:a607cd9655d7 426 * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
yihui 1:a607cd9655d7 427 *
yihui 1:a607cd9655d7 428 * @param[in] sys_evt System event to be handled.
yihui 1:a607cd9655d7 429 */
yihui 1:a607cd9655d7 430 void pstorage_sys_event_handler(uint32_t sys_evt)
yihui 1:a607cd9655d7 431 {
yihui 1:a607cd9655d7 432 uint32_t retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 433
yihui 1:a607cd9655d7 434 // Its possible the flash access was not initiated by bond manager, hence
yihui 1:a607cd9655d7 435 // event is processed only if the event triggered was for an operation requested by the
yihui 1:a607cd9655d7 436 // bond manager.
yihui 1:a607cd9655d7 437 if (m_cmd_queue.flash_access == true)
yihui 1:a607cd9655d7 438 {
yihui 1:a607cd9655d7 439 cmd_queue_element_t * p_cmd;
yihui 1:a607cd9655d7 440
yihui 1:a607cd9655d7 441 m_cmd_queue.flash_access = false;
yihui 1:a607cd9655d7 442
yihui 1:a607cd9655d7 443 if (m_swap_state == STATE_SWAP_DIRTY)
yihui 1:a607cd9655d7 444 {
yihui 1:a607cd9655d7 445 if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
yihui 1:a607cd9655d7 446 {
yihui 1:a607cd9655d7 447 m_swap_state = STATE_INIT;
yihui 1:a607cd9655d7 448 }
yihui 1:a607cd9655d7 449 else
yihui 1:a607cd9655d7 450 {
yihui 1:a607cd9655d7 451 // If clearing the swap fails, set the application back to un-initialized, to give
yihui 1:a607cd9655d7 452 // the application a chance for a retry.
yihui 1:a607cd9655d7 453 m_module_initialized = false;
yihui 1:a607cd9655d7 454 }
yihui 1:a607cd9655d7 455
yihui 1:a607cd9655d7 456 // Schedule any queued flash access operations.
yihui 1:a607cd9655d7 457 retval = cmd_queue_dequeue();
yihui 1:a607cd9655d7 458 if (retval != NRF_SUCCESS)
yihui 1:a607cd9655d7 459 {
yihui 1:a607cd9655d7 460 app_notify(retval);
yihui 1:a607cd9655d7 461 }
yihui 1:a607cd9655d7 462 return;
yihui 1:a607cd9655d7 463 }
yihui 1:a607cd9655d7 464
yihui 1:a607cd9655d7 465 switch (sys_evt)
yihui 1:a607cd9655d7 466 {
yihui 1:a607cd9655d7 467 case NRF_EVT_FLASH_OPERATION_SUCCESS:
yihui 1:a607cd9655d7 468 {
yihui 1:a607cd9655d7 469 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
yihui 1:a607cd9655d7 470 m_round_val++;
yihui 1:a607cd9655d7 471
yihui 1:a607cd9655d7 472 const bool store_finished =
yihui 1:a607cd9655d7 473 ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
yihui 1:a607cd9655d7 474 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));
yihui 1:a607cd9655d7 475
yihui 1:a607cd9655d7 476 const bool update_finished =
yihui 1:a607cd9655d7 477 ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
yihui 1:a607cd9655d7 478 (m_swap_state == STATE_COMPLETE));
yihui 1:a607cd9655d7 479
yihui 1:a607cd9655d7 480 const bool clear_block_finished =
yihui 1:a607cd9655d7 481 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
yihui 1:a607cd9655d7 482 (m_swap_state == STATE_COMPLETE));
yihui 1:a607cd9655d7 483
yihui 1:a607cd9655d7 484 const bool clear_all_finished =
yihui 1:a607cd9655d7 485 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
yihui 1:a607cd9655d7 486 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
yihui 1:a607cd9655d7 487 (m_swap_state == STATE_INIT));
yihui 1:a607cd9655d7 488
yihui 1:a607cd9655d7 489 if (update_finished ||
yihui 1:a607cd9655d7 490 clear_block_finished ||
yihui 1:a607cd9655d7 491 clear_all_finished ||
yihui 1:a607cd9655d7 492 store_finished)
yihui 1:a607cd9655d7 493 {
yihui 1:a607cd9655d7 494 m_swap_state = STATE_INIT;
yihui 1:a607cd9655d7 495
yihui 1:a607cd9655d7 496 app_notify(retval);
yihui 1:a607cd9655d7 497
yihui 1:a607cd9655d7 498 // Initialize/free the element as it is now processed.
yihui 1:a607cd9655d7 499 cmd_queue_element_init(m_cmd_queue.rp);
yihui 1:a607cd9655d7 500 m_round_val = 0;
yihui 1:a607cd9655d7 501 m_cmd_queue.count--;
yihui 1:a607cd9655d7 502 m_cmd_queue.rp++;
yihui 1:a607cd9655d7 503
yihui 1:a607cd9655d7 504 if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
yihui 1:a607cd9655d7 505 {
yihui 1:a607cd9655d7 506 m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
yihui 1:a607cd9655d7 507 }
yihui 1:a607cd9655d7 508 }
yihui 1:a607cd9655d7 509 // Schedule any queued flash access operations.
yihui 1:a607cd9655d7 510 retval = cmd_queue_dequeue();
yihui 1:a607cd9655d7 511
yihui 1:a607cd9655d7 512 if (retval != NRF_SUCCESS)
yihui 1:a607cd9655d7 513 {
yihui 1:a607cd9655d7 514 app_notify(retval);
yihui 1:a607cd9655d7 515 }
yihui 1:a607cd9655d7 516 }
yihui 1:a607cd9655d7 517 break;
yihui 1:a607cd9655d7 518
yihui 1:a607cd9655d7 519 case NRF_EVT_FLASH_OPERATION_ERROR:
yihui 1:a607cd9655d7 520 app_notify(NRF_ERROR_TIMEOUT);
yihui 1:a607cd9655d7 521 break;
yihui 1:a607cd9655d7 522
yihui 1:a607cd9655d7 523 default:
yihui 1:a607cd9655d7 524 // No implementation needed.
yihui 1:a607cd9655d7 525 break;
yihui 1:a607cd9655d7 526
yihui 1:a607cd9655d7 527 }
yihui 1:a607cd9655d7 528 }
yihui 1:a607cd9655d7 529 }
yihui 1:a607cd9655d7 530
yihui 1:a607cd9655d7 531
yihui 1:a607cd9655d7 532 /** @brief Function for handling flash accesses when using swap.
yihui 1:a607cd9655d7 533 *
yihui 1:a607cd9655d7 534 * __________________________________________________________
yihui 1:a607cd9655d7 535 * | Page |
yihui 1:a607cd9655d7 536 * |________________________________________________________|
yihui 1:a607cd9655d7 537 * | head | affected body (to be updated or cleared) | tail |
yihui 1:a607cd9655d7 538 * |______|__________________________________________|______|
yihui 1:a607cd9655d7 539 *
yihui 1:a607cd9655d7 540 * @param[in] p_cmd Queue element being processed.
yihui 1:a607cd9655d7 541 * @param[in] page_number The affected page number.
yihui 1:a607cd9655d7 542 * @param[in] head_word_size Size of the head in number of words.
yihui 1:a607cd9655d7 543 * @param[in] tail_word_size Size of the tail in number of words.
yihui 1:a607cd9655d7 544 *
yihui 1:a607cd9655d7 545 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
yihui 1:a607cd9655d7 546 */
yihui 1:a607cd9655d7 547 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd,
yihui 1:a607cd9655d7 548 uint32_t page_number,
yihui 1:a607cd9655d7 549 uint32_t head_word_size,
yihui 1:a607cd9655d7 550 uint32_t tail_word_size)
yihui 1:a607cd9655d7 551 {
yihui 1:a607cd9655d7 552 uint32_t retval = NRF_ERROR_INTERNAL;
yihui 1:a607cd9655d7 553
yihui 1:a607cd9655d7 554 // Adjust entry point to state machine if needed. When we update has no head or tail its
yihui 1:a607cd9655d7 555 // no need for using the swap.
yihui 1:a607cd9655d7 556 if (m_swap_state == STATE_INIT)
yihui 1:a607cd9655d7 557 {
yihui 1:a607cd9655d7 558 if ((head_word_size == 0) && (tail_word_size == 0))
yihui 1:a607cd9655d7 559 {
yihui 1:a607cd9655d7 560 // Only skip swap usage if the new data fills a whole flash page.
yihui 1:a607cd9655d7 561 m_swap_state = STATE_DATA_ERASE;
yihui 1:a607cd9655d7 562 }
yihui 1:a607cd9655d7 563 else
yihui 1:a607cd9655d7 564 {
yihui 1:a607cd9655d7 565 // Else start backing up application data to swap.
yihui 1:a607cd9655d7 566 m_swap_state = STATE_DATA_TO_SWAP_WRITE;
yihui 1:a607cd9655d7 567 }
yihui 1:a607cd9655d7 568 }
yihui 1:a607cd9655d7 569
yihui 1:a607cd9655d7 570 switch (m_swap_state)
yihui 1:a607cd9655d7 571 {
yihui 1:a607cd9655d7 572 case STATE_DATA_TO_SWAP_WRITE:
yihui 1:a607cd9655d7 573 // Backup previous content into swap page.
yihui 1:a607cd9655d7 574 retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
yihui 1:a607cd9655d7 575 (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
yihui 1:a607cd9655d7 576 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
yihui 1:a607cd9655d7 577 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 578 {
yihui 1:a607cd9655d7 579 m_swap_state = STATE_DATA_ERASE;
yihui 1:a607cd9655d7 580 }
yihui 1:a607cd9655d7 581 break;
yihui 1:a607cd9655d7 582
yihui 1:a607cd9655d7 583 case STATE_DATA_ERASE:
yihui 1:a607cd9655d7 584 // Clear the application data page.
yihui 1:a607cd9655d7 585 retval = sd_flash_page_erase(page_number);
yihui 1:a607cd9655d7 586 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 587 {
yihui 1:a607cd9655d7 588 if (head_word_size == 0)
yihui 1:a607cd9655d7 589 {
yihui 1:a607cd9655d7 590 if (tail_word_size == 0)
yihui 1:a607cd9655d7 591 {
yihui 1:a607cd9655d7 592 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
yihui 1:a607cd9655d7 593 {
yihui 1:a607cd9655d7 594 m_swap_state = STATE_COMPLETE;
yihui 1:a607cd9655d7 595 }
yihui 1:a607cd9655d7 596 else
yihui 1:a607cd9655d7 597 {
yihui 1:a607cd9655d7 598 m_swap_state = STATE_NEW_BODY_WRITE;
yihui 1:a607cd9655d7 599 }
yihui 1:a607cd9655d7 600 }
yihui 1:a607cd9655d7 601 else
yihui 1:a607cd9655d7 602 {
yihui 1:a607cd9655d7 603 m_swap_state = STATE_TAIL_RESTORE;
yihui 1:a607cd9655d7 604 }
yihui 1:a607cd9655d7 605 }
yihui 1:a607cd9655d7 606 else
yihui 1:a607cd9655d7 607 {
yihui 1:a607cd9655d7 608 m_swap_state = STATE_HEAD_RESTORE;
yihui 1:a607cd9655d7 609 }
yihui 1:a607cd9655d7 610 }
yihui 1:a607cd9655d7 611 break;
yihui 1:a607cd9655d7 612
yihui 1:a607cd9655d7 613 case STATE_HEAD_RESTORE:
yihui 1:a607cd9655d7 614 // Restore head from swap to application data page.
yihui 1:a607cd9655d7 615 retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
yihui 1:a607cd9655d7 616 (uint32_t *)PSTORAGE_SWAP_ADDR,
yihui 1:a607cd9655d7 617 head_word_size);
yihui 1:a607cd9655d7 618 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 619 {
yihui 1:a607cd9655d7 620 if (tail_word_size == 0)
yihui 1:a607cd9655d7 621 {
yihui 1:a607cd9655d7 622 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
yihui 1:a607cd9655d7 623 {
yihui 1:a607cd9655d7 624 m_swap_state = STATE_SWAP_ERASE;
yihui 1:a607cd9655d7 625 }
yihui 1:a607cd9655d7 626 else
yihui 1:a607cd9655d7 627 {
yihui 1:a607cd9655d7 628 m_swap_state = STATE_NEW_BODY_WRITE;
yihui 1:a607cd9655d7 629 }
yihui 1:a607cd9655d7 630 }
yihui 1:a607cd9655d7 631 else
yihui 1:a607cd9655d7 632 {
yihui 1:a607cd9655d7 633 m_swap_state = STATE_TAIL_RESTORE;
yihui 1:a607cd9655d7 634 }
yihui 1:a607cd9655d7 635 }
yihui 1:a607cd9655d7 636 break;
yihui 1:a607cd9655d7 637
yihui 1:a607cd9655d7 638 case STATE_TAIL_RESTORE:
yihui 1:a607cd9655d7 639 // Restore tail from swap to application data page.
yihui 1:a607cd9655d7 640 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
yihui 1:a607cd9655d7 641 (head_word_size * sizeof(uint32_t)) +
yihui 1:a607cd9655d7 642 p_cmd->size),
yihui 1:a607cd9655d7 643 (uint32_t *)(PSTORAGE_SWAP_ADDR +
yihui 1:a607cd9655d7 644 (head_word_size * sizeof(uint32_t)) +
yihui 1:a607cd9655d7 645 p_cmd->size),
yihui 1:a607cd9655d7 646 tail_word_size);
yihui 1:a607cd9655d7 647 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 648 {
yihui 1:a607cd9655d7 649 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
yihui 1:a607cd9655d7 650 {
yihui 1:a607cd9655d7 651 m_swap_state = STATE_SWAP_ERASE;
yihui 1:a607cd9655d7 652 }
yihui 1:a607cd9655d7 653 else
yihui 1:a607cd9655d7 654 {
yihui 1:a607cd9655d7 655 m_swap_state = STATE_NEW_BODY_WRITE;
yihui 1:a607cd9655d7 656 }
yihui 1:a607cd9655d7 657 }
yihui 1:a607cd9655d7 658 break;
yihui 1:a607cd9655d7 659
yihui 1:a607cd9655d7 660 case STATE_NEW_BODY_WRITE:
yihui 1:a607cd9655d7 661 // Write new data (body) to application data page.
yihui 1:a607cd9655d7 662 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
yihui 1:a607cd9655d7 663 (head_word_size * sizeof(uint32_t))),
yihui 1:a607cd9655d7 664 (uint32_t *)p_cmd->p_data_addr,
yihui 1:a607cd9655d7 665 p_cmd->size / sizeof(uint32_t));
yihui 1:a607cd9655d7 666 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 667 {
yihui 1:a607cd9655d7 668 if ((head_word_size == 0) && (tail_word_size == 0))
yihui 1:a607cd9655d7 669 {
yihui 1:a607cd9655d7 670 m_swap_state = STATE_COMPLETE;
yihui 1:a607cd9655d7 671 }
yihui 1:a607cd9655d7 672 else
yihui 1:a607cd9655d7 673 {
yihui 1:a607cd9655d7 674 m_swap_state = STATE_SWAP_ERASE;
yihui 1:a607cd9655d7 675 }
yihui 1:a607cd9655d7 676 }
yihui 1:a607cd9655d7 677 break;
yihui 1:a607cd9655d7 678
yihui 1:a607cd9655d7 679 case STATE_SWAP_ERASE:
yihui 1:a607cd9655d7 680 // Clear the swap page for subsequent use.
yihui 1:a607cd9655d7 681 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
yihui 1:a607cd9655d7 682 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 683 {
yihui 1:a607cd9655d7 684 m_swap_state = STATE_COMPLETE;
yihui 1:a607cd9655d7 685 }
yihui 1:a607cd9655d7 686 break;
yihui 1:a607cd9655d7 687
yihui 1:a607cd9655d7 688 default:
yihui 1:a607cd9655d7 689 break;
yihui 1:a607cd9655d7 690 }
yihui 1:a607cd9655d7 691
yihui 1:a607cd9655d7 692 return retval;
yihui 1:a607cd9655d7 693 }
yihui 1:a607cd9655d7 694
yihui 1:a607cd9655d7 695
yihui 1:a607cd9655d7 696 /**
yihui 1:a607cd9655d7 697 * @brief Routine called to actually issue the flash access request to the SoftDevice.
yihui 1:a607cd9655d7 698 *
yihui 1:a607cd9655d7 699 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
yihui 1:a607cd9655d7 700 */
yihui 1:a607cd9655d7 701 static uint32_t cmd_process(void)
yihui 1:a607cd9655d7 702 {
yihui 1:a607cd9655d7 703 uint32_t retval;
yihui 1:a607cd9655d7 704 uint32_t storage_addr;
yihui 1:a607cd9655d7 705 cmd_queue_element_t * p_cmd;
yihui 1:a607cd9655d7 706
yihui 1:a607cd9655d7 707 retval = NRF_ERROR_FORBIDDEN;
yihui 1:a607cd9655d7 708
yihui 1:a607cd9655d7 709 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
yihui 1:a607cd9655d7 710
yihui 1:a607cd9655d7 711 storage_addr = p_cmd->storage_addr.block_id;
yihui 1:a607cd9655d7 712
yihui 1:a607cd9655d7 713 switch (p_cmd->op_code)
yihui 1:a607cd9655d7 714 {
yihui 1:a607cd9655d7 715 case PSTORAGE_STORE_OP_CODE:
yihui 1:a607cd9655d7 716 {
yihui 1:a607cd9655d7 717 uint32_t size;
yihui 1:a607cd9655d7 718 uint32_t offset;
yihui 1:a607cd9655d7 719 uint8_t * p_data_addr = p_cmd->p_data_addr;
yihui 1:a607cd9655d7 720
yihui 1:a607cd9655d7 721 offset = (m_round_val * SOC_MAX_WRITE_SIZE);
yihui 1:a607cd9655d7 722 size = p_cmd->size - offset;
yihui 1:a607cd9655d7 723 p_data_addr += offset;
yihui 1:a607cd9655d7 724 storage_addr += (p_cmd->offset + offset);
yihui 1:a607cd9655d7 725
yihui 1:a607cd9655d7 726 if (size < SOC_MAX_WRITE_SIZE)
yihui 1:a607cd9655d7 727 {
yihui 1:a607cd9655d7 728 retval = sd_flash_write(((uint32_t *)storage_addr),
yihui 1:a607cd9655d7 729 (uint32_t *)p_data_addr,
yihui 1:a607cd9655d7 730 size / sizeof(uint32_t));
yihui 1:a607cd9655d7 731 }
yihui 1:a607cd9655d7 732 else
yihui 1:a607cd9655d7 733 {
yihui 1:a607cd9655d7 734 retval = sd_flash_write(((uint32_t *)storage_addr),
yihui 1:a607cd9655d7 735 (uint32_t *)p_data_addr,
yihui 1:a607cd9655d7 736 SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
yihui 1:a607cd9655d7 737 }
yihui 1:a607cd9655d7 738 }
yihui 1:a607cd9655d7 739 break;
yihui 1:a607cd9655d7 740
yihui 1:a607cd9655d7 741 case PSTORAGE_CLEAR_OP_CODE:
yihui 1:a607cd9655d7 742 {
yihui 1:a607cd9655d7 743 // Calculate page number before clearing.
yihui 1:a607cd9655d7 744 uint32_t page_number;
yihui 1:a607cd9655d7 745
yihui 1:a607cd9655d7 746 pstorage_size_t block_size =
yihui 1:a607cd9655d7 747 m_app_table[p_cmd->storage_addr.module_id].block_size;
yihui 1:a607cd9655d7 748
yihui 1:a607cd9655d7 749 pstorage_size_t block_count =
yihui 1:a607cd9655d7 750 m_app_table[p_cmd->storage_addr.module_id].block_count;
yihui 1:a607cd9655d7 751
yihui 1:a607cd9655d7 752 pstorage_block_t base_address =
yihui 1:a607cd9655d7 753 m_app_table[p_cmd->storage_addr.module_id].base_id;
yihui 1:a607cd9655d7 754
yihui 1:a607cd9655d7 755 // If the whole module should be cleared.
yihui 1:a607cd9655d7 756 if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) ||
yihui 1:a607cd9655d7 757 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
yihui 1:a607cd9655d7 758 {
yihui 1:a607cd9655d7 759 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val);
yihui 1:a607cd9655d7 760
yihui 1:a607cd9655d7 761 retval = sd_flash_page_erase(page_number);
yihui 1:a607cd9655d7 762 }
yihui 1:a607cd9655d7 763 // If one block is to be erased.
yihui 1:a607cd9655d7 764 else
yihui 1:a607cd9655d7 765 {
yihui 1:a607cd9655d7 766 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
yihui 1:a607cd9655d7 767
yihui 1:a607cd9655d7 768 uint32_t head_word_size = (
yihui 1:a607cd9655d7 769 storage_addr -
yihui 1:a607cd9655d7 770 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
yihui 1:a607cd9655d7 771 ) / sizeof(uint32_t);
yihui 1:a607cd9655d7 772
yihui 1:a607cd9655d7 773 uint32_t tail_word_size = (
yihui 1:a607cd9655d7 774 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
yihui 1:a607cd9655d7 775 (storage_addr + p_cmd->size)
yihui 1:a607cd9655d7 776 ) / sizeof(uint32_t);
yihui 1:a607cd9655d7 777
yihui 1:a607cd9655d7 778 retval = swap_state_process(p_cmd,
yihui 1:a607cd9655d7 779 page_number,
yihui 1:a607cd9655d7 780 head_word_size,
yihui 1:a607cd9655d7 781 tail_word_size);
yihui 1:a607cd9655d7 782 }
yihui 1:a607cd9655d7 783 }
yihui 1:a607cd9655d7 784 break;
yihui 1:a607cd9655d7 785
yihui 1:a607cd9655d7 786 case PSTORAGE_UPDATE_OP_CODE:
yihui 1:a607cd9655d7 787 {
yihui 1:a607cd9655d7 788 uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
yihui 1:a607cd9655d7 789
yihui 1:a607cd9655d7 790 uint32_t head_word_size = (
yihui 1:a607cd9655d7 791 storage_addr + p_cmd->offset -
yihui 1:a607cd9655d7 792 (page_number * PSTORAGE_FLASH_PAGE_SIZE)
yihui 1:a607cd9655d7 793 ) / sizeof(uint32_t);
yihui 1:a607cd9655d7 794
yihui 1:a607cd9655d7 795 uint32_t tail_word_size = (
yihui 1:a607cd9655d7 796 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
yihui 1:a607cd9655d7 797 (storage_addr + p_cmd->offset + p_cmd->size)
yihui 1:a607cd9655d7 798 ) / sizeof(uint32_t);
yihui 1:a607cd9655d7 799
yihui 1:a607cd9655d7 800 retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size);
yihui 1:a607cd9655d7 801 }
yihui 1:a607cd9655d7 802 break;
yihui 1:a607cd9655d7 803
yihui 1:a607cd9655d7 804 default:
yihui 1:a607cd9655d7 805 // Should never reach here.
yihui 1:a607cd9655d7 806 break;
yihui 1:a607cd9655d7 807 }
yihui 1:a607cd9655d7 808
yihui 1:a607cd9655d7 809 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 810 {
yihui 1:a607cd9655d7 811 m_cmd_queue.flash_access = true;
yihui 1:a607cd9655d7 812 }
yihui 1:a607cd9655d7 813
yihui 1:a607cd9655d7 814 return retval;
yihui 1:a607cd9655d7 815 }
yihui 1:a607cd9655d7 816 /** @} */
yihui 1:a607cd9655d7 817
yihui 1:a607cd9655d7 818
yihui 1:a607cd9655d7 819 uint32_t pstorage_init(void)
yihui 1:a607cd9655d7 820 {
yihui 1:a607cd9655d7 821 uint32_t retval;
yihui 1:a607cd9655d7 822
yihui 1:a607cd9655d7 823 cmd_queue_init();
yihui 1:a607cd9655d7 824
yihui 1:a607cd9655d7 825 m_next_app_instance = 0;
yihui 1:a607cd9655d7 826 m_next_page_addr = PSTORAGE_DATA_START_ADDR;
yihui 1:a607cd9655d7 827 m_round_val = 0;
yihui 1:a607cd9655d7 828
yihui 1:a607cd9655d7 829 for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
yihui 1:a607cd9655d7 830 {
yihui 1:a607cd9655d7 831 m_app_table[index].cb = NULL;
yihui 1:a607cd9655d7 832 m_app_table[index].block_size = 0;
yihui 1:a607cd9655d7 833 m_app_table[index].num_of_pages = 0;
yihui 1:a607cd9655d7 834 m_app_table[index].block_count = 0;
yihui 1:a607cd9655d7 835 }
yihui 1:a607cd9655d7 836
yihui 1:a607cd9655d7 837 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 838 m_raw_app_table.cb = NULL;
yihui 1:a607cd9655d7 839 m_raw_app_table.num_of_pages = 0;
yihui 1:a607cd9655d7 840 m_module_initialized = true;
yihui 1:a607cd9655d7 841 m_swap_state = STATE_INIT;
yihui 1:a607cd9655d7 842
yihui 1:a607cd9655d7 843 retval = NRF_SUCCESS;
yihui 1:a607cd9655d7 844 #else
yihui 1:a607cd9655d7 845 m_swap_state = STATE_SWAP_DIRTY;
yihui 1:a607cd9655d7 846
yihui 1:a607cd9655d7 847 // Erase swap region in case it is dirty.
yihui 1:a607cd9655d7 848 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
yihui 1:a607cd9655d7 849 if (retval == NRF_SUCCESS)
yihui 1:a607cd9655d7 850 {
yihui 1:a607cd9655d7 851 m_cmd_queue.flash_access = true;
yihui 1:a607cd9655d7 852 m_module_initialized = true;
yihui 1:a607cd9655d7 853 }
yihui 1:a607cd9655d7 854 #endif //PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 855
yihui 1:a607cd9655d7 856 return retval;
yihui 1:a607cd9655d7 857 }
yihui 1:a607cd9655d7 858
yihui 1:a607cd9655d7 859
yihui 1:a607cd9655d7 860 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
yihui 1:a607cd9655d7 861 pstorage_handle_t * p_block_id)
yihui 1:a607cd9655d7 862 {
yihui 1:a607cd9655d7 863 uint16_t page_count;
yihui 1:a607cd9655d7 864 uint32_t total_size;
yihui 1:a607cd9655d7 865
yihui 1:a607cd9655d7 866 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 867 NULL_PARAM_CHECK(p_module_param);
yihui 1:a607cd9655d7 868 NULL_PARAM_CHECK(p_block_id);
yihui 1:a607cd9655d7 869 NULL_PARAM_CHECK(p_module_param->cb);
yihui 1:a607cd9655d7 870 BLOCK_SIZE_CHECK(p_module_param->block_size);
yihui 1:a607cd9655d7 871 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
yihui 1:a607cd9655d7 872
yihui 1:a607cd9655d7 873 // Block size should be a multiple of word size.
yihui 1:a607cd9655d7 874 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
yihui 1:a607cd9655d7 875 {
yihui 1:a607cd9655d7 876 return NRF_ERROR_INVALID_PARAM;
yihui 1:a607cd9655d7 877 }
yihui 1:a607cd9655d7 878
yihui 1:a607cd9655d7 879 if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
yihui 1:a607cd9655d7 880 {
yihui 1:a607cd9655d7 881 return NRF_ERROR_NO_MEM;
yihui 1:a607cd9655d7 882 }
yihui 1:a607cd9655d7 883
yihui 1:a607cd9655d7 884 p_block_id->module_id = m_next_app_instance;
yihui 1:a607cd9655d7 885 p_block_id->block_id = m_next_page_addr;
yihui 1:a607cd9655d7 886
yihui 1:a607cd9655d7 887 m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
yihui 1:a607cd9655d7 888 m_app_table[m_next_app_instance].cb = p_module_param->cb;
yihui 1:a607cd9655d7 889 m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
yihui 1:a607cd9655d7 890 m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
yihui 1:a607cd9655d7 891
yihui 1:a607cd9655d7 892 // Calculate number of flash pages allocated for the device.
yihui 1:a607cd9655d7 893 page_count = 0;
yihui 1:a607cd9655d7 894 total_size = p_module_param->block_size * p_module_param->block_count;
yihui 1:a607cd9655d7 895 do
yihui 1:a607cd9655d7 896 {
yihui 1:a607cd9655d7 897 page_count++;
yihui 1:a607cd9655d7 898 if (total_size > PSTORAGE_FLASH_PAGE_SIZE)
yihui 1:a607cd9655d7 899 {
yihui 1:a607cd9655d7 900 total_size -= PSTORAGE_FLASH_PAGE_SIZE;
yihui 1:a607cd9655d7 901 }
yihui 1:a607cd9655d7 902 else
yihui 1:a607cd9655d7 903 {
yihui 1:a607cd9655d7 904 total_size = 0;
yihui 1:a607cd9655d7 905 }
yihui 1:a607cd9655d7 906 m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
yihui 1:a607cd9655d7 907 }
yihui 1:a607cd9655d7 908 while (total_size >= PSTORAGE_FLASH_PAGE_SIZE);
yihui 1:a607cd9655d7 909
yihui 1:a607cd9655d7 910 m_app_table[m_next_app_instance].num_of_pages = page_count;
yihui 1:a607cd9655d7 911 m_next_app_instance++;
yihui 1:a607cd9655d7 912
yihui 1:a607cd9655d7 913 return NRF_SUCCESS;
yihui 1:a607cd9655d7 914 }
yihui 1:a607cd9655d7 915
yihui 1:a607cd9655d7 916
yihui 1:a607cd9655d7 917 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
yihui 1:a607cd9655d7 918 pstorage_size_t block_num,
yihui 1:a607cd9655d7 919 pstorage_handle_t * p_block_id)
yihui 1:a607cd9655d7 920 {
yihui 1:a607cd9655d7 921 pstorage_handle_t temp_id;
yihui 1:a607cd9655d7 922
yihui 1:a607cd9655d7 923 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 924 NULL_PARAM_CHECK(p_base_id);
yihui 1:a607cd9655d7 925 NULL_PARAM_CHECK(p_block_id);
yihui 1:a607cd9655d7 926 MODULE_ID_RANGE_CHECK(p_base_id);
yihui 1:a607cd9655d7 927
yihui 1:a607cd9655d7 928 temp_id = (*p_base_id);
yihui 1:a607cd9655d7 929 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
yihui 1:a607cd9655d7 930
yihui 1:a607cd9655d7 931 BLOCK_ID_RANGE_CHECK(&temp_id);
yihui 1:a607cd9655d7 932
yihui 1:a607cd9655d7 933 (*p_block_id) = temp_id;
yihui 1:a607cd9655d7 934
yihui 1:a607cd9655d7 935 return NRF_SUCCESS;
yihui 1:a607cd9655d7 936 }
yihui 1:a607cd9655d7 937
yihui 1:a607cd9655d7 938
yihui 1:a607cd9655d7 939 uint32_t pstorage_store(pstorage_handle_t * p_dest,
yihui 1:a607cd9655d7 940 uint8_t * p_src,
yihui 1:a607cd9655d7 941 pstorage_size_t size,
yihui 1:a607cd9655d7 942 pstorage_size_t offset)
yihui 1:a607cd9655d7 943 {
yihui 1:a607cd9655d7 944 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 945 NULL_PARAM_CHECK(p_src);
yihui 1:a607cd9655d7 946 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 947 MODULE_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 948 BLOCK_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 949 SIZE_CHECK(p_dest, size);
yihui 1:a607cd9655d7 950 OFFSET_CHECK(p_dest, offset,size);
yihui 1:a607cd9655d7 951
yihui 1:a607cd9655d7 952 // Verify word alignment.
yihui 1:a607cd9655d7 953 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
yihui 1:a607cd9655d7 954 {
yihui 1:a607cd9655d7 955 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 956 }
yihui 1:a607cd9655d7 957
yihui 1:a607cd9655d7 958 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
yihui 1:a607cd9655d7 959 {
yihui 1:a607cd9655d7 960 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 961 }
yihui 1:a607cd9655d7 962
yihui 1:a607cd9655d7 963 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
yihui 1:a607cd9655d7 964 }
yihui 1:a607cd9655d7 965
yihui 1:a607cd9655d7 966
yihui 1:a607cd9655d7 967 uint32_t pstorage_update(pstorage_handle_t * p_dest,
yihui 1:a607cd9655d7 968 uint8_t * p_src,
yihui 1:a607cd9655d7 969 pstorage_size_t size,
yihui 1:a607cd9655d7 970 pstorage_size_t offset)
yihui 1:a607cd9655d7 971 {
yihui 1:a607cd9655d7 972 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 973 NULL_PARAM_CHECK(p_src);
yihui 1:a607cd9655d7 974 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 975 MODULE_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 976 BLOCK_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 977 SIZE_CHECK(p_dest, size);
yihui 1:a607cd9655d7 978 OFFSET_CHECK(p_dest, offset, size);
yihui 1:a607cd9655d7 979
yihui 1:a607cd9655d7 980 // Verify word alignment.
yihui 1:a607cd9655d7 981 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
yihui 1:a607cd9655d7 982 {
yihui 1:a607cd9655d7 983 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 984 }
yihui 1:a607cd9655d7 985
yihui 1:a607cd9655d7 986 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
yihui 1:a607cd9655d7 987 {
yihui 1:a607cd9655d7 988 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 989 }
yihui 1:a607cd9655d7 990
yihui 1:a607cd9655d7 991 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
yihui 1:a607cd9655d7 992 }
yihui 1:a607cd9655d7 993
yihui 1:a607cd9655d7 994
yihui 1:a607cd9655d7 995 uint32_t pstorage_load(uint8_t * p_dest,
yihui 1:a607cd9655d7 996 pstorage_handle_t * p_src,
yihui 1:a607cd9655d7 997 pstorage_size_t size,
yihui 1:a607cd9655d7 998 pstorage_size_t offset)
yihui 1:a607cd9655d7 999 {
yihui 1:a607cd9655d7 1000 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1001 NULL_PARAM_CHECK(p_src);
yihui 1:a607cd9655d7 1002 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 1003 MODULE_ID_RANGE_CHECK(p_src);
yihui 1:a607cd9655d7 1004 BLOCK_ID_RANGE_CHECK(p_src);
yihui 1:a607cd9655d7 1005 SIZE_CHECK(p_src, size);
yihui 1:a607cd9655d7 1006 OFFSET_CHECK(p_src, offset, size);
yihui 1:a607cd9655d7 1007
yihui 1:a607cd9655d7 1008 // Verify word alignment.
yihui 1:a607cd9655d7 1009 if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
yihui 1:a607cd9655d7 1010 {
yihui 1:a607cd9655d7 1011 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 1012 }
yihui 1:a607cd9655d7 1013
yihui 1:a607cd9655d7 1014 if ((!is_word_aligned((uint32_t *)p_src->block_id)))
yihui 1:a607cd9655d7 1015 {
yihui 1:a607cd9655d7 1016 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 1017 }
yihui 1:a607cd9655d7 1018
yihui 1:a607cd9655d7 1019 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
yihui 1:a607cd9655d7 1020
yihui 1:a607cd9655d7 1021 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
yihui 1:a607cd9655d7 1022
yihui 1:a607cd9655d7 1023 return NRF_SUCCESS;
yihui 1:a607cd9655d7 1024 }
yihui 1:a607cd9655d7 1025
yihui 1:a607cd9655d7 1026
yihui 1:a607cd9655d7 1027 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
yihui 1:a607cd9655d7 1028 {
yihui 1:a607cd9655d7 1029 uint32_t retval;
yihui 1:a607cd9655d7 1030
yihui 1:a607cd9655d7 1031 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1032 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 1033 MODULE_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 1034 BLOCK_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 1035
yihui 1:a607cd9655d7 1036 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
yihui 1:a607cd9655d7 1037 {
yihui 1:a607cd9655d7 1038 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 1039 }
yihui 1:a607cd9655d7 1040
yihui 1:a607cd9655d7 1041 if (
yihui 1:a607cd9655d7 1042 !(
yihui 1:a607cd9655d7 1043 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
yihui 1:a607cd9655d7 1044 m_app_table[p_dest->module_id].block_size) == 0
yihui 1:a607cd9655d7 1045 )
yihui 1:a607cd9655d7 1046 )
yihui 1:a607cd9655d7 1047 {
yihui 1:a607cd9655d7 1048 return NRF_ERROR_INVALID_PARAM;
yihui 1:a607cd9655d7 1049 }
yihui 1:a607cd9655d7 1050
yihui 1:a607cd9655d7 1051 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
yihui 1:a607cd9655d7 1052
yihui 1:a607cd9655d7 1053 return retval;
yihui 1:a607cd9655d7 1054 }
yihui 1:a607cd9655d7 1055
yihui 1:a607cd9655d7 1056
yihui 1:a607cd9655d7 1057 uint32_t pstorage_access_status_get(uint32_t * p_count)
yihui 1:a607cd9655d7 1058 {
yihui 1:a607cd9655d7 1059 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1060 NULL_PARAM_CHECK(p_count);
yihui 1:a607cd9655d7 1061
yihui 1:a607cd9655d7 1062 (*p_count) = m_cmd_queue.count;
yihui 1:a607cd9655d7 1063
yihui 1:a607cd9655d7 1064 return NRF_SUCCESS;
yihui 1:a607cd9655d7 1065 }
yihui 1:a607cd9655d7 1066
yihui 1:a607cd9655d7 1067 #ifdef PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 1068
yihui 1:a607cd9655d7 1069
yihui 1:a607cd9655d7 1070 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
yihui 1:a607cd9655d7 1071 pstorage_handle_t * p_block_id)
yihui 1:a607cd9655d7 1072 {
yihui 1:a607cd9655d7 1073 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1074 NULL_PARAM_CHECK(p_module_param);
yihui 1:a607cd9655d7 1075 NULL_PARAM_CHECK(p_block_id);
yihui 1:a607cd9655d7 1076 NULL_PARAM_CHECK(p_module_param->cb);
yihui 1:a607cd9655d7 1077
yihui 1:a607cd9655d7 1078 if (m_raw_app_table.cb != NULL)
yihui 1:a607cd9655d7 1079 {
yihui 1:a607cd9655d7 1080 return NRF_ERROR_NO_MEM;
yihui 1:a607cd9655d7 1081 }
yihui 1:a607cd9655d7 1082
yihui 1:a607cd9655d7 1083 p_block_id->module_id = RAW_MODE_APP_ID;
yihui 1:a607cd9655d7 1084 m_raw_app_table.cb = p_module_param->cb;
yihui 1:a607cd9655d7 1085
yihui 1:a607cd9655d7 1086 return NRF_SUCCESS;
yihui 1:a607cd9655d7 1087 }
yihui 1:a607cd9655d7 1088
yihui 1:a607cd9655d7 1089
yihui 1:a607cd9655d7 1090 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
yihui 1:a607cd9655d7 1091 uint8_t * p_src,
yihui 1:a607cd9655d7 1092 pstorage_size_t size,
yihui 1:a607cd9655d7 1093 pstorage_size_t offset)
yihui 1:a607cd9655d7 1094 {
yihui 1:a607cd9655d7 1095 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1096 NULL_PARAM_CHECK(p_src);
yihui 1:a607cd9655d7 1097 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 1098 MODULE_RAW_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 1099
yihui 1:a607cd9655d7 1100 // Verify word alignment.
yihui 1:a607cd9655d7 1101 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
yihui 1:a607cd9655d7 1102 {
yihui 1:a607cd9655d7 1103 return NRF_ERROR_INVALID_ADDR;
yihui 1:a607cd9655d7 1104 }
yihui 1:a607cd9655d7 1105
yihui 1:a607cd9655d7 1106 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
yihui 1:a607cd9655d7 1107 }
yihui 1:a607cd9655d7 1108
yihui 1:a607cd9655d7 1109
yihui 1:a607cd9655d7 1110 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
yihui 1:a607cd9655d7 1111 {
yihui 1:a607cd9655d7 1112 uint32_t retval;
yihui 1:a607cd9655d7 1113
yihui 1:a607cd9655d7 1114 VERIFY_MODULE_INITIALIZED();
yihui 1:a607cd9655d7 1115 NULL_PARAM_CHECK(p_dest);
yihui 1:a607cd9655d7 1116 MODULE_RAW_ID_RANGE_CHECK(p_dest);
yihui 1:a607cd9655d7 1117
yihui 1:a607cd9655d7 1118 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
yihui 1:a607cd9655d7 1119
yihui 1:a607cd9655d7 1120 return retval;
yihui 1:a607cd9655d7 1121 }
yihui 1:a607cd9655d7 1122
yihui 1:a607cd9655d7 1123 #endif // PSTORAGE_RAW_MODE_ENABLE
yihui 1:a607cd9655d7 1124
yihui 1:a607cd9655d7 1125 #endif /* #if NEED_PSTORAGE */