test
Fork of nrf51-sdk by
Embed:
(wiki syntax)
Show/hide line numbers
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 15:51:29 by 1.7.2