usb_cdc.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: BSD-3-Clause
  2. // Copyright (c) 2017-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
  3. /*- Includes ----------------------------------------------------------------*/
  4. #include "usb.h"
  5. #include "usb_std.h"
  6. #include "usb_cdc.h"
  7. #include "usb_descriptors.h"
  8. /*- Definitions -------------------------------------------------------------*/
  9. #define ONE_SHOT_STATES (USB_CDC_SERIAL_STATE_BREAK | USB_CDC_SERIAL_STATE_RING | \
  10. USB_CDC_SERIAL_STATE_FRAMING | USB_CDC_SERIAL_STATE_PARITY | USB_CDC_SERIAL_STATE_OVERRUN)
  11. /*- Prototypes --------------------------------------------------------------*/
  12. static void usb_cdc_send_state_notify(void);
  13. static void usb_cdc_ep_comm_callback(void);
  14. /*- Variables ---------------------------------------------------------------*/
  15. static usb_cdc_line_coding_t usb_cdc_line_coding =
  16. {
  17. .dwDTERate = 115200,
  18. .bCharFormat = USB_CDC_1_STOP_BIT,
  19. .bParityType = USB_CDC_NO_PARITY,
  20. .bDataBits = USB_CDC_8_DATA_BITS,
  21. };
  22. static alignas(4) usb_cdc_notify_serial_state_t usb_cdc_notify_message;
  23. static int usb_cdc_serial_state;
  24. static bool usb_cdc_comm_busy;
  25. /*- Implementations ---------------------------------------------------------*/
  26. //-----------------------------------------------------------------------------
  27. void usb_cdc_init(void)
  28. {
  29. usb_set_send_callback(USB_CDC_EP_COMM, usb_cdc_ep_comm_callback);
  30. usb_set_send_callback(USB_CDC_EP_SEND, usb_cdc_send_callback);
  31. usb_set_recv_callback(USB_CDC_EP_RECV, usb_cdc_recv_callback);
  32. usb_cdc_notify_message.request.bmRequestType = USB_IN_TRANSFER |
  33. USB_INTERFACE_RECIPIENT | USB_CLASS_REQUEST;
  34. usb_cdc_notify_message.request.bRequest = USB_CDC_NOTIFY_SERIAL_STATE;
  35. usb_cdc_notify_message.request.wValue = 0;
  36. usb_cdc_notify_message.request.wIndex = 0;
  37. usb_cdc_notify_message.request.wLength = sizeof(uint16_t);
  38. usb_cdc_notify_message.value = 0;
  39. usb_cdc_serial_state = 0;
  40. usb_cdc_comm_busy = false;
  41. usb_cdc_line_coding_updated(&usb_cdc_line_coding);
  42. }
  43. //-----------------------------------------------------------------------------
  44. void usb_cdc_send(uint8_t *data, int size)
  45. {
  46. usb_send(USB_CDC_EP_SEND, data, size);
  47. }
  48. //-----------------------------------------------------------------------------
  49. void usb_cdc_recv(uint8_t *data, int size)
  50. {
  51. usb_recv(USB_CDC_EP_RECV, data, size);
  52. }
  53. //-----------------------------------------------------------------------------
  54. void usb_cdc_set_state(int mask)
  55. {
  56. usb_cdc_serial_state |= mask;
  57. usb_cdc_send_state_notify();
  58. }
  59. //-----------------------------------------------------------------------------
  60. void usb_cdc_clear_state(int mask)
  61. {
  62. usb_cdc_serial_state &= ~mask;
  63. usb_cdc_send_state_notify();
  64. }
  65. //-----------------------------------------------------------------------------
  66. usb_cdc_line_coding_t *usb_cdc_get_line_coding(void)
  67. {
  68. return &usb_cdc_line_coding;
  69. }
  70. //-----------------------------------------------------------------------------
  71. static void usb_cdc_send_state_notify(void)
  72. {
  73. if (usb_cdc_comm_busy)
  74. return;
  75. if (usb_cdc_serial_state != usb_cdc_notify_message.value)
  76. {
  77. usb_cdc_comm_busy = true;
  78. usb_cdc_notify_message.value = usb_cdc_serial_state;
  79. usb_cdc_serial_state &= ~ONE_SHOT_STATES;
  80. usb_send(USB_CDC_EP_COMM, (uint8_t *)&usb_cdc_notify_message, sizeof(usb_cdc_notify_serial_state_t));
  81. }
  82. }
  83. //-----------------------------------------------------------------------------
  84. static void usb_cdc_ep_comm_callback(void)
  85. {
  86. usb_cdc_comm_busy = false;
  87. usb_cdc_notify_message.value &= ~ONE_SHOT_STATES;
  88. usb_cdc_send_state_notify();
  89. }
  90. //-----------------------------------------------------------------------------
  91. static void usb_cdc_set_line_coding_handler(uint8_t *data, int size)
  92. {
  93. usb_cdc_line_coding_t *line_coding = (usb_cdc_line_coding_t *)data;
  94. if (sizeof(usb_cdc_line_coding_t) != size)
  95. return;
  96. usb_cdc_line_coding = *line_coding;
  97. usb_cdc_line_coding_updated(&usb_cdc_line_coding);
  98. }
  99. //-----------------------------------------------------------------------------
  100. bool usb_cdc_handle_request(usb_request_t *request)
  101. {
  102. int length = request->wLength;
  103. switch (USB_CMD_VALUE(request))
  104. {
  105. case USB_CMD(OUT, INTERFACE, CLASS, CDC_SET_LINE_CODING):
  106. {
  107. length = USB_LIMIT(length, sizeof(usb_cdc_line_coding_t));
  108. usb_control_recv(usb_cdc_set_line_coding_handler);
  109. } break;
  110. case USB_CMD(IN, INTERFACE, CLASS, CDC_GET_LINE_CODING):
  111. {
  112. length = USB_LIMIT(length, sizeof(usb_cdc_line_coding_t));
  113. usb_control_send((uint8_t *)&usb_cdc_line_coding, length);
  114. } break;
  115. case USB_CMD(OUT, INTERFACE, CLASS, CDC_SET_CONTROL_LINE_STATE):
  116. {
  117. usb_cdc_control_line_state_update(request->wValue);
  118. usb_control_send_zlp();
  119. } break;
  120. case USB_CMD(OUT, INTERFACE, CLASS, CDC_SEND_BREAK):
  121. {
  122. usb_cdc_send_break(request->wValue);
  123. usb_control_send_zlp();
  124. } break;
  125. default:
  126. return false;
  127. }
  128. return true;
  129. }