pstorage.c 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  1. /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include "pstorage.h"
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <string.h>
  16. #include "nordic_common.h"
  17. #include "nrf_error.h"
  18. #include "nrf_assert.h"
  19. #include "nrf.h"
  20. #include "nrf_soc.h"
  21. #include "app_util.h"
  22. #include "app_error.h"
  23. #define INVALID_OPCODE 0x00 /**< Invalid op code identifier. */
  24. #define SOC_MAX_WRITE_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
  25. #define RAW_MODE_APP_ID (PSTORAGE_NUM_OF_PAGES + 1) /**< Application id for raw mode. */
  26. #if defined(NRF52)
  27. #define SD_CMD_MAX_TRIES 1000 /**< Number of times to try a softdevice flash operatoion, specific for nRF52 to account for longest time of flash page erase*/
  28. #else
  29. #define SD_CMD_MAX_TRIES 3 /**< Number of times to try a softdevice flash operation when the @ref NRF_EVT_FLASH_OPERATION_ERROR sys_evt is received. */
  30. #endif /* defined(NRF52) */
  31. #define MASK_TAIL_SWAP_DONE (1 << 0) /**< Flag for checking if the tail restore area has been written to swap page. */
  32. #define MASK_SINGLE_PAGE_OPERATION (1 << 1) /**< Flag for checking if command is a single flash page operation. */
  33. #define MASK_MODULE_INITIALIZED (1 << 2) /**< Flag for checking if the module has been initialized. */
  34. #define MASK_FLASH_API_ERR_BUSY (1 << 3) /**< Flag for checking if flash API returned NRF_ERROR_BUSY. */
  35. /**
  36. * @defgroup api_param_check API Parameters check macros.
  37. *
  38. * @details Macros that verify parameters passed to the module in the APIs. These macros
  39. * could be mapped to nothing in final code versions to save execution and size.
  40. *
  41. * @{
  42. */
  43. /**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL.
  44. */
  45. #define NULL_PARAM_CHECK(PARAM) \
  46. if ((PARAM) == NULL) \
  47. { \
  48. return NRF_ERROR_NULL; \
  49. }
  50. /**@brief Verifies that the module identifier supplied by the application is within permissible
  51. * range.
  52. */
  53. #define MODULE_ID_RANGE_CHECK(ID) \
  54. if ((((ID)->module_id) >= PSTORAGE_NUM_OF_PAGES) || \
  55. (m_app_table[(ID)->module_id].cb == NULL)) \
  56. { \
  57. return NRF_ERROR_INVALID_PARAM; \
  58. }
  59. /**@brief Verifies that the block identifier supplied by the application is within the permissible
  60. * range.
  61. */
  62. #define BLOCK_ID_RANGE_CHECK(ID) \
  63. if (((ID)->block_id) >= (m_app_table[(ID)->module_id].base_id + \
  64. (m_app_table[(ID)->module_id].block_count * MODULE_BLOCK_SIZE(ID)))) \
  65. { \
  66. return NRF_ERROR_INVALID_PARAM; \
  67. }
  68. /**@brief Verifies that the block size requested by the application can be supported by the module.
  69. */
  70. #define BLOCK_SIZE_CHECK(X) \
  71. if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE)) \
  72. { \
  73. return NRF_ERROR_INVALID_PARAM; \
  74. }
  75. /**@brief Verifies the block size requested by the application in registration API.
  76. */
  77. #define BLOCK_COUNT_CHECK(COUNT, SIZE) \
  78. if (((COUNT) == 0) || \
  79. ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR))) \
  80. { \
  81. return NRF_ERROR_INVALID_PARAM; \
  82. }
  83. /**@brief Verifies the size parameter provided by the application in API.
  84. */
  85. #define SIZE_CHECK(ID, SIZE) \
  86. if(((SIZE) == 0) || ((SIZE) > MODULE_BLOCK_SIZE(ID))) \
  87. { \
  88. return NRF_ERROR_INVALID_PARAM; \
  89. }
  90. /**@brief Verifies the offset parameter provided by the application in API.
  91. */
  92. #define OFFSET_CHECK(ID, OFFSET, SIZE) \
  93. if(((SIZE) + (OFFSET)) > MODULE_BLOCK_SIZE(ID)) \
  94. { \
  95. return NRF_ERROR_INVALID_PARAM; \
  96. }
  97. #ifdef PSTORAGE_RAW_MODE_ENABLE
  98. /**@brief Verifies the module identifier supplied by the application.
  99. */
  100. #define MODULE_RAW_HANDLE_CHECK(ID) \
  101. if ((((ID)->module_id) != RAW_MODE_APP_ID)) \
  102. { \
  103. return NRF_ERROR_INVALID_PARAM; \
  104. }
  105. #endif // PSTORAGE_RAW_MODE_ENABLE
  106. /**@} */
  107. /**@brief Verify module's initialization status.
  108. *
  109. * @details Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE when a
  110. * module API is called without initializing the module.
  111. */
  112. #define VERIFY_MODULE_INITIALIZED() \
  113. do \
  114. { \
  115. if (!(m_flags & MASK_MODULE_INITIALIZED)) \
  116. { \
  117. return NRF_ERROR_INVALID_STATE; \
  118. } \
  119. } while(0)
  120. /**@brief Macro to fetch the block size registered for the module. */
  121. #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
  122. /**@brief Main state machine of the component. */
  123. typedef enum
  124. {
  125. STATE_IDLE, /**< State for being idle (no command execution in progress). */
  126. STATE_STORE, /**< State for storing data when using store/update API. */
  127. STATE_DATA_ERASE_WITH_SWAP, /**< State for erasing the data page when using update/clear API when use of swap page is required. */
  128. STATE_DATA_ERASE, /**< State for erasing the data page when using update/clear API without the need to use the swap page. */
  129. STATE_ERROR /**< State entered when command processing is terminated abnormally. */
  130. } pstorage_state_t;
  131. /**@brief Sub state machine contained by @ref STATE_DATA_ERASE_WITH_SWAP super state machine. */
  132. typedef enum
  133. {
  134. STATE_ERASE_SWAP, /**< State for erasing the swap page when using the update/clear API. */
  135. STATE_WRITE_DATA_TO_SWAP, /**< State for writing the data page into the swap page when using update/clear API. */
  136. STATE_ERASE_DATA_PAGE, /**< State for erasing data page when using update/clear API. */
  137. STATE_RESTORE_TAIL, /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
  138. STATE_RESTORE_HEAD, /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
  139. SWAP_SUB_STATE_MAX /**< Enumeration upper bound. */
  140. } flash_swap_sub_state_t;
  141. /**@brief Application registration information.
  142. *
  143. * @details Defines application specific information that the application needs to maintain to be able
  144. * to process requests from each one of them.
  145. */
  146. typedef struct
  147. {
  148. pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of result of flash access. */
  149. pstorage_block_t base_id; /**< Base block ID assigned to the module. */
  150. pstorage_size_t block_size; /**< Size of block for the module. */
  151. pstorage_size_t block_count; /**< Number of blocks requested by the application. */
  152. } pstorage_module_table_t;
  153. #ifdef PSTORAGE_RAW_MODE_ENABLE
  154. /**@brief Application registration information.
  155. *
  156. * @details Defines application specific information that the application registered for raw mode.
  157. */
  158. typedef struct
  159. {
  160. pstorage_ntf_cb_t cb; /**< Callback registered with the module to be notified of the result of flash access. */
  161. } pstorage_raw_module_table_t;
  162. #endif // PSTORAGE_RAW_MODE_ENABLE
  163. /**@brief Defines command queue element.
  164. *
  165. * @details Defines command queue element. Each element encapsulates needed information to process
  166. * a flash access command.
  167. */
  168. typedef struct
  169. {
  170. uint8_t op_code; /**< Identifies the flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
  171. pstorage_size_t size; /**< Identifies the size in bytes requested for the operation. */
  172. pstorage_size_t offset; /**< Offset requested by the application for the access operation. */
  173. pstorage_handle_t storage_addr; /**< Address/Identifier for persistent memory. */
  174. uint8_t * p_data_addr; /**< Address/Identifier for data memory. This is assumed to be resident memory. */
  175. } cmd_queue_element_t;
  176. /**@brief Defines command queue, an element is free if the op_code field is not invalid.
  177. *
  178. * @details Defines commands enqueued for flash access. At any point in time, this queue has one or
  179. * more flash access operations pending if the count field is not zero. When the queue is
  180. * not empty, the rp (read pointer) field points to the flash access command in progress
  181. * or, if none is in progress, the command to be requested next. The queue implements a
  182. * simple first in first out algorithm. Data addresses are assumed to be resident.
  183. */
  184. typedef struct
  185. {
  186. uint8_t rp; /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
  187. uint8_t count; /**< Number of elements in the queue. */
  188. cmd_queue_element_t cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
  189. } cmd_queue_t;
  190. static cmd_queue_t m_cmd_queue; /**< Flash operation request queue. */
  191. static pstorage_size_t m_next_app_instance; /**< Points to the application module instance that can be allocated next. */
  192. 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 that can span across flash pages. */
  193. static pstorage_state_t m_state; /**< Main state tracking variable. */
  194. static flash_swap_sub_state_t m_swap_sub_state; /**< Flash swap erase when swap used state tracking variable. */
  195. static uint32_t m_head_word_size; /**< Head restore area size in words. */
  196. static uint32_t m_tail_word_size; /**< Tail restore area size in words. */
  197. static uint32_t m_current_page_id; /**< Variable for tracking the flash page being processed. */
  198. static uint32_t m_num_of_command_retries; /**< Variable for tracking flash operation retries upon flash operation failures. */
  199. static pstorage_module_table_t m_app_table[PSTORAGE_NUM_OF_PAGES]; /**< Registered application information table. */
  200. static uint32_t m_num_of_bytes_written; /**< Variable for tracking the number of bytes written by the store operation. */
  201. static uint32_t m_app_data_size; /**< Variable for storing the application command size parameter internally. */
  202. static uint32_t m_flags = 0; /**< Storage for boolean flags for state tracking. */
  203. #ifdef PSTORAGE_RAW_MODE_ENABLE
  204. static pstorage_raw_module_table_t m_raw_app_table; /**< Registered application information table for raw mode. */
  205. #endif // PSTORAGE_RAW_MODE_ENABLE
  206. // Required forward declarations.
  207. static void cmd_process(void);
  208. static void store_operation_execute(void);
  209. static void app_notify(uint32_t result, cmd_queue_element_t * p_elem);
  210. static void cmd_queue_element_init(uint32_t index);
  211. static void cmd_queue_dequeue(void);
  212. static void sm_state_change(pstorage_state_t new_state);
  213. static void swap_sub_state_state_change(flash_swap_sub_state_t new_state);
  214. /**@brief Function for consuming a command queue element.
  215. *
  216. * @details Function for consuming a command queue element, which has been fully processed.
  217. */
  218. static void command_queue_element_consume(void)
  219. {
  220. // Initialize/free the element as it is now processed.
  221. cmd_queue_element_init(m_cmd_queue.rp);
  222. // Adjust command queue state tracking variables.
  223. --(m_cmd_queue.count);
  224. if (++(m_cmd_queue.rp) == PSTORAGE_CMD_QUEUE_SIZE)
  225. {
  226. m_cmd_queue.rp = 0;
  227. }
  228. }
  229. /**@brief Function for executing the finalization procedure for the command executed.
  230. *
  231. * @details Function for executing the finalization procedure for command executed, which includes
  232. * notifying the application of command completion, consuming the command queue element,
  233. * and changing the internal state.
  234. */
  235. static void command_end_procedure_run(void)
  236. {
  237. app_notify(NRF_SUCCESS, &m_cmd_queue.cmd[m_cmd_queue.rp]);
  238. command_queue_element_consume();
  239. sm_state_change(STATE_IDLE);
  240. }
  241. /**@brief Function for idle state entry actions.
  242. *
  243. * @details Function for idle state entry actions, which include resetting relevant state data and
  244. * scheduling any possible queued flash access operation.
  245. */
  246. static void state_idle_entry_run(void)
  247. {
  248. m_num_of_command_retries = 0;
  249. m_num_of_bytes_written = 0;
  250. // Schedule any possible queued flash access operation.
  251. cmd_queue_dequeue();
  252. }
  253. /**@brief Function for notifying an application of command completion and transitioning to an error
  254. * state.
  255. *
  256. * @param[in] result Result code of the operation for the application.
  257. */
  258. static void app_notify_error_state_transit(uint32_t result)
  259. {
  260. app_notify(result, &m_cmd_queue.cmd[m_cmd_queue.rp]);
  261. sm_state_change(STATE_ERROR);
  262. }
  263. /**@brief Function for processing flash API error code.
  264. *
  265. * @param[in] err_code Error code from the flash API.
  266. */
  267. static void flash_api_err_code_process(uint32_t err_code)
  268. {
  269. switch (err_code)
  270. {
  271. case NRF_SUCCESS:
  272. break;
  273. case NRF_ERROR_BUSY:
  274. // Flash access operation was not accepted and must be reissued upon flash operation
  275. // complete event.
  276. m_flags |= MASK_FLASH_API_ERR_BUSY;
  277. break;
  278. default:
  279. // Complete the operation with appropriate result code and transit to an error state.
  280. app_notify_error_state_transit(err_code);
  281. break;
  282. }
  283. }
  284. /**@brief Function for writing data to flash.
  285. *
  286. * @param[in] p_dst Pointer to start of flash location to be written.
  287. * @param[in] p_src Pointer to buffer with data to be written.
  288. * @param[in] size_in_words Number of 32-bit words to write.
  289. */
  290. static void flash_write(uint32_t * const p_dst,
  291. uint32_t const * const p_src,
  292. uint32_t size_in_words)
  293. {
  294. flash_api_err_code_process(sd_flash_write(p_dst, p_src, size_in_words));
  295. }
  296. /**@brief Function for writing data to flash upon store command.
  297. *
  298. * @details Function for writing data to flash upon executing store command. Data is written to
  299. * flash in reverse order, meaning starting at the end. If the data that is to be written
  300. * is greater than the flash page size, it will be fragmented to fit the flash page size.
  301. */
  302. static void store_cmd_flash_write_execute(void)
  303. {
  304. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  305. if (p_cmd->size > SOC_MAX_WRITE_SIZE)
  306. {
  307. const uint32_t offset = p_cmd->size - PSTORAGE_FLASH_PAGE_SIZE;
  308. flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset + offset),
  309. (uint32_t *)(p_cmd->p_data_addr + offset),
  310. PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
  311. m_num_of_bytes_written = PSTORAGE_FLASH_PAGE_SIZE;
  312. }
  313. else
  314. {
  315. flash_write((uint32_t *)(p_cmd->storage_addr.block_id + p_cmd->offset),
  316. (uint32_t *)(p_cmd->p_data_addr),
  317. p_cmd->size / sizeof(uint32_t));
  318. m_num_of_bytes_written = p_cmd->size;
  319. }
  320. }
  321. /**@brief Function for store state entry action.
  322. *
  323. * @details Function for store state entry action, which includes writing data to a flash page.
  324. */
  325. static void state_store_entry_run(void)
  326. {
  327. store_cmd_flash_write_execute();
  328. }
  329. /**@brief Function for data erase with swap state entry actions.
  330. *
  331. * @details Function for data erase with swap state entry actions. This includes adjusting relevant
  332. * state and data variables and transitioning to the correct sub state.
  333. */
  334. static void state_data_erase_swap_entry_run(void)
  335. {
  336. m_flags &= ~MASK_TAIL_SWAP_DONE;
  337. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  338. const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
  339. const uint32_t clear_start_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
  340. m_current_page_id = clear_start_page_id;
  341. // @note: No need to include p_cmd->offset when calculating clear_end_page_id as:
  342. // - clear API does not include offset parameter
  343. // - update and store APIs are limited to operate on single block boundary thus the boolean
  344. // clause ((m_head_word_size == 0) && is_more_than_one_page) below in this function will never
  345. // evaluate as true as if is_more_than_one_page == true m_head_word_size is always != 0
  346. const uint32_t clear_end_page_id = (cmd_block_id + p_cmd->size - 1u) /
  347. PSTORAGE_FLASH_PAGE_SIZE;
  348. if (clear_start_page_id == clear_end_page_id)
  349. {
  350. m_flags |= MASK_SINGLE_PAGE_OPERATION;
  351. }
  352. else
  353. {
  354. m_flags &= ~MASK_SINGLE_PAGE_OPERATION;
  355. }
  356. if ((m_head_word_size == 0) && !(m_flags & MASK_SINGLE_PAGE_OPERATION))
  357. {
  358. // No head restore required and clear/update area is shared by multiple flash pages, which
  359. // means the current flash page does not have any tail area to restore. You can proceed with
  360. // data page erase directly as no swap is needed for the current flash page.
  361. swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
  362. }
  363. else
  364. {
  365. swap_sub_state_state_change(STATE_ERASE_SWAP);
  366. }
  367. }
  368. /**@brief Function for erasing flash page.
  369. *
  370. * @param[in] page_number Page number of the page to be erased.
  371. */
  372. static void flash_page_erase(uint32_t page_number)
  373. {
  374. flash_api_err_code_process(sd_flash_page_erase(page_number));
  375. }
  376. /**@brief Function for data erase state entry action.
  377. *
  378. * @details Function for data erase state entry action, which includes erasing the data flash page.
  379. */
  380. static void state_data_erase_entry_run(void)
  381. {
  382. flash_page_erase(m_current_page_id);
  383. }
  384. /**@brief Function for dispatching the correct application main state entry action.
  385. */
  386. static void state_entry_action_run(void)
  387. {
  388. switch (m_state)
  389. {
  390. case STATE_IDLE:
  391. state_idle_entry_run();
  392. break;
  393. case STATE_STORE:
  394. state_store_entry_run();
  395. break;
  396. case STATE_DATA_ERASE_WITH_SWAP:
  397. state_data_erase_swap_entry_run();
  398. break;
  399. case STATE_DATA_ERASE:
  400. state_data_erase_entry_run();
  401. break;
  402. default:
  403. // No action needed.
  404. break;
  405. }
  406. }
  407. /**@brief Function for changing application main state and dispatching state entry action.
  408. *
  409. * @param[in] new_state New application main state to transit to.
  410. */
  411. static void sm_state_change(pstorage_state_t new_state)
  412. {
  413. m_state = new_state;
  414. state_entry_action_run();
  415. }
  416. /**@brief Function for swap erase state entry action.
  417. *
  418. * @details Function for swap erase state entry action, which includes erasing swap flash
  419. * page.
  420. */
  421. static void state_swap_erase_entry_run(void)
  422. {
  423. flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
  424. }
  425. /**@brief Function for write data to the swap state entry action.
  426. *
  427. * @details Function for write data to the swap state entry action, which includes writing the
  428. * current data page to the swap flash page.
  429. */
  430. static void state_write_data_swap_entry_run(void)
  431. {
  432. // @note: There is room for further optimization here as there is only need to write the
  433. // whole flash page to swap area if there is both head and tail area to be restored. In any
  434. // other case we can omit some data from the head or end of the page as that is the clear area.
  435. flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
  436. (uint32_t *)(m_current_page_id * PSTORAGE_FLASH_PAGE_SIZE),
  437. PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
  438. }
  439. /**@brief Function for erase data page state entry action.
  440. *
  441. * @details Function for erase data page state entry action, which includes erasing the data flash
  442. * page.
  443. */
  444. static void state_erase_data_page_entry_run(void)
  445. {
  446. flash_page_erase(m_current_page_id);
  447. }
  448. /**@brief Function for restore tail state entry action.
  449. *
  450. * @details Function for restore tail state entry action, which includes writing the tail section
  451. * back from swap to the data page.
  452. */
  453. static void state_restore_tail_entry_run(void)
  454. {
  455. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  456. const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
  457. const uint32_t tail_offset = (cmd_block_id + p_cmd->size + p_cmd->offset) %
  458. PSTORAGE_FLASH_PAGE_SIZE;
  459. flash_write((uint32_t *)(cmd_block_id + p_cmd->size + p_cmd->offset),
  460. (uint32_t *)(PSTORAGE_SWAP_ADDR + tail_offset),
  461. m_tail_word_size);
  462. }
  463. /**@brief Function for restore head state entry action.
  464. *
  465. * @details Function for restore head state entry action, which includes writing the head section
  466. * back from swap to the data page.
  467. */
  468. static void state_restore_head_entry_run(void)
  469. {
  470. flash_write((uint32_t *)((m_current_page_id - 1u) * PSTORAGE_FLASH_PAGE_SIZE),
  471. (uint32_t *)PSTORAGE_SWAP_ADDR,
  472. m_head_word_size);
  473. }
  474. /**@brief Function for dispatching the correct swap sub state entry action.
  475. */
  476. static void swap_sub_state_entry_action_run(void)
  477. {
  478. static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) =
  479. {
  480. state_swap_erase_entry_run,
  481. state_write_data_swap_entry_run,
  482. state_erase_data_page_entry_run,
  483. state_restore_tail_entry_run,
  484. state_restore_head_entry_run
  485. };
  486. swap_sub_state_sm_lut[m_swap_sub_state]();
  487. }
  488. /**@brief Function for changing the swap sub state and dispatching state entry action.
  489. *
  490. * @param[in] new_state New swap sub state to transit to.
  491. */
  492. static void swap_sub_state_state_change(flash_swap_sub_state_t new_state)
  493. {
  494. m_swap_sub_state = new_state;
  495. swap_sub_state_entry_action_run();
  496. }
  497. /**@brief Function for initializing the command queue element.
  498. *
  499. * @param[in] index Index of the element to be initialized.
  500. */
  501. static void cmd_queue_element_init(uint32_t index)
  502. {
  503. // Internal function and checks on range of index can be avoided.
  504. m_cmd_queue.cmd[index].op_code = INVALID_OPCODE;
  505. m_cmd_queue.cmd[index].size = 0;
  506. m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_NUM_OF_PAGES;
  507. m_cmd_queue.cmd[index].storage_addr.block_id = 0;
  508. m_cmd_queue.cmd[index].p_data_addr = NULL;
  509. m_cmd_queue.cmd[index].offset = 0;
  510. }
  511. /**@brief Function for initializing the command queue.
  512. */
  513. static void cmd_queue_init(void)
  514. {
  515. m_cmd_queue.rp = 0;
  516. m_cmd_queue.count = 0;
  517. for (uint32_t cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; ++cmd_index)
  518. {
  519. cmd_queue_element_init(cmd_index);
  520. }
  521. }
  522. /**@brief Function for enqueuing, and possibly dispatching, a flash access operation.
  523. *
  524. * @param[in] opcode Identifies the operation requested to be enqueued.
  525. * @param[in] p_storage_addr Identifies the module and flash address on which the operation is
  526. * requested.
  527. * @param[in] p_data_addr Identifies the data address for flash access.
  528. * @param[in] size Size in bytes of data requested for the access operation.
  529. * @param[in] offset Offset within the flash memory block at which operation is requested.
  530. *
  531. * @retval NRF_SUCCESS Upon success.
  532. * @retval NRF_ERROR_NO_MEM Upon failure, when no space is available in the command queue.
  533. */
  534. static uint32_t cmd_queue_enqueue(uint8_t opcode,
  535. pstorage_handle_t * p_storage_addr,
  536. uint8_t * p_data_addr,
  537. pstorage_size_t size,
  538. pstorage_size_t offset)
  539. {
  540. uint32_t err_code;
  541. if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
  542. {
  543. // Enqueue the command if it the queue is not full.
  544. uint32_t write_index = m_cmd_queue.rp + m_cmd_queue.count;
  545. if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
  546. {
  547. write_index -= PSTORAGE_CMD_QUEUE_SIZE;
  548. }
  549. m_cmd_queue.cmd[write_index].op_code = opcode;
  550. m_cmd_queue.cmd[write_index].p_data_addr = p_data_addr;
  551. m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
  552. m_cmd_queue.cmd[write_index].size = size;
  553. m_cmd_queue.cmd[write_index].offset = offset;
  554. m_cmd_queue.count++;
  555. if (m_state == STATE_IDLE)
  556. {
  557. cmd_process();
  558. }
  559. err_code = NRF_SUCCESS;
  560. }
  561. else
  562. {
  563. err_code = NRF_ERROR_NO_MEM;
  564. }
  565. return err_code;
  566. }
  567. /**@brief Function for dequeing a possible pending flash access operation.
  568. */
  569. static void cmd_queue_dequeue(void)
  570. {
  571. if ((m_cmd_queue.count != 0))
  572. {
  573. cmd_process();
  574. }
  575. }
  576. /**@brief Function for notifying an application of command completion.
  577. *
  578. * @param[in] result Result code of the operation for the application.
  579. * @param[in] p_elem Pointer to the command queue element for which this result was received.
  580. */
  581. static void app_notify(uint32_t result, cmd_queue_element_t * p_elem)
  582. {
  583. pstorage_ntf_cb_t ntf_cb;
  584. const uint8_t op_code = p_elem->op_code;
  585. #ifdef PSTORAGE_RAW_MODE_ENABLE
  586. if (p_elem->storage_addr.module_id == RAW_MODE_APP_ID)
  587. {
  588. ntf_cb = m_raw_app_table.cb;
  589. }
  590. else
  591. #endif // PSTORAGE_RAW_MODE_ENABLE
  592. {
  593. ntf_cb = m_app_table[p_elem->storage_addr.module_id].cb;
  594. }
  595. ntf_cb(&p_elem->storage_addr, op_code, result, p_elem->p_data_addr, m_app_data_size);
  596. }
  597. /**@brief Function for evaluating if a data page swap is required for the tail section on the
  598. * current page.
  599. *
  600. * @retval true If data page swap is required.
  601. * @retval false If data page swap is not required.
  602. */
  603. static bool is_tail_data_page_swap_required(void)
  604. {
  605. bool ret_value;
  606. // Extract id of the last page command is executed upon.
  607. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  608. const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
  609. const uint32_t last_page_id = (cmd_block_id + p_cmd->size + p_cmd->offset - 1u) /
  610. PSTORAGE_FLASH_PAGE_SIZE;
  611. // If tail section area exists and the current page is the last page then tail data page swap is
  612. // required.
  613. if ((m_tail_word_size != 0) && (m_current_page_id == last_page_id))
  614. {
  615. ret_value = true;
  616. }
  617. else
  618. {
  619. ret_value = false;
  620. }
  621. return ret_value;
  622. }
  623. /**@brief Function for performing post processing for the update and clear commands.
  624. *
  625. * @details Function for performing post processing for the update and clear commands, which implies
  626. * executing the correct execution path depending on the command.
  627. */
  628. static void clear_post_processing_run(void)
  629. {
  630. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  631. if (p_cmd->op_code != PSTORAGE_UPDATE_OP_CODE)
  632. {
  633. command_end_procedure_run();
  634. }
  635. else
  636. {
  637. store_operation_execute();
  638. }
  639. }
  640. /**@brief Function for doing swap sub state exit action.
  641. */
  642. static void swap_sub_sm_exit_action_run(void)
  643. {
  644. clear_post_processing_run();
  645. }
  646. /**@brief Function for evaluating if the page erase operation is required for the current page.
  647. *
  648. * @retval true If page erase is required.
  649. * @retval false If page erase is not required.
  650. */
  651. static bool is_page_erase_required(void)
  652. {
  653. bool ret;
  654. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  655. const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
  656. const uint32_t id_last_page_to_be_cleared = (cmd_block_id + p_cmd->size +
  657. p_cmd->offset - 1u) /
  658. PSTORAGE_FLASH_PAGE_SIZE;
  659. // True if:
  660. // - current page is not the last page OR
  661. // - current page is the last page AND no tail exists
  662. if ((m_current_page_id < id_last_page_to_be_cleared) ||
  663. ((m_current_page_id == id_last_page_to_be_cleared) && (m_tail_word_size == 0)))
  664. {
  665. ret = true;
  666. }
  667. else
  668. {
  669. ret = false;
  670. }
  671. return ret;
  672. }
  673. /**@brief Function for reissuing the last flash operation request, which was rejected by the flash
  674. * API, in swap sub sate.
  675. */
  676. static void swap_sub_state_err_busy_process(void)
  677. {
  678. // Reissue the request by doing a self transition to the current state.
  679. m_flags &= ~MASK_FLASH_API_ERR_BUSY;
  680. swap_sub_state_state_change(m_swap_sub_state);
  681. }
  682. /**@brief Function for doing restore head state action upon flash operation success event.
  683. *
  684. * @details Function for doing restore head state action upon flash operation success event, which
  685. * includes making a state transition depending on the current state.
  686. */
  687. static void head_restore_state_run(void)
  688. {
  689. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  690. {
  691. if (is_tail_data_page_swap_required())
  692. {
  693. // Additional data page needs to be swapped for tail section as we are clearing a block,
  694. // which is shared between 2 flash pages.
  695. // Adjust variables to ensure correct state transition path is taken after the tail
  696. // section swap has completed.
  697. m_head_word_size = 0;
  698. m_flags |= MASK_TAIL_SWAP_DONE;
  699. swap_sub_state_state_change(STATE_ERASE_SWAP);
  700. }
  701. else if (is_page_erase_required())
  702. {
  703. // Additional page erase operation is required.
  704. // Adjust variable to ensure correct state transition path is taken after the additional
  705. // page erase operation has completed.
  706. m_head_word_size = 0;
  707. swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
  708. }
  709. else if (m_tail_word_size != 0)
  710. {
  711. // Proceed with restoring tail from swap to data page.
  712. swap_sub_state_state_change(STATE_RESTORE_TAIL);
  713. }
  714. else
  715. {
  716. // Swap statemachine execution end reached.
  717. swap_sub_sm_exit_action_run();
  718. }
  719. }
  720. else
  721. {
  722. // As operation request was rejected by the flash API reissue the request.
  723. swap_sub_state_err_busy_process();
  724. }
  725. }
  726. /**@brief Function for doing restore tail state action upon flash operation success event.
  727. */
  728. static void tail_restore_state_run(void)
  729. {
  730. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  731. {
  732. swap_sub_sm_exit_action_run();
  733. }
  734. else
  735. {
  736. // As operation request was rejected by the flash API reissue the request.
  737. swap_sub_state_err_busy_process();
  738. }
  739. }
  740. /**@brief Function for doing data page erase state action upon a flash operation success event.
  741. *
  742. * @details Function for doing data page erase state action upon a flash operation success event,
  743. * which includes making a state transit to a new state depending on the current state.
  744. */
  745. static void data_page_erase_state_run(void)
  746. {
  747. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  748. {
  749. ++m_current_page_id;
  750. if (m_head_word_size != 0)
  751. {
  752. swap_sub_state_state_change(STATE_RESTORE_HEAD);
  753. }
  754. else if (is_page_erase_required())
  755. {
  756. // Additional page erase operation is required.
  757. swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
  758. }
  759. else if (m_tail_word_size != 0)
  760. {
  761. if (!(m_flags & MASK_TAIL_SWAP_DONE))
  762. {
  763. // Tail area restore is required and we have not yet written the relevant data page
  764. // to swap area. Start the process of writing the data page to swap.
  765. m_flags |= MASK_TAIL_SWAP_DONE;
  766. swap_sub_state_state_change(STATE_ERASE_SWAP);
  767. }
  768. else
  769. {
  770. // Tail area restore is required and we have already written the relevant data page
  771. // to swap area. Proceed by restoring the tail area.
  772. swap_sub_state_state_change(STATE_RESTORE_TAIL);
  773. }
  774. }
  775. else
  776. {
  777. swap_sub_sm_exit_action_run();
  778. }
  779. }
  780. else
  781. {
  782. // As operation request was rejected by the flash API reissue the request.
  783. swap_sub_state_err_busy_process();
  784. }
  785. }
  786. /**@brief Function for doing data to swap write state action upon flash operation success event.
  787. */
  788. static void data_to_swap_write_state_run(void)
  789. {
  790. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  791. {
  792. // If the operation is executed only on 1 single flash page it automatically means that tail
  793. // area is written to the swap, which we store to flags.
  794. if (m_flags & MASK_SINGLE_PAGE_OPERATION)
  795. {
  796. m_flags |= MASK_TAIL_SWAP_DONE;
  797. }
  798. swap_sub_state_state_change(STATE_ERASE_DATA_PAGE);
  799. }
  800. else
  801. {
  802. // As operation request was rejected by the flash API reissue the request.
  803. swap_sub_state_err_busy_process();
  804. }
  805. }
  806. /**@brief Function for doing swap erase state action upon flash operation success event.
  807. */
  808. static void swap_erase_state_run(void)
  809. {
  810. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  811. {
  812. swap_sub_state_state_change(STATE_WRITE_DATA_TO_SWAP);
  813. }
  814. else
  815. {
  816. // As operation request was rejected by the flash API reissue the request.
  817. swap_sub_state_err_busy_process();
  818. }
  819. }
  820. /**@brief Function for dispatching the correct state action for data erase with a swap composite
  821. * state upon a flash operation success event.
  822. */
  823. static void swap_sub_state_sm_run(void)
  824. {
  825. static void (* const swap_sub_state_sm_lut[SWAP_SUB_STATE_MAX])(void) =
  826. {
  827. swap_erase_state_run,
  828. data_to_swap_write_state_run,
  829. data_page_erase_state_run,
  830. tail_restore_state_run,
  831. head_restore_state_run
  832. };
  833. swap_sub_state_sm_lut[m_swap_sub_state]();
  834. }
  835. /**@brief Function for reissuing the last flash operation request, which was rejected by the flash
  836. * API, in main sate.
  837. */
  838. static void main_state_err_busy_process(void)
  839. {
  840. // Reissue the request by doing a self transition to the current state.
  841. m_flags &= ~MASK_FLASH_API_ERR_BUSY;
  842. sm_state_change(m_state);
  843. }
  844. /**@brief Function for doing erase state action upon flash operation success event.
  845. *
  846. * @details Function for doing erase state action upon flash operation success event, which includes
  847. * making a state transition depending on the current state.
  848. */
  849. static void erase_sub_state_sm_run(void)
  850. {
  851. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  852. {
  853. // Clear operation request has succeeded.
  854. ++m_current_page_id;
  855. if (!is_page_erase_required())
  856. {
  857. clear_post_processing_run();
  858. }
  859. else
  860. {
  861. // All required flash pages have not yet been erased, issue erase by doing a self
  862. // transit.
  863. sm_state_change(m_state);
  864. }
  865. }
  866. else
  867. {
  868. // As operation request was rejected by the flash API reissue the request.
  869. main_state_err_busy_process();
  870. }
  871. }
  872. /**@brief Function for doing store state action upon flash operation success event.
  873. */
  874. static void store_sub_state_sm_run(void)
  875. {
  876. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  877. {
  878. // As write operation request has succeeded, adjust the size tracking state information
  879. // accordingly.
  880. cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  881. p_cmd->size -= m_num_of_bytes_written;
  882. if (p_cmd->size == 0)
  883. {
  884. command_end_procedure_run();
  885. }
  886. else
  887. {
  888. store_cmd_flash_write_execute();
  889. }
  890. }
  891. else
  892. {
  893. // As operation request was rejected by the flash API reissue the request.
  894. main_state_err_busy_process();
  895. }
  896. }
  897. /**@brief Function for doing action upon flash operation success event.
  898. */
  899. static void flash_operation_success_run(void)
  900. {
  901. switch (m_state)
  902. {
  903. case STATE_STORE:
  904. store_sub_state_sm_run();
  905. break;
  906. case STATE_DATA_ERASE:
  907. erase_sub_state_sm_run();
  908. break;
  909. case STATE_DATA_ERASE_WITH_SWAP:
  910. swap_sub_state_sm_run();
  911. break;
  912. default:
  913. // No implementation needed.
  914. break;
  915. }
  916. }
  917. /**@brief Function for doing action upon flash operation failure event.
  918. *
  919. * @details Function for doing action upon flash operation failure event, which includes retrying
  920. * the last operation or if retry count has been reached completing the operation with
  921. * appropriate result code and transitioning to an error state.
  922. *
  923. * @note The command is not removed from the command queue, which will result to stalling of the
  924. * command pipeline and the appropriate application recovery procedure for this is to reset
  925. * the system by issuing @ref pstorage_init which will also result to flushing of the
  926. * command queue.
  927. */
  928. static void flash_operation_failure_run(void)
  929. {
  930. if (++m_num_of_command_retries != SD_CMD_MAX_TRIES)
  931. {
  932. // Retry the last operation by doing a self transition to the current state.
  933. if (m_state != STATE_DATA_ERASE_WITH_SWAP)
  934. {
  935. sm_state_change(m_state);
  936. }
  937. else
  938. {
  939. swap_sub_state_state_change(m_swap_sub_state);
  940. }
  941. }
  942. else
  943. {
  944. // Complete the operation with appropriate result code and transit to an error state.
  945. app_notify_error_state_transit(NRF_ERROR_TIMEOUT);
  946. }
  947. }
  948. /**@brief Function for handling flash access result events.
  949. *
  950. * @param[in] sys_evt System event to be handled.
  951. */
  952. void pstorage_sys_event_handler(uint32_t sys_evt)
  953. {
  954. if (m_state != STATE_IDLE && m_state != STATE_ERROR)
  955. {
  956. switch (sys_evt)
  957. {
  958. case NRF_EVT_FLASH_OPERATION_SUCCESS:
  959. flash_operation_success_run();
  960. break;
  961. case NRF_EVT_FLASH_OPERATION_ERROR:
  962. if (!(m_flags & MASK_FLASH_API_ERR_BUSY))
  963. {
  964. flash_operation_failure_run();
  965. }
  966. else
  967. {
  968. // As our last flash operation request was rejected by the flash API reissue the
  969. // request by doing same code execution path as for flash operation sucess
  970. // event. This will promote code reuse in the implementation.
  971. flash_operation_success_run();
  972. }
  973. break;
  974. default:
  975. // No implementation needed.
  976. break;
  977. }
  978. }
  979. }
  980. /**@brief Function for calculating the tail area size in number of 32-bit words.
  981. *
  982. * @param[in] cmd_end_of_storage_address End of storage area within the scope of the command.
  983. * @param[in] end_of_storage_address End of allocated storage area for the application.
  984. */
  985. static void tail_word_size_calculate(pstorage_size_t cmd_end_of_storage_address,
  986. pstorage_size_t end_of_storage_address)
  987. {
  988. // Two different cases to resolve when calculating correct size for restore tail section:
  989. // 1) End of storage area and command end area are in the same page.
  990. // 2) End of storage area and command end area are not in the same page.
  991. const uint32_t end_of_storage_area_page = end_of_storage_address /
  992. PSTORAGE_FLASH_PAGE_SIZE;
  993. const uint32_t command_end_of_storage_area_page = cmd_end_of_storage_address /
  994. PSTORAGE_FLASH_PAGE_SIZE;
  995. if (end_of_storage_area_page == command_end_of_storage_area_page)
  996. {
  997. //lint -e{573} suppress "Signed-unsigned mix with divide".
  998. m_tail_word_size = (end_of_storage_address - cmd_end_of_storage_address) / sizeof(uint32_t);
  999. }
  1000. else
  1001. {
  1002. //lint -e{573} suppress "Signed-unsigned mix with divide".
  1003. m_tail_word_size = (PSTORAGE_FLASH_PAGE_SIZE -
  1004. (cmd_end_of_storage_address % PSTORAGE_FLASH_PAGE_SIZE)) /
  1005. sizeof(uint32_t);
  1006. }
  1007. }
  1008. /**@brief Function for executing the clear operation.
  1009. */
  1010. static void clear_operation_execute(void)
  1011. {
  1012. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  1013. const pstorage_block_t cmd_block_id = p_cmd->storage_addr.block_id;
  1014. const pstorage_size_t block_size = m_app_table[p_cmd->storage_addr.module_id].block_size;
  1015. const pstorage_size_t block_count = m_app_table[p_cmd->storage_addr.module_id].block_count;
  1016. const pstorage_block_t block_base_id = m_app_table[p_cmd->storage_addr.module_id].base_id;
  1017. const bool is_start_address_page_aligned = (cmd_block_id % PSTORAGE_FLASH_PAGE_SIZE) == 0;
  1018. // Calculate the end (1 beyond allocated area) for complete storage area and to the area only
  1019. // within scope of this command.
  1020. const pstorage_block_t end_of_storage_address = block_base_id + (block_size * block_count);
  1021. const pstorage_block_t cmd_end_of_storage_address = cmd_block_id + p_cmd->size + p_cmd->offset;
  1022. // Zero tail to make sure no extra erase is done erroneously.
  1023. m_tail_word_size = 0;
  1024. // If the following is true no swap access is needed:
  1025. // - 1st logical test covers the case of: clear/update 1 complete single page.
  1026. // - 2nd logical test covers the case of:
  1027. // 1) Clear/update last allocated page and page is not full (page can't be shared between
  1028. // multiple clients so the end of the page is unused area).
  1029. // 2) Clear/update all allocated storage.
  1030. if ((is_start_address_page_aligned && (p_cmd->size == PSTORAGE_FLASH_PAGE_SIZE)) ||
  1031. (is_start_address_page_aligned && (cmd_end_of_storage_address == end_of_storage_address) &&
  1032. (p_cmd->offset == 0)) || (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
  1033. {
  1034. // Nothing to put to the swap and we can just erase the pages(s).
  1035. m_current_page_id = cmd_block_id / PSTORAGE_FLASH_PAGE_SIZE;
  1036. sm_state_change(STATE_DATA_ERASE);
  1037. }
  1038. else
  1039. {
  1040. // Not all the blocks for the module can be cleared, we need to use swap page for storing
  1041. // data temporarily.
  1042. m_head_word_size = ((cmd_block_id + p_cmd->offset) % PSTORAGE_FLASH_PAGE_SIZE) /
  1043. sizeof(uint32_t);
  1044. const bool is_cmd_end_address_page_aligned = ((cmd_end_of_storage_address %
  1045. PSTORAGE_FLASH_PAGE_SIZE) == 0);
  1046. if ((cmd_end_of_storage_address != end_of_storage_address) &&
  1047. !is_cmd_end_address_page_aligned)
  1048. {
  1049. // When command area is not equal to end of the storage allocation area and not ending
  1050. // to page boundary there is a need to restore the tail area.
  1051. tail_word_size_calculate(cmd_end_of_storage_address, end_of_storage_address);
  1052. }
  1053. sm_state_change(STATE_DATA_ERASE_WITH_SWAP);
  1054. }
  1055. }
  1056. /**@brief Function for executing the store operation.
  1057. */
  1058. static void store_operation_execute(void)
  1059. {
  1060. sm_state_change(STATE_STORE);
  1061. }
  1062. /**@brief Function for executing the update operation.
  1063. */
  1064. static void update_operation_execute(void)
  1065. {
  1066. clear_operation_execute();
  1067. }
  1068. /**@brief Function for dispatching the flash access operation.
  1069. */
  1070. static void cmd_process(void)
  1071. {
  1072. const cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
  1073. m_app_data_size = p_cmd->size;
  1074. switch (p_cmd->op_code)
  1075. {
  1076. case PSTORAGE_STORE_OP_CODE:
  1077. store_operation_execute();
  1078. break;
  1079. case PSTORAGE_CLEAR_OP_CODE:
  1080. clear_operation_execute();
  1081. break;
  1082. case PSTORAGE_UPDATE_OP_CODE:
  1083. update_operation_execute();
  1084. break;
  1085. default:
  1086. // No action required.
  1087. break;
  1088. }
  1089. }
  1090. uint32_t pstorage_init(void)
  1091. {
  1092. cmd_queue_init();
  1093. m_next_app_instance = 0;
  1094. m_next_page_addr = PSTORAGE_DATA_START_ADDR;
  1095. m_current_page_id = 0;
  1096. for (uint32_t index = 0; index < PSTORAGE_NUM_OF_PAGES; index++)
  1097. {
  1098. m_app_table[index].cb = NULL;
  1099. m_app_table[index].block_size = 0;
  1100. m_app_table[index].block_count = 0;
  1101. }
  1102. #ifdef PSTORAGE_RAW_MODE_ENABLE
  1103. m_raw_app_table.cb = NULL;
  1104. #endif //PSTORAGE_RAW_MODE_ENABLE
  1105. m_state = STATE_IDLE;
  1106. m_num_of_command_retries = 0;
  1107. m_flags = 0;
  1108. m_num_of_bytes_written = 0;
  1109. m_flags |= MASK_MODULE_INITIALIZED;
  1110. return NRF_SUCCESS;
  1111. }
  1112. uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
  1113. pstorage_handle_t * p_block_id)
  1114. {
  1115. VERIFY_MODULE_INITIALIZED();
  1116. NULL_PARAM_CHECK(p_module_param);
  1117. NULL_PARAM_CHECK(p_block_id);
  1118. NULL_PARAM_CHECK(p_module_param->cb);
  1119. BLOCK_SIZE_CHECK(p_module_param->block_size);
  1120. BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
  1121. if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
  1122. {
  1123. return NRF_ERROR_INVALID_PARAM;
  1124. }
  1125. if (m_next_app_instance == PSTORAGE_NUM_OF_PAGES)
  1126. {
  1127. return NRF_ERROR_NO_MEM;
  1128. }
  1129. p_block_id->module_id = m_next_app_instance;
  1130. p_block_id->block_id = m_next_page_addr;
  1131. m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
  1132. m_app_table[m_next_app_instance].cb = p_module_param->cb;
  1133. m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
  1134. m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
  1135. // Calculate number of flash pages allocated for the device and adjust next free page address.
  1136. /*lint -save -e666 */
  1137. const uint32_t page_count = CEIL_DIV((p_module_param->block_size * p_module_param->block_count),
  1138. PSTORAGE_FLASH_PAGE_SIZE);
  1139. /*lint -restore */
  1140. m_next_page_addr += page_count * PSTORAGE_FLASH_PAGE_SIZE;
  1141. ++m_next_app_instance;
  1142. return NRF_SUCCESS;
  1143. }
  1144. uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
  1145. pstorage_size_t block_num,
  1146. pstorage_handle_t * p_block_id)
  1147. {
  1148. pstorage_handle_t temp_id;
  1149. VERIFY_MODULE_INITIALIZED();
  1150. NULL_PARAM_CHECK(p_base_id);
  1151. NULL_PARAM_CHECK(p_block_id);
  1152. MODULE_ID_RANGE_CHECK(p_base_id);
  1153. temp_id = (*p_base_id);
  1154. temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
  1155. BLOCK_ID_RANGE_CHECK(&temp_id);
  1156. (*p_block_id) = temp_id;
  1157. return NRF_SUCCESS;
  1158. }
  1159. uint32_t pstorage_store(pstorage_handle_t * p_dest,
  1160. uint8_t * p_src,
  1161. pstorage_size_t size,
  1162. pstorage_size_t offset)
  1163. {
  1164. VERIFY_MODULE_INITIALIZED();
  1165. NULL_PARAM_CHECK(p_src);
  1166. NULL_PARAM_CHECK(p_dest);
  1167. MODULE_ID_RANGE_CHECK(p_dest);
  1168. BLOCK_ID_RANGE_CHECK(p_dest);
  1169. SIZE_CHECK(p_dest, size);
  1170. OFFSET_CHECK(p_dest, offset, size);
  1171. if ((!is_word_aligned(p_src)) ||
  1172. (!is_word_aligned((void *)(uint32_t)offset)) ||
  1173. (!is_word_aligned((uint32_t *)p_dest->block_id)))
  1174. {
  1175. return NRF_ERROR_INVALID_ADDR;
  1176. }
  1177. return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
  1178. }
  1179. uint32_t pstorage_update(pstorage_handle_t * p_dest,
  1180. uint8_t * p_src,
  1181. pstorage_size_t size,
  1182. pstorage_size_t offset)
  1183. {
  1184. VERIFY_MODULE_INITIALIZED();
  1185. NULL_PARAM_CHECK(p_src);
  1186. NULL_PARAM_CHECK(p_dest);
  1187. MODULE_ID_RANGE_CHECK(p_dest);
  1188. BLOCK_ID_RANGE_CHECK(p_dest);
  1189. SIZE_CHECK(p_dest, size);
  1190. OFFSET_CHECK(p_dest, offset, size);
  1191. if ((!is_word_aligned(p_src)) ||
  1192. (!is_word_aligned((void *)(uint32_t)offset)) ||
  1193. (!is_word_aligned((uint32_t *)p_dest->block_id)))
  1194. {
  1195. return NRF_ERROR_INVALID_ADDR;
  1196. }
  1197. return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
  1198. }
  1199. uint32_t pstorage_load(uint8_t * p_dest,
  1200. pstorage_handle_t * p_src,
  1201. pstorage_size_t size,
  1202. pstorage_size_t offset)
  1203. {
  1204. VERIFY_MODULE_INITIALIZED();
  1205. NULL_PARAM_CHECK(p_src);
  1206. NULL_PARAM_CHECK(p_dest);
  1207. MODULE_ID_RANGE_CHECK(p_src);
  1208. BLOCK_ID_RANGE_CHECK(p_src);
  1209. SIZE_CHECK(p_src, size);
  1210. OFFSET_CHECK(p_src, offset, size);
  1211. if ((!is_word_aligned(p_dest)) ||
  1212. (!is_word_aligned((void *)(uint32_t)offset)) ||
  1213. (!is_word_aligned((uint32_t *)p_src->block_id)))
  1214. {
  1215. return NRF_ERROR_INVALID_ADDR;
  1216. }
  1217. memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
  1218. m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
  1219. return NRF_SUCCESS;
  1220. }
  1221. uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
  1222. {
  1223. VERIFY_MODULE_INITIALIZED();
  1224. NULL_PARAM_CHECK(p_dest);
  1225. MODULE_ID_RANGE_CHECK(p_dest);
  1226. BLOCK_ID_RANGE_CHECK(p_dest);
  1227. if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
  1228. {
  1229. return NRF_ERROR_INVALID_ADDR;
  1230. }
  1231. // Check is the area starting from block_id multiple of block_size.
  1232. if (
  1233. !(
  1234. ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
  1235. m_app_table[p_dest->module_id].block_size) == 0
  1236. )
  1237. )
  1238. {
  1239. return NRF_ERROR_INVALID_PARAM;
  1240. }
  1241. // Check is requested size multiple of registered block size or 0.
  1242. if (((size % m_app_table[p_dest->module_id].block_size) != 0) || (size == 0))
  1243. {
  1244. return NRF_ERROR_INVALID_PARAM;
  1245. }
  1246. const uint32_t registered_allocation_size = m_app_table[p_dest->module_id].block_size *
  1247. m_app_table[p_dest->module_id].block_count;
  1248. const pstorage_block_t clear_request_end_address = p_dest->block_id + size;
  1249. const pstorage_block_t allocation_end_address = m_app_table[p_dest->module_id].base_id +
  1250. registered_allocation_size;
  1251. // Check if request would lead to a buffer overrun.
  1252. if (clear_request_end_address > allocation_end_address)
  1253. {
  1254. return NRF_ERROR_INVALID_PARAM;
  1255. }
  1256. return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
  1257. }
  1258. uint32_t pstorage_access_status_get(uint32_t * p_count)
  1259. {
  1260. VERIFY_MODULE_INITIALIZED();
  1261. NULL_PARAM_CHECK(p_count);
  1262. (*p_count) = m_cmd_queue.count;
  1263. return NRF_SUCCESS;
  1264. }
  1265. #ifdef PSTORAGE_RAW_MODE_ENABLE
  1266. uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
  1267. pstorage_handle_t * p_block_id)
  1268. {
  1269. VERIFY_MODULE_INITIALIZED();
  1270. NULL_PARAM_CHECK(p_module_param);
  1271. NULL_PARAM_CHECK(p_block_id);
  1272. NULL_PARAM_CHECK(p_module_param->cb);
  1273. if (m_raw_app_table.cb != NULL)
  1274. {
  1275. return NRF_ERROR_NO_MEM;
  1276. }
  1277. p_block_id->module_id = RAW_MODE_APP_ID;
  1278. m_raw_app_table.cb = p_module_param->cb;
  1279. return NRF_SUCCESS;
  1280. }
  1281. uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
  1282. uint8_t * p_src,
  1283. pstorage_size_t size,
  1284. pstorage_size_t offset)
  1285. {
  1286. VERIFY_MODULE_INITIALIZED();
  1287. NULL_PARAM_CHECK(p_src);
  1288. NULL_PARAM_CHECK(p_dest);
  1289. MODULE_RAW_HANDLE_CHECK(p_dest);
  1290. if (size == 0)
  1291. {
  1292. return NRF_ERROR_INVALID_PARAM;
  1293. }
  1294. // Verify word alignment.
  1295. if ((!is_word_aligned(p_src)) ||
  1296. (!is_word_aligned((void *)(uint32_t)size)) ||
  1297. (!is_word_aligned((void *)(uint32_t)offset)) ||
  1298. (!is_word_aligned((void *)(p_dest->block_id))))
  1299. {
  1300. return NRF_ERROR_INVALID_ADDR;
  1301. }
  1302. return cmd_queue_enqueue(PSTORAGE_STORE_OP_CODE, p_dest, p_src, size, offset);
  1303. }
  1304. uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
  1305. {
  1306. VERIFY_MODULE_INITIALIZED();
  1307. NULL_PARAM_CHECK(p_dest);
  1308. MODULE_RAW_HANDLE_CHECK(p_dest);
  1309. if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
  1310. {
  1311. return NRF_ERROR_INVALID_ADDR;
  1312. }
  1313. return cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
  1314. }
  1315. #endif // PSTORAGE_RAW_MODE_ENABLE