nrf_dfu_serial.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /**
  2. * Copyright (c) 2017 - 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 "nrf_dfu_serial.h"
  41. #include "nrf_dfu_req_handler.h"
  42. #include "nrf_dfu_handling_error.h"
  43. #define NRF_LOG_MODULE_NAME nrf_dfu_serial
  44. #include "nrf_log.h"
  45. NRF_LOG_MODULE_REGISTER();
  46. #define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
  47. #if defined(NRF_DFU_PROTOCOL_REDUCED) && NRF_DFU_PROTOCOL_REDUCED
  48. #error Serial DFU (UART and USB) cannot function with the reduced protocol set.
  49. #endif
  50. static uint32_t response_ext_err_payload_add(uint8_t * p_buffer, uint32_t buf_offset)
  51. {
  52. p_buffer[buf_offset] = ext_error_get();
  53. (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
  54. return 1;
  55. }
  56. static void response_send(nrf_dfu_serial_t * p_transport,
  57. nrf_dfu_response_t const * p_response)
  58. {
  59. uint8_t index = 0;
  60. uint8_t * p_serialized_rsp = p_transport->p_rsp_buf;
  61. NRF_LOG_DEBUG("Sending Response: [0x%01x, 0x%01x]", p_response->request, p_response->result);
  62. p_serialized_rsp[index++] = NRF_DFU_OP_RESPONSE;
  63. p_serialized_rsp[index++] = p_response->request;
  64. p_serialized_rsp[index++] = (uint8_t)(p_response->result);
  65. if (p_response->result == NRF_DFU_RES_CODE_SUCCESS)
  66. {
  67. switch (p_response->request)
  68. {
  69. case NRF_DFU_OP_PROTOCOL_VERSION:
  70. {
  71. p_serialized_rsp[index] = p_response->protocol.version;
  72. index += sizeof(uint8_t);
  73. } break;
  74. case NRF_DFU_OP_HARDWARE_VERSION:
  75. {
  76. index += uint32_encode(p_response->hardware.part, &p_serialized_rsp[index]);
  77. index += uint32_encode(p_response->hardware.variant, &p_serialized_rsp[index]);
  78. index += uint32_encode(p_response->hardware.memory.rom_size, &p_serialized_rsp[index]);
  79. index += uint32_encode(p_response->hardware.memory.ram_size, &p_serialized_rsp[index]);
  80. index += uint32_encode(p_response->hardware.memory.rom_page_size, &p_serialized_rsp[index]);
  81. } break;
  82. case NRF_DFU_OP_FIRMWARE_VERSION:
  83. {
  84. p_serialized_rsp[index++] = p_response->firmware.type;
  85. index += uint32_encode(p_response->firmware.version, &p_serialized_rsp[index]);
  86. index += uint32_encode(p_response->firmware.addr, &p_serialized_rsp[index]);
  87. index += uint32_encode(p_response->firmware.len, &p_serialized_rsp[index]);
  88. } break;
  89. case NRF_DFU_OP_CRC_GET:
  90. index += uint32_encode(p_response->crc.offset, &p_serialized_rsp[index]);
  91. index += uint32_encode(p_response->crc.crc, &p_serialized_rsp[index]);
  92. break;
  93. case NRF_DFU_OP_OBJECT_SELECT:
  94. index += uint32_encode(p_response->select.max_size, &p_serialized_rsp[index]);
  95. index += uint32_encode(p_response->select.offset, &p_serialized_rsp[index]);
  96. index += uint32_encode(p_response->select.crc, &p_serialized_rsp[index]);
  97. break;
  98. case NRF_DFU_OP_MTU_GET:
  99. index += uint16_encode(p_response->mtu.size, &p_serialized_rsp[index]);
  100. break;
  101. case NRF_DFU_OP_PING:
  102. p_serialized_rsp[index] = p_response->ping.id;
  103. index += sizeof(uint8_t);
  104. break;
  105. default:
  106. // no implementation
  107. break;
  108. }
  109. }
  110. else if (p_response->result == NRF_DFU_RES_CODE_EXT_ERROR)
  111. {
  112. index += response_ext_err_payload_add(p_serialized_rsp, index);
  113. }
  114. if (index > NRF_SERIAL_MAX_RESPONSE_SIZE)
  115. {
  116. NRF_LOG_ERROR("Message is larger than expected.");
  117. }
  118. // Send response.
  119. if (p_transport->rsp_func((uint8_t const *)(p_serialized_rsp), index) != NRF_SUCCESS)
  120. {
  121. NRF_LOG_ERROR("Failed to send data over serial interface!");
  122. }
  123. }
  124. void dfu_req_handler_rsp_clbk(nrf_dfu_response_t * p_res, void * p_context)
  125. {
  126. nrf_dfu_serial_t * p_transport = (nrf_dfu_serial_t *)(p_context);
  127. if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
  128. {
  129. NRF_LOG_WARNING("DFU request completed with result: 0x%x", p_res->result);
  130. }
  131. switch (p_res->request)
  132. {
  133. default:
  134. /* Reply normally.
  135. * Make sure to reply to NRF_DFU_OP_OBJECT_CREATE when running DFU over serial,
  136. * otherwise the transfer might run very slow, without an apparent reason.
  137. */
  138. break;
  139. case NRF_DFU_OP_OBJECT_WRITE:
  140. {
  141. p_transport->pkt_notif_target_count--;
  142. if ( (p_transport->pkt_notif_target == 0)
  143. || (p_transport->pkt_notif_target_count != 0))
  144. {
  145. /* Do not reply to _OBJECT_WRITE messages. */
  146. return;
  147. }
  148. /* Reply with a CRC message and reset the packet counter. */
  149. p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
  150. p_res->request = NRF_DFU_OP_CRC_GET;
  151. p_res->crc.offset = p_res->write.offset;
  152. p_res->crc.crc = p_res->write.crc;
  153. } break;
  154. }
  155. response_send(p_transport, p_res);
  156. }
  157. void nrf_dfu_serial_on_packet_received(nrf_dfu_serial_t * p_transport,
  158. uint8_t const * p_data,
  159. uint32_t length)
  160. {
  161. uint8_t const * p_payload = &p_data[NRF_SERIAL_OPCODE_SIZE];
  162. uint16_t const payload_len = (length - NRF_SERIAL_OPCODE_SIZE);
  163. nrf_dfu_request_t request =
  164. {
  165. .request = (nrf_dfu_op_t)(p_data[0]),
  166. .callback.response = dfu_req_handler_rsp_clbk,
  167. .p_context = p_transport
  168. };
  169. bool buf_free = true;
  170. switch (request.request)
  171. {
  172. case NRF_DFU_OP_FIRMWARE_VERSION:
  173. {
  174. request.firmware.image_number = p_payload[0];
  175. } break;
  176. case NRF_DFU_OP_RECEIPT_NOTIF_SET:
  177. {
  178. NRF_LOG_DEBUG("Set receipt notif target: %d", p_transport->pkt_notif_target);
  179. p_transport->pkt_notif_target = uint16_decode(&p_payload[0]);
  180. p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
  181. } break;
  182. case NRF_DFU_OP_OBJECT_SELECT:
  183. {
  184. request.select.object_type = p_payload[0];
  185. } break;
  186. case NRF_DFU_OP_OBJECT_CREATE:
  187. {
  188. // Reset the packet receipt notification on create object
  189. p_transport->pkt_notif_target_count = p_transport->pkt_notif_target;
  190. request.create.object_type = p_payload[0];
  191. request.create.object_size = uint32_decode(&p_payload[1]);
  192. if (request.create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
  193. {
  194. /* Activity on the current transport. Close all except the current one. */
  195. (void) nrf_dfu_transports_close(p_transport->p_low_level_transport);
  196. }
  197. } break;
  198. case NRF_DFU_OP_OBJECT_WRITE:
  199. {
  200. // Buffer will be freed asynchronously
  201. buf_free = false;
  202. request.write.p_data = p_payload;
  203. request.write.len = payload_len;
  204. request.callback.write = p_transport->payload_free_func;
  205. } break;
  206. case NRF_DFU_OP_MTU_GET:
  207. {
  208. NRF_LOG_DEBUG("Received serial mtu");
  209. request.mtu.size = p_transport->mtu;
  210. } break;
  211. case NRF_DFU_OP_PING:
  212. {
  213. NRF_LOG_DEBUG("Received ping %d", p_payload[0]);
  214. request.ping.id = p_payload[0];
  215. } break;
  216. case 0x77:
  217. {
  218. NRF_LOG_DEBUG("Received Update %d", p_payload[0]);
  219. //request.ping.id = p_payload[0];
  220. } break;
  221. default:
  222. /* Do nothing. */
  223. break;
  224. }
  225. if (buf_free)
  226. {
  227. p_transport->payload_free_func((void *)(p_payload));
  228. }
  229. ret_code_t ret_code = nrf_dfu_req_handler_on_req(&request);
  230. ASSERT(ret_code == NRF_SUCCESS);
  231. }