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