cdc_acm_mavlink_template.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright (c) 2025, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbd_core.h"
  7. #include "usbd_cdc_acm.h"
  8. #include "chry_ringbuffer.h"
  9. #include <mavlink.h>
  10. /*!< endpoint address */
  11. #define CDC_IN_EP 0x81
  12. #define CDC_OUT_EP 0x02
  13. #define CDC_INT_EP 0x83
  14. #define USBD_VID 0xFFFF
  15. #define USBD_PID 0xFFFF
  16. #define USBD_MAX_POWER 100
  17. #define USBD_LANGID_STRING 1033
  18. /*!< config descriptor size */
  19. #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
  20. #ifdef CONFIG_USB_HS
  21. #define CDC_MAX_MPS 512
  22. #else
  23. #define CDC_MAX_MPS 64
  24. #endif
  25. #ifdef CONFIG_USBDEV_ADVANCE_DESC
  26. static const uint8_t device_descriptor[] = {
  27. USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
  28. };
  29. static const uint8_t config_descriptor[] = {
  30. USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
  31. CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
  32. };
  33. static const uint8_t device_quality_descriptor[] = {
  34. ///////////////////////////////////////
  35. /// device qualifier descriptor
  36. ///////////////////////////////////////
  37. 0x0a,
  38. USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
  39. 0x00,
  40. 0x02,
  41. 0x00,
  42. 0x00,
  43. 0x00,
  44. 0x40,
  45. 0x00,
  46. 0x00,
  47. };
  48. static const char *string_descriptors[] = {
  49. (const char[]){ 0x09, 0x04 }, /* Langid */
  50. "CherryUSB", /* Manufacturer */
  51. "CherryUSB CDC DEMO", /* Product */
  52. "2022123456", /* Serial Number */
  53. };
  54. static const uint8_t *device_descriptor_callback(uint8_t speed)
  55. {
  56. return device_descriptor;
  57. }
  58. static const uint8_t *config_descriptor_callback(uint8_t speed)
  59. {
  60. return config_descriptor;
  61. }
  62. static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
  63. {
  64. return device_quality_descriptor;
  65. }
  66. static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
  67. {
  68. if (index > 3) {
  69. return NULL;
  70. }
  71. return string_descriptors[index];
  72. }
  73. const struct usb_descriptor cdc_descriptor = {
  74. .device_descriptor_callback = device_descriptor_callback,
  75. .config_descriptor_callback = config_descriptor_callback,
  76. .device_quality_descriptor_callback = device_quality_descriptor_callback,
  77. .string_descriptor_callback = string_descriptor_callback
  78. };
  79. #else
  80. /*!< global descriptor */
  81. static const uint8_t cdc_descriptor[] = {
  82. USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
  83. USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
  84. CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
  85. ///////////////////////////////////////
  86. /// string0 descriptor
  87. ///////////////////////////////////////
  88. USB_LANGID_INIT(USBD_LANGID_STRING),
  89. ///////////////////////////////////////
  90. /// string1 descriptor
  91. ///////////////////////////////////////
  92. 0x14, /* bLength */
  93. USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
  94. 'C', 0x00, /* wcChar0 */
  95. 'h', 0x00, /* wcChar1 */
  96. 'e', 0x00, /* wcChar2 */
  97. 'r', 0x00, /* wcChar3 */
  98. 'r', 0x00, /* wcChar4 */
  99. 'y', 0x00, /* wcChar5 */
  100. 'U', 0x00, /* wcChar6 */
  101. 'S', 0x00, /* wcChar7 */
  102. 'B', 0x00, /* wcChar8 */
  103. ///////////////////////////////////////
  104. /// string2 descriptor
  105. ///////////////////////////////////////
  106. 0x26, /* bLength */
  107. USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
  108. 'C', 0x00, /* wcChar0 */
  109. 'h', 0x00, /* wcChar1 */
  110. 'e', 0x00, /* wcChar2 */
  111. 'r', 0x00, /* wcChar3 */
  112. 'r', 0x00, /* wcChar4 */
  113. 'y', 0x00, /* wcChar5 */
  114. 'U', 0x00, /* wcChar6 */
  115. 'S', 0x00, /* wcChar7 */
  116. 'B', 0x00, /* wcChar8 */
  117. ' ', 0x00, /* wcChar9 */
  118. 'C', 0x00, /* wcChar10 */
  119. 'D', 0x00, /* wcChar11 */
  120. 'C', 0x00, /* wcChar12 */
  121. ' ', 0x00, /* wcChar13 */
  122. 'D', 0x00, /* wcChar14 */
  123. 'E', 0x00, /* wcChar15 */
  124. 'M', 0x00, /* wcChar16 */
  125. 'O', 0x00, /* wcChar17 */
  126. ///////////////////////////////////////
  127. /// string3 descriptor
  128. ///////////////////////////////////////
  129. 0x16, /* bLength */
  130. USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
  131. '2', 0x00, /* wcChar0 */
  132. '0', 0x00, /* wcChar1 */
  133. '2', 0x00, /* wcChar2 */
  134. '2', 0x00, /* wcChar3 */
  135. '1', 0x00, /* wcChar4 */
  136. '2', 0x00, /* wcChar5 */
  137. '3', 0x00, /* wcChar6 */
  138. '4', 0x00, /* wcChar7 */
  139. '5', 0x00, /* wcChar8 */
  140. '6', 0x00, /* wcChar9 */
  141. #ifdef CONFIG_USB_HS
  142. ///////////////////////////////////////
  143. /// device qualifier descriptor
  144. ///////////////////////////////////////
  145. 0x0a,
  146. USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
  147. 0x00,
  148. 0x02,
  149. 0x00,
  150. 0x00,
  151. 0x00,
  152. 0x40,
  153. 0x00,
  154. 0x00,
  155. #endif
  156. 0x00
  157. };
  158. #endif
  159. chry_ringbuffer_t usb_rx_rb;
  160. uint8_t usb_rx_buffer[2048];
  161. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t temp_rx_buffer[512];
  162. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tx_buffer[MAVLINK_MAX_PACKET_LEN];
  163. volatile bool ep_tx_busy_flag = false;
  164. static void usbd_event_handler(uint8_t busid, uint8_t event)
  165. {
  166. switch (event) {
  167. case USBD_EVENT_RESET:
  168. break;
  169. case USBD_EVENT_CONNECTED:
  170. break;
  171. case USBD_EVENT_DISCONNECTED:
  172. break;
  173. case USBD_EVENT_RESUME:
  174. break;
  175. case USBD_EVENT_SUSPEND:
  176. break;
  177. case USBD_EVENT_CONFIGURED:
  178. ep_tx_busy_flag = false;
  179. /* setup first out ep read transfer */
  180. usbd_ep_start_read(busid, CDC_OUT_EP, temp_rx_buffer, usbd_get_ep_mps(busid, CDC_OUT_EP));
  181. break;
  182. case USBD_EVENT_SET_REMOTE_WAKEUP:
  183. break;
  184. case USBD_EVENT_CLR_REMOTE_WAKEUP:
  185. break;
  186. default:
  187. break;
  188. }
  189. }
  190. void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
  191. {
  192. USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
  193. chry_ringbuffer_write(&usb_rx_rb, temp_rx_buffer, nbytes);
  194. usbd_ep_start_read(busid, CDC_OUT_EP, temp_rx_buffer, usbd_get_ep_mps(busid, CDC_OUT_EP));
  195. }
  196. void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
  197. {
  198. USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
  199. if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
  200. /* send zlp */
  201. usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
  202. } else {
  203. ep_tx_busy_flag = false;
  204. }
  205. }
  206. /*!< endpoint call back */
  207. struct usbd_endpoint cdc_out_ep = {
  208. .ep_addr = CDC_OUT_EP,
  209. .ep_cb = usbd_cdc_acm_bulk_out
  210. };
  211. struct usbd_endpoint cdc_in_ep = {
  212. .ep_addr = CDC_IN_EP,
  213. .ep_cb = usbd_cdc_acm_bulk_in
  214. };
  215. static struct usbd_interface intf0;
  216. static struct usbd_interface intf1;
  217. void cdc_acm_mavlink_init(uint8_t busid, uintptr_t reg_base)
  218. {
  219. chry_ringbuffer_init(&usb_rx_rb, usb_rx_buffer, sizeof(usb_rx_buffer));
  220. #ifdef CONFIG_USBDEV_ADVANCE_DESC
  221. usbd_desc_register(busid, &cdc_descriptor);
  222. #else
  223. usbd_desc_register(busid, cdc_descriptor);
  224. #endif
  225. usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
  226. usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
  227. usbd_add_endpoint(busid, &cdc_out_ep);
  228. usbd_add_endpoint(busid, &cdc_in_ep);
  229. usbd_initialize(busid, reg_base, usbd_event_handler);
  230. }
  231. void cdc_acm_mavlink_write(uint8_t *data, uint32_t len)
  232. {
  233. if (!usb_device_is_configured(0)) {
  234. return;
  235. }
  236. ep_tx_busy_flag = true;
  237. usbd_ep_start_write(0, CDC_IN_EP, data, len);
  238. while (ep_tx_busy_flag) {
  239. }
  240. }
  241. void send_heartbeat(void)
  242. {
  243. mavlink_message_t message;
  244. const uint8_t system_id = 42;
  245. const uint8_t base_mode = 0;
  246. const uint8_t custom_mode = 0;
  247. mavlink_msg_heartbeat_pack_chan(
  248. system_id,
  249. MAV_COMP_ID_PERIPHERAL,
  250. MAVLINK_COMM_0,
  251. &message,
  252. MAV_TYPE_GENERIC,
  253. MAV_AUTOPILOT_GENERIC,
  254. base_mode,
  255. custom_mode,
  256. MAV_STATE_STANDBY);
  257. const int len = mavlink_msg_to_send_buffer(usb_tx_buffer, &message);
  258. cdc_acm_mavlink_write(usb_tx_buffer, len);
  259. }
  260. void handle_heartbeat(const mavlink_message_t *message)
  261. {
  262. mavlink_heartbeat_t heartbeat;
  263. mavlink_msg_heartbeat_decode(message, &heartbeat);
  264. USB_LOG_RAW("Got heartbeat from ");
  265. switch (heartbeat.autopilot) {
  266. case MAV_AUTOPILOT_GENERIC:
  267. USB_LOG_RAW("generic");
  268. break;
  269. case MAV_AUTOPILOT_ARDUPILOTMEGA:
  270. USB_LOG_RAW("ArduPilot");
  271. break;
  272. case MAV_AUTOPILOT_PX4:
  273. USB_LOG_RAW("PX4");
  274. break;
  275. default:
  276. USB_LOG_RAW("other");
  277. break;
  278. }
  279. USB_LOG_RAW(" autopilot\n");
  280. send_heartbeat();
  281. }
  282. void mavlink_polling(void)
  283. {
  284. uint8_t ch;
  285. bool ret;
  286. mavlink_message_t message;
  287. mavlink_status_t status;
  288. ret = chry_ringbuffer_read_byte(&usb_rx_rb, &ch);
  289. if (ret) {
  290. if (mavlink_parse_char(MAVLINK_COMM_0, ch, &message, &status) == 1) {
  291. USB_LOG_INFO(
  292. "Received message %d from %d/%d\n",
  293. message.msgid, message.sysid, message.compid);
  294. switch (message.msgid) {
  295. case MAVLINK_MSG_ID_HEARTBEAT:
  296. handle_heartbeat(&message);
  297. break;
  298. }
  299. }
  300. }
  301. }