api-hal-vcp.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. }
  27. void _api_hal_vcp_init() {
  28. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  29. }
  30. void _api_hal_vcp_deinit() {
  31. api_hal_vcp->alive = false;
  32. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  33. }
  34. void _api_hal_vcp_control_line(uint8_t state) {
  35. // bit 0: DTR state, bit 1: RTS state
  36. // bool dtr = state & 0b01;
  37. bool rts = state & 0b10;
  38. if (rts) {
  39. if (!api_hal_vcp->alive) {
  40. api_hal_vcp->alive = true;
  41. _api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
  42. }
  43. } else {
  44. if (api_hal_vcp->alive) {
  45. _api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
  46. api_hal_vcp->alive = false;
  47. }
  48. }
  49. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  50. }
  51. void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) {
  52. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  53. size_t ret = xStreamBufferSendFromISR(api_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken);
  54. if (ret != size) {
  55. api_hal_vcp->underrun = true;
  56. }
  57. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  58. }
  59. void _api_hal_vcp_tx_complete(size_t size) {
  60. osSemaphoreRelease(api_hal_vcp->tx_semaphore);
  61. }
  62. size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) {
  63. furi_assert(api_hal_vcp);
  64. return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, portMAX_DELAY);
  65. }
  66. size_t api_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) {
  67. furi_assert(api_hal_vcp);
  68. return xStreamBufferReceive(api_hal_vcp->rx_stream, buffer, size, timeout);
  69. }
  70. void api_hal_vcp_tx(const uint8_t* buffer, size_t size) {
  71. furi_assert(api_hal_vcp);
  72. while (size > 0 && api_hal_vcp->alive) {
  73. furi_check(osSemaphoreAcquire(api_hal_vcp->tx_semaphore, osWaitForever) == osOK);
  74. size_t batch_size = size;
  75. if (batch_size > APP_TX_DATA_SIZE) {
  76. batch_size = APP_TX_DATA_SIZE;
  77. }
  78. if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) {
  79. size -= batch_size;
  80. buffer += batch_size;
  81. } else {
  82. // Shouldn't be there
  83. osDelay(100);
  84. }
  85. }
  86. }