background_dfu_block.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /**
  2. * Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /** @file
  41. *
  42. * @defgroup background_dfu_block background_dfu_block.c
  43. * @{
  44. * @ingroup background_dfu
  45. * @brief Background DFU block handling implementation.
  46. *
  47. */
  48. #include "background_dfu_block.h"
  49. #include <assert.h>
  50. #include "sdk_config.h"
  51. #include "app_scheduler.h"
  52. #include "background_dfu_operation.h"
  53. #include "compiler_abstraction.h"
  54. #include "nrf_dfu_handling_error.h"
  55. #define NRF_LOG_MODULE_NAME background_dfu
  56. #define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
  57. #define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
  58. #define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
  59. #include "nrf_log.h"
  60. #define BITMAP_BYTE_FROM_INDEX(index) ((index) / 8)
  61. #define BITMAP_BIT_FROM_INDEX(index) (7 - ((index) % 8))
  62. /**@brief A maximum number of concurrent delayed context structures. */
  63. #ifndef SOFTDEVICE_PRESENT
  64. #define DFU_FLASH_OPERATION_OP_ENTRIES 2
  65. #else
  66. #define DFU_FLASH_OPERATION_OP_ENTRIES NRF_FSTORAGE_SD_QUEUE_SIZE
  67. #endif
  68. /**@brief An enumeration describing delayed flash operation status. */
  69. typedef enum
  70. {
  71. STATUS_NONE,
  72. STATUS_REGISTERED,
  73. STATUS_FLASH_DONE,
  74. STATUS_PROCESSING_DONE,
  75. STATUS_CALLBACK_CALLED
  76. } dfu_flash_operation_status_t;
  77. /**@brief A structure representing delayed DFU context. */
  78. typedef struct
  79. {
  80. nrf_dfu_response_t response;
  81. void * p_context;
  82. void * p_buf;
  83. dfu_flash_operation_status_t status;
  84. } dfu_flash_operation_ctx_t;
  85. /**@brief An array storing delayed DFU context structures.
  86. */
  87. static dfu_flash_operation_ctx_t m_flash_operations[DFU_FLASH_OPERATION_OP_ENTRIES];
  88. static void block_buffer_store(background_dfu_block_manager_t * p_bm);
  89. static void dfu_operation_callback(nrf_dfu_response_t * p_res, void * p_context);
  90. /**@brief A function to initialize delayed DFU context module.
  91. */
  92. static void dfu_flash_operation_init(void)
  93. {
  94. uint32_t i;
  95. for (i = 0; i < DFU_FLASH_OPERATION_OP_ENTRIES; i++)
  96. {
  97. m_flash_operations[i].status = STATUS_NONE;
  98. }
  99. }
  100. /**@brief A function to register a new context for delayed DFU operations.
  101. *
  102. * @param[in] p_buf Pointer to the memory buffer, that will be used for flash operation.
  103. * @param[in] p_context Pointer to the DFU request context.
  104. *
  105. * @return NRF_SUCCESS if a new context entry was registered, NRF_ERROR_NO_MEM otherwise.
  106. */
  107. static ret_code_t dfu_flash_operation_register(void * p_buf, void * p_context)
  108. {
  109. uint32_t i;
  110. for (i = 0; i < DFU_FLASH_OPERATION_OP_ENTRIES; i++)
  111. {
  112. if (m_flash_operations[i].status == STATUS_NONE)
  113. {
  114. m_flash_operations[i].status = STATUS_REGISTERED;
  115. m_flash_operations[i].p_buf = p_buf;
  116. m_flash_operations[i].p_context = p_context;
  117. memset(&m_flash_operations[i].response, 0, sizeof(nrf_dfu_response_t));
  118. return NRF_SUCCESS;
  119. }
  120. }
  121. return NRF_ERROR_NO_MEM;
  122. }
  123. /**@brief A function to get a context structure based on DFU block context.
  124. *
  125. * @param[in] p_context Pointer to the DFU request context.
  126. *
  127. * @return Pointer to the found delayed DFU context structure, NULL otherwise.
  128. */
  129. static dfu_flash_operation_ctx_t * dfu_flash_operation_find_by_context(void * p_context)
  130. {
  131. uint32_t i;
  132. for (i = 0; i < DFU_FLASH_OPERATION_OP_ENTRIES; i++)
  133. {
  134. if ((m_flash_operations[i].status != STATUS_NONE) && (m_flash_operations[i].p_context == p_context))
  135. {
  136. return &m_flash_operations[i];
  137. }
  138. }
  139. return NULL;
  140. }
  141. /**@brief A function to get a context structure based on flash operation buffer address.
  142. *
  143. * @param[in] p_buf Pointer to the memory buffer, that will be used for flash operation.
  144. *
  145. * @return Pointer to the found delayed DFU context structure, NULL otherwise.
  146. */
  147. static dfu_flash_operation_ctx_t * dfu_flash_operation_find_by_buffer(void * p_buf)
  148. {
  149. uint32_t i;
  150. for (i = 0; i < DFU_FLASH_OPERATION_OP_ENTRIES; i++)
  151. {
  152. if ((m_flash_operations[i].status != STATUS_NONE) && (m_flash_operations[i].p_buf == p_buf))
  153. {
  154. return &m_flash_operations[i];
  155. }
  156. }
  157. return NULL;
  158. }
  159. /**@brief A callback function for processing events, implementing delayed DFU operation.
  160. *
  161. * @param[in] p_res Pointer to the DFU response structure.
  162. * @param[in] p_context Pointer to the DFU request context.
  163. */
  164. static void dfu_operation_callback_delayed(nrf_dfu_response_t * p_res, void * p_context)
  165. {
  166. dfu_flash_operation_ctx_t * p_flash_ctx = dfu_flash_operation_find_by_context(p_context);
  167. bool call = false;
  168. if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
  169. {
  170. dfu_operation_callback(p_res, p_context);
  171. return;
  172. }
  173. if (p_flash_ctx == NULL)
  174. {
  175. return;
  176. }
  177. CRITICAL_REGION_ENTER();
  178. switch(p_flash_ctx->status)
  179. {
  180. case STATUS_REGISTERED:
  181. // Store operation result for a delayed call.
  182. p_flash_ctx->response = *p_res;
  183. p_flash_ctx->status = STATUS_PROCESSING_DONE;
  184. break;
  185. case STATUS_FLASH_DONE:
  186. p_flash_ctx->status = STATUS_CALLBACK_CALLED;
  187. call = true;
  188. break;
  189. case STATUS_NONE:
  190. case STATUS_PROCESSING_DONE:
  191. case STATUS_CALLBACK_CALLED:
  192. default:
  193. break;
  194. }
  195. CRITICAL_REGION_EXIT();
  196. if (call)
  197. {
  198. // If both: flash and processing callbacks received - call main state machine.
  199. dfu_operation_callback(p_res, p_flash_ctx->p_context);
  200. p_flash_ctx->status = STATUS_NONE;
  201. }
  202. }
  203. /**@brief A callback function for flash events, implementing delayed DFU operation.
  204. *
  205. * @param[in] p_buf Pointer to the memory buffer, related to the finished flash operation.
  206. */
  207. static void dfu_operation_flash_callback(void * p_buf)
  208. {
  209. dfu_flash_operation_ctx_t * p_flash_ctx = dfu_flash_operation_find_by_buffer(p_buf);
  210. bool call = false;
  211. if (p_flash_ctx == NULL)
  212. {
  213. return;
  214. }
  215. CRITICAL_REGION_ENTER();
  216. switch(p_flash_ctx->status)
  217. {
  218. case STATUS_REGISTERED:
  219. p_flash_ctx->status = STATUS_FLASH_DONE;
  220. break;
  221. case STATUS_PROCESSING_DONE:
  222. p_flash_ctx->status = STATUS_CALLBACK_CALLED;
  223. call = true;
  224. break;
  225. case STATUS_NONE:
  226. case STATUS_FLASH_DONE:
  227. case STATUS_CALLBACK_CALLED:
  228. default:
  229. break;
  230. }
  231. CRITICAL_REGION_EXIT();
  232. if (call)
  233. {
  234. // If both: flash and processing callbacks received - call main state machine.
  235. dfu_operation_callback(&p_flash_ctx->response, p_flash_ctx->p_context);
  236. p_flash_ctx->status = STATUS_NONE;
  237. }
  238. }
  239. /**@brief Convert block number to bitmap index.
  240. *
  241. * @param[in] block_num Block number.
  242. *
  243. * @return Corresponding index.
  244. */
  245. static __INLINE uint16_t block_num_to_index(uint32_t block_num)
  246. {
  247. return block_num % BLOCKS_PER_BUFFER;
  248. }
  249. /**@brief Set a bit in a bitmap.
  250. *
  251. * @param[inout] p_bitmap A pointer to the bitmap.
  252. * @param[in] index Bit index to set.
  253. */
  254. static __INLINE void set_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
  255. {
  256. p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] |= (0x01 << BITMAP_BIT_FROM_INDEX(index));
  257. }
  258. /**@brief Clear a bit in a bitmap.
  259. *
  260. * @param[inout] p_bitmap A pointer to the bitmap.
  261. * @param[in] index Bit index to clear.
  262. */
  263. static __INLINE void clear_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
  264. {
  265. p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] &= ~((uint8_t)(0x01 << BITMAP_BIT_FROM_INDEX(index)));
  266. }
  267. /**@brief Check if a bit in a bitmap is set.
  268. *
  269. * @param[inout] p_bitmap A pointer to the bitmap.
  270. * @param[in] index Bit index to check.
  271. *
  272. * @return True if bit is set, false otherwise.
  273. */
  274. static __INLINE bool is_block_present(const uint8_t * p_bitmap, uint16_t index)
  275. {
  276. return (p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] >> BITMAP_BIT_FROM_INDEX(index)) & 0x01;
  277. }
  278. /**
  279. * @brief A callback function for DFU operation.
  280. */
  281. static void dfu_operation_callback(nrf_dfu_response_t * p_res, void * p_context)
  282. {
  283. background_dfu_block_manager_t * p_bm = (background_dfu_block_manager_t *)p_context;
  284. ret_code_t ret_code;
  285. if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
  286. {
  287. p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
  288. }
  289. else
  290. {
  291. switch (p_res->request)
  292. {
  293. case NRF_DFU_OP_OBJECT_CREATE:
  294. {
  295. // Object created, write respective block.
  296. uint32_t current_size = p_bm->currently_stored_block * DEFAULT_BLOCK_SIZE;
  297. uint16_t data_offset = block_num_to_index(p_bm->currently_stored_block) * DEFAULT_BLOCK_SIZE;
  298. uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
  299. ret_code = dfu_flash_operation_register(p_bm->data + data_offset, p_bm);
  300. if (ret_code == NRF_SUCCESS)
  301. {
  302. ret_code = background_dfu_op_write(p_bm->data + data_offset,
  303. store_size,
  304. dfu_operation_callback_delayed,
  305. dfu_operation_flash_callback,
  306. p_bm);
  307. }
  308. else
  309. {
  310. ret_code = background_dfu_op_write(p_bm->data + data_offset,
  311. store_size,
  312. dfu_operation_callback,
  313. dfu_operation_flash_callback,
  314. p_bm);
  315. }
  316. if (ret_code != NRF_SUCCESS)
  317. {
  318. NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
  319. p_bm->currently_stored_block,
  320. p_bm->current_block);
  321. p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
  322. }
  323. break;
  324. }
  325. case NRF_DFU_OP_OBJECT_WRITE:
  326. if (!((p_bm->currently_stored_block + 1) % BLOCKS_PER_DFU_OBJECT) ||
  327. ((p_bm->currently_stored_block + 1) == (int32_t)BLOCKS_PER_SIZE(p_bm->image_size)))
  328. {
  329. ret_code = background_dfu_op_crc(dfu_operation_callback, p_bm);
  330. if (ret_code != NRF_SUCCESS)
  331. {
  332. NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
  333. p_bm->currently_stored_block,
  334. p_bm->current_block);
  335. p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
  336. }
  337. }
  338. else
  339. {
  340. p_bm->last_block_stored = p_bm->currently_stored_block;
  341. clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
  342. p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
  343. p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
  344. block_buffer_store(p_bm);
  345. }
  346. break;
  347. case NRF_DFU_OP_CRC_GET:
  348. ret_code = background_dfu_op_execute(dfu_operation_callback, p_bm);
  349. if (ret_code != NRF_SUCCESS)
  350. {
  351. NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
  352. p_bm->currently_stored_block,
  353. p_bm->current_block);
  354. p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
  355. }
  356. break;
  357. case NRF_DFU_OP_OBJECT_EXECUTE:
  358. p_bm->last_block_stored = p_bm->currently_stored_block;
  359. clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
  360. p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
  361. p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
  362. block_buffer_store(p_bm);
  363. break;
  364. default:
  365. ASSERT(false);
  366. }
  367. }
  368. }
  369. /**@brief Store a block from the buffer in a flash.
  370. *
  371. * @param[inout] p_bm A pointer to the block manager.
  372. * @param[in] p_block A block number to store.
  373. *
  374. * @return NRF_SUCCESS on success, an error code is returned otherwise.
  375. */
  376. static ret_code_t block_store(background_dfu_block_manager_t * p_bm, uint32_t block_num)
  377. {
  378. p_bm->currently_stored_block = block_num;
  379. ret_code_t ret_code = NRF_SUCCESS;
  380. uint32_t current_size = block_num * DEFAULT_BLOCK_SIZE;
  381. do
  382. {
  383. // Initialize DFU object if needed.
  384. if (!(block_num % BLOCKS_PER_DFU_OBJECT))
  385. {
  386. uint32_t object_size = MIN(DEFAULT_DFU_OBJECT_SIZE, (p_bm->image_size - current_size));
  387. ret_code = background_dfu_op_create(p_bm->image_type,
  388. object_size,
  389. dfu_operation_callback,
  390. p_bm);
  391. break;
  392. }
  393. // Store block.
  394. uint16_t data_offset = block_num_to_index(block_num) * DEFAULT_BLOCK_SIZE;
  395. uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
  396. ret_code = dfu_flash_operation_register(p_bm->data + data_offset, p_bm);
  397. if (ret_code == NRF_SUCCESS)
  398. {
  399. ret_code = background_dfu_op_write(p_bm->data + data_offset,
  400. store_size,
  401. dfu_operation_callback_delayed,
  402. dfu_operation_flash_callback,
  403. p_bm);
  404. }
  405. else
  406. {
  407. ret_code = background_dfu_op_write(p_bm->data + data_offset,
  408. store_size,
  409. dfu_operation_callback,
  410. dfu_operation_flash_callback,
  411. p_bm);
  412. }
  413. } while (0);
  414. return ret_code;
  415. }
  416. /**@brief Check if block manager is busy storing a block.
  417. *
  418. * @param[inout] p_bm A pointer to the block manager.
  419. *
  420. */
  421. static bool is_block_manager_busy(background_dfu_block_manager_t * p_bm)
  422. {
  423. return p_bm->currently_stored_block >= 0;
  424. }
  425. /**@brief Store any valid blocks from the buffer in a flash.
  426. *
  427. * @param[inout] p_bm A pointer to the block manager.
  428. *
  429. */
  430. static void block_buffer_store(background_dfu_block_manager_t * p_bm)
  431. {
  432. ret_code_t ret_code = NRF_SUCCESS;
  433. if (!is_block_manager_busy(p_bm))
  434. {
  435. if (p_bm->last_block_stored < p_bm->current_block)
  436. {
  437. int32_t block = p_bm->last_block_stored + 1;
  438. if (is_block_present(p_bm->bitmap, block_num_to_index(block)))
  439. {
  440. NRF_LOG_INFO("Storing block (b:%d c:%d).", block, p_bm->current_block);
  441. // There is a block to store.
  442. ret_code = block_store(p_bm, block);
  443. if (ret_code != NRF_SUCCESS)
  444. {
  445. NRF_LOG_ERROR("Failed to store block (b:%d c:%d).", block, p_bm->current_block);
  446. p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
  447. }
  448. }
  449. else
  450. {
  451. NRF_LOG_WARNING("Gap encountered - quit (b:%d c:%d).", block, p_bm->current_block);
  452. }
  453. }
  454. }
  455. }
  456. /**
  457. * @brief A callback function for scheduling DFU block operations.
  458. */
  459. static void block_store_scheduled(void * p_evt, uint16_t event_length)
  460. {
  461. UNUSED_PARAMETER(event_length);
  462. background_dfu_block_manager_t * p_bm = *((background_dfu_block_manager_t **)p_evt);
  463. block_buffer_store(p_bm);
  464. }
  465. /**@brief Copy block data to the buffer.
  466. *
  467. * @param[inout] p_bm A pointer to the block manager.
  468. * @param[in] p_block A pointer to the block.
  469. */
  470. static void block_buffer_add(background_dfu_block_manager_t * p_bm,
  471. const background_dfu_block_t * p_block)
  472. {
  473. uint16_t index = block_num_to_index(p_block->number);
  474. memcpy(p_bm->data + index * DEFAULT_BLOCK_SIZE, p_block->p_payload, DEFAULT_BLOCK_SIZE);
  475. set_bitmap_bit(p_bm->bitmap, index);
  476. if (p_bm->current_block < (int32_t)p_block->number)
  477. {
  478. p_bm->current_block = (int32_t)p_block->number;
  479. }
  480. // Schedule block store.
  481. UNUSED_RETURN_VALUE(app_sched_event_put(&p_bm, sizeof(p_bm), block_store_scheduled));
  482. }
  483. /***************************************************************************************************
  484. * @section Public
  485. **************************************************************************************************/
  486. void block_manager_init(background_dfu_block_manager_t * p_bm,
  487. uint32_t object_type,
  488. uint32_t object_size,
  489. int32_t initial_block,
  490. block_manager_result_notify_t result_handler,
  491. void * p_context)
  492. {
  493. p_bm->image_type = object_type;
  494. p_bm->image_size = object_size;
  495. p_bm->last_block_stored = p_bm->current_block = initial_block - 1;
  496. p_bm->result_handler = result_handler;
  497. p_bm->p_context = p_context;
  498. p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
  499. memset(p_bm->bitmap, 0, sizeof(p_bm->bitmap));
  500. dfu_flash_operation_init();
  501. }
  502. background_dfu_block_result_t block_manager_block_process(background_dfu_block_manager_t * p_bm,
  503. const background_dfu_block_t * p_block)
  504. {
  505. /*
  506. * Possible scenarios:
  507. * 1) We receive a block older than our last stored block - simply ignore it.
  508. * 2) We receive a block that fits within current buffer range - process it.
  509. * 3) We receive a block that exceeds current buffer range - abort DFU as we won't be able to catch-up.
  510. */
  511. if (p_block->size != DEFAULT_BLOCK_SIZE)
  512. {
  513. NRF_LOG_WARNING("Block with incorrect size received (s:%d n:%d).",
  514. p_block->size, p_block->number);
  515. return BACKGROUND_DFU_BLOCK_IGNORE;
  516. }
  517. if ((int32_t)p_block->number <= p_bm->last_block_stored)
  518. {
  519. NRF_LOG_WARNING("Ignoring block that already was stored(o:%d n:%d).",
  520. p_bm->last_block_stored, p_block->number);
  521. return BACKGROUND_DFU_BLOCK_IGNORE;
  522. }
  523. if ((int32_t)p_block->number > p_bm->last_block_stored + BLOCKS_PER_BUFFER)
  524. {
  525. NRF_LOG_WARNING("Too many blocks missed - abort DFU (o:%d n:%d).",
  526. p_bm->last_block_stored, p_block->number);
  527. return BACKGROUND_DFU_BLOCK_INVALID;
  528. }
  529. // Block fits within current buffer - copy it into the buffer and update the current block if most
  530. // recent block was received.
  531. block_buffer_add(p_bm, p_block);
  532. return BACKGROUND_DFU_BLOCK_SUCCESS;
  533. }
  534. bool block_manager_is_image_complete(const background_dfu_block_manager_t * p_bm)
  535. {
  536. int32_t image_blocks = (int32_t)BLOCKS_PER_SIZE(p_bm->image_size);
  537. NRF_LOG_DEBUG("Is image complete (o:%d n:%d).", p_bm->last_block_stored, image_blocks);
  538. if (p_bm->last_block_stored + 1 == image_blocks)
  539. {
  540. return true;
  541. }
  542. return false;
  543. }
  544. bool block_manager_request_bitmap_get(const background_dfu_block_manager_t * p_bm,
  545. background_dfu_request_bitmap_t * p_req_bmp)
  546. {
  547. if (p_bm->current_block > p_bm->last_block_stored)
  548. {
  549. memset(p_req_bmp, 0, sizeof(*p_req_bmp));
  550. p_req_bmp->offset = p_bm->last_block_stored + 1;
  551. p_req_bmp->size = (p_bm->current_block - p_bm->last_block_stored + 7) / 8;
  552. for (uint16_t block = p_req_bmp->offset; block <= p_bm->current_block; block++)
  553. {
  554. if (!is_block_present(p_bm->bitmap, block_num_to_index(block)))
  555. {
  556. set_bitmap_bit(p_req_bmp->bitmap, block - p_req_bmp->offset);
  557. }
  558. }
  559. // Clip empty bytes at the end.
  560. while ((p_req_bmp->size > 0) && (p_req_bmp->bitmap[p_req_bmp->size - 1] == 0))
  561. {
  562. p_req_bmp->size--;
  563. }
  564. if (p_req_bmp->size == 0)
  565. {
  566. return false;
  567. }
  568. return true;
  569. }
  570. return false;
  571. }
  572. bool block_manager_increment_current_block(background_dfu_block_manager_t * p_bm)
  573. {
  574. int32_t image_blocks = (int32_t)BLOCKS_PER_SIZE(p_bm->image_size);
  575. if (p_bm->current_block + 1 == image_blocks)
  576. {
  577. // Already on last block.
  578. return false;
  579. }
  580. else
  581. {
  582. p_bm->current_block++;
  583. }
  584. return true;
  585. }
  586. int32_t block_manager_get_current_block(const background_dfu_block_manager_t * p_bm)
  587. {
  588. return p_bm->current_block;
  589. }