Nordic stack and drivers for the mbed BLE API Modified for HRM1017 for library 0.1.0
Fork of nRF51822 by
pstorage.cpp
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 #if NEED_PSTORAGE /* disabled by default */ 00014 00015 #include "pstorage.h " 00016 #include <stdlib.h> 00017 #include <stdint.h> 00018 #include <string.h> 00019 #include "nordic_common.h" 00020 #include "nrf_error.h" 00021 #include "nrf_assert.h" 00022 #include "nrf.h" 00023 #include "nrf_soc.h" 00024 #include "app_util.h " 00025 00026 #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */ 00027 #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. */ 00028 #define RAW_MODE_APP_ID (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */ 00029 00030 /** 00031 * @defgroup api_param_check API Parameters check macros. 00032 * 00033 * @details Macros that verify parameters passed to the module in the APIs. These macros 00034 * could be mapped to nothing in final versions of code to save execution and size. 00035 * 00036 * @{ 00037 */ 00038 00039 /** 00040 * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL. 00041 */ 00042 #define NULL_PARAM_CHECK(PARAM) \ 00043 if ((PARAM) == NULL) \ 00044 { \ 00045 return NRF_ERROR_NULL; \ 00046 } 00047 00048 /** 00049 * @brief Verifies the module identifier supplied by the application is within permissible 00050 * range. 00051 */ 00052 #define MODULE_ID_RANGE_CHECK(ID) \ 00053 if ((((ID)->module_id) >= PSTORAGE_MAX_APPLICATIONS) || \ 00054 (m_app_table[(ID)->module_id].cb == NULL)) \ 00055 { \ 00056 return NRF_ERROR_INVALID_PARAM; \ 00057 } 00058 00059 /** 00060 * @brief Verifies the block identifier supplied by the application is within the permissible 00061 * range. 00062 */ 00063 #define BLOCK_ID_RANGE_CHECK(ID) \ 00064 if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \ 00065 (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \ 00066 { \ 00067 return NRF_ERROR_INVALID_PARAM; \ 00068 } 00069 00070 /** 00071 * @brief Verifies the block size requested by the application can be supported by the module. 00072 */ 00073 #define BLOCK_SIZE_CHECK(X) \ 00074 if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \ 00075 { \ 00076 return NRF_ERROR_INVALID_PARAM; \ 00077 } 00078 00079 /** 00080 * @brief Verifies block size requested by Application in registration API. 00081 */ 00082 #define BLOCK_COUNT_CHECK(COUNT, SIZE) \ 00083 if (((COUNT) == 0) || ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR))) \ 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 app_notify(retval); 00378 } 00379 else 00380 { 00381 // In case of busy next trigger will be a success or a failure event. 00382 } 00383 } 00384 } 00385 else 00386 { 00387 // No flash access request pending. 00388 } 00389 00390 return retval; 00391 } 00392 00393 00394 /** 00395 * @brief Routine to notify application of any errors. 00396 * 00397 * @param[in] result Result of event being notified. 00398 */ 00399 static void app_notify(uint32_t result) 00400 { 00401 pstorage_ntf_cb_t ntf_cb; 00402 uint8_t op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code; 00403 00404 #ifdef PSTORAGE_RAW_MODE_ENABLE 00405 if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID) 00406 { 00407 ntf_cb = m_raw_app_table.cb; 00408 } 00409 else 00410 #endif // PSTORAGE_RAW_MODE_ENABLE 00411 { 00412 ntf_cb = m_app_table[m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id].cb; 00413 } 00414 00415 // Indicate result to client. 00416 // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally 00417 // for clients registering multiple pages. 00418 ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr, 00419 op_code, 00420 result, 00421 m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr, 00422 m_cmd_queue.cmd[m_cmd_queue.rp].size); 00423 } 00424 00425 00426 /** 00427 * @brief Handles Flash Access Result Events declared in pstorage_platform.h. 00428 * 00429 * @param[in] sys_evt System event to be handled. 00430 */ 00431 void pstorage_sys_event_handler(uint32_t sys_evt) 00432 { 00433 uint32_t retval = NRF_SUCCESS; 00434 00435 // Its possible the flash access was not initiated by bond manager, hence 00436 // event is processed only if the event triggered was for an operation requested by the 00437 // bond manager. 00438 if (m_cmd_queue.flash_access == true) 00439 { 00440 cmd_queue_element_t * p_cmd; 00441 00442 m_cmd_queue.flash_access = false; 00443 00444 if (m_swap_state == STATE_SWAP_DIRTY) 00445 { 00446 if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS) 00447 { 00448 m_swap_state = STATE_INIT; 00449 } 00450 else 00451 { 00452 // If clearing the swap fails, set the application back to un-initialized, to give 00453 // the application a chance for a retry. 00454 m_module_initialized = false; 00455 } 00456 00457 // Schedule any queued flash access operations. 00458 retval = cmd_queue_dequeue(); 00459 if (retval != NRF_SUCCESS) 00460 { 00461 app_notify(retval); 00462 } 00463 return; 00464 } 00465 00466 switch (sys_evt) 00467 { 00468 case NRF_EVT_FLASH_OPERATION_SUCCESS: 00469 { 00470 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00471 m_round_val++; 00472 00473 const bool store_finished = 00474 ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) && 00475 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size)); 00476 00477 const bool update_finished = 00478 ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) && 00479 (m_swap_state == STATE_COMPLETE)); 00480 00481 const bool clear_block_finished = 00482 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) && 00483 (m_swap_state == STATE_COMPLETE)); 00484 00485 const bool clear_all_finished = 00486 ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) && 00487 ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) && 00488 (m_swap_state == STATE_INIT)); 00489 00490 if (update_finished || 00491 clear_block_finished || 00492 clear_all_finished || 00493 store_finished) 00494 { 00495 m_swap_state = STATE_INIT; 00496 00497 app_notify(retval); 00498 00499 // Initialize/free the element as it is now processed. 00500 cmd_queue_element_init(m_cmd_queue.rp); 00501 m_round_val = 0; 00502 m_cmd_queue.count--; 00503 m_cmd_queue.rp++; 00504 00505 if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE) 00506 { 00507 m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE; 00508 } 00509 } 00510 // Schedule any queued flash access operations. 00511 retval = cmd_queue_dequeue(); 00512 00513 if (retval != NRF_SUCCESS) 00514 { 00515 app_notify(retval); 00516 } 00517 } 00518 break; 00519 00520 case NRF_EVT_FLASH_OPERATION_ERROR: 00521 app_notify(NRF_ERROR_TIMEOUT); 00522 break; 00523 00524 default: 00525 // No implementation needed. 00526 break; 00527 00528 } 00529 } 00530 } 00531 00532 00533 /** @brief Function for handling flash accesses when using swap. 00534 * 00535 * __________________________________________________________ 00536 * | Page | 00537 * |________________________________________________________| 00538 * | head | affected body (to be updated or cleared) | tail | 00539 * |______|__________________________________________|______| 00540 * 00541 * @param[in] p_cmd Queue element being processed. 00542 * @param[in] page_number The affected page number. 00543 * @param[in] head_word_size Size of the head in number of words. 00544 * @param[in] tail_word_size Size of the tail in number of words. 00545 * 00546 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00547 */ 00548 static uint32_t swap_state_process(cmd_queue_element_t * p_cmd, 00549 uint32_t page_number, 00550 uint32_t head_word_size, 00551 uint32_t tail_word_size) 00552 { 00553 uint32_t retval = NRF_ERROR_INTERNAL; 00554 00555 // Adjust entry point to state machine if needed. When we update has no head or tail its 00556 // no need for using the swap. 00557 if (m_swap_state == STATE_INIT) 00558 { 00559 if ((head_word_size == 0) && (tail_word_size == 0)) 00560 { 00561 // Only skip swap usage if the new data fills a whole flash page. 00562 m_swap_state = STATE_DATA_ERASE; 00563 } 00564 else 00565 { 00566 // Else start backing up application data to swap. 00567 m_swap_state = STATE_DATA_TO_SWAP_WRITE; 00568 } 00569 } 00570 00571 switch (m_swap_state) 00572 { 00573 case STATE_DATA_TO_SWAP_WRITE: 00574 // Backup previous content into swap page. 00575 retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR), 00576 (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE), 00577 PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t)); 00578 if (retval == NRF_SUCCESS) 00579 { 00580 m_swap_state = STATE_DATA_ERASE; 00581 } 00582 break; 00583 00584 case STATE_DATA_ERASE: 00585 // Clear the application data page. 00586 retval = sd_flash_page_erase(page_number); 00587 if (retval == NRF_SUCCESS) 00588 { 00589 if (head_word_size == 0) 00590 { 00591 if (tail_word_size == 0) 00592 { 00593 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00594 { 00595 m_swap_state = STATE_COMPLETE; 00596 } 00597 else 00598 { 00599 m_swap_state = STATE_NEW_BODY_WRITE; 00600 } 00601 } 00602 else 00603 { 00604 m_swap_state = STATE_TAIL_RESTORE; 00605 } 00606 } 00607 else 00608 { 00609 m_swap_state = STATE_HEAD_RESTORE; 00610 } 00611 } 00612 break; 00613 00614 case STATE_HEAD_RESTORE: 00615 // Restore head from swap to application data page. 00616 retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE), 00617 (uint32_t *)PSTORAGE_SWAP_ADDR, 00618 head_word_size); 00619 if (retval == NRF_SUCCESS) 00620 { 00621 if (tail_word_size == 0) 00622 { 00623 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00624 { 00625 m_swap_state = STATE_SWAP_ERASE; 00626 } 00627 else 00628 { 00629 m_swap_state = STATE_NEW_BODY_WRITE; 00630 } 00631 } 00632 else 00633 { 00634 m_swap_state = STATE_TAIL_RESTORE; 00635 } 00636 } 00637 break; 00638 00639 case STATE_TAIL_RESTORE: 00640 // Restore tail from swap to application data page. 00641 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) + 00642 (head_word_size * sizeof(uint32_t)) + 00643 p_cmd->size), 00644 (uint32_t *)(PSTORAGE_SWAP_ADDR + 00645 (head_word_size * sizeof(uint32_t)) + 00646 p_cmd->size), 00647 tail_word_size); 00648 if (retval == NRF_SUCCESS) 00649 { 00650 if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) 00651 { 00652 m_swap_state = STATE_SWAP_ERASE; 00653 } 00654 else 00655 { 00656 m_swap_state = STATE_NEW_BODY_WRITE; 00657 } 00658 } 00659 break; 00660 00661 case STATE_NEW_BODY_WRITE: 00662 // Write new data (body) to application data page. 00663 retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) + 00664 (head_word_size * sizeof(uint32_t))), 00665 (uint32_t *)p_cmd->p_data_addr, 00666 p_cmd->size / sizeof(uint32_t)); 00667 if (retval == NRF_SUCCESS) 00668 { 00669 if ((head_word_size == 0) && (tail_word_size == 0)) 00670 { 00671 m_swap_state = STATE_COMPLETE; 00672 } 00673 else 00674 { 00675 m_swap_state = STATE_SWAP_ERASE; 00676 } 00677 } 00678 break; 00679 00680 case STATE_SWAP_ERASE: 00681 // Clear the swap page for subsequent use. 00682 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE); 00683 if (retval == NRF_SUCCESS) 00684 { 00685 m_swap_state = STATE_COMPLETE; 00686 } 00687 break; 00688 00689 default: 00690 break; 00691 } 00692 00693 return retval; 00694 } 00695 00696 00697 /** 00698 * @brief Routine called to actually issue the flash access request to the SoftDevice. 00699 * 00700 * @retval NRF_SUCCESS on success, else an error code indicating reason for failure. 00701 */ 00702 static uint32_t cmd_process(void) 00703 { 00704 uint32_t retval; 00705 uint32_t storage_addr; 00706 cmd_queue_element_t * p_cmd; 00707 00708 retval = NRF_ERROR_FORBIDDEN; 00709 00710 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp]; 00711 00712 storage_addr = p_cmd->storage_addr.block_id; 00713 00714 switch (p_cmd->op_code) 00715 { 00716 case PSTORAGE_STORE_OP_CODE: 00717 { 00718 uint32_t size; 00719 uint32_t offset; 00720 uint8_t * p_data_addr = p_cmd->p_data_addr; 00721 00722 offset = (m_round_val * SOC_MAX_WRITE_SIZE); 00723 size = p_cmd->size - offset; 00724 p_data_addr += offset; 00725 storage_addr += (p_cmd->offset + offset); 00726 00727 if (size < SOC_MAX_WRITE_SIZE) 00728 { 00729 retval = sd_flash_write(((uint32_t *)storage_addr), 00730 (uint32_t *)p_data_addr, 00731 size / sizeof(uint32_t)); 00732 } 00733 else 00734 { 00735 retval = sd_flash_write(((uint32_t *)storage_addr), 00736 (uint32_t *)p_data_addr, 00737 SOC_MAX_WRITE_SIZE / sizeof(uint32_t)); 00738 } 00739 } 00740 break; 00741 00742 case PSTORAGE_CLEAR_OP_CODE: 00743 { 00744 // Calculate page number before clearing. 00745 uint32_t page_number; 00746 00747 pstorage_size_t block_size = 00748 m_app_table[p_cmd->storage_addr.module_id].block_size; 00749 00750 pstorage_size_t block_count = 00751 m_app_table[p_cmd->storage_addr.module_id].block_count; 00752 00753 pstorage_block_t base_address = 00754 m_app_table[p_cmd->storage_addr.module_id].base_id; 00755 00756 // If the whole module should be cleared. 00757 if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) || 00758 (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID)) 00759 { 00760 page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val); 00761 00762 retval = sd_flash_page_erase(page_number); 00763 } 00764 // If one block is to be erased. 00765 else 00766 { 00767 page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE); 00768 00769 uint32_t head_word_size = ( 00770 storage_addr - 00771 (page_number * PSTORAGE_FLASH_PAGE_SIZE) 00772 ) / sizeof(uint32_t); 00773 00774 uint32_t tail_word_size = ( 00775 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) - 00776 (storage_addr + p_cmd->size) 00777 ) / sizeof(uint32_t); 00778 00779 retval = swap_state_process(p_cmd, 00780 page_number, 00781 head_word_size, 00782 tail_word_size); 00783 } 00784 } 00785 break; 00786 00787 case PSTORAGE_UPDATE_OP_CODE: 00788 { 00789 uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE); 00790 00791 uint32_t head_word_size = ( 00792 storage_addr + p_cmd->offset - 00793 (page_number * PSTORAGE_FLASH_PAGE_SIZE) 00794 ) / sizeof(uint32_t); 00795 00796 uint32_t tail_word_size = ( 00797 ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) - 00798 (storage_addr + p_cmd->offset + p_cmd->size) 00799 ) / sizeof(uint32_t); 00800 00801 retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size); 00802 } 00803 break; 00804 00805 default: 00806 // Should never reach here. 00807 break; 00808 } 00809 00810 if (retval == NRF_SUCCESS) 00811 { 00812 m_cmd_queue.flash_access = true; 00813 } 00814 00815 return retval; 00816 } 00817 /** @} */ 00818 00819 00820 uint32_t pstorage_init(void) 00821 { 00822 uint32_t retval; 00823 00824 cmd_queue_init(); 00825 00826 m_next_app_instance = 0; 00827 m_next_page_addr = PSTORAGE_DATA_START_ADDR; 00828 m_round_val = 0; 00829 00830 for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++) 00831 { 00832 m_app_table[index].cb = NULL; 00833 m_app_table[index].block_size = 0; 00834 m_app_table[index].num_of_pages = 0; 00835 m_app_table[index].block_count = 0; 00836 } 00837 00838 #ifdef PSTORAGE_RAW_MODE_ENABLE 00839 m_raw_app_table.cb = NULL; 00840 m_raw_app_table.num_of_pages = 0; 00841 m_module_initialized = true; 00842 m_swap_state = STATE_INIT; 00843 00844 retval = NRF_SUCCESS; 00845 #else 00846 m_swap_state = STATE_SWAP_DIRTY; 00847 00848 // Erase swap region in case it is dirty. 00849 retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE); 00850 if (retval == NRF_SUCCESS) 00851 { 00852 m_cmd_queue.flash_access = true; 00853 m_module_initialized = true; 00854 } 00855 #endif //PSTORAGE_RAW_MODE_ENABLE 00856 00857 return retval; 00858 } 00859 00860 00861 uint32_t pstorage_register(pstorage_module_param_t * p_module_param, 00862 pstorage_handle_t * p_block_id) 00863 { 00864 uint16_t page_count; 00865 uint32_t total_size; 00866 00867 VERIFY_MODULE_INITIALIZED(); 00868 NULL_PARAM_CHECK(p_module_param); 00869 NULL_PARAM_CHECK(p_block_id); 00870 NULL_PARAM_CHECK(p_module_param->cb); 00871 BLOCK_SIZE_CHECK(p_module_param->block_size); 00872 BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size); 00873 00874 // Block size should be a multiple of word size. 00875 if (!((p_module_param->block_size % sizeof(uint32_t)) == 0)) 00876 { 00877 return NRF_ERROR_INVALID_PARAM; 00878 } 00879 00880 if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS) 00881 { 00882 return NRF_ERROR_NO_MEM; 00883 } 00884 00885 p_block_id->module_id = m_next_app_instance; 00886 p_block_id->block_id = m_next_page_addr; 00887 00888 m_app_table[m_next_app_instance].base_id = p_block_id->block_id; 00889 m_app_table[m_next_app_instance].cb = p_module_param->cb; 00890 m_app_table[m_next_app_instance].block_size = p_module_param->block_size; 00891 m_app_table[m_next_app_instance].block_count = p_module_param->block_count; 00892 00893 // Calculate number of flash pages allocated for the device. 00894 page_count = 0; 00895 total_size = p_module_param->block_size * p_module_param->block_count; 00896 do 00897 { 00898 page_count++; 00899 if (total_size > PSTORAGE_FLASH_PAGE_SIZE) 00900 { 00901 total_size -= PSTORAGE_FLASH_PAGE_SIZE; 00902 } 00903 else 00904 { 00905 total_size = 0; 00906 } 00907 m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE; 00908 } 00909 while (total_size >= PSTORAGE_FLASH_PAGE_SIZE); 00910 00911 m_app_table[m_next_app_instance].num_of_pages = page_count; 00912 m_next_app_instance++; 00913 00914 return NRF_SUCCESS; 00915 } 00916 00917 00918 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id, 00919 pstorage_size_t block_num, 00920 pstorage_handle_t * p_block_id) 00921 { 00922 pstorage_handle_t temp_id; 00923 00924 VERIFY_MODULE_INITIALIZED(); 00925 NULL_PARAM_CHECK(p_base_id); 00926 NULL_PARAM_CHECK(p_block_id); 00927 MODULE_ID_RANGE_CHECK(p_base_id); 00928 00929 temp_id = (*p_base_id); 00930 temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id)); 00931 00932 BLOCK_ID_RANGE_CHECK(&temp_id); 00933 00934 (*p_block_id) = temp_id; 00935 00936 return NRF_SUCCESS; 00937 } 00938 00939 00940 uint32_t pstorage_store(pstorage_handle_t * p_dest, 00941 uint8_t * p_src, 00942 pstorage_size_t size, 00943 pstorage_size_t offset) 00944 { 00945 VERIFY_MODULE_INITIALIZED(); 00946 NULL_PARAM_CHECK(p_src); 00947 NULL_PARAM_CHECK(p_dest); 00948 MODULE_ID_RANGE_CHECK(p_dest); 00949 BLOCK_ID_RANGE_CHECK(p_dest); 00950 SIZE_CHECK(p_dest, size); 00951 OFFSET_CHECK(p_dest, offset,size); 00952 00953 // Verify word alignment. 00954 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 00955 { 00956 return NRF_ERROR_INVALID_ADDR; 00957 } 00958 00959 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 00960 { 00961 return NRF_ERROR_INVALID_ADDR; 00962 } 00963 00964 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 00965 } 00966 00967 00968 uint32_t pstorage_update(pstorage_handle_t * p_dest, 00969 uint8_t * p_src, 00970 pstorage_size_t size, 00971 pstorage_size_t offset) 00972 { 00973 VERIFY_MODULE_INITIALIZED(); 00974 NULL_PARAM_CHECK(p_src); 00975 NULL_PARAM_CHECK(p_dest); 00976 MODULE_ID_RANGE_CHECK(p_dest); 00977 BLOCK_ID_RANGE_CHECK(p_dest); 00978 SIZE_CHECK(p_dest, size); 00979 OFFSET_CHECK(p_dest, offset, size); 00980 00981 // Verify word alignment. 00982 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 00983 { 00984 return NRF_ERROR_INVALID_ADDR; 00985 } 00986 00987 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 00988 { 00989 return NRF_ERROR_INVALID_ADDR; 00990 } 00991 00992 return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset); 00993 } 00994 00995 00996 uint32_t pstorage_load(uint8_t * p_dest, 00997 pstorage_handle_t * p_src, 00998 pstorage_size_t size, 00999 pstorage_size_t offset) 01000 { 01001 VERIFY_MODULE_INITIALIZED(); 01002 NULL_PARAM_CHECK(p_src); 01003 NULL_PARAM_CHECK(p_dest); 01004 MODULE_ID_RANGE_CHECK(p_src); 01005 BLOCK_ID_RANGE_CHECK(p_src); 01006 SIZE_CHECK(p_src, size); 01007 OFFSET_CHECK(p_src, offset, size); 01008 01009 // Verify word alignment. 01010 if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset))) 01011 { 01012 return NRF_ERROR_INVALID_ADDR; 01013 } 01014 01015 if ((!is_word_aligned((uint32_t *)p_src->block_id))) 01016 { 01017 return NRF_ERROR_INVALID_ADDR; 01018 } 01019 01020 memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size); 01021 01022 m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size); 01023 01024 return NRF_SUCCESS; 01025 } 01026 01027 01028 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01029 { 01030 uint32_t retval; 01031 01032 VERIFY_MODULE_INITIALIZED(); 01033 NULL_PARAM_CHECK(p_dest); 01034 MODULE_ID_RANGE_CHECK(p_dest); 01035 BLOCK_ID_RANGE_CHECK(p_dest); 01036 01037 if ((!is_word_aligned((uint32_t *)p_dest->block_id))) 01038 { 01039 return NRF_ERROR_INVALID_ADDR; 01040 } 01041 01042 if ( 01043 !( 01044 ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) % 01045 m_app_table[p_dest->module_id].block_size) == 0 01046 ) 01047 ) 01048 { 01049 return NRF_ERROR_INVALID_PARAM; 01050 } 01051 01052 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01053 01054 return retval; 01055 } 01056 01057 01058 uint32_t pstorage_access_status_get(uint32_t * p_count) 01059 { 01060 VERIFY_MODULE_INITIALIZED(); 01061 NULL_PARAM_CHECK(p_count); 01062 01063 (*p_count) = m_cmd_queue.count; 01064 01065 return NRF_SUCCESS; 01066 } 01067 01068 #ifdef PSTORAGE_RAW_MODE_ENABLE 01069 01070 01071 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param, 01072 pstorage_handle_t * p_block_id) 01073 { 01074 VERIFY_MODULE_INITIALIZED(); 01075 NULL_PARAM_CHECK(p_module_param); 01076 NULL_PARAM_CHECK(p_block_id); 01077 NULL_PARAM_CHECK(p_module_param->cb); 01078 01079 if (m_raw_app_table.cb != NULL) 01080 { 01081 return NRF_ERROR_NO_MEM; 01082 } 01083 01084 p_block_id->module_id = RAW_MODE_APP_ID; 01085 m_raw_app_table.cb = p_module_param->cb; 01086 01087 return NRF_SUCCESS; 01088 } 01089 01090 01091 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest, 01092 uint8_t * p_src, 01093 pstorage_size_t size, 01094 pstorage_size_t offset) 01095 { 01096 VERIFY_MODULE_INITIALIZED(); 01097 NULL_PARAM_CHECK(p_src); 01098 NULL_PARAM_CHECK(p_dest); 01099 MODULE_RAW_ID_RANGE_CHECK(p_dest); 01100 01101 // Verify word alignment. 01102 if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset))) 01103 { 01104 return NRF_ERROR_INVALID_ADDR; 01105 } 01106 01107 return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset); 01108 } 01109 01110 01111 uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size) 01112 { 01113 uint32_t retval; 01114 01115 VERIFY_MODULE_INITIALIZED(); 01116 NULL_PARAM_CHECK(p_dest); 01117 MODULE_RAW_ID_RANGE_CHECK(p_dest); 01118 01119 retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0); 01120 01121 return retval; 01122 } 01123 01124 #endif // PSTORAGE_RAW_MODE_ENABLE 01125 01126 #endif /* #if NEED_PSTORAGE */
Generated on Tue Jul 12 2022 14:11:57 by 1.7.2