Nordic nrf51 sdk sources. Mirrored from https://github.com/ARMmbed/nrf51-sdk.

Dependents:   nRF51822 nRF51822

Committer:
vcoubard
Date:
Thu Apr 07 17:37:56 2016 +0100
Revision:
28:041dac1366b2
Parent:
27:0fe148f1bca3
Child:
29:286940b7ee5a
Synchronized with git rev 012b8118
Author: Liyou Zhou
Pull in files from sdk 10.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vcoubard 28:041dac1366b2 1 /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
vcoubard 28:041dac1366b2 2 *
vcoubard 28:041dac1366b2 3 * The information contained herein is property of Nordic Semiconductor ASA.
vcoubard 28:041dac1366b2 4 * Terms and conditions of usage are described in detail in NORDIC
vcoubard 28:041dac1366b2 5 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
vcoubard 28:041dac1366b2 6 *
vcoubard 28:041dac1366b2 7 * Licensees are granted free, non-transferable use of the information. NO
vcoubard 28:041dac1366b2 8 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
vcoubard 28:041dac1366b2 9 * the file.
vcoubard 28:041dac1366b2 10 *
Vincent Coubard 0:f2542974c862 11 */
Vincent Coubard 0:f2542974c862 12
Vincent Coubard 0:f2542974c862 13 #include "pstorage.h"
Vincent Coubard 0:f2542974c862 14 #include <stdlib.h>
Vincent Coubard 0:f2542974c862 15 #include <stdint.h>
Vincent Coubard 0:f2542974c862 16 #include <string.h>
Vincent Coubard 0:f2542974c862 17 #include "nordic_common.h"
Vincent Coubard 0:f2542974c862 18 #include "nrf_error.h"
Vincent Coubard 0:f2542974c862 19 #include "nrf_assert.h"
vcoubard 1:ebc0e0ef0a11 20 #include "nrf.h"
Vincent Coubard 0:f2542974c862 21 #include "nrf_soc.h"
Vincent Coubard 0:f2542974c862 22 #include "app_util.h"
vcoubard 28:041dac1366b2 23 #include "app_error.h"
Vincent Coubard 0:f2542974c862 24
vcoubard 28:041dac1366b2 25 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */
vcoubard 28:041dac1366b2 26 #define SOC_MAX_WRITE_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
vcoubard 28:041dac1366b2 27 #define RAW_MODE_APP_ID (PSTORAGE_NUM_OF_PAGES + 1) /**< Application id for raw mode. */
vcoubard 28:041dac1366b2 28
vcoubard 28:041dac1366b2 29 #if defined(NRF52)
vcoubard 28:041dac1366b2 30 #define SD_CMD_MAX_TRIES 1000 /**< Number of times to try a softdevice flash operatoion, specific for nRF52 to account for longest time of flash page erase*/
vcoubard 28:041dac1366b2 31 #else
vcoubard 28:041dac1366b2 32 #define SD_CMD_MAX_TRIES 3 /**< Number of times to try a softdevice flash operation when the @ref NRF_EVT_FLASH_OPERATION_ERROR sys_evt is received. */
vcoubard 28:041dac1366b2 33 #endif /* defined(NRF52) */
vcoubard 28:041dac1366b2 34
vcoubard 28:041dac1366b2 35 #define MASK_TAIL_SWAP_DONE (1 << 0) /**< Flag for checking if the tail restore area has been written to swap page. */
vcoubard 28:041dac1366b2 36 #define MASK_SINGLE_PAGE_OPERATION (1 << 1) /**< Flag for checking if command is a single flash page operation. */
vcoubard 28:041dac1366b2 37 #define MASK_MODULE_INITIALIZED (1 << 2) /**< Flag for checking if the module has been initialized. */
vcoubard 28:041dac1366b2 38 #define MASK_FLASH_API_ERR_BUSY (1 << 3) /**< Flag for checking if flash API returned NRF_ERROR_BUSY. */
Vincent Coubard 0:f2542974c862 39
Vincent Coubard 0:f2542974c862 40 /**
Vincent Coubard 0:f2542974c862 41 * @defgroup api_param_check API Parameters check macros.
Vincent Coubard 0:f2542974c862 42 *
Vincent Coubard 0:f2542974c862 43 * @details Macros that verify parameters passed to the module in the APIs. These macros
vcoubard 28:041dac1366b2 44 * could be mapped to nothing in final code versions to save execution and size.
Vincent Coubard 0:f2542974c862 45 *
Vincent Coubard 0:f2542974c862 46 * @{
Vincent Coubard 0:f2542974c862 47 */
Vincent Coubard 0:f2542974c862 48
vcoubard 28:041dac1366b2 49 /**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL.
Vincent Coubard 0:f2542974c862 50 */
Vincent Coubard 0:f2542974c862 51 #define NULL_PARAM_CHECK(PARAM) \
Vincent Coubard 0:f2542974c862 52 if ((PARAM) == NULL) \
Vincent Coubard 0:f2542974c862 53 { \
Vincent Coubard 0:f2542974c862 54 return NRF_ERROR_NULL; \
Vincent Coubard 0:f2542974c862 55 }
Vincent Coubard 0:f2542974c862 56
vcoubard 28:041dac1366b2 57 /**@brief Verifies that the module identifier supplied by the application is within permissible
Vincent Coubard 0:f2542974c862 58 * range.
Vincent Coubard 0:f2542974c862 59 */
Vincent Coubard 0:f2542974c862 60 #define MODULE_ID_RANGE_CHECK(ID) \
vcoubard 28:041dac1366b2 61 if ((((ID)->module_id) >= PSTORAGE_NUM_OF_PAGES) || \
Vincent Coubard 0:f2542974c862 62 (m_app_table[(ID)->module_id].cb == NULL)) \
Vincent Coubard 0:f2542974c862 63 { \
Vincent Coubard 0:f2542974c862 64 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 65 }
Vincent Coubard 0:f2542974c862 66
vcoubard 28:041dac1366b2 67 /**@brief Verifies that the block identifier supplied by the application is within the permissible
Vincent Coubard 0:f2542974c862 68 * range.
Vincent Coubard 0:f2542974c862 69 */
Vincent Coubard 0:f2542974c862 70 #define BLOCK_ID_RANGE_CHECK(ID) \
Vincent Coubard 0:f2542974c862 71 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \
Vincent Coubard 0:f2542974c862 72 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \
Vincent Coubard 0:f2542974c862 73 { \
Vincent Coubard 0:f2542974c862 74 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 75 }
Vincent Coubard 0:f2542974c862 76
vcoubard 28:041dac1366b2 77 /**@brief Verifies that the block size requested by the application can be supported by the module.
Vincent Coubard 0:f2542974c862 78 */
Vincent Coubard 0:f2542974c862 79 #define BLOCK_SIZE_CHECK(X) \
Vincent Coubard 0:f2542974c862 80 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \
Vincent Coubard 0:f2542974c862 81 { \
Vincent Coubard 0:f2542974c862 82 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 83 }
Vincent Coubard 0:f2542974c862 84
vcoubard 28:041dac1366b2 85 /**@brief Verifies the block size requested by the application in registration API.
Vincent Coubard 0:f2542974c862 86 */
Vincent Coubard 0:f2542974c862 87 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \
Vincent Coubard 0:f2542974c862 88 if (((COUNT) == 0) || \
vcoubard 28:041dac1366b2 89 ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR))) \
Vincent Coubard 0:f2542974c862 90 { \
Vincent Coubard 0:f2542974c862 91 return NRF_ERROR_INVALID_PARAM; \
vcoubard 28:041dac1366b2 92 }
Vincent Coubard 0:f2542974c862 93
vcoubard 28:041dac1366b2 94 /**@brief Verifies the size parameter provided by the application in API.
Vincent Coubard 0:f2542974c862 95 */
Vincent Coubard 0:f2542974c862 96 #define SIZE_CHECK(ID, SIZE) \
Vincent Coubard 0:f2542974c862 97 if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \
Vincent Coubard 0:f2542974c862 98 { \
Vincent Coubard 0:f2542974c862 99 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 100 }
Vincent Coubard 0:f2542974c862 101
vcoubard 28:041dac1366b2 102 /**@brief Verifies the offset parameter provided by the application in API.
Vincent Coubard 0:f2542974c862 103 */
Vincent Coubard 0:f2542974c862 104 #define OFFSET_CHECK(ID, OFFSET, SIZE) \
Vincent Coubard 0:f2542974c862 105 if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \
Vincent Coubard 0:f2542974c862 106 { \
Vincent Coubard 0:f2542974c862 107 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 108 }
Vincent Coubard 0:f2542974c862 109
Vincent Coubard 0:f2542974c862 110 #ifdef PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 111
vcoubard 28:041dac1366b2 112 /**@brief Verifies the module identifier supplied by the application.
Vincent Coubard 0:f2542974c862 113 */
vcoubard 28:041dac1366b2 114 #define MODULE_RAW_HANDLE_CHECK(ID) \
vcoubard 28:041dac1366b2 115 if ((((ID)->module_id) != RAW_MODE_APP_ID)) \
Vincent Coubard 0:f2542974c862 116 { \
Vincent Coubard 0:f2542974c862 117 return NRF_ERROR_INVALID_PARAM; \
Vincent Coubard 0:f2542974c862 118 }
Vincent Coubard 0:f2542974c862 119
Vincent Coubard 0:f2542974c862 120 #endif // PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 121
Vincent Coubard 0:f2542974c862 122 /**@} */
Vincent Coubard 0:f2542974c862 123
Vincent Coubard 0:f2542974c862 124
vcoubard 28:041dac1366b2 125 /**@brief Verify module's initialization status.
Vincent Coubard 0:f2542974c862 126 *
vcoubard 28:041dac1366b2 127 * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE when a
vcoubard 28:041dac1366b2 128 * module API is called without initializing the module.
Vincent Coubard 0:f2542974c862 129 */
Vincent Coubard 0:f2542974c862 130 #define VERIFY_MODULE_INITIALIZED() \
Vincent Coubard 0:f2542974c862 131 do \
Vincent Coubard 0:f2542974c862 132 { \
vcoubard 28:041dac1366b2 133 if (!(m_flags & MASK_MODULE_INITIALIZED)) \
Vincent Coubard 0:f2542974c862 134 { \
Vincent Coubard 0:f2542974c862 135 return NRF_ERROR_INVALID_STATE; \
Vincent Coubard 0:f2542974c862 136 } \
Vincent Coubard 0:f2542974c862 137 } while(0)
Vincent Coubard 0:f2542974c862 138
Vincent Coubard 0:f2542974c862 139 /**@brief Macro to fetch the block size registered for the module. */
Vincent Coubard 0:f2542974c862 140 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
Vincent Coubard 0:f2542974c862 141
vcoubard 28:041dac1366b2 142 /**@brief Main state machine of the component. */
Vincent Coubard 0:f2542974c862 143 typedef enum
Vincent Coubard 0:f2542974c862 144 {
vcoubard 28:041dac1366b2 145 STATE_IDLE, /**< State for being idle (no command execution in progress). */
vcoubard 28:041dac1366b2 146 STATE_STORE, /**< State for storing data when using store/update API. */
vcoubard 28:041dac1366b2 147 STATE_DATA_ERASE_WITH_SWAP, /**< State for erasing the data page when using update/clear API when use of swap page is required. */
vcoubard 28:041dac1366b2 148 STATE_DATA_ERASE, /**< State for erasing the data page when using update/clear API without the need to use the swap page. */
vcoubard 28:041dac1366b2 149 STATE_ERROR /**< State entered when command processing is terminated abnormally. */
vcoubard 28:041dac1366b2 150 } pstorage_state_t;
Vincent Coubard 0:f2542974c862 151
vcoubard 28:041dac1366b2 152 /**@brief Sub state machine contained by @ref STATE_DATA_ERASE_WITH_SWAP super state machine. */
vcoubard 28:041dac1366b2 153 typedef enum
vcoubard 28:041dac1366b2 154 {
vcoubard 28:041dac1366b2 155 STATE_ERASE_SWAP, /**< State for erasing the swap page when using the update/clear API. */
vcoubard 28:041dac1366b2 156 STATE_WRITE_DATA_TO_SWAP, /**< State for writing the data page into the swap page when using update/clear API. */
vcoubard 28:041dac1366b2 157 STATE_ERASE_DATA_PAGE, /**< State for erasing data page when using update/clear API. */
vcoubard 28:041dac1366b2 158 STATE_RESTORE_TAIL, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
vcoubard 28:041dac1366b2 159 STATE_RESTORE_HEAD, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
vcoubard 28:041dac1366b2 160 SWAP_SUB_STATE_MAX /**< Enumeration upper bound. */
vcoubard 28:041dac1366b2 161 } flash_swap_sub_state_t;
Vincent Coubard 0:f2542974c862 162
vcoubard 28:041dac1366b2 163 /**@brief Application registration information.
Vincent Coubard 0:f2542974c862 164 *
vcoubard 28:041dac1366b2 165 * @details Defines application specific information that the application needs to maintain to be able
Vincent Coubard 0:f2542974c862 166 * to process requests from each one of them.
Vincent Coubard 0:f2542974c862 167 */
Vincent Coubard 0:f2542974c862 168 typedef struct
Vincent Coubard 0:f2542974c862 169 {
vcoubard 28:041dac1366b2 170 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
vcoubard 28:041dac1366b2 171 pstorage_block_t base_id; /**< Base block ID assigned to the module. */
vcoubard 28:041dac1366b2 172 pstorage_size_t block_size; /**< Size of block for the module. */
vcoubard 28:041dac1366b2 173 pstorage_size_t block_count; /**< Number of blocks requested by the application. */
Vincent Coubard 0:f2542974c862 174 } pstorage_module_table_t;
Vincent Coubard 0:f2542974c862 175
Vincent Coubard 0:f2542974c862 176
Vincent Coubard 0:f2542974c862 177 #ifdef PSTORAGE_RAW_MODE_ENABLE
vcoubard 28:041dac1366b2 178 /**@brief Application registration information.
Vincent Coubard 0:f2542974c862 179 *
vcoubard 28:041dac1366b2 180 * @details Defines application specific information that the application registered for raw mode.
Vincent Coubard 0:f2542974c862 181 */
Vincent Coubard 0:f2542974c862 182 typedef struct
Vincent Coubard 0:f2542974c862 183 {
vcoubard 28:041dac1366b2 184 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of the result of flash access. */
Vincent Coubard 0:f2542974c862 185 } pstorage_raw_module_table_t;
Vincent Coubard 0:f2542974c862 186 #endif // PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 187
Vincent Coubard 0:f2542974c862 188
vcoubard 28:041dac1366b2 189 /**@brief Defines command queue element.
Vincent Coubard 0:f2542974c862 190 *
Vincent Coubard 0:f2542974c862 191 * @details Defines command queue element. Each element encapsulates needed information to process
Vincent Coubard 0:f2542974c862 192 * a flash access command.
Vincent Coubard 0:f2542974c862 193 */
Vincent Coubard 0:f2542974c862 194 typedef struct
Vincent Coubard 0:f2542974c862 195 {
vcoubard 28:041dac1366b2 196 uint8_t op_code; /**< Identifies the flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
vcoubard 28:041dac1366b2 197 pstorage_size_t size; /**< Identifies the size in bytes requested for the operation. */
vcoubard 28:041dac1366b2 198 pstorage_size_t offset; /**< Offset requested by the application for the access operation. */
vcoubard 28:041dac1366b2 199 pstorage_handle_t storage_addr; /**< Address/Identifier for persistent memory. */
vcoubard 28:041dac1366b2 200 uint8_t * p_data_addr; /**< Address/Identifier for data memory. This is assumed to be resident memory. */
Vincent Coubard 0:f2542974c862 201 } cmd_queue_element_t;
Vincent Coubard 0:f2542974c862 202
Vincent Coubard 0:f2542974c862 203
vcoubard 28:041dac1366b2 204 /**@brief Defines command queue, an element is free if the op_code field is not invalid.
Vincent Coubard 0:f2542974c862 205 *
vcoubard 28:041dac1366b2 206 * @details Defines commands enqueued for flash access. At any point in time, this queue has one or
vcoubard 28:041dac1366b2 207 * more flash access operations pending if the count field is not zero. When the queue is
vcoubard 28:041dac1366b2 208 * not empty, the rp (read pointer) field points to the flash access command in progress
vcoubard 28:041dac1366b2 209 * or, if none is in progress, the command to be requested next. The queue implements a
vcoubard 28:041dac1366b2 210 * simple first in first out algorithm. Data addresses are assumed to be resident.
Vincent Coubard 0:f2542974c862 211 */
Vincent Coubard 0:f2542974c862 212 typedef struct
Vincent Coubard 0:f2542974c862 213 {
vcoubard 28:041dac1366b2 214 uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
vcoubard 28:041dac1366b2 215 uint8_t count; /**< Number of elements in the queue. */
vcoubard 28:041dac1366b2 216 cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
Vincent Coubard 0:f2542974c862 217 } cmd_queue_t;
Vincent Coubard 0:f2542974c862 218
vcoubard 28:041dac1366b2 219 static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
vcoubard 28:041dac1366b2 220 static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */
vcoubard 28:041dac1366b2 221 static uint32_t m_next_page_addr; /**< Points to the flash address that can be allocated to a module next. This is needed as blocks of a module that can span across flash pages. */
vcoubard 28:041dac1366b2 222 static pstorage_state_t m_state; /**< Main state tracking variable. */
vcoubard 28:041dac1366b2 223 static flash_swap_sub_state_t m_swap_sub_state; /**< Flash swap erase when swap used state tracking variable. */
vcoubard 28:041dac1366b2 224 static uint32_t m_head_word_size; /**< Head restore area size in words. */
vcoubard 28:041dac1366b2 225 static uint32_t m_tail_word_size; /**< Tail restore area size in words. */
vcoubard 28:041dac1366b2 226 static uint32_t m_current_page_id; /**< Variable for tracking the flash page being processed. */
vcoubard 28:041dac1366b2 227 static uint32_t m_num_of_command_retries; /**< Variable for tracking flash operation retries upon flash operation failures. */
vcoubard 28:041dac1366b2 228 static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES]; /**< Registered application information table. */
vcoubard 28:041dac1366b2 229 static uint32_t m_num_of_bytes_written; /**< Variable for tracking the number of bytes written by the store operation. */
vcoubard 28:041dac1366b2 230 static uint32_t m_app_data_size; /**< Variable for storing the application command size parameter internally. */
vcoubard 28:041dac1366b2 231 static uint32_t m_flags = 0; /**< Storage for boolean flags for state tracking. */
Vincent Coubard 0:f2542974c862 232
Vincent Coubard 0:f2542974c862 233 #ifdef PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 234 static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */
Vincent Coubard 0:f2542974c862 235 #endif // PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 236
vcoubard 28:041dac1366b2 237 // Required forward declarations.
vcoubard 28:041dac1366b2 238 static void cmd_process(void);
vcoubard 28:041dac1366b2 239 static void store_operation_execute(void);
vcoubard 28:041dac1366b2 240 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem);
vcoubard 28:041dac1366b2 241 static void cmd_queue_element_init(uint32_t index);
vcoubard 28:041dac1366b2 242 static void cmd_queue_dequeue(void);
vcoubard 28:041dac1366b2 243 static void sm_state_change(pstorage_state_t new_state);
vcoubard 28:041dac1366b2 244 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state);
Vincent Coubard 0:f2542974c862 245
vcoubard 28:041dac1366b2 246 /**@brief Function for consuming a command queue element.
vcoubard 28:041dac1366b2 247 *
vcoubard 28:041dac1366b2 248 * @details Function for consuming a command queue element, which has been fully processed.
vcoubard 28:041dac1366b2 249 */
vcoubard 28:041dac1366b2 250 static void command_queue_element_consume(void)
vcoubard 28:041dac1366b2 251 {
vcoubard 28:041dac1366b2 252 // Initialize/free the element as it is now processed.
vcoubard 28:041dac1366b2 253 cmd_queue_element_init(m_cmd_queue.rp);
vcoubard 28:041dac1366b2 254
vcoubard 28:041dac1366b2 255 // Adjust command queue state tracking variables.
vcoubard 28:041dac1366b2 256 --(m_cmd_queue.count);
vcoubard 28:041dac1366b2 257 if (++(m_cmd_queue.rp) == PSTORAGE_CMD_QUEUE_SIZE)
vcoubard 28:041dac1366b2 258 {
vcoubard 28:041dac1366b2 259 m_cmd_queue.rp = 0;
vcoubard 28:041dac1366b2 260 }
vcoubard 28:041dac1366b2 261 }
vcoubard 28:041dac1366b2 262
vcoubard 28:041dac1366b2 263
vcoubard 28:041dac1366b2 264 /**@brief Function for executing the finalization procedure for the command executed.
vcoubard 28:041dac1366b2 265 *
vcoubard 28:041dac1366b2 266 * @details Function for executing the finalization procedure for command executed, which includes
vcoubard 28:041dac1366b2 267 * notifying the application of command completion, consuming the command queue element,
vcoubard 28:041dac1366b2 268 * and changing the internal state.
vcoubard 28:041dac1366b2 269 */
vcoubard 28:041dac1366b2 270 static void command_end_procedure_run(void)
vcoubard 28:041dac1366b2 271 {
vcoubard 28:041dac1366b2 272 app_notify(NRF_SUCCESS, &m_cmd_queue.cmd[m_cmd_queue.rp]);
vcoubard 28:041dac1366b2 273
vcoubard 28:041dac1366b2 274 command_queue_element_consume();
vcoubard 28:041dac1366b2 275
vcoubard 28:041dac1366b2 276 sm_state_change(STATE_IDLE);
vcoubard 28:041dac1366b2 277 }
vcoubard 28:041dac1366b2 278
vcoubard 28:041dac1366b2 279
vcoubard 28:041dac1366b2 280 /**@brief Function for idle state entry actions.
vcoubard 28:041dac1366b2 281 *
vcoubard 28:041dac1366b2 282 * @details Function for idle state entry actions, which include resetting relevant state data and
vcoubard 28:041dac1366b2 283 * scheduling any possible queued flash access operation.
vcoubard 28:041dac1366b2 284 */
vcoubard 28:041dac1366b2 285 static void state_idle_entry_run(void)
vcoubard 28:041dac1366b2 286 {
vcoubard 28:041dac1366b2 287 m_num_of_command_retries = 0;
vcoubard 28:041dac1366b2 288 m_num_of_bytes_written = 0;
vcoubard 28:041dac1366b2 289
vcoubard 28:041dac1366b2 290 // Schedule any possible queued flash access operation.
vcoubard 28:041dac1366b2 291 cmd_queue_dequeue();
vcoubard 28:041dac1366b2 292 }
vcoubard 28:041dac1366b2 293
vcoubard 28:041dac1366b2 294
vcoubard 28:041dac1366b2 295 /**@brief Function for notifying an application of command completion and transitioning to an error
vcoubard 28:041dac1366b2 296 * state.
vcoubard 28:041dac1366b2 297 *
vcoubard 28:041dac1366b2 298 * @param[in] result Result code of the operation for the application.
vcoubard 28:041dac1366b2 299 */
vcoubard 28:041dac1366b2 300 static void app_notify_error_state_transit(uint32_t result)
vcoubard 28:041dac1366b2 301 {
vcoubard 28:041dac1366b2 302 app_notify(result, &m_cmd_queue.cmd[m_cmd_queue.rp]);
vcoubard 28:041dac1366b2 303 sm_state_change(STATE_ERROR);
vcoubard 28:041dac1366b2 304 }
vcoubard 28:041dac1366b2 305
vcoubard 28:041dac1366b2 306
vcoubard 28:041dac1366b2 307 /**@brief Function for processing flash API error code.
Vincent Coubard 0:f2542974c862 308 *
vcoubard 28:041dac1366b2 309 * @param[in] err_code Error code from the flash API.
vcoubard 28:041dac1366b2 310 */
vcoubard 28:041dac1366b2 311 static void flash_api_err_code_process(uint32_t err_code)
vcoubard 28:041dac1366b2 312 {
vcoubard 28:041dac1366b2 313 switch (err_code)
vcoubard 28:041dac1366b2 314 {
vcoubard 28:041dac1366b2 315 case NRF_SUCCESS:
vcoubard 28:041dac1366b2 316 break;
vcoubard 28:041dac1366b2 317
vcoubard 28:041dac1366b2 318 case NRF_ERROR_BUSY:
vcoubard 28:041dac1366b2 319 // Flash access operation was not accepted and must be reissued upon flash operation
vcoubard 28:041dac1366b2 320 // complete event.
vcoubard 28:041dac1366b2 321 m_flags |= MASK_FLASH_API_ERR_BUSY;
vcoubard 28:041dac1366b2 322 break;
vcoubard 28:041dac1366b2 323
vcoubard 28:041dac1366b2 324 default:
vcoubard 28:041dac1366b2 325 // Complete the operation with appropriate result code and transit to an error state.
vcoubard 28:041dac1366b2 326 app_notify_error_state_transit(err_code);
vcoubard 28:041dac1366b2 327 break;
vcoubard 28:041dac1366b2 328 }
vcoubard 28:041dac1366b2 329 }
vcoubard 28:041dac1366b2 330
vcoubard 28:041dac1366b2 331 /**@brief Function for writing data to flash.
vcoubard 28:041dac1366b2 332 *
vcoubard 28:041dac1366b2 333 * @param[in] p_dst Pointer to start of flash location to be written.
vcoubard 28:041dac1366b2 334 * @param[in] p_src Pointer to buffer with data to be written.
vcoubard 28:041dac1366b2 335 * @param[in] size_in_words Number of 32-bit words to write.
Vincent Coubard 0:f2542974c862 336 */
vcoubard 28:041dac1366b2 337 static void flash_write(uint32_t * const p_dst,
vcoubard 28:041dac1366b2 338 uint32_t const * const p_src,
vcoubard 28:041dac1366b2 339 uint32_t size_in_words)
vcoubard 28:041dac1366b2 340 {
vcoubard 28:041dac1366b2 341 flash_api_err_code_process(sd_flash_write(p_dst, p_src, size_in_words));
vcoubard 28:041dac1366b2 342 }
vcoubard 28:041dac1366b2 343
vcoubard 28:041dac1366b2 344
vcoubard 28:041dac1366b2 345 /**@brief Function for writing data to flash upon store command.
vcoubard 28:041dac1366b2 346 *
vcoubard 28:041dac1366b2 347 * @details Function for writing data to flash upon executing store command. Data is written to
vcoubard 28:041dac1366b2 348 * flash in reverse order, meaning starting at the end. If the data that is to be written
vcoubard 28:041dac1366b2 349 * is greater than the flash page size, it will be fragmented to fit the flash page size.
vcoubard 28:041dac1366b2 350 */
vcoubard 28:041dac1366b2 351 static void store_cmd_flash_write_execute(void)
vcoubard 28:041dac1366b2 352 {
vcoubard 28:041dac1366b2 353 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 354
vcoubard 28:041dac1366b2 355 if (p_cmd->size > SOC_MAX_WRITE_SIZE)
vcoubard 28:041dac1366b2 356 {
vcoubard 28:041dac1366b2 357 const uint32_t offset = p_cmd->size - PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 358 flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset + offset),
vcoubard 28:041dac1366b2 359 (uint32_t *)(p_cmd->p_data_addr + offset),
vcoubard 28:041dac1366b2 360 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
vcoubard 28:041dac1366b2 361
vcoubard 28:041dac1366b2 362 m_num_of_bytes_written = PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 363 }
vcoubard 28:041dac1366b2 364 else
vcoubard 28:041dac1366b2 365 {
vcoubard 28:041dac1366b2 366 flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset),
vcoubard 28:041dac1366b2 367 (uint32_t *)(p_cmd->p_data_addr),
vcoubard 28:041dac1366b2 368 p_cmd->size / sizeof(uint32_t));
vcoubard 28:041dac1366b2 369
vcoubard 28:041dac1366b2 370 m_num_of_bytes_written = p_cmd->size;
vcoubard 28:041dac1366b2 371 }
vcoubard 28:041dac1366b2 372 }
vcoubard 28:041dac1366b2 373
vcoubard 28:041dac1366b2 374
vcoubard 28:041dac1366b2 375 /**@brief Function for store state entry action.
vcoubard 28:041dac1366b2 376 *
vcoubard 28:041dac1366b2 377 * @details Function for store state entry action, which includes writing data to a flash page.
vcoubard 28:041dac1366b2 378 */
vcoubard 28:041dac1366b2 379 static void state_store_entry_run(void)
vcoubard 28:041dac1366b2 380 {
vcoubard 28:041dac1366b2 381 store_cmd_flash_write_execute();
vcoubard 28:041dac1366b2 382 }
Vincent Coubard 0:f2542974c862 383
Vincent Coubard 0:f2542974c862 384
vcoubard 28:041dac1366b2 385 /**@brief Function for data erase with swap state entry actions.
Vincent Coubard 0:f2542974c862 386 *
vcoubard 28:041dac1366b2 387 * @details Function for data erase with swap state entry actions. This includes adjusting relevant
vcoubard 28:041dac1366b2 388 * state and data variables and transitioning to the correct sub state.
Vincent Coubard 0:f2542974c862 389 */
vcoubard 28:041dac1366b2 390 static void state_data_erase_swap_entry_run(void)
vcoubard 28:041dac1366b2 391 {
vcoubard 28:041dac1366b2 392 m_flags &= ~MASK_TAIL_SWAP_DONE;
vcoubard 28:041dac1366b2 393
vcoubard 28:041dac1366b2 394 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 395 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
vcoubard 28:041dac1366b2 396
vcoubard 28:041dac1366b2 397 const uint32_t clear_start_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 398 m_current_page_id = clear_start_page_id;
vcoubard 28:041dac1366b2 399
vcoubard 28:041dac1366b2 400 // @note: No need to include p_cmd->offset when calculating clear_end_page_id as:
vcoubard 28:041dac1366b2 401 // - clear API does not include offset parameter
vcoubard 28:041dac1366b2 402 // - update and store APIs are limited to operate on single block boundary thus the boolean
vcoubard 28:041dac1366b2 403 // clause ((m_head_word_size == 0) && is_more_than_one_page) below in this function will never
vcoubard 28:041dac1366b2 404 // evaluate as true as if is_more_than_one_page == true m_head_word_size is always != 0
vcoubard 28:041dac1366b2 405 const uint32_t clear_end_page_id = (cmd_block_id + p_cmd->size - 1u) /
vcoubard 28:041dac1366b2 406 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 407
vcoubard 28:041dac1366b2 408 if (clear_start_page_id == clear_end_page_id)
vcoubard 28:041dac1366b2 409 {
vcoubard 28:041dac1366b2 410 m_flags |= MASK_SINGLE_PAGE_OPERATION;
vcoubard 28:041dac1366b2 411 }
vcoubard 28:041dac1366b2 412 else
vcoubard 28:041dac1366b2 413 {
vcoubard 28:041dac1366b2 414 m_flags &= ~MASK_SINGLE_PAGE_OPERATION;
vcoubard 28:041dac1366b2 415 }
vcoubard 28:041dac1366b2 416
vcoubard 28:041dac1366b2 417 if ((m_head_word_size == 0) && !(m_flags & MASK_SINGLE_PAGE_OPERATION))
vcoubard 28:041dac1366b2 418 {
vcoubard 28:041dac1366b2 419 // No head restore required and clear/update area is shared by multiple flash pages, which
vcoubard 28:041dac1366b2 420 // means the current flash page does not have any tail area to restore. You can proceed with
vcoubard 28:041dac1366b2 421 // data page erase directly as no swap is needed for the current flash page.
vcoubard 28:041dac1366b2 422 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
vcoubard 28:041dac1366b2 423 }
vcoubard 28:041dac1366b2 424 else
vcoubard 28:041dac1366b2 425 {
vcoubard 28:041dac1366b2 426 swap_sub_state_state_change(STATE_ERASE_SWAP);
vcoubard 28:041dac1366b2 427 }
vcoubard 28:041dac1366b2 428 }
vcoubard 28:041dac1366b2 429
vcoubard 28:041dac1366b2 430
vcoubard 28:041dac1366b2 431 /**@brief Function for erasing flash page.
vcoubard 28:041dac1366b2 432 *
vcoubard 28:041dac1366b2 433 * @param[in] page_number Page number of the page to be erased.
vcoubard 28:041dac1366b2 434 */
vcoubard 28:041dac1366b2 435 static void flash_page_erase(uint32_t page_number)
vcoubard 28:041dac1366b2 436 {
vcoubard 28:041dac1366b2 437 flash_api_err_code_process(sd_flash_page_erase(page_number));
vcoubard 28:041dac1366b2 438 }
vcoubard 28:041dac1366b2 439
vcoubard 28:041dac1366b2 440
vcoubard 28:041dac1366b2 441 /**@brief Function for data erase state entry action.
vcoubard 28:041dac1366b2 442 *
vcoubard 28:041dac1366b2 443 * @details Function for data erase state entry action, which includes erasing the data flash page.
vcoubard 28:041dac1366b2 444 */
vcoubard 28:041dac1366b2 445 static void state_data_erase_entry_run(void)
vcoubard 28:041dac1366b2 446 {
vcoubard 28:041dac1366b2 447 flash_page_erase(m_current_page_id);
vcoubard 28:041dac1366b2 448 }
vcoubard 28:041dac1366b2 449
vcoubard 28:041dac1366b2 450
vcoubard 28:041dac1366b2 451 /**@brief Function for dispatching the correct application main state entry action.
vcoubard 28:041dac1366b2 452 */
vcoubard 28:041dac1366b2 453 static void state_entry_action_run(void)
vcoubard 28:041dac1366b2 454 {
vcoubard 28:041dac1366b2 455 switch (m_state)
vcoubard 28:041dac1366b2 456 {
vcoubard 28:041dac1366b2 457 case STATE_IDLE:
vcoubard 28:041dac1366b2 458 state_idle_entry_run();
vcoubard 28:041dac1366b2 459 break;
vcoubard 28:041dac1366b2 460
vcoubard 28:041dac1366b2 461 case STATE_STORE:
vcoubard 28:041dac1366b2 462 state_store_entry_run();
vcoubard 28:041dac1366b2 463 break;
vcoubard 28:041dac1366b2 464
vcoubard 28:041dac1366b2 465 case STATE_DATA_ERASE_WITH_SWAP:
vcoubard 28:041dac1366b2 466 state_data_erase_swap_entry_run();
vcoubard 28:041dac1366b2 467 break;
vcoubard 28:041dac1366b2 468
vcoubard 28:041dac1366b2 469 case STATE_DATA_ERASE:
vcoubard 28:041dac1366b2 470 state_data_erase_entry_run();
vcoubard 28:041dac1366b2 471 break;
vcoubard 28:041dac1366b2 472
vcoubard 28:041dac1366b2 473 default:
vcoubard 28:041dac1366b2 474 // No action needed.
vcoubard 28:041dac1366b2 475 break;
vcoubard 28:041dac1366b2 476 }
vcoubard 28:041dac1366b2 477 }
Vincent Coubard 0:f2542974c862 478
Vincent Coubard 0:f2542974c862 479
vcoubard 28:041dac1366b2 480 /**@brief Function for changing application main state and dispatching state entry action.
vcoubard 28:041dac1366b2 481 *
vcoubard 28:041dac1366b2 482 * @param[in] new_state New application main state to transit to.
vcoubard 28:041dac1366b2 483 */
vcoubard 28:041dac1366b2 484 static void sm_state_change(pstorage_state_t new_state)
vcoubard 28:041dac1366b2 485 {
vcoubard 28:041dac1366b2 486 m_state = new_state;
vcoubard 28:041dac1366b2 487 state_entry_action_run();
vcoubard 28:041dac1366b2 488 }
vcoubard 28:041dac1366b2 489
vcoubard 28:041dac1366b2 490
vcoubard 28:041dac1366b2 491 /**@brief Function for swap erase state entry action.
vcoubard 28:041dac1366b2 492 *
vcoubard 28:041dac1366b2 493 * @details Function for swap erase state entry action, which includes erasing swap flash
vcoubard 28:041dac1366b2 494 * page.
vcoubard 28:041dac1366b2 495 */
vcoubard 28:041dac1366b2 496 static void state_swap_erase_entry_run(void)
vcoubard 28:041dac1366b2 497 {
vcoubard 28:041dac1366b2 498 flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
vcoubard 28:041dac1366b2 499 }
vcoubard 28:041dac1366b2 500
vcoubard 28:041dac1366b2 501
vcoubard 28:041dac1366b2 502 /**@brief Function for write data to the swap state entry action.
Vincent Coubard 0:f2542974c862 503 *
vcoubard 28:041dac1366b2 504 * @details Function for write data to the swap state entry action, which includes writing the
vcoubard 28:041dac1366b2 505 * current data page to the swap flash page.
Vincent Coubard 0:f2542974c862 506 */
vcoubard 28:041dac1366b2 507 static void state_write_data_swap_entry_run(void)
vcoubard 28:041dac1366b2 508 {
vcoubard 28:041dac1366b2 509 // @note: There is room for further optimization here as there is only need to write the
vcoubard 28:041dac1366b2 510 // whole flash page to swap area if there is both head and tail area to be restored. In any
vcoubard 28:041dac1366b2 511 // other case we can omit some data from the head or end of the page as that is the clear area.
vcoubard 28:041dac1366b2 512 flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
vcoubard 28:041dac1366b2 513 (uint32_t *)(m_current_page_id * PSTORAGE_FLASH_PAGE_SIZE),
vcoubard 28:041dac1366b2 514 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
vcoubard 28:041dac1366b2 515 }
vcoubard 28:041dac1366b2 516
vcoubard 28:041dac1366b2 517
vcoubard 28:041dac1366b2 518 /**@brief Function for erase data page state entry action.
vcoubard 28:041dac1366b2 519 *
vcoubard 28:041dac1366b2 520 * @details Function for erase data page state entry action, which includes erasing the data flash
vcoubard 28:041dac1366b2 521 * page.
vcoubard 28:041dac1366b2 522 */
vcoubard 28:041dac1366b2 523 static void state_erase_data_page_entry_run(void)
vcoubard 28:041dac1366b2 524 {
vcoubard 28:041dac1366b2 525 flash_page_erase(m_current_page_id);
vcoubard 28:041dac1366b2 526 }
Vincent Coubard 0:f2542974c862 527
Vincent Coubard 0:f2542974c862 528
vcoubard 28:041dac1366b2 529 /**@brief Function for restore tail state entry action.
vcoubard 28:041dac1366b2 530 *
vcoubard 28:041dac1366b2 531 * @details Function for restore tail state entry action, which includes writing the tail section
vcoubard 28:041dac1366b2 532 * back from swap to the data page.
vcoubard 28:041dac1366b2 533 */
vcoubard 28:041dac1366b2 534 static void state_restore_tail_entry_run(void)
vcoubard 28:041dac1366b2 535 {
vcoubard 28:041dac1366b2 536 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 537 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
vcoubard 28:041dac1366b2 538
vcoubard 28:041dac1366b2 539 const uint32_t tail_offset = (cmd_block_id + p_cmd->size + p_cmd->offset) %
vcoubard 28:041dac1366b2 540 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 541
vcoubard 28:041dac1366b2 542 flash_write((uint32_t *)(cmd_block_id + p_cmd->size + p_cmd->offset),
vcoubard 28:041dac1366b2 543 (uint32_t *)(PSTORAGE_SWAP_ADDR + tail_offset),
vcoubard 28:041dac1366b2 544 m_tail_word_size);
vcoubard 28:041dac1366b2 545 }
vcoubard 28:041dac1366b2 546
vcoubard 28:041dac1366b2 547
vcoubard 28:041dac1366b2 548 /**@brief Function for restore head state entry action.
Vincent Coubard 0:f2542974c862 549 *
vcoubard 28:041dac1366b2 550 * @details Function for restore head state entry action, which includes writing the head section
vcoubard 28:041dac1366b2 551 * back from swap to the data page.
vcoubard 28:041dac1366b2 552 */
vcoubard 28:041dac1366b2 553 static void state_restore_head_entry_run(void)
vcoubard 28:041dac1366b2 554 {
vcoubard 28:041dac1366b2 555 flash_write((uint32_t *)((m_current_page_id - 1u) * PSTORAGE_FLASH_PAGE_SIZE),
vcoubard 28:041dac1366b2 556 (uint32_t *)PSTORAGE_SWAP_ADDR,
vcoubard 28:041dac1366b2 557 m_head_word_size);
vcoubard 28:041dac1366b2 558 }
vcoubard 28:041dac1366b2 559
vcoubard 28:041dac1366b2 560
vcoubard 28:041dac1366b2 561 /**@brief Function for dispatching the correct swap sub state entry action.
vcoubard 28:041dac1366b2 562 */
vcoubard 28:041dac1366b2 563 static void swap_sub_state_entry_action_run(void)
vcoubard 28:041dac1366b2 564 {
vcoubard 28:041dac1366b2 565 static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) =
vcoubard 28:041dac1366b2 566 {
vcoubard 28:041dac1366b2 567 state_swap_erase_entry_run,
vcoubard 28:041dac1366b2 568 state_write_data_swap_entry_run,
vcoubard 28:041dac1366b2 569 state_erase_data_page_entry_run,
vcoubard 28:041dac1366b2 570 state_restore_tail_entry_run,
vcoubard 28:041dac1366b2 571 state_restore_head_entry_run
vcoubard 28:041dac1366b2 572 };
vcoubard 28:041dac1366b2 573
vcoubard 28:041dac1366b2 574 swap_sub_state_sm_lut[m_swap_sub_state]();
vcoubard 28:041dac1366b2 575 }
vcoubard 28:041dac1366b2 576
vcoubard 28:041dac1366b2 577
vcoubard 28:041dac1366b2 578 /**@brief Function for changing the swap sub state and dispatching state entry action.
vcoubard 28:041dac1366b2 579 *
vcoubard 28:041dac1366b2 580 * @param[in] new_state New swap sub state to transit to.
vcoubard 28:041dac1366b2 581 */
vcoubard 28:041dac1366b2 582 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state)
vcoubard 28:041dac1366b2 583 {
vcoubard 28:041dac1366b2 584 m_swap_sub_state = new_state;
vcoubard 28:041dac1366b2 585 swap_sub_state_entry_action_run();
vcoubard 28:041dac1366b2 586 }
vcoubard 28:041dac1366b2 587
vcoubard 28:041dac1366b2 588
vcoubard 28:041dac1366b2 589 /**@brief Function for initializing the command queue element.
vcoubard 28:041dac1366b2 590 *
vcoubard 28:041dac1366b2 591 * @param[in] index Index of the element to be initialized.
Vincent Coubard 0:f2542974c862 592 */
Vincent Coubard 0:f2542974c862 593 static void cmd_queue_element_init(uint32_t index)
Vincent Coubard 0:f2542974c862 594 {
Vincent Coubard 0:f2542974c862 595 // Internal function and checks on range of index can be avoided.
Vincent Coubard 0:f2542974c862 596 m_cmd_queue.cmd[index].op_code = INVALID_OPCODE;
Vincent Coubard 0:f2542974c862 597 m_cmd_queue.cmd[index].size = 0;
vcoubard 28:041dac1366b2 598 m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_NUM_OF_PAGES;
Vincent Coubard 0:f2542974c862 599 m_cmd_queue.cmd[index].storage_addr.block_id = 0;
Vincent Coubard 0:f2542974c862 600 m_cmd_queue.cmd[index].p_data_addr = NULL;
Vincent Coubard 0:f2542974c862 601 m_cmd_queue.cmd[index].offset = 0;
Vincent Coubard 0:f2542974c862 602 }
Vincent Coubard 0:f2542974c862 603
Vincent Coubard 0:f2542974c862 604
vcoubard 28:041dac1366b2 605 /**@brief Function for initializing the command queue.
Vincent Coubard 0:f2542974c862 606 */
Vincent Coubard 0:f2542974c862 607 static void cmd_queue_init(void)
Vincent Coubard 0:f2542974c862 608 {
vcoubard 28:041dac1366b2 609 m_cmd_queue.rp = 0;
vcoubard 28:041dac1366b2 610 m_cmd_queue.count = 0;
Vincent Coubard 0:f2542974c862 611
vcoubard 28:041dac1366b2 612 for (uint32_t cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; ++cmd_index)
Vincent Coubard 0:f2542974c862 613 {
Vincent Coubard 0:f2542974c862 614 cmd_queue_element_init(cmd_index);
Vincent Coubard 0:f2542974c862 615 }
Vincent Coubard 0:f2542974c862 616 }
Vincent Coubard 0:f2542974c862 617
Vincent Coubard 0:f2542974c862 618
vcoubard 28:041dac1366b2 619 /**@brief Function for enqueuing, and possibly dispatching, a flash access operation.
Vincent Coubard 0:f2542974c862 620 *
vcoubard 28:041dac1366b2 621 * @param[in] opcode Identifies the operation requested to be enqueued.
vcoubard 28:041dac1366b2 622 * @param[in] p_storage_addr Identifies the module and flash address on which the operation is
vcoubard 28:041dac1366b2 623 * requested.
vcoubard 28:041dac1366b2 624 * @param[in] p_data_addr Identifies the data address for flash access.
Vincent Coubard 0:f2542974c862 625 * @param[in] size Size in bytes of data requested for the access operation.
Vincent Coubard 0:f2542974c862 626 * @param[in] offset Offset within the flash memory block at which operation is requested.
Vincent Coubard 0:f2542974c862 627 *
vcoubard 28:041dac1366b2 628 * @retval NRF_SUCCESS Upon success.
vcoubard 28:041dac1366b2 629 * @retval NRF_ERROR_NO_MEM Upon failure, when no space is available in the command queue.
Vincent Coubard 0:f2542974c862 630 */
Vincent Coubard 0:f2542974c862 631 static uint32_t cmd_queue_enqueue(uint8_t opcode,
Vincent Coubard 0:f2542974c862 632 pstorage_handle_t * p_storage_addr,
Vincent Coubard 0:f2542974c862 633 uint8_t * p_data_addr,
Vincent Coubard 0:f2542974c862 634 pstorage_size_t size,
Vincent Coubard 0:f2542974c862 635 pstorage_size_t offset)
Vincent Coubard 0:f2542974c862 636 {
vcoubard 28:041dac1366b2 637 uint32_t err_code;
Vincent Coubard 0:f2542974c862 638
Vincent Coubard 0:f2542974c862 639 if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
Vincent Coubard 0:f2542974c862 640 {
vcoubard 28:041dac1366b2 641 // Enqueue the command if it the queue is not full.
vcoubard 28:041dac1366b2 642 uint32_t write_index = m_cmd_queue.rp + m_cmd_queue.count;
Vincent Coubard 0:f2542974c862 643
vcoubard 28:041dac1366b2 644 if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
Vincent Coubard 0:f2542974c862 645 {
Vincent Coubard 0:f2542974c862 646 write_index -= PSTORAGE_CMD_QUEUE_SIZE;
Vincent Coubard 0:f2542974c862 647 }
Vincent Coubard 0:f2542974c862 648
Vincent Coubard 0:f2542974c862 649 m_cmd_queue.cmd[write_index].op_code = opcode;
Vincent Coubard 0:f2542974c862 650 m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr;
Vincent Coubard 0:f2542974c862 651 m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
Vincent Coubard 0:f2542974c862 652 m_cmd_queue.cmd[write_index].size = size;
Vincent Coubard 0:f2542974c862 653 m_cmd_queue.cmd[write_index].offset = offset;
vcoubard 28:041dac1366b2 654
vcoubard 28:041dac1366b2 655 m_cmd_queue.count++;
vcoubard 28:041dac1366b2 656
vcoubard 28:041dac1366b2 657 if (m_state == STATE_IDLE)
Vincent Coubard 0:f2542974c862 658 {
vcoubard 28:041dac1366b2 659 cmd_process();
vcoubard 28:041dac1366b2 660 }
vcoubard 28:041dac1366b2 661
vcoubard 28:041dac1366b2 662 err_code = NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 663 }
Vincent Coubard 0:f2542974c862 664 else
Vincent Coubard 0:f2542974c862 665 {
vcoubard 28:041dac1366b2 666 err_code = NRF_ERROR_NO_MEM;
Vincent Coubard 0:f2542974c862 667 }
Vincent Coubard 0:f2542974c862 668
vcoubard 28:041dac1366b2 669 return err_code;
Vincent Coubard 0:f2542974c862 670 }
Vincent Coubard 0:f2542974c862 671
Vincent Coubard 0:f2542974c862 672
vcoubard 28:041dac1366b2 673 /**@brief Function for dequeing a possible pending flash access operation.
Vincent Coubard 0:f2542974c862 674 */
vcoubard 28:041dac1366b2 675 static void cmd_queue_dequeue(void)
Vincent Coubard 0:f2542974c862 676 {
vcoubard 28:041dac1366b2 677 if ((m_cmd_queue.count != 0))
Vincent Coubard 0:f2542974c862 678 {
vcoubard 28:041dac1366b2 679 cmd_process();
Vincent Coubard 0:f2542974c862 680 }
Vincent Coubard 0:f2542974c862 681 }
Vincent Coubard 0:f2542974c862 682
Vincent Coubard 0:f2542974c862 683
vcoubard 28:041dac1366b2 684 /**@brief Function for notifying an application of command completion.
Vincent Coubard 0:f2542974c862 685 *
vcoubard 28:041dac1366b2 686 * @param[in] result Result code of the operation for the application.
vcoubard 28:041dac1366b2 687 * @param[in] p_elem Pointer to the command queue element for which this result was received.
Vincent Coubard 0:f2542974c862 688 */
vcoubard 1:ebc0e0ef0a11 689 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem)
Vincent Coubard 0:f2542974c862 690 {
Vincent Coubard 0:f2542974c862 691 pstorage_ntf_cb_t ntf_cb;
vcoubard 28:041dac1366b2 692 const uint8_t op_code = p_elem->op_code;
Vincent Coubard 0:f2542974c862 693
Vincent Coubard 0:f2542974c862 694 #ifdef PSTORAGE_RAW_MODE_ENABLE
vcoubard 1:ebc0e0ef0a11 695 if (p_elem->storage_addr.module_id == RAW_MODE_APP_ID)
Vincent Coubard 0:f2542974c862 696 {
Vincent Coubard 0:f2542974c862 697 ntf_cb = m_raw_app_table.cb;
Vincent Coubard 0:f2542974c862 698 }
Vincent Coubard 0:f2542974c862 699 else
Vincent Coubard 0:f2542974c862 700 #endif // PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 701 {
vcoubard 1:ebc0e0ef0a11 702 ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb;
Vincent Coubard 0:f2542974c862 703 }
Vincent Coubard 0:f2542974c862 704
vcoubard 28:041dac1366b2 705 ntf_cb(&p_elem->storage_addr, op_code, result, p_elem->p_data_addr, m_app_data_size);
vcoubard 28:041dac1366b2 706 }
vcoubard 28:041dac1366b2 707
vcoubard 28:041dac1366b2 708
vcoubard 28:041dac1366b2 709 /**@brief Function for evaluating if a data page swap is required for the tail section on the
vcoubard 28:041dac1366b2 710 * current page.
vcoubard 28:041dac1366b2 711 *
vcoubard 28:041dac1366b2 712 * @retval true If data page swap is required.
vcoubard 28:041dac1366b2 713 * @retval false If data page swap is not required.
vcoubard 28:041dac1366b2 714 */
vcoubard 28:041dac1366b2 715 static bool is_tail_data_page_swap_required(void)
vcoubard 28:041dac1366b2 716 {
vcoubard 28:041dac1366b2 717 bool ret_value;
vcoubard 28:041dac1366b2 718
vcoubard 28:041dac1366b2 719 // Extract id of the last page command is executed upon.
vcoubard 28:041dac1366b2 720 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 721 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
vcoubard 28:041dac1366b2 722 const uint32_t last_page_id = (cmd_block_id + p_cmd->size + p_cmd->offset - 1u) /
vcoubard 28:041dac1366b2 723 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 724
vcoubard 28:041dac1366b2 725 // If tail section area exists and the current page is the last page then tail data page swap is
vcoubard 28:041dac1366b2 726 // required.
vcoubard 28:041dac1366b2 727 if ((m_tail_word_size != 0) && (m_current_page_id == last_page_id))
vcoubard 28:041dac1366b2 728 {
vcoubard 28:041dac1366b2 729 ret_value = true;
vcoubard 28:041dac1366b2 730 }
vcoubard 28:041dac1366b2 731 else
vcoubard 28:041dac1366b2 732 {
vcoubard 28:041dac1366b2 733 ret_value = false;
vcoubard 28:041dac1366b2 734 }
vcoubard 28:041dac1366b2 735
vcoubard 28:041dac1366b2 736 return ret_value;
vcoubard 28:041dac1366b2 737 }
vcoubard 28:041dac1366b2 738
vcoubard 28:041dac1366b2 739
vcoubard 28:041dac1366b2 740 /**@brief Function for performing post processing for the update and clear commands.
vcoubard 28:041dac1366b2 741 *
vcoubard 28:041dac1366b2 742 * @details Function for performing post processing for the update and clear commands, which implies
vcoubard 28:041dac1366b2 743 * executing the correct execution path depending on the command.
vcoubard 28:041dac1366b2 744 */
vcoubard 28:041dac1366b2 745 static void clear_post_processing_run(void)
vcoubard 28:041dac1366b2 746 {
vcoubard 28:041dac1366b2 747 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 748
vcoubard 28:041dac1366b2 749 if (p_cmd->op_code != PSTORAGE_UPDATE_OP_CODE)
vcoubard 28:041dac1366b2 750 {
vcoubard 28:041dac1366b2 751 command_end_procedure_run();
vcoubard 28:041dac1366b2 752 }
vcoubard 28:041dac1366b2 753 else
vcoubard 28:041dac1366b2 754 {
vcoubard 28:041dac1366b2 755 store_operation_execute();
vcoubard 28:041dac1366b2 756 }
vcoubard 28:041dac1366b2 757 }
vcoubard 28:041dac1366b2 758
vcoubard 28:041dac1366b2 759
vcoubard 28:041dac1366b2 760 /**@brief Function for doing swap sub state exit action.
vcoubard 28:041dac1366b2 761 */
vcoubard 28:041dac1366b2 762 static void swap_sub_sm_exit_action_run(void)
vcoubard 28:041dac1366b2 763 {
vcoubard 28:041dac1366b2 764 clear_post_processing_run();
vcoubard 28:041dac1366b2 765 }
vcoubard 28:041dac1366b2 766
vcoubard 28:041dac1366b2 767
vcoubard 28:041dac1366b2 768 /**@brief Function for evaluating if the page erase operation is required for the current page.
vcoubard 28:041dac1366b2 769 *
vcoubard 28:041dac1366b2 770 * @retval true If page erase is required.
vcoubard 28:041dac1366b2 771 * @retval false If page erase is not required.
vcoubard 28:041dac1366b2 772 */
vcoubard 28:041dac1366b2 773 static bool is_page_erase_required(void)
vcoubard 28:041dac1366b2 774 {
vcoubard 28:041dac1366b2 775 bool ret;
vcoubard 28:041dac1366b2 776
vcoubard 28:041dac1366b2 777 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 778 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
vcoubard 28:041dac1366b2 779 const uint32_t id_last_page_to_be_cleared = (cmd_block_id + p_cmd->size +
vcoubard 28:041dac1366b2 780 p_cmd->offset - 1u) /
vcoubard 28:041dac1366b2 781 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 782
vcoubard 28:041dac1366b2 783 // True if:
vcoubard 28:041dac1366b2 784 // - current page is not the last page OR
vcoubard 28:041dac1366b2 785 // - current page is the last page AND no tail exists
vcoubard 28:041dac1366b2 786 if ((m_current_page_id < id_last_page_to_be_cleared) ||
vcoubard 28:041dac1366b2 787 ((m_current_page_id == id_last_page_to_be_cleared) && (m_tail_word_size == 0)))
vcoubard 28:041dac1366b2 788 {
vcoubard 28:041dac1366b2 789 ret = true;
vcoubard 28:041dac1366b2 790 }
vcoubard 28:041dac1366b2 791 else
vcoubard 28:041dac1366b2 792 {
vcoubard 28:041dac1366b2 793 ret = false;
vcoubard 28:041dac1366b2 794 }
vcoubard 28:041dac1366b2 795
vcoubard 28:041dac1366b2 796 return ret;
vcoubard 24:2aea0c1c57ee 797 }
vcoubard 24:2aea0c1c57ee 798
vcoubard 22:67a8d2c0bbbf 799
vcoubard 28:041dac1366b2 800 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash
vcoubard 28:041dac1366b2 801 * API, in swap sub sate.
vcoubard 24:2aea0c1c57ee 802 */
vcoubard 28:041dac1366b2 803 static void swap_sub_state_err_busy_process(void)
vcoubard 24:2aea0c1c57ee 804 {
vcoubard 28:041dac1366b2 805 // Reissue the request by doing a self transition to the current state.
vcoubard 28:041dac1366b2 806 m_flags &= ~MASK_FLASH_API_ERR_BUSY;
vcoubard 28:041dac1366b2 807 swap_sub_state_state_change(m_swap_sub_state);
vcoubard 28:041dac1366b2 808 }
vcoubard 28:041dac1366b2 809
vcoubard 27:0fe148f1bca3 810
vcoubard 28:041dac1366b2 811 /**@brief Function for doing restore head state action upon flash operation success event.
vcoubard 28:041dac1366b2 812 *
vcoubard 28:041dac1366b2 813 * @details Function for doing restore head state action upon flash operation success event, which
vcoubard 28:041dac1366b2 814 * includes making a state transition depending on the current state.
vcoubard 28:041dac1366b2 815 */
vcoubard 28:041dac1366b2 816 static void head_restore_state_run(void)
vcoubard 28:041dac1366b2 817 {
vcoubard 28:041dac1366b2 818 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 819 {
vcoubard 28:041dac1366b2 820 if (is_tail_data_page_swap_required())
vcoubard 28:041dac1366b2 821 {
vcoubard 28:041dac1366b2 822 // Additional data page needs to be swapped for tail section as we are clearing a block,
vcoubard 28:041dac1366b2 823 // which is shared between 2 flash pages.
vcoubard 28:041dac1366b2 824
vcoubard 28:041dac1366b2 825 // Adjust variables to ensure correct state transition path is taken after the tail
vcoubard 28:041dac1366b2 826 // section swap has completed.
vcoubard 28:041dac1366b2 827 m_head_word_size = 0;
vcoubard 28:041dac1366b2 828 m_flags |= MASK_TAIL_SWAP_DONE;
vcoubard 28:041dac1366b2 829
vcoubard 28:041dac1366b2 830 swap_sub_state_state_change(STATE_ERASE_SWAP);
vcoubard 28:041dac1366b2 831 }
vcoubard 28:041dac1366b2 832 else if (is_page_erase_required())
vcoubard 28:041dac1366b2 833 {
vcoubard 28:041dac1366b2 834 // Additional page erase operation is required.
vcoubard 28:041dac1366b2 835
vcoubard 28:041dac1366b2 836 // Adjust variable to ensure correct state transition path is taken after the additional
vcoubard 28:041dac1366b2 837 // page erase operation has completed.
vcoubard 28:041dac1366b2 838 m_head_word_size = 0;
vcoubard 28:041dac1366b2 839 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
vcoubard 28:041dac1366b2 840 }
vcoubard 28:041dac1366b2 841 else if (m_tail_word_size != 0)
vcoubard 28:041dac1366b2 842 {
vcoubard 28:041dac1366b2 843 // Proceed with restoring tail from swap to data page.
vcoubard 28:041dac1366b2 844 swap_sub_state_state_change(STATE_RESTORE_TAIL);
vcoubard 28:041dac1366b2 845 }
vcoubard 28:041dac1366b2 846 else
vcoubard 28:041dac1366b2 847 {
vcoubard 28:041dac1366b2 848 // Swap statemachine execution end reached.
vcoubard 28:041dac1366b2 849 swap_sub_sm_exit_action_run();
vcoubard 28:041dac1366b2 850 }
vcoubard 28:041dac1366b2 851 }
vcoubard 28:041dac1366b2 852 else
Vincent Coubard 0:f2542974c862 853 {
vcoubard 28:041dac1366b2 854 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 855 swap_sub_state_err_busy_process();
vcoubard 28:041dac1366b2 856 }
vcoubard 28:041dac1366b2 857 }
vcoubard 24:2aea0c1c57ee 858
vcoubard 28:041dac1366b2 859
vcoubard 28:041dac1366b2 860 /**@brief Function for doing restore tail state action upon flash operation success event.
vcoubard 28:041dac1366b2 861 */
vcoubard 28:041dac1366b2 862 static void tail_restore_state_run(void)
vcoubard 28:041dac1366b2 863 {
vcoubard 28:041dac1366b2 864 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 865 {
vcoubard 28:041dac1366b2 866 swap_sub_sm_exit_action_run();
vcoubard 28:041dac1366b2 867 }
vcoubard 28:041dac1366b2 868 else
vcoubard 28:041dac1366b2 869 {
vcoubard 28:041dac1366b2 870 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 871 swap_sub_state_err_busy_process();
vcoubard 28:041dac1366b2 872 }
vcoubard 28:041dac1366b2 873 }
vcoubard 28:041dac1366b2 874
Vincent Coubard 0:f2542974c862 875
vcoubard 28:041dac1366b2 876 /**@brief Function for doing data page erase state action upon a flash operation success event.
vcoubard 28:041dac1366b2 877 *
vcoubard 28:041dac1366b2 878 * @details Function for doing data page erase state action upon a flash operation success event,
vcoubard 28:041dac1366b2 879 * which includes making a state transit to a new state depending on the current state.
vcoubard 28:041dac1366b2 880 */
vcoubard 28:041dac1366b2 881 static void data_page_erase_state_run(void)
vcoubard 28:041dac1366b2 882 {
vcoubard 28:041dac1366b2 883 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 884 {
vcoubard 28:041dac1366b2 885 ++m_current_page_id;
vcoubard 28:041dac1366b2 886
vcoubard 28:041dac1366b2 887 if (m_head_word_size != 0)
vcoubard 28:041dac1366b2 888 {
vcoubard 28:041dac1366b2 889 swap_sub_state_state_change(STATE_RESTORE_HEAD);
vcoubard 28:041dac1366b2 890 }
vcoubard 28:041dac1366b2 891 else if (is_page_erase_required())
Vincent Coubard 0:f2542974c862 892 {
vcoubard 28:041dac1366b2 893 // Additional page erase operation is required.
vcoubard 28:041dac1366b2 894 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
vcoubard 28:041dac1366b2 895 }
vcoubard 28:041dac1366b2 896 else if (m_tail_word_size != 0)
vcoubard 28:041dac1366b2 897 {
vcoubard 28:041dac1366b2 898 if (!(m_flags & MASK_TAIL_SWAP_DONE))
Vincent Coubard 0:f2542974c862 899 {
vcoubard 28:041dac1366b2 900 // Tail area restore is required and we have not yet written the relevant data page
vcoubard 28:041dac1366b2 901 // to swap area. Start the process of writing the data page to swap.
vcoubard 28:041dac1366b2 902 m_flags |= MASK_TAIL_SWAP_DONE;
vcoubard 28:041dac1366b2 903
vcoubard 28:041dac1366b2 904 swap_sub_state_state_change(STATE_ERASE_SWAP);
Vincent Coubard 0:f2542974c862 905 }
Vincent Coubard 0:f2542974c862 906 else
Vincent Coubard 0:f2542974c862 907 {
vcoubard 28:041dac1366b2 908 // Tail area restore is required and we have already written the relevant data page
vcoubard 28:041dac1366b2 909 // to swap area. Proceed by restoring the tail area.
vcoubard 28:041dac1366b2 910 swap_sub_state_state_change(STATE_RESTORE_TAIL);
Vincent Coubard 0:f2542974c862 911 }
vcoubard 28:041dac1366b2 912 }
vcoubard 28:041dac1366b2 913 else
vcoubard 28:041dac1366b2 914 {
vcoubard 28:041dac1366b2 915 swap_sub_sm_exit_action_run();
vcoubard 28:041dac1366b2 916 }
vcoubard 28:041dac1366b2 917 }
vcoubard 28:041dac1366b2 918 else
vcoubard 28:041dac1366b2 919 {
vcoubard 28:041dac1366b2 920 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 921 swap_sub_state_err_busy_process();
vcoubard 28:041dac1366b2 922 }
vcoubard 28:041dac1366b2 923 }
Vincent Coubard 0:f2542974c862 924
vcoubard 28:041dac1366b2 925
vcoubard 28:041dac1366b2 926 /**@brief Function for doing data to swap write state action upon flash operation success event.
vcoubard 28:041dac1366b2 927 */
vcoubard 28:041dac1366b2 928 static void data_to_swap_write_state_run(void)
vcoubard 28:041dac1366b2 929 {
vcoubard 28:041dac1366b2 930 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 931 {
vcoubard 28:041dac1366b2 932 // If the operation is executed only on 1 single flash page it automatically means that tail
vcoubard 28:041dac1366b2 933 // area is written to the swap, which we store to flags.
vcoubard 28:041dac1366b2 934 if (m_flags & MASK_SINGLE_PAGE_OPERATION)
vcoubard 28:041dac1366b2 935 {
vcoubard 28:041dac1366b2 936 m_flags |= MASK_TAIL_SWAP_DONE;
Vincent Coubard 0:f2542974c862 937 }
Vincent Coubard 0:f2542974c862 938
vcoubard 28:041dac1366b2 939 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
vcoubard 28:041dac1366b2 940 }
vcoubard 28:041dac1366b2 941 else
vcoubard 28:041dac1366b2 942 {
vcoubard 28:041dac1366b2 943 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 944 swap_sub_state_err_busy_process();
vcoubard 28:041dac1366b2 945 }
vcoubard 28:041dac1366b2 946 }
Vincent Coubard 0:f2542974c862 947
vcoubard 1:ebc0e0ef0a11 948
vcoubard 28:041dac1366b2 949 /**@brief Function for doing swap erase state action upon flash operation success event.
vcoubard 28:041dac1366b2 950 */
vcoubard 28:041dac1366b2 951 static void swap_erase_state_run(void)
vcoubard 28:041dac1366b2 952 {
vcoubard 28:041dac1366b2 953 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 954 {
vcoubard 28:041dac1366b2 955 swap_sub_state_state_change(STATE_WRITE_DATA_TO_SWAP);
vcoubard 28:041dac1366b2 956 }
vcoubard 28:041dac1366b2 957 else
vcoubard 28:041dac1366b2 958 {
vcoubard 28:041dac1366b2 959 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 960 swap_sub_state_err_busy_process();
Vincent Coubard 0:f2542974c862 961 }
Vincent Coubard 0:f2542974c862 962 }
Vincent Coubard 0:f2542974c862 963
Vincent Coubard 0:f2542974c862 964
vcoubard 28:041dac1366b2 965 /**@brief Function for dispatching the correct state action for data erase with a swap composite
vcoubard 28:041dac1366b2 966 * state upon a flash operation success event.
vcoubard 28:041dac1366b2 967 */
vcoubard 28:041dac1366b2 968 static void swap_sub_state_sm_run(void)
vcoubard 28:041dac1366b2 969 {
vcoubard 28:041dac1366b2 970 static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) =
vcoubard 28:041dac1366b2 971 {
vcoubard 28:041dac1366b2 972 swap_erase_state_run,
vcoubard 28:041dac1366b2 973 data_to_swap_write_state_run,
vcoubard 28:041dac1366b2 974 data_page_erase_state_run,
vcoubard 28:041dac1366b2 975 tail_restore_state_run,
vcoubard 28:041dac1366b2 976 head_restore_state_run
vcoubard 28:041dac1366b2 977 };
vcoubard 28:041dac1366b2 978
vcoubard 28:041dac1366b2 979 swap_sub_state_sm_lut[m_swap_sub_state]();
vcoubard 28:041dac1366b2 980 }
vcoubard 28:041dac1366b2 981
vcoubard 28:041dac1366b2 982
vcoubard 28:041dac1366b2 983 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash
vcoubard 28:041dac1366b2 984 * API, in main sate.
vcoubard 28:041dac1366b2 985 */
vcoubard 28:041dac1366b2 986 static void main_state_err_busy_process(void)
vcoubard 28:041dac1366b2 987 {
vcoubard 28:041dac1366b2 988 // Reissue the request by doing a self transition to the current state.
vcoubard 28:041dac1366b2 989 m_flags &= ~MASK_FLASH_API_ERR_BUSY;
vcoubard 28:041dac1366b2 990 sm_state_change(m_state);
vcoubard 28:041dac1366b2 991 }
vcoubard 28:041dac1366b2 992
vcoubard 28:041dac1366b2 993
vcoubard 28:041dac1366b2 994 /**@brief Function for doing erase state action upon flash operation success event.
vcoubard 27:0fe148f1bca3 995 *
vcoubard 28:041dac1366b2 996 * @details Function for doing erase state action upon flash operation success event, which includes
vcoubard 28:041dac1366b2 997 * making a state transition depending on the current state.
vcoubard 24:2aea0c1c57ee 998 */
vcoubard 28:041dac1366b2 999 static void erase_sub_state_sm_run(void)
Vincent Coubard 0:f2542974c862 1000 {
vcoubard 28:041dac1366b2 1001 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 1002 {
vcoubard 28:041dac1366b2 1003 // Clear operation request has succeeded.
vcoubard 28:041dac1366b2 1004 ++m_current_page_id;
vcoubard 28:041dac1366b2 1005
vcoubard 28:041dac1366b2 1006 if (!is_page_erase_required())
vcoubard 28:041dac1366b2 1007 {
vcoubard 28:041dac1366b2 1008 clear_post_processing_run();
vcoubard 28:041dac1366b2 1009 }
vcoubard 28:041dac1366b2 1010 else
vcoubard 28:041dac1366b2 1011 {
vcoubard 28:041dac1366b2 1012 // All required flash pages have not yet been erased, issue erase by doing a self
vcoubard 28:041dac1366b2 1013 // transit.
vcoubard 28:041dac1366b2 1014 sm_state_change(m_state);
vcoubard 28:041dac1366b2 1015 }
vcoubard 28:041dac1366b2 1016 }
vcoubard 28:041dac1366b2 1017 else
vcoubard 28:041dac1366b2 1018 {
vcoubard 28:041dac1366b2 1019 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 1020 main_state_err_busy_process();
vcoubard 28:041dac1366b2 1021 }
vcoubard 28:041dac1366b2 1022 }
vcoubard 27:0fe148f1bca3 1023
vcoubard 28:041dac1366b2 1024
vcoubard 28:041dac1366b2 1025 /**@brief Function for doing store state action upon flash operation success event.
vcoubard 28:041dac1366b2 1026 */
vcoubard 28:041dac1366b2 1027 static void store_sub_state_sm_run(void)
vcoubard 28:041dac1366b2 1028 {
vcoubard 28:041dac1366b2 1029 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 28:041dac1366b2 1030 {
vcoubard 28:041dac1366b2 1031 // As write operation request has succeeded, adjust the size tracking state information
vcoubard 28:041dac1366b2 1032 // accordingly.
vcoubard 28:041dac1366b2 1033 cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 1034 p_cmd->size -= m_num_of_bytes_written;
vcoubard 28:041dac1366b2 1035
vcoubard 28:041dac1366b2 1036 if (p_cmd->size == 0)
Vincent Coubard 0:f2542974c862 1037 {
vcoubard 28:041dac1366b2 1038 command_end_procedure_run();
Vincent Coubard 0:f2542974c862 1039 }
Vincent Coubard 0:f2542974c862 1040 else
Vincent Coubard 0:f2542974c862 1041 {
vcoubard 28:041dac1366b2 1042 store_cmd_flash_write_execute();
Vincent Coubard 0:f2542974c862 1043 }
Vincent Coubard 0:f2542974c862 1044 }
vcoubard 28:041dac1366b2 1045 else
Vincent Coubard 0:f2542974c862 1046 {
vcoubard 28:041dac1366b2 1047 // As operation request was rejected by the flash API reissue the request.
vcoubard 28:041dac1366b2 1048 main_state_err_busy_process();
vcoubard 28:041dac1366b2 1049 }
vcoubard 28:041dac1366b2 1050 }
vcoubard 28:041dac1366b2 1051
vcoubard 28:041dac1366b2 1052
vcoubard 28:041dac1366b2 1053 /**@brief Function for doing action upon flash operation success event.
vcoubard 28:041dac1366b2 1054 */
vcoubard 28:041dac1366b2 1055 static void flash_operation_success_run(void)
vcoubard 28:041dac1366b2 1056 {
vcoubard 28:041dac1366b2 1057 switch (m_state)
vcoubard 28:041dac1366b2 1058 {
vcoubard 28:041dac1366b2 1059 case STATE_STORE:
vcoubard 28:041dac1366b2 1060 store_sub_state_sm_run();
vcoubard 27:0fe148f1bca3 1061 break;
vcoubard 28:041dac1366b2 1062
vcoubard 27:0fe148f1bca3 1063 case STATE_DATA_ERASE:
vcoubard 28:041dac1366b2 1064 erase_sub_state_sm_run();
vcoubard 22:67a8d2c0bbbf 1065 break;
vcoubard 28:041dac1366b2 1066
vcoubard 28:041dac1366b2 1067 case STATE_DATA_ERASE_WITH_SWAP:
vcoubard 28:041dac1366b2 1068 swap_sub_state_sm_run();
vcoubard 28:041dac1366b2 1069 break;
vcoubard 28:041dac1366b2 1070
vcoubard 28:041dac1366b2 1071 default:
vcoubard 28:041dac1366b2 1072 // No implementation needed.
vcoubard 28:041dac1366b2 1073 break;
vcoubard 28:041dac1366b2 1074 }
vcoubard 28:041dac1366b2 1075 }
vcoubard 28:041dac1366b2 1076
vcoubard 24:2aea0c1c57ee 1077
vcoubard 28:041dac1366b2 1078 /**@brief Function for doing action upon flash operation failure event.
vcoubard 28:041dac1366b2 1079 *
vcoubard 28:041dac1366b2 1080 * @details Function for doing action upon flash operation failure event, which includes retrying
vcoubard 28:041dac1366b2 1081 * the last operation or if retry count has been reached completing the operation with
vcoubard 28:041dac1366b2 1082 * appropriate result code and transitioning to an error state.
vcoubard 28:041dac1366b2 1083 *
vcoubard 28:041dac1366b2 1084 * @note The command is not removed from the command queue, which will result to stalling of the
vcoubard 28:041dac1366b2 1085 * command pipeline and the appropriate application recovery procedure for this is to reset
vcoubard 28:041dac1366b2 1086 * the system by issuing @ref pstorage_init which will also result to flushing of the
vcoubard 28:041dac1366b2 1087 * command queue.
vcoubard 28:041dac1366b2 1088 */
vcoubard 28:041dac1366b2 1089 static void flash_operation_failure_run(void)
vcoubard 28:041dac1366b2 1090 {
vcoubard 28:041dac1366b2 1091 if (++m_num_of_command_retries != SD_CMD_MAX_TRIES)
vcoubard 28:041dac1366b2 1092 {
vcoubard 28:041dac1366b2 1093 // Retry the last operation by doing a self transition to the current state.
vcoubard 28:041dac1366b2 1094
vcoubard 28:041dac1366b2 1095 if (m_state != STATE_DATA_ERASE_WITH_SWAP)
vcoubard 28:041dac1366b2 1096 {
vcoubard 28:041dac1366b2 1097 sm_state_change(m_state);
vcoubard 28:041dac1366b2 1098 }
vcoubard 28:041dac1366b2 1099 else
vcoubard 28:041dac1366b2 1100 {
vcoubard 28:041dac1366b2 1101 swap_sub_state_state_change(m_swap_sub_state);
vcoubard 28:041dac1366b2 1102 }
vcoubard 28:041dac1366b2 1103 }
vcoubard 28:041dac1366b2 1104 else
vcoubard 28:041dac1366b2 1105 {
vcoubard 28:041dac1366b2 1106 // Complete the operation with appropriate result code and transit to an error state.
vcoubard 28:041dac1366b2 1107 app_notify_error_state_transit(NRF_ERROR_TIMEOUT);
vcoubard 28:041dac1366b2 1108 }
vcoubard 28:041dac1366b2 1109 }
vcoubard 19:47192cb9def7 1110
vcoubard 28:041dac1366b2 1111
vcoubard 28:041dac1366b2 1112 /**@brief Function for handling flash access result events.
vcoubard 28:041dac1366b2 1113 *
vcoubard 28:041dac1366b2 1114 * @param[in] sys_evt System event to be handled.
vcoubard 28:041dac1366b2 1115 */
vcoubard 28:041dac1366b2 1116 void pstorage_sys_event_handler(uint32_t sys_evt)
vcoubard 28:041dac1366b2 1117 {
vcoubard 28:041dac1366b2 1118 if (m_state != STATE_IDLE && m_state != STATE_ERROR)
vcoubard 28:041dac1366b2 1119 {
vcoubard 28:041dac1366b2 1120 switch (sys_evt)
vcoubard 28:041dac1366b2 1121 {
vcoubard 28:041dac1366b2 1122 case NRF_EVT_FLASH_OPERATION_SUCCESS:
vcoubard 28:041dac1366b2 1123 flash_operation_success_run();
vcoubard 28:041dac1366b2 1124 break;
vcoubard 28:041dac1366b2 1125
vcoubard 28:041dac1366b2 1126 case NRF_EVT_FLASH_OPERATION_ERROR:
vcoubard 28:041dac1366b2 1127 if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
vcoubard 27:0fe148f1bca3 1128 {
vcoubard 28:041dac1366b2 1129 flash_operation_failure_run();
vcoubard 27:0fe148f1bca3 1130 }
vcoubard 27:0fe148f1bca3 1131 else
vcoubard 27:0fe148f1bca3 1132 {
vcoubard 28:041dac1366b2 1133 // As our last flash operation request was rejected by the flash API reissue the
vcoubard 28:041dac1366b2 1134 // request by doing same code execution path as for flash operation sucess
vcoubard 28:041dac1366b2 1135 // event. This will promote code reuse in the implementation.
vcoubard 28:041dac1366b2 1136 flash_operation_success_run();
vcoubard 28:041dac1366b2 1137 }
vcoubard 28:041dac1366b2 1138 break;
vcoubard 28:041dac1366b2 1139
vcoubard 28:041dac1366b2 1140 default:
vcoubard 28:041dac1366b2 1141 // No implementation needed.
vcoubard 28:041dac1366b2 1142 break;
vcoubard 28:041dac1366b2 1143 }
vcoubard 28:041dac1366b2 1144
vcoubard 28:041dac1366b2 1145 }
vcoubard 28:041dac1366b2 1146 }
vcoubard 28:041dac1366b2 1147
vcoubard 27:0fe148f1bca3 1148
vcoubard 28:041dac1366b2 1149 /**@brief Function for calculating the tail area size in number of 32-bit words.
vcoubard 28:041dac1366b2 1150 *
vcoubard 28:041dac1366b2 1151 * @param[in] cmd_end_of_storage_address End of storage area within the scope of the command.
vcoubard 28:041dac1366b2 1152 * @param[in] end_of_storage_address End of allocated storage area for the application.
vcoubard 28:041dac1366b2 1153 */
vcoubard 28:041dac1366b2 1154 static void tail_word_size_calculate(pstorage_size_t cmd_end_of_storage_address,
vcoubard 28:041dac1366b2 1155 pstorage_size_t end_of_storage_address)
vcoubard 28:041dac1366b2 1156 {
vcoubard 28:041dac1366b2 1157 // Two different cases to resolve when calculating correct size for restore tail section:
vcoubard 28:041dac1366b2 1158 // 1) End of storage area and command end area are in the same page.
vcoubard 28:041dac1366b2 1159 // 2) End of storage area and command end area are not in the same page.
vcoubard 28:041dac1366b2 1160
vcoubard 28:041dac1366b2 1161 const uint32_t end_of_storage_area_page = end_of_storage_address /
vcoubard 28:041dac1366b2 1162 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 1163 const uint32_t command_end_of_storage_area_page = cmd_end_of_storage_address /
vcoubard 28:041dac1366b2 1164 PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 27:0fe148f1bca3 1165
vcoubard 28:041dac1366b2 1166 if (end_of_storage_area_page == command_end_of_storage_area_page)
vcoubard 28:041dac1366b2 1167 {
vcoubard 28:041dac1366b2 1168 //lint -e{573} suppress "Signed-unsigned mix with divide".
vcoubard 28:041dac1366b2 1169 m_tail_word_size = (end_of_storage_address - cmd_end_of_storage_address) / sizeof(uint32_t);
vcoubard 24:2aea0c1c57ee 1170 }
vcoubard 28:041dac1366b2 1171 else
vcoubard 28:041dac1366b2 1172 {
vcoubard 28:041dac1366b2 1173 //lint -e{573} suppress "Signed-unsigned mix with divide".
vcoubard 28:041dac1366b2 1174 m_tail_word_size = (PSTORAGE_FLASH_PAGE_SIZE -
vcoubard 28:041dac1366b2 1175 (cmd_end_of_storage_address % PSTORAGE_FLASH_PAGE_SIZE)) /
vcoubard 28:041dac1366b2 1176 sizeof(uint32_t);
vcoubard 28:041dac1366b2 1177 }
vcoubard 24:2aea0c1c57ee 1178 }
Vincent Coubard 0:f2542974c862 1179
vcoubard 24:2aea0c1c57ee 1180
vcoubard 28:041dac1366b2 1181 /**@brief Function for executing the clear operation.
vcoubard 24:2aea0c1c57ee 1182 */
vcoubard 28:041dac1366b2 1183 static void clear_operation_execute(void)
vcoubard 28:041dac1366b2 1184 {
vcoubard 28:041dac1366b2 1185 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 1186 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
vcoubard 28:041dac1366b2 1187
vcoubard 28:041dac1366b2 1188 const pstorage_size_t block_size = m_app_table[p_cmd->storage_addr.module_id].block_size;
vcoubard 28:041dac1366b2 1189 const pstorage_size_t block_count = m_app_table[p_cmd->storage_addr.module_id].block_count;
vcoubard 28:041dac1366b2 1190 const pstorage_block_t block_base_id = m_app_table[p_cmd->storage_addr.module_id].base_id;
vcoubard 28:041dac1366b2 1191
vcoubard 28:041dac1366b2 1192 const bool is_start_address_page_aligned = (cmd_block_id % PSTORAGE_FLASH_PAGE_SIZE) == 0;
vcoubard 28:041dac1366b2 1193
vcoubard 28:041dac1366b2 1194 // Calculate the end (1 beyond allocated area) for complete storage area and to the area only
vcoubard 28:041dac1366b2 1195 // within scope of this command.
vcoubard 28:041dac1366b2 1196 const pstorage_block_t end_of_storage_address = block_base_id + (block_size * block_count);
vcoubard 28:041dac1366b2 1197 const pstorage_block_t cmd_end_of_storage_address = cmd_block_id + p_cmd->size + p_cmd->offset;
vcoubard 28:041dac1366b2 1198
vcoubard 28:041dac1366b2 1199 // Zero tail to make sure no extra erase is done erroneously.
vcoubard 28:041dac1366b2 1200 m_tail_word_size = 0;
vcoubard 28:041dac1366b2 1201
vcoubard 28:041dac1366b2 1202 // If the following is true no swap access is needed:
vcoubard 28:041dac1366b2 1203 // - 1st logical test covers the case of: clear/update 1 complete single page.
vcoubard 28:041dac1366b2 1204 // - 2nd logical test covers the case of:
vcoubard 28:041dac1366b2 1205 // 1) Clear/update last allocated page and page is not full (page can't be shared between
vcoubard 28:041dac1366b2 1206 // multiple clients so the end of the page is unused area).
vcoubard 28:041dac1366b2 1207 // 2) Clear/update all allocated storage.
vcoubard 28:041dac1366b2 1208 if ((is_start_address_page_aligned && (p_cmd->size == PSTORAGE_FLASH_PAGE_SIZE)) ||
vcoubard 28:041dac1366b2 1209 (is_start_address_page_aligned && (cmd_end_of_storage_address == end_of_storage_address) &&
vcoubard 28:041dac1366b2 1210 (p_cmd->offset == 0)) || (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
vcoubard 28:041dac1366b2 1211 {
vcoubard 28:041dac1366b2 1212 // Nothing to put to the swap and we can just erase the pages(s).
vcoubard 28:041dac1366b2 1213
vcoubard 28:041dac1366b2 1214 m_current_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 1215
vcoubard 28:041dac1366b2 1216 sm_state_change(STATE_DATA_ERASE);
vcoubard 28:041dac1366b2 1217 }
vcoubard 28:041dac1366b2 1218 else
vcoubard 28:041dac1366b2 1219 {
vcoubard 28:041dac1366b2 1220 // Not all the blocks for the module can be cleared, we need to use swap page for storing
vcoubard 28:041dac1366b2 1221 // data temporarily.
vcoubard 28:041dac1366b2 1222
vcoubard 28:041dac1366b2 1223 m_head_word_size = ((cmd_block_id + p_cmd->offset) % PSTORAGE_FLASH_PAGE_SIZE) /
vcoubard 28:041dac1366b2 1224 sizeof(uint32_t);
vcoubard 28:041dac1366b2 1225
vcoubard 28:041dac1366b2 1226 const bool is_cmd_end_address_page_aligned = ((cmd_end_of_storage_address %
vcoubard 28:041dac1366b2 1227 PSTORAGE_FLASH_PAGE_SIZE) == 0);
vcoubard 28:041dac1366b2 1228 if ((cmd_end_of_storage_address != end_of_storage_address) &&
vcoubard 28:041dac1366b2 1229 !is_cmd_end_address_page_aligned)
vcoubard 28:041dac1366b2 1230 {
vcoubard 28:041dac1366b2 1231 // When command area is not equal to end of the storage allocation area and not ending
vcoubard 28:041dac1366b2 1232 // to page boundary there is a need to restore the tail area.
vcoubard 28:041dac1366b2 1233 tail_word_size_calculate(cmd_end_of_storage_address, end_of_storage_address);
vcoubard 28:041dac1366b2 1234 }
vcoubard 28:041dac1366b2 1235
vcoubard 28:041dac1366b2 1236 sm_state_change(STATE_DATA_ERASE_WITH_SWAP);
vcoubard 28:041dac1366b2 1237 }
vcoubard 28:041dac1366b2 1238 }
vcoubard 28:041dac1366b2 1239
vcoubard 28:041dac1366b2 1240
vcoubard 28:041dac1366b2 1241 /**@brief Function for executing the store operation.
vcoubard 28:041dac1366b2 1242 */
vcoubard 28:041dac1366b2 1243 static void store_operation_execute(void)
vcoubard 28:041dac1366b2 1244 {
vcoubard 28:041dac1366b2 1245 sm_state_change(STATE_STORE);
vcoubard 28:041dac1366b2 1246 }
vcoubard 28:041dac1366b2 1247
vcoubard 28:041dac1366b2 1248
vcoubard 28:041dac1366b2 1249 /**@brief Function for executing the update operation.
vcoubard 28:041dac1366b2 1250 */
vcoubard 28:041dac1366b2 1251 static void update_operation_execute(void)
vcoubard 27:0fe148f1bca3 1252 {
vcoubard 28:041dac1366b2 1253 clear_operation_execute();
vcoubard 28:041dac1366b2 1254 }
vcoubard 28:041dac1366b2 1255
vcoubard 24:2aea0c1c57ee 1256
vcoubard 28:041dac1366b2 1257 /**@brief Function for dispatching the flash access operation.
vcoubard 28:041dac1366b2 1258 */
vcoubard 28:041dac1366b2 1259 static void cmd_process(void)
vcoubard 28:041dac1366b2 1260 {
vcoubard 28:041dac1366b2 1261 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
vcoubard 28:041dac1366b2 1262 m_app_data_size = p_cmd->size;
Vincent Coubard 0:f2542974c862 1263
Vincent Coubard 0:f2542974c862 1264 switch (p_cmd->op_code)
Vincent Coubard 0:f2542974c862 1265 {
vcoubard 28:041dac1366b2 1266 case PSTORAGE_STORE_OP_CODE:
vcoubard 28:041dac1366b2 1267 store_operation_execute();
vcoubard 28:041dac1366b2 1268 break;
Vincent Coubard 0:f2542974c862 1269
Vincent Coubard 0:f2542974c862 1270 case PSTORAGE_CLEAR_OP_CODE:
vcoubard 28:041dac1366b2 1271 clear_operation_execute();
vcoubard 28:041dac1366b2 1272 break;
Vincent Coubard 0:f2542974c862 1273
Vincent Coubard 0:f2542974c862 1274 case PSTORAGE_UPDATE_OP_CODE:
vcoubard 28:041dac1366b2 1275 update_operation_execute();
vcoubard 28:041dac1366b2 1276 break;
Vincent Coubard 0:f2542974c862 1277
Vincent Coubard 0:f2542974c862 1278 default:
vcoubard 28:041dac1366b2 1279 // No action required.
Vincent Coubard 0:f2542974c862 1280 break;
Vincent Coubard 0:f2542974c862 1281 }
Vincent Coubard 0:f2542974c862 1282 }
Vincent Coubard 0:f2542974c862 1283
Vincent Coubard 0:f2542974c862 1284
Vincent Coubard 0:f2542974c862 1285 uint32_t pstorage_init(void)
Vincent Coubard 0:f2542974c862 1286 {
Vincent Coubard 0:f2542974c862 1287 cmd_queue_init();
Vincent Coubard 0:f2542974c862 1288
Vincent Coubard 0:f2542974c862 1289 m_next_app_instance = 0;
Vincent Coubard 0:f2542974c862 1290 m_next_page_addr = PSTORAGE_DATA_START_ADDR;
vcoubard 28:041dac1366b2 1291 m_current_page_id = 0;
vcoubard 28:041dac1366b2 1292
vcoubard 28:041dac1366b2 1293 for (uint32_t index = 0; index < PSTORAGE_NUM_OF_PAGES; index++)
Vincent Coubard 0:f2542974c862 1294 {
Vincent Coubard 0:f2542974c862 1295 m_app_table[index].cb = NULL;
Vincent Coubard 0:f2542974c862 1296 m_app_table[index].block_size = 0;
Vincent Coubard 0:f2542974c862 1297 m_app_table[index].block_count = 0;
Vincent Coubard 0:f2542974c862 1298 }
Vincent Coubard 0:f2542974c862 1299
Vincent Coubard 0:f2542974c862 1300 #ifdef PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 1301 m_raw_app_table.cb = NULL;
Vincent Coubard 0:f2542974c862 1302 #endif //PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 1303
vcoubard 28:041dac1366b2 1304 m_state = STATE_IDLE;
vcoubard 28:041dac1366b2 1305 m_num_of_command_retries = 0;
vcoubard 28:041dac1366b2 1306 m_flags = 0;
vcoubard 28:041dac1366b2 1307 m_num_of_bytes_written = 0;
vcoubard 28:041dac1366b2 1308 m_flags |= MASK_MODULE_INITIALIZED;
vcoubard 28:041dac1366b2 1309
vcoubard 28:041dac1366b2 1310 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1311 }
Vincent Coubard 0:f2542974c862 1312
Vincent Coubard 0:f2542974c862 1313
Vincent Coubard 0:f2542974c862 1314 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
Vincent Coubard 0:f2542974c862 1315 pstorage_handle_t * p_block_id)
Vincent Coubard 0:f2542974c862 1316 {
Vincent Coubard 0:f2542974c862 1317 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1318 NULL_PARAM_CHECK(p_module_param);
Vincent Coubard 0:f2542974c862 1319 NULL_PARAM_CHECK(p_block_id);
Vincent Coubard 0:f2542974c862 1320 NULL_PARAM_CHECK(p_module_param->cb);
vcoubard 1:ebc0e0ef0a11 1321 BLOCK_SIZE_CHECK(p_module_param->block_size);
Vincent Coubard 0:f2542974c862 1322 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
Vincent Coubard 0:f2542974c862 1323
Vincent Coubard 0:f2542974c862 1324 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
Vincent Coubard 0:f2542974c862 1325 {
Vincent Coubard 0:f2542974c862 1326 return NRF_ERROR_INVALID_PARAM;
Vincent Coubard 0:f2542974c862 1327 }
vcoubard 28:041dac1366b2 1328
vcoubard 28:041dac1366b2 1329 if (m_next_app_instance == PSTORAGE_NUM_OF_PAGES)
Vincent Coubard 0:f2542974c862 1330 {
Vincent Coubard 0:f2542974c862 1331 return NRF_ERROR_NO_MEM;
Vincent Coubard 0:f2542974c862 1332 }
Vincent Coubard 0:f2542974c862 1333
Vincent Coubard 0:f2542974c862 1334 p_block_id->module_id = m_next_app_instance;
Vincent Coubard 0:f2542974c862 1335 p_block_id->block_id = m_next_page_addr;
Vincent Coubard 0:f2542974c862 1336
Vincent Coubard 0:f2542974c862 1337 m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
Vincent Coubard 0:f2542974c862 1338 m_app_table[m_next_app_instance].cb = p_module_param->cb;
Vincent Coubard 0:f2542974c862 1339 m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
Vincent Coubard 0:f2542974c862 1340 m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
Vincent Coubard 0:f2542974c862 1341
vcoubard 28:041dac1366b2 1342 // Calculate number of flash pages allocated for the device and adjust next free page address.
vcoubard 28:041dac1366b2 1343 /*lint -save -e666 */
vcoubard 28:041dac1366b2 1344 const uint32_t page_count = CEIL_DIV((p_module_param->block_size * p_module_param->block_count),
vcoubard 28:041dac1366b2 1345 PSTORAGE_FLASH_PAGE_SIZE);
vcoubard 28:041dac1366b2 1346 /*lint -restore */
vcoubard 28:041dac1366b2 1347 m_next_page_addr += page_count * PSTORAGE_FLASH_PAGE_SIZE;
vcoubard 28:041dac1366b2 1348
vcoubard 28:041dac1366b2 1349 ++m_next_app_instance;
Vincent Coubard 0:f2542974c862 1350
Vincent Coubard 0:f2542974c862 1351 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1352 }
Vincent Coubard 0:f2542974c862 1353
Vincent Coubard 0:f2542974c862 1354
Vincent Coubard 0:f2542974c862 1355 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
Vincent Coubard 0:f2542974c862 1356 pstorage_size_t block_num,
Vincent Coubard 0:f2542974c862 1357 pstorage_handle_t * p_block_id)
Vincent Coubard 0:f2542974c862 1358 {
Vincent Coubard 0:f2542974c862 1359 pstorage_handle_t temp_id;
Vincent Coubard 0:f2542974c862 1360
Vincent Coubard 0:f2542974c862 1361 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1362 NULL_PARAM_CHECK(p_base_id);
Vincent Coubard 0:f2542974c862 1363 NULL_PARAM_CHECK(p_block_id);
Vincent Coubard 0:f2542974c862 1364 MODULE_ID_RANGE_CHECK(p_base_id);
Vincent Coubard 0:f2542974c862 1365
Vincent Coubard 0:f2542974c862 1366 temp_id = (*p_base_id);
Vincent Coubard 0:f2542974c862 1367 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
Vincent Coubard 0:f2542974c862 1368
Vincent Coubard 0:f2542974c862 1369 BLOCK_ID_RANGE_CHECK(&temp_id);
Vincent Coubard 0:f2542974c862 1370
Vincent Coubard 0:f2542974c862 1371 (*p_block_id) = temp_id;
Vincent Coubard 0:f2542974c862 1372
Vincent Coubard 0:f2542974c862 1373 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1374 }
Vincent Coubard 0:f2542974c862 1375
Vincent Coubard 0:f2542974c862 1376
Vincent Coubard 0:f2542974c862 1377 uint32_t pstorage_store(pstorage_handle_t * p_dest,
Vincent Coubard 0:f2542974c862 1378 uint8_t * p_src,
Vincent Coubard 0:f2542974c862 1379 pstorage_size_t size,
Vincent Coubard 0:f2542974c862 1380 pstorage_size_t offset)
Vincent Coubard 0:f2542974c862 1381 {
Vincent Coubard 0:f2542974c862 1382 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1383 NULL_PARAM_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1384 NULL_PARAM_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1385 MODULE_ID_RANGE_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1386 BLOCK_ID_RANGE_CHECK(p_dest);
vcoubard 28:041dac1366b2 1387 SIZE_CHECK(p_dest, size);
vcoubard 28:041dac1366b2 1388 OFFSET_CHECK(p_dest, offset, size);
vcoubard 28:041dac1366b2 1389
vcoubard 28:041dac1366b2 1390 if ((!is_word_aligned(p_src)) ||
vcoubard 28:041dac1366b2 1391 (!is_word_aligned((void *)(uint32_t)offset)) ||
vcoubard 28:041dac1366b2 1392 (!is_word_aligned((uint32_t *)p_dest->block_id)))
Vincent Coubard 0:f2542974c862 1393 {
Vincent Coubard 0:f2542974c862 1394 return NRF_ERROR_INVALID_ADDR;
Vincent Coubard 0:f2542974c862 1395 }
Vincent Coubard 0:f2542974c862 1396
Vincent Coubard 0:f2542974c862 1397 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
Vincent Coubard 0:f2542974c862 1398 }
Vincent Coubard 0:f2542974c862 1399
Vincent Coubard 0:f2542974c862 1400
Vincent Coubard 0:f2542974c862 1401 uint32_t pstorage_update(pstorage_handle_t * p_dest,
Vincent Coubard 0:f2542974c862 1402 uint8_t * p_src,
Vincent Coubard 0:f2542974c862 1403 pstorage_size_t size,
Vincent Coubard 0:f2542974c862 1404 pstorage_size_t offset)
Vincent Coubard 0:f2542974c862 1405 {
Vincent Coubard 0:f2542974c862 1406 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1407 NULL_PARAM_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1408 NULL_PARAM_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1409 MODULE_ID_RANGE_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1410 BLOCK_ID_RANGE_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1411 SIZE_CHECK(p_dest, size);
Vincent Coubard 0:f2542974c862 1412 OFFSET_CHECK(p_dest, offset, size);
Vincent Coubard 0:f2542974c862 1413
vcoubard 28:041dac1366b2 1414 if ((!is_word_aligned(p_src)) ||
vcoubard 28:041dac1366b2 1415 (!is_word_aligned((void *)(uint32_t)offset)) ||
vcoubard 28:041dac1366b2 1416 (!is_word_aligned((uint32_t *)p_dest->block_id)))
Vincent Coubard 0:f2542974c862 1417 {
Vincent Coubard 0:f2542974c862 1418 return NRF_ERROR_INVALID_ADDR;
Vincent Coubard 0:f2542974c862 1419 }
Vincent Coubard 0:f2542974c862 1420
Vincent Coubard 0:f2542974c862 1421 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
Vincent Coubard 0:f2542974c862 1422 }
Vincent Coubard 0:f2542974c862 1423
Vincent Coubard 0:f2542974c862 1424
Vincent Coubard 0:f2542974c862 1425 uint32_t pstorage_load(uint8_t * p_dest,
Vincent Coubard 0:f2542974c862 1426 pstorage_handle_t * p_src,
Vincent Coubard 0:f2542974c862 1427 pstorage_size_t size,
Vincent Coubard 0:f2542974c862 1428 pstorage_size_t offset)
Vincent Coubard 0:f2542974c862 1429 {
Vincent Coubard 0:f2542974c862 1430 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1431 NULL_PARAM_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1432 NULL_PARAM_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1433 MODULE_ID_RANGE_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1434 BLOCK_ID_RANGE_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1435 SIZE_CHECK(p_src, size);
Vincent Coubard 0:f2542974c862 1436 OFFSET_CHECK(p_src, offset, size);
Vincent Coubard 0:f2542974c862 1437
vcoubard 28:041dac1366b2 1438 if ((!is_word_aligned(p_dest)) ||
vcoubard 28:041dac1366b2 1439 (!is_word_aligned((void *)(uint32_t)offset)) ||
vcoubard 28:041dac1366b2 1440 (!is_word_aligned((uint32_t *)p_src->block_id)))
Vincent Coubard 0:f2542974c862 1441 {
Vincent Coubard 0:f2542974c862 1442 return NRF_ERROR_INVALID_ADDR;
Vincent Coubard 0:f2542974c862 1443 }
Vincent Coubard 0:f2542974c862 1444
Vincent Coubard 0:f2542974c862 1445 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
Vincent Coubard 0:f2542974c862 1446
Vincent Coubard 0:f2542974c862 1447 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
Vincent Coubard 0:f2542974c862 1448
Vincent Coubard 0:f2542974c862 1449 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1450 }
Vincent Coubard 0:f2542974c862 1451
Vincent Coubard 0:f2542974c862 1452
Vincent Coubard 0:f2542974c862 1453 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
Vincent Coubard 0:f2542974c862 1454 {
Vincent Coubard 0:f2542974c862 1455 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1456 NULL_PARAM_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1457 MODULE_ID_RANGE_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1458 BLOCK_ID_RANGE_CHECK(p_dest);
Vincent Coubard 0:f2542974c862 1459
Vincent Coubard 0:f2542974c862 1460 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
Vincent Coubard 0:f2542974c862 1461 {
Vincent Coubard 0:f2542974c862 1462 return NRF_ERROR_INVALID_ADDR;
Vincent Coubard 0:f2542974c862 1463 }
Vincent Coubard 0:f2542974c862 1464
vcoubard 28:041dac1366b2 1465 // Check is the area starting from block_id multiple of block_size.
Vincent Coubard 0:f2542974c862 1466 if (
Vincent Coubard 0:f2542974c862 1467 !(
Vincent Coubard 0:f2542974c862 1468 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
Vincent Coubard 0:f2542974c862 1469 m_app_table[p_dest->module_id].block_size) == 0
Vincent Coubard 0:f2542974c862 1470 )
Vincent Coubard 0:f2542974c862 1471 )
Vincent Coubard 0:f2542974c862 1472 {
Vincent Coubard 0:f2542974c862 1473 return NRF_ERROR_INVALID_PARAM;
Vincent Coubard 0:f2542974c862 1474 }
Vincent Coubard 0:f2542974c862 1475
vcoubard 28:041dac1366b2 1476 // Check is requested size multiple of registered block size or 0.
vcoubard 28:041dac1366b2 1477 if (((size % m_app_table[p_dest->module_id].block_size) != 0) || (size == 0))
vcoubard 28:041dac1366b2 1478 {
vcoubard 28:041dac1366b2 1479 return NRF_ERROR_INVALID_PARAM;
vcoubard 28:041dac1366b2 1480 }
Vincent Coubard 0:f2542974c862 1481
vcoubard 28:041dac1366b2 1482 const uint32_t registered_allocation_size = m_app_table[p_dest->module_id].block_size *
vcoubard 28:041dac1366b2 1483 m_app_table[p_dest->module_id].block_count;
vcoubard 28:041dac1366b2 1484
vcoubard 28:041dac1366b2 1485 const pstorage_block_t clear_request_end_address = p_dest->block_id + size;
vcoubard 28:041dac1366b2 1486 const pstorage_block_t allocation_end_address = m_app_table[p_dest->module_id].base_id +
vcoubard 28:041dac1366b2 1487 registered_allocation_size;
vcoubard 28:041dac1366b2 1488 // Check if request would lead to a buffer overrun.
vcoubard 28:041dac1366b2 1489 if (clear_request_end_address > allocation_end_address)
vcoubard 28:041dac1366b2 1490 {
vcoubard 28:041dac1366b2 1491 return NRF_ERROR_INVALID_PARAM;
vcoubard 28:041dac1366b2 1492 }
vcoubard 28:041dac1366b2 1493
vcoubard 28:041dac1366b2 1494 return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
Vincent Coubard 0:f2542974c862 1495 }
Vincent Coubard 0:f2542974c862 1496
Vincent Coubard 0:f2542974c862 1497
Vincent Coubard 0:f2542974c862 1498 uint32_t pstorage_access_status_get(uint32_t * p_count)
Vincent Coubard 0:f2542974c862 1499 {
Vincent Coubard 0:f2542974c862 1500 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1501 NULL_PARAM_CHECK(p_count);
Vincent Coubard 0:f2542974c862 1502
Vincent Coubard 0:f2542974c862 1503 (*p_count) = m_cmd_queue.count;
Vincent Coubard 0:f2542974c862 1504
Vincent Coubard 0:f2542974c862 1505 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1506 }
Vincent Coubard 0:f2542974c862 1507
Vincent Coubard 0:f2542974c862 1508 #ifdef PSTORAGE_RAW_MODE_ENABLE
Vincent Coubard 0:f2542974c862 1509
Vincent Coubard 0:f2542974c862 1510 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
Vincent Coubard 0:f2542974c862 1511 pstorage_handle_t * p_block_id)
Vincent Coubard 0:f2542974c862 1512 {
Vincent Coubard 0:f2542974c862 1513 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1514 NULL_PARAM_CHECK(p_module_param);
Vincent Coubard 0:f2542974c862 1515 NULL_PARAM_CHECK(p_block_id);
Vincent Coubard 0:f2542974c862 1516 NULL_PARAM_CHECK(p_module_param->cb);
Vincent Coubard 0:f2542974c862 1517
Vincent Coubard 0:f2542974c862 1518 if (m_raw_app_table.cb != NULL)
Vincent Coubard 0:f2542974c862 1519 {
Vincent Coubard 0:f2542974c862 1520 return NRF_ERROR_NO_MEM;
Vincent Coubard 0:f2542974c862 1521 }
Vincent Coubard 0:f2542974c862 1522
Vincent Coubard 0:f2542974c862 1523 p_block_id->module_id = RAW_MODE_APP_ID;
Vincent Coubard 0:f2542974c862 1524 m_raw_app_table.cb = p_module_param->cb;
Vincent Coubard 0:f2542974c862 1525
Vincent Coubard 0:f2542974c862 1526 return NRF_SUCCESS;
Vincent Coubard 0:f2542974c862 1527 }
Vincent Coubard 0:f2542974c862 1528
Vincent Coubard 0:f2542974c862 1529
Vincent Coubard 0:f2542974c862 1530 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
Vincent Coubard 0:f2542974c862 1531 uint8_t * p_src,
Vincent Coubard 0:f2542974c862 1532 pstorage_size_t size,
Vincent Coubard 0:f2542974c862 1533 pstorage_size_t offset)
Vincent Coubard 0:f2542974c862 1534 {
Vincent Coubard 0:f2542974c862 1535 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1536 NULL_PARAM_CHECK(p_src);
Vincent Coubard 0:f2542974c862 1537 NULL_PARAM_CHECK(p_dest);
vcoubard 28:041dac1366b2 1538 MODULE_RAW_HANDLE_CHECK(p_dest);
vcoubard 28:041dac1366b2 1539
vcoubard 28:041dac1366b2 1540 if (size == 0)
vcoubard 28:041dac1366b2 1541 {
vcoubard 28:041dac1366b2 1542 return NRF_ERROR_INVALID_PARAM;
vcoubard 28:041dac1366b2 1543 }
vcoubard 28:041dac1366b2 1544
Vincent Coubard 0:f2542974c862 1545 // Verify word alignment.
vcoubard 28:041dac1366b2 1546 if ((!is_word_aligned(p_src)) ||
vcoubard 28:041dac1366b2 1547 (!is_word_aligned((void *)(uint32_t)size)) ||
vcoubard 28:041dac1366b2 1548 (!is_word_aligned((void *)(uint32_t)offset)) ||
vcoubard 28:041dac1366b2 1549 (!is_word_aligned((void *)(p_dest->block_id))))
Vincent Coubard 0:f2542974c862 1550 {
Vincent Coubard 0:f2542974c862 1551 return NRF_ERROR_INVALID_ADDR;
Vincent Coubard 0:f2542974c862 1552 }
vcoubard 28:041dac1366b2 1553
Vincent Coubard 0:f2542974c862 1554 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
Vincent Coubard 0:f2542974c862 1555 }
Vincent Coubard 0:f2542974c862 1556
Vincent Coubard 0:f2542974c862 1557
Vincent Coubard 0:f2542974c862 1558 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
Vincent Coubard 0:f2542974c862 1559 {
Vincent Coubard 0:f2542974c862 1560 VERIFY_MODULE_INITIALIZED();
Vincent Coubard 0:f2542974c862 1561 NULL_PARAM_CHECK(p_dest);
vcoubard 28:041dac1366b2 1562 MODULE_RAW_HANDLE_CHECK(p_dest);
vcoubard 28:041dac1366b2 1563
vcoubard 28:041dac1366b2 1564 if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
vcoubard 28:041dac1366b2 1565 {
vcoubard 28:041dac1366b2 1566 return NRF_ERROR_INVALID_ADDR;
vcoubard 28:041dac1366b2 1567 }
Vincent Coubard 0:f2542974c862 1568
vcoubard 28:041dac1366b2 1569 return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
Vincent Coubard 0:f2542974c862 1570 }
Vincent Coubard 0:f2542974c862 1571
vcoubard 1:ebc0e0ef0a11 1572 #endif // PSTORAGE_RAW_MODE_ENABLE