nrf_dfu_req_handler.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /**
  2. * Copyright (c) 2016 - 2020, 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. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include "sdk_config.h"
  43. #include "nrf_dfu.h"
  44. #include "nrf_dfu_types.h"
  45. #include "nrf_dfu_req_handler.h"
  46. #include "nrf_dfu_handling_error.h"
  47. #include "nrf_dfu_settings.h"
  48. #include "nrf_dfu_utils.h"
  49. #include "nrf_dfu_flash.h"
  50. #include "nrf_fstorage.h"
  51. #include "nrf_bootloader_info.h"
  52. #include "app_util.h"
  53. #include "pb.h"
  54. #include "pb_common.h"
  55. #include "pb_decode.h"
  56. #include "dfu-cc.pb.h"
  57. #include "crc32.h"
  58. #include "app_scheduler.h"
  59. #include "sdk_macros.h"
  60. #include "nrf_crypto.h"
  61. #include "nrf_assert.h"
  62. #include "nrf_dfu_validation.h"
  63. #define NRF_LOG_MODULE_NAME nrf_dfu_req_handler
  64. #include "nrf_log.h"
  65. NRF_LOG_MODULE_REGISTER();
  66. #define NRF_DFU_PROTOCOL_VERSION (0x01)
  67. #ifndef NRF_DFU_PROTOCOL_REDUCED
  68. #define NRF_DFU_PROTOCOL_REDUCED 0
  69. #endif
  70. STATIC_ASSERT(DFU_SIGNED_COMMAND_SIZE <= INIT_COMMAND_MAX_SIZE);
  71. static uint32_t m_firmware_start_addr; /**< Start address of the current firmware image. */
  72. static uint32_t m_firmware_size_req; /**< The size of the entire firmware image. Defined by the init command. */
  73. static nrf_dfu_observer_t m_observer;
  74. static void on_dfu_complete(nrf_fstorage_evt_t * p_evt)
  75. {
  76. UNUSED_PARAMETER(p_evt);
  77. NRF_LOG_DEBUG("All flash operations have completed. DFU completed.");
  78. m_observer(NRF_DFU_EVT_DFU_COMPLETED);
  79. }
  80. static nrf_dfu_result_t ext_err_code_handle(nrf_dfu_result_t ret_val)
  81. {
  82. if (ret_val < NRF_DFU_RES_CODE_EXT_ERROR)
  83. {
  84. return ret_val;
  85. }
  86. else
  87. {
  88. nrf_dfu_ext_error_code_t ext_err =
  89. (nrf_dfu_ext_error_code_t)((uint8_t)ret_val - (uint8_t)NRF_DFU_RES_CODE_EXT_ERROR);
  90. return ext_error_set(ext_err);
  91. }
  92. }
  93. #if !NRF_DFU_PROTOCOL_REDUCED
  94. static void on_protocol_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  95. {
  96. UNUSED_PARAMETER(p_req);
  97. NRF_LOG_DEBUG("Handle NRF_DFU_OP_PROTOCOL_VERSION");
  98. if (NRF_DFU_PROTOCOL_VERSION_MSG)
  99. {
  100. p_res->protocol.version = NRF_DFU_PROTOCOL_VERSION;
  101. }
  102. else
  103. {
  104. NRF_LOG_DEBUG("NRF_DFU_OP_PROTOCOL_VERSION disabled.");
  105. p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
  106. }
  107. }
  108. static void on_hw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  109. {
  110. NRF_LOG_DEBUG("Handle NRF_DFU_OP_HARDWARE_VERSION");
  111. p_res->hardware.part = NRF_FICR->INFO.PART;
  112. p_res->hardware.variant = NRF_FICR->INFO.VARIANT;
  113. /* FICR values are in Kilobytes, we report them in bytes. */
  114. p_res->hardware.memory.ram_size = NRF_FICR->INFO.RAM * 1024;
  115. p_res->hardware.memory.rom_size = NRF_FICR->INFO.FLASH * 1024;
  116. p_res->hardware.memory.rom_page_size = NRF_FICR->CODEPAGESIZE;
  117. }
  118. static void on_fw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  119. {
  120. NRF_LOG_DEBUG("Handle NRF_DFU_OP_FIRMWARE_VERSION");
  121. NRF_LOG_DEBUG("Firmware image requested: %d", p_req->firmware.image_number);
  122. if (NRF_DFU_PROTOCOL_FW_VERSION_MSG)
  123. {
  124. uint8_t fw_count = 1;
  125. if (SD_PRESENT)
  126. {
  127. fw_count++;
  128. }
  129. if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
  130. {
  131. fw_count++;
  132. }
  133. p_res->result = NRF_DFU_RES_CODE_SUCCESS;
  134. if (p_req->firmware.image_number == 0)
  135. {
  136. /* Bootloader is always present and it is always image zero. */
  137. p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_BOOTLOADER;
  138. p_res->firmware.version = s_dfu_settings.bootloader_version;
  139. p_res->firmware.addr = BOOTLOADER_START_ADDR;
  140. p_res->firmware.len = BOOTLOADER_SIZE;
  141. }
  142. else if ((p_req->firmware.image_number == 1) && SD_PRESENT)
  143. {
  144. /* If a SoftDevice is present, it will be firmware image one. */
  145. p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE;
  146. p_res->firmware.version = SD_VERSION_GET(MBR_SIZE);
  147. p_res->firmware.addr = MBR_SIZE;
  148. p_res->firmware.len = SD_SIZE_GET(MBR_SIZE);
  149. }
  150. else if ((p_req->firmware.image_number < fw_count))
  151. {
  152. /* Either there is no SoftDevice and the firmware image requested is one,
  153. * or there is a SoftDevice and the firmware image requested is two.
  154. */
  155. p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_APPLICATION;
  156. p_res->firmware.version = s_dfu_settings.app_version;
  157. p_res->firmware.addr = nrf_dfu_app_start_address();
  158. p_res->firmware.len = s_dfu_settings.bank_0.image_size;
  159. }
  160. else
  161. {
  162. NRF_LOG_DEBUG("No such firmware image");
  163. p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
  164. p_res->firmware.version = 0x00;
  165. p_res->firmware.addr = 0x00;
  166. p_res->firmware.len = 0x00;
  167. }
  168. }
  169. else
  170. {
  171. NRF_LOG_DEBUG("NRF_DFU_OP_FIRMWARE_VERSION disabled.");
  172. p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
  173. p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
  174. }
  175. }
  176. static void on_ping_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  177. {
  178. NRF_LOG_DEBUG("Handle NRF_DFU_OP_PING");
  179. p_res->ping.id = p_req->ping.id;
  180. }
  181. static void on_mtu_get_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  182. {
  183. NRF_LOG_DEBUG("Handle NRF_DFU_OP_MTU_GET");
  184. p_res->mtu.size = p_req->mtu.size;
  185. }
  186. #endif // !NRF_DFU_PROTOCOL_REDUCED
  187. static void on_prn_set_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  188. {
  189. UNUSED_PARAMETER(p_req);
  190. UNUSED_PARAMETER(p_res);
  191. NRF_LOG_DEBUG("Handle NRF_DFU_OP_RECEIPT_NOTIF_SET");
  192. }
  193. static void on_abort_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  194. {
  195. UNUSED_PARAMETER(p_req);
  196. UNUSED_PARAMETER(p_res);
  197. NRF_LOG_DEBUG("Handle NRF_DFU_OP_ABORT");
  198. m_observer(NRF_DFU_EVT_DFU_ABORTED);
  199. }
  200. /* Set offset and CRC fields in the response for a 'command' message. */
  201. static void cmd_response_offset_and_crc_set(nrf_dfu_response_t * const p_res)
  202. {
  203. ASSERT(p_res);
  204. /* Copy the CRC and offset of the init packet. */
  205. p_res->crc.offset = s_dfu_settings.progress.command_offset;
  206. p_res->crc.crc = s_dfu_settings.progress.command_crc;
  207. }
  208. static void on_cmd_obj_select_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  209. {
  210. UNUSED_PARAMETER(p_req);
  211. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (command)");
  212. p_res->select.max_size = INIT_COMMAND_MAX_SIZE;
  213. cmd_response_offset_and_crc_set(p_res);
  214. }
  215. static void on_cmd_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  216. {
  217. ASSERT(p_req);
  218. ASSERT(p_res);
  219. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (command)");
  220. m_observer(NRF_DFU_EVT_DFU_STARTED);
  221. nrf_dfu_result_t ret_val = nrf_dfu_validation_init_cmd_create(p_req->create.object_size);
  222. p_res->result = ext_err_code_handle(ret_val);
  223. }
  224. static void on_cmd_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  225. {
  226. ASSERT(p_req);
  227. ASSERT(p_req->write.p_data);
  228. ASSERT(p_req->write.len);
  229. ASSERT(p_res);
  230. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (command)");
  231. nrf_dfu_result_t ret_val;
  232. ret_val = nrf_dfu_validation_init_cmd_append(p_req->write.p_data, p_req->write.len);
  233. p_res->result = ext_err_code_handle(ret_val);
  234. /* Update response. This is only used when the PRN is triggered and the 'write' message
  235. * is answered with a CRC message and these field are copied into the response. */
  236. cmd_response_offset_and_crc_set(p_res);
  237. /* If a callback to free the request payload buffer was provided, invoke it now. */
  238. if (p_req->callback.write)
  239. {
  240. p_req->callback.write((void*)p_req->write.p_data);
  241. }
  242. }
  243. static void on_cmd_obj_execute_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  244. {
  245. ASSERT(p_req);
  246. ASSERT(p_res);
  247. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (command)");
  248. nrf_dfu_result_t ret_val;
  249. ret_val = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
  250. p_res->result = ext_err_code_handle(ret_val);
  251. if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
  252. {
  253. if (nrf_dfu_settings_write_and_backup(NULL) == NRF_SUCCESS)
  254. {
  255. /* Setting DFU to initialized */
  256. NRF_LOG_DEBUG("Writing valid init command to flash.");
  257. }
  258. else
  259. {
  260. p_res->result = NRF_DFU_RES_CODE_OPERATION_FAILED;
  261. }
  262. }
  263. }
  264. static void on_cmd_obj_crc_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
  265. {
  266. UNUSED_PARAMETER(p_req);
  267. NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (command)");
  268. cmd_response_offset_and_crc_set(p_res);
  269. }
  270. /** @brief Function handling command requests from the transport layer.
  271. *
  272. * @param p_req[in] Pointer to the structure holding the DFU request.
  273. * @param p_res[out] Pointer to the structure holding the DFU response.
  274. *
  275. * @retval NRF_SUCCESS If the command request was executed successfully.
  276. * Any other error code indicates that the data request
  277. * could not be handled.
  278. */
  279. static void nrf_dfu_command_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  280. {
  281. ASSERT(p_req);
  282. ASSERT(p_res);
  283. switch (p_req->request)
  284. {
  285. case NRF_DFU_OP_OBJECT_CREATE:
  286. {
  287. on_cmd_obj_create_request(p_req, p_res);
  288. } break;
  289. case NRF_DFU_OP_CRC_GET:
  290. {
  291. on_cmd_obj_crc_request(p_req, p_res);
  292. } break;
  293. case NRF_DFU_OP_OBJECT_WRITE:
  294. {
  295. on_cmd_obj_write_request(p_req, p_res);
  296. } break;
  297. case NRF_DFU_OP_OBJECT_EXECUTE:
  298. {
  299. on_cmd_obj_execute_request(p_req, p_res);
  300. } break;
  301. case NRF_DFU_OP_OBJECT_SELECT:
  302. {
  303. on_cmd_obj_select_request(p_req, p_res);
  304. } break;
  305. default:
  306. {
  307. ASSERT(false);
  308. } break;
  309. }
  310. }
  311. static void on_data_obj_select_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  312. {
  313. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (data)");
  314. p_res->select.crc = s_dfu_settings.progress.firmware_image_crc;
  315. p_res->select.offset = s_dfu_settings.progress.firmware_image_offset;
  316. p_res->select.max_size = DATA_OBJECT_MAX_SIZE;
  317. NRF_LOG_DEBUG("crc = 0x%x, offset = 0x%x, max_size = 0x%x",
  318. p_res->select.crc,
  319. p_res->select.offset,
  320. p_res->select.max_size);
  321. }
  322. static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  323. {
  324. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
  325. if (!nrf_dfu_validation_init_cmd_present())
  326. {
  327. /* Can't accept data because DFU isn't initialized by init command. */
  328. NRF_LOG_ERROR("Cannot create data object without valid init command");
  329. p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
  330. return;
  331. }
  332. if (p_req->create.object_size == 0)
  333. {
  334. NRF_LOG_ERROR("Object size cannot be 0.")
  335. p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
  336. return;
  337. }
  338. if ( ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
  339. && (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
  340. {
  341. NRF_LOG_ERROR("Object size must be page aligned");
  342. p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
  343. return;
  344. }
  345. if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
  346. {
  347. /* It is impossible to handle the command because the size is too large */
  348. NRF_LOG_ERROR("Invalid size for object (too large)");
  349. p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
  350. return;
  351. }
  352. if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
  353. m_firmware_size_req)
  354. {
  355. NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
  356. "Offset is 0x%08x and firmware size is 0x%08x.",
  357. p_req->create.object_size,
  358. s_dfu_settings.progress.firmware_image_offset_last,
  359. m_firmware_size_req);
  360. p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
  361. return;
  362. }
  363. s_dfu_settings.progress.data_object_size = p_req->create.object_size;
  364. s_dfu_settings.progress.firmware_image_crc = s_dfu_settings.progress.firmware_image_crc_last;
  365. s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
  366. s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
  367. /* Erase the page we're at. */
  368. if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
  369. CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
  370. {
  371. NRF_LOG_ERROR("Erase operation failed");
  372. p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
  373. return;
  374. }
  375. NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
  376. s_dfu_settings.progress.data_object_size,
  377. s_dfu_settings.progress.firmware_image_offset,
  378. s_dfu_settings.progress.firmware_image_crc);
  379. }
  380. static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  381. {
  382. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");
  383. if (!nrf_dfu_validation_init_cmd_present())
  384. {
  385. /* Can't accept data because DFU isn't initialized by init command. */
  386. p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
  387. return;
  388. }
  389. uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
  390. s_dfu_settings.progress.firmware_image_offset_last;
  391. if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
  392. {
  393. /* Can't accept data because too much data has been received. */
  394. NRF_LOG_ERROR("Write request too long");
  395. p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
  396. return;
  397. }
  398. uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
  399. /* CRC must be calculated before handing off the data to fstorage because the data is
  400. * freed on write completion.
  401. */
  402. uint32_t const next_crc =
  403. crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);
  404. ASSERT(p_req->callback.write);
  405. ret_code_t ret =
  406. nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
  407. if (ret != NRF_SUCCESS)
  408. {
  409. /* When nrf_dfu_flash_store() fails because there is no space in the queue,
  410. * stop processing the request so that the peer can detect a CRC error
  411. * and retransmit this object. Remember to manually free the buffer !
  412. */
  413. p_req->callback.write((void*)p_req->write.p_data);
  414. return;
  415. }
  416. /* Update the CRC of the firmware image. */
  417. s_dfu_settings.write_offset += p_req->write.len;
  418. s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
  419. s_dfu_settings.progress.firmware_image_crc = next_crc;
  420. /* This is only used when the PRN is triggered and the 'write' message
  421. * is answered with a CRC message and these field are copied into the response.
  422. */
  423. p_res->write.crc = s_dfu_settings.progress.firmware_image_crc;
  424. p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
  425. }
  426. static void on_data_obj_crc_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  427. {
  428. NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (data)");
  429. NRF_LOG_DEBUG("Offset:%d, CRC:0x%08x",
  430. s_dfu_settings.progress.firmware_image_offset,
  431. s_dfu_settings.progress.firmware_image_crc);
  432. p_res->crc.crc = s_dfu_settings.progress.firmware_image_crc;
  433. p_res->crc.offset = s_dfu_settings.progress.firmware_image_offset;
  434. }
  435. static void on_data_obj_execute_request_sched(void * p_evt, uint16_t event_length)
  436. {
  437. UNUSED_PARAMETER(event_length);
  438. ret_code_t ret;
  439. nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
  440. /* Wait for all buffers to be written in flash. */
  441. if (nrf_fstorage_is_busy(NULL))
  442. {
  443. ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), on_data_obj_execute_request_sched);
  444. if (ret != NRF_SUCCESS)
  445. {
  446. NRF_LOG_ERROR("Failed to schedule object execute: 0x%x.", ret);
  447. }
  448. return;
  449. }
  450. nrf_dfu_response_t res =
  451. {
  452. .request = NRF_DFU_OP_OBJECT_EXECUTE,
  453. };
  454. if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req)
  455. {
  456. NRF_LOG_DEBUG("Whole firmware image received. Postvalidating.");
  457. #if NRF_DFU_IN_APP
  458. res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
  459. #else
  460. res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
  461. #endif
  462. res.result = ext_err_code_handle(res.result);
  463. /* Provide response to transport */
  464. p_req->callback.response(&res, p_req->p_context);
  465. ret = nrf_dfu_settings_write_and_backup((nrf_dfu_flash_callback_t)on_dfu_complete);
  466. UNUSED_RETURN_VALUE(ret);
  467. }
  468. else
  469. {
  470. res.result = NRF_DFU_RES_CODE_SUCCESS;
  471. /* Provide response to transport */
  472. p_req->callback.response(&res, p_req->p_context);
  473. if (NRF_DFU_SAVE_PROGRESS_IN_FLASH)
  474. {
  475. /* Allowing skipping settings backup to save time and flash wear. */
  476. ret = nrf_dfu_settings_write_and_backup(NULL);
  477. UNUSED_RETURN_VALUE(ret);
  478. }
  479. }
  480. NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", res.result);
  481. }
  482. static bool on_data_obj_execute_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  483. {
  484. NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (data)");
  485. uint32_t const data_object_size = s_dfu_settings.progress.firmware_image_offset -
  486. s_dfu_settings.progress.firmware_image_offset_last;
  487. if (s_dfu_settings.progress.data_object_size != data_object_size)
  488. {
  489. /* The size of the written object was not as expected. */
  490. NRF_LOG_ERROR("Invalid data. expected: %d, got: %d",
  491. s_dfu_settings.progress.data_object_size,
  492. data_object_size);
  493. p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
  494. return true;
  495. }
  496. /* Update the offset and crc values for the last object written. */
  497. s_dfu_settings.progress.data_object_size = 0;
  498. s_dfu_settings.progress.firmware_image_crc_last = s_dfu_settings.progress.firmware_image_crc;
  499. s_dfu_settings.progress.firmware_image_offset_last = s_dfu_settings.progress.firmware_image_offset;
  500. on_data_obj_execute_request_sched(p_req, 0);
  501. m_observer(NRF_DFU_EVT_OBJECT_RECEIVED);
  502. return false;
  503. }
  504. static bool nrf_dfu_data_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  505. {
  506. ASSERT(p_req);
  507. ASSERT(p_res);
  508. bool response_ready = true;
  509. switch (p_req->request)
  510. {
  511. case NRF_DFU_OP_OBJECT_CREATE:
  512. {
  513. on_data_obj_create_request(p_req, p_res);
  514. } break;
  515. case NRF_DFU_OP_OBJECT_WRITE:
  516. {
  517. on_data_obj_write_request(p_req, p_res);
  518. } break;
  519. case NRF_DFU_OP_CRC_GET:
  520. {
  521. on_data_obj_crc_request(p_req, p_res);
  522. } break;
  523. case NRF_DFU_OP_OBJECT_EXECUTE:
  524. {
  525. response_ready = on_data_obj_execute_request(p_req, p_res);
  526. } break;
  527. case NRF_DFU_OP_OBJECT_SELECT:
  528. {
  529. on_data_obj_select_request(p_req, p_res);
  530. } break;
  531. default:
  532. {
  533. ASSERT(false);
  534. } break;
  535. }
  536. return response_ready;
  537. }
  538. /**@brief Function for handling requests to manipulate data or command objects.
  539. *
  540. * @param[in] p_req Request.
  541. * @param[out] p_res Response.
  542. *
  543. * @return Whether response is ready to be sent.
  544. */
  545. static bool nrf_dfu_obj_op(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
  546. {
  547. /* Keep track of the current object type since write and execute requests don't contain it. */
  548. static nrf_dfu_obj_type_t current_object = NRF_DFU_OBJ_TYPE_COMMAND;
  549. if ( (p_req->request == NRF_DFU_OP_OBJECT_SELECT)
  550. || (p_req->request == NRF_DFU_OP_OBJECT_CREATE))
  551. {
  552. STATIC_ASSERT(offsetof(nrf_dfu_request_select_t, object_type) ==
  553. offsetof(nrf_dfu_request_create_t, object_type),
  554. "Wrong object_type offset!");
  555. current_object = (nrf_dfu_obj_type_t)(p_req->select.object_type);
  556. }
  557. bool response_ready = true;
  558. switch (current_object)
  559. {
  560. case NRF_DFU_OBJ_TYPE_COMMAND:
  561. nrf_dfu_command_req(p_req, p_res);
  562. break;
  563. case NRF_DFU_OBJ_TYPE_DATA:
  564. response_ready = nrf_dfu_data_req(p_req, p_res);
  565. break;
  566. default:
  567. /* The select request had an invalid object type. */
  568. NRF_LOG_ERROR("Invalid object type in request.");
  569. current_object = NRF_DFU_OBJ_TYPE_INVALID;
  570. p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
  571. break;
  572. }
  573. return response_ready;
  574. }
  575. static void nrf_dfu_req_handler_req_process(nrf_dfu_request_t * p_req)
  576. {
  577. ASSERT(p_req->callback.response);
  578. bool response_ready = true;
  579. /* The request handlers assume these values to be set. */
  580. nrf_dfu_response_t response =
  581. {
  582. .request = p_req->request,
  583. .result = NRF_DFU_RES_CODE_SUCCESS,
  584. };
  585. switch (p_req->request)
  586. {
  587. #if !NRF_DFU_PROTOCOL_REDUCED
  588. case NRF_DFU_OP_PROTOCOL_VERSION:
  589. {
  590. on_protocol_version_request(p_req, &response);
  591. } break;
  592. case NRF_DFU_OP_HARDWARE_VERSION:
  593. {
  594. on_hw_version_request(p_req, &response);
  595. } break;
  596. case NRF_DFU_OP_FIRMWARE_VERSION:
  597. {
  598. on_fw_version_request(p_req, &response);
  599. } break;
  600. case NRF_DFU_OP_PING:
  601. {
  602. on_ping_request(p_req, &response);
  603. } break;
  604. case NRF_DFU_OP_MTU_GET:
  605. {
  606. on_mtu_get_request(p_req, &response);
  607. } break;
  608. #endif
  609. case NRF_DFU_OP_RECEIPT_NOTIF_SET:
  610. {
  611. on_prn_set_request(p_req, &response);
  612. } break;
  613. case NRF_DFU_OP_ABORT:
  614. {
  615. on_abort_request(p_req, &response);
  616. } break;
  617. case NRF_DFU_OP_OBJECT_CREATE:
  618. /* Restart the inactivity timer on CREATE messages. */
  619. /* Fallthrough. */
  620. case NRF_DFU_OP_OBJECT_SELECT:
  621. case NRF_DFU_OP_OBJECT_WRITE:
  622. case NRF_DFU_OP_OBJECT_EXECUTE:
  623. case NRF_DFU_OP_CRC_GET:
  624. {
  625. response_ready = nrf_dfu_obj_op(p_req, &response);
  626. } break;
  627. default:
  628. NRF_LOG_INFO("Invalid opcode received: 0x%x.", p_req->request);
  629. response.result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
  630. break;
  631. }
  632. if (response_ready)
  633. {
  634. NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", response.result);
  635. p_req->callback.response(&response, p_req->p_context);
  636. if (response.result != NRF_DFU_RES_CODE_SUCCESS)
  637. {
  638. m_observer(NRF_DFU_EVT_DFU_FAILED);
  639. }
  640. }
  641. }
  642. static void nrf_dfu_req_handler_req(void * p_evt, uint16_t event_length)
  643. {
  644. nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
  645. nrf_dfu_req_handler_req_process(p_req);
  646. }
  647. ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req)
  648. {
  649. ret_code_t ret;
  650. if (p_req->callback.response == NULL)
  651. {
  652. return NRF_ERROR_INVALID_PARAM;
  653. }
  654. ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), nrf_dfu_req_handler_req);
  655. if (ret != NRF_SUCCESS)
  656. {
  657. NRF_LOG_WARNING("Scheduler ran out of space!");
  658. }
  659. return ret;
  660. }
  661. ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer)
  662. {
  663. ret_code_t ret_val;
  664. nrf_dfu_result_t result;
  665. if (observer == NULL)
  666. {
  667. return NRF_ERROR_INVALID_PARAM;
  668. }
  669. #if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
  670. ret_val = nrf_dfu_flash_init(true);
  671. #else
  672. ret_val = nrf_dfu_flash_init(false);
  673. #endif
  674. if (ret_val != NRF_SUCCESS)
  675. {
  676. return ret_val;
  677. }
  678. nrf_dfu_validation_init();
  679. if (nrf_dfu_validation_init_cmd_present())
  680. {
  681. /* Execute a previously received init packed. Subsequent executes will have no effect. */
  682. result = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
  683. if (result != NRF_DFU_RES_CODE_SUCCESS)
  684. {
  685. /* Init packet in flash is not valid! */
  686. return NRF_ERROR_INTERNAL;
  687. }
  688. }
  689. m_observer = observer;
  690. /* Initialize extended error handling with "No error" as the most recent error. */
  691. result = ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
  692. UNUSED_RETURN_VALUE(result);
  693. return NRF_SUCCESS;
  694. }