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