Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nrf51-sdk by
pstorage.c
00001 /* 00002 * Copyright (c) Nordic Semiconductor ASA 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without modification, 00006 * are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * 00011 * 2. Redistributions in binary form must reproduce the above copyright notice, this 00012 * list of conditions and the following disclaimer in the documentation and/or 00013 * other materials provided with the distribution. 00014 * 00015 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other 00016 * contributors to this software may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00021 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00023 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 00024 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 00027 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #include "pstorage.h " 00034 #include <stdlib.h> 00035 #include <stdint.h> 00036 #include <string.h> 00037 #include "nordic_common.h" 00038 #include "nrf_error.h" 00039 #include "nrf_assert.h" 00040 #include "nrf.h" 00041 #include "nrf_soc.h" 00042 #include "app_util.h " 00043 #include "app_error.h " 00044 00045 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */ 00046 #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. */ 00047 #define RAW_MODE_APP_ID (PSTORAGE_NUM_OF_PAGES + 1) /**< Application id for raw mode. */ 00048 00049 #if defined(NRF52) 00050 #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*/ 00051 #else 00052 #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. */ 00053 #endif /* defined(NRF52) */ 00054 00055 #define MASK_TAIL_SWAP_DONE (1 << 0) /**< Flag for checking if the tail restore area has been written to swap page. */ 00056 #define MASK_SINGLE_PAGE_OPERATION (1 << 1) /**< Flag for checking if command is a single flash page operation. */ 00057 #define MASK_MODULE_INITIALIZED (1 << 2) /**< Flag for checking if the module has been initialized. */ 00058 #define MASK_FLASH_API_ERR_BUSY (1 << 3) /**< Flag for checking if flash API returned NRF_ERROR_BUSY. */ 00059 00060 /** 00061 * @defgroup api_param_check API Parameters check macros. 00062 * 00063 * @details Macros that verify parameters passed to the module in the APIs. These macros 00064 * could be mapped to nothing in final code versions to save execution and size. 00065 * 00066 * @{ 00067 */ 00068 00069 /**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL. 00070 */ 00071 #define NULL_PARAM_CHECK(PARAM) \ 00072 if ((PARAM) == NULL) \ 00073 { \ 00074 return NRF_ERROR_NULL; \ 00075 } 00076 00077 /**@brief Verifies that the module identifier supplied by the application is within permissible 00078 * range. 00079 */ 00080 #define MODULE_ID_RANGE_CHECK(ID) \ 00081 if ((((ID)->module_id) >= PSTORAGE_NUM_OF_PAGES) || \ 00082 (m_app_table[(ID)->module_id].cb == NULL)) \ 00083 { \ 00084 return NRF_ERROR_INVALID_PARAM; \ 00085 } 00086 00087 /**@brief Verifies that the block identifier supplied by the application is within the permissible 00088 * range. 00089 */ 00090 #define BLOCK_ID_RANGE_CHECK(ID) \ 00091 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \ 00092 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \ 00093 { \ 00094 return NRF_ERROR_INVALID_PARAM; \ 00095 } 00096 00097 /**@brief Verifies that the block size requested by the application can be supported by the module. 00098 */ 00099 #define BLOCK_SIZE_CHECK(X) \ 00100 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \ 00101 { \ 00102 return NRF_ERROR_INVALID_PARAM; \ 00103 } 00104 00105 /**@brief Verifies the block size requested by the application in registration API. 00106 */ 00107 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \ 00108 if (((COUNT) == 0) || \ 00109 ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR))) \ 00110 { \ 00111 return NRF_ERROR_INVALID_PARAM; \ 00112 } 00113 00114 /**@brief Verifies the size parameter provided by the application in API. 00115 */ 00116 #define SIZE_CHECK(ID, SIZE) \ 00117 if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \ 00118 { \ 00119 return NRF_ERROR_INVALID_PARAM; \ 00120 } 00121 00122 /**@brief Verifies the offset parameter provided by the application in API. 00123 */ 00124 #define OFFSET_CHECK(ID, OFFSET, SIZE) \ 00125 if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \ 00126 { \ 00127 return NRF_ERROR_INVALID_PARAM; \ 00128 } 00129 00130 #ifdef PSTORAGE_RAW_MODE_ENABLE 00131 00132 /**@brief Verifies the module identifier supplied by the application. 00133 */ 00134 #define MODULE_RAW_HANDLE_CHECK(ID) \ 00135 if ((((ID)->module_id) != RAW_MODE_APP_ID)) \ 00136 { \ 00137 return NRF_ERROR_INVALID_PARAM; \ 00138 } 00139 00140 #endif // PSTORAGE_RAW_MODE_ENABLE 00141 00142 /**@} */ 00143 00144 00145 /**@brief Verify module's initialization status. 00146 * 00147 * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE when a 00148 * module API is called without initializing the module. 00149 */ 00150 #define VERIFY_MODULE_INITIALIZED() \ 00151 do \ 00152 { \ 00153 if (!(m_flags & MASK_MODULE_INITIALIZED)) \ 00154 { \ 00155 return NRF_ERROR_INVALID_STATE; \ 00156 } \ 00157 } while(0) 00158 00159 /**@brief Macro to fetch the block size registered for the module. */ 00160 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size) 00161 00162 /**@brief Main state machine of the component. */ 00163 typedef enum 00164 { 00165 STATE_IDLE, /**< State for being idle (no command execution in progress). */ 00166 STATE_STORE, /**< State for storing data when using store/update API. */ 00167 STATE_DATA_ERASE_WITH_SWAP, /**< State for erasing the data page when using update/clear API when use of swap page is required. */ 00168 STATE_DATA_ERASE, /**< State for erasing the data page when using update/clear API without the need to use the swap page. */ 00169 STATE_ERROR /**< State entered when command processing is terminated abnormally. */ 00170 } pstorage_state_t; 00171 00172 /**@brief Sub state machine contained by @ref STATE_DATA_ERASE_WITH_SWAP super state machine. */ 00173 typedef enum 00174 { 00175 STATE_ERASE_SWAP, /**< State for erasing the swap page when using the update/clear API. */ 00176 STATE_WRITE_DATA_TO_SWAP, /**< State for writing the data page into the swap page when using update/clear API. */ 00177 STATE_ERASE_DATA_PAGE, /**< State for erasing data page when using update/clear API. */ 00178 STATE_RESTORE_TAIL, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */ 00179 STATE_RESTORE_HEAD, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */ 00180 SWAP_SUB_STATE_MAX /**< Enumeration upper bound. */ 00181 } flash_swap_sub_state_t; 00182 00183 /**@brief Application registration information. 00184 * 00185 * @details Defines application specific information that the application needs to maintain to be able 00186 * to process requests from each one of them. 00187 */ 00188 typedef struct 00189 { 00190 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */ 00191 pstorage_block_t base_id; /**< Base block ID assigned to the module. */ 00192 pstorage_size_t block_size; /**< Size of block for the module. */ 00193 pstorage_size_t block_count; /**< Number of blocks requested by the application. */ 00194 } pstorage_module_table_t; 00195 00196 00197 #ifdef PSTORAGE_RAW_MODE_ENABLE 00198 /**@brief Application registration information. 00199 * 00200 * @details Defines application specific information that the application registered for raw mode. 00201 */ 00202 typedef struct 00203 { 00204 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of the result of flash access. */ 00205 } pstorage_raw_module_table_t; 00206 #endif // PSTORAGE_RAW_MODE_ENABLE 00207 00208 00209 /**@brief Defines command queue element. 00210 * 00211 * @details Defines command queue element. Each element encapsulates needed information to process 00212 * a flash access command. 00213 */ 00214 typedef struct 00215 { 00216 uint8_t op_code; /**< Identifies the flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */ 00217 pstorage_size_t size; /**< Identifies the size in bytes requested for the operation. */ 00218 pstorage_size_t offset; /**< Offset requested by the application for the access operation. */ 00219 pstorage_handle_t storage_addr; /**< Address/Identifier for persistent memory. */ 00220 uint8_t * p_data_addr; /**< Address/Identifier for data memory. This is assumed to be resident memory. */ 00221 } cmd_queue_element_t; 00222 00223 00224 /**@brief Defines command queue, an element is free if the op_code field is not invalid. 00225 * 00226 * @details Defines commands enqueued for flash access. At any point in time, this queue has one or 00227 * more flash access operations pending if the count field is not zero. When the queue is 00228 * not empty, the rp (read pointer) field points to the flash access command in progress 00229 * or, if none is in progress, the command to be requested next. The queue implements a 00230 * simple first in first out algorithm. Data addresses are assumed to be resident. 00231 */ 00232 typedef struct 00233 { 00234 uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */ 00235 uint8_t count; /**< Number of elements in the queue. */ 00236 cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */ 00237 } cmd_queue_t; 00238 00239 static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */ 00240 static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */ 00241 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. */ 00242 static pstorage_state_t m_state; /**< Main state tracking variable. */ 00243 static flash_swap_sub_state_t m_swap_sub_state; /**< Flash swap erase when swap used state tracking variable. */ 00244 static uint32_t m_head_word_size; /**< Head restore area size in words. */ 00245 static uint32_t m_tail_word_size; /**< Tail restore area size in words. */ 00246 static uint32_t m_current_page_id; /**< Variable for tracking the flash page being processed. */ 00247 static uint32_t m_num_of_command_retries; /**< Variable for tracking flash operation retries upon flash operation failures. */ 00248 static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES]; /**< Registered application information table. */ 00249 static uint32_t m_num_of_bytes_written; /**< Variable for tracking the number of bytes written by the store operation. */ 00250 static uint32_t m_app_data_size; /**< Variable for storing the application command size parameter internally. */ 00251 static uint32_t m_flags = 0; /**< Storage for boolean flags for state tracking. */ 00252 00253 #ifdef PSTORAGE_RAW_MODE_ENABLE 00254 static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */ 00255 #endif // PSTORAGE_RAW_MODE_ENABLE 00256 00257 // Required forward declarations. 00258 static void cmd_process(void); 00259 static void store_operation_execute(void); 00260 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem); 00261 static void cmd_queue_element_init(uint32_t index); 00262 static void cmd_queue_dequeue(void); 00263 static void sm_state_change(pstorage_state_t new_state); 00264 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state); 00265 00266 /**@brief Function for consuming a command queue element. 00267 * 00268 * @details Function for consuming a command queue element, which has been fully processed. 00269 */ 00270 static void command_queue_element_consume(void) 00271 { 00272 // Initialize/free the element as it is now processed. 00273 cmd_queue_element_init(m_cmd_queue.rp); 00274 00275 // Adjust command queue state tracking variables. 00276 --(m_cmd_queue.count); 00277 if (++(m_cmd_queue.rp) == PSTORAGE_CMD_QUEUE_SIZE) 00278 { 00279 m_cmd_queue.rp = 0; 00280 } 00281 } 00282 00283 00284 /**@brief Function for executing the finalization procedure for the command executed. 00285 * 00286 * @details Function for executing the finalization procedure for command executed, which includes 00287 * notifying the application of command completion, consuming the command queue element, 00288 * and changing the internal state. 00289 */ 00290 static void command_end_procedure_run(void) 00291 { 00292 app_notify(NRF_SUCCESS, &m_cmd_queue.cmd[m_cmd_queue.rp]); 00293 00294 command_queue_element_consume(); 00295 00296 sm_state_change(STATE_IDLE); 00297 } 00298 00299 00300 /**@brief Function for idle state entry actions. 00301 * 00302 * @details Function for idle state entry actions, which include resetting relevant state data and 00303 * scheduling any possible queued flash access operation. 00304 */ 00305 static void state_idle_entry_run(void) 00306 { 00307 m_num_of_command_retries = 0; 00308 m_num_of_bytes_written = 0; 00309 00310 // Schedule any possible queued flash access operation. 00311 cmd_queue_dequeue(); 00312 } 00313 00314 00315 /**@brief Function for notifying an application of command completion and transitioning to an error 00316 * state. 00317 * 00318 * @param[in] result Result code of the operation for the application. 00319 */ 00320 static void app_notify_error_state_transit(uint32_t result) 00321 { 00322 app_notify(result, &m_cmd_queue.cmd[m_cmd_queue.rp]); 00323 sm_state_change(STATE_ERROR); 00324 } 00325 00326 00327 /**@brief Function for processing flash API error code. 00328 * 00329 * @param[in] err_code Error code from the flash API. 00330 */ 00331 static void flash_api_err_code_process(uint32_t err_code) 00332 { 00333 switch (err_code) 00334 { 00335 case NRF_SUCCESS: 00336 break; 00337 00338 case NRF_ERROR_BUSY: 00339 // Flash access operation was not accepted and must be reissued upon flash operation 00340 // complete event. 00341 m_flags |= MASK_FLASH_API_ERR_BUSY; 00342 break; 00343 00344 default: 00345 // Complete the operation with appropriate result code and transit to an error state. 00346 app_notify_error_state_transit(err_code); 00347 break; 00348 } 00349 } 00350 00351 /**@brief Function for writing data to flash. 00352 * 00353 * @param[in] p_dst Pointer to start of flash location to be written. 00354 * @param[in] p_src Pointer to buffer with data to be written. 00355 * @param[in] size_in_words Number of 32-bit words to write. 00356 */ 00357 static void flash_write(uint32_t * const p_dst, 00358 uint32_t const * const p_src, 00359 uint32_t size_in_words) 00360 { 00361 flash_api_err_code_process(sd_flash_write(p_dst, p_src, size_in_words)); 00362 } 00363 00364 00365 /**@brief Function for writing data to flash upon store command. 00366 * 00367 * @details Function for writing data to flash upon executing store command. Data is written to 00368 * flash in reverse order, meaning starting at the end. If the data that is to be written 00369 * is greater than the flash page size, it will be fragmented to fit the flash page size. 00370 */ 00371 static void store_cmd_flash_write_execute(void) 00372 { 00373 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00374 00375 if (p_cmd->size > SOC_MAX_WRITE_SIZE) 00376 { 00377 const uint32_t offset = p_cmd->size - PSTORAGE_FLASH_PAGE_SIZE; 00378 flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset + offset), 00379 (uint32_t *)(p_cmd->p_data_addr + offset), 00380 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t)); 00381 00382 m_num_of_bytes_written = PSTORAGE_FLASH_PAGE_SIZE; 00383 } 00384 else 00385 { 00386 flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset), 00387 (uint32_t *)(p_cmd->p_data_addr), 00388 p_cmd->size / sizeof(uint32_t)); 00389 00390 m_num_of_bytes_written = p_cmd->size; 00391 } 00392 } 00393 00394 00395 /**@brief Function for store state entry action. 00396 * 00397 * @details Function for store state entry action, which includes writing data to a flash page. 00398 */ 00399 static void state_store_entry_run(void) 00400 { 00401 store_cmd_flash_write_execute(); 00402 } 00403 00404 00405 /**@brief Function for data erase with swap state entry actions. 00406 * 00407 * @details Function for data erase with swap state entry actions. This includes adjusting relevant 00408 * state and data variables and transitioning to the correct sub state. 00409 */ 00410 static void state_data_erase_swap_entry_run(void) 00411 { 00412 m_flags &= ~MASK_TAIL_SWAP_DONE; 00413 00414 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00415 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id; 00416 00417 const uint32_t clear_start_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE; 00418 m_current_page_id = clear_start_page_id; 00419 00420 // @note: No need to include p_cmd->offset when calculating clear_end_page_id as: 00421 // - clear API does not include offset parameter 00422 // - update and store APIs are limited to operate on single block boundary thus the boolean 00423 // clause ((m_head_word_size == 0) && is_more_than_one_page) below in this function will never 00424 // evaluate as true as if is_more_than_one_page == true m_head_word_size is always != 0 00425 const uint32_t clear_end_page_id = (cmd_block_id + p_cmd->size - 1u) / 00426 PSTORAGE_FLASH_PAGE_SIZE; 00427 00428 if (clear_start_page_id == clear_end_page_id) 00429 { 00430 m_flags |= MASK_SINGLE_PAGE_OPERATION; 00431 } 00432 else 00433 { 00434 m_flags &= ~MASK_SINGLE_PAGE_OPERATION; 00435 } 00436 00437 if ((m_head_word_size == 0) && !(m_flags & MASK_SINGLE_PAGE_OPERATION)) 00438 { 00439 // No head restore required and clear/update area is shared by multiple flash pages, which 00440 // means the current flash page does not have any tail area to restore. You can proceed with 00441 // data page erase directly as no swap is needed for the current flash page. 00442 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE); 00443 } 00444 else 00445 { 00446 swap_sub_state_state_change(STATE_ERASE_SWAP); 00447 } 00448 } 00449 00450 00451 /**@brief Function for erasing flash page. 00452 * 00453 * @param[in] page_number Page number of the page to be erased. 00454 */ 00455 static void flash_page_erase(uint32_t page_number) 00456 { 00457 flash_api_err_code_process(sd_flash_page_erase(page_number)); 00458 } 00459 00460 00461 /**@brief Function for data erase state entry action. 00462 * 00463 * @details Function for data erase state entry action, which includes erasing the data flash page. 00464 */ 00465 static void state_data_erase_entry_run(void) 00466 { 00467 flash_page_erase(m_current_page_id); 00468 } 00469 00470 00471 /**@brief Function for dispatching the correct application main state entry action. 00472 */ 00473 static void state_entry_action_run(void) 00474 { 00475 switch (m_state) 00476 { 00477 case STATE_IDLE: 00478 state_idle_entry_run(); 00479 break; 00480 00481 case STATE_STORE: 00482 state_store_entry_run(); 00483 break; 00484 00485 case STATE_DATA_ERASE_WITH_SWAP: 00486 state_data_erase_swap_entry_run(); 00487 break; 00488 00489 case STATE_DATA_ERASE: 00490 state_data_erase_entry_run(); 00491 break; 00492 00493 default: 00494 // No action needed. 00495 break; 00496 } 00497 } 00498 00499 00500 /**@brief Function for changing application main state and dispatching state entry action. 00501 * 00502 * @param[in] new_state New application main state to transit to. 00503 */ 00504 static void sm_state_change(pstorage_state_t new_state) 00505 { 00506 m_state = new_state; 00507 state_entry_action_run(); 00508 } 00509 00510 00511 /**@brief Function for swap erase state entry action. 00512 * 00513 * @details Function for swap erase state entry action, which includes erasing swap flash 00514 * page. 00515 */ 00516 static void state_swap_erase_entry_run(void) 00517 { 00518 flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE); 00519 } 00520 00521 00522 /**@brief Function for write data to the swap state entry action. 00523 * 00524 * @details Function for write data to the swap state entry action, which includes writing the 00525 * current data page to the swap flash page. 00526 */ 00527 static void state_write_data_swap_entry_run(void) 00528 { 00529 // @note: There is room for further optimization here as there is only need to write the 00530 // whole flash page to swap area if there is both head and tail area to be restored. In any 00531 // other case we can omit some data from the head or end of the page as that is the clear area. 00532 flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR), 00533 (uint32_t *)(m_current_page_id * PSTORAGE_FLASH_PAGE_SIZE), 00534 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t)); 00535 } 00536 00537 00538 /**@brief Function for erase data page state entry action. 00539 * 00540 * @details Function for erase data page state entry action, which includes erasing the data flash 00541 * page. 00542 */ 00543 static void state_erase_data_page_entry_run(void) 00544 { 00545 flash_page_erase(m_current_page_id); 00546 } 00547 00548 00549 /**@brief Function for restore tail state entry action. 00550 * 00551 * @details Function for restore tail state entry action, which includes writing the tail section 00552 * back from swap to the data page. 00553 */ 00554 static void state_restore_tail_entry_run(void) 00555 { 00556 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00557 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id; 00558 00559 const uint32_t tail_offset = (cmd_block_id + p_cmd->size + p_cmd->offset) % 00560 PSTORAGE_FLASH_PAGE_SIZE; 00561 00562 flash_write((uint32_t *)(cmd_block_id + p_cmd->size + p_cmd->offset), 00563 (uint32_t *)(PSTORAGE_SWAP_ADDR + tail_offset), 00564 m_tail_word_size); 00565 } 00566 00567 00568 /**@brief Function for restore head state entry action. 00569 * 00570 * @details Function for restore head state entry action, which includes writing the head section 00571 * back from swap to the data page. 00572 */ 00573 static void state_restore_head_entry_run(void) 00574 { 00575 flash_write((uint32_t *)((m_current_page_id - 1u) * PSTORAGE_FLASH_PAGE_SIZE), 00576 (uint32_t *)PSTORAGE_SWAP_ADDR, 00577 m_head_word_size); 00578 } 00579 00580 00581 /**@brief Function for dispatching the correct swap sub state entry action. 00582 */ 00583 static void swap_sub_state_entry_action_run(void) 00584 { 00585 static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) = 00586 { 00587 state_swap_erase_entry_run, 00588 state_write_data_swap_entry_run, 00589 state_erase_data_page_entry_run, 00590 state_restore_tail_entry_run, 00591 state_restore_head_entry_run 00592 }; 00593 00594 swap_sub_state_sm_lut[m_swap_sub_state](); 00595 } 00596 00597 00598 /**@brief Function for changing the swap sub state and dispatching state entry action. 00599 * 00600 * @param[in] new_state New swap sub state to transit to. 00601 */ 00602 static void swap_sub_state_state_change(flash_swap_sub_state_t new_state) 00603 { 00604 m_swap_sub_state = new_state; 00605 swap_sub_state_entry_action_run(); 00606 } 00607 00608 00609 /**@brief Function for initializing the command queue element. 00610 * 00611 * @param[in] index Index of the element to be initialized. 00612 */ 00613 static void cmd_queue_element_init(uint32_t index) 00614 { 00615 // Internal function and checks on range of index can be avoided. 00616 m_cmd_queue.cmd[index].op_code = INVALID_OPCODE; 00617 m_cmd_queue.cmd[index].size = 0; 00618 m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_NUM_OF_PAGES; 00619 m_cmd_queue.cmd[index].storage_addr.block_id = 0; 00620 m_cmd_queue.cmd[index].p_data_addr = NULL; 00621 m_cmd_queue.cmd[index].offset = 0; 00622 } 00623 00624 00625 /**@brief Function for initializing the command queue. 00626 */ 00627 static void cmd_queue_init(void) 00628 { 00629 m_cmd_queue.rp = 0; 00630 m_cmd_queue.count = 0; 00631 00632 for (uint32_t cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; ++cmd_index) 00633 { 00634 cmd_queue_element_init(cmd_index); 00635 } 00636 } 00637 00638 00639 /**@brief Function for enqueuing, and possibly dispatching, a flash access operation. 00640 * 00641 * @param[in] opcode Identifies the operation requested to be enqueued. 00642 * @param[in] p_storage_addr Identifies the module and flash address on which the operation is 00643 * requested. 00644 * @param[in] p_data_addr Identifies the data address for flash access. 00645 * @param[in] size Size in bytes of data requested for the access operation. 00646 * @param[in] offset Offset within the flash memory block at which operation is requested. 00647 * 00648 * @retval NRF_SUCCESS Upon success. 00649 * @retval NRF_ERROR_NO_MEM Upon failure, when no space is available in the command queue. 00650 */ 00651 static uint32_t cmd_queue_enqueue(uint8_t opcode, 00652 pstorage_handle_t * p_storage_addr, 00653 uint8_t * p_data_addr, 00654 pstorage_size_t size, 00655 pstorage_size_t offset) 00656 { 00657 uint32_t err_code; 00658 00659 if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE) 00660 { 00661 // Enqueue the command if it the queue is not full. 00662 uint32_t write_index = m_cmd_queue.rp + m_cmd_queue.count; 00663 00664 if (write_index >= PSTORAGE_CMD_QUEUE_SIZE) 00665 { 00666 write_index -= PSTORAGE_CMD_QUEUE_SIZE; 00667 } 00668 00669 m_cmd_queue.cmd[write_index].op_code = opcode; 00670 m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr; 00671 m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr); 00672 m_cmd_queue.cmd[write_index].size = size; 00673 m_cmd_queue.cmd[write_index].offset = offset; 00674 00675 m_cmd_queue.count++; 00676 00677 if (m_state == STATE_IDLE) 00678 { 00679 cmd_process(); 00680 } 00681 00682 err_code = NRF_SUCCESS; 00683 } 00684 else 00685 { 00686 err_code = NRF_ERROR_NO_MEM; 00687 } 00688 00689 return err_code; 00690 } 00691 00692 00693 /**@brief Function for dequeing a possible pending flash access operation. 00694 */ 00695 static void cmd_queue_dequeue(void) 00696 { 00697 if ((m_cmd_queue.count != 0)) 00698 { 00699 cmd_process(); 00700 } 00701 } 00702 00703 00704 /**@brief Function for notifying an application of command completion. 00705 * 00706 * @param[in] result Result code of the operation for the application. 00707 * @param[in] p_elem Pointer to the command queue element for which this result was received. 00708 */ 00709 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem) 00710 { 00711 pstorage_ntf_cb_t ntf_cb; 00712 const uint8_t op_code = p_elem->op_code; 00713 00714 #ifdef PSTORAGE_RAW_MODE_ENABLE 00715 if (p_elem->storage_addr.module_id == RAW_MODE_APP_ID) 00716 { 00717 ntf_cb = m_raw_app_table.cb; 00718 } 00719 else 00720 #endif // PSTORAGE_RAW_MODE_ENABLE 00721 { 00722 ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb; 00723 } 00724 00725 ntf_cb(&p_elem->storage_addr, op_code, result, p_elem->p_data_addr, m_app_data_size); 00726 } 00727 00728 00729 /**@brief Function for evaluating if a data page swap is required for the tail section on the 00730 * current page. 00731 * 00732 * @retval true If data page swap is required. 00733 * @retval false If data page swap is not required. 00734 */ 00735 static bool is_tail_data_page_swap_required(void) 00736 { 00737 bool ret_value; 00738 00739 // Extract id of the last page command is executed upon. 00740 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00741 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id; 00742 const uint32_t last_page_id = (cmd_block_id + p_cmd->size + p_cmd->offset - 1u) / 00743 PSTORAGE_FLASH_PAGE_SIZE; 00744 00745 // If tail section area exists and the current page is the last page then tail data page swap is 00746 // required. 00747 if ((m_tail_word_size != 0) && (m_current_page_id == last_page_id)) 00748 { 00749 ret_value = true; 00750 } 00751 else 00752 { 00753 ret_value = false; 00754 } 00755 00756 return ret_value; 00757 } 00758 00759 00760 /**@brief Function for performing post processing for the update and clear commands. 00761 * 00762 * @details Function for performing post processing for the update and clear commands, which implies 00763 * executing the correct execution path depending on the command. 00764 */ 00765 static void clear_post_processing_run(void) 00766 { 00767 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00768 00769 if (p_cmd->op_code != PSTORAGE_UPDATE_OP_CODE) 00770 { 00771 command_end_procedure_run(); 00772 } 00773 else 00774 { 00775 store_operation_execute(); 00776 } 00777 } 00778 00779 00780 /**@brief Function for doing swap sub state exit action. 00781 */ 00782 static void swap_sub_sm_exit_action_run(void) 00783 { 00784 clear_post_processing_run(); 00785 } 00786 00787 00788 /**@brief Function for evaluating if the page erase operation is required for the current page. 00789 * 00790 * @retval true If page erase is required. 00791 * @retval false If page erase is not required. 00792 */ 00793 static bool is_page_erase_required(void) 00794 { 00795 bool ret; 00796 00797 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00798 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id; 00799 const uint32_t id_last_page_to_be_cleared = (cmd_block_id + p_cmd->size + 00800 p_cmd->offset - 1u) / 00801 PSTORAGE_FLASH_PAGE_SIZE; 00802 00803 // True if: 00804 // - current page is not the last page OR 00805 // - current page is the last page AND no tail exists 00806 if ((m_current_page_id < id_last_page_to_be_cleared) || 00807 ((m_current_page_id == id_last_page_to_be_cleared) && (m_tail_word_size == 0))) 00808 { 00809 ret = true; 00810 } 00811 else 00812 { 00813 ret = false; 00814 } 00815 00816 return ret; 00817 } 00818 00819 00820 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash 00821 * API, in swap sub sate. 00822 */ 00823 static void swap_sub_state_err_busy_process(void) 00824 { 00825 // Reissue the request by doing a self transition to the current state. 00826 m_flags &= ~MASK_FLASH_API_ERR_BUSY; 00827 swap_sub_state_state_change(m_swap_sub_state); 00828 } 00829 00830 00831 /**@brief Function for doing restore head state action upon flash operation success event. 00832 * 00833 * @details Function for doing restore head state action upon flash operation success event, which 00834 * includes making a state transition depending on the current state. 00835 */ 00836 static void head_restore_state_run(void) 00837 { 00838 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 00839 { 00840 if (is_tail_data_page_swap_required()) 00841 { 00842 // Additional data page needs to be swapped for tail section as we are clearing a block, 00843 // which is shared between 2 flash pages. 00844 00845 // Adjust variables to ensure correct state transition path is taken after the tail 00846 // section swap has completed. 00847 m_head_word_size = 0; 00848 m_flags |= MASK_TAIL_SWAP_DONE; 00849 00850 swap_sub_state_state_change(STATE_ERASE_SWAP); 00851 } 00852 else if (is_page_erase_required()) 00853 { 00854 // Additional page erase operation is required. 00855 00856 // Adjust variable to ensure correct state transition path is taken after the additional 00857 // page erase operation has completed. 00858 m_head_word_size = 0; 00859 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE); 00860 } 00861 else if (m_tail_word_size != 0) 00862 { 00863 // Proceed with restoring tail from swap to data page. 00864 swap_sub_state_state_change(STATE_RESTORE_TAIL); 00865 } 00866 else 00867 { 00868 // Swap statemachine execution end reached. 00869 swap_sub_sm_exit_action_run(); 00870 } 00871 } 00872 else 00873 { 00874 // As operation request was rejected by the flash API reissue the request. 00875 swap_sub_state_err_busy_process(); 00876 } 00877 } 00878 00879 00880 /**@brief Function for doing restore tail state action upon flash operation success event. 00881 */ 00882 static void tail_restore_state_run(void) 00883 { 00884 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 00885 { 00886 swap_sub_sm_exit_action_run(); 00887 } 00888 else 00889 { 00890 // As operation request was rejected by the flash API reissue the request. 00891 swap_sub_state_err_busy_process(); 00892 } 00893 } 00894 00895 00896 /**@brief Function for doing data page erase state action upon a flash operation success event. 00897 * 00898 * @details Function for doing data page erase state action upon a flash operation success event, 00899 * which includes making a state transit to a new state depending on the current state. 00900 */ 00901 static void data_page_erase_state_run(void) 00902 { 00903 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 00904 { 00905 ++m_current_page_id; 00906 00907 if (m_head_word_size != 0) 00908 { 00909 swap_sub_state_state_change(STATE_RESTORE_HEAD); 00910 } 00911 else if (is_page_erase_required()) 00912 { 00913 // Additional page erase operation is required. 00914 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE); 00915 } 00916 else if (m_tail_word_size != 0) 00917 { 00918 if (!(m_flags & MASK_TAIL_SWAP_DONE)) 00919 { 00920 // Tail area restore is required and we have not yet written the relevant data page 00921 // to swap area. Start the process of writing the data page to swap. 00922 m_flags |= MASK_TAIL_SWAP_DONE; 00923 00924 swap_sub_state_state_change(STATE_ERASE_SWAP); 00925 } 00926 else 00927 { 00928 // Tail area restore is required and we have already written the relevant data page 00929 // to swap area. Proceed by restoring the tail area. 00930 swap_sub_state_state_change(STATE_RESTORE_TAIL); 00931 } 00932 } 00933 else 00934 { 00935 swap_sub_sm_exit_action_run(); 00936 } 00937 } 00938 else 00939 { 00940 // As operation request was rejected by the flash API reissue the request. 00941 swap_sub_state_err_busy_process(); 00942 } 00943 } 00944 00945 00946 /**@brief Function for doing data to swap write state action upon flash operation success event. 00947 */ 00948 static void data_to_swap_write_state_run(void) 00949 { 00950 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 00951 { 00952 // If the operation is executed only on 1 single flash page it automatically means that tail 00953 // area is written to the swap, which we store to flags. 00954 if (m_flags & MASK_SINGLE_PAGE_OPERATION) 00955 { 00956 m_flags |= MASK_TAIL_SWAP_DONE; 00957 } 00958 00959 swap_sub_state_state_change(STATE_ERASE_DATA_PAGE); 00960 } 00961 else 00962 { 00963 // As operation request was rejected by the flash API reissue the request. 00964 swap_sub_state_err_busy_process(); 00965 } 00966 } 00967 00968 00969 /**@brief Function for doing swap erase state action upon flash operation success event. 00970 */ 00971 static void swap_erase_state_run(void) 00972 { 00973 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 00974 { 00975 swap_sub_state_state_change(STATE_WRITE_DATA_TO_SWAP); 00976 } 00977 else 00978 { 00979 // As operation request was rejected by the flash API reissue the request. 00980 swap_sub_state_err_busy_process(); 00981 } 00982 } 00983 00984 00985 /**@brief Function for dispatching the correct state action for data erase with a swap composite 00986 * state upon a flash operation success event. 00987 */ 00988 static void swap_sub_state_sm_run(void) 00989 { 00990 static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) = 00991 { 00992 swap_erase_state_run, 00993 data_to_swap_write_state_run, 00994 data_page_erase_state_run, 00995 tail_restore_state_run, 00996 head_restore_state_run 00997 }; 00998 00999 swap_sub_state_sm_lut[m_swap_sub_state](); 01000 } 01001 01002 01003 /**@brief Function for reissuing the last flash operation request, which was rejected by the flash 01004 * API, in main sate. 01005 */ 01006 static void main_state_err_busy_process(void) 01007 { 01008 // Reissue the request by doing a self transition to the current state. 01009 m_flags &= ~MASK_FLASH_API_ERR_BUSY; 01010 sm_state_change(m_state); 01011 } 01012 01013 01014 /**@brief Function for doing erase state action upon flash operation success event. 01015 * 01016 * @details Function for doing erase state action upon flash operation success event, which includes 01017 * making a state transition depending on the current state. 01018 */ 01019 static void erase_sub_state_sm_run(void) 01020 { 01021 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 01022 { 01023 // Clear operation request has succeeded. 01024 ++m_current_page_id; 01025 01026 if (!is_page_erase_required()) 01027 { 01028 clear_post_processing_run(); 01029 } 01030 else 01031 { 01032 // All required flash pages have not yet been erased, issue erase by doing a self 01033 // transit. 01034 sm_state_change(m_state); 01035 } 01036 } 01037 else 01038 { 01039 // As operation request was rejected by the flash API reissue the request. 01040 main_state_err_busy_process(); 01041 } 01042 } 01043 01044 01045 /**@brief Function for doing store state action upon flash operation success event. 01046 */ 01047 static void store_sub_state_sm_run(void) 01048 { 01049 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 01050 { 01051 // As write operation request has succeeded, adjust the size tracking state information 01052 // accordingly. 01053 cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 01054 p_cmd->size -= m_num_of_bytes_written; 01055 01056 if (p_cmd->size == 0) 01057 { 01058 command_end_procedure_run(); 01059 } 01060 else 01061 { 01062 store_cmd_flash_write_execute(); 01063 } 01064 } 01065 else 01066 { 01067 // As operation request was rejected by the flash API reissue the request. 01068 main_state_err_busy_process(); 01069 } 01070 } 01071 01072 01073 /**@brief Function for doing action upon flash operation success event. 01074 */ 01075 static void flash_operation_success_run(void) 01076 { 01077 switch (m_state) 01078 { 01079 case STATE_STORE: 01080 store_sub_state_sm_run(); 01081 break; 01082 01083 case STATE_DATA_ERASE: 01084 erase_sub_state_sm_run(); 01085 break; 01086 01087 case STATE_DATA_ERASE_WITH_SWAP: 01088 swap_sub_state_sm_run(); 01089 break; 01090 01091 default: 01092 // No implementation needed. 01093 break; 01094 } 01095 } 01096 01097 01098 /**@brief Function for doing action upon flash operation failure event. 01099 * 01100 * @details Function for doing action upon flash operation failure event, which includes retrying 01101 * the last operation or if retry count has been reached completing the operation with 01102 * appropriate result code and transitioning to an error state. 01103 * 01104 * @note The command is not removed from the command queue, which will result to stalling of the 01105 * command pipeline and the appropriate application recovery procedure for this is to reset 01106 * the system by issuing @ref pstorage_init which will also result to flushing of the 01107 * command queue. 01108 */ 01109 static void flash_operation_failure_run(void) 01110 { 01111 if (++m_num_of_command_retries != SD_CMD_MAX_TRIES) 01112 { 01113 // Retry the last operation by doing a self transition to the current state. 01114 01115 if (m_state != STATE_DATA_ERASE_WITH_SWAP) 01116 { 01117 sm_state_change(m_state); 01118 } 01119 else 01120 { 01121 swap_sub_state_state_change(m_swap_sub_state); 01122 } 01123 } 01124 else 01125 { 01126 // Complete the operation with appropriate result code and transit to an error state. 01127 app_notify_error_state_transit(NRF_ERROR_TIMEOUT); 01128 } 01129 } 01130 01131 01132 /**@brief Function for handling flash access result events. 01133 * 01134 * @param[in] sys_evt System event to be handled. 01135 */ 01136 void pstorage_sys_event_handler(uint32_t sys_evt) 01137 { 01138 if (m_state != STATE_IDLE && m_state != STATE_ERROR) 01139 { 01140 switch (sys_evt) 01141 { 01142 case NRF_EVT_FLASH_OPERATION_SUCCESS: 01143 flash_operation_success_run(); 01144 break; 01145 01146 case NRF_EVT_FLASH_OPERATION_ERROR: 01147 if (!(m_flags & MASK_FLASH_API_ERR_BUSY)) 01148 { 01149 flash_operation_failure_run(); 01150 } 01151 else 01152 { 01153 // As our last flash operation request was rejected by the flash API reissue the 01154 // request by doing same code execution path as for flash operation sucess 01155 // event. This will promote code reuse in the implementation. 01156 flash_operation_success_run(); 01157 } 01158 break; 01159 01160 default: 01161 // No implementation needed. 01162 break; 01163 } 01164 01165 } 01166 } 01167 01168 01169 /**@brief Function for calculating the tail area size in number of 32-bit words. 01170 * 01171 * @param[in] cmd_end_of_storage_address End of storage area within the scope of the command. 01172 * @param[in] end_of_storage_address End of allocated storage area for the application. 01173 */ 01174 static void tail_word_size_calculate(pstorage_size_t cmd_end_of_storage_address, 01175 pstorage_size_t end_of_storage_address) 01176 { 01177 // Two different cases to resolve when calculating correct size for restore tail section: 01178 // 1) End of storage area and command end area are in the same page. 01179 // 2) End of storage area and command end area are not in the same page. 01180 01181 const uint32_t end_of_storage_area_page = end_of_storage_address / 01182 PSTORAGE_FLASH_PAGE_SIZE; 01183 const uint32_t command_end_of_storage_area_page = cmd_end_of_storage_address / 01184 PSTORAGE_FLASH_PAGE_SIZE; 01185 01186 if (end_of_storage_area_page == command_end_of_storage_area_page) 01187 { 01188 //lint -e{573} suppress "Signed-unsigned mix with divide". 01189 m_tail_word_size = (end_of_storage_address - cmd_end_of_storage_address) / sizeof(uint32_t); 01190 } 01191 else 01192 { 01193 //lint -e{573} suppress "Signed-unsigned mix with divide". 01194 m_tail_word_size = (PSTORAGE_FLASH_PAGE_SIZE - 01195 (cmd_end_of_storage_address % PSTORAGE_FLASH_PAGE_SIZE)) / 01196 sizeof(uint32_t); 01197 } 01198 } 01199 01200 01201 /**@brief Function for executing the clear operation. 01202 */ 01203 static void clear_operation_execute(void) 01204 { 01205 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 01206 const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id; 01207 01208 const pstorage_size_t block_size = m_app_table[p_cmd->storage_addr.module_id].block_size; 01209 const pstorage_size_t block_count = m_app_table[p_cmd->storage_addr.module_id].block_count; 01210 const pstorage_block_t block_base_id = m_app_table[p_cmd->storage_addr.module_id].base_id; 01211 01212 const bool is_start_address_page_aligned = (cmd_block_id % PSTORAGE_FLASH_PAGE_SIZE) == 0; 01213 01214 // Calculate the end (1 beyond allocated area) for complete storage area and to the area only 01215 // within scope of this command. 01216 const pstorage_block_t end_of_storage_address = block_base_id + (block_size * block_count); 01217 const pstorage_block_t cmd_end_of_storage_address = cmd_block_id + p_cmd->size + p_cmd->offset; 01218 01219 // Zero tail to make sure no extra erase is done erroneously. 01220 m_tail_word_size = 0; 01221 01222 // If the following is true no swap access is needed: 01223 // - 1st logical test covers the case of: clear/update 1 complete single page. 01224 // - 2nd logical test covers the case of: 01225 // 1) Clear/update last allocated page and page is not full (page can't be shared between 01226 // multiple clients so the end of the page is unused area). 01227 // 2) Clear/update all allocated storage. 01228 if ((is_start_address_page_aligned && (p_cmd->size == PSTORAGE_FLASH_PAGE_SIZE)) || 01229 (is_start_address_page_aligned && (cmd_end_of_storage_address == end_of_storage_address) && 01230 (p_cmd->offset == 0)) || (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID)) 01231 { 01232 // Nothing to put to the swap and we can just erase the pages(s). 01233 01234 m_current_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE; 01235 01236 sm_state_change(STATE_DATA_ERASE); 01237 } 01238 else 01239 { 01240 // Not all the blocks for the module can be cleared, we need to use swap page for storing 01241 // data temporarily. 01242 01243 m_head_word_size = ((cmd_block_id + p_cmd->offset) % PSTORAGE_FLASH_PAGE_SIZE) / 01244 sizeof(uint32_t); 01245 01246 const bool is_cmd_end_address_page_aligned = ((cmd_end_of_storage_address % 01247 PSTORAGE_FLASH_PAGE_SIZE) == 0); 01248 if ((cmd_end_of_storage_address != end_of_storage_address) && 01249 !is_cmd_end_address_page_aligned) 01250 { 01251 // When command area is not equal to end of the storage allocation area and not ending 01252 // to page boundary there is a need to restore the tail area. 01253 tail_word_size_calculate(cmd_end_of_storage_address, end_of_storage_address); 01254 } 01255 01256 sm_state_change(STATE_DATA_ERASE_WITH_SWAP); 01257 } 01258 } 01259 01260 01261 /**@brief Function for executing the store operation. 01262 */ 01263 static void store_operation_execute(void) 01264 { 01265 sm_state_change(STATE_STORE); 01266 } 01267 01268 01269 /**@brief Function for executing the update operation. 01270 */ 01271 static void update_operation_execute(void) 01272 { 01273 clear_operation_execute(); 01274 } 01275 01276 01277 /**@brief Function for dispatching the flash access operation. 01278 */ 01279 static void cmd_process(void) 01280 { 01281 const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 01282 m_app_data_size = p_cmd->size; 01283 01284 switch (p_cmd->op_code) 01285 { 01286 case PSTORAGE_STORE_OP_CODE: 01287 store_operation_execute(); 01288 break; 01289 01290 case PSTORAGE_CLEAR_OP_CODE: 01291 clear_operation_execute(); 01292 break; 01293 01294 case PSTORAGE_UPDATE_OP_CODE: 01295 update_operation_execute(); 01296 break; 01297 01298 default: 01299 // No action required. 01300 break; 01301 } 01302 } 01303 01304 01305 uint32_t pstorage_init(void) 01306 { 01307 cmd_queue_init(); 01308 01309 m_next_app_instance = 0; 01310 m_next_page_addr = PSTORAGE_DATA_START_ADDR; 01311 m_current_page_id = 0; 01312 01313 for (uint32_t index = 0; index < PSTORAGE_NUM_OF_PAGES; index++) 01314 { 01315 m_app_table[index].cb = NULL; 01316 m_app_table[index].block_size = 0; 01317 m_app_table[index].block_count = 0; 01318 } 01319 01320 #ifdef PSTORAGE_RAW_MODE_ENABLE 01321 m_raw_app_table.cb = NULL; 01322 #endif //PSTORAGE_RAW_MODE_ENABLE 01323 01324 m_state = STATE_IDLE; 01325 m_num_of_command_retries = 0; 01326 m_flags = 0; 01327 m_num_of_bytes_written = 0; 01328 m_flags |= MASK_MODULE_INITIALIZED; 01329 01330 return NRF_SUCCESS; 01331 } 01332 01333 01334 uint32_t pstorage_register(pstorage_module_param_t * p_module_param, 01335 pstorage_handle_t * p_block_id) 01336 { 01337 VERIFY_MODULE_INITIALIZED(); 01338 NULL_PARAM_CHECK(p_module_param); 01339 NULL_PARAM_CHECK(p_block_id); 01340 NULL_PARAM_CHECK(p_module_param->cb); 01341 BLOCK_SIZE_CHECK(p_module_param->block_size); 01342 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size); 01343 01344 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0)) 01345 { 01346 return NRF_ERROR_INVALID_PARAM; 01347 } 01348 01349 if (m_next_app_instance == PSTORAGE_NUM_OF_PAGES) 01350 { 01351 return NRF_ERROR_NO_MEM; 01352 } 01353 01354 p_block_id->module_id = m_next_app_instance; 01355 p_block_id->block_id = m_next_page_addr; 01356 01357 m_app_table[m_next_app_instance].base_id = p_block_id->block_id; 01358 m_app_table[m_next_app_instance].cb = p_module_param->cb; 01359 m_app_table[m_next_app_instance].block_size = p_module_param->block_size; 01360 m_app_table[m_next_app_instance].block_count = p_module_param->block_count; 01361 01362 // Calculate number of flash pages allocated for the device and adjust next free page address. 01363 /*lint -save -e666 */ 01364 const uint32_t page_count = CEIL_DIV((p_module_param->block_size * p_module_param->block_count), 01365 PSTORAGE_FLASH_PAGE_SIZE); 01366 /*lint -restore */ 01367 m_next_page_addr += page_count * PSTORAGE_FLASH_PAGE_SIZE; 01368 01369 ++m_next_app_instance; 01370 01371 return NRF_SUCCESS; 01372 } 01373 01374 01375 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id, 01376 pstorage_size_t block_num, 01377 pstorage_handle_t * p_block_id) 01378 { 01379 pstorage_handle_t temp_id; 01380 01381 VERIFY_MODULE_INITIALIZED(); 01382 NULL_PARAM_CHECK(p_base_id); 01383 NULL_PARAM_CHECK(p_block_id); 01384 MODULE_ID_RANGE_CHECK(p_base_id); 01385 01386 temp_id = (*p_base_id); 01387 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id)); 01388 01389 BLOCK_ID_RANGE_CHECK(&temp_id); 01390 01391 (*p_block_id) = temp_id; 01392 01393 return NRF_SUCCESS; 01394 } 01395 01396 01397 uint32_t pstorage_store(pstorage_handle_t * p_dest, 01398 uint8_t * p_src, 01399 pstorage_size_t size, 01400 pstorage_size_t offset) 01401 { 01402 VERIFY_MODULE_INITIALIZED(); 01403 NULL_PARAM_CHECK(p_src); 01404 NULL_PARAM_CHECK(p_dest); 01405 MODULE_ID_RANGE_CHECK(p_dest); 01406 BLOCK_ID_RANGE_CHECK(p_dest); 01407 SIZE_CHECK(p_dest, size); 01408 OFFSET_CHECK(p_dest, offset, size); 01409 01410 if ((!is_word_aligned(p_src)) || 01411 (!is_word_aligned((void *)(uint32_t)offset)) || 01412 (!is_word_aligned((uint32_t *)p_dest->block_id))) 01413 { 01414 return NRF_ERROR_INVALID_ADDR; 01415 } 01416 01417 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 01418 } 01419 01420 01421 uint32_t pstorage_update(pstorage_handle_t * p_dest, 01422 uint8_t * p_src, 01423 pstorage_size_t size, 01424 pstorage_size_t offset) 01425 { 01426 VERIFY_MODULE_INITIALIZED(); 01427 NULL_PARAM_CHECK(p_src); 01428 NULL_PARAM_CHECK(p_dest); 01429 MODULE_ID_RANGE_CHECK(p_dest); 01430 BLOCK_ID_RANGE_CHECK(p_dest); 01431 SIZE_CHECK(p_dest, size); 01432 OFFSET_CHECK(p_dest, offset, size); 01433 01434 if ((!is_word_aligned(p_src)) || 01435 (!is_word_aligned((void *)(uint32_t)offset)) || 01436 (!is_word_aligned((uint32_t *)p_dest->block_id))) 01437 { 01438 return NRF_ERROR_INVALID_ADDR; 01439 } 01440 01441 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset); 01442 } 01443 01444 01445 uint32_t pstorage_load(uint8_t * p_dest, 01446 pstorage_handle_t * p_src, 01447 pstorage_size_t size, 01448 pstorage_size_t offset) 01449 { 01450 VERIFY_MODULE_INITIALIZED(); 01451 NULL_PARAM_CHECK(p_src); 01452 NULL_PARAM_CHECK(p_dest); 01453 MODULE_ID_RANGE_CHECK(p_src); 01454 BLOCK_ID_RANGE_CHECK(p_src); 01455 SIZE_CHECK(p_src, size); 01456 OFFSET_CHECK(p_src, offset, size); 01457 01458 if ((!is_word_aligned(p_dest)) || 01459 (!is_word_aligned((void *)(uint32_t)offset)) || 01460 (!is_word_aligned((uint32_t *)p_src->block_id))) 01461 { 01462 return NRF_ERROR_INVALID_ADDR; 01463 } 01464 01465 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size); 01466 01467 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size); 01468 01469 return NRF_SUCCESS; 01470 } 01471 01472 01473 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01474 { 01475 VERIFY_MODULE_INITIALIZED(); 01476 NULL_PARAM_CHECK(p_dest); 01477 MODULE_ID_RANGE_CHECK(p_dest); 01478 BLOCK_ID_RANGE_CHECK(p_dest); 01479 01480 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01481 { 01482 return NRF_ERROR_INVALID_ADDR; 01483 } 01484 01485 // Check is the area starting from block_id multiple of block_size. 01486 if ( 01487 !( 01488 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) % 01489 m_app_table[p_dest->module_id].block_size) == 0 01490 ) 01491 ) 01492 { 01493 return NRF_ERROR_INVALID_PARAM; 01494 } 01495 01496 // Check is requested size multiple of registered block size or 0. 01497 if (((size % m_app_table[p_dest->module_id].block_size) != 0) || (size == 0)) 01498 { 01499 return NRF_ERROR_INVALID_PARAM; 01500 } 01501 01502 const uint32_t registered_allocation_size = m_app_table[p_dest->module_id].block_size * 01503 m_app_table[p_dest->module_id].block_count; 01504 01505 const pstorage_block_t clear_request_end_address = p_dest->block_id + size; 01506 const pstorage_block_t allocation_end_address = m_app_table[p_dest->module_id].base_id + 01507 registered_allocation_size; 01508 // Check if request would lead to a buffer overrun. 01509 if (clear_request_end_address > allocation_end_address) 01510 { 01511 return NRF_ERROR_INVALID_PARAM; 01512 } 01513 01514 return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01515 } 01516 01517 01518 uint32_t pstorage_access_status_get(uint32_t * p_count) 01519 { 01520 VERIFY_MODULE_INITIALIZED(); 01521 NULL_PARAM_CHECK(p_count); 01522 01523 (*p_count) = m_cmd_queue.count; 01524 01525 return NRF_SUCCESS; 01526 } 01527 01528 #ifdef PSTORAGE_RAW_MODE_ENABLE 01529 01530 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param, 01531 pstorage_handle_t * p_block_id) 01532 { 01533 VERIFY_MODULE_INITIALIZED(); 01534 NULL_PARAM_CHECK(p_module_param); 01535 NULL_PARAM_CHECK(p_block_id); 01536 NULL_PARAM_CHECK(p_module_param->cb); 01537 01538 if (m_raw_app_table.cb != NULL) 01539 { 01540 return NRF_ERROR_NO_MEM; 01541 } 01542 01543 p_block_id->module_id = RAW_MODE_APP_ID; 01544 m_raw_app_table.cb = p_module_param->cb; 01545 01546 return NRF_SUCCESS; 01547 } 01548 01549 01550 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest, 01551 uint8_t * p_src, 01552 pstorage_size_t size, 01553 pstorage_size_t offset) 01554 { 01555 VERIFY_MODULE_INITIALIZED(); 01556 NULL_PARAM_CHECK(p_src); 01557 NULL_PARAM_CHECK(p_dest); 01558 MODULE_RAW_HANDLE_CHECK(p_dest); 01559 01560 if (size == 0) 01561 { 01562 return NRF_ERROR_INVALID_PARAM; 01563 } 01564 01565 // Verify word alignment. 01566 if ((!is_word_aligned(p_src)) || 01567 (!is_word_aligned((void *)(uint32_t)size)) || 01568 (!is_word_aligned((void *)(uint32_t)offset)) || 01569 (!is_word_aligned((void *)(p_dest->block_id)))) 01570 { 01571 return NRF_ERROR_INVALID_ADDR; 01572 } 01573 01574 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 01575 } 01576 01577 01578 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01579 { 01580 VERIFY_MODULE_INITIALIZED(); 01581 NULL_PARAM_CHECK(p_dest); 01582 MODULE_RAW_HANDLE_CHECK(p_dest); 01583 01584 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01585 { 01586 return NRF_ERROR_INVALID_ADDR; 01587 } 01588 01589 return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01590 } 01591 01592 #endif // PSTORAGE_RAW_MODE_ENABLE
Generated on Tue Jul 12 2022 14:11:20 by
