background_dfu_state.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. /**
  2. * Copyright (c) 2017 - 2018, 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_state background_dfu_state.c
  43. * @{
  44. * @ingroup background_dfu
  45. * @brief Background DFU state management.
  46. *
  47. */
  48. #include "background_dfu_state.h"
  49. #include <string.h>
  50. #include "sdk_config.h"
  51. #include "app_timer.h"
  52. #include "compiler_abstraction.h"
  53. #include "nrf_dfu_types.h"
  54. #include "nrf_dfu_settings.h"
  55. #include "sha256.h"
  56. #include "background_dfu_transport.h"
  57. #include "background_dfu_operation.h"
  58. #define NRF_LOG_MODULE_NAME background_dfu
  59. #define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
  60. #define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
  61. #define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
  62. #include "nrf_log.h"
  63. NRF_LOG_MODULE_REGISTER();
  64. #define BLOCK_REQUEST_JITTER_MIN 200 /**< Minimum jitter value when sending bitmap with requested blocks in multicast DFU. */
  65. #define BLOCK_REQUEST_JITTER_MAX 2000 /**< Maximum jitter value when sending bitmap with requested blocks in multicast DFU. */
  66. #define BLOCK_RECEIVE_TIMEOUT 2000 /**< Timeout value after which block is considered missing in multicast DFU. */
  67. #define DFU_DATE_TIME (__DATE__ " " __TIME__)
  68. /**@brief DFU trigger packet version. */
  69. #define TRIGGER_VERSION 1
  70. /**
  71. * @defgroup background_dfu_trigger_flags Trigger flags and offsets.
  72. * @{
  73. */
  74. #define TRIGGER_FLAGS_VERSION_OFFSET 4
  75. #define TRIGGER_FLAGS_VERSION_MASK 0xF0
  76. #define TRIGGER_FLAGS_MODE_OFFSET 3
  77. #define TRIGGER_FLAGS_MODE_MASK 0x08
  78. #define TRIGGER_FLAGS_RESET_OFFSET 2
  79. #define TRIGGER_FLAGS_RESET_MASK 0x04
  80. /** @} */
  81. APP_TIMER_DEF(m_missing_block_timer);
  82. APP_TIMER_DEF(m_block_timeout_timer);
  83. /**@brief Defines how many retries are performed in case no response is received. */
  84. #define DEFAULT_RETRIES 3
  85. /**@brief DFU error handler.
  86. *
  87. * @param[inout] p_dfu_ctx DFU context.
  88. */
  89. static __INLINE void dfu_handle_error(background_dfu_context_t * p_dfu_ctx)
  90. {
  91. p_dfu_ctx->dfu_state = BACKGROUND_DFU_ERROR;
  92. background_dfu_handle_error();
  93. }
  94. /**@brief Get randomized jitter value.
  95. *
  96. * @return Randomized jitter value between BLOCK_REQUEST_JITTER_MIN and BLOCK_REQUEST_JITTER_MAX.
  97. */
  98. static __INLINE uint32_t block_request_jitter_get(void)
  99. {
  100. return BLOCK_REQUEST_JITTER_MIN + (background_dfu_random() %
  101. (BLOCK_REQUEST_JITTER_MAX - BLOCK_REQUEST_JITTER_MIN));
  102. }
  103. /**@brief Starts block timeout timer.
  104. *
  105. * @param[inout] p_dfu_ctx DFU context.
  106. */
  107. static __INLINE void start_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
  108. {
  109. uint32_t err_code = app_timer_start(m_block_timeout_timer,
  110. APP_TIMER_TICKS(BLOCK_RECEIVE_TIMEOUT),
  111. p_dfu_ctx);
  112. if (err_code != NRF_SUCCESS)
  113. {
  114. NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
  115. }
  116. }
  117. /**@brief Stops block timeout timer.
  118. *
  119. * @param[inout] p_dfu_ctx DFU context.
  120. */
  121. static __INLINE void stop_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
  122. {
  123. UNUSED_PARAMETER(p_dfu_ctx);
  124. uint32_t err_code = app_timer_stop(m_block_timeout_timer);
  125. if (err_code != NRF_SUCCESS)
  126. {
  127. NRF_LOG_ERROR("Error in app_timer_stop (%d)", err_code);
  128. }
  129. }
  130. /**@brief Restarts block timeout timer.
  131. *
  132. * @param[inout] p_dfu_ctx DFU context.
  133. */
  134. static __INLINE void restart_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
  135. {
  136. stop_block_timeout_timer(p_dfu_ctx);
  137. start_block_timeout_timer(p_dfu_ctx);
  138. }
  139. /***************************************************************************************************
  140. * @section Handle DFU Trigger
  141. **************************************************************************************************/
  142. /**@brief Parses trigger data and updates DFU client context accordingly.
  143. *
  144. * @param[inout] p_dfu_ctx A pointer to DFU Client context.
  145. * @param[in] p_trigger A pointer to trigger data.
  146. *
  147. * @return True if parsing was successful, false otherwise.
  148. */
  149. static bool parse_trigger(background_dfu_context_t * p_dfu_ctx,
  150. const background_dfu_trigger_t * p_trigger)
  151. {
  152. uint8_t trigger_version = (p_trigger->flags & TRIGGER_FLAGS_VERSION_MASK)
  153. >> TRIGGER_FLAGS_VERSION_OFFSET;
  154. if (trigger_version <= TRIGGER_VERSION)
  155. {
  156. // Base fields available from version 0.
  157. p_dfu_ctx->init_cmd_size = uint32_big_decode((const uint8_t *)&p_trigger->init_length);
  158. p_dfu_ctx->init_cmd_crc = uint32_big_decode((const uint8_t *)&p_trigger->init_crc);
  159. p_dfu_ctx->firmware_size = uint32_big_decode((const uint8_t *)&p_trigger->image_length);
  160. p_dfu_ctx->firmware_crc = uint32_big_decode((const uint8_t *)&p_trigger->image_crc);
  161. // Mode flag was added in DFU Trigger version 1.
  162. if (trigger_version >= 1)
  163. {
  164. p_dfu_ctx->dfu_mode = (background_dfu_mode_t)((p_trigger->flags
  165. & TRIGGER_FLAGS_MODE_MASK) >> TRIGGER_FLAGS_MODE_OFFSET);
  166. p_dfu_ctx->reset_suppress = (p_trigger->flags & TRIGGER_FLAGS_RESET_MASK) >>
  167. TRIGGER_FLAGS_RESET_OFFSET;
  168. }
  169. else
  170. {
  171. p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
  172. }
  173. NRF_LOG_INFO("DFU trigger: init (sz=%d, crc=%0X) image (sz=%d, crc=%0X)",
  174. p_dfu_ctx->init_cmd_size,
  175. p_dfu_ctx->init_cmd_crc,
  176. p_dfu_ctx->firmware_size,
  177. p_dfu_ctx->firmware_crc);
  178. return true;
  179. }
  180. return false;
  181. }
  182. bool background_dfu_validate_trigger(background_dfu_context_t * p_dfu_ctx,
  183. const uint8_t * p_payload,
  184. uint32_t payload_len)
  185. {
  186. if (payload_len != sizeof(background_dfu_trigger_t))
  187. {
  188. NRF_LOG_ERROR("Validate trigger: size mismatch");
  189. return false;
  190. }
  191. if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
  192. (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_TRIG))
  193. {
  194. NRF_LOG_ERROR("Validate trigger: DFU already in progress (s:%s).",
  195. (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state));
  196. return false;
  197. }
  198. uint8_t trigger_version = (((background_dfu_trigger_t *)p_payload)->flags
  199. & TRIGGER_FLAGS_VERSION_MASK) >> TRIGGER_FLAGS_VERSION_OFFSET;
  200. if (trigger_version > TRIGGER_VERSION)
  201. {
  202. NRF_LOG_ERROR("Validate trigger: invalid trigger version.");
  203. return false;
  204. }
  205. return true;
  206. }
  207. bool background_dfu_process_trigger(background_dfu_context_t * p_dfu_ctx,
  208. const uint8_t * p_payload,
  209. uint32_t payload_len)
  210. {
  211. bool result = false;
  212. do
  213. {
  214. if (!parse_trigger(p_dfu_ctx, (background_dfu_trigger_t *)p_payload))
  215. {
  216. NRF_LOG_ERROR("Process trigger: failed to parse payload");
  217. break;
  218. }
  219. p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
  220. uint32_t err_code = background_dfu_handle_event(p_dfu_ctx,
  221. BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
  222. if (err_code != NRF_SUCCESS)
  223. {
  224. NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
  225. }
  226. result = true;
  227. } while(0);
  228. return result;
  229. }
  230. /***************************************************************************************************
  231. * @section DFU checks
  232. **************************************************************************************************/
  233. background_dfu_block_result_t background_dfu_process_block(background_dfu_context_t * p_dfu_ctx,
  234. const background_dfu_block_t * p_block)
  235. {
  236. background_dfu_block_result_t result = block_manager_block_process(&p_dfu_ctx->block_manager,
  237. p_block);
  238. uint32_t err_code = NRF_SUCCESS;
  239. switch (result)
  240. {
  241. case BACKGROUND_DFU_BLOCK_IGNORE:
  242. // Ignore.
  243. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  244. {
  245. restart_block_timeout_timer(p_dfu_ctx);
  246. }
  247. break;
  248. case BACKGROUND_DFU_BLOCK_SUCCESS:
  249. // Intentionally empty.
  250. break;
  251. default:
  252. err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
  253. if (err_code != NRF_SUCCESS)
  254. {
  255. NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
  256. }
  257. break;
  258. }
  259. return result;
  260. }
  261. /**@brief Check if installed image is different from the incoming one.
  262. *
  263. * @param[in] p_dfu_ctx A pointer to DFU client context.
  264. *
  265. * @return True if image different, false otherwise.
  266. *
  267. */
  268. static bool is_image_different(const background_dfu_context_t * p_dfu_ctx)
  269. {
  270. if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_INVALID)
  271. {
  272. NRF_LOG_WARNING("No image in bank 0");
  273. return true;
  274. }
  275. if (s_dfu_settings.bank_0.image_crc != p_dfu_ctx->firmware_crc)
  276. {
  277. NRF_LOG_WARNING("Installed image CRC is different");
  278. return true;
  279. }
  280. return false;
  281. }
  282. /**
  283. * @brief A callback function for block manager.
  284. */
  285. static void dfu_block_manager_result_handler(background_dfu_block_result_t result, void * p_context)
  286. {
  287. background_dfu_context_t * p_dfu_ctx = p_context;
  288. uint32_t err_code;
  289. if (result == BACKGROUND_DFU_BLOCK_SUCCESS)
  290. {
  291. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  292. {
  293. restart_block_timeout_timer(p_dfu_ctx);
  294. }
  295. if (block_manager_is_image_complete(&p_dfu_ctx->block_manager))
  296. {
  297. err_code = background_dfu_handle_event(p_dfu_ctx,
  298. BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
  299. if (err_code != NRF_SUCCESS)
  300. {
  301. NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
  302. }
  303. }
  304. else
  305. {
  306. // FIXME I don't like it here.
  307. p_dfu_ctx->block_num++;
  308. err_code = background_dfu_handle_event(p_dfu_ctx,
  309. BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE);
  310. if (err_code != NRF_SUCCESS)
  311. {
  312. NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
  313. }
  314. }
  315. }
  316. else
  317. {
  318. err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
  319. if (err_code != NRF_SUCCESS)
  320. {
  321. NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
  322. }
  323. }
  324. }
  325. /**
  326. * @brief Prepare state machine to download init command.
  327. */
  328. static void setup_download_init_command(background_dfu_context_t * p_dfu_ctx)
  329. {
  330. p_dfu_ctx->p_resource_size = &p_dfu_ctx->init_cmd_size;
  331. p_dfu_ctx->retry_count = DEFAULT_RETRIES;
  332. p_dfu_ctx->block_num = 0;
  333. background_dfu_transport_state_update(p_dfu_ctx);
  334. block_manager_init(&p_dfu_ctx->block_manager,
  335. p_dfu_ctx->dfu_state,
  336. *p_dfu_ctx->p_resource_size,
  337. p_dfu_ctx->block_num,
  338. dfu_block_manager_result_handler,
  339. p_dfu_ctx);
  340. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  341. {
  342. NRF_LOG_INFO("Init complete. Multicast Mode.");
  343. uint32_t jitter = block_request_jitter_get();
  344. uint32_t err_code = app_timer_start(m_missing_block_timer,
  345. APP_TIMER_TICKS(jitter),
  346. p_dfu_ctx);
  347. if (err_code != NRF_SUCCESS)
  348. {
  349. NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
  350. }
  351. }
  352. else
  353. {
  354. NRF_LOG_INFO("Init complete. Unicast Mode.");
  355. }
  356. }
  357. /**
  358. * @brief A callback function for DFU command operations.
  359. */
  360. static void dfu_init_check_callback(nrf_dfu_response_t * p_res, void * p_context)
  361. {
  362. background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
  363. switch (p_res->request)
  364. {
  365. case NRF_DFU_OP_OBJECT_SELECT:
  366. if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
  367. {
  368. NRF_LOG_ERROR("No valid init command - select failed");
  369. setup_download_init_command((background_dfu_context_t *)p_context);
  370. UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
  371. }
  372. p_dfu_ctx->max_obj_size = p_res->select.max_size;
  373. p_dfu_ctx->block_num = p_res->select.offset / DEFAULT_BLOCK_SIZE;
  374. if (background_dfu_op_execute(dfu_init_check_callback, p_context) != NRF_SUCCESS)
  375. {
  376. NRF_LOG_ERROR("No valid init command - execute error");
  377. setup_download_init_command((background_dfu_context_t *)p_context);
  378. UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
  379. }
  380. break;
  381. case NRF_DFU_OP_OBJECT_EXECUTE:
  382. if ((p_res->result != NRF_DFU_RES_CODE_SUCCESS) ||
  383. (s_dfu_settings.progress.command_crc != p_dfu_ctx->init_cmd_crc))
  384. {
  385. NRF_LOG_ERROR("Init commad has changed");
  386. p_dfu_ctx->remaining_size = 0;
  387. setup_download_init_command((background_dfu_context_t *)p_context);
  388. UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
  389. }
  390. else
  391. {
  392. // Valid init command stored, download firmware.
  393. p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
  394. UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE));
  395. }
  396. break;
  397. default:
  398. ASSERT(false);
  399. }
  400. }
  401. /**
  402. * @brief A callback function for DFU data operation.
  403. */
  404. static void dfu_data_select_callback(nrf_dfu_response_t * p_res, void * p_context)
  405. {
  406. ASSERT(p_res->request == NRF_DFU_OP_OBJECT_SELECT);
  407. background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
  408. if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
  409. {
  410. NRF_LOG_ERROR("Select failed");
  411. dfu_handle_error(p_dfu_ctx);
  412. return;
  413. }
  414. p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
  415. p_dfu_ctx->p_resource_size = &p_dfu_ctx->firmware_size;
  416. p_dfu_ctx->retry_count = DEFAULT_RETRIES;
  417. p_dfu_ctx->block_num = (p_res->select.offset / DEFAULT_BLOCK_SIZE);
  418. p_dfu_ctx->max_obj_size = p_res->select.max_size;
  419. background_dfu_transport_state_update(p_dfu_ctx);
  420. block_manager_init(&p_dfu_ctx->block_manager,
  421. p_dfu_ctx->dfu_state,
  422. *p_dfu_ctx->p_resource_size,
  423. p_dfu_ctx->block_num,
  424. dfu_block_manager_result_handler,
  425. p_dfu_ctx);
  426. UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
  427. }
  428. /***************************************************************************************************
  429. * @section Timer handlers
  430. **************************************************************************************************/
  431. /**@brief Handler function for block request timer.
  432. *
  433. * @param[inout] p_context DFU context.
  434. */
  435. static void block_request_handler(void * p_context)
  436. {
  437. background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
  438. if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
  439. (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
  440. {
  441. return;
  442. }
  443. background_dfu_request_bitmap_t req_bmp;
  444. if (block_manager_request_bitmap_get(&p_dfu_ctx->block_manager, &req_bmp) &&
  445. (req_bmp.size > 0))
  446. {
  447. background_dfu_transport_block_request_send(p_dfu_ctx, &req_bmp);
  448. }
  449. // Reschedule the timer.
  450. uint32_t jitter = block_request_jitter_get();
  451. uint32_t err_code = app_timer_start(m_missing_block_timer, APP_TIMER_TICKS(jitter), p_dfu_ctx);
  452. if (err_code != NRF_SUCCESS)
  453. {
  454. NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
  455. }
  456. }
  457. /**@brief Handler function for block timeout timer.
  458. *
  459. * @param[inout] p_context DFU context.
  460. */
  461. static void block_timeout_handler(void * p_context)
  462. {
  463. background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
  464. NRF_LOG_INFO("Block timeout! (b: %d)",
  465. block_manager_get_current_block(&p_dfu_ctx->block_manager));
  466. if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
  467. (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
  468. {
  469. return;
  470. }
  471. if (block_manager_increment_current_block(&p_dfu_ctx->block_manager))
  472. {
  473. start_block_timeout_timer(p_dfu_ctx);
  474. }
  475. }
  476. /***************************************************************************************************
  477. * @section API functions
  478. **************************************************************************************************/
  479. /** @brief Helper function converting DFU state to string.
  480. *
  481. * @param[in] state DFU client state.
  482. *
  483. * @return A pointer to null terminated string with state name.
  484. */
  485. const char * background_dfu_state_to_string(const background_dfu_state_t state)
  486. {
  487. static const char * const names[] =
  488. {
  489. "DFU_DOWNLOAD_INIT_CMD",
  490. "DFU_DOWNLOAD_FIRMWARE",
  491. "DFU_DOWNLOAD_TRIG",
  492. "DFU_WAIT_FOR_RESET",
  493. "DFU_IDLE",
  494. "DFU_ERROR",
  495. };
  496. return names[(uint32_t)state - BACKGROUND_DFU_DOWNLOAD_INIT_CMD];
  497. }
  498. /** @brief Helper function convering DFU event name to string.
  499. *
  500. * @param[in] state DFU client event.
  501. *
  502. * @return A pointer to null terminated string with event name.
  503. */
  504. const char * background_dfu_event_to_string(const background_dfu_event_t event)
  505. {
  506. static const char * const names[] = {
  507. "DFU_EVENT_TRANSFER_COMPLETE",
  508. "DFU_EVENT_TRANSFER_CONTINUE",
  509. "DFU_EVENT_TRANSFER_ERROR",
  510. "DFU_EVENT_PROCESSING_ERROR",
  511. };
  512. return names[event];
  513. }
  514. uint32_t background_dfu_handle_event(background_dfu_context_t * p_dfu_ctx,
  515. background_dfu_event_t event)
  516. {
  517. uint32_t err_code = NRF_SUCCESS;
  518. NRF_LOG_INFO("state=%s event=%s",
  519. (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state),
  520. (uint32_t)background_dfu_event_to_string(event));
  521. switch (p_dfu_ctx->dfu_state)
  522. {
  523. case BACKGROUND_DFU_IDLE:
  524. {
  525. if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
  526. {
  527. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
  528. p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
  529. p_dfu_ctx->block_num = 0;
  530. p_dfu_ctx->retry_count = DEFAULT_RETRIES;
  531. background_dfu_transport_state_update(p_dfu_ctx);
  532. }
  533. break;
  534. }
  535. case BACKGROUND_DFU_DOWNLOAD_TRIG:
  536. {
  537. if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
  538. {
  539. if (!is_image_different(p_dfu_ctx))
  540. {
  541. NRF_LOG_INFO("Image is already installed");
  542. background_dfu_reset_state(p_dfu_ctx);
  543. break;
  544. }
  545. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
  546. p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
  547. // Initiate init command check procedure.
  548. if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_COMMAND,
  549. dfu_init_check_callback,
  550. p_dfu_ctx) != NRF_SUCCESS)
  551. {
  552. NRF_LOG_ERROR("No valid init command - select error");
  553. setup_download_init_command(p_dfu_ctx);
  554. }
  555. else
  556. {
  557. // We wait for dfu request to finish - do not send anything.
  558. return NRF_SUCCESS;
  559. }
  560. }
  561. break;
  562. }
  563. case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
  564. {
  565. if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
  566. {
  567. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
  568. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  569. {
  570. stop_block_timeout_timer(p_dfu_ctx);
  571. }
  572. if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_DATA,
  573. dfu_data_select_callback,
  574. p_dfu_ctx) != NRF_SUCCESS)
  575. {
  576. NRF_LOG_ERROR("Select failed");
  577. dfu_handle_error(p_dfu_ctx);
  578. err_code = NRF_ERROR_INTERNAL;
  579. }
  580. else
  581. {
  582. return NRF_SUCCESS;
  583. }
  584. }
  585. else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
  586. {
  587. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
  588. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  589. {
  590. stop_block_timeout_timer(p_dfu_ctx);
  591. }
  592. NRF_LOG_ERROR("Processing error while downloading init command.");
  593. dfu_handle_error(p_dfu_ctx);
  594. }
  595. break;
  596. }
  597. case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
  598. {
  599. if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
  600. {
  601. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
  602. p_dfu_ctx->dfu_state = BACKGROUND_DFU_WAIT_FOR_RESET;
  603. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  604. {
  605. stop_block_timeout_timer(p_dfu_ctx);
  606. }
  607. background_dfu_transport_state_update(p_dfu_ctx);
  608. }
  609. else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
  610. {
  611. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
  612. if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
  613. {
  614. stop_block_timeout_timer(p_dfu_ctx);
  615. }
  616. NRF_LOG_ERROR("Processing error while downloading firmware.");
  617. dfu_handle_error(p_dfu_ctx);
  618. }
  619. break;
  620. }
  621. case BACKGROUND_DFU_WAIT_FOR_RESET:
  622. NRF_LOG_WARNING("An event received in wait for reset state. This should not happen.");
  623. break;
  624. default:
  625. NRF_LOG_ERROR("Unhandled state");
  626. break;
  627. }
  628. if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
  629. (p_dfu_ctx->dfu_state != BACKGROUND_DFU_ERROR) &&
  630. (p_dfu_ctx->dfu_state != BACKGROUND_DFU_WAIT_FOR_RESET))
  631. {
  632. if (((p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_FIRMWARE) ||
  633. (p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_INIT_CMD)) &&
  634. (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST))
  635. {
  636. // In multicast DFU firmware download, client doesn't initiate block requests.
  637. }
  638. else
  639. {
  640. if ((event == BACKGROUND_DFU_EVENT_TRANSFER_ERROR) && (p_dfu_ctx->retry_count > 0))
  641. {
  642. p_dfu_ctx->retry_count -= 1;
  643. }
  644. if (p_dfu_ctx->retry_count > 0)
  645. {
  646. background_dfu_transport_send_request(p_dfu_ctx);
  647. }
  648. else
  649. {
  650. NRF_LOG_ERROR("No more retries");
  651. dfu_handle_error(p_dfu_ctx);
  652. }
  653. }
  654. }
  655. return err_code;
  656. }
  657. void background_dfu_reset_state(background_dfu_context_t * p_dfu_ctx)
  658. {
  659. sha256_context_t sha256_ctx;
  660. uint8_t hash[32];
  661. uint32_t err_code = NRF_SUCCESS;
  662. p_dfu_ctx->dfu_state = BACKGROUND_DFU_IDLE;
  663. p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
  664. p_dfu_ctx->init_cmd_size = 0;
  665. p_dfu_ctx->firmware_size = 0;
  666. p_dfu_ctx->remaining_size = 0;
  667. memset(&p_dfu_ctx->dfu_diag, 0, sizeof(p_dfu_ctx->dfu_diag));
  668. err_code = sha256_init(&sha256_ctx);
  669. if (err_code != NRF_SUCCESS)
  670. {
  671. NRF_LOG_ERROR("Error in sha256_init (%d)", err_code);
  672. }
  673. err_code = sha256_update(&sha256_ctx, (const uint8_t *)DFU_DATE_TIME, strlen(DFU_DATE_TIME));
  674. if (err_code != NRF_SUCCESS)
  675. {
  676. NRF_LOG_ERROR("Error in sha256_update (%d)", err_code);
  677. }
  678. err_code = sha256_final(&sha256_ctx, (uint8_t *)hash, false);
  679. if (err_code != NRF_SUCCESS)
  680. {
  681. NRF_LOG_ERROR("Error in sha256_final (%d)", err_code);
  682. }
  683. p_dfu_ctx->dfu_diag.build_id = uint32_big_decode(hash);
  684. p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_IDLE;
  685. p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
  686. NRF_LOG_INFO("Current DFU Diag version: %s, 0x%08x",
  687. (uint32_t)DFU_DATE_TIME, p_dfu_ctx->dfu_diag.build_id);
  688. }
  689. void background_dfu_state_init(background_dfu_context_t * p_dfu_ctx)
  690. {
  691. uint32_t err_code;
  692. err_code = app_timer_create(&m_missing_block_timer,
  693. APP_TIMER_MODE_SINGLE_SHOT,
  694. block_request_handler);
  695. if (err_code != NRF_SUCCESS)
  696. {
  697. NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
  698. }
  699. err_code = app_timer_create(&m_block_timeout_timer,
  700. APP_TIMER_MODE_SINGLE_SHOT,
  701. block_timeout_handler);
  702. if (err_code != NRF_SUCCESS)
  703. {
  704. NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
  705. }
  706. background_dfu_reset_state(p_dfu_ctx);
  707. }