nrf_dfu_serial_usb.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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 <string.h>
  41. #include "nrf_dfu_req_handler.h"
  42. #include "nrf_dfu_transport.h"
  43. #include "slip.h"
  44. #include "nrf_balloc.h"
  45. #include "nrf_drv_power.h"
  46. #include "nrf_drv_clock.h"
  47. #include "nrf_drv_usbd.h"
  48. #include "nrf_dfu_serial.h"
  49. #include "app_scheduler.h"
  50. #include "app_usbd.h"
  51. #include "app_usbd_cdc_acm.h"
  52. #include "app_usbd_core.h"
  53. #include "app_usbd_string_desc.h"
  54. #include "app_util_platform.h"
  55. #include "app_usbd_serial_num.h"
  56. #define NRF_LOG_MODULE_NAME nrf_dfu_serial_usb
  57. #include "nrf_log.h"
  58. NRF_LOG_MODULE_REGISTER();
  59. /**@file
  60. *
  61. * @defgroup nrf_dfu_serial_usb DFU Serial USB CDC ACM transport
  62. * @ingroup nrf_dfu
  63. * @brief Device Firmware Update (DFU) transport layer using USB CDC ACM.
  64. */
  65. #define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
  66. #define NRF_USB_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
  67. #define RX_BUF_SIZE (1024)
  68. #define SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1)
  69. #define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
  70. #define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
  71. #define CDC_ACM_COMM_INTERFACE 0
  72. #define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
  73. #define CDC_ACM_DATA_INTERFACE 1
  74. #define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
  75. #define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
  76. /**
  77. * @brief Enable power USB detection
  78. *
  79. * Configure if example supports USB port connection
  80. */
  81. #ifndef USBD_POWER_DETECTION
  82. #define USBD_POWER_DETECTION true
  83. #endif
  84. /**
  85. * @brief Interfaces list passed to @ref APP_USBD_CDC_ACM_GLOBAL_DEF
  86. * */
  87. #define CDC_ACM_INTERFACES_CONFIG() \
  88. APP_USBD_CDC_ACM_CONFIG(CDC_ACM_COMM_INTERFACE, \
  89. CDC_ACM_COMM_EPIN, \
  90. CDC_ACM_DATA_INTERFACE, \
  91. CDC_ACM_DATA_EPIN, \
  92. CDC_ACM_DATA_EPOUT)
  93. /*lint -save -e26 -e64 -e505 -e651 */
  94. static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
  95. app_usbd_cdc_acm_user_event_t event);
  96. /**@brief CDC_ACM class instance. */
  97. APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
  98. cdc_acm_user_ev_handler,
  99. CDC_ACM_COMM_INTERFACE,
  100. CDC_ACM_DATA_INTERFACE,
  101. CDC_ACM_COMM_EPIN,
  102. CDC_ACM_DATA_EPIN,
  103. CDC_ACM_DATA_EPOUT,
  104. APP_USBD_CDC_COMM_PROTOCOL_NONE);
  105. /*lint -restore */
  106. NRF_BALLOC_DEF(m_payload_pool, (SLIP_MTU+1), NRF_DFU_SERIAL_USB_RX_BUFFERS);
  107. static nrf_dfu_serial_t m_serial;
  108. static slip_t m_slip;
  109. static uint8_t m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP];
  110. static uint8_t m_rx_buf[NRF_DRV_USBD_EPSIZE];
  111. static nrf_dfu_observer_t m_observer;
  112. static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer);
  113. static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
  114. DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const usb_dfu_transport) =
  115. {
  116. .init_func = usb_dfu_transport_init,
  117. .close_func = usb_dfu_transport_close,
  118. };
  119. static void payload_free(void * p_buf)
  120. {
  121. uint8_t * p_buf_root = ((uint8_t *)(p_buf)) - DATA_OFFSET; //pointer is shifted to point to data
  122. nrf_balloc_free(&m_payload_pool, p_buf_root);
  123. }
  124. static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
  125. {
  126. ASSERT(p_data);
  127. ASSERT(length != 0);
  128. uint32_t slip_len;
  129. // Cannot fail if inputs are non-NULL.
  130. (void) slip_encode(m_rsp_buf, (uint8_t *)(p_data), length, &slip_len);
  131. return app_usbd_cdc_acm_write(&m_app_cdc_acm, m_rsp_buf, slip_len);
  132. }
  133. static void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
  134. {
  135. ret_code_t ret_code;
  136. for (uint32_t i = 0; i < len; i++)
  137. {
  138. ret_code = slip_decode_add_byte(&m_slip, p_data[i]);
  139. if (ret_code != NRF_SUCCESS)
  140. {
  141. continue;
  142. }
  143. nrf_dfu_serial_on_packet_received(p_transport,
  144. (uint8_t const *)(m_slip.p_buffer),
  145. m_slip.current_index);
  146. uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
  147. if (p_rx_buf == NULL)
  148. {
  149. NRF_LOG_ERROR("Failed to allocate buffer!");
  150. return;
  151. }
  152. NRF_LOG_DEBUG("Allocated buffer %x", p_rx_buf);
  153. // reset the slip decoding
  154. m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
  155. m_slip.current_index = 0;
  156. m_slip.state = SLIP_STATE_DECODING;
  157. }
  158. }
  159. /**
  160. * @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones)
  161. * */
  162. static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
  163. app_usbd_cdc_acm_user_event_t event)
  164. {
  165. ret_code_t ret_code;
  166. switch (event)
  167. {
  168. case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
  169. {
  170. ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1);
  171. NRF_LOG_WARNING("Could not read from CDC. Error: 0x%x.", ret_code);
  172. } break;
  173. case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
  174. {
  175. do
  176. {
  177. on_rx_complete(&m_serial, m_rx_buf, 1);
  178. ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1);
  179. } while (ret_code == NRF_SUCCESS);
  180. } break;
  181. default:
  182. break;
  183. }
  184. }
  185. static void usbd_dfu_transport_ev_handler(app_usbd_event_type_t event)
  186. {
  187. switch (event)
  188. {
  189. case APP_USBD_EVT_STOPPED:
  190. app_usbd_disable();
  191. break;
  192. case APP_USBD_EVT_POWER_DETECTED:
  193. NRF_LOG_INFO("USB power detected");
  194. if (!nrf_drv_usbd_is_enabled())
  195. {
  196. app_usbd_enable();
  197. }
  198. if (m_observer)
  199. {
  200. m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
  201. }
  202. break;
  203. case APP_USBD_EVT_POWER_REMOVED:
  204. NRF_LOG_INFO("USB power removed");
  205. app_usbd_stop();
  206. if (m_observer)
  207. {
  208. m_observer(NRF_DFU_EVT_TRANSPORT_DEACTIVATED);
  209. }
  210. break;
  211. case APP_USBD_EVT_POWER_READY:
  212. NRF_LOG_INFO("USB ready");
  213. app_usbd_start();
  214. break;
  215. default:
  216. break;
  217. }
  218. }
  219. static void usbd_sched_event_handler(void * p_event_data, uint16_t event_size)
  220. {
  221. app_usbd_event_execute(p_event_data);
  222. }
  223. static void usbd_event_handler(app_usbd_internal_evt_t const * const p_event)
  224. {
  225. ret_code_t ret_code;
  226. if (p_event->type == APP_USBD_EVT_DRV_SOF)
  227. {
  228. app_usbd_event_execute(p_event);
  229. }
  230. else
  231. {
  232. ret_code = app_sched_event_put(p_event,
  233. sizeof(app_usbd_internal_evt_t),
  234. usbd_sched_event_handler);
  235. if (ret_code != NRF_SUCCESS)
  236. {
  237. NRF_LOG_ERROR("Could not schedule USB event!");
  238. }
  239. }
  240. }
  241. static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer)
  242. {
  243. uint32_t err_code;
  244. /* Execute event directly in interrupt handler */
  245. static const app_usbd_config_t usbd_config =
  246. {
  247. .ev_handler = usbd_event_handler,
  248. .ev_state_proc = usbd_dfu_transport_ev_handler
  249. };
  250. (void) nrf_balloc_init(&m_payload_pool); //Result is checked by checking result of _alloc().
  251. m_observer = observer;
  252. uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
  253. if (p_rx_buf == NULL)
  254. {
  255. NRF_LOG_ERROR("Could not allocate payload pool.");
  256. return NRF_ERROR_INTERNAL;
  257. }
  258. m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
  259. m_slip.current_index = 0;
  260. m_slip.buffer_len = SLIP_MTU;
  261. m_slip.state = SLIP_STATE_DECODING;
  262. m_serial.rsp_func = rsp_send;
  263. m_serial.payload_free_func = payload_free;
  264. m_serial.mtu = SLIP_MTU;
  265. m_serial.p_rsp_buf = &m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP -
  266. NRF_SERIAL_MAX_RESPONSE_SIZE];
  267. m_serial.p_low_level_transport = &usb_dfu_transport;
  268. NRF_LOG_DEBUG("Initializing drivers.");
  269. err_code = nrf_drv_clock_init();
  270. if (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED)
  271. {
  272. VERIFY_SUCCESS(err_code);
  273. }
  274. err_code = nrf_drv_power_init(NULL);
  275. VERIFY_SUCCESS(err_code);
  276. app_usbd_serial_num_generate();
  277. err_code = app_usbd_init(&usbd_config);
  278. VERIFY_SUCCESS(err_code);
  279. app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
  280. err_code = app_usbd_class_append(class_cdc_acm);
  281. VERIFY_SUCCESS(err_code);
  282. NRF_LOG_DEBUG("Starting USB");
  283. if (USBD_POWER_DETECTION)
  284. {
  285. err_code = app_usbd_power_events_enable();
  286. VERIFY_SUCCESS(err_code);
  287. }
  288. else
  289. {
  290. NRF_LOG_DEBUG("No USB power detection enabled, starting USB now");
  291. app_usbd_enable();
  292. app_usbd_start();
  293. }
  294. NRF_LOG_DEBUG("USB Transport initialized");
  295. return err_code;
  296. }
  297. static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
  298. {
  299. return NRF_SUCCESS;
  300. }