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 LinkNode-Test 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 00044 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */ 00045 #define SOC_MAX_WRITE_SIZE 1024 /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */ 00046 #define RAW_MODE_APP_ID (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */ 00047 #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. */ 00048 00049 /** 00050 * @defgroup api_param_check API Parameters check macros. 00051 * 00052 * @details Macros that verify parameters passed to the module in the APIs. These macros 00053 * could be mapped to nothing in final versions of code to save execution and size. 00054 * 00055 * @{ 00056 */ 00057 00058 /** 00059 * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL. 00060 */ 00061 #define NULL_PARAM_CHECK(PARAM) \ 00062 if ((PARAM) == NULL) \ 00063 { \ 00064 return NRF_ERROR_NULL; \ 00065 } 00066 00067 /** 00068 * @brief Verifies the module identifier supplied by the application is within permissible 00069 * range. 00070 */ 00071 #define MODULE_ID_RANGE_CHECK(ID) \ 00072 if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) || \ 00073 (m_app_table[(ID)->module_id].cb == NULL)) \ 00074 { \ 00075 return NRF_ERROR_INVALID_PARAM; \ 00076 } 00077 00078 /** 00079 * @brief Verifies the block identifier supplied by the application is within the permissible 00080 * range. 00081 */ 00082 #define BLOCK_ID_RANGE_CHECK(ID) \ 00083 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \ 00084 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \ 00085 { \ 00086 return NRF_ERROR_INVALID_PARAM; \ 00087 } 00088 00089 /** 00090 * @brief Verifies the block size requested by the application can be supported by the module. 00091 */ 00092 #define BLOCK_SIZE_CHECK(X) \ 00093 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \ 00094 { \ 00095 return NRF_ERROR_INVALID_PARAM; \ 00096 } 00097 00098 /** 00099 * @brief Verifies block size requested by Application in registration API. 00100 */ 00101 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \ 00102 if (((COUNT) == 0) || \ 00103 ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)) || \ 00104 ((((COUNT) * (SIZE)) > PSTORAGE_FLASH_PAGE_SIZE) && (PSTORAGE_FLASH_PAGE_SIZE % (SIZE)))) \ 00105 { \ 00106 return NRF_ERROR_INVALID_PARAM; \ 00107 } 00108 00109 /** 00110 * @brief Verifies size parameter provided by application in API. 00111 */ 00112 #define SIZE_CHECK(ID, SIZE) \ 00113 if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \ 00114 { \ 00115 return NRF_ERROR_INVALID_PARAM; \ 00116 } 00117 00118 /** 00119 * @brief Verifies offset parameter provided by application in API. 00120 */ 00121 #define OFFSET_CHECK(ID, OFFSET, SIZE) \ 00122 if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \ 00123 { \ 00124 return NRF_ERROR_INVALID_PARAM; \ 00125 } 00126 00127 #ifdef PSTORAGE_RAW_MODE_ENABLE 00128 00129 /** 00130 * @brief Verifies the module identifier supplied by the application is registered for raw mode. 00131 */ 00132 #define MODULE_RAW_ID_RANGE_CHECK(ID) \ 00133 if ((PSTORAGE_MAX_APPLICATIONS+1 != ((ID)->module_id)) || \ 00134 (m_raw_app_table.cb == NULL)) \ 00135 { \ 00136 return NRF_ERROR_INVALID_PARAM; \ 00137 } 00138 00139 #endif // PSTORAGE_RAW_MODE_ENABLE 00140 00141 /**@} */ 00142 00143 00144 /**@brief Verify module's initialization status. 00145 * 00146 * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a 00147 * module API is called without initializing the module. 00148 */ 00149 #define VERIFY_MODULE_INITIALIZED() \ 00150 do \ 00151 { \ 00152 if (!m_module_initialized) \ 00153 { \ 00154 return NRF_ERROR_INVALID_STATE; \ 00155 } \ 00156 } while(0) 00157 00158 /**@brief Macro to fetch the block size registered for the module. */ 00159 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size) 00160 00161 00162 /** @brief States for the Update/Clear swap backup state machine. */ 00163 typedef enum 00164 { 00165 STATE_INIT, /**< State for indicating that swap can be used when using update/clear API. */ 00166 STATE_DATA_TO_SWAP_WRITE, /**< State for doing backup of data page into the swap page when using update/clear API. */ 00167 STATE_DATA_ERASE, /**< State for erasing data page when using update/clear API. */ 00168 STATE_HEAD_RESTORE, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */ 00169 STATE_TAIL_RESTORE, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */ 00170 STATE_NEW_BODY_WRITE, /**< State for writing body (middle) data to the data page when using update/clear API. */ 00171 STATE_SWAP_ERASE, /**< State for erasing the swap page when using the update/clear API. */ 00172 STATE_COMPLETE, /**< State for indicating that update/clear sequence is completed internal in the module when using the update/clear API. */ 00173 STATE_SWAP_DIRTY /**< State for initializing the swap region on module initialization. */ 00174 } swap_backup_state_t; 00175 00176 00177 /** 00178 * @brief Application registration information. 00179 * 00180 * @details Define application specific information that application needs to maintain to be able 00181 * to process requests from each one of them. 00182 */ 00183 typedef struct 00184 { 00185 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */ 00186 pstorage_block_t base_id; /**< Base block id assigned to the module. */ 00187 pstorage_size_t block_size; /**< Size of block for the module. */ 00188 pstorage_size_t block_count; /**< Number of block requested by application. */ 00189 pstorage_size_t num_of_pages; /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */ 00190 } pstorage_module_table_t; 00191 00192 00193 #ifdef PSTORAGE_RAW_MODE_ENABLE 00194 /** 00195 * @brief Application registration information. 00196 * 00197 * @details Define application specific information that application registered for raw mode. 00198 */ 00199 typedef struct 00200 { 00201 pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */ 00202 uint16_t num_of_pages; /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */ 00203 } pstorage_raw_module_table_t; 00204 #endif // PSTORAGE_RAW_MODE_ENABLE 00205 00206 00207 /** 00208 * @brief Defines command queue element. 00209 * 00210 * @details Defines command queue element. Each element encapsulates needed information to process 00211 * a flash access command. 00212 */ 00213 typedef struct 00214 { 00215 uint8_t op_code; /**< Identifies flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */ 00216 uint8_t n_tries; /**< Number of times this command has been retried after failing. */ 00217 pstorage_size_t size; /**< Identifies size in bytes requested for the operation. */ 00218 pstorage_size_t offset; /**< Offset requested by the application for 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 /** 00225 * @brief Defines command queue, an element is free if op_code field is not invalid. 00226 * 00227 * @details Defines commands enqueued for flash access. At any point of time, this queue has one or 00228 * more flash access operation pending if the count field is not zero. When the queue is 00229 * not empty, the rp (read pointer) field points to the flash access command in progress 00230 * or to requested next. The queue implements a simple first in first out algorithm. 00231 * Data addresses are assumed to be resident. 00232 */ 00233 typedef struct 00234 { 00235 uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */ 00236 uint8_t count; /**< Number of elements in the queue. */ 00237 bool flash_access; /**< Flag to ensure an flash event received is for an request issued by the module. */ 00238 cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */ 00239 } cmd_queue_t; 00240 00241 00242 static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */ 00243 static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */ 00244 static uint32_t m_next_page_addr; /**< Points to the flash address that can be allocated to a module next, this is needed as blocks of a module can span across flash pages. */ 00245 static pstorage_size_t m_round_val; /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */ 00246 static bool m_module_initialized = false; /**< Flag for checking if module has been initialized. */ 00247 static swap_backup_state_t m_swap_state; /**< Swap page state. */ 00248 00249 00250 static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS]; /**< Registered application information table. */ 00251 00252 #ifdef PSTORAGE_RAW_MODE_ENABLE 00253 static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */ 00254 #endif // PSTORAGE_RAW_MODE_ENABLE 00255 00256 00257 /** 00258 * @brief Routine called to actually issue the flash access request to the SoftDevice. 00259 * 00260 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00261 */ 00262 static uint32_t cmd_process(void); 00263 00264 00265 /** 00266 * @brief Routine to notify application of any errors. 00267 * 00268 * @param[in] result Result of event being notified. 00269 */ 00270 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem); 00271 00272 00273 /** 00274 * @defgroup utility_functions Utility internal functions. 00275 * @{ 00276 * @details Utility functions needed for interfacing with flash through SoC APIs. 00277 * SoC APIs are non blocking and provide the result of flash access through an event. 00278 * 00279 * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is 00280 * maintained by this module. 00281 */ 00282 00283 00284 /** 00285 * @brief Initializes command queue element. 00286 * 00287 * @param[in] index Element index being initialized. 00288 */ 00289 static void cmd_queue_element_init(uint32_t index) 00290 { 00291 // Internal function and checks on range of index can be avoided. 00292 m_cmd_queue.cmd[index].op_code = INVALID_OPCODE; 00293 m_cmd_queue.cmd[index].size = 0; 00294 m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS; 00295 m_cmd_queue.cmd[index].storage_addr.block_id = 0; 00296 m_cmd_queue.cmd[index].p_data_addr = NULL; 00297 m_cmd_queue.cmd[index].offset = 0; 00298 } 00299 00300 00301 /** 00302 * @brief Initializes command queue. 00303 */ 00304 static void cmd_queue_init(void) 00305 { 00306 uint32_t cmd_index; 00307 00308 m_round_val = 0; 00309 m_swap_state = STATE_INIT; 00310 m_cmd_queue.rp = 0; 00311 m_cmd_queue.count = 0; 00312 m_cmd_queue.flash_access = false; 00313 00314 for (cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++) 00315 { 00316 cmd_queue_element_init(cmd_index); 00317 } 00318 } 00319 00320 00321 /** 00322 * @brief Routine to enqueue a flash access operation. 00323 * 00324 * @param[in] opcode Identifies operation requested to be enqueued. 00325 * @param[in] p_storage_addr Identiifes module and flash address on which operation is requested. 00326 * @param[in] p_data_addr Identifies data address for flash access. 00327 * @param[in] size Size in bytes of data requested for the access operation. 00328 * @param[in] offset Offset within the flash memory block at which operation is requested. 00329 * 00330 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00331 * 00332 * @note All paramater check should be performed before requesting in an enqueue. 00333 */ 00334 static uint32_t cmd_queue_enqueue(uint8_t opcode, 00335 pstorage_handle_t * p_storage_addr, 00336 uint8_t * p_data_addr, 00337 pstorage_size_t size, 00338 pstorage_size_t offset) 00339 { 00340 uint32_t retval; 00341 uint8_t write_index = 0; 00342 00343 if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE) 00344 { 00345 // Enqueue the command if it is queue is not full. 00346 write_index = m_cmd_queue.rp + m_cmd_queue.count; 00347 00348 if (write_index >= PSTORAGE_CMD_QUEUE_SIZE) 00349 { 00350 write_index -= PSTORAGE_CMD_QUEUE_SIZE; 00351 } 00352 00353 m_cmd_queue.cmd[write_index].op_code = opcode; 00354 m_cmd_queue.cmd[write_index].n_tries = 0; 00355 m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr; 00356 m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr); 00357 m_cmd_queue.cmd[write_index].size = size; 00358 m_cmd_queue.cmd[write_index].offset = offset; 00359 retval = NRF_SUCCESS; 00360 if (m_cmd_queue.flash_access == false) 00361 { 00362 retval = cmd_process(); 00363 if (retval == NRF_ERROR_BUSY) 00364 { 00365 // In case of busy error code, it is possible to attempt to access flash. 00366 retval = NRF_SUCCESS; 00367 } 00368 } 00369 m_cmd_queue.count++; 00370 } 00371 else 00372 { 00373 retval = NRF_ERROR_NO_MEM; 00374 } 00375 00376 return retval; 00377 } 00378 00379 00380 /** 00381 * @brief Dequeues a command element. 00382 * 00383 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00384 */ 00385 static uint32_t cmd_queue_dequeue(void) 00386 { 00387 uint32_t retval; 00388 retval = NRF_SUCCESS; 00389 00390 // If any flash operation is enqueued, schedule. 00391 if ((m_cmd_queue.count > 0) && (m_cmd_queue.flash_access == false)) 00392 { 00393 retval = cmd_process(); 00394 if (retval != NRF_SUCCESS) 00395 { 00396 // Flash could be accessed by modules other than Bond Manager, hence a busy error is 00397 // acceptable, but any other error needs to be indicated to the bond manager. 00398 if (retval == NRF_ERROR_BUSY) 00399 { 00400 // In case of busy error code, it is possible to attempt to access flash. 00401 retval = NRF_SUCCESS; 00402 } 00403 } 00404 } 00405 else 00406 { 00407 // No flash access request pending. 00408 } 00409 00410 return retval; 00411 } 00412 00413 00414 /** 00415 * @brief Routine to notify application of any errors. 00416 * 00417 * @param[in] result Result of event being notified. 00418 * @param[in] p_elem Pointer to the element for which this result was received. 00419 */ 00420 static void app_notify(uint32_t result, cmd_queue_element_t * p_elem) 00421 { 00422 pstorage_ntf_cb_t ntf_cb; 00423 uint8_t op_code = p_elem->op_code; 00424 00425 #ifdef PSTORAGE_RAW_MODE_ENABLE 00426 if (p_elem->storage_addr.module_id == RAW_MODE_APP_ID) 00427 { 00428 ntf_cb = m_raw_app_table.cb; 00429 } 00430 else 00431 #endif // PSTORAGE_RAW_MODE_ENABLE 00432 { 00433 ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb; 00434 } 00435 00436 // Indicate result to client. 00437 // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally 00438 // for clients registering multiple pages. 00439 ntf_cb(&p_elem->storage_addr, 00440 op_code, 00441 result, 00442 p_elem->p_data_addr, 00443 p_elem->size); 00444 } 00445 00446 00447 /** 00448 * @brief Handles Flash Access Result Events declared in pstorage_platform.h. 00449 * 00450 * @param[in] sys_evt System event to be handled. 00451 */ 00452 void pstorage_sys_event_handler(uint32_t sys_evt) 00453 { 00454 uint32_t retval = NRF_SUCCESS; 00455 00456 // Its possible the flash access was not initiated by bond manager, hence 00457 // event is processed only if the event triggered was for an operation requested by the 00458 // bond manager. 00459 if (m_cmd_queue.flash_access == true) 00460 { 00461 cmd_queue_element_t * p_cmd; 00462 00463 m_cmd_queue.flash_access = false; 00464 00465 if (m_swap_state == STATE_SWAP_DIRTY) 00466 { 00467 if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS) 00468 { 00469 m_swap_state = STATE_INIT; 00470 } 00471 else 00472 { 00473 // If clearing the swap fails, set the application back to un-initialized, to give 00474 // the application a chance for a retry. 00475 m_module_initialized = false; 00476 } 00477 00478 // Schedule any queued flash access operations. 00479 retval = cmd_queue_dequeue(); 00480 if (retval != NRF_SUCCESS) 00481 { 00482 app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]); 00483 } 00484 return; 00485 } 00486 00487 switch (sys_evt) 00488 { 00489 case NRF_EVT_FLASH_OPERATION_SUCCESS: 00490 { 00491 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00492 m_round_val++; 00493 00494 const bool store_finished = 00495 ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) && 00496 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size)); 00497 00498 const bool update_finished = 00499 ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) && 00500 (m_swap_state == STATE_COMPLETE)); 00501 00502 const bool clear_block_finished = 00503 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) && 00504 (m_swap_state == STATE_COMPLETE)); 00505 00506 const bool clear_all_finished = 00507 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) && 00508 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) && 00509 (m_swap_state == STATE_INIT)); 00510 00511 if (update_finished || 00512 clear_block_finished || 00513 clear_all_finished || 00514 store_finished) 00515 { 00516 uint8_t queue_rp = m_cmd_queue.rp; 00517 00518 m_swap_state = STATE_INIT; 00519 00520 m_round_val = 0; 00521 m_cmd_queue.count--; 00522 m_cmd_queue.rp++; 00523 00524 if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE) 00525 { 00526 m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE; 00527 } 00528 00529 app_notify(retval, &m_cmd_queue.cmd[queue_rp]); 00530 00531 // Initialize/free the element as it is now processed. 00532 cmd_queue_element_init(queue_rp); 00533 } 00534 // Schedule any queued flash access operations. 00535 retval = cmd_queue_dequeue(); 00536 00537 if (retval != NRF_SUCCESS) 00538 { 00539 app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]); 00540 } 00541 } 00542 break; 00543 00544 case NRF_EVT_FLASH_OPERATION_ERROR: 00545 // Current command timed out and was not started in SoftDevice. 00546 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00547 00548 ASSERT(p_cmd->n_tries < SD_CMD_MAX_TRIES); 00549 if (++p_cmd->n_tries == SD_CMD_MAX_TRIES) 00550 { 00551 // If we have already attempted SD_CMD_MAX_TRIES times, give up. 00552 app_notify(NRF_ERROR_TIMEOUT, &m_cmd_queue.cmd[m_cmd_queue.rp]); 00553 } 00554 else 00555 { 00556 // Retry operation 00557 retval = cmd_process(); 00558 if (retval != NRF_SUCCESS && retval != NRF_ERROR_BUSY) 00559 { 00560 app_notify(retval, p_cmd); 00561 } 00562 } 00563 break; 00564 00565 default: 00566 // No implementation needed. 00567 break; 00568 00569 } 00570 } 00571 } 00572 00573 00574 /** @brief Function for handling flash accesses when using swap. 00575 * 00576 * __________________________________________________________ 00577 * | Page | 00578 * |________________________________________________________| 00579 * | head | affected body (to be updated or cleared) | tail | 00580 * |______|__________________________________________|______| 00581 * 00582 * @param[in] p_cmd Queue element being processed. 00583 * @param[in] page_number The affected page number. 00584 * @param[in] head_word_size Size of the head in number of words. 00585 * @param[in] tail_word_size Size of the tail in number of words. 00586 * 00587 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00588 */ 00589 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd, 00590 uint32_t page_number, 00591 uint32_t head_word_size, 00592 uint32_t tail_word_size) 00593 { 00594 uint32_t retval = NRF_ERROR_INTERNAL; 00595 00596 // Adjust entry point to state machine if needed. When we update has no head or tail its 00597 // no need for using the swap. 00598 if (m_swap_state == STATE_INIT) 00599 { 00600 if ((head_word_size == 0) && (tail_word_size == 0)) 00601 { 00602 // Only skip swap usage if the new data fills a whole flash page. 00603 m_swap_state = STATE_DATA_ERASE; 00604 } 00605 else 00606 { 00607 // Else start backing up application data to swap. 00608 m_swap_state = STATE_DATA_TO_SWAP_WRITE; 00609 } 00610 } 00611 00612 switch (m_swap_state) 00613 { 00614 case STATE_DATA_TO_SWAP_WRITE: 00615 // Backup previous content into swap page. 00616 retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR), 00617 (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE), 00618 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t)); 00619 if (retval == NRF_SUCCESS) 00620 { 00621 m_swap_state = STATE_DATA_ERASE; 00622 } 00623 break; 00624 00625 case STATE_DATA_ERASE: 00626 // Clear the application data page. 00627 retval = sd_flash_page_erase(page_number); 00628 if (retval == NRF_SUCCESS) 00629 { 00630 if (head_word_size == 0) 00631 { 00632 if (tail_word_size == 0) 00633 { 00634 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00635 { 00636 m_swap_state = STATE_COMPLETE; 00637 } 00638 else 00639 { 00640 m_swap_state = STATE_NEW_BODY_WRITE; 00641 } 00642 } 00643 else 00644 { 00645 m_swap_state = STATE_TAIL_RESTORE; 00646 } 00647 } 00648 else 00649 { 00650 m_swap_state = STATE_HEAD_RESTORE; 00651 } 00652 } 00653 break; 00654 00655 case STATE_HEAD_RESTORE: 00656 // Restore head from swap to application data page. 00657 retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE), 00658 (uint32_t *)PSTORAGE_SWAP_ADDR, 00659 head_word_size); 00660 if (retval == NRF_SUCCESS) 00661 { 00662 if (tail_word_size == 0) 00663 { 00664 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00665 { 00666 m_swap_state = STATE_SWAP_ERASE; 00667 } 00668 else 00669 { 00670 m_swap_state = STATE_NEW_BODY_WRITE; 00671 } 00672 } 00673 else 00674 { 00675 m_swap_state = STATE_TAIL_RESTORE; 00676 } 00677 } 00678 break; 00679 00680 case STATE_TAIL_RESTORE: 00681 // Restore tail from swap to application data page. 00682 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) + 00683 (head_word_size * sizeof(uint32_t)) + 00684 p_cmd->size), 00685 (uint32_t *)(PSTORAGE_SWAP_ADDR + 00686 (head_word_size * sizeof(uint32_t)) + 00687 p_cmd->size), 00688 tail_word_size); 00689 if (retval == NRF_SUCCESS) 00690 { 00691 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00692 { 00693 m_swap_state = STATE_SWAP_ERASE; 00694 } 00695 else 00696 { 00697 m_swap_state = STATE_NEW_BODY_WRITE; 00698 } 00699 } 00700 break; 00701 00702 case STATE_NEW_BODY_WRITE: 00703 // Write new data (body) to application data page. 00704 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) + 00705 (head_word_size * sizeof(uint32_t))), 00706 (uint32_t *)p_cmd->p_data_addr, 00707 p_cmd->size / sizeof(uint32_t)); 00708 if (retval == NRF_SUCCESS) 00709 { 00710 if ((head_word_size == 0) && (tail_word_size == 0)) 00711 { 00712 m_swap_state = STATE_COMPLETE; 00713 } 00714 else 00715 { 00716 m_swap_state = STATE_SWAP_ERASE; 00717 } 00718 } 00719 break; 00720 00721 case STATE_SWAP_ERASE: 00722 // Clear the swap page for subsequent use. 00723 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE); 00724 if (retval == NRF_SUCCESS) 00725 { 00726 m_swap_state = STATE_COMPLETE; 00727 } 00728 break; 00729 00730 default: 00731 break; 00732 } 00733 00734 return retval; 00735 } 00736 00737 00738 /** 00739 * @brief Routine called to actually issue the flash access request to the SoftDevice. 00740 * 00741 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00742 */ 00743 static uint32_t cmd_process(void) 00744 { 00745 uint32_t retval; 00746 uint32_t storage_addr; 00747 cmd_queue_element_t * p_cmd; 00748 00749 retval = NRF_ERROR_FORBIDDEN; 00750 00751 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00752 00753 storage_addr = p_cmd->storage_addr.block_id; 00754 00755 switch (p_cmd->op_code) 00756 { 00757 case PSTORAGE_STORE_OP_CODE: 00758 { 00759 uint32_t size; 00760 uint32_t offset; 00761 uint8_t * p_data_addr = p_cmd->p_data_addr; 00762 00763 offset = (m_round_val * SOC_MAX_WRITE_SIZE); 00764 size = p_cmd->size - offset; 00765 p_data_addr += offset; 00766 storage_addr += (p_cmd->offset + offset); 00767 00768 if (size < SOC_MAX_WRITE_SIZE) 00769 { 00770 retval = sd_flash_write(((uint32_t *)storage_addr), 00771 (uint32_t *)p_data_addr, 00772 size / sizeof(uint32_t)); 00773 } 00774 else 00775 { 00776 retval = sd_flash_write(((uint32_t *)storage_addr), 00777 (uint32_t *)p_data_addr, 00778 SOC_MAX_WRITE_SIZE / sizeof(uint32_t)); 00779 } 00780 } 00781 break; 00782 00783 case PSTORAGE_CLEAR_OP_CODE: 00784 { 00785 // Calculate page number before clearing. 00786 uint32_t page_number; 00787 00788 pstorage_size_t block_size = 00789 m_app_table[p_cmd->storage_addr.module_id].block_size; 00790 00791 pstorage_size_t block_count = 00792 m_app_table[p_cmd->storage_addr.module_id].block_count; 00793 00794 pstorage_block_t base_address = 00795 m_app_table[p_cmd->storage_addr.module_id].base_id; 00796 00797 // If the whole module should be cleared. 00798 if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) || 00799 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID)) 00800 { 00801 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val); 00802 00803 retval = sd_flash_page_erase(page_number); 00804 } 00805 // If one block is to be erased. 00806 else 00807 { 00808 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE); 00809 00810 uint32_t head_word_size = ( 00811 storage_addr - 00812 (page_number * PSTORAGE_FLASH_PAGE_SIZE) 00813 ) / sizeof(uint32_t); 00814 00815 uint32_t tail_word_size = ( 00816 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) - 00817 (storage_addr + p_cmd->size) 00818 ) / sizeof(uint32_t); 00819 00820 retval = swap_state_process(p_cmd, 00821 page_number, 00822 head_word_size, 00823 tail_word_size); 00824 } 00825 } 00826 break; 00827 00828 case PSTORAGE_UPDATE_OP_CODE: 00829 { 00830 uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE); 00831 00832 uint32_t head_word_size = ( 00833 storage_addr + p_cmd->offset - 00834 (page_number * PSTORAGE_FLASH_PAGE_SIZE) 00835 ) / sizeof(uint32_t); 00836 00837 uint32_t tail_word_size = ( 00838 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) - 00839 (storage_addr + p_cmd->offset + p_cmd->size) 00840 ) / sizeof(uint32_t); 00841 00842 retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size); 00843 } 00844 break; 00845 00846 default: 00847 // Should never reach here. 00848 break; 00849 } 00850 00851 if (retval == NRF_SUCCESS) 00852 { 00853 m_cmd_queue.flash_access = true; 00854 } 00855 00856 return retval; 00857 } 00858 /** @} */ 00859 00860 00861 uint32_t pstorage_init(void) 00862 { 00863 uint32_t retval; 00864 00865 cmd_queue_init(); 00866 00867 m_next_app_instance = 0; 00868 m_next_page_addr = PSTORAGE_DATA_START_ADDR; 00869 m_round_val = 0; 00870 00871 for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++) 00872 { 00873 m_app_table[index].cb = NULL; 00874 m_app_table[index].block_size = 0; 00875 m_app_table[index].num_of_pages = 0; 00876 m_app_table[index].block_count = 0; 00877 } 00878 00879 #ifdef PSTORAGE_RAW_MODE_ENABLE 00880 m_raw_app_table.cb = NULL; 00881 m_raw_app_table.num_of_pages = 0; 00882 m_module_initialized = true; 00883 m_swap_state = STATE_INIT; 00884 00885 retval = NRF_SUCCESS; 00886 #else 00887 m_swap_state = STATE_SWAP_DIRTY; 00888 00889 // Erase swap region in case it is dirty. 00890 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE); 00891 if (retval == NRF_SUCCESS) 00892 { 00893 m_cmd_queue.flash_access = true; 00894 m_module_initialized = true; 00895 } 00896 #endif //PSTORAGE_RAW_MODE_ENABLE 00897 00898 return retval; 00899 } 00900 00901 00902 uint32_t pstorage_register(pstorage_module_param_t * p_module_param, 00903 pstorage_handle_t * p_block_id) 00904 { 00905 uint16_t page_count; 00906 uint32_t total_size; 00907 00908 VERIFY_MODULE_INITIALIZED(); 00909 NULL_PARAM_CHECK(p_module_param); 00910 NULL_PARAM_CHECK(p_block_id); 00911 NULL_PARAM_CHECK(p_module_param->cb); 00912 BLOCK_SIZE_CHECK(p_module_param->block_size); 00913 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size); 00914 00915 // Block size should be a multiple of word size. 00916 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0)) 00917 { 00918 return NRF_ERROR_INVALID_PARAM; 00919 } 00920 00921 if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS) 00922 { 00923 return NRF_ERROR_NO_MEM; 00924 } 00925 00926 p_block_id->module_id = m_next_app_instance; 00927 p_block_id->block_id = m_next_page_addr; 00928 00929 m_app_table[m_next_app_instance].base_id = p_block_id->block_id; 00930 m_app_table[m_next_app_instance].cb = p_module_param->cb; 00931 m_app_table[m_next_app_instance].block_size = p_module_param->block_size; 00932 m_app_table[m_next_app_instance].block_count = p_module_param->block_count; 00933 00934 // Calculate number of flash pages allocated for the device. 00935 page_count = 0; 00936 total_size = p_module_param->block_size * p_module_param->block_count; 00937 do 00938 { 00939 page_count++; 00940 if (total_size > PSTORAGE_FLASH_PAGE_SIZE) 00941 { 00942 total_size -= PSTORAGE_FLASH_PAGE_SIZE; 00943 } 00944 else 00945 { 00946 total_size = 0; 00947 } 00948 m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE; 00949 } 00950 while (total_size > 0); 00951 00952 m_app_table[m_next_app_instance].num_of_pages = page_count; 00953 m_next_app_instance++; 00954 00955 return NRF_SUCCESS; 00956 } 00957 00958 00959 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id, 00960 pstorage_size_t block_num, 00961 pstorage_handle_t * p_block_id) 00962 { 00963 pstorage_handle_t temp_id; 00964 00965 VERIFY_MODULE_INITIALIZED(); 00966 NULL_PARAM_CHECK(p_base_id); 00967 NULL_PARAM_CHECK(p_block_id); 00968 MODULE_ID_RANGE_CHECK(p_base_id); 00969 00970 temp_id = (*p_base_id); 00971 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id)); 00972 00973 BLOCK_ID_RANGE_CHECK(&temp_id); 00974 00975 (*p_block_id) = temp_id; 00976 00977 return NRF_SUCCESS; 00978 } 00979 00980 00981 uint32_t pstorage_store(pstorage_handle_t * p_dest, 00982 uint8_t * p_src, 00983 pstorage_size_t size, 00984 pstorage_size_t offset) 00985 { 00986 VERIFY_MODULE_INITIALIZED(); 00987 NULL_PARAM_CHECK(p_src); 00988 NULL_PARAM_CHECK(p_dest); 00989 MODULE_ID_RANGE_CHECK(p_dest); 00990 BLOCK_ID_RANGE_CHECK(p_dest); 00991 SIZE_CHECK(p_dest, size); 00992 OFFSET_CHECK(p_dest, offset,size); 00993 00994 // Verify word alignment. 00995 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 00996 { 00997 return NRF_ERROR_INVALID_ADDR; 00998 } 00999 01000 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01001 { 01002 return NRF_ERROR_INVALID_ADDR; 01003 } 01004 01005 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 01006 } 01007 01008 01009 uint32_t pstorage_update(pstorage_handle_t * p_dest, 01010 uint8_t * p_src, 01011 pstorage_size_t size, 01012 pstorage_size_t offset) 01013 { 01014 VERIFY_MODULE_INITIALIZED(); 01015 NULL_PARAM_CHECK(p_src); 01016 NULL_PARAM_CHECK(p_dest); 01017 MODULE_ID_RANGE_CHECK(p_dest); 01018 BLOCK_ID_RANGE_CHECK(p_dest); 01019 SIZE_CHECK(p_dest, size); 01020 OFFSET_CHECK(p_dest, offset, size); 01021 01022 // Verify word alignment. 01023 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 01024 { 01025 return NRF_ERROR_INVALID_ADDR; 01026 } 01027 01028 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01029 { 01030 return NRF_ERROR_INVALID_ADDR; 01031 } 01032 01033 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset); 01034 } 01035 01036 01037 uint32_t pstorage_load(uint8_t * p_dest, 01038 pstorage_handle_t * p_src, 01039 pstorage_size_t size, 01040 pstorage_size_t offset) 01041 { 01042 VERIFY_MODULE_INITIALIZED(); 01043 NULL_PARAM_CHECK(p_src); 01044 NULL_PARAM_CHECK(p_dest); 01045 MODULE_ID_RANGE_CHECK(p_src); 01046 BLOCK_ID_RANGE_CHECK(p_src); 01047 SIZE_CHECK(p_src, size); 01048 OFFSET_CHECK(p_src, offset, size); 01049 01050 // Verify word alignment. 01051 if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset))) 01052 { 01053 return NRF_ERROR_INVALID_ADDR; 01054 } 01055 01056 if ((!is_word_aligned((uint32_t *)p_src->block_id))) 01057 { 01058 return NRF_ERROR_INVALID_ADDR; 01059 } 01060 01061 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size); 01062 01063 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size); 01064 01065 return NRF_SUCCESS; 01066 } 01067 01068 01069 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01070 { 01071 uint32_t retval; 01072 01073 VERIFY_MODULE_INITIALIZED(); 01074 NULL_PARAM_CHECK(p_dest); 01075 MODULE_ID_RANGE_CHECK(p_dest); 01076 BLOCK_ID_RANGE_CHECK(p_dest); 01077 01078 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01079 { 01080 return NRF_ERROR_INVALID_ADDR; 01081 } 01082 01083 if ( 01084 !( 01085 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) % 01086 m_app_table[p_dest->module_id].block_size) == 0 01087 ) 01088 ) 01089 { 01090 return NRF_ERROR_INVALID_PARAM; 01091 } 01092 01093 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01094 01095 return retval; 01096 } 01097 01098 01099 uint32_t pstorage_access_status_get(uint32_t * p_count) 01100 { 01101 VERIFY_MODULE_INITIALIZED(); 01102 NULL_PARAM_CHECK(p_count); 01103 01104 (*p_count) = m_cmd_queue.count; 01105 01106 return NRF_SUCCESS; 01107 } 01108 01109 #ifdef PSTORAGE_RAW_MODE_ENABLE 01110 01111 01112 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param, 01113 pstorage_handle_t * p_block_id) 01114 { 01115 VERIFY_MODULE_INITIALIZED(); 01116 NULL_PARAM_CHECK(p_module_param); 01117 NULL_PARAM_CHECK(p_block_id); 01118 NULL_PARAM_CHECK(p_module_param->cb); 01119 01120 if (m_raw_app_table.cb != NULL) 01121 { 01122 return NRF_ERROR_NO_MEM; 01123 } 01124 01125 p_block_id->module_id = RAW_MODE_APP_ID; 01126 m_raw_app_table.cb = p_module_param->cb; 01127 01128 return NRF_SUCCESS; 01129 } 01130 01131 01132 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest, 01133 uint8_t * p_src, 01134 pstorage_size_t size, 01135 pstorage_size_t offset) 01136 { 01137 VERIFY_MODULE_INITIALIZED(); 01138 NULL_PARAM_CHECK(p_src); 01139 NULL_PARAM_CHECK(p_dest); 01140 MODULE_RAW_ID_RANGE_CHECK(p_dest); 01141 01142 // Verify word alignment. 01143 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 01144 { 01145 return NRF_ERROR_INVALID_ADDR; 01146 } 01147 01148 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 01149 } 01150 01151 01152 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01153 { 01154 uint32_t retval; 01155 01156 VERIFY_MODULE_INITIALIZED(); 01157 NULL_PARAM_CHECK(p_dest); 01158 MODULE_RAW_ID_RANGE_CHECK(p_dest); 01159 01160 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01161 01162 return retval; 01163 } 01164 01165 #endif // PSTORAGE_RAW_MODE_ENABLE
Generated on Tue Jul 12 2022 16:00:22 by
