api-hal-vcp.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include <api-hal-vcp.h>
  2. #include <usbd_cdc_if.h>
  3. #include <furi.h>
  4. #include <stream_buffer.h>
  5. #define API_HAL_VCP_RX_BUFFER_SIZE 600
  6. typedef struct {
  7. StreamBufferHandle_t rx_stream;
  8. osSemaphoreId_t tx_semaphore;
  9. volatile bool alive;
  10. volatile bool underrun;
  11. } ApiHalVcp;
  12. static ApiHalVcp* api_hal_vcp = NULL;
  13. static const uint8_t ascii_soh = 0x01;
  14. static const uint8_t ascii_eot = 0x04;
  15. void _api_hal_vcp_init();
  16. void _api_hal_vcp_deinit();
  17. void _api_hal_vcp_control_line(uint8_t state);
  18. void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size);
  19. void _api_hal_vcp_tx_complete(size_t size);
  20. void api_hal_vcp_init() {
  21. api_hal_vcp = furi_alloc(sizeof(ApiHalVcp));
  22. api_hal_vcp->rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1);
  23. api_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL);
  24. api_hal_vcp->alive = false;
  25. api_hal_vcp->underrun = false;
  26. FURI_LOG_I("FuriHalVcp", "Init OK");
  27. }
  28. void _api_hal_vcp_init() {
  29. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  30. }
  31. void _api_hal_vcp_deinit() {
  32. api_hal_vcp->alive = false;
  33. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  34. }
  35. void _api_hal_vcp_control_line(uint8_t state) {
  36. // bit 0: DTR state, bit 1: RTS state
  37. // bool dtr = state & 0b01;
  38. bool dtr = state & 0b1;
  39. if (dtr) {
  40. if (!api_hal_vcp->alive) {
  41. api_hal_vcp->alive = true;
  42. _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
  43. }
  44. } else {
  45. if (api_hal_vcp->alive) {
  46. _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
  47. api_hal_vcp->alive = false;
  48. }
  49. }
  50. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  51. }
  52. void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) {
  53. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  54. size_t ret = xStreamBufferSendFromISR(api_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken);
  55. if (ret != size) {
  56. api_hal_vcp->underrun = true;
  57. }
  58. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  59. }
  60. void _api_hal_vcp_tx_complete(size_t size) {
  61. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  62. }
  63. size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) {
  64. furi_assert(api_hal_vcp);
  65. return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY);
  66. }
  67. size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) {
  68. furi_assert(api_hal_vcp);
  69. return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, timeout);
  70. }
  71. void api_hal_vcp_tx(const uint8_t* buffer, size_t size) {
  72. furi_assert(api_hal_vcp);
  73. while (size > 0 && api_hal_vcp->alive) {
  74. furi_check(osSemaphoreAcquire(api_hal_vcp->tx_semaphore, osWaitForever) == osOK);
  75. size_t batch_size = size;
  76. if (batch_size > APP_TX_DATA_SIZE) {
  77. batch_size = APP_TX_DATA_SIZE;
  78. }
  79. if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) {
  80. size -= batch_size;
  81. buffer += batch_size;
  82. } else {
  83. // Shouldn't be there
  84. osDelay(100);
  85. }
  86. }
  87. }