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